diff --color-moved-ws: optimize allow-indentation-change

When running git diff --color-moved-ws=allow-indentation-change v2.18.0 v2.19.0 cmp_in_block_with_wsd() is called 694908327 times. Of those 42.7% return after comparing a and b. By comparing the lengths first we can return early in all but 0.03% of those cases without dereferencing the string pointers. The comparison between a and c fails in 6.8% of calls, by comparing the lengths first we reject all the failing calls without dereferencing the string pointers. This reduces the time to run the command above by by 42% from 14.6s to 8.5s. This is still much slower than the normal --color-moved which takes ~0.6-0.7s to run but is a significant improvement. The next commits will replace the current implementation with one that works with mixed tabs and spaces in the indentation. I think it is worth optimizing the current implementation first to enable a fair comparison between the two implementations. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Phillip Wood committed Nov 23, 2018 at 11:16 UTC 7a4252c4df49fe07bf91dbb5be2c6012f6a65329
1 file changed +11 -8
diff.c
+11 -8
@@ -831,20 +831,23 @@ static int cmp_in_block_with_wsd(const struct diff_options *o,
831 int n)
832 {
833 struct emitted_diff_symbol *l = &o->emitted_symbols->buf[n];
834 - int al = cur->es->len, cl = l->len;
834 + int al = cur->es->len, bl = match->es->len, cl = l->len;
835 const char *a = cur->es->line,
836 *b = match->es->line,
837 *c = l->line;
838 -
838 + const char *orig_a = a;
839 int wslen;
840
841 /*
842 - * We need to check if 'cur' is equal to 'match'.
843 - * As those are from the same (+/-) side, we do not need to adjust for
844 - * indent changes. However these were found using fuzzy matching
845 - * so we do have to check if they are equal.
842 + * We need to check if 'cur' is equal to 'match'. As those
843 + * are from the same (+/-) side, we do not need to adjust for
844 + * indent changes. However these were found using fuzzy
845 + * matching so we do have to check if they are equal. Here we
846 + * just check the lengths. We delay calling memcmp() to check
847 + * the contents until later as if the length comparison for a
848 + * and c fails we can avoid the call all together.
849 */
847 - if (strcmp(a, b))
850 + if (al != bl)
851 return 1;
852
853 if (!pmb->wsd.string)
@@ -872,7 +875,7 @@ static int cmp_in_block_with_wsd(const struct diff_options *o,
875 al -= wslen;
876 }
877
875 - if (al != cl || memcmp(a, c, al))
878 + if (al != cl || memcmp(orig_a, b, bl) || memcmp(a, c, al))
879 return 1;
880
881 return 0;