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

Re: [PATCH 03/12] reftable/merged: advance subiter on subsequent iteration

From
Justin Tobler <jltobler@gmail.com>
Date
Feb 20, 2024, 18:25 UTC
Message-ID
<ns2yw3icnl3udejbgsv4ojwgzbe7eg57bvsm53kciuemlvmgbr@mpjtogpzdavi>
In-Reply-To
<38d45995662ba92f4b985b82deac298446274511.1707895758.git.ps@pks.im>
On 24/02/14 08:45AM, Patrick Steinhardt wrote:
> When advancing the merged iterator, we pop the top-most entry from its
s/top-most/topmost
> priority queue and then advance the sub-iterator that the entry belongs
> to, adding the result as a new entry. This is quite sensible in the case
> where the merged iterator is used to actual iterate through records. But
s/actual/actually
Show 62 quoted lines
> the merged iterator is also used when we look up a single record, only,
> so advancing the sub-iterator is wasted effort because we would never
> even look at the result.
> 
> Instead of immediately advancing the sub-iterator, we can also defer
> this to the next iteration of the merged iterator by storing the
> intent-to-advance. This results in a small speedup when reading many
> records. The following benchmark creates 10000 refs, which will also end
> up with many ref lookups:
> 
>     Benchmark 1: update-ref: create many refs (revision = HEAD~)
>       Time (mean ± σ):     337.2 ms ±   7.3 ms    [User: 200.1 ms, System: 136.9 ms]
>       Range (min … max):   329.3 ms … 373.2 ms    100 runs
> 
>     Benchmark 2: update-ref: create many refs (revision = HEAD)
>       Time (mean ± σ):     332.5 ms ±   5.9 ms    [User: 197.2 ms, System: 135.1 ms]
>       Range (min … max):   327.6 ms … 359.8 ms    100 runs
> 
>     Summary
>       update-ref: create many refs (revision = HEAD) ran
>         1.01 ± 0.03 times faster than update-ref: create many refs (revision = HEAD~)
> 
> While this speedup alone isn't really worth it, this refactoring will
> also allow two additional optimizations in subsequent patches. First, it
> will allow us to special-case when there is only a single sub-iter left
> to circumvent the priority queue altogether. And second, it makes it
> easier to avoid copying records to the caller.
> 
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  reftable/merged.c | 26 ++++++++++++--------------
>  1 file changed, 12 insertions(+), 14 deletions(-)
> 
> diff --git a/reftable/merged.c b/reftable/merged.c
> index 12ebd732e8..9b1ccfff00 100644
> --- a/reftable/merged.c
> +++ b/reftable/merged.c
> @@ -19,11 +19,12 @@ license that can be found in the LICENSE file or at
>  
>  struct merged_iter {
>  	struct reftable_iterator *stack;
> +	struct merged_iter_pqueue pq;
>  	uint32_t hash_id;
>  	size_t stack_len;
>  	uint8_t typ;
>  	int suppress_deletions;
> -	struct merged_iter_pqueue pq;
> +	ssize_t advance_index;
>  };
>  
>  static int merged_iter_init(struct merged_iter *mi)
> @@ -96,13 +97,17 @@ static int merged_iter_next_entry(struct merged_iter *mi,
>  	struct pq_entry entry = { 0 };
>  	int err = 0;
>  
> +	if (mi->advance_index >= 0) {
> +		err = merged_iter_advance_subiter(mi, mi->advance_index);
> +		if (err < 0)
> +			return err;
> +		mi->advance_index = -1;
> +	}
> +

Without additional context, it isn't immediately clear to me why the sub-iterator is condionally advanced at the beginning. Maybe a comment could be added to explain as done in the commit message to help with clarity?

Show 22 quoted lines
>  	if (merged_iter_pqueue_is_empty(mi->pq))
>  		return 1;
>  
>  	entry = merged_iter_pqueue_remove(&mi->pq);
> -	err = merged_iter_advance_subiter(mi, entry.index);
> -	if (err < 0)
> -		return err;
>  
>  	/*
>  	  One can also use reftable as datacenter-local storage, where the ref
> @@ -116,14 +121,6 @@ static int merged_iter_next_entry(struct merged_iter *mi,
>  		struct pq_entry top = merged_iter_pqueue_top(mi->pq);
>  		int cmp;
>  
> -		/*
> -		 * When the next entry comes from the same queue as the current
> -		 * entry then it must by definition be larger. This avoids a
> -		 * comparison in the most common case.
> -		 */
> -		if (top.index == entry.index)
> -			break;
> -

I'm not quite sure I follow by the above check is removed as part of this change. Would you mind clarifying?

-Justin
Previous: Patrick SteinhardtNext: Patrick Steinhardt
Message 7 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.