Am 23.09.19 um 22:47 schrieb SZEDER Gábor:
> On Mon, Sep 23, 2019 at 09:55:11PM +0200, René Scharfe wrote:
>> -- >8 --
>> Subject: [PATCH] name-rev: use FLEX_ARRAY for tip_name in struct rev_name
>>
>> Give each rev_name its very own tip_name string. This simplifies memory
>> ownership, as callers of name_rev() only have to make sure the tip_name
>> parameter exists for the duration of the call and don't have to preserve
>> it for the whole run of the program.
>>
>> It also saves four or eight bytes per object because this change removes
>> the pointer indirection. Memory usage is still higher for linear
>> histories that previously shared the same tip_name value between
>> multiple name_rev instances.
>
> Besides looking at memory usage, have you run any performance
> benchmarks? Here it seems to make 'git name-rev --all >out' slower by
> 17% in the git repo and by 19.5% in the linux repo.
Did measure now; I also see a slowdown with my patch applied:
git:
Benchmark #1: ~/src/git/git name-rev --all
Time (mean ± σ): 462.8 ms ± 2.8 ms [User: 440.6 ms, System: 20.5 ms]
Range (min … max): 459.6 ms … 466.5 ms 10 runs
git w/ commit-graph:
Benchmark #1: ~/src/git/git name-rev --all
Time (mean ± σ): 104.0 ms ± 1.5 ms [User: 93.7 ms, System: 10.0 ms]
Range (min … max): 101.5 ms … 107.1 ms 28 runs
git w/ patch:
Benchmark #1: ~/src/git/git name-rev --all
Time (mean ± σ): 475.1 ms ± 3.7 ms [User: 458.3 ms, System: 16.0 ms]
Range (min … max): 470.4 ms … 481.4 ms 10 runs
git w/ commit-graph and patch:
Benchmark #1: ~/src/git/git name-rev --all
Time (mean ± σ): 110.9 ms ± 1.5 ms [User: 106.6 ms, System: 4.1 ms]
Range (min … max): 109.0 ms … 114.7 ms 26 runs
linux:
Benchmark #1: ~/src/git/git name-rev --all
Time (mean ± σ): 6.670 s ± 0.027 s [User: 6.450 s, System: 0.208 s]
Range (min … max): 6.640 s … 6.721 s 10 runs
linux w/ patch:
Benchmark #1: ~/src/git/git name-rev --all
Time (mean ± σ): 6.784 s ± 0.160 s [User: 6.567 s, System: 0.214 s]
Range (min … max): 6.638 s … 7.211 s 10 runs
linux w/ commit-graph:
Benchmark #1: ~/src/git/git name-rev --all
Time (mean ± σ): 929.6 ms ± 5.3 ms [User: 881.4 ms, System: 46.8 ms]
Range (min … max): 924.1 ms … 939.5 ms 10 runs
linux w/ commit-graph and patch:
Benchmark #1: ~/src/git/git name-rev --all
Time (mean ± σ): 1.004 s ± 0.007 s [User: 957.4 ms, System: 45.6 ms]
Range (min … max): 0.997 s … 1.021 s 10 runs
We can reuse a strbuf instead of allocating new strings when adding
suffixes to get some of the performance loss back. I guess it's easier
after the recursion is removed. Numbers:
git w/ both patches:
Benchmark #1: ~/src/git/git name-rev --all
Time (mean ± σ): 448.0 ms ± 2.4 ms [User: 428.2 ms, System: 19.6 ms]
Range (min … max): 445.3 ms … 453.4 ms 10 runs
git w/ commit-graph and both patches:
Benchmark #1: ~/src/git/git name-rev --all
Time (mean ± σ): 98.7 ms ± 1.6 ms [User: 93.5 ms, System: 5.0 ms]
Range (min … max): 96.7 ms … 102.8 ms 30 runs
linux w/ both patches:
Benchmark #1: ~/src/git/git name-rev --all
Time (mean ± σ): 6.727 s ± 0.063 s [User: 6.486 s, System: 0.226 s]
Range (min … max): 6.675 s … 6.872 s 10 runs
linux w/ commit-graph and both patches:
Benchmark #1: ~/src/git/git name-rev --all
Time (mean ± σ): 988.8 ms ± 4.5 ms [User: 937.5 ms, System: 49.2 ms]
Range (min … max): 981.4 ms … 994.8 ms 10 runs
---
builtin/name-rev.c | 39 +++++++++++++++++++--------------------
1 file changed, 19 insertions(+), 20 deletions(-)
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 4162fb29ee..7fee664574 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -75,15 +75,14 @@ static int is_better_name(struct rev_name *name,
return 0;
}
-static void name_rev(struct commit *commit,
- const char *tip_name, timestamp_t taggerdate,
+static void name_rev(struct commit *commit, struct strbuf *sb,
+ timestamp_t taggerdate,
int generation, int distance, int from_tag,
int deref)
{
struct rev_name *name = get_commit_rev_name(commit);
struct commit_list *parents;
int parent_number = 1;
- char *to_free = NULL;
parse_commit(commit);
@@ -91,7 +90,7 @@ static void name_rev(struct commit *commit,
return;
if (deref) {
- tip_name = to_free = xstrfmt("%s^0", tip_name);
+ strbuf_addstr(sb, "^0");
if (generation)
die("generation: %d, but deref?", generation);
@@ -99,14 +98,13 @@ static void name_rev(struct commit *commit,
if (!name || is_better_name(name, taggerdate, distance, from_tag)) {
free(name);
- FLEX_ALLOC_STR(name, tip_name, tip_name);
+ FLEX_ALLOC_MEM(name, tip_name, sb->buf, sb->len);
name->taggerdate = taggerdate;
name->generation = generation;
name->distance = distance;
name->from_tag = from_tag;
set_commit_rev_name(commit, name);
} else {
- free(to_free);
return;
}
@@ -114,28 +112,26 @@ static void name_rev(struct commit *commit,
parents;
parents = parents->next, parent_number++) {
if (parent_number > 1) {
- size_t len;
- char *new_name;
-
- strip_suffix(tip_name, "^0", &len);
+ int stripped = strbuf_strip_suffix(sb, "^0");
+ size_t base_len = sb->len;
if (generation > 0)
- new_name = xstrfmt("%.*s~%d^%d", (int)len,
tip_name,
- generation, parent_number);
- else
- new_name = xstrfmt("%.*s^%d", (int)len,
tip_name,
- parent_number);
+ strbuf_addf(sb, "~%d", generation);
+ strbuf_addf(sb, "^%d", parent_number);
- name_rev(parents->item, new_name, taggerdate, 0,
+ name_rev(parents->item, sb, taggerdate, 0,
distance + MERGE_TRAVERSAL_WEIGHT,
from_tag, 0);
- free(new_name);
+ strbuf_setlen(sb, base_len);
+ if (stripped)
+ strbuf_addstr(sb, "^0");
} else {
- name_rev(parents->item, tip_name, taggerdate,
+ size_t base_len = sb->len;
+ name_rev(parents->item, sb, taggerdate,
generation + 1, distance + 1,
from_tag, 0);
+ strbuf_setlen(sb, base_len);
}
}
- free(to_free);
}
static int subpath_matches(const char *path, const char *filter)
@@ -200,6 +196,7 @@ static int tipcmp(const void *a_, const void *b_)
static int name_ref(const char *path, const struct object_id *oid, int flags,
void *cb_data)
{
+ static struct strbuf sb = STRBUF_INIT;
struct object *o = parse_object(the_repository, oid);
struct name_ref_data *data = cb_data;
int can_abbreviate_output = data->tags_only && data->name_only;
@@ -269,7 +266,9 @@ static int name_ref(const char *path, const struct
object_id *oid, int flags, vo
if (taggerdate == TIME_MAX)
taggerdate = ((struct commit *)o)->date;
path = name_ref_abbrev(path, can_abbreviate_output);
- name_rev(commit, path, taggerdate, 0, 0, from_tag, deref);
+ strbuf_reset(&sb);
+ strbuf_addstr(&sb, path);
+ name_rev(commit, &sb, taggerdate, 0, 0, from_tag, deref);
}
return 0;
}
--
2.23.0