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

[PATCH v3 07/13] reftable/merged: circumvent pqueue with single subiter

From
Patrick Steinhardt <ps@pks.im>
Date
Mar 4, 2024, 10:49 UTC
Message-ID
<2199881d476875d37bba0a510e3d74a594b8c61a.1709548907.git.ps@pks.im>
In-Reply-To
<cover.1709548907.git.ps@pks.im>

The merged iterator uses a priority queue to order records so that we can yielid them in the expected order. This priority queue of course comes with some overhead as we need to add, compare and remove entries in that priority queue.

In the general case, that overhead cannot really be avoided. But when we have a single subiter left then there is no need to use the priority queue anymore because the order is exactly the same as what that subiter would return.

While having a single subiter may sound like an edge case, it happens more frequently than one might think. In the most common scenario, you can expect a repository to have a single large table that contains most of the records and then a set of smaller tables which contain later additions to the reftable stack. In this case it is quite likely that we exhaust subiters of those smaller stacks before exhausting the large table.

Special-case this and return records directly from the remaining subiter. This results in a sizeable speedup when iterating over 1m refs in a repository with a single table:

  Benchmark 1: show-ref: single matching ref (revision = HEAD~)
    Time (mean ± σ):     135.4 ms ±   4.4 ms    [User: 132.5 ms, System: 2.8 ms]
    Range (min … max):   131.0 ms … 166.3 ms    1000 runs
  Benchmark 2: show-ref: single matching ref (revision = HEAD)
    Time (mean ± σ):     126.3 ms ±   3.9 ms    [User: 123.3 ms, System: 2.8 ms]
    Range (min … max):   122.7 ms … 157.0 ms    1000 runs
  Summary
    show-ref: single matching ref (revision = HEAD) ran
      1.07 ± 0.05 times faster than show-ref: single matching ref (revision = HEAD~)
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 reftable/merged.c | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/reftable/merged.c b/reftable/merged.c
index d9ed4a19dd..29161a32cf 100644
--- a/reftable/merged.c
+++ b/reftable/merged.c
@@ -87,16 +87,36 @@ static int merged_iter_next_entry(struct merged_iter *mi,
 				  struct reftable_record *rec)
 {
 	struct pq_entry entry = { 0 };
-	int err = 0;
+	int err = 0, empty;
+
+	empty = merged_iter_pqueue_is_empty(mi->pq);
 
 	if (mi->advance_index >= 0) {
+		/*
+		 * When there are no pqueue entries then we only have a single
+		 * subiter left. There is no need to use the pqueue in that
+		 * case anymore as we know that the subiter will return entries
+		 * in the correct order already.
+		 *
+		 * While this may sound like a very specific edge case, it may
+		 * happen more frequently than you think. Most repositories
+		 * will end up having a single large base table that contains
+		 * most of the refs. It's thus likely that we exhaust all
+		 * subiters but the one from that base ref.
+		 */
+		if (empty)
+			return iterator_next(&mi->subiters[mi->advance_index].iter,
+					     rec);
+
 		err = merged_iter_advance_subiter(mi, mi->advance_index);
 		if (err < 0)
 			return err;
+		if (!err)
+			empty = 0;
 		mi->advance_index = -1;
 	}
 
-	if (merged_iter_pqueue_is_empty(mi->pq))
+	if (empty)
 		return 1;
 
 	entry = merged_iter_pqueue_remove(&mi->pq);
-- 
2.44.0
Previous: Patrick SteinhardtNext: Patrick Steinhardt
Message 45 of 51 in “reftable: improve ref iteration performance (pt.2)”
  1. 00/12 reftable: improve ref iteration performance (pt.2)Patrick Steinhardt, Feb 14, 2024
  2. 01/12 reftable/pq: use `size_t` to track iterator indexPatrick Steinhardt, Feb 14, 2024
  3. 02/12 reftable/merged: make `merged_iter` structure privatePatrick Steinhardt, Feb 14, 2024
  4. Justin ToblerFeb 20, 2024
  5. Patrick SteinhardtFeb 27, 2024
  6. 03/12 reftable/merged: advance subiter on subsequent iterationPatrick Steinhardt, Feb 14, 2024
  7. Justin ToblerFeb 20, 2024
  8. Patrick SteinhardtFeb 27, 2024
  9. 04/12 reftable/merged: make subiters own their recordsPatrick Steinhardt, Feb 14, 2024
  10. 05/12 reftable/merged: remove unnecessary null check for subitersPatrick Steinhardt, Feb 14, 2024
  11. 06/12 reftable/merged: handle subiter cleanup on close onlyPatrick Steinhardt, Feb 14, 2024
  12. 07/12 reftable/merged: circumvent pqueue with single subiterPatrick Steinhardt, Feb 14, 2024
  13. 08/12 reftable/merged: avoid duplicate pqueue emptiness checkPatrick Steinhardt, Feb 14, 2024
  14. James LiuFeb 27, 2024
  15. 09/12 reftable/record: reuse refname when decodingPatrick Steinhardt, Feb 14, 2024
  16. James LiuFeb 28, 2024
  17. Patrick SteinhardtMar 4, 2024
  18. 10/12 reftable/record: reuse refname when copyingPatrick Steinhardt, Feb 14, 2024
  19. James LiuFeb 28, 2024
  20. 11/12 reftable/record: decode keys in placePatrick Steinhardt, Feb 14, 2024
  21. James LiuFeb 28, 2024
  22. Patrick SteinhardtMar 4, 2024
  23. 12/12 reftable: allow inlining of a few functionsPatrick Steinhardt, Feb 14, 2024
  24. 00/13 reftable: improve ref iteration performance (pt.2)Patrick Steinhardt, Feb 27, 2024
  25. 01/13 reftable/pq: use `size_t` to track iterator indexPatrick Steinhardt, Feb 27, 2024
  26. 02/13 reftable/merged: make `merged_iter` structure privatePatrick Steinhardt, Feb 27, 2024
  27. 03/13 reftable/merged: advance subiter on subsequent iterationPatrick Steinhardt, Feb 27, 2024
  28. 04/13 reftable/merged: make subiters own their recordsPatrick Steinhardt, Feb 27, 2024
  29. 05/13 reftable/merged: remove unnecessary null check for subitersPatrick Steinhardt, Feb 27, 2024
  30. 06/13 reftable/merged: handle subiter cleanup on close onlyPatrick Steinhardt, Feb 27, 2024
  31. 07/13 reftable/merged: circumvent pqueue with single subiterPatrick Steinhardt, Feb 27, 2024
  32. 08/13 reftable/merged: avoid duplicate pqueue emptiness checkPatrick Steinhardt, Feb 27, 2024
  33. 09/13 reftable/record: reuse refname when decodingPatrick Steinhardt, Feb 27, 2024
  34. 10/13 reftable/record: reuse refname when copyingPatrick Steinhardt, Feb 27, 2024
  35. 11/13 reftable/record: decode keys in placePatrick Steinhardt, Feb 27, 2024
  36. 12/13 reftable: allow inlining of a few functionsPatrick Steinhardt, Feb 27, 2024
  37. 13/13 refs/reftable: precompute prefix lengthPatrick Steinhardt, Feb 27, 2024
  38. 00/13 reftable: improve ref iteration performance (pt.2)Patrick Steinhardt, Mar 4, 2024
  39. 01/13 reftable/pq: use `size_t` to track iterator indexPatrick Steinhardt, Mar 4, 2024
  40. 02/13 reftable/merged: make `merged_iter` structure privatePatrick Steinhardt, Mar 4, 2024
  41. 03/13 reftable/merged: advance subiter on subsequent iterationPatrick Steinhardt, Mar 4, 2024
  42. 04/13 reftable/merged: make subiters own their recordsPatrick Steinhardt, Mar 4, 2024
  43. 05/13 reftable/merged: remove unnecessary null check for subitersPatrick Steinhardt, Mar 4, 2024
  44. 06/13 reftable/merged: handle subiter cleanup on close onlyPatrick Steinhardt, Mar 4, 2024
  45. 07/13 reftable/merged: circumvent pqueue with single subiterPatrick Steinhardt, Mar 4, 2024
  46. 08/13 reftable/merged: avoid duplicate pqueue emptiness checkPatrick Steinhardt, Mar 4, 2024
  47. 09/13 reftable/record: reuse refname when decodingPatrick Steinhardt, Mar 4, 2024
  48. 10/13 reftable/record: reuse refname when copyingPatrick Steinhardt, Mar 4, 2024
  49. 11/13 reftable/record: decode keys in placePatrick Steinhardt, Mar 4, 2024
  50. 12/13 reftable: allow inlining of a few functionsPatrick Steinhardt, Mar 4, 2024
  51. 13/13 refs/reftable: precompute prefix lengthPatrick Steinhardt, Mar 4, 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.