Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: git/git
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: bc627658b06155a0b1c3d0b1b0bf72db70770dc9
Choose a base ref
...
head repository: git/git
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2e7c6d2f4112dd374f615f4e612e1cebbcb6d431
Choose a head ref
  • 1 commit
  • 1 file changed
  • 1 contributor

Commits on Oct 21, 2024

  1. ref-filter: format iteratively with lexicographic refname sorting

    In bd98f97 (ref-filter.c: filter & format refs in the same callback,
    2023-11-14), we have introduced logic into the ref-filter subsystem that
    determines whether or not we can output references iteratively instead
    of first collecting all references, post-processing them and printing
    them once done. This has the advantage that we don't have to store all
    refs in memory and, when used with e.g. `--count=1`, that we don't have
    to read all refs in the first place.
    
    One restriction we have in place for that is that caller must not ask
    for sorted refs, because there is no way to sort the refs without first
    reading them all into an array. So the benefits can only be reaped when
    explicitly asking for output not to be sorted.
    
    But there is one exception here where we _can_ get away with sorting
    refs while streaming: ref backends sort references returned by their
    iterators in lexicographic order. So if the following conditions are all
    true we can do iterative streaming:
    
      - There must be at most a single sorting specification, as otherwise
        we're not using plain lexicographic ordering.
    
      - The sorting specification must use the "refname".
    
      - The sorting specification must not be using any flags, like
        case-insensitive sorting.
    
    Now the resulting logic does feel quite fragile overall, which makes me
    a bit uneasy. But after thinking about this for a while I couldn't find
    any obvious gaps in my reasoning. Furthermore, given that lexicographic
    sorting order is the default in git-for-each-ref(1), this is likely to
    benefit a whole lot of usecases out there.
    
    The following benchmark executes git-for-each-ref(1) in a crafted repo
    with 1 million references:
    
      Benchmark 1: git for-each-ref (revision = HEAD~)
        Time (mean ± σ):      6.756 s ±  0.014 s    [User: 3.004 s, System: 3.541 s]
        Range (min … max):    6.738 s …  6.784 s    10 runs
    
      Benchmark 2: git for-each-ref (revision = HEAD)
        Time (mean ± σ):      6.479 s ±  0.017 s    [User: 2.858 s, System: 3.422 s]
        Range (min … max):    6.450 s …  6.519 s    10 runs
    
      Summary
        git for-each-ref (revision = HEAD)
          1.04 ± 0.00 times faster than git for-each-ref (revision = HEAD~)
    
    The change results in a slight performance improvement, but nothing that
    would really stand out. Something that cannot be seen in the benchmark
    though is peak memory usage, which went from 404.5MB to 68.96kB.
    
    A more interesting benchmark is printing a single referenence with
    `--count=1`:
    
      Benchmark 1: git for-each-ref --count=1 (revision = HEAD~)
        Time (mean ± σ):      6.655 s ±  0.018 s    [User: 2.865 s, System: 3.576 s]
        Range (min … max):    6.630 s …  6.680 s    10 runs
    
      Benchmark 2: git for-each-ref --count=1 (revision = HEAD)
        Time (mean ± σ):       8.6 ms ±   1.3 ms    [User: 2.3 ms, System: 6.1 ms]
        Range (min … max):     6.7 ms …  14.4 ms    266 runs
    
      Summary
        git git for-each-ref --count=1 (revision = HEAD)
        770.58 ± 116.19 times faster than git for-each-ref --count=1 (revision = HEAD~)
    
    Whereas we scaled with the number of references before, we now print the
    first reference and exit immediately, which provides a massive win.
    
    Signed-off-by: Patrick Steinhardt <ps@pks.im>
    Signed-off-by: Taylor Blau <me@ttaylorr.com>
    pks-t authored and ttaylorr committed Oct 21, 2024
    Configuration menu
    Copy the full SHA
    2e7c6d2 View commit details
    Browse the repository at this point in the history
Loading