Big performance regression with --no-color option in git-log
On today git tree
bash-3.1$ time git log HEAD > /dev/null
1.31user 0.07system 0:01.39elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+2455minor)pagefaults 0swaps
bash-3.1$ time git log --no-color HEAD > /dev/null
5.01user 0.11system 0:05.16elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+6319minor)pagefaults 0swaps
bash-3.1$ git --version
git version 1.5.3.2.124.g648db
Marco
Quoted 1 line · Marco Costalba
On today git tree
hmmm interesting... Here is what happens with --no-color:
38708 33.2920 diff_tree
23908 20.5628 base_name_compare
18478 15.8926 decode_tree_entry
8310 7.1473 find_pack_entry_one
5654 4.8629 update_tree_entry
2748 2.3635 pretty_print_commit
1838 1.5808 get_one_line
1460 1.2557 .pltand wihtout it:
2594 18.0893 pretty_print_commit
1887 13.1590 get_one_line
1574 10.9763 find_pack_entry_one
967 6.7434 get_short_sha1
892 6.2204 parse_commit_buffer
863 6.0181 lookup_object
595 4.1492 strbuf_grow
440 3.0683 insert_obj_hashWhy on earth does --no-color has such a different code path ...
Signature · 3 lines
·O· Pierre Habouzit ··O [email protected] OOO http://www.madism.org
Quoted 2 lines · Pierre Habouzit
Quoted 1 line · Marco Costalba
On today git tree
Okay for me it's not only from today, and the issue seems to be with
the fact that we pass options or that we don't... git log --color also takes an awful lot of time here, whereas it's my default. Looks like diff_opt_parse is called too many times.
Signature · 3 lines
·O· Pierre Habouzit ··O [email protected] OOO http://www.madism.org
Quoted 9 lines · Pierre Habouzit
Quoted 2 lines · Pierre Habouzit
Quoted 1 line · Marco Costalba
On today git tree
Okay for me it's not only from today, and the issue seems to be with
the fact that we pass options or that we don't... git log --color also takes an awful lot of time here, whereas it's my default. Looks likediff_opt_parseis called too many times.
There was a patch some time ago to fix a similar issue with '-z' option (66e41f7b9912), perhaps the fix could be the same also for --no-color, --color, or other new options that force to actually compute diffs when is not needed.
Marco
PATCH 1/1 --color and --no-color git-log options don't need diffs to be computed.
---
revision.c | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-)
revision.c +3 -2
@@ -1209,8 +1209,9 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch opts =diff_opt_parse (&revs->diffopt, argv+i, argc-i);if (opts >0 ) { -if (strcmp (argv[i],"-z" )) - revs->diff =1 ; + revs->diff =strcmp (argv[i],"-z" ) + &&strcmp (argv[i],"--color" ) + &&strcmp (argv[i],"--no-color" ); i += opts -1 ;continue ; }
Signature · 1 line
1.5.3.2.1110.g61a7cd-dirty
Re: [PATCH 1/1] --color and --no-color git-log options don't need diffs to be computed.
Quoted 12 lines · Pierre Habouzit
Signed-off-by Pierre Habouzit <[email protected]>---
revision.c | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-)revision.c +0
-0@@ -1209,8 +1209,9 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
revision.c int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch · line 1217
Quoted 10 lines
revision.c +3
-2opts =diff_opt_parse (&revs->diffopt, argv+i, argc-i);if (opts >0 ) { -if (strcmp (argv[i],"-z" )) - revs->diff =1 ; + revs->diff =strcmp (argv[i],"-z" ) + &&strcmp (argv[i],"--color" ) + &&strcmp (argv[i],"--no-color" ); i += opts -1 ;continue ; }
Aside from the "don't override the option that is already set" comment from David, I am somewhat unhappy that this piece already knows too much about which option to diff potentially changes the output (but not commits us to produce the diff) and which option causes us to actually produce output.
Re: [PATCH 1/1] --color and --no-color git-log options don't need diffs to be computed.
In reply to Pierre Habouzitrevision.c int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch · line 1216
Quoted 9 lines · Pierre Habouzit
Signed-off-by Pierre Habouzit <[email protected]>revision.c +3
-2-if (strcmp (argv[i],"-z" )) - revs->diff =1 ; + revs->diff =strcmp (argv[i],"-z" ) + &&strcmp (argv[i],"--color" ) + &&strcmp (argv[i],"--no-color" ); i += opts -1 ;continue ;
This can clear a previously set value of revs->diff.
Signature · 1 line
David Kastrup, Kriemhildstr. 15, 44793 Bochum
Re: [PATCH 1/1] --color and --no-color git-log options don't need diffs to be computed.
Quoted 4 lines · David Kastrup
Quoted 1 line · Pierre Habouzit
Signed-off-by Pierre Habouzit <[email protected]>
Quoted 9 lines
revision.c int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch · line 1216
Quoted 7 lines
revision.c +3
-2-if (strcmp (argv[i],"-z" )) - revs->diff =1 ; + revs->diff =strcmp (argv[i],"-z" ) + &&strcmp (argv[i],"--color" ) + &&strcmp (argv[i],"--no-color" ); i += opts -1 ;continue ;This can clear a previously set value of
revs->diff.
Good catch, that should be |= of course.
Signature · 3 lines
·O· Pierre Habouzit ··O [email protected] OOO http://www.madism.org
Re: [PATCH 1/1] --color and --no-color git-log options don't need diffs to be computed.
Quoted 11 lines · Pierre Habouzit
Quoted 11 lines
Quoted 10 lines
Signed-off-by Pierre Habouzit <[email protected]>revision.c +3
-2-if (strcmp (argv[i],"-z" )) - revs->diff =1 ; + revs->diff =strcmp (argv[i],"-z" ) + &&strcmp (argv[i],"--color" ) + &&strcmp (argv[i],"--no-color" ); i += opts -1 ;continue ;
Quoted 4 lines
Quoted 1 line
This can clear a previously set value of
revs->diff.Good catch, that should be |= of course.
Perhaps also with an 'if' before to avoid clearing an already set revs->diff if the passed option does not match any of the three.
Marco
Re: [PATCH 1/1] --color and --no-color git-log options don't need diffs to be computed.
Quoted 4 lines · Marco Costalba
Perhaps also with an 'if' before to avoid clearing an already set
revs->diffif the passed option does not match any of the three.
Please discard, I mistakenly pressed 'send' button.
Fix revision log diff setup, avoid unnecessary diff generation
In reply to Pierre HabouzitWe used to incorrectly start calculating diffs whenever any argument but '-z' was recognized by the diff options parsing. That was bogus, since not all arguments result in diffs being needed, so we just waste a lot of time and effort on calculating diffs that don't matter.
This actually also fixes another bug in "git log". Try this:
git log -C
and notice how it prints an extra empty line in between log entries, even though it never prints the actual diff (because we didn't ask for any diff format, so the diff machinery never prints anything).
With this patch, that bogus empty line is gone, because "revs->diff" is never set. So this isn't just a "wasted time and effort" issue, it's also a slight semantic fix.
---
Review
Quoted 6 lines · Pierre Habouzit
(quoted diff) +3
-2- if (strcmp(argv[i], "-z")) - revs->diff = 1; + revs->diff = strcmp(argv[i], "-z") + && strcmp(argv[i], "--color") + && strcmp(argv[i], "--no-color");
The old code was already pretty damn ugly, the new code is worse (never mind the bug).
I don't think we should care *at*all* about the actual argument string, we should just look at what the diffopts end up being at the end.
So I would suggest a patch like the appended instead!
(Maybe there are other cases where we'd want to run the diff, but I can't think of any)
Linus
--- revision.c | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-)
revision.c +8 -2
@@ -1209,8 +1209,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch opts =diff_opt_parse (&revs->diffopt, argv+i, argc-i);if (opts >0 ) { -if (strcmp (argv[i],"-z" )) - revs->diff =1 ; i += opts -1 ;continue ; }
@@ -1254,6 +1252,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const chadd_pending_object_with_mode (revs, object, def, mode); } +/* Did the user ask for any diff output? Run the diff! */ +if (revs->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT ) + revs->diff =1 ; + +/* Pickaxe needs diffs */ +if (revs->diffopt.pickaxe) + revs->diff =1 ; +if (revs->topo_order) revs->limited =1 ;
Re: Fix revision log diff setup, avoid unnecessary diff generation
Quoted 11 lines · Linus Torvalds
Review
Quoted 6 lines · Pierre Habouzit
(quoted diff) +3
-2- if (strcmp(argv[i], "-z")) - revs->diff = 1; + revs->diff = strcmp(argv[i], "-z") + && strcmp(argv[i], "--color") + && strcmp(argv[i], "--no-color");The old code was already pretty damn ugly, the new code is worse (never mind the bug).
Quoted 2 lines
I don't think we should care *at*all* about the actual argument string, we should just look at what the diffopts end up being at the end.
Thanks, I think this is the sanest thing to do.