ref-filter: reuse output buffer

When we use `git for-each-ref`, every ref will allocate its own output strbuf and error strbuf. But we can reuse the final strbuf for each step ref's output. The error buffer will also be reused, despite the fact that the git will exit when `format_ref_array_item()` return a non-zero value and output the contents of the error buffer. The performance for `git for-each-ref` on the Git repository itself with performance testing tool `hyperfine` changes from 23.7 ms ± 0.9 ms to 22.2 ms ± 1.0 ms. Optimization is relatively minor. At the same time, we apply this optimization to `git tag -l` and `git branch -l`. This approach is similar to the one used by 79ed0a5 (cat-file: use a single strbuf for all output, 2018-08-14) to speed up the cat-file builtin. Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Jeff King <peff@peff.net> Helped-by: René Scharfe <l.s.r@web.de> Signed-off-by: ZheNing Hu <adlternative@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

ZheNing Hu committed Apr 20, 2021 at 16:52 UTC 844c3f0b0b5cc45f8aa8bd65c7ad407df7301c39
3 files changed +20 -16
builtin/branch.c
+6 -4
@@ -411,6 +411,8 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
411 {
412 int i;
413 struct ref_array array;
414 + struct strbuf out = STRBUF_INIT;
415 + struct strbuf err = STRBUF_INIT;
416 int maxwidth = 0;
417 const char *remote_prefix = "";
418 char *to_free = NULL;
@@ -440,8 +442,8 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
442 ref_array_sort(sorting, &array);
443
444 for (i = 0; i < array.nr; i++) {
443 - struct strbuf out = STRBUF_INIT;
444 - struct strbuf err = STRBUF_INIT;
445 + strbuf_reset(&err);
446 + strbuf_reset(&out);
447 if (format_ref_array_item(array.items[i], format, &out, &err))
448 die("%s", err.buf);
449 if (column_active(colopts)) {
@@ -452,10 +454,10 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
454 fwrite(out.buf, 1, out.len, stdout);
455 putchar('\n');
456 }
455 - strbuf_release(&err);
456 - strbuf_release(&out);
457 }
458
459 + strbuf_release(&err);
460 + strbuf_release(&out);
461 ref_array_clear(&array);
462 free(to_free);
463 }
builtin/for-each-ref.c
+7 -6
@@ -22,6 +22,8 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
22 struct ref_array array;
23 struct ref_filter filter;
24 struct ref_format format = REF_FORMAT_INIT;
25 + struct strbuf output = STRBUF_INIT;
26 + struct strbuf err = STRBUF_INIT;
27
28 struct option opts[] = {
29 OPT_BIT('s', "shell", &format.quote_style,
@@ -81,17 +83,16 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
83 if (!maxcount || array.nr < maxcount)
84 maxcount = array.nr;
85 for (i = 0; i < maxcount; i++) {
84 - struct strbuf output = STRBUF_INIT;
85 - struct strbuf err = STRBUF_INIT;
86 -
86 + strbuf_reset(&err);
87 + strbuf_reset(&output);
88 if (format_ref_array_item(array.items[i], &format, &output, &err))
89 die("%s", err.buf);
90 fwrite(output.buf, 1, output.len, stdout);
91 putchar('\n');
91 -
92 - strbuf_release(&err);
93 - strbuf_release(&output);
92 }
93 +
94 + strbuf_release(&err);
95 + strbuf_release(&output);
96 ref_array_clear(&array);
97 return 0;
98 }
builtin/tag.c
+7 -6
@@ -39,6 +39,8 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
39 struct ref_format *format)
40 {
41 struct ref_array array;
42 + struct strbuf output = STRBUF_INIT;
43 + struct strbuf err = STRBUF_INIT;
44 char *to_free = NULL;
45 int i;
46
@@ -64,17 +66,16 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
66 ref_array_sort(sorting, &array);
67
68 for (i = 0; i < array.nr; i++) {
67 - struct strbuf output = STRBUF_INIT;
68 - struct strbuf err = STRBUF_INIT;
69 -
69 + strbuf_reset(&output);
70 + strbuf_reset(&err);
71 if (format_ref_array_item(array.items[i], format, &output, &err))
72 die("%s", err.buf);
73 fwrite(output.buf, 1, output.len, stdout);
74 putchar('\n');
74 -
75 - strbuf_release(&err);
76 - strbuf_release(&output);
75 }
76 +
77 + strbuf_release(&err);
78 + strbuf_release(&output);
79 ref_array_clear(&array);
80 free(to_free);
81