shortlog: optimize out useless string list

If we are in "--summary" mode, then we do not care about the actual list of subject onelines associated with each author. We care only about the number. So rather than store a string-list for each author full of "<none>", let's just keep a count. This drops my best-of-five for "git shortlog -ns HEAD" on linux.git from: real 0m5.194s user 0m5.028s sys 0m0.168s to: real 0m5.057s user 0m4.916s sys 0m0.144s That's about 2.5%. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Jan 18, 2016 at 15:02 UTC 9b21a34a968080873519a927afd9c2570f464785
1 file changed +31 -12
builtin/shortlog.c
+31 -12
@@ -14,7 +14,26 @@ static char const * const shortlog_usage[] = {
14 NULL
15 };
16
17 -static int compare_by_number(const void *a1, const void *a2)
17 +/*
18 + * The util field of our string_list_items will contain one of two things:
19 + *
20 + * - if --summary is not in use, it will point to a string list of the
21 + * oneline subjects assigned to this author
22 + *
23 + * - if --summary is in use, we don't need that list; we only need to know
24 + * its size. So we abuse the pointer slot to store our integer counter.
25 + *
26 + * This macro accesses the latter.
27 + */
28 +#define UTIL_TO_INT(x) ((intptr_t)(x)->util)
29 +
30 +static int compare_by_counter(const void *a1, const void *a2)
31 +{
32 + const struct string_list_item *i1 = a1, *i2 = a2;
33 + return UTIL_TO_INT(i2) - UTIL_TO_INT(i1);
34 +}
35 +
36 +static int compare_by_list(const void *a1, const void *a2)
37 {
38 const struct string_list_item *i1 = a1, *i2 = a2;
39 const struct string_list *l1 = i1->util, *l2 = i2->util;
@@ -52,11 +71,9 @@ static void insert_one_record(struct shortlog *log,
71 strbuf_addf(&namemailbuf, " <%.*s>", (int)maillen, mailbuf);
72
73 item = string_list_insert(&log->list, namemailbuf.buf);
55 - if (item->util == NULL)
56 - item->util = xcalloc(1, sizeof(struct string_list));
74
75 if (log->summary)
59 - string_list_append(item->util, xstrdup(""));
76 + item->util = (void *)(UTIL_TO_INT(item) + 1);
77 else {
78 const char *dot3 = log->common_repo_prefix;
79 char *buffer, *p;
@@ -90,6 +107,8 @@ static void insert_one_record(struct shortlog *log,
107 }
108 }
109
110 + if (item->util == NULL)
111 + item->util = xcalloc(1, sizeof(struct string_list));
112 string_list_append(item->util, buffer);
113 }
114 }
@@ -295,14 +314,14 @@ void shortlog_output(struct shortlog *log)
314
315 if (log->sort_by_number)
316 qsort(log->list.items, log->list.nr, sizeof(struct string_list_item),
298 - compare_by_number);
317 + log->summary ? compare_by_counter : compare_by_list);
318 for (i = 0; i < log->list.nr; i++) {
300 - struct string_list *onelines = log->list.items[i].util;
301 -
319 + const struct string_list_item *item = &log->list.items[i];
320 if (log->summary) {
303 - printf("%6d\t%s\n", onelines->nr, log->list.items[i].string);
321 + printf("%6d\t%s\n", (int)UTIL_TO_INT(item), item->string);
322 } else {
305 - printf("%s (%d):\n", log->list.items[i].string, onelines->nr);
323 + struct string_list *onelines = item->util;
324 + printf("%s (%d):\n", item->string, onelines->nr);
325 for (j = onelines->nr - 1; j >= 0; j--) {
326 const char *msg = onelines->items[j].string;
327
@@ -315,11 +334,11 @@ void shortlog_output(struct shortlog *log)
334 printf(" %s\n", msg);
335 }
336 putchar('\n');
337 + onelines->strdup_strings = 1;
338 + string_list_clear(onelines, 0);
339 + free(onelines);
340 }
341
320 - onelines->strdup_strings = 1;
321 - string_list_clear(onelines, 0);
322 - free(onelines);
342 log->list.items[i].util = NULL;
343 }
344