diff options
author | René Scharfe <rene.scharfe@lsrfire.ath.cx> | 2007-11-09 01:49:42 +0100 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2007-11-09 01:30:07 -0800 |
commit | cde75e59e1b2d8dd3ba49bc9034692dd06ee3907 (patch) | |
tree | 224b5ca0f6d7c0814ada85c5dce4f809d61a1b2b /strbuf.c | |
parent | 659c69cfef984e7416decc78841877207e9d5914 (diff) | |
download | git-cde75e59e1b2d8dd3ba49bc9034692dd06ee3907.tar.gz |
--pretty=format: on-demand format expansion
Some of the --pretty=format placeholders expansions are expensive to
calculate. This is made worse by the current code's use of
interpolate(), which requires _all_ placeholders are to be prepared
up front.
One way to speed this up is to check which placeholders are present
in the format string and to prepare only the expansions that are
needed. That still leaves the allocation overhead of interpolate().
Another way is to use a callback based approach together with the
strbuf library to keep allocations to a minimum and avoid string
copies. That's what this patch does. It introduces a new strbuf
function, strbuf_expand().
The function takes a format string, list of placeholder strings,
a user supplied function 'fn', and an opaque pointer 'context'
to tell 'fn' what thingy to operate on.
The function 'fn' is expected to accept a strbuf, a parsed
placeholder string and the 'context' pointer, and append the
interpolated value for the 'context' thingy, according to the
format specified by the placeholder.
Thanks to Pierre Habouzit for his suggestion to use strchrnul() and
the code surrounding its callsite. And thanks to Junio for most of
this commit message. :)
Here my measurements of most of Paul Mackerras' test cases that
highlighted the performance problem (best of three runs):
(master)
$ time git log --pretty=oneline >/dev/null
real 0m0.390s
user 0m0.340s
sys 0m0.040s
(master)
$ time git log --pretty=raw >/dev/null
real 0m0.434s
user 0m0.408s
sys 0m0.016s
(master)
$ time git log --pretty="format:%H {%P} %ct" >/dev/null
real 0m1.347s
user 0m0.080s
sys 0m1.256s
(interp_find_active -- Dscho)
$ time ./git log --pretty="format:%H {%P} %ct" >/dev/null
real 0m0.694s
user 0m0.020s
sys 0m0.672s
(strbuf_expand -- this patch)
$ time ./git log --pretty="format:%H {%P} %ct" >/dev/null
real 0m0.395s
user 0m0.352s
sys 0m0.028s
Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'strbuf.c')
-rw-r--r-- | strbuf.c | 24 |
1 files changed, 24 insertions, 0 deletions
@@ -129,6 +129,30 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...) strbuf_setlen(sb, sb->len + len); } +void strbuf_expand(struct strbuf *sb, const char *format, + const char **placeholders, expand_fn_t fn, void *context) +{ + for (;;) { + const char *percent, **p; + + percent = strchrnul(format, '%'); + strbuf_add(sb, format, percent - format); + if (!*percent) + break; + format = percent + 1; + + for (p = placeholders; *p; p++) { + if (!prefixcmp(format, *p)) + break; + } + if (*p) { + fn(sb, *p, context); + format += strlen(*p); + } else + strbuf_addch(sb, '%'); + } +} + size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f) { size_t res; |