git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 08/15] name-rev: pull out deref handling from the recursion

From
René Scharfe <l.s.r@web.de>
Date
Sep 24, 2019, 17:03 UTC
Message-ID
<ce55a33b-aa8b-9325-fe87-8ff4c7e02627@web.de>
In-Reply-To
<20190923204714.GC2637@szeder.dev>
Am 23.09.19 um 22:47 schrieb SZEDER Gábor:
Show 17 quoted lines
> 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
Previous: SZEDER GáborNext: SZEDER Gábor
Message 36 of 98 in “name-rev: eliminate recursion”
  1. 00/15 name-rev: eliminate recursionSZEDER Gábor, Sep 19, 2019
  2. 01/15 t6120-describe: correct test repo history graph in commentSZEDER Gábor, Sep 19, 2019
  3. Junio C HamanoSep 20, 2019
  4. SZEDER GáborSep 20, 2019
  5. Junio C HamanoSep 28, 2019
  6. 02/15 t6120-describe: modernize the 'check_describe' helperSZEDER Gábor, Sep 19, 2019
  7. Junio C HamanoSep 20, 2019
  8. 03/15 name-rev: use strip_suffix() in get_rev_name()SZEDER Gábor, Sep 19, 2019
  9. René ScharfeSep 20, 2019
  10. SZEDER GáborSep 20, 2019
  11. 05/15 name-rev: use sizeof(*ptr) instead of sizeof(type) in allocationSZEDER Gábor, Sep 19, 2019
  12. Derrick StoleeSep 20, 2019
  13. SZEDER GáborSep 20, 2019
  14. René ScharfeSep 20, 2019
  15. 06/15 t6120: add a test to cover inner conditions in 'git name-rev's name_rev()SZEDER Gábor, Sep 19, 2019
  16. Derrick StoleeSep 20, 2019
  17. SZEDER GáborSep 20, 2019
  18. 04/15 name-rev: avoid unnecessary cast in name_ref()SZEDER Gábor, Sep 19, 2019
  19. René ScharfeSep 20, 2019
  20. 10/15 name-rev: restructure creating/updating 'struct rev_name' instancesSZEDER Gábor, Sep 19, 2019
  21. Derrick StoleeSep 20, 2019
  22. SZEDER GáborSep 20, 2019
  23. 08/15 name-rev: pull out deref handling from the recursionSZEDER Gábor, Sep 19, 2019
  24. Derrick StoleeSep 20, 2019
  25. SZEDER GáborSep 20, 2019
  26. René ScharfeSep 20, 2019
  27. SZEDER GáborSep 20, 2019
  28. SZEDER GáborSep 20, 2019
  29. SZEDER GáborSep 21, 2019
  30. René ScharfeSep 21, 2019
  31. SZEDER GáborSep 22, 2019
  32. René ScharfeSep 23, 2019
  33. SZEDER GáborSep 23, 2019
  34. René ScharfeSep 23, 2019
  35. SZEDER GáborSep 23, 2019
  36. René ScharfeSep 24, 2019
  37. SZEDER GáborSep 26, 2019
  38. René ScharfeSep 21, 2019
  39. SZEDER GáborSep 21, 2019
  40. René ScharfeSep 21, 2019
  41. 09/15 name-rev: restructure parsing commits and applying date cutoffSZEDER Gábor, Sep 19, 2019
  42. René ScharfeSep 21, 2019
  43. 07/15 name-rev: extract creating/updating a 'struct name_rev' into a helperSZEDER Gábor, Sep 19, 2019
  44. Derrick StoleeSep 20, 2019
  45. name-rev: rewrite create_or_update_name()Martin Ågren, Sep 22, 2019
  46. SZEDER GáborDec 9, 2019
  47. 11/15 name-rev: drop name_rev()'s 'generation' and 'distance' parametersSZEDER Gábor, Sep 19, 2019
  48. 13/15 name-rev: cleanup name_ref()SZEDER Gábor, Sep 19, 2019
  49. 12/15 name-rev: eliminate recursion in name_rev()SZEDER Gábor, Sep 19, 2019
  50. 14/15 name-rev: plug a memory leak in name_rev()SZEDER Gábor, Sep 19, 2019
  51. 15/15 name-rev: plug a memory leak in name_rev() in the deref caseSZEDER Gábor, Sep 19, 2019
  52. Derrick StoleeSep 20, 2019
  53. 14/15 name-rev: plug memory leak in name_rev() in the deref caseSZEDER Gábor, Sep 19, 2019
  54. SZEDER GáborSep 19, 2019
  55. 15/15 name-rev: plug memory leak in name_rev()SZEDER Gábor, Sep 19, 2019
  56. SZEDER GáborSep 19, 2019
  57. Derrick StoleeSep 20, 2019
  58. SZEDER GáborSep 20, 2019
  59. 00/13 name-rev: eliminate recursionSZEDER Gábor, Nov 12, 2019
  60. 01/13 t6120-describe: correct test repo history graph in commentSZEDER Gábor, Nov 12, 2019
  61. 03/13 name-rev: use strbuf_strip_suffix() in get_rev_name()SZEDER Gábor, Nov 12, 2019
  62. René ScharfeNov 12, 2019
  63. 02/13 t6120-describe: modernize the 'check_describe' helperSZEDER Gábor, Nov 12, 2019
  64. Jonathan TanNov 27, 2019
  65. 07/13 name-rev: extract creating/updating a 'struct name_rev' into a helperSZEDER Gábor, Nov 12, 2019
  66. 05/13 name-rev: use sizeof(*ptr) instead of sizeof(type) in allocationSZEDER Gábor, Nov 12, 2019
  67. 08/13 name-rev: pull out deref handling from the recursionSZEDER Gábor, Nov 12, 2019
  68. 06/13 t6120: add a test to cover inner conditions in 'git name-rev's name_rev()SZEDER Gábor, Nov 12, 2019
  69. 09/13 name-rev: restructure parsing commits and applying date cutoffSZEDER Gábor, Nov 12, 2019
  70. 04/13 name-rev: avoid unnecessary cast in name_ref()SZEDER Gábor, Nov 12, 2019
  71. 11/13 name-rev: drop name_rev()'s 'generation' and 'distance' parametersSZEDER Gábor, Nov 12, 2019
  72. Jonathan TanNov 27, 2019
  73. 13/13 name-rev: cleanup name_ref()SZEDER Gábor, Nov 12, 2019
  74. Jonathan TanNov 27, 2019
  75. SZEDER GáborDec 9, 2019
  76. 10/13 name-rev: restructure creating/updating 'struct rev_name' instancesSZEDER Gábor, Nov 12, 2019
  77. 12/13 name-rev: eliminate recursion in name_rev()SZEDER Gábor, Nov 12, 2019
  78. Jonathan TanNov 27, 2019
  79. SZEDER GáborDec 9, 2019
  80. Johannes SchindelinNov 12, 2019
  81. Sebastiaan DammannNov 13, 2019
  82. 00/14 name-rev: eliminate recursionSZEDER Gábor, Dec 9, 2019
  83. 01/14 t6120-describe: correct test repo history graph in commentSZEDER Gábor, Dec 9, 2019
  84. 02/14 t6120-describe: modernize the 'check_describe' helperSZEDER Gábor, Dec 9, 2019
  85. 03/14 name-rev: use strbuf_strip_suffix() in get_rev_name()SZEDER Gábor, Dec 9, 2019
  86. 04/14 name-rev: avoid unnecessary cast in name_ref()SZEDER Gábor, Dec 9, 2019
  87. 05/14 name-rev: use sizeof(*ptr) instead of sizeof(type) in allocationSZEDER Gábor, Dec 9, 2019
  88. 07/14 name-rev: extract creating/updating a 'struct name_rev' into a helperSZEDER Gábor, Dec 9, 2019
  89. 06/14 t6120: add a test to cover inner conditions in 'git name-rev's name_rev()SZEDER Gábor, Dec 9, 2019
  90. 08/14 name-rev: pull out deref handling from the recursionSZEDER Gábor, Dec 9, 2019
  91. 11/14 name-rev: drop name_rev()'s 'generation' and 'distance' parametersSZEDER Gábor, Dec 9, 2019
  92. 12/14 name-rev: use 'name->tip_name' instead of 'tip_name'SZEDER Gábor, Dec 9, 2019
  93. 10/14 name-rev: restructure creating/updating 'struct rev_name' instancesSZEDER Gábor, Dec 9, 2019
  94. 09/14 name-rev: restructure parsing commits and applying date cutoffSZEDER Gábor, Dec 9, 2019
  95. 14/14 name-rev: cleanup name_ref()SZEDER Gábor, Dec 9, 2019
  96. 13/14 name-rev: eliminate recursion in name_rev()SZEDER Gábor, Dec 9, 2019
  97. Derrick StoleeDec 9, 2019
  98. Junio C HamanoDec 11, 2019

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.