Skip to content

perf: unmeasured leads from the whole-repo audit behind #457 #458

Closed

Description

@CMGS

Performance leads the static audit behind #457 found and left without code, because none is measured end to end. Each needs an interleaved A/B (or a hold-time measurement) before a change; the expected effect below is an estimate.

Where Lead What to measure
store/s3/s3.go Metas GETs labels.json for every record, though only templates carry labels: one extra 404 GET per checkpoint on every GET /v1/checkpoints and hourly TTL sweep S3 request count and listing latency at a few thousand checkpoints
server/server.go checkpoint claim on a shared S3 store An unknown checkpoint still probes every peer, which answer from the same bucket; a genuine miss waits for every peer (up to the 1 s probe timeout) before 404 miss latency with and without the prober on a shared store
pool/archive.go wakeArchived Deletes the consumed archive checkpoint (several sequential S3 round trips) and drops the tombstone while holding the claim's transition, before the relay gets its socket; the pre-commit marker already makes the delete retryable archived-wake latency, delete inline vs in the background
store/peer/move.go, store/sparse.go Every live-move round hashes each non-zero chunk on both sides; the final round's hashes sit inside the guest's pause final-round pause with and without the hash on the 2xlarge tier
silkd/src/server.rs feed_client Each stdin/data frame decodes into a fresh buffer (up to 768 KiB for a 1 MiB port chunk) because the decode takes the scratch port-forward throughput and allocation rate
silkd/src/find.rs fs_replace replace_all over up to 8 MiB runs on the tokio worker; a 1-vCPU guest stalls other relays for that pass relay latency during a large replace
pool/telemetry.go egress decisions Each decision appends a usage line (and an audit line with audit_log) under the node-wide journal lock before the response header request time to first byte under load
pool/liveness.go onVMChange Each VM-down/deleted event walks every claim under the manager lock (no VM-name index) lock hold time at 20000 claims under release load
pool/claim.go admission at the cap Concurrent claims at the last free slot each pop a warm VM; all but one fail at finalize and their VMs are destroyed a burst at the cap: refill clones per refused claim
pool/template.go promoted-template claim on S3 Each claim GETs meta.json even when the generation is cached (two for a checkpoint claim) promoted-template claim p50, S3 vs dir store

Activity

  1. CMGS commented on Nov 5, 2026

    @CMGS
    ContributorAuthor

    Progress on 2026-11-05.

    Measured and done:

    Split into issues, each with its measurement and trigger:

    Still open here, not measured yet:

    • feed_client decode buffer (silkd). A measurement of write_frame's per-frame write buffer (0.1-0.3 µs) was taken by mistake. It says nothing about this lead, the fresh decode buffer per stdin or data frame on the read side.
    • Usage and audit line on every egress decision, under the node-wide journal lock. Only the uncontended append was measured: 2.3 µs per event on the test host. Contention across many claims' proxies, and time to first byte under load, are not measured.
    • Claims racing at the last free slot, each popping a warm VM.
    • A promoted-template claim GETting meta.json on S3 even when the generation is cached.
  2. CMGS commented on Nov 5, 2026

    @CMGS
    ContributorAuthor

    The remaining four leads, measured on 2026-11-05. All 10 leads now have an outcome, so this issue closes.

    lead measured outcome
    silkd feed_client decode buffer Fresh per frame vs recycled, ABBA, 4 rounds. 64 KiB: 24.2 vs 23.2 µs; 256 KiB: 93 vs 91 µs; 768 KiB: 272 vs 268 µs (mac), 283 vs 277 µs (linux/arm64, glibc). Base64 decoding is the cost; the allocation is 1-4%. The 16-frame input channel bounds what a stream holds either way (about 12 MiB at 768 KiB frames). dropped
    usage and audit append on every egress decision 2.5 µs (usage) and 5.2 µs (usage + audit) per decision. With 2-12 concurrent callers, throughput flattens at about 3.4 µs (usage) and 4.5 µs (with audit) per decision: the journal lock serializes them at roughly 300k and 220k decisions/s per node. At 10k egress decisions/s the lock is busy about 3.4% of the time. dropped; revisit past about 50k decisions/s per node
    claims racing at the last free slot Bursts of 2, 4 and 8 claims at one free slot (in-process engine, 20 bursts each): 1 winner, and 0.6, 1.4 and 1.5 warm VMs destroyed per burst fixed in #465 (admission holds the slot until the commit)
    promoted-template meta.json GET on S3 1 GET per warm-miss claim even when the generation is cached (10 fetches, 10 requests); 2 for a checkpoint claim #466: the GET is the freshness check for deletes and republishes

    Earlier on this issue: #459, #460, #461 and #462 merged; #463 and #464 opened.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions