Skip to content

test-suites: pipelined score-collision ZINCRBY throughput spec (1M elements, pipeline-10) - #434

Open
fcostaoliveira wants to merge 1 commit into
redis:mainfrom
fcostaoliveira:zincrby-score-collision-pipeline-10
Open

test-suites: pipelined score-collision ZINCRBY throughput spec (1M elements, pipeline-10)#434
fcostaoliveira wants to merge 1 commit into
redis:mainfrom
fcostaoliveira:zincrby-score-collision-pipeline-10

Conversation

@fcostaoliveira

@fcostaoliveira fcostaoliveira commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

What

Adds a throughput counterpart to the pipeline-1 score-collision ZINCRBY spec added in #430:

memtier_benchmark-1key-zincrby-1M-elements-score-collision-pipeline-10

Bumps the package version to 0.3.26.

Why

The existing …-score-collision-pipeline-1 spec is a per-op latency probe (-c 1 -t 1 --pipeline 1). It successfully drives every ZINCRBY onto the skiplist's equal-score-run path — all 1M members start at score 0, so the live scores stay concentrated in a narrow translating integer band and each reinsert lands into a dense equal-score run, where zslCompareWithNode falls back to member-string sdscmp instead of the cheap early-terminating score compare.

But at --pipeline 1 the single-connection Ops/sec is bounded by the per-op kernel write() syscall, which masks the per-op skiplist-walk CPU cost. So the pipeline-1 spec cannot show whether a change to the equal-score-run walk moves throughput.

This variant saturates the single-threaded server core (-t 4 -c 50 = 200 connections, --pipeline 10, --test-time 180), amortizing the syscall ~10× so the equal-score-run walk becomes the binding constraint and surfaces as an Ops/sec delta.

Design notes

  • Reuses the 0.3.24: skiplist score-collision ZINCRBY + 64KiB RAW GET coverage #430 dataset (dataset_name: 1key-zset-1M-elements-score-collision) — the preload is byte-identical, so the 1M-member score-0 artifact is shared.
  • ~99.8% equal-score-run firing for the whole 180s window: modelling per-member touch counts as Poisson, the score band stays tens-of-thousands deep even at the end of the run; only a ~0.2–1% leading-edge tail (members pushed to a brand-new maximum score with no neighbor yet) takes the ordinary path. The description states this honestly rather than claiming 100%.
  • Keyspace aligned: client --key-maximum 999999 matches the preload's exact member range (IDs 0..999999), so the R-uniform selection only ever targets preloaded members.
  • Encoding: skiplist+hashtable (1M elements > zset-max-listpack-entries 128); members are numeric-string SDS compared via sdscmp.
  • Metric of interest stated as Ops/sec (saturated throughput), matching the load model.

Why --pipeline 10 (and why one spec, not a matrix)

10 is not arbitrary — it's the repo's established depth for single-key sorted-set throughput probes (…-zscore-pipeline-10, …-zcard-pipeline-10, …-zremrangebyscore-pipeline-10 all use --pipeline 10). Together with the existing --pipeline 1 score-collision sibling from #430, this forms the natural two-point latency→throughput pair for the same dataset, so no new matrix is needed to justify the value.

The spec is a measurement instrument added ahead of the change it measures — the same ordering used for the pipeline-1 collision spec in #430. It is self-contained and does not depend on any unmerged code: it simply gives the equal-score-run ZINCRBY path a saturating throughput probe that the syscall-bound pipeline-1 spec cannot provide. Even absent any future optimization, it is valid coverage of a dense-equal-score-run ZINCRBY workload.

Validation

Key-range semantics confirmed empirically against the redislabs/memtier_benchmark:edge image used by the runners: R selection over --key-maximum N covers [0, N] inclusive, and the sequential preload (-n 1000000, --key-maximum 1000000) creates members 0..999999. Client --key-maximum 999999 therefore selects exactly the 1M preloaded members — no ZINCRBY ever lands on a non-preloaded id (which would create a member outside the score band).

Test plan

  • tested-commands: [zincrby], tested-groups: [sorted-set], keyspacelen: 1.
  • oss-standalone; amd64 + arm64 + dockerhub build variants.

…M elements, pipeline-10); bump 0.3.26

Throughput counterpart of the pipeline-1 score-collision latency probe (redis#430).
The pipeline-1 sibling puts every ZINCRBY on the equal-score-run skiplist path
(all members start at score 0 -> one dense translating band) but its Ops/sec is
capped by the per-op kernel write() syscall, so a per-op skiplist-walk cost cannot
surface. This variant saturates the single-threaded core (-t 4 -c 50 = 200 conns,
--pipeline 10, 180s), amortizing the syscall ~10x so the equal-score-run walk cost
becomes the binding constraint and shows up as an Ops/sec delta. ~99.8% fast-path
firing (Poisson touch band stays tens-of-thousands deep for the whole window; only a
~0.2-1% leading-edge tail misses). Reuses the redis#430 collision dataset (dataset_name
1key-zset-1M-elements-score-collision); client key-maximum 999999 aligns the R range
exactly to the 1M preloaded members.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant