Currently, the --pretty=format prefix is looked up in a
tight loop in strbuf_expand(), if prefix is found it is then
used as argument for format_commit_item() that does another
search by a switch statement to select the proper operation.
Because the switch statement is already able to discard
unknown matches we don't need the prefix lookup before
to call format_commit_item().
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
When e-mail address is empty (e.g. "A U Thor <>"), --pretty=format
misparsed the commit header and did not pick up the date field correctly.
Noticed by Marco, fixed slightly differently with additional sanity
check and with a test.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
When a commit message that does not have a terminating LF is
read in and the memory that was allocated to read it happens to
have a LF immediately after that, the code was not careful and
went past the terminating NUL.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
As Jeff King remarked, format strings with duplicate placeholders can
be slow to expand, because each instance is calculated anew.
This patch makes use of the fact that format_commit_message() and its
helper functions only ever add stuff to the end of the strbuf. For
certain expensive placeholders, store the offset and length of their
expansion with the strbuf at the first occurrence. Later they
expansion result can simply be copied from there -- no malloc() or
strdup() required.
These certain placeholders are the abbreviated commit, tree and
parent hashes, as the search for a unique abbreviated hash is quite
costly. Here are the times for next (best of three runs):
$ time git log --pretty=format:%h >/dev/null
real 0m0.611s
user 0m0.404s
sys 0m0.204s
$ time git log --pretty=format:%h%h%h%h >/dev/null
real 0m1.206s
user 0m0.744s
sys 0m0.452s
And here those with this patch (and the previous two); the speedup
of the single placeholder case is just noise:
$ time git log --pretty=format:%h >/dev/null
real 0m0.608s
user 0m0.416s
sys 0m0.192s
$ time git log --pretty=format:%h%h%h%h >/dev/null
real 0m0.639s
user 0m0.488s
sys 0m0.140s
Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
As Jeff King pointed out, some placeholder expansions are related to
each other: the steps to calculate one go most of the way towards
calculating the other, too.
This patch makes format_commit_message() parse the commit message
only once, remembering the position of each item. This speeds up
handling of format strings containing multiple placeholders from the
set %s, %a*, %c*, %e, %b.
Here are the timings for the git version in next. The first one is
to estimate the overhead of the caching, the second one is taken
from http://svn.tue.mpg.de/tentakel/trunk/tentakel/Makefile as an
example of a format string found in the wild. The times are the
fastest of three consecutive runs in each case:
$ time git log --pretty=format:%e >/dev/null
real 0m0.381s
user 0m0.340s
sys 0m0.024s
$ time git log --pretty=format:"* %cd %cn%n%n%s%n%b" >/dev/null
real 0m0.623s
user 0m0.556s
sys 0m0.052s
And here the times with this patch:
$ time git log --pretty=format:%e >/dev/null
real 0m0.385s
user 0m0.332s
sys 0m0.040s
$ time git log --pretty=format:"* %cd %cn%n%n%s%n%b" >/dev/null
real 0m0.563s
user 0m0.504s
sys 0m0.048s
Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
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>
The file commit.c got quite large, but it does not have to be: the
code concerning pretty printing is pretty well contained. In fact,
this commit just splits it off into pretty.c, leaving commit.c with
just 672 lines.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>