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

[PATCH 3/7] reftable/record: avoid copying author info

From
Patrick Steinhardt <ps@pks.im>
Date
Mar 5, 2024, 12:11 UTC
Message-ID
<6f568e4ccb67a7af8279352153d052c5f9a88234.1709640322.git.ps@pks.im>
In-Reply-To
<cover.1709640322.git.ps@pks.im>

Each reflog entry contains information regarding the authorship of who has made the change. This authorship information is not the same as that of any of the commits that the reflog entry references, but instead corresponds to the local user that has executed the command. Thus, it is almost always the case that all reflog entries have the same author.

We can make use of this fact when decoding reftable records: instead of freeing and then reallocating the authorship information of log records, we can special-case when the next record during an iteration has the exact same authorship as the preceding record. If so, then there is no need to reallocate the respective fields.

This change results in two allocations less per log record that we're iterating over in the most common case. Before:

    HEAP SUMMARY:
        in use at exit: 13,473 bytes in 122 blocks
      total heap usage: 6,068,489 allocs, 6,068,367 frees, 361,011,822 bytes allocated
After:
    HEAP SUMMARY:
        in use at exit: 13,473 bytes in 122 blocks
      total heap usage: 4,068,487 allocs, 4,068,365 frees, 332,011,793 bytes allocated

An alternative would be to store the capacity of both name and email and then use `REFTABLE_ALLOC_GROW()` to conditionally reallocate the array. But reftable records are copied around quite a lot, and thus we need to be a bit mindful of the overall record size. Furthermore, a memory comparison should also be more efficient than having to copy over memory even if we wouldn't have to allocate a new array every time.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 reftable/record.c | 29 +++++++++++++++++++++--------
 1 file changed, 21 insertions(+), 8 deletions(-)
diff --git a/reftable/record.c b/reftable/record.c
index 8d2cd6b081..d816de6d93 100644
--- a/reftable/record.c
+++ b/reftable/record.c
@@ -896,10 +896,19 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
 		goto done;
 	string_view_consume(&in, n);
 
-	r->value.update.name =
-		reftable_realloc(r->value.update.name, dest.len + 1);
-	memcpy(r->value.update.name, dest.buf, dest.len);
-	r->value.update.name[dest.len] = 0;
+	/*
+	 * In almost all cases we can expect the reflog name to not change for
+	 * reflog entries as they are tied to the local identity, not to the
+	 * target commits. As an optimization for this common case we can thus
+	 * skip copying over the name in case it's accurate already.
+	 */
+	if (!r->value.update.name ||
+	    strcmp(r->value.update.name, dest.buf)) {
+		r->value.update.name =
+			reftable_realloc(r->value.update.name, dest.len + 1);
+		memcpy(r->value.update.name, dest.buf, dest.len);
+		r->value.update.name[dest.len] = 0;
+	}
 
 	strbuf_reset(&dest);
 	n = decode_string(&dest, in);
@@ -907,10 +916,14 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
 		goto done;
 	string_view_consume(&in, n);
 
-	r->value.update.email =
-		reftable_realloc(r->value.update.email, dest.len + 1);
-	memcpy(r->value.update.email, dest.buf, dest.len);
-	r->value.update.email[dest.len] = 0;
+	/* Same as above, but for the reflog email. */
+	if (!r->value.update.email ||
+	    strcmp(r->value.update.email, dest.buf)) {
+		r->value.update.email =
+			reftable_realloc(r->value.update.email, dest.len + 1);
+		memcpy(r->value.update.email, dest.buf, dest.len);
+		r->value.update.email[dest.len] = 0;
+	}
 
 	ts = 0;
 	n = get_var_int(&ts, &in);
-- 
2.44.0
Previous: Patrick SteinhardtNext: James Liu
Message 9 of 20 in “reftable: memory optimizations for reflog iteration”
  1. 0/7 reftable: memory optimizations for reflog iterationPatrick Steinhardt, Mar 5, 2024
  2. 1/7 refs/reftable: reload correct stack when creating reflog iterPatrick Steinhardt, Mar 5, 2024
  3. Karthik NayakMar 6, 2024
  4. Junio C HamanoMar 6, 2024
  5. Patrick SteinhardtMar 7, 2024
  6. Josh SteadmonMar 11, 2024
  7. Patrick SteinhardtMar 11, 2024
  8. 2/7 reftable/record: convert old and new object IDs to arraysPatrick Steinhardt, Mar 5, 2024
  9. 3/7 reftable/record: avoid copying author infoPatrick Steinhardt, Mar 5, 2024
  10. James LiuMar 13, 2024
  11. Patrick SteinhardtMar 21, 2024
  12. 4/7 reftable/record: reuse refnames when decoding log recordsPatrick Steinhardt, Mar 5, 2024
  13. 5/7 reftable/record: reuse message when decoding log recordsPatrick Steinhardt, Mar 5, 2024
  14. 6/7 reftable/record: use scratch buffer when decoding recordsPatrick Steinhardt, Mar 5, 2024
  15. Josh SteadmonMar 11, 2024
  16. Patrick SteinhardtMar 11, 2024
  17. Josh SteadmonMar 11, 2024
  18. 7/7 refs/reftable: track last log record name via strbufPatrick Steinhardt, Mar 5, 2024
  19. Josh SteadmonMar 11, 2024
  20. Patrick SteinhardtMar 11, 2024

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.