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