Skip to main content

Performance

Cold and warm sync timings for esysrepo (libgit2 / hybrid / gitcmdline) versus Google’s repo tool, from CI esysrepo-bench matrices.

The charts match the internal Grafana dashboards (durations in seconds):

  1. Sync duration — grouped bars for the latest samples across j1 / j4 / j8: esysrepo (libgit2 / hybrid / gitcmdline) vs Google repo (filters: manifest_tier, sync_mode).
  2. Duration over time — the same four series over time (filters: manifest_tier including future large, -j, sync_mode).

Data is loaded from same-origin /metrics/performance/latest.json. On production, a Pages Function serves live R2 data without a site rebuild (ADR-0005). On staging (GitLab Pages), docs CI bakes a snapshot of that JSON into the static tree (ADR-0006) so charts can be verified — use Grafana for realtime trends.

Loading charts…

Clone/fetch CPU profiles (FlameGraphs)

Matrix timings show libgit2 colder sync slower than gitcmdline / Google repo on non-trivial histories (often ~2–3× on clone/fetch-heavy work). To attribute CPU time, CI runs erepo-bench profile (linux:bench:profile): Linux perf samples a cold sync, then FlameGraph builds an SVG.

How to read a FlameGraph: the x-axis is the share of CPU samples (wider = hotter). The y-axis is call-stack depth. Use the toolbar (or scroll-wheel zoom and drag-pan) to inspect frames. System git stacks need debug symbols (git-dbgsym); without them frames collapse to [git] / libraries only.

libgit2 backend

Cold sync with ESYSREPO_GIT_BACKEND=libgit2 (medium tier, -j1).

Loading flamegraph…

What dominates

  • Collision-detecting SHA-1 (SHA1DC): frames such as sha1_compression_states, ubc_check, sha1_process.
  • zlib inflate (inflate_fast / related) while unpacking the pack.
  • libgit2’s pack indexer / receive path — not esysrepo progress wrappers or logging.

Threading

  • Pack indexing on clone/fetch is effectively single-threaded. libgit2 exposes thread knobs for packbuilder (push / creating packs), not for the indexer used when receiving a pack. There is no pack.threads-style API for this path today.

gitcmdline backend

Cold sync with ESYSREPO_GIT_BACKEND=gitcmdline (medium tier, -j1), profiled with git-dbgsym so frames resolve into git itself.

Loading flamegraph…

What dominates

  • Still pack work: almost all of git is cmd_index_pack (index a received pack), with the same SHA1DC + zlib diet as libgit2.
  • Transport appears as a separate ssh process slice (not pack CPU).

Threading

  • Second pass is multi-threaded: start_threadthreaded_second_passresolve_delta (git’s pack.threads / index-pack workers).
  • First pass (parse/unpack as the pack streams in) remains largely serial; parallelism is concentrated in delta resolution.

What this means

libgit2gitcmdline (system git)
Hot workIndexer + SHA1DC + zlibindex-pack + SHA1DC + zlib
Delta resolveSingle-threadedMulti-threaded (threaded_second_pass)
Controllable threadsPackbuilder (push) onlypack.threads / index-pack
  • The gap is not “git avoids SHA1DC.” Both backends spend heavy CPU on SHA1DC and inflate; git spreads the heavy second pass across cores, libgit2 does not on fetch/clone.
  • That validates routing clone/fetch through hybrid / gitcmdline while keeping libgit2 for operations that need its API (see product ADR-0025).
  • Upstream libgit2 has long-standing clone-vs-git performance issues and an open indexer optimization PR, but no shipped multi-threaded indexer API; adding one is a large library change, not a one-line option.

How we capture: erepo-bench profile --sync-tier … --git-backend … locally, or manual CI jobs linux:bench:profile / windows:bench:profile. SVGs on this page are curated snapshots from those Linux runs (replace files under website/static/img/performance/ to refresh).

How data is published

  1. Manual / scheduled linux:bench:matrix pushes each cell to VictoriaMetrics (same TSDB Grafana uses) via esys-metrics.
  2. publish:performance:site queries the last ≈14 days of esys_bench_duration_seconds from VictoriaMetrics, writes latest.json, and uploads it to R2 (docs/esysrepo/metrics/performance/).
  3. A Cloudflare Pages Function serves that object at https://esysrepo.libesys.org/metrics/performance/latest.json.

The over-time chart auto-fits the x-axis to the samples present (no empty left padding when history is shorter than 14 days).