From b9a1fa9ec62792596113846f06989a30f0de9665 Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Sat, 12 Sep 2026 00:37:04 -0500 Subject: [PATCH 001/183] Update Narya to latest Zen 5 verification optimizations --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 4607b760..2463c0b1 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.26.4 replace github.com/gagliardetto/binary => github.com/palmerlao/binary v0.0.0-20250617062159-3054b4d33aed require ( - github.com/Overclock-Validator/narya-ed25519 v0.0.0-20260726222623-da0d045dae9d + github.com/Overclock-Validator/narya-ed25519 v0.0.0-20260730051143-c265ee966713 github.com/cespare/xxhash/v2 v2.3.0 github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 github.com/charmbracelet/bubbletea v1.3.10 diff --git a/go.sum b/go.sum index 069571ee..b5997c28 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,8 @@ github.com/Overclock-Validator/gnark-crypto v0.0.0-20250309203346-2a67ed08a105 h github.com/Overclock-Validator/gnark-crypto v0.0.0-20250309203346-2a67ed08a105/go.mod h1:Poczuq3dbt+CwyTKgOjGaEwJOMP7YxQobF7QhgNcguk= github.com/Overclock-Validator/narya-ed25519 v0.0.0-20260726222623-da0d045dae9d h1:ipaL+9MHKeI8QIfWneId0VLa+STLRM1e6MnvZhQyhPU= github.com/Overclock-Validator/narya-ed25519 v0.0.0-20260726222623-da0d045dae9d/go.mod h1:B7/xqV/5NtGJa8OlZAa9TRMHgeIE+VEJNiPzMP4FrIg= +github.com/Overclock-Validator/narya-ed25519 v0.0.0-20260730051143-c265ee966713 h1:nRAD+snanlR/sX4W5rkrxr6+sYBZ3Hl2xZQ6HCpM0Hc= +github.com/Overclock-Validator/narya-ed25519 v0.0.0-20260730051143-c265ee966713/go.mod h1:B7/xqV/5NtGJa8OlZAa9TRMHgeIE+VEJNiPzMP4FrIg= github.com/Overclock-Validator/solana-snapshot-finder-go v0.0.0-20260223201452-d8363b514fc0 h1:elgavEQb8l7Zn3gS3Y+2/98PlUylOWdlM3V1VumQ7mA= github.com/Overclock-Validator/solana-snapshot-finder-go v0.0.0-20260223201452-d8363b514fc0/go.mod h1:XbqbvMA2NKeosY0w3WdBOpCg2eYJesBjfE4cNt9HSE8= github.com/Overclock-Validator/wide v0.0.0-20250221123529-f80959d02044 h1:ph9gnWIY116AWT/iCfXoPe9/cn2aWx2uJBuLdf/LyEE= From 9803f16c0edd31f9f53afcd3e6256c30226949ea Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Sat, 12 Sep 2026 01:20:54 -0500 Subject: [PATCH 002/183] Overlap Turbine signature verification with shred arrival --- cmd/mithril/node/node.go | 19 +- cmd/mithril/node/sigverify_reporter.go | 3 +- config.example.toml | 35 +- docs/transaction_sigverify_streaming.md | 96 ++++ pkg/block/block.go | 17 +- pkg/block/block_test.go | 7 +- pkg/metrics/metrics.go | 13 +- pkg/replay/block.go | 5 + pkg/sigverify/config_policy_test.go | 63 +++ pkg/sigverify/sigverify.go | 70 ++- pkg/statsd/statsd.go | 21 + pkg/statsd/statsd_test.go | 9 + pkg/turbine/assembler.go | 43 +- pkg/turbine/cancellation_regression_test.go | 67 +-- pkg/turbine/entries.go | 116 +++-- pkg/turbine/entries_prefetch_test.go | 146 ++++++ pkg/turbine/entry_prefetch.go | 343 +++++++++++++ pkg/turbine/entry_prefetch_benchmark_test.go | 217 ++++++++ pkg/turbine/entry_prefetch_bounds_test.go | 50 ++ pkg/turbine/entry_prefetch_test.go | 360 +++++++++++++ pkg/turbine/receiver.go | 30 +- .../receiver_prefetch_lifecycle_test.go | 116 +++++ pkg/turbine/transaction_verifier.go | 348 +++++++++---- ...ransaction_verifier_flow_benchmark_test.go | 479 ++++++++++++++++++ pkg/turbine/transaction_verifier_test.go | 298 ++++++++++- 25 files changed, 2733 insertions(+), 238 deletions(-) create mode 100644 docs/transaction_sigverify_streaming.md create mode 100644 pkg/sigverify/config_policy_test.go create mode 100644 pkg/turbine/entries_prefetch_test.go create mode 100644 pkg/turbine/entry_prefetch.go create mode 100644 pkg/turbine/entry_prefetch_benchmark_test.go create mode 100644 pkg/turbine/entry_prefetch_bounds_test.go create mode 100644 pkg/turbine/entry_prefetch_test.go create mode 100644 pkg/turbine/receiver_prefetch_lifecycle_test.go create mode 100644 pkg/turbine/transaction_verifier_flow_benchmark_test.go diff --git a/cmd/mithril/node/node.go b/cmd/mithril/node/node.go index c452d494..e23d9682 100644 --- a/cmd/mithril/node/node.go +++ b/cmd/mithril/node/node.go @@ -560,6 +560,12 @@ func init() { Run.Flags().StringVar(&snapshot.SnapshotIndexTempDir, "snapshot-index-temp-dir", "", "Optional directory for snapshot index shard logs/SST staging") Run.Flags().StringVar(&sigverify.Cfg.Backend, "sigverify-backend", sigverify.Defaults().Backend, "ed25519 verification backend: auto|r51|generic|stdlib") + Run.Flags().IntVar(&sigverify.Cfg.Workers, "sigverify-workers", 0, + "Turbine transaction signature verification workers (0 = min(2, GOMAXPROCS))") + Run.Flags().IntVar(&sigverify.Cfg.BatchTarget, "sigverify-batch-target", sigverify.Defaults().BatchTarget, + "Turbine transaction signature batch target: 4 or 8 (available short batches run immediately)") + Run.Flags().BoolVar(&sigverify.Cfg.DisableShredOverlap, "sigverify-disable-shred-overlap", false, + "Defer Turbine transaction decoding and signature verification until all block shreds arrive") Run.Flags().BoolVar(&sbpf.UsePool, "use-pool", true, "Disable to allocate fresh slices") Run.Flags().IntVar(&accountsdb.StoreAccountsWorkers, "store-accounts-workers", 128, "Number of workers to write account updates") Run.Flags().IntVar(&accountsdb.ProgramCacheMaxMB, "program-cache-max-mb", accountsdb.DefaultProgramCacheMaxMB, "Maximum approximate SBPF program cache size in MiB") @@ -1127,10 +1133,17 @@ func initConfigAndBindFlags(cmd *cobra.Command) error { // later: narya pins its backend on first use, and selecting it explicitly // doubles as a startup health check, so a machine that cannot run the // requested backend fails now instead of at the first block. - sigverify.Cfg.Backend = getString("sigverify-backend", "tuning.sigverify_backend") + backendKey := "sigverify.backend" + if !config.IsSet(backendKey) { + backendKey = "tuning.sigverify_backend" // older configuration files + } + sigverify.Cfg.Backend = getString("sigverify-backend", backendKey) + sigverify.Cfg.Workers = getInt("sigverify-workers", "sigverify.workers") + sigverify.Cfg.BatchTarget = getInt("sigverify-batch-target", "sigverify.batch_target") + sigverify.Cfg.DisableShredOverlap = getBool("sigverify-disable-shred-overlap", "sigverify.disable_shred_overlap") resolved, err := sigverify.Configure(sigverify.Cfg) if err != nil { - return fmt.Errorf("tuning.sigverify_backend: %w", err) + return fmt.Errorf("signature verification configuration: %w", err) } resolvedSigverifyBackend = resolved sbpf.UsePool = getBool("use-pool", "tuning.use_pool") @@ -3214,6 +3227,8 @@ func printStartupInfo(commandName string) { } fmt.Printf(" Sigverify: %s%s%s %s(%s)%s\n", green, resolvedSigverifyBackend, reset, dim, sigverifyDesc, reset) + fmt.Printf(" workers=%d batch_target=%d shred_overlap=%t\n", + sigverify.TransactionWorkers(), sigverify.TransactionBatchTarget(), !sigverify.Cfg.DisableShredOverlap) } // Load state file for detailed info (only show for modes that use existing AccountsDB) diff --git a/cmd/mithril/node/sigverify_reporter.go b/cmd/mithril/node/sigverify_reporter.go index d374d93b..597a3c11 100644 --- a/cmd/mithril/node/sigverify_reporter.go +++ b/cmd/mithril/node/sigverify_reporter.go @@ -42,7 +42,8 @@ func startSigverifyReporter(ctx context.Context) { // against, and so the resolved backend is recorded even on a node that // exits before the first tick. previous := sigverify.Stats() - mlog.NamedFilef("sigverify", "startup: %s", previous) + mlog.NamedFilef("sigverify", "startup: %s workers=%d batch_target=%d shred_overlap=%t", previous, + sigverify.TransactionWorkers(), sigverify.TransactionBatchTarget(), !sigverify.Cfg.DisableShredOverlap) for { select { diff --git a/config.example.toml b/config.example.toml index 7e383308..2636e1b1 100644 --- a/config.example.toml +++ b/config.example.toml @@ -524,14 +524,6 @@ name = "mithril" # Number of borrowed accounts to preallocate in arena (0 to disable) borrowed_account_arena_size = 1024 - # ed25519 signature verification backend. - # auto - use the AVX-512 accelerated backend when the CPU has - # AVX512-IFMA (Zen 4/5, Ice Lake and newer), else portable - # r51 - force the accelerated backend; startup fails without AVX512-IFMA - # generic - force the portable pure-Go backend - # stdlib - use Go’s crypto/ed25519 implementation after the mandatory strict rejection checks. - sigverify_backend = "auto" - # Enable/disable pool allocator for slices use_pool = true @@ -574,6 +566,33 @@ name = "mithril" # Filename to write CPU profile (for offline analysis with go tool pprof) # cpu_profile_path = "/mnt/mithril-data/profiling/cpu.pprof" +# ============================================================================ +# [sigverify] - Transaction Signature Verification +# ============================================================================ + +[sigverify] + # ed25519 backend: auto selects AVX-512 IFMA when available, else portable. + # r51 requires AVX-512 IFMA; generic and stdlib force portable backends. + # Strict signature checks are always enabled. The older + # tuning.sigverify_backend key remains supported when this key is absent. + backend = "auto" + + # Shared Turbine transaction verification workers; 0 = min(2, GOMAXPROCS). + # Leaves execution and shred/consensus processing room to run concurrently. + # This does not change validator.tpu_sigverify_workers or replay's fallback pool. + workers = 0 + + # Signature lanes per group: 4 or 8 (0 also means 8). Transactions stay + # indivisible, so a multisignature transaction may exceed this target. + # Ready short groups run immediately; no timer waits for more shreds. + batch_target = 8 + + # Decode complete entry batches and verify while later shreds arrive. + # Set true to compare against completion-only verification. + # Early work reserves at most 8 slots and 64 MiB of encoded component bytes; + # decoded transactions and Go bookkeeping use additional heap memory. + disable_shred_overlap = false + # ============================================================================ # [debug] - Debug Logging # ============================================================================ diff --git a/docs/transaction_sigverify_streaming.md b/docs/transaction_sigverify_streaming.md new file mode 100644 index 00000000..fc29745b --- /dev/null +++ b/docs/transaction_sigverify_streaming.md @@ -0,0 +1,96 @@ +# Transaction signature verification during shred arrival + +Turbine verifies transaction signatures as complete entry batches arrive. The +default shared transaction pool has two workers and targets eight signature +lanes. A ready batch containing four transactions runs immediately; there is no +timer or minimum occupancy requirement. The same policy handles live reception +and repair catch-up without a mode transition or a 200 ms batching delay. + +## Order of work + +1. The receiver authenticates the shred and performs existing assembly/FEC + recovery. The packet reader advances a contiguous data-shred frontier and + attempts a nonblocking background enqueue. +2. Two background preparation workers copy and decode complete DATA_COMPLETE + entry batches. A batch may span several FEC sets. They submit its immutable + transactions to the shared signature pool while later shreds arrive. +3. Signature groups contain available transactions up to the configured lane + target. Transactions with multiple signatures remain indivisible. A rolling + per-request window refills when any group finishes, without a wave barrier. +4. Once the full slot is assembled, completion rechecks exact batch bytes, + processes all Alpenglow markers and FEC roots, and constructs the final ordered + block. It submits any transactions not already covered and joins signature + work for the retained batches before marking the block verified. +5. The existing replay pipeline receives the verified block. This change does + not execute transactions before full-slot admission, alter execution batching, + or move parent-dependent validation ahead of its required state. + +The 200 ms slot interval provides an opportunity to overlap work. It is not a +mandatory local wait: replay can continue as soon as the block is available and +its checks complete. If all shreds arrive in a burst during catch-up, full-slot +completion uses the same efficient groups with whatever early work was able to +start. Four workers can improve catch-up latency but occupy more cores at once. + +## Bounds and correctness + +- At most eight slot generations hold early preparation reservations, with a + combined 64 MiB budget for raw component bytes and a 1 MiB per-component limit. + Decoded transaction objects add heap overhead. Saturation skips optional early + work; normal full-slot verification still covers every retained transaction. +- One queued/active preparation token per generation coalesces packet arrivals. + Verifier requests and each request's outstanding groups are also bounded. + Request admission can wait behind existing requests; this is not a strict + replay-head priority scheduler. +- No transaction decoding or verifier admission occurs under the assembler mutex or on the + packet reader. A gap prevents early component decoding until recovery or + arrival closes it. Duplicate shreds do not create duplicate requests. +- Cached results belong to one generation, shred range and exact byte sequence. + Reset/eviction cancels that generation. Reservations remain charged until + admitted readers have relinquished their transaction buffers. +- `UpdateParent` can discard an optimistic prefix. Parse and marker checks still + cover that prefix, while its transaction signature verdict is discarded along + with its transactions. Retained signatures must all pass before replay. +- Cancellation is not an invalid-signature verdict. A retry on the same slot + generation verifies transactions again if an earlier request was canceled. + +## Configuration and observability + +```toml +[sigverify] +backend = "auto" +workers = 0 # min(2, GOMAXPROCS) +batch_target = 8 # 4 or 8; short groups never wait to fill +disable_shred_overlap = false +``` + +Equivalent CLI flags are `--sigverify-workers`, `--sigverify-batch-target` and +`--sigverify-disable-shred-overlap`. These settings apply to Turbine transaction +signatures; TPU, shred signatures, consensus BLS and replay's fallback verifier +retain their existing configuration. + +Use `TurbineFullToReady` to measure residual wall time after the slot becomes +complete. `TurbineEarlyVerifiedTransactions` counts retained transactions whose +verification finished before full assembly. `TurbineTransactionSigverify` now +measures completion's outstanding-signature join/fallback work. The remaining +wait for an already claimed background preparation job, including +any outstanding admission delay, appears in `TurbineEarlyPreparationWait`, +separately from active completion decoding. It does not sum every background +admission wait. Early parse and signature durations are component sums observed +at completion; +a discarded prefix still being verified is not included. These durations +overlap reception and each other and must not be added as sequential stages +or interpreted as CPU time. + +## Benchmark scope + +`BenchmarkTransactionVerificationFlow` compares two/four workers and targets +four/eight using catch-up, synthetic 200 ms component arrivals, and sparse +four/seven/eight-transaction components. It supports captured public transaction +fixtures and generated, distinct valid transactions of exactly 228 or 1,232 wire +bytes. Decoding and fixture construction are outside those pool measurements. + +The execution contention probe runs the real transfer load/execute benchmark +alongside signature work on the same eight physical cores. Its separate +processes measure hardware/OS contention, excluding shared Go scheduler/heap +effects, full-block dependency planning, commit and live network timing. Pool +throughput alone is insufficient evidence of end-to-end replay improvement. diff --git a/pkg/block/block.go b/pkg/block/block.go index 23bfd1f0..459fd68d 100644 --- a/pkg/block/block.go +++ b/pkg/block/block.go @@ -14,15 +14,30 @@ import ( "github.com/gagliardetto/solana-go/rpc" ) -// TurbineIngressTimings is the per-slot decomposition carried only by a +// TurbineIngressTimings carries per-slot observations only on a // trusted in-memory Turbine block. Durations never serialize with Block. type TurbineIngressTimings struct { ShredCollection time.Duration CompletionQueueDelay time.Duration BlockDecode time.Duration + // Completion-only parse and outstanding-signature join/verification time. TransactionParse time.Duration TransactionSigverify time.Duration ReplayAdmission time.Duration + // Early durations sum completed prefetched component work, including an + // optimistic prefix later discarded, and overlap reception and each other. + // EarlyTransactionSigverify includes queueing through future completion; + // neither early duration is CPU time or an additive pipeline wall stage. + EarlyTransactionParse time.Duration + EarlyTransactionSigverify time.Duration + // Completion wait for already-claimed background parsing/submission. + // Recorded separately from BlockDecode's active completion work. + EarlyPreparationWait time.Duration + // Only retained transactions whose verification finished by ShredFullNanos. + EarlyVerifiedTransactions uint64 + // FullToReady is wall time from full shred assembly to replay-ready completion. + // It contains completion queueing, decode and outstanding verification waits. + FullToReady time.Duration } var transactionDerivedStateInitMu sync.Mutex diff --git a/pkg/block/block_test.go b/pkg/block/block_test.go index 2ffcd302..31ac89e6 100644 --- a/pkg/block/block_test.go +++ b/pkg/block/block_test.go @@ -11,7 +11,12 @@ func TestTransactionSignaturesVerifiedMarkerIsNotSerialized(t *testing.T) { original.MarkTransactionSignaturesVerified() admissionStart := time.Now() original.MarkTurbineReplayAdmissionStart(admissionStart) - ingress := TurbineIngressTimings{ShredCollection: 12 * time.Millisecond, TransactionSigverify: 34 * time.Millisecond} + ingress := TurbineIngressTimings{ + ShredCollection: 12 * time.Millisecond, TransactionSigverify: 34 * time.Millisecond, + EarlyTransactionParse: 2 * time.Millisecond, EarlyTransactionSigverify: 56 * time.Millisecond, + EarlyPreparationWait: 3 * time.Millisecond, + EarlyVerifiedTransactions: 80, FullToReady: 35 * time.Millisecond, + } original.MarkTurbineIngressTimings(ingress) if got, ok := original.TurbineIngressTimings(); !ok || got != ingress { t.Fatalf("ingress timings = %+v, %t; want %+v, true", got, ok, ingress) diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index 10548fdd..fee3c92f 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -94,15 +94,26 @@ type AccountLoader struct { SysvarCachePublicationEpochRejects uint64 } -// TurbineIngress is the exact per-slot pre-replay pipeline decomposition. +// TurbineIngress records per-slot pre-replay pipeline observations. // It is written to replay_timings.jsonl without high-cardinality metric labels. type TurbineIngress struct { ShredCollection Timing CompletionQueueDelay Timing BlockDecode Timing + // Completion-only parse and outstanding-signature join/verification time. TransactionParse Timing TransactionSigverify Timing ReplayAdmission Timing + // Summed completed prefetched component durations, including any discarded + // optimistic prefix. Overlap reception; not CPU time or additive wall stages. + // Early sigverify includes queueing. + EarlyTransactionParse Timing + EarlyTransactionSigverify Timing + // Completion wait for claimed background parsing/submission, outside BlockDecode. + EarlyPreparationWait Timing + EarlyVerifiedTransactions uint64 + // FullToReady contains the completion stages above, excluding admission. + FullToReady Timing } // VoteRewardDetails decomposes RewardCertificatePreflight and diff --git a/pkg/replay/block.go b/pkg/replay/block.go index bb465bc7..fdc40257 100644 --- a/pkg/replay/block.go +++ b/pkg/replay/block.go @@ -2831,6 +2831,11 @@ func ReplayBlocks( record.TransactionParse.AddTiming(ingressTimings.TransactionParse) record.TransactionSigverify.AddTiming(ingressTimings.TransactionSigverify) record.ReplayAdmission.AddTiming(ingressTimings.ReplayAdmission) + record.EarlyTransactionParse.AddTiming(ingressTimings.EarlyTransactionParse) + record.EarlyTransactionSigverify.AddTiming(ingressTimings.EarlyTransactionSigverify) + record.EarlyPreparationWait.AddTiming(ingressTimings.EarlyPreparationWait) + record.EarlyVerifiedTransactions = ingressTimings.EarlyVerifiedTransactions + record.FullToReady.AddTiming(ingressTimings.FullToReady) } start := time.Now() diff --git a/pkg/sigverify/config_policy_test.go b/pkg/sigverify/config_policy_test.go new file mode 100644 index 00000000..52e8948c --- /dev/null +++ b/pkg/sigverify/config_policy_test.go @@ -0,0 +1,63 @@ +package sigverify + +import ( + "runtime" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestResolveConfigPolicyDefaultsAndOverrides(t *testing.T) { + zero, err := ResolveConfig(Config{}) + require.NoError(t, err) + require.Equal(t, BackendAuto, zero.Backend) + require.Equal(t, min(2, runtime.GOMAXPROCS(0)), zero.Workers) + require.Equal(t, 8, zero.BatchTarget) + require.False(t, zero.DisableShredOverlap) + defaults, err := ResolveConfig(Defaults()) + require.NoError(t, err) + require.Equal(t, zero, defaults) + + override := Config{Backend: BackendGeneric, Workers: 4, BatchTarget: 4, DisableShredOverlap: true} + resolved, err := ResolveConfig(override) + require.NoError(t, err) + require.Equal(t, override, resolved) +} + +func TestInvalidPolicyDoesNotLatchBackend(t *testing.T) { + if !inChild() { + out, err := runConfigureChild(t, t.Name()) + require.NoError(t, err, "child output:\n%s", out) + require.Contains(t, out, "PASS") + return + } + before := Cfg + for _, cfg := range []Config{ + {Backend: BackendGeneric, Workers: -1}, + {Backend: BackendGeneric, BatchTarget: -1}, + {Backend: BackendGeneric, BatchTarget: 3}, + {Backend: BackendGeneric, BatchTarget: 16}, + } { + _, err := Configure(cfg) + require.Error(t, err) + require.Equal(t, before, Cfg, "invalid policy must not become live") + require.Empty(t, configuredBackend, "invalid policy must not latch the backend") + } + _, err := Configure(Config{Backend: BackendGeneric, Workers: 2, BatchTarget: 4}) + require.NoError(t, err, "valid configuration must remain possible after rejection") + require.Equal(t, 2, TransactionWorkers()) + require.Equal(t, 4, TransactionBatchTarget()) +} + +func TestTransactionPolicyWithoutConfigure(t *testing.T) { + if !inChild() { + out, err := runConfigureChild(t, t.Name()) + require.NoError(t, err, "child output:\n%s", out) + require.Contains(t, out, "PASS") + return + } + Cfg = Config{} + require.Equal(t, min(2, runtime.GOMAXPROCS(0)), TransactionWorkers()) + require.Equal(t, 8, TransactionBatchTarget()) + require.False(t, Cfg.DisableShredOverlap) +} diff --git a/pkg/sigverify/sigverify.go b/pkg/sigverify/sigverify.go index fae00447..a0502712 100644 --- a/pkg/sigverify/sigverify.go +++ b/pkg/sigverify/sigverify.go @@ -20,6 +20,7 @@ package sigverify import ( "fmt" + "runtime" "sync" narya "github.com/Overclock-Validator/narya-ed25519/ed25519" @@ -40,15 +41,60 @@ const ( BackendStdlib = "stdlib" ) -// Config selects the verification backend. It is deliberately tiny: the -// library's own defaults are good, and every knob here is a consensus-visible -// or performance-visible choice that an operator should have to state. +// Config selects the backend and the Turbine transaction-verification policy. +// Worker and batching settings do not change the TPU or fallback replay pools. type Config struct { - Backend string + Backend string + Workers int + BatchTarget int + DisableShredOverlap bool } // Defaults returns the configuration used when the operator sets nothing. -func Defaults() Config { return Config{Backend: BackendAuto} } +func Defaults() Config { return Config{Backend: BackendAuto, BatchTarget: BatchTarget} } + +// ResolveConfig validates every setting before the one-shot backend selection. +// Zero workers selects at most two transaction-verification workers; zero batch +// target uses eight signatures. Available short batches are never held to fill. +func ResolveConfig(cfg Config) (Config, error) { + if cfg.Backend == "" { + cfg.Backend = BackendAuto + } + switch cfg.Backend { + case BackendAuto, BackendR51, BackendGeneric, BackendStdlib: + default: + return Config{}, fmt.Errorf("sigverify.backend must be one of %q, %q, %q, %q; got %q", BackendAuto, BackendR51, BackendGeneric, BackendStdlib, cfg.Backend) + } + if cfg.Workers < 0 { + return Config{}, fmt.Errorf("sigverify.workers must be >= 0; got %d", cfg.Workers) + } + if cfg.Workers == 0 { + cfg.Workers = min(2, max(1, runtime.GOMAXPROCS(0))) + } + if cfg.BatchTarget == 0 { + cfg.BatchTarget = BatchTarget + } + if cfg.BatchTarget != 4 && cfg.BatchTarget != 8 { + return Config{}, fmt.Errorf("sigverify.batch_target must be 4 or 8 (0 uses 8); got %d", cfg.BatchTarget) + } + return cfg, nil +} + +// TransactionWorkers also supports callers that do not run node Configure. +func TransactionWorkers() int { + if Cfg.Workers > 0 { + return Cfg.Workers + } + return min(2, max(1, runtime.GOMAXPROCS(0))) +} + +// TransactionBatchTarget also supports the zero configuration outside startup. +func TransactionBatchTarget() int { + if Cfg.BatchTarget == 4 { + return 4 + } + return BatchTarget +} // Cfg is the live configuration, set once by Configure during startup and // read-only afterwards. It follows the same shape as replay.TrailingVerifierCfg. @@ -64,10 +110,6 @@ var Cfg = Defaults() // underlying library pins its backend on first use and a late switch would // leave the process in a state neither caller asked for. func Configure(cfg Config) (string, error) { - if cfg.Backend == "" { - cfg.Backend = Defaults().Backend - } - configureMu.Lock() defer configureMu.Unlock() @@ -79,12 +121,10 @@ func Configure(cfg Config) (string, error) { // Validate before publishing anything. Assigning Cfg first would leave a // rejected backend name visible to Backend() and to the startup log. - switch cfg.Backend { - case BackendAuto, BackendR51, BackendGeneric, BackendStdlib: - default: - return "", fmt.Errorf( - "sigverify.backend must be one of %q, %q, %q, %q; got %q", - BackendAuto, BackendR51, BackendGeneric, BackendStdlib, cfg.Backend) + var err error + cfg, err = ResolveConfig(cfg) + if err != nil { + return "", err } resolved, err := installBackend(cfg.Backend) diff --git a/pkg/statsd/statsd.go b/pkg/statsd/statsd.go index bbf3eea9..828d3cec 100644 --- a/pkg/statsd/statsd.go +++ b/pkg/statsd/statsd.go @@ -124,6 +124,13 @@ var ( TurbineBlockDecode = Metric{"turbine_block_decode_duration_seconds"} TurbineTransactionParse = Metric{"turbine_transaction_parse_duration_seconds"} TurbineTransactionSigverify = Metric{"turbine_transaction_sigverify_duration_seconds"} + // Early durations sum elapsed component work, including verifier queueing; + // they overlap shred collection and are neither CPU nor pipeline wall time. + TurbineEarlyTransactionParse = Metric{"turbine_early_transaction_parse_duration_seconds"} + TurbineEarlyTransactionSigverify = Metric{"turbine_early_transaction_sigverify_elapsed_seconds"} + TurbineEarlyPreparationWait = Metric{"turbine_early_preparation_wait_seconds"} + TurbineEarlyVerifiedTransactions = Metric{"turbine_early_verified_transactions_total"} + TurbineFullToReady = Metric{"turbine_full_to_ready_duration_seconds"} // ReplaySigverifyGroup times one drained group of transaction signatures // and ReplaySigverifyGroupSignatures counts how many signatures were in it. // The pair is what tells an operator whether batching is actually happening: @@ -245,6 +252,11 @@ var MetricToType = map[Metric]metricType{ TurbineBlockDecode: TimingT, TurbineTransactionParse: TimingT, TurbineTransactionSigverify: TimingT, + TurbineEarlyTransactionParse: TimingT, + TurbineEarlyTransactionSigverify: TimingT, + TurbineEarlyPreparationWait: TimingT, + TurbineEarlyVerifiedTransactions: CountT, + TurbineFullToReady: TimingT, ReplaySigverifyGroup: TimingT, ReplaySigverifyGroupSignatures: CountT, TurbineReplayAdmission: TimingT, @@ -353,6 +365,11 @@ var MetricToLabels = map[Metric][]string{ TurbineBlockDecode: {}, TurbineTransactionParse: {}, TurbineTransactionSigverify: {}, + TurbineEarlyTransactionParse: {}, + TurbineEarlyTransactionSigverify: {}, + TurbineEarlyPreparationWait: {}, + TurbineEarlyVerifiedTransactions: {}, + TurbineFullToReady: {}, ReplaySigverifyGroup: {}, ReplaySigverifyGroupSignatures: {}, TurbineReplayAdmission: {}, @@ -390,6 +407,10 @@ var MetricToBuckets = map[Metric][]float64{ TurbineBlockDecode: turbinePipelineDurationBuckets, TurbineTransactionParse: turbinePipelineDurationBuckets, TurbineTransactionSigverify: turbinePipelineDurationBuckets, + TurbineEarlyTransactionParse: turbinePipelineDurationBuckets, + TurbineEarlyTransactionSigverify: turbinePipelineDurationBuckets, + TurbineEarlyPreparationWait: turbinePipelineDurationBuckets, + TurbineFullToReady: turbinePipelineDurationBuckets, ReplaySigverifyGroup: turbinePipelineDurationBuckets, TurbineReplayAdmission: turbinePipelineDurationBuckets, AlpenglowVoteRewards: turbinePipelineDurationBuckets, diff --git a/pkg/statsd/statsd_test.go b/pkg/statsd/statsd_test.go index 830ea99e..6ec3cd0c 100644 --- a/pkg/statsd/statsd_test.go +++ b/pkg/statsd/statsd_test.go @@ -203,6 +203,10 @@ func TestTurbinePipelineDurationMetricsUseSecondsAndBoundedSchema(t *testing.T) TurbineBlockDecode, TurbineTransactionParse, TurbineTransactionSigverify, + TurbineEarlyTransactionParse, + TurbineEarlyTransactionSigverify, + TurbineEarlyPreparationWait, + TurbineFullToReady, TurbineReplayAdmission, } duration := 25 * time.Millisecond @@ -228,6 +232,11 @@ func TestTurbinePipelineDurationMetricsUseSecondsAndBoundedSchema(t *testing.T) } } +func TestTurbineEarlyVerifiedTransactionsHasBoundedCountSchema(t *testing.T) { + assert.Equal(t, CountT, MetricToType[TurbineEarlyVerifiedTransactions]) + assert.Equal(t, []string{}, MetricToLabels[TurbineEarlyVerifiedTransactions]) +} + func TestBlockProductionMetricLabelsStayBounded(t *testing.T) { assert.Equal(t, []string{"outcome", "reason"}, MetricToLabels[BlockProductionLeaderSlots]) assert.Equal(t, []string{"outcome", "terminal", "cause"}, MetricToLabels[BlockProductionLeaderSlotTerminals]) diff --git a/pkg/turbine/assembler.go b/pkg/turbine/assembler.go index 9b69f437..b558e058 100644 --- a/pkg/turbine/assembler.go +++ b/pkg/turbine/assembler.go @@ -72,6 +72,7 @@ type SlotAssembler struct { // Configured before ingestion; tests may replace it with a blocking probe. // Production uses the process-wide bounded transaction verifier. verifyTransactions func(context.Context, *block.Block) error + entryPrefetch *entryPrefetchPool } type SlotRepairRequest struct { @@ -106,7 +107,10 @@ type slotState struct { fullAt time.Time repairedShreds int // completing makes the immutable full state a single-owner generation token. - completing bool + completing bool + batchScan, batchStart uint32 + completeBatches []shredBatchRange + prefetch *slotEntryPrefetch // Assembly failures for this slot (mixed variants/signatures, FEC layout // conflicts, ...). A slot frozen below completion while repair responses // flow is usually poisoned state — the latest error names the poison. @@ -174,7 +178,6 @@ func NewSlotAssembler() *SlotAssembler { priorityRepairSlots: make(map[uint64]struct{}), partialShredObs: make(map[uint64]PartialShredObservation), encoders: make(map[fecLayout]reedsolomon.Encoder), - verifyTransactions: validateBlockTransactionsContext, } } @@ -307,6 +310,7 @@ func (a *SlotAssembler) addShredFrom(shred *Shred, fromRepair bool) (*slotComple } } + a.prefetchEntriesLocked(state) if !state.complete() { return nil, nil } @@ -374,19 +378,27 @@ func (a *SlotAssembler) processCompletion(ctx context.Context, work *slotComplet } decodeStartedAt := time.Now() - var decodeTimings entryDecodeTimings + decodeTimings := entryDecodeTimings{ctx: ctx} + if work.state.prefetch != nil { + decodeTimings.prefetched = work.state.prefetch.batches + } blk, parentInfo, roots, err := work.state.decodeBlock(&decodeTimings) decodeTotal := time.Since(decodeStartedAt) - decodeOnly := decodeTotal - decodeTimings.transactionParse + decodeOnly := decodeTotal - decodeTimings.transactionParse - decodeTimings.prefetchWait if decodeOnly < 0 { decodeOnly = 0 } timings.BlockDecode = decodeOnly timings.TransactionParse = decodeTimings.transactionParse + timings.EarlyPreparationWait = decodeTimings.prefetchWait _ = statsd.Duration(statsd.TurbineBlockDecode, timings.BlockDecode, nil) _ = statsd.Duration(statsd.TurbineTransactionParse, timings.TransactionParse, nil) processed := processedSlotCompletion{block: blk, parentInfo: parentInfo, roots: roots, err: err, timings: timings} if err != nil { + if ctx.Err() != nil { + processed.canceled = true + processed.err = nil + } return processed } if ctx.Err() != nil { @@ -395,7 +407,12 @@ func (a *SlotAssembler) processCompletion(ctx context.Context, work *slotComplet } sigverifyStartedAt := time.Now() - processed.err = work.verifyTransactions(ctx, blk) + if work.state.prefetch != nil && len(decodeTimings.retained) > 0 { + processed.err = verifyDecodedEntryBatches(ctx, blk, decodeTimings.retained, work.state.prefetch.pool.verifier) + } else { + processed.err = work.verifyTransactions(ctx, blk) + } + earlyEntryTimings(&decodeTimings, work.state.fullAt, &processed.timings) processed.timings.TransactionSigverify = time.Since(sigverifyStartedAt) _ = statsd.Duration(statsd.TurbineTransactionSigverify, processed.timings.TransactionSigverify, nil) if ctx.Err() != nil { @@ -406,6 +423,12 @@ func (a *SlotAssembler) processCompletion(ctx context.Context, work *slotComplet if processed.err == nil { blk.MarkTransactionSignaturesVerified() processed.completionReadyAt = time.Now() + processed.timings.FullToReady = processed.completionReadyAt.Sub(work.state.fullAt) + _ = statsd.Duration(statsd.TurbineFullToReady, processed.timings.FullToReady, nil) + _ = statsd.Duration(statsd.TurbineEarlyPreparationWait, processed.timings.EarlyPreparationWait, nil) + _ = statsd.Duration(statsd.TurbineEarlyTransactionParse, processed.timings.EarlyTransactionParse, nil) + _ = statsd.Duration(statsd.TurbineEarlyTransactionSigverify, processed.timings.EarlyTransactionSigverify, nil) + _ = statsd.Count(statsd.TurbineEarlyVerifiedTransactions, int64(processed.timings.EarlyVerifiedTransactions), nil) } return processed } @@ -420,6 +443,11 @@ func (a *SlotAssembler) finalizeCompletion(work *slotCompletionWork, processed p a.mu.Unlock() return nil, nil } + if processed.canceled { + state.completing = false + a.mu.Unlock() + return nil, nil + } if processed.err != nil { // Retain a deterministic decode/verification failure on the live full // state so catchup diagnostics report poison instead of a missing slot. @@ -434,6 +462,7 @@ func (a *SlotAssembler) finalizeCompletion(work *slotCompletionWork, processed p if !a.acceptAlpenglowBlockIDLocked(blk) { a.trackNonCanonicalBlockIDLocked(blk) a.recordPartialObsLocked(state) + a.releasePrefetchLocked(state) delete(a.slots, state.slot) a.mu.Unlock() if work.reportNonCanonical { @@ -442,6 +471,7 @@ func (a *SlotAssembler) finalizeCompletion(work *slotCompletionWork, processed p return nil, nil } + a.releasePrefetchLocked(state) delete(a.slots, state.slot) a.completedSlots[state.slot] = struct{}{} a.trackBlockIDLocked(blk) @@ -542,6 +572,7 @@ func (a *SlotAssembler) ResetSlot(slot uint64) { defer a.mu.Unlock() a.recordPartialObsLocked(a.slots[slot]) + a.releasePrefetchLocked(a.slots[slot]) delete(a.slots, slot) delete(a.completedSlots, slot) } @@ -643,6 +674,7 @@ func (a *SlotAssembler) pruneOldSlotsLocked() { for slot, state := range a.slots { if slot < minSlot && !state.completing { a.recordPartialObsLocked(state) + a.releasePrefetchLocked(a.slots[slot]) delete(a.slots, slot) a.evictedSlots++ } @@ -695,6 +727,7 @@ func (a *SlotAssembler) pruneOldSlotsLocked() { return } a.recordPartialObsLocked(a.slots[victim]) + a.releasePrefetchLocked(a.slots[victim]) delete(a.slots, victim) a.evictedSlots++ } diff --git a/pkg/turbine/cancellation_regression_test.go b/pkg/turbine/cancellation_regression_test.go index 1f85e4df..71993121 100644 --- a/pkg/turbine/cancellation_regression_test.go +++ b/pkg/turbine/cancellation_regression_test.go @@ -17,86 +17,52 @@ func TestTransactionVerifierCancellationDuringBlockedAdmissionJoinsAdmittedJobs( const workers = 2 blocker := verifierTestBlock(workers) target := verifierTestBlock(2 * workers) - filler := &solana.Transaction{} - release := make(chan struct{}) var releaseOnce sync.Once started := make(chan struct{}, workers) var targetFirstCalls atomic.Int32 var targetLaterCalls atomic.Int32 - - verifier := newTransactionVerifier(workers, workers, func(tx *solana.Transaction) error { + // Single-transaction groups make the blocked-admission boundary exact. + verifier := newTransactionVerifierWithBatchTarget(workers, 1, 1, func(tx *solana.Transaction) error { switch tx { case blocker.Transactions[0], blocker.Transactions[1]: started <- struct{}{} <-release case target.Transactions[0]: targetFirstCalls.Add(1) - case target.Transactions[1], target.Transactions[2], target.Transactions[3]: + default: targetLaterCalls.Add(1) } return nil }) - + defer verifier.closeAndWait() + defer releaseOnce.Do(func() { close(release) }) ctx, cancel := context.WithCancel(context.Background()) + defer cancel() blockerDone := make(chan error, 1) targetDone := make(chan error, 1) - var calls sync.WaitGroup - calls.Add(1) - go func() { - defer calls.Done() - blockerDone <- verifier.verifyBlock(blocker) - }() + go func() { blockerDone <- verifier.verifyBlock(blocker) }() for range workers { - select { - case <-started: - case <-time.After(3 * time.Second): - cancel() - releaseOnce.Do(func() { close(release) }) - calls.Wait() - verifier.closeAndWait() - t.Fatal("timed out occupying transaction verifier workers") - } + waitSignal(t, started, "occupied verifier worker") } - // Leave one queued job ahead of the target. With both workers occupied and - // a two-entry queue, the target admits transaction 0 and then blocks trying - // to admit transaction 1. Cancellation must wait for transaction 0 to drain, - // while transactions 1 and all later chunks must never reach a worker. - var fillerErr error - var fillerDone sync.WaitGroup - fillerDone.Add(1) - verifier.jobs <- transactionVerifyJob{tx: filler, err: &fillerErr, done: &fillerDone} - - calls.Add(1) - go func() { - defer calls.Done() - targetDone <- verifier.verifyBlockContext(ctx, target) - }() + // Both workers are occupied. The target's first group fills the one-entry + // queue, and its second blocks on admission. Cancellation must still join + // the first group while preventing any later transactions from running. + go func() { targetDone <- verifier.verifyBlockContext(ctx, target) }() deadline := time.Now().Add(3 * time.Second) for len(verifier.jobs) != cap(verifier.jobs) { if time.Now().After(deadline) { - cancel() - releaseOnce.Do(func() { close(release) }) - calls.Wait() - fillerDone.Wait() - verifier.closeAndWait() - t.Fatalf("transaction queue did not fill: len=%d cap=%d", len(verifier.jobs), cap(verifier.jobs)) + t.Fatal("transaction queue did not fill") } time.Sleep(time.Millisecond) } - cancel() select { case err := <-targetDone: - releaseOnce.Do(func() { close(release) }) - calls.Wait() - fillerDone.Wait() - verifier.closeAndWait() t.Fatalf("canceled verifier returned before its admitted job joined: %v", err) case <-time.After(50 * time.Millisecond): } - releaseOnce.Do(func() { close(release) }) select { case err := <-targetDone: @@ -114,13 +80,6 @@ func TestTransactionVerifierCancellationDuringBlockedAdmissionJoinsAdmittedJobs( case <-time.After(3 * time.Second): t.Fatal("blocker verification did not drain") } - fillerDone.Wait() - calls.Wait() - verifier.closeAndWait() - - if fillerErr != nil { - t.Fatalf("filler verification: %v", fillerErr) - } if got := targetFirstCalls.Load(); got != 1 { t.Fatalf("admitted target transaction calls = %d, want 1", got) } diff --git a/pkg/turbine/entries.go b/pkg/turbine/entries.go index 9f625131..333eb23a 100644 --- a/pkg/turbine/entries.go +++ b/pkg/turbine/entries.go @@ -1,6 +1,8 @@ package turbine import ( + "bytes" + "context" "encoding/binary" "fmt" "sort" @@ -40,6 +42,11 @@ type AlpenglowParentInfo struct { type entryDecodeTimings struct { transactionParse time.Duration + ctx context.Context + prefetched map[uint32]*prefetchedShredBatch + retained []*prefetchedShredBatch + all []*prefetchedShredBatch + prefetchWait time.Duration } func (e *Entry) UnmarshalWithDecoder(decoder *bin.Decoder) error { @@ -125,11 +132,7 @@ func decodeEntriesAndAlpenglowMarkersFromDataShreds(shreds []*Shred, timings *en return shreds[i].Index < shreds[j].Index }) - type decodedEntryBatch struct { - start uint32 - entries []Entry - } - var entryBatches []decodedEntryBatch + var entryBatches []*prefetchedShredBatch var parentInfo *AlpenglowParentInfo var blockFooter *BlockFooter var batchBytes []byte @@ -147,39 +150,61 @@ func decodeEntriesAndAlpenglowMarkersFromDataShreds(shreds []*Shred, timings *en if !shred.DataComplete() { continue } - if parent, footer, ok, err := decodeAlpenglowMarkerFromShredBatch(batchBytes, batchStart); err != nil { - return nil, nil, nil, fmt.Errorf("decode alpenglow block marker ending at shred %d: %w", shred.Index, err) - } else if ok { - if parent != nil { - parentInfo, err = mergeAlpenglowParentInfo(parentInfo, parent) + var batch *prefetchedShredBatch + if timings != nil { + if cached := timings.prefetched[batchStart]; cached != nil && cached.start == batchStart && cached.end == shred.Index { + ctx := timings.ctx + if ctx == nil { + ctx = context.Background() + } + if cached.ready != nil { + waitStarted := time.Now() + select { + case <-cached.ready: + case <-ctx.Done(): + timings.prefetchWait += time.Since(waitStarted) + return nil, nil, nil, ctx.Err() + } + timings.prefetchWait += time.Since(waitStarted) + } + if err := ctx.Err(); err != nil { + return nil, nil, nil, err + } + // Bounds alone cannot prove identity after repair or replacement. + // Read decoded fields only after the preparation channel closes. + if bytes.Equal(batchBytes, cached.raw) { + batch = cached + } + } + } + if batch == nil { + batch = decodeClosedShredBatch(batchBytes, batchStart, shred.Index) + if timings != nil { + timings.transactionParse += batch.parseDuration + } + } + if timings != nil { + timings.all = append(timings.all, batch) + } + if batch.err != nil { + return nil, nil, nil, batch.err + } + if batch.marker { + if batch.parent != nil { + var err error + parentInfo, err = mergeAlpenglowParentInfo(parentInfo, batch.parent) if err != nil { return nil, nil, nil, fmt.Errorf("merge alpenglow parent marker ending at shred %d: %w", shred.Index, err) } } - if footer != nil { - blockFooter = footer + if batch.footer != nil { + blockFooter = batch.footer } batchBytes = nil haveBatch = false continue } - parseStart := time.Now() - batchEntries, consumed, err := decodeEntryBatchPrefix(batchBytes) - if timings != nil { - timings.transactionParse += time.Since(parseStart) - } - // A zero entry count with more bytes denotes a marker. Preserve the - // rejection of unrecognized or misplaced markers in this fallback path. - if err == nil && len(batchEntries) == 0 && consumed != len(batchBytes) { - err = fmt.Errorf("entry batch has %d trailing bytes", len(batchBytes)-consumed) - } - if err != nil { - return nil, nil, nil, fmt.Errorf("decode entry batch ending at shred %d: %w", shred.Index, err) - } - entryBatches = append(entryBatches, decodedEntryBatch{ - start: batchStart, - entries: batchEntries, - }) + entryBatches = append(entryBatches, batch) // Decoded transactions retain slices into the batch buffer for instruction data. // Keep the backing array alive instead of reusing and overwriting it. batchBytes = nil @@ -199,10 +224,43 @@ func decodeEntriesAndAlpenglowMarkersFromDataShreds(shreds []*Shred, timings *en continue } entries = append(entries, batch.entries...) + if timings != nil { + timings.retained = append(timings.retained, batch) + } } return entries, parentInfo, blockFooter, nil } +// decodeClosedShredBatch owns raw through the returned decoded transactions. +// It decodes the same padded component envelope for early and full assembly; +// marker merging and UpdateParent selection still require the full slot. +func decodeClosedShredBatch(raw []byte, start, end uint32) *prefetchedShredBatch { + batch := &prefetchedShredBatch{start: start, end: end, raw: raw} + parent, footer, marker, err := decodeAlpenglowMarkerFromShredBatch(raw, start) + if err != nil { + batch.err = fmt.Errorf("decode alpenglow block marker ending at shred %d: %w", end, err) + return batch + } + if marker { + batch.parent, batch.footer, batch.marker = parent, footer, true + return batch + } + parseStarted := time.Now() + entries, consumed, err := decodeEntryBatchPrefix(raw) + batch.parseDuration = time.Since(parseStarted) + // A zero entry count with more bytes denotes a marker. Preserve rejection + // of unknown or misplaced markers instead of treating them as an empty batch. + if err == nil && len(entries) == 0 && consumed != len(raw) { + err = fmt.Errorf("entry batch has %d trailing bytes", len(raw)-consumed) + } + if err != nil { + batch.err = fmt.Errorf("decode entry batch ending at shred %d: %w", end, err) + return batch + } + batch.entries = entries + return batch +} + func decodeEntryBatch(data []byte) ([]Entry, error) { entries, consumed, err := decodeEntryBatchPrefix(data) if err != nil { diff --git a/pkg/turbine/entries_prefetch_test.go b/pkg/turbine/entries_prefetch_test.go new file mode 100644 index 00000000..9ecdbf59 --- /dev/null +++ b/pkg/turbine/entries_prefetch_test.go @@ -0,0 +1,146 @@ +package turbine + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/gagliardetto/solana-go" + "github.com/stretchr/testify/require" +) + +func decodedPrefetchForTest(shreds []*Shred) map[uint32]*prefetchedShredBatch { + cache := make(map[uint32]*prefetchedShredBatch) + var raw []byte + var start uint32 + for _, shred := range shreds { + if raw == nil { + start = shred.Index + } + raw = append(raw, shred.Data...) + if shred.DataComplete() { + batch := decodeClosedShredBatch(raw, start, shred.Index) + batch.ready = make(chan struct{}) + close(batch.ready) + cache[start] = batch + raw = nil + } + } + return cache +} + +func TestEntryDecodeReusesOnlyExactPrefetchedBytesAndBounds(t *testing.T) { + component, err := NewEntryBatch([]Entry{{Hash: solana.Hash{9}, Txns: []solana.Transaction{mustParseTransferTx(t, 21)}}}) + require.NoError(t, err) + raw, err := MarshalBlockComponent(component) + require.NoError(t, err) + for _, mode := range []string{"match", "different_bytes", "different_end", "different_start"} { + t.Run(mode, func(t *testing.T) { + shreds := paddedComponentShreds(t, raw, 0, 0xa5) + cache := decodedPrefetchForTest(shreds) + cached := cache[0] + require.NoError(t, cached.err) + cached.parseDuration = time.Hour // must not enter final parse accounting + if mode != "match" { + cached.err = errors.New("stale cached failure must be ignored") + } + switch mode { + case "different_bytes": + cached.raw[len(cached.raw)-1] ^= 1 // even differing padding invalidates reuse + case "different_end": + cached.end++ + cached.ready = make(chan struct{}) // mismatched bounds must never wait + case "different_start": + cached.start++ + cached.ready = make(chan struct{}) + } + timings := entryDecodeTimings{prefetched: cache} + entries, _, _, err := decodeEntriesAndAlpenglowMarkersFromDataShreds(shreds, &timings) + require.NoError(t, err) + require.Len(t, entries, 1) + require.Len(t, timings.all, 1) + require.Len(t, timings.retained, 1) + if mode == "match" { + require.Same(t, cached, timings.retained[0]) + require.Same(t, &cached.entries[0].Txns[0], &entries[0].Txns[0]) + require.Zero(t, timings.transactionParse) + } else { + require.NotSame(t, cached, timings.retained[0]) + require.Less(t, timings.transactionParse, time.Hour) + } + }) + } +} + +func TestEntryDecodePrefetchPreparationWaitHonorsCancellation(t *testing.T) { + raw, err := marshalEntryBatch([]Entry{{Hash: solana.Hash{3}}}) + require.NoError(t, err) + shreds := paddedComponentShreds(t, raw, 0, 0) + cache := decodedPrefetchForTest(shreds) + cache[0].ready = make(chan struct{}) + ctx, cancel := context.WithCancel(context.Background()) + cancel() + timings := entryDecodeTimings{ctx: ctx, prefetched: cache} + _, _, _, err = decodeEntriesAndAlpenglowMarkersFromDataShreds(shreds, &timings) + require.ErrorIs(t, err, context.Canceled) + require.Empty(t, timings.retained) + require.Zero(t, timings.transactionParse) +} + +func TestEntryDecodePrefetchPreservesUpdateParentAndIgnoresVerificationErrors(t *testing.T) { + prefix, err := NewEntryBatch([]Entry{{Hash: solana.Hash{1}, Txns: []solana.Transaction{mustParseTransferTx(t, 20)}}}) + require.NoError(t, err) + suffix, err := NewEntryBatch([]Entry{{Hash: solana.Hash{2}, Txns: []solana.Transaction{mustParseTransferTx(t, 21)}}}) + require.NoError(t, err) + components := []BlockComponent{NewBlockHeader(99, solana.Hash{9}), prefix, NewUpdateParent(98, solana.Hash{8}), suffix, NewBlockFooter(BlockFooter{BankHash: solana.Hash{7}})} + var shreds []*Shred + for _, component := range components { + raw, err := MarshalBlockComponent(component) + require.NoError(t, err) + shreds = append(shreds, paddedComponentShreds(t, raw, uint32(len(shreds)), 0xa5)...) + } + cache := decodedPrefetchForTest(shreds) + for _, start := range []uint32{32, 96} { + // Decoding must not make a signature decision, even for retained entries. + cache[start].verification = &transactionVerification{err: errors.New("signature result belongs to completion")} + cache[start].submitErr = errors.New("submission result belongs to completion") + } + timings := entryDecodeTimings{prefetched: cache} + entries, parent, footer, err := decodeEntriesAndAlpenglowMarkersFromDataShreds(shreds, &timings) + require.NoError(t, err) + require.Len(t, entries, 1) + require.Equal(t, solana.Hash{2}, entries[0].Hash) + require.Equal(t, uint32(64), parent.ReplayFECSetIndex) + require.Equal(t, solana.Hash{7}, footer.BankHash) + require.Len(t, timings.all, 5) + require.Len(t, timings.retained, 1) + require.Same(t, cache[96], timings.retained[0]) + + // Parsing the discarded prefix remains mandatory, unlike its signatures. + cache[32].err = errors.New("malformed optimistic prefix") + timings = entryDecodeTimings{prefetched: cache} + _, _, _, err = decodeEntriesAndAlpenglowMarkersFromDataShreds(shreds, &timings) + require.ErrorContains(t, err, "malformed optimistic prefix") +} + +func TestEntryDecodePrefetchedAgavePaddedCaptureMatchesFullDecode(t *testing.T) { + packets := agavePaddedSlot1752420Packets(t) + shreds := make([]*Shred, len(packets)) + for i, packet := range packets { + var err error + shreds[i], err = ParseShred(packet) + require.NoError(t, err) + } + wantEntries, wantParent, wantFooter, err := DecodeEntriesAndAlpenglowMarkersFromDataShreds(shreds) + require.NoError(t, err) + timings := entryDecodeTimings{prefetched: decodedPrefetchForTest(shreds)} + entries, parent, footer, err := decodeEntriesAndAlpenglowMarkersFromDataShreds(shreds, &timings) + require.NoError(t, err) + require.Equal(t, wantEntries, entries) + require.Equal(t, wantParent, parent) + require.Equal(t, wantFooter, footer) + require.Len(t, timings.all, 4) + require.Len(t, timings.retained, 2) + require.Zero(t, timings.transactionParse) +} diff --git a/pkg/turbine/entry_prefetch.go b/pkg/turbine/entry_prefetch.go new file mode 100644 index 00000000..5816b1e8 --- /dev/null +++ b/pkg/turbine/entry_prefetch.go @@ -0,0 +1,343 @@ +package turbine + +import ( + "context" + "errors" + "sync" + "time" + + "github.com/Overclock-Validator/mithril/pkg/block" + "github.com/gagliardetto/solana-go" +) + +const ( + entryPrefetchSlots = 8 + // Covers a large block of maximum-size transactions while bounding the + // extra retained encoded bytes across all in-flight generations. + entryPrefetchBytes = 64 << 20 + entryPrefetchBatchBytes = 1 << 20 +) + +type shredBatchRange struct{ start, end uint32 } + +// A result belongs to one exact DATA_COMPLETE range in one slot generation. +// Fields are immutable after ready closes; signature readers own its decoded +// transactions until verification.done closes. +type prefetchedShredBatch struct { + start, end uint32 + raw []byte + entries []Entry + parent *AlpenglowParentInfo + footer *BlockFooter + marker bool + parseDuration time.Duration + err error + ready chan struct{} + verification *transactionVerification + submittedAt time.Time + submitErr error +} + +type slotEntryPrefetch struct { + pool *entryPrefetchPool + ctx context.Context + cancel context.CancelFunc + batches map[uint32]*prefetchedShredBatch + next int + queued, released bool + bytes int +} + +// All scheduling and accounting use assembler.mu. The packet reader only +// advances a contiguous frontier and attempts a nonblocking, coalesced enqueue. +// Decoding and bounded verifier admission run on separate background workers. +type entryPrefetchPool struct { + a *SlotAssembler + ctx context.Context + cancel context.CancelFunc + verifier *transactionVerifier + jobs chan *slotState + workers, cleanup sync.WaitGroup + slots, bytes int + closed bool + close sync.Once +} + +func newEntryPrefetchPool(ctx context.Context, a *SlotAssembler, verifier *transactionVerifier) *entryPrefetchPool { + ctx, cancel := context.WithCancel(ctx) + p := &entryPrefetchPool{a: a, ctx: ctx, cancel: cancel, verifier: verifier, jobs: make(chan *slotState, entryPrefetchSlots)} + a.mu.Lock() + a.entryPrefetch = p + a.mu.Unlock() + p.workers.Add(2) + for i := 0; i < 2; i++ { + go p.run() + } + return p +} + +func (a *SlotAssembler) prefetchEntriesLocked(s *slotState) { + p := a.entryPrefetch + if p == nil || p.closed || p.ctx.Err() != nil { + return + } + // Each index is visited once, even when one batch spans many FEC sets or + // arrives out of order. A gap never yields a speculative partial decode. + for s.batchScan < maxDataShredsPerSlot { + sh := s.shreds[s.batchScan] + if sh == nil { + break + } + if sh.DataComplete() { + s.completeBatches = append(s.completeBatches, shredBatchRange{s.batchStart, s.batchScan}) + s.batchStart = s.batchScan + 1 + } + s.batchScan++ + } + if s.prefetch == nil && len(s.completeBatches) > 0 && p.slots < entryPrefetchSlots { + ctx, cancel := context.WithCancel(p.ctx) + s.prefetch = &slotEntryPrefetch{pool: p, ctx: ctx, cancel: cancel, batches: make(map[uint32]*prefetchedShredBatch)} + p.slots++ + } + p.enqueueLocked(s) +} + +func (p *entryPrefetchPool) enqueueLocked(s *slotState) { + f := s.prefetch + if f == nil || f.pool != p || f.queued || f.released || s.completing || p.closed || f.next >= len(s.completeBatches) { + return + } + select { + case p.jobs <- s: + f.queued = true + default: + } +} + +func (p *entryPrefetchPool) run() { + defer p.workers.Done() + for s := range p.jobs { + p.a.mu.Lock() + f := s.prefetch + if p.closed || f.released || f.ctx.Err() != nil || p.a.slots[s.slot] != s || s.completing { + f.queued = false + p.a.mu.Unlock() + continue + } + var batch *prefetchedShredBatch + var shreds []*Shred + var rawSize int + for f.next < len(s.completeBatches) { + r := s.completeBatches[f.next] + size := 0 + for i := r.start; i <= r.end; i++ { + size += len(s.shreds[i].Data) + if size > entryPrefetchBatchBytes { + break + } + } + if size > entryPrefetchBatchBytes { + f.next++ + continue + } + if p.bytes+size > entryPrefetchBytes { + break + } + f.next++ + p.bytes += size + f.bytes += size + rawSize = size + batch = &prefetchedShredBatch{start: r.start, end: r.end, ready: make(chan struct{})} + f.batches[r.start] = batch + shreds = make([]*Shred, 0, r.end-r.start+1) + for i := r.start; i <= r.end; i++ { + shreds = append(shreds, s.shreds[i]) + } + break + } + if batch == nil { + f.queued = false + p.a.mu.Unlock() + continue + } + p.a.mu.Unlock() + + raw := make([]byte, 0, rawSize) + for _, sh := range shreds { + raw = append(raw, sh.Data...) + } + decoded := decodeClosedShredBatch(raw, batch.start, batch.end) + ready := batch.ready + batch.raw, batch.entries = decoded.raw, decoded.entries + batch.parent, batch.footer, batch.marker = decoded.parent, decoded.footer, decoded.marker + batch.parseDuration, batch.err = decoded.parseDuration, decoded.err + if batch.err == nil && !batch.marker && f.ctx.Err() == nil { + txs := entryBatchTransactions(batch.entries) + if len(txs) > 0 { + batch.submittedAt = time.Now() + batch.verification, batch.submitErr = p.verifier.submitTransactions(f.ctx, txs) + } + } + close(ready) + p.a.mu.Lock() + f.queued = false + p.enqueueLocked(s) + p.a.mu.Unlock() + } +} + +func entryBatchTransactions(entries []Entry) []*solana.Transaction { + var txs []*solana.Transaction + for i := range entries { + for j := range entries[i].Txns { + txs = append(txs, &entries[i].Txns[j]) + } + } + return txs +} + +// Keep reservations until canceled readers have actually relinquished their +// buffers. Repeated resets cannot evade the memory or slot bounds. +func (a *SlotAssembler) releasePrefetchLocked(s *slotState) { + if s == nil || s.prefetch == nil || s.prefetch.released { + return + } + f := s.prefetch + f.released = true + f.cancel() + p := f.pool + p.cleanup.Add(1) + go func() { + defer p.cleanup.Done() + for _, b := range f.batches { + <-b.ready + if b.verification != nil { + b.verification.wait() + } + } + p.a.mu.Lock() + p.slots-- + p.bytes -= f.bytes + p.a.mu.Unlock() + }() +} + +func (p *entryPrefetchPool) closeAndWait() { + p.close.Do(func() { + p.cancel() + p.a.mu.Lock() + p.closed = true + if p.a.entryPrefetch == p { + p.a.entryPrefetch = nil + } + for _, s := range p.a.slots { + if s.prefetch != nil && s.prefetch.pool == p { + p.a.releasePrefetchLocked(s) + } + } + close(p.jobs) + p.a.mu.Unlock() + p.workers.Wait() + p.cleanup.Wait() + }) +} + +// Reuse only retained entry results. UpdateParent may intentionally discard an +// invalid optimistic prefix. Unprefetched transactions form one immediately +// available request, overlapping any early requests still running. +func verifyDecodedEntryBatches(ctx context.Context, blk *block.Block, batches []*prefetchedShredBatch, verifier *transactionVerifier) error { + type pending struct { + future *transactionVerification + offset int + } + var early []pending + var missing []*solana.Transaction + var indices []int + offset := 0 + for _, b := range batches { + count := 0 + for _, e := range b.entries { + count += len(e.Txns) + } + reusable := b.verification != nil + if reusable { + select { + case <-b.verification.done: + // Cancellation is not a signature verdict. A completion canceled + // after preparation may be retried on this same slot generation. + reusable = !errors.Is(b.verification.err, context.Canceled) && !errors.Is(b.verification.err, context.DeadlineExceeded) + default: + } + } + if reusable { + early = append(early, pending{b.verification, offset}) + } else { + missing = append(missing, blk.Transactions[offset:offset+count]...) + for i := 0; i < count; i++ { + indices = append(indices, offset+i) + } + } + offset += count + } + var fallback *transactionVerification + var err error + if len(missing) > 0 { + fallback, err = verifier.submitTransactions(ctx, missing) + } + firstIndex := len(blk.Transactions) + firstErr := err + for _, p := range early { + i, e := p.future.waitContext(ctx) + if e != nil && (firstErr == nil || (i >= 0 && p.offset+i < firstIndex)) { + firstErr = e + if i >= 0 { + firstIndex = p.offset + i + } + } + } + if fallback != nil { + i, e := fallback.waitContext(ctx) + if e != nil && (firstErr == nil || (i >= 0 && indices[i] < firstIndex)) { + firstErr = e + if i >= 0 { + firstIndex = indices[i] + } + } + } + if ctx.Err() != nil { + return ctx.Err() + } + if firstErr != nil && firstIndex < len(blk.Transactions) { + return formatTransactionVerificationError(blk, firstIndex, firstErr) + } + return firstErr +} + +func earlyEntryTimings(t *entryDecodeTimings, fullAt time.Time, timings *block.TurbineIngressTimings) { + for _, b := range t.all { + if b.ready == nil { + continue + } + timings.EarlyTransactionParse += b.parseDuration + if b.verification != nil { + select { + case <-b.verification.done: + timings.EarlyTransactionSigverify += b.verification.finishedAt.Sub(b.submittedAt) + default: + } + } + } + for _, b := range t.retained { + if b.verification != nil { + select { + case <-b.verification.done: + if b.verification.err == nil && !b.verification.finishedAt.After(fullAt) { + for _, e := range b.entries { + timings.EarlyVerifiedTransactions += uint64(len(e.Txns)) + } + } + default: + } + } + } +} diff --git a/pkg/turbine/entry_prefetch_benchmark_test.go b/pkg/turbine/entry_prefetch_benchmark_test.go new file mode 100644 index 00000000..4a0f14e7 --- /dev/null +++ b/pkg/turbine/entry_prefetch_benchmark_test.go @@ -0,0 +1,217 @@ +package turbine + +import ( + "context" + "crypto/ed25519" + "encoding/binary" + "fmt" + "testing" + "time" + + "github.com/Overclock-Validator/mithril/pkg/block" + "github.com/Overclock-Validator/mithril/pkg/sigverify" + "github.com/gagliardetto/solana-go" +) + +// BenchmarkEntryPrefetchAssembly runs actual assembler ingestion, component +// decoding, final Merkle identity checks, transaction verification, and final +// publication. Source transactions use the same generated 228/1232-byte or +// captured fixtures as BenchmarkTransactionVerificationFlow. Generation, +// packet parsing and shred-signature authentication happen outside the timer. +// There is no network I/O, loss/recovery, replay, PoH or footer-bankhash execution. +// +// Complete component bursts are scheduled across 200 ms for tip scenarios; +// catchup offers all shreds immediately. This is a workload model, not a +// measured cluster arrival distribution. A 60 KiB signed-transaction budget +// defines components; actual entry overhead and FEC padding are generated. +// Pools persist across iterations; the identical fixture slot is reset between +// samples outside the timer. Use fixed counts (e.g. -benchtime=3x). +func BenchmarkEntryPrefetchAssembly(b *testing.B) { + flowConfigureBackend(b) + for _, source := range flowBenchmarkFixtures(b) { + b.Run(source.name, func(b *testing.B) { + fixture := makeAssemblyFlowFixture(b, source.blk) + for _, workers := range []int{2, 4} { + b.Run(fmt.Sprintf("workers_%d", workers), func(b *testing.B) { + for _, target := range []int{4, 8} { + b.Run(fmt.Sprintf("target_%d", target), func(b *testing.B) { + for _, arrival := range []struct { + name string + span time.Duration + }{{"catchup", 0}, {"tip_200ms", 200 * time.Millisecond}} { + b.Run(arrival.name, func(b *testing.B) { + for _, overlap := range []bool{false, true} { + name := "overlap_off" + if overlap { + name = "overlap_on" + } + b.Run(name, func(b *testing.B) { + runAssemblyFlowBenchmark(b, source.blk, fixture, workers, target, arrival.span, overlap) + }) + } + }) + } + }) + } + }) + } + }) + } +} + +type assemblyFlowFixture struct { + components [][]*Shred + blockID solana.Hash + parentID solana.Hash + bankhash solana.Hash + shreds int +} + +func makeAssemblyFlowFixture(tb testing.TB, source *block.Block) assemblyFlowFixture { + tb.Helper() + fixture := assemblyFlowFixture{parentID: solana.Hash{31}, bankhash: solana.Hash{47}} + var seed [ed25519.SeedSize]byte + seed[0] = 193 // Public deterministic benchmark leader, not validator material. + leader := solana.PrivateKey(ed25519.NewKeyFromSeed(seed[:])) + public := solana.PublicKeyFromBytes(ed25519.PrivateKey(leader).Public().(ed25519.PublicKey)) + generator := ShredGenerator{Slot: 100, ParentSlot: 99, Version: 7, ReferenceTick: 63} + var nextData, nextCode uint32 + var chained solana.Hash + var roots []solana.Hash + appendComponent := func(component BlockComponent, last bool) { + raw, err := MarshalBlockComponent(component) + if err != nil { + tb.Fatal(err) + } + generated, dataEnd, codeEnd, err := generator.makeShredsFromData(leader, raw, last, chained, nextData, nextCode) + if err != nil { + tb.Fatal(err) + } + chained, nextData, nextCode = generated.chainedMerkleRoot, dataEnd, codeEnd + roots = append(roots, generated.fecSetRoots...) + var data []*Shred + for _, packet := range generated.packets { + shred, err := ParseShred(packet) + if err != nil { + tb.Fatal(err) + } + if shred.Type != ShredTypeData { + continue + } + if err := shred.VerifySignature(public); err != nil { + tb.Fatal(err) + } + data = append(data, shred) + } + fixture.components = append(fixture.components, data) + fixture.shreds += len(data) + } + appendComponent(NewBlockHeader(99, fixture.parentID), false) + for i, txs := range flowComponents(source.Transactions, 60*1024) { + entry := Entry{NumHashes: 1, Txns: make([]solana.Transaction, len(txs))} + binary.LittleEndian.PutUint64(entry.Hash[:], uint64(i+1)) + for j, tx := range txs { + entry.Txns[j] = *tx + } + appendComponent(BlockComponent{EntryBatch: []Entry{entry}}, false) + } + appendComponent(NewBlockFooter(BlockFooter{BankHash: fixture.bankhash}), true) + if nextData > maxDataShredsPerSlot { + tb.Fatalf("fixture requires %d data shreds; assembler limit is %d", nextData, maxDataShredsPerSlot) + } + fixture.blockID = DoubleMerkleBlockID(99, fixture.parentID, roots) + return fixture +} + +func runAssemblyFlowBenchmark(b *testing.B, source *block.Block, fixture assemblyFlowFixture, workers, target int, span time.Duration, overlap bool) { + v := newTransactionVerifierWithBatchTarget(workers, 2*workers*target, target, nil) + defer v.closeAndWait() + if err := v.verifyBlock(source); err != nil { + b.Fatal(err) + } + a := NewSlotAssembler() + a.verifyTransactions = v.verifyBlockContext + a.SetKnownAlpenglowBlockID(99, fixture.parentID) + a.SetKnownAlpenglowBlockID(100, fixture.blockID) + if overlap { + prefetch := newEntryPrefetchPool(context.Background(), a, v) + defer prefetch.closeAndWait() + } + var ready, parse, preparation, joins, arrivals []time.Duration + var early uint64 + var cpu float64 + before := sigverify.Stats() + b.ReportAllocs() + b.ResetTimer() + for range b.N { + b.StopTimer() + a.ResetSlot(100) + cpuStarted := flowCPUSeconds(b) + b.StartTimer() + started := time.Now() + var work *slotCompletionWork + for componentIndex, component := range fixture.components { + if span > 0 { + time.Sleep(time.Until(started.Add(flowArrivalOffset(componentIndex, len(fixture.components), span)))) + } + for _, shred := range component { + candidate, err := a.addShredFrom(shred, false) + if err != nil { + b.Fatal(err) + } + if candidate != nil { + if work != nil { + b.Fatal("slot claimed completion more than once") + } + work = candidate + } + } + } + if work == nil { + b.Fatal("all generated data shreds did not complete the slot") + } + processed := a.processCompletion(context.Background(), work) + completed, err := a.finalizeCompletion(work, processed) + b.StopTimer() + cpu += flowCPUSeconds(b) - cpuStarted + if err != nil || completed == nil { + b.Fatalf("completion failed: block=%v error=%v", completed != nil, err) + } + if !completed.TransactionSignaturesVerified() || len(completed.Transactions) != len(source.Transactions) || + !completed.HasAlpenglowBlockID || solana.Hash(completed.AlpenglowBlockID) != fixture.blockID || + !completed.HasExpectedBankhash || completed.ExpectedBankhash != fixture.bankhash { + b.Fatal("completion changed transaction coverage or authenticated block metadata") + } + ready = append(ready, processed.timings.FullToReady) + parse = append(parse, processed.timings.TransactionParse) + preparation = append(preparation, processed.timings.EarlyPreparationWait) + joins = append(joins, processed.timings.TransactionSigverify) + arrivals = append(arrivals, processed.timings.ShredCollection) + early += processed.timings.EarlyVerifiedTransactions + } + after := sigverify.Stats() + b.ReportMetric(cpu*1000/float64(b.N), "cpu-ms/block") + b.ReportMetric(cpu/b.Elapsed().Seconds(), "avg_cpu_cores") + b.ReportMetric(float64(early)/float64(b.N), "early_verified_tx/block") + b.ReportMetric(float64(len(source.Transactions)), "tx/block") + b.ReportMetric(float64(fixture.shreds), "data_shreds/block") + b.ReportMetric(float64(len(fixture.components)), "components/block") + if batches := after.Batches - before.Batches; batches > 0 { + b.ReportMetric(float64(after.Signatures-before.Signatures)/float64(batches), "mean_width") + } + flowReportPercentiles(b, ready, "full_to_ready") + flowReportPercentiles(b, parse, "completion_parse") + flowReportPercentiles(b, preparation, "preparation_wait") + flowReportPercentiles(b, joins, "completion_sigverify") + flowReportPercentiles(b, arrivals, "collection") + if after.InternalFaultFallbacks != before.InternalFaultFallbacks { + b.Fatal("signature verifier used an internal fault fallback") + } + var signatures uint64 + for _, tx := range source.Transactions { + signatures += uint64(len(tx.Signatures)) + } + if got, want := after.Signatures-before.Signatures, signatures*uint64(b.N); got != want { + b.Fatalf("verified %d signatures; want %d, exactly once per retained transaction", got, want) + } +} diff --git a/pkg/turbine/entry_prefetch_bounds_test.go b/pkg/turbine/entry_prefetch_bounds_test.go new file mode 100644 index 00000000..189ff25c --- /dev/null +++ b/pkg/turbine/entry_prefetch_bounds_test.go @@ -0,0 +1,50 @@ +package turbine + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestEntryPrefetchByteBoundsFallBackToCompleteVerification(t *testing.T) { + for _, mode := range []string{"budget_full", "oversized_component"} { + t.Run(mode, func(t *testing.T) { + v := newTransactionVerifier(2, 16, nil) + defer v.closeAndWait() + a := NewSlotAssembler() + p := newEntryPrefetchPool(context.Background(), a, v) + defer p.closeAndWait() + if mode == "budget_full" { + // Model other generations owning the entire encoded-byte budget. + a.mu.Lock() + p.bytes = entryPrefetchBytes + a.mu.Unlock() + defer func() { a.mu.Lock(); p.bytes -= entryPrefetchBytes; a.mu.Unlock() }() + } + raw := prefetchTestPayload(t, verifierSignedTransactions(t, 3)) + if mode == "oversized_component" { + // Ordinary entry components permit trailing FEC padding. The + // complete decoder must accept this even though prefetch skips it. + raw = append(raw, make([]byte, entryPrefetchBatchBytes+1-len(raw))...) + } + const slot = 400 + batches := prefetchTestShreds(t, slot, raw, buildAlpenglowEndingTick(t)) + require.Nil(t, feedPrefetchShreds(t, a, batches[0])) + require.Eventually(t, func() bool { + a.mu.Lock() + defer a.mu.Unlock() + f := a.slots[slot].prefetch + return f != nil && !f.queued && len(f.batches) == 0 + }, 3*time.Second, time.Millisecond) + blk := feedPrefetchShreds(t, a, batches[1]) + require.NotNil(t, blk) + require.Len(t, blk.Transactions, 3) + require.True(t, blk.TransactionSignaturesVerified()) + timings, ok := blk.TurbineIngressTimings() + require.True(t, ok) + require.Zero(t, timings.EarlyVerifiedTransactions) + }) + } +} diff --git a/pkg/turbine/entry_prefetch_test.go b/pkg/turbine/entry_prefetch_test.go new file mode 100644 index 00000000..e22f514c --- /dev/null +++ b/pkg/turbine/entry_prefetch_test.go @@ -0,0 +1,360 @@ +package turbine + +import ( + "context" + "errors" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/Overclock-Validator/mithril/pkg/block" + "github.com/Overclock-Validator/mithril/pkg/txverify" + "github.com/gagliardetto/solana-go" + "github.com/stretchr/testify/require" +) + +func prefetchTestPayload(t *testing.T, txs []*solana.Transaction) []byte { + t.Helper() + entry := Entry{NumHashes: 1, Hash: solana.Hash{7}, Txns: make([]solana.Transaction, len(txs))} + for i, tx := range txs { + entry.Txns[i] = *tx + } + raw, err := marshalEntryBatch([]Entry{entry}) + require.NoError(t, err) + return raw +} + +func prefetchTestShreds(t *testing.T, slot uint64, payloads ...[]byte) [][]*Shred { + t.Helper() + gen := ShredGenerator{Slot: slot, ParentSlot: slot - 1, Version: 1} + var nextData, nextCode uint32 + var root solana.Hash + batches := make([][]*Shred, len(payloads)) + for i, raw := range payloads { + packets, nextRoot, data, code, err := gen.MakeShredsFromData(testShredLeader(t), raw, i == len(payloads)-1, root, nextData, nextCode) + require.NoError(t, err) + root, nextData, nextCode = nextRoot, data, code + for _, packet := range packets { + shred, err := ParseShred(packet) + require.NoError(t, err) + if shred.Type == ShredTypeData { + batches[i] = append(batches[i], shred) + } + } + } + return batches +} + +func feedPrefetchShreds(t *testing.T, a *SlotAssembler, shreds []*Shred) *block.Block { + t.Helper() + var result *block.Block + for _, shred := range shreds { + blk, err := a.AddShred(shred) + require.NoError(t, err) + if blk != nil { + require.Nil(t, result) + result = blk + } + } + return result +} + +func waitPrefetchedBatch(t *testing.T, a *SlotAssembler, slot uint64, start uint32) *prefetchedShredBatch { + t.Helper() + var batch *prefetchedShredBatch + require.Eventually(t, func() bool { + a.mu.Lock() + defer a.mu.Unlock() + if s := a.slots[slot]; s != nil && s.prefetch != nil { + batch = s.prefetch.batches[start] + } + return batch != nil + }, 3*time.Second, time.Millisecond) + waitSignal(t, batch.ready, "prefetched component preparation") + require.NoError(t, batch.err) + require.NoError(t, batch.submitErr) + return batch +} + +func TestEntryPrefetchVerifiesBeforeLastShredAndReusesResults(t *testing.T) { + var calls atomic.Int32 + v := newTransactionVerifier(2, 16, func(tx *solana.Transaction) error { + calls.Add(1) + return txverify.VerifyTransaction(tx) + }) + defer v.closeAndWait() + a := NewSlotAssembler() + p := newEntryPrefetchPool(context.Background(), a, v) + defer p.closeAndWait() + const slot = 100 + batches := prefetchTestShreds(t, slot, + prefetchTestPayload(t, verifierSignedTransactions(t, 3)), + prefetchTestPayload(t, verifierSignedTransactions(t, 4))) + require.Nil(t, feedPrefetchShreds(t, a, batches[0])) + cached := waitPrefetchedBatch(t, a, slot, 0) + require.NotNil(t, cached.verification) + _, err := cached.verification.wait() + require.NoError(t, err) + require.Equal(t, int32(3), calls.Load()) + for range 5 { + require.Nil(t, feedPrefetchShreds(t, a, batches[0])) + } + blk := feedPrefetchShreds(t, a, batches[1]) + require.NotNil(t, blk) + require.Len(t, blk.Transactions, 7) + require.True(t, blk.TransactionSignaturesVerified()) + require.Equal(t, int32(7), calls.Load(), "cached transactions must not be verified twice") + timings, ok := blk.TurbineIngressTimings() + require.True(t, ok) + require.Equal(t, uint64(3), timings.EarlyVerifiedTransactions) + require.LessOrEqual(t, cached.verification.finishedAt.UnixNano(), blk.ShredFullNanos) +} + +func TestEntryPrefetchWaitsForGapAcrossMultipleFECSets(t *testing.T) { + var calls atomic.Int32 + v := newTransactionVerifier(2, 16, func(*solana.Transaction) error { calls.Add(1); return nil }) + defer v.closeAndWait() + a := NewSlotAssembler() + p := newEntryPrefetchPool(context.Background(), a, v) + defer p.closeAndWait() + const slot = 104 + batches := prefetchTestShreds(t, slot, + prefetchTestPayload(t, verifierSignedTransactions(t, 300)), buildAlpenglowEndingTick(t)) + require.Greater(t, len(batches[0]), dataShredsPerFECBlock) + // Arrival of DATA_COMPLETE and later FEC sets cannot bypass the hole. + for i := len(batches[0]) - 1; i >= 0; i-- { + if i != 1 { + require.Nil(t, feedPrefetchShreds(t, a, batches[0][i:i+1])) + } + } + a.mu.Lock() + require.Empty(t, a.slots[slot].completeBatches) + require.Nil(t, a.slots[slot].prefetch) + a.mu.Unlock() + require.Zero(t, calls.Load()) + require.Nil(t, feedPrefetchShreds(t, a, batches[0][1:2])) + cached := waitPrefetchedBatch(t, a, slot, 0) + _, err := cached.verification.wait() + require.NoError(t, err) + require.Equal(t, int32(300), calls.Load()) + blk := feedPrefetchShreds(t, a, batches[1]) + require.NotNil(t, blk) + require.Equal(t, int32(300), calls.Load()) +} + +func TestEntryPrefetchResetKeepsOldReservationsUntilReadersJoin(t *testing.T) { + txs := verifierSignedTransactions(t, 2) + txs[0].Signatures[0][9] ^= 0x40 + oldSignature := txs[0].Signatures[0] + started := make(chan struct{}) + release := make(chan struct{}) + var releaseOnce sync.Once + v := newTransactionVerifier(1, 8, func(tx *solana.Transaction) error { + if tx.Signatures[0] == oldSignature { + close(started) + <-release + } + return txverify.VerifyTransaction(tx) + }) + defer v.closeAndWait() + a := NewSlotAssembler() + p := newEntryPrefetchPool(context.Background(), a, v) + defer p.closeAndWait() + defer releaseOnce.Do(func() { close(release) }) + const slot = 108 + old := prefetchTestShreds(t, slot, prefetchTestPayload(t, txs[:1]), buildAlpenglowEndingTick(t)) + fresh := prefetchTestShreds(t, slot, prefetchTestPayload(t, txs[1:]), buildAlpenglowEndingTick(t)) + require.Nil(t, feedPrefetchShreds(t, a, old[0])) + waitSignal(t, started, "old generation verifier") + oldBatch := waitPrefetchedBatch(t, a, slot, 0) + a.ResetSlot(slot) + a.mu.Lock() + require.Equal(t, 1, p.slots) + require.Positive(t, p.bytes) + a.mu.Unlock() + require.Nil(t, feedPrefetchShreds(t, a, fresh[0])) + newBatch := waitPrefetchedBatch(t, a, slot, 0) + require.NotSame(t, oldBatch, newBatch) + a.mu.Lock() + require.Equal(t, 2, p.slots) + a.mu.Unlock() + releaseOnce.Do(func() { close(release) }) + _, err := oldBatch.verification.wait() + require.ErrorIs(t, err, context.Canceled) + _, err = newBatch.verification.wait() + require.NoError(t, err) + blk := feedPrefetchShreds(t, a, fresh[1]) + require.NotNil(t, blk) + require.Equal(t, txs[1].Signatures[0], blk.Transactions[0].Signatures[0]) + require.Eventually(t, func() bool { + a.mu.Lock() + defer a.mu.Unlock() + return p.slots == 0 && p.bytes == 0 + }, 3*time.Second, time.Millisecond) +} + +func TestEntryPrefetchSaturationDoesNotBlockShredAdmissionAndShutdownJoins(t *testing.T) { + started := make(chan struct{}) + release := make(chan struct{}) + var first, releaseOnce sync.Once + v := newTransactionVerifier(1, 8, func(*solana.Transaction) error { + first.Do(func() { close(started) }) + <-release + return nil + }) + defer v.closeAndWait() + a := NewSlotAssembler() + p := newEntryPrefetchPool(context.Background(), a, v) + defer p.closeAndWait() + defer releaseOnce.Do(func() { close(release) }) + payload := prefetchTestPayload(t, verifierSignedTransactions(t, 1)) + for i := 0; i < entryPrefetchSlots+1; i++ { + batches := prefetchTestShreds(t, uint64(200+i), payload, buildAlpenglowEndingTick(t)) + admitted := make(chan struct{}) + go func() { + defer close(admitted) + for _, sh := range batches[0] { + _, err := a.addShredFrom(sh, false) + if err != nil { + t.Errorf("admit shred: %v", err) + } + } + }() + waitSignal(t, admitted, "nonblocking ingress while prefetch saturated") + } + waitSignal(t, started, "blocked verifier") + a.mu.Lock() + require.Equal(t, entryPrefetchSlots, p.slots) + require.LessOrEqual(t, p.bytes, entryPrefetchBytes) + require.Nil(t, a.slots[200+entryPrefetchSlots].prefetch) + a.mu.Unlock() + done := make(chan struct{}) + go func() { p.closeAndWait(); close(done) }() + select { + case <-done: + t.Fatal("early pool released buffers before signature worker joined") + case <-time.After(20 * time.Millisecond): + } + releaseOnce.Do(func() { close(release) }) + waitSignal(t, done, "saturated pool shutdown") + a.mu.Lock() + require.Zero(t, p.slots) + require.Zero(t, p.bytes) + require.Nil(t, a.entryPrefetch) + a.mu.Unlock() +} + +func TestEntryPrefetchInvalidRetainedTransactionFailsClosed(t *testing.T) { + txs := verifierSignedTransactions(t, 3) + txs[1].Signatures[0][3] ^= 0x80 + v := newTransactionVerifier(2, 16, nil) + defer v.closeAndWait() + a := NewSlotAssembler() + p := newEntryPrefetchPool(context.Background(), a, v) + defer p.closeAndWait() + batches := prefetchTestShreds(t, 300, prefetchTestPayload(t, txs), buildAlpenglowEndingTick(t)) + require.Nil(t, feedPrefetchShreds(t, a, batches[0])) + cached := waitPrefetchedBatch(t, a, 300, 0) + index, err := cached.verification.wait() + require.Equal(t, 1, index) + require.ErrorContains(t, err, "invalid signature") + var finalErr error + for _, sh := range batches[1] { + blk, err := a.AddShred(sh) + require.Nil(t, blk) + if err != nil { + finalErr = err + } + } + require.ErrorContains(t, finalErr, "transaction 1") + require.False(t, a.SlotCompleted(300)) +} + +func TestEntryPrefetchUpdateParentDiscardsInvalidOptimisticPrefix(t *testing.T) { + txs := verifierSignedTransactions(t, 2) + txs[0].Signatures[0][3] ^= 0x80 + v := newTransactionVerifier(2, 16, nil) + defer v.closeAndWait() + a := NewSlotAssembler() + p := newEntryPrefetchPool(context.Background(), a, v) + defer p.closeAndWait() + const slot = 304 + batches := prefetchTestShreds(t, slot, + prefetchTestPayload(t, txs[:1]), + testAlpenglowParentMarkerBytes(blockMarkerVariantUpdateParent, slot-2, solana.Hash{12}), + prefetchTestPayload(t, txs[1:])) + require.Nil(t, feedPrefetchShreds(t, a, batches[0])) + cached := waitPrefetchedBatch(t, a, slot, 0) + _, err := cached.verification.wait() + require.ErrorContains(t, err, "invalid signature") + require.Nil(t, feedPrefetchShreds(t, a, batches[1])) + blk := feedPrefetchShreds(t, a, batches[2]) + require.NotNil(t, blk) + require.Len(t, blk.Transactions, 1) + require.Equal(t, txs[1].Signatures[0], blk.Transactions[0].Signatures[0]) + require.Equal(t, uint64(slot-2), blk.SourceParentSlot) + require.True(t, blk.TransactionSignaturesVerified()) +} + +func TestEntryPrefetchCanceledCompletionCanRetrySameGeneration(t *testing.T) { + started := make(chan struct{}) + release := make(chan struct{}) + var first, releaseOnce sync.Once + v := newTransactionVerifier(1, 8, func(tx *solana.Transaction) error { + first.Do(func() { close(started); <-release }) + return txverify.VerifyTransaction(tx) + }) + defer v.closeAndWait() + a := NewSlotAssembler() + p := newEntryPrefetchPool(context.Background(), a, v) + defer p.closeAndWait() + defer releaseOnce.Do(func() { close(release) }) + const slot = 308 + batches := prefetchTestShreds(t, slot, + prefetchTestPayload(t, verifierSignedTransactions(t, 3)), buildAlpenglowEndingTick(t)) + require.Nil(t, feedPrefetchShreds(t, a, batches[0])) + waitSignal(t, started, "early verification") + cached := waitPrefetchedBatch(t, a, slot, 0) + var work *slotCompletionWork + for _, sh := range batches[1] { + var err error + work, err = a.addShredFrom(sh, false) + require.NoError(t, err) + } + require.NotNil(t, work) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + canceled := make(chan struct{}) + originalCancel := cached.verification.cancel + cached.verification.cancel = func() { close(canceled); originalCancel() } + done := make(chan processedSlotCompletion, 1) + go func() { done <- a.processCompletion(ctx, work) }() + // The completion has no expensive decode left and blocks joining this + // one already-prepared future; cancel while it owns those transactions. + time.Sleep(20 * time.Millisecond) + cancel() + waitSignal(t, canceled, "completion canceled its signature request") + releaseOnce.Do(func() { close(release) }) + var processed processedSlotCompletion + select { + case processed = <-done: + case <-time.After(3 * time.Second): + t.Fatal("canceled completion failed to join") + } + require.True(t, processed.canceled) + _, err := a.finalizeCompletion(work, processed) + require.NoError(t, err) + _, err = cached.verification.wait() + require.True(t, errors.Is(err, context.Canceled)) + a.mu.Lock() + retry := a.claimCompletionLocked(a.slots[slot], false) + a.mu.Unlock() + require.NotNil(t, retry) + processed = a.processCompletion(context.Background(), retry) + require.NoError(t, processed.err) + blk, err := a.finalizeCompletion(retry, processed) + require.NoError(t, err) + require.NotNil(t, blk) + require.True(t, blk.TransactionSignaturesVerified()) +} diff --git a/pkg/turbine/receiver.go b/pkg/turbine/receiver.go index d042131a..69b67190 100644 --- a/pkg/turbine/receiver.go +++ b/pkg/turbine/receiver.go @@ -12,6 +12,7 @@ import ( "github.com/Overclock-Validator/mithril/pkg/block" "github.com/Overclock-Validator/mithril/pkg/gossip" + "github.com/Overclock-Validator/mithril/pkg/sigverify" "github.com/gagliardetto/solana-go" ) @@ -546,7 +547,6 @@ func (r *UDPReceiver) Run(ctx context.Context) error { r.retransmitter.Run(runCtx) }() } - r.signalReady(nil) completionPool := newSlotCompletionPool(r.assembler, &r.slotResetMu, r.startPendingBlock, defaultSlotCompletionWorkers(), slotCompletionQueueDepth) r.completionPool = completionPool completionDone := make(chan struct{}) @@ -555,6 +555,18 @@ func (r *UDPReceiver) Run(ctx context.Context) error { r.consumeCompletionResults(runCtx, completionPool.results) }() + // Install the bounded decode/verification stage before any packet reader + // or spool hydrator can expose a DATA_COMPLETE component. Custom verifiers + // used by callers/tests retain the whole-block completion path. + var entryPrefetch *entryPrefetchPool + r.assembler.mu.Lock() + useEntryPrefetch := !sigverify.Cfg.DisableShredOverlap && r.assembler.verifyTransactions == nil + r.assembler.mu.Unlock() + if useEntryPrefetch { + entryPrefetch = newEntryPrefetchPool(runCtx, r.assembler, getDefaultTransactionVerifier()) + } + r.signalReady(nil) + go func() { <-runCtx.Done() _ = liveConn.Close() @@ -562,8 +574,13 @@ func (r *UDPReceiver) Run(ctx context.Context) error { _ = repairConn.Close() } }() + var repairDone chan struct{} if repairConn != nil { - go r.repairClient.run(runCtx, repairConn, r.assembler) + repairDone = make(chan struct{}) + go func() { + defer close(repairDone) + r.repairClient.run(runCtx, repairConn, r.assembler) + }() } var hydratorDone chan struct{} if r.spool != nil { @@ -604,6 +621,15 @@ func (r *UDPReceiver) Run(ctx context.Context) error { if retransmitDone != nil { <-retransmitDone } + if repairDone != nil { + <-repairDone + } + // Readers and hydration can no longer add components. Cancel and join + // the early stage before draining completion workers, while + // all transaction objects and the spool are still owned by this receiver. + if entryPrefetch != nil { + entryPrefetch.closeAndWait() + } // No submitters remain. Drain queued work while the spool hook and result // consumer are alive, then close results and join it before channel close. completionPool.closeAndWait() diff --git a/pkg/turbine/receiver_prefetch_lifecycle_test.go b/pkg/turbine/receiver_prefetch_lifecycle_test.go new file mode 100644 index 00000000..9a4311a4 --- /dev/null +++ b/pkg/turbine/receiver_prefetch_lifecycle_test.go @@ -0,0 +1,116 @@ +package turbine + +import ( + "context" + "sync" + "testing" + "time" + + "github.com/Overclock-Validator/mithril/pkg/block" + "github.com/Overclock-Validator/mithril/pkg/gossip" + "github.com/Overclock-Validator/mithril/pkg/sigverify" + "github.com/stretchr/testify/require" +) + +func TestReceiverEntryPrefetchLifecycle(t *testing.T) { + for _, tc := range []struct { + name string + disabled bool + custom bool + wantPool bool + }{ + {name: "default", wantPool: true}, + {name: "disabled", disabled: true}, + {name: "custom verifier", custom: true}, + } { + t.Run(tc.name, func(t *testing.T) { + previous := sigverify.Cfg.DisableShredOverlap + sigverify.Cfg.DisableShredOverlap = tc.disabled + defer func() { sigverify.Cfg.DisableShredOverlap = previous }() + r := NewUDPReceiver("127.0.0.1:0") + if tc.custom { + r.assembler.verifyTransactions = func(context.Context, *block.Block) error { return nil } + } + ctx, cancel := context.WithCancel(context.Background()) + done := make(chan struct{}) + var runErr error + go func() { runErr = r.Run(ctx); close(done) }() + defer func() { + cancel() + select { + case <-done: + case <-time.After(3 * time.Second): + t.Error("receiver did not join on cleanup") + } + }() + select { + case err := <-r.Ready(): + require.NoError(t, err) + case <-time.After(3 * time.Second): + t.Fatal("receiver did not become ready") + } + r.assembler.mu.Lock() + attached := r.assembler.entryPrefetch != nil + r.assembler.mu.Unlock() + require.Equal(t, tc.wantPool, attached, "pool must be attached before readiness") + cancel() + waitSignal(t, done, "receiver shutdown") + require.NoError(t, runErr) + r.assembler.mu.Lock() + detached := r.assembler.entryPrefetch == nil + r.assembler.mu.Unlock() + require.True(t, detached, "shutdown must detach early workers from the assembler") + }) + } +} + +func TestReceiverStartupFailureDoesNotAttachEntryPrefetch(t *testing.T) { + r := NewUDPReceiver("invalid::udp::address") + require.Error(t, r.Run(context.Background())) + require.Error(t, <-r.Ready()) + require.Nil(t, r.assembler.entryPrefetch) + _, blocksOpen := <-r.Blocks() + require.False(t, blocksOpen) +} + +func TestReceiverShutdownJoinsRepairScheduler(t *testing.T) { + r := NewUDPReceiver("127.0.0.1:0") + started := make(chan struct{}) + release := make(chan struct{}) + var first sync.Once + var releaseOnce sync.Once + require.NoError(t, r.SetRepairPeerSource(nil, func() []gossip.RepairPeer { + first.Do(func() { close(started) }) + <-release + return nil + })) + ctx, cancel := context.WithCancel(context.Background()) + done := make(chan struct{}) + var runErr error + go func() { runErr = r.Run(ctx); close(done) }() + defer func() { + releaseOnce.Do(func() { close(release) }) + cancel() + select { + case <-done: + case <-time.After(3 * time.Second): + t.Error("receiver did not join on cleanup") + } + }() + select { + case err := <-r.Ready(): + require.NoError(t, err) + case <-time.After(3 * time.Second): + t.Fatal("receiver did not become ready") + } + waitSignal(t, started, "repair scheduler peer lookup") + cancel() + select { + case <-done: + t.Fatal("receiver returned while repair scheduler was still running") + case <-time.After(20 * time.Millisecond): + } + releaseOnce.Do(func() { close(release) }) + waitSignal(t, done, "repair scheduler joined") + require.NoError(t, runErr) +} diff --git a/pkg/turbine/transaction_verifier.go b/pkg/turbine/transaction_verifier.go index e64e3669..f8a1d27d 100644 --- a/pkg/turbine/transaction_verifier.go +++ b/pkg/turbine/transaction_verifier.go @@ -3,8 +3,8 @@ package turbine import ( "context" "fmt" - "runtime" "sync" + "time" "github.com/Overclock-Validator/mithril/pkg/block" "github.com/Overclock-Validator/mithril/pkg/sigverify" @@ -12,105 +12,251 @@ import ( "github.com/gagliardetto/solana-go" ) -var errNilTransaction = fmt.Errorf("nil transaction") +var ( + errNilTransaction = fmt.Errorf("nil transaction") + errTransactionVerifierClosed = fmt.Errorf("transaction verifier closed") +) +// A job is formed before admission, from transactions which are already +// available. Workers never wait for more transactions to fill a vector group. type transactionVerifyJob struct { - tx *solana.Transaction - err *error - done *sync.WaitGroup + txs []*solana.Transaction + errs []error + start int + done chan<- *transactionVerifyJob } -type transactionVerifier struct { - jobs chan transactionVerifyJob - verify func(*solana.Transaction) error - workers int - // wave is how many transactions verifyBlockContext admits at once. It is - // workers * sigverify.BatchTarget so each worker can actually accumulate a - // full vector group rather than being handed one transaction at a time. - wave int - close sync.Once +// transactionVerification owns an asynchronous request until done closes. +// Transactions submitted to it must remain immutable until wait returns. +type transactionVerification struct { + done chan struct{} + cancel context.CancelFunc + index int + err error + finishedAt time.Time +} - worker sync.WaitGroup +func (r *transactionVerification) wait() (int, error) { + return r.waitContext(context.Background()) } -func newTransactionVerifier(workers, queueDepth int, verify func(*solana.Transaction) error) *transactionVerifier { - if workers < 1 { - workers = 1 +// waitContext cancels further admission when ctx is canceled, but joins every +// admitted job before returning. The caller may then safely release or mutate +// the transaction objects, including their backing message byte slices. +func (r *transactionVerification) waitContext(ctx context.Context) (int, error) { + if ctx == nil { + ctx = context.Background() } - wave := workers * sigverify.BatchTarget - if queueDepth < 1 { - queueDepth = 1 + select { + case <-r.done: + case <-ctx.Done(): + r.cancel() + <-r.done + return -1, ctx.Err() } + if err := ctx.Err(); err != nil { + return -1, err + } + return r.index, r.err +} + +type transactionVerifier struct { + jobs chan *transactionVerifyJob + verify func(*solana.Transaction) error + workers int + batchTarget int + // Each accepted request owns at most workers outstanding groups. The + // admission semaphore also bounds asynchronous request goroutines; callers + // apply backpressure before handing off another decoded component. + requests chan struct{} + request sync.WaitGroup + mu sync.Mutex + closed bool + stopped chan struct{} + close sync.Once + worker sync.WaitGroup +} + +func newTransactionVerifier(workers, queueDepth int, verify func(*solana.Transaction) error) *transactionVerifier { + return newTransactionVerifierWithBatchTarget(workers, queueDepth, sigverify.BatchTarget, verify) +} + +// queueDepth is a transaction budget, rounded up to whole groups. batchTarget +// counts signature lanes: multi-signature transactions stay indivisible and +// may exceed the target. Four/eight targets can be compared without changing +// the admission or cancellation policy. +func newTransactionVerifierWithBatchTarget(workers, queueDepth, batchTarget int, verify func(*solana.Transaction) error) *transactionVerifier { + workers = max(1, workers) + batchTarget = max(1, min(batchTarget, sigverify.BatchTarget)) + queueGroups := max(1, (queueDepth+batchTarget-1)/batchTarget) v := &transactionVerifier{ - jobs: make(chan transactionVerifyJob, queueDepth), - verify: verify, - workers: workers, - wave: wave, + jobs: make(chan *transactionVerifyJob, queueGroups), + verify: verify, + workers: workers, + batchTarget: batchTarget, + requests: make(chan struct{}, 2*workers), + stopped: make(chan struct{}), } v.worker.Add(workers) for i := 0; i < workers; i++ { go func() { defer v.worker.Done() - // Worker-local scratch reused across groups. - var ( - group []transactionVerifyJob - scr verifyScratch - ) + var batch txverify.BatchVerifier for job := range v.jobs { - group = sigverify.Drain(group, job, v.jobs, - sigverify.FairShare(len(v.jobs), v.workers, sigverify.BatchTarget)) - v.verifyGroup(group, &scr) - // Do not keep finished jobs reachable through the scratch. - clear(group) + v.verifyGroup(job, &batch) } }() } return v } -// verifyScratch is one worker's reusable buffers. -type verifyScratch struct { - txs []*solana.Transaction - errs []error - batch txverify.BatchVerifier -} - -// verifyGroup verifies a drained group and releases every job in it. -// -// Releasing happens in a defer covering the whole group, so no caller can be -// left waiting on a job that was drained into a batch which then failed — -// a stranded job would hang verifyBlockContext's done.Wait() forever. -func (v *transactionVerifier) verifyGroup(group []transactionVerifyJob, scr *verifyScratch) { - defer func() { - for _, job := range group { - job.done.Done() - } - }() - - // An injected verifier is a per-transaction function and stays that way; - // only the default path can batch. This seam is used by tests. +// verifyGroup releases its job even if signature verification panics. The +// request's bounded completion channel always has room for every pending job. +func (v *transactionVerifier) verifyGroup(job *transactionVerifyJob, batch *txverify.BatchVerifier) { + defer func() { job.done <- job }() if v.verify != nil { - for _, job := range group { - *job.err = verifyTransactionSafely(v.verify, job.tx) + for i, tx := range job.txs { + if tx == nil { + job.errs[i] = errNilTransaction + } else { + job.errs[i] = verifyTransactionSafely(v.verify, tx) + } } return } + verifyBatchSafely(batch, job.txs, job.errs) +} - scr.txs = scr.txs[:0] - for _, job := range group { - scr.txs = append(scr.txs, job.tx) +// submitTransactions admits one immutable decoded component or complete block. +// Admission is bounded and may block: call it from a decode/completion worker, +// never the UDP reader or while holding the assembler mutex. Cancellation of +// ctx stops further groups but still joins every admitted group. +func (v *transactionVerifier) submitTransactions(ctx context.Context, txs []*solana.Transaction) (*transactionVerification, error) { + if ctx == nil { + ctx = context.Background() + } + if err := ctx.Err(); err != nil { + return nil, err } - if cap(scr.errs) < len(scr.txs) { - scr.errs = make([]error, len(scr.txs)) + select { + case v.requests <- struct{}{}: + case <-ctx.Done(): + return nil, ctx.Err() + case <-v.stopped: + return nil, errTransactionVerifierClosed } - scr.errs = scr.errs[:len(scr.txs)] - verifyBatchSafely(&scr.batch, scr.txs, scr.errs) + v.mu.Lock() + if v.closed { + v.mu.Unlock() + <-v.requests + return nil, errTransactionVerifierClosed + } + v.request.Add(1) + v.mu.Unlock() + ctx, cancel := context.WithCancel(ctx) + r := &transactionVerification{done: make(chan struct{}), cancel: cancel, index: -1} + go func() { + defer v.request.Done() + defer func() { <-v.requests }() + defer cancel() + r.index, r.err = v.verifyTransactions(ctx, txs) + r.finishedAt = time.Now() + close(r.done) + }() + return r, nil +} + +// verifyTransactions keeps a rolling window instead of waiting for an entire +// worker wave. A slow group cannot idle workers whose earlier groups finished. +// One caller can queue at most workers groups, so a large catch-up block cannot +// put all its transactions ahead of a newly available component. +func (v *transactionVerifier) verifyTransactions(ctx context.Context, txs []*solana.Transaction) (int, error) { + if len(txs) == 0 { + return -1, ctx.Err() + } + window := min(v.workers, len(txs)) + completed := make(chan *transactionVerifyJob, window) + groups := make([]transactionVerifyJob, window) + errs := make([]error, window*v.batchTarget) + free := make([]*transactionVerifyJob, window) + for i := range groups { + groups[i].errs = errs[i*v.batchTarget : (i+1)*v.batchTarget] + groups[i].done = completed + free[i] = &groups[i] + } - for i, job := range group { - *job.err = scr.errs[i] + nextIndex, active := 0, 0 + failureIndex := -1 + var failure error + var pending *transactionVerifyJob + ctxDone := ctx.Done() + stopped := false + for active > 0 || (!stopped && nextIndex < len(txs)) { + if !stopped && ctx.Err() != nil { + stopped = true + ctxDone = nil + } + if stopped && active == 0 { + break + } + if !stopped && pending == nil && nextIndex < len(txs) && len(free) > 0 { + pending = free[len(free)-1] + free = free[:len(free)-1] + end := transactionVerifyGroupEnd(txs, nextIndex, v.batchTarget) + pending.start = nextIndex + pending.txs = txs[nextIndex:end] + pending.errs = pending.errs[:end-nextIndex] + clear(pending.errs) + } + var admission chan *transactionVerifyJob + if !stopped && pending != nil { + admission = v.jobs + } + select { + case admission <- pending: + nextIndex += len(pending.txs) + active++ + pending = nil + case job := <-completed: + active-- + for i, err := range job.errs { + if err != nil && (failureIndex < 0 || job.start+i < failureIndex) { + failureIndex, failure = job.start+i, err + stopped = true + } + } + job.txs = nil + clear(job.errs) + free = append(free, job) + case <-ctxDone: + stopped = true + ctxDone = nil + } + } + if err := ctx.Err(); err != nil { + return -1, err + } + return failureIndex, failure +} + +func transactionVerifyGroupEnd(txs []*solana.Transaction, start, target int) int { + end, signatures := start, 0 + for end < len(txs) && end-start < target { + count := 1 + if txs[end] != nil { + count = max(1, len(txs[end].Signatures)) + } + if end > start && signatures+count > target { + break + } + signatures += count + end++ + if signatures >= target { + break + } } - clear(scr.txs) + return end } // verifyBatchSafely mirrors verifyTransactionSafely: a panic in the verifier @@ -134,6 +280,11 @@ func (v *transactionVerifier) closeAndWait() { return } v.close.Do(func() { + v.mu.Lock() + v.closed = true + close(v.stopped) + v.mu.Unlock() + v.request.Wait() close(v.jobs) v.worker.Wait() }) @@ -162,47 +313,15 @@ func (v *transactionVerifier) verifyBlockContext(ctx context.Context, blk *block if blk == nil || len(blk.Transactions) == 0 { return nil } - // Admit one worker-wave at a time. A monster block still occupies every - // verifier lane, but cannot park tens of thousands of jobs ahead of a newly - // completed small block in the shared bounded queue. - for chunkStart := 0; chunkStart < len(blk.Transactions); chunkStart += v.wave { - if err := ctx.Err(); err != nil { - return err - } - chunkEnd := min(chunkStart+v.wave, len(blk.Transactions)) - errs := make([]error, chunkEnd-chunkStart) - var done sync.WaitGroup - for txIdx := chunkStart; txIdx < chunkEnd; txIdx++ { - if err := ctx.Err(); err != nil { - done.Wait() - return err - } - tx := blk.Transactions[txIdx] - errIdx := txIdx - chunkStart - if tx == nil { - errs[errIdx] = errNilTransaction - continue - } - done.Add(1) - select { - case v.jobs <- transactionVerifyJob{tx: tx, err: &errs[errIdx], done: &done}: - case <-ctx.Done(): - done.Done() - done.Wait() - return ctx.Err() - } - } - done.Wait() - if err := ctx.Err(); err != nil { - return err - } - for errIdx, err := range errs { - if err != nil { - return formatTransactionVerificationError(blk, chunkStart+errIdx, err) - } - } + request, err := v.submitTransactions(ctx, blk.Transactions) + if err != nil { + return err + } + index, err := request.wait() + if err != nil && index >= 0 { + return formatTransactionVerificationError(blk, index, err) } - return nil + return err } func formatTransactionVerificationError(blk *block.Block, txIdx int, err error) error { @@ -226,12 +345,17 @@ var ( defaultTransactionVerifier *transactionVerifier ) -func validateBlockTransactionsContext(ctx context.Context, blk *block.Block) error { +func getDefaultTransactionVerifier() *transactionVerifier { defaultTransactionVerifierOnce.Do(func() { - workers := max(1, (runtime.GOMAXPROCS(0)+1)/2) - defaultTransactionVerifier = newTransactionVerifier(workers, 2*workers*sigverify.BatchTarget, nil) + workers := sigverify.TransactionWorkers() + target := sigverify.TransactionBatchTarget() + defaultTransactionVerifier = newTransactionVerifierWithBatchTarget(workers, 2*workers*target, target, nil) }) - return defaultTransactionVerifier.verifyBlockContext(ctx, blk) + return defaultTransactionVerifier +} + +func validateBlockTransactionsContext(ctx context.Context, blk *block.Block) error { + return getDefaultTransactionVerifier().verifyBlockContext(ctx, blk) } func validateBlockTransactions(blk *block.Block) error { diff --git a/pkg/turbine/transaction_verifier_flow_benchmark_test.go b/pkg/turbine/transaction_verifier_flow_benchmark_test.go new file mode 100644 index 00000000..0c8ce131 --- /dev/null +++ b/pkg/turbine/transaction_verifier_flow_benchmark_test.go @@ -0,0 +1,479 @@ +package turbine + +import ( + "context" + "crypto/ed25519" + "encoding/base64" + "encoding/binary" + "encoding/json" + "fmt" + "os" + "path/filepath" + "sort" + "strconv" + "sync" + "syscall" + "testing" + "time" + + "github.com/Overclock-Validator/mithril/pkg/block" + "github.com/Overclock-Validator/mithril/pkg/sigverify" + "github.com/Overclock-Validator/mithril/pkg/txverify" + "github.com/gagliardetto/solana-go" +) + +// BenchmarkTransactionVerificationFlow measures the real verifier pool under +// simulated transaction availability, not actual network reception or replay. +// Decode and fixture generation are outside the timer. "tip" spreads complete +// components over 200 ms; this is an explicit workload model, not a claim about +// the cluster's observed component sizes or arrival distribution. No component +// waits for another component to fill a verification batch. +// +// Optional environment: +// +// MITHRIL_SIGVERIFY_FLOW_BACKEND=r51 (use -run '^$' in a fresh test process) +// MITHRIL_SIGVERIFY_FLOW_FIXTURES=/path/to/fixtures (block-*.json, base64 txs) +// MITHRIL_SIGVERIFY_FLOW_COUNT=33760 (generated count or captured prefix limit) +// +// Without captured fixtures, use reproducible signed 228-byte and 1232-byte +// legacy memo transactions. They are signature workloads, not replay fixtures. +// Use -benchtime=3x or another fixed count when comparing configurations so the +// deliberate arrival waits do not change the number of observations. +func BenchmarkTransactionVerificationFlow(b *testing.B) { + flowConfigureBackend(b) + for _, fixture := range flowBenchmarkFixtures(b) { + b.Run(fixture.name, func(b *testing.B) { + for _, workers := range []int{2, 4} { + b.Run(fmt.Sprintf("workers_%d", workers), func(b *testing.B) { + for _, target := range []int{4, 8} { + b.Run(fmt.Sprintf("target_%d", target), func(b *testing.B) { + for _, scenario := range flowScenarios(fixture.blk) { + b.Run(scenario.name, func(b *testing.B) { + flowRunBenchmark(b, workers, target, fixture.blk, scenario) + }) + } + }) + } + }) + } + }) + } +} + +type flowFixture struct { + name string + blk *block.Block +} + +type flowScenario struct { + name string + components [][]*solana.Transaction + arrivalSpan time.Duration + overlap bool +} + +func flowScenarios(blk *block.Block) []flowScenario { + // 60 KiB is a benchmark parameter only. Include signed transaction bytes; + // actual serialized entry/component overhead and shred recovery are omitted. + components := flowComponents(blk.Transactions, 60*1024) + scenarios := []flowScenario{ + {name: "catchup", components: [][]*solana.Transaction{blk.Transactions}}, + {name: "tip_200ms_after_complete", components: components, arrivalSpan: 200 * time.Millisecond}, + {name: "tip_200ms_overlap", components: components, arrivalSpan: 200 * time.Millisecond, overlap: true}, + } + // Sparse components expose tail behavior without requiring microsecond + // timer precision to deliver tens of thousands of tiny arrival events. + for _, width := range []int{4, 7, 8} { + txs := blk.Transactions[:min(256, len(blk.Transactions))] + var small [][]*solana.Transaction + for start := 0; start < len(txs); start += width { + small = append(small, txs[start:min(start+width, len(txs))]) + } + scenarios = append(scenarios, flowScenario{ + name: fmt.Sprintf("sparse_%dtx_200ms_overlap", width), components: small, + arrivalSpan: 200 * time.Millisecond, overlap: true, + }) + } + return scenarios +} + +func flowComponents(txs []*solana.Transaction, bytesPerComponent int) [][]*solana.Transaction { + var components [][]*solana.Transaction + start, size := 0, 0 + for i, tx := range txs { + wireSize, err := txverify.TransactionWireSize(tx) + if err != nil { + panic(err) // fixtures are validated before entering this helper + } + if i > start && size+wireSize > bytesPerComponent { + components = append(components, txs[start:i]) + start, size = i, 0 + } + size += wireSize + } + if start < len(txs) { + components = append(components, txs[start:]) + } + return components +} + +type flowObservation struct { + latencies []time.Duration + submits []time.Duration + feedLags []time.Duration + residual time.Duration + err error +} + +func flowArrivalOffset(index, count int, span time.Duration) time.Duration { + if count <= 1 { + return span + } + return time.Duration(int64(span) * int64(index) / int64(count-1)) +} + +func flowObserve(v *transactionVerifier, blk *block.Block, scenario flowScenario) flowObservation { + observation := flowObservation{ + latencies: make([]time.Duration, len(scenario.components)), + submits: make([]time.Duration, len(scenario.components)), + feedLags: make([]time.Duration, len(scenario.components)), + } + started := time.Now() + finalArrival := started.Add(scenario.arrivalSpan) + if !scenario.overlap { + time.Sleep(time.Until(finalArrival)) + submitStarted := time.Now() + future, err := v.submitTransactions(context.Background(), blk.Transactions) + submitDuration := time.Since(submitStarted) + if err != nil { + observation.err = err + return observation + } + _, observation.err = future.wait() + finished := future.finishedAt + for i := range observation.latencies { + available := started.Add(flowArrivalOffset(i, len(scenario.components), scenario.arrivalSpan)) + observation.latencies[i] = finished.Sub(available) + observation.submits[i] = submitDuration + observation.feedLags[i] = submitStarted.Sub(available) + } + observation.residual = max(0, finished.Sub(finalArrival)) + return observation + } + + var waiters sync.WaitGroup + errs := make([]error, len(scenario.components)) + finished := make([]time.Time, len(scenario.components)) + for i, txs := range scenario.components { + available := started.Add(flowArrivalOffset(i, len(scenario.components), scenario.arrivalSpan)) + time.Sleep(time.Until(available)) + submitStarted := time.Now() + observation.feedLags[i] = submitStarted.Sub(available) + future, err := v.submitTransactions(context.Background(), txs) + observation.submits[i] = time.Since(submitStarted) + if err != nil { + errs[i] = err + break + } + waiters.Add(1) + go func() { + defer waiters.Done() + _, errs[i] = future.wait() + finished[i] = future.finishedAt + observation.latencies[i] = finished[i].Sub(available) + }() + } + waiters.Wait() + for _, completed := range finished { + observation.residual = max(observation.residual, completed.Sub(finalArrival)) + } + for _, err := range errs { + if err != nil { + observation.err = err + break + } + } + return observation +} + +func flowRunBenchmark(b *testing.B, workers, target int, blk *block.Block, scenario flowScenario) { + v := newTransactionVerifierWithBatchTarget(workers, 2*workers*8, target, nil) + defer v.closeAndWait() + if err := v.verifyBlock(blk); err != nil { + b.Fatal(err) + } + flowBenchmarkGate(b) + var signatureCount int + for _, component := range scenario.components { + for _, tx := range component { + signatureCount += len(tx.Signatures) + } + } + var latencies, submits, feedLags, residuals []time.Duration + before := sigverify.Stats() + cpuBefore := flowCPUSeconds(b) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + observation := flowObserve(v, blk, scenario) + if observation.err != nil { + b.Fatal(observation.err) + } + latencies = append(latencies, observation.latencies...) + submits = append(submits, observation.submits...) + feedLags = append(feedLags, observation.feedLags...) + residuals = append(residuals, observation.residual) + } + b.StopTimer() + cpuSeconds := flowCPUSeconds(b) - cpuBefore + after := sigverify.Stats() + b.ReportMetric(1000*cpuSeconds/float64(b.N), "cpu-ms/block") + b.ReportMetric(cpuSeconds/b.Elapsed().Seconds(), "avg_cpu_cores") + b.ReportMetric(float64(b.N*signatureCount)/b.Elapsed().Seconds(), "signatures/s") + b.ReportMetric(float64(signatureCount), "signatures/block") + b.ReportMetric(float64(len(scenario.components)), "components/block") + b.ReportMetric(float64(after.Signatures-before.Signatures)/float64(after.Batches-before.Batches), "mean_width") + flowReportPercentiles(b, latencies, "ready") + flowReportPercentiles(b, submits, "submit") + flowReportPercentiles(b, feedLags, "feed_lag") + flowReportPercentiles(b, residuals, "residual") + if after.InternalFaultFallbacks != before.InternalFaultFallbacks { + b.Fatal("signature verifier used an internal fault fallback") + } + if want := uint64(b.N * signatureCount); after.Signatures-before.Signatures != want { + b.Fatalf("verified signature count = %d, want %d", after.Signatures-before.Signatures, want) + } +} + +// The optional rendezvous is outside the timer. An external contention runner +// starts the real execution probe after seeing READY, then creates START. Both +// paths are explicit files in that runner's output directory. This is only for +// coordination; ordinary benchmark invocations do no filesystem polling. +func flowBenchmarkGate(b *testing.B) { + b.Helper() + ready, start := os.Getenv("MITHRIL_SIGVERIFY_FLOW_READY"), os.Getenv("MITHRIL_SIGVERIFY_FLOW_START") + if ready == "" && start == "" { + return + } + if ready == "" || start == "" { + b.Fatal("set both MITHRIL_SIGVERIFY_FLOW_READY and MITHRIL_SIGVERIFY_FLOW_START") + } + // Go's first N=1 calibration and warmup must finish before the external + // execution probe starts. The runner selects a fixed N greater than one. + if b.N == 1 { + return + } + if err := os.WriteFile(ready, []byte(b.Name()+"\n"), 0600); err != nil { + b.Fatal(err) + } + deadline := time.Now().Add(30 * time.Second) + for { + if _, err := os.Stat(start); err == nil { + return + } else if !os.IsNotExist(err) { + b.Fatal(err) + } + if time.Now().After(deadline) { + b.Fatal("contention runner did not release benchmark within 30 seconds") + } + time.Sleep(time.Millisecond) + } +} + +func flowReportPercentiles(b *testing.B, values []time.Duration, prefix string) { + sort.Slice(values, func(i, j int) bool { return values[i] < values[j] }) + for _, percentile := range []int{50, 95} { + index := max(0, (len(values)*percentile+99)/100-1) + b.ReportMetric(float64(values[index])/float64(time.Millisecond), fmt.Sprintf("%s_p%d-ms", prefix, percentile)) + } +} + +func flowCPUSeconds(tb testing.TB) float64 { + tb.Helper() + var usage syscall.Rusage + if err := syscall.Getrusage(syscall.RUSAGE_SELF, &usage); err != nil { + tb.Fatal(err) + } + return float64(usage.Utime.Sec+usage.Stime.Sec) + float64(usage.Utime.Usec+usage.Stime.Usec)/1e6 +} + +var flowBackendOnce sync.Once +var flowBackendError error + +func flowConfigureBackend(tb testing.TB) { + tb.Helper() + flowBackendOnce.Do(func() { + if backend := os.Getenv("MITHRIL_SIGVERIFY_FLOW_BACKEND"); backend != "" { + _, flowBackendError = sigverify.Configure(sigverify.Config{Backend: backend}) + } + }) + if flowBackendError != nil { + tb.Fatal(flowBackendError) + } +} + +func flowBenchmarkFixtures(tb testing.TB) []flowFixture { + tb.Helper() + count := 33760 + limit := false + if value := os.Getenv("MITHRIL_SIGVERIFY_FLOW_COUNT"); value != "" { + var err error + count, err = strconv.Atoi(value) + if err != nil || count < 1 { + tb.Fatal("MITHRIL_SIGVERIFY_FLOW_COUNT must be a positive integer") + } + limit = true + } + if dir := os.Getenv("MITHRIL_SIGVERIFY_FLOW_FIXTURES"); dir != "" { + paths, err := filepath.Glob(filepath.Join(dir, "block-*.json")) + if err != nil || len(paths) == 0 { + tb.Fatalf("captured fixtures: %v, files=%d", err, len(paths)) + } + var fixtures []flowFixture + for _, path := range paths { + data, err := os.ReadFile(path) + if err != nil { + tb.Fatal(err) + } + var captured struct { + Slot uint64 + Transactions []string + } + if err := json.Unmarshal(data, &captured); err != nil { + tb.Fatal(err) + } + blk := &block.Block{Slot: captured.Slot} + for i, encoded := range captured.Transactions { + if limit && i == count { + break + } + wire, err := base64.StdEncoding.DecodeString(encoded) + if err != nil { + tb.Fatal(err) + } + tx, err := solana.TransactionFromBytes(wire) + if err != nil { + tb.Fatal(err) + } + if err := txverify.SanitizeTransaction(tx); err != nil { + tb.Fatal(err) + } + blk.Transactions = append(blk.Transactions, tx) + } + if len(blk.Transactions) == 0 { + tb.Fatalf("fixture %s contains no transactions", path) + } + fixtures = append(fixtures, flowFixture{fmt.Sprintf("captured_%d", blk.Slot), blk}) + } + return fixtures + } + var fixtures []flowFixture + for _, wireSize := range []int{228, txverify.MaxLegacyTransactionSize} { + blk := &block.Block{Slot: 1, Transactions: make([]*solana.Transaction, count)} + for i := range blk.Transactions { + blk.Transactions[i] = flowGeneratedTransaction(tb, wireSize, uint64(i)) + } + fixtures = append(fixtures, flowFixture{fmt.Sprintf("generated_%dB", wireSize), blk}) + } + return fixtures +} + +func flowGeneratedTransaction(tb testing.TB, wireSize int, index uint64) *solana.Transaction { + tb.Helper() + // Public, deterministic benchmark material, never a validator identity. + var seed [ed25519.SeedSize]byte + binary.LittleEndian.PutUint64(seed[:], index+1) + private := ed25519.NewKeyFromSeed(seed[:]) + public := solana.PublicKeyFromBytes(private.Public().(ed25519.PublicKey)) + tx := &solana.Transaction{ + Signatures: make([]solana.Signature, 1), + Message: solana.Message{ + Header: solana.MessageHeader{NumRequiredSignatures: 1, NumReadonlyUnsignedAccounts: 1}, + AccountKeys: []solana.PublicKey{public, solana.MemoProgramID}, + Instructions: []solana.CompiledInstruction{{ProgramIDIndex: 1, Accounts: []uint16{0}}}, + }, + } + binary.LittleEndian.PutUint64(tx.Message.RecentBlockhash[:], index+1) + baseSize, err := txverify.TransactionWireSize(tx) + if err != nil { + tb.Fatal(err) + } + padding := wireSize - baseSize + for attempts := 0; attempts < 3 && padding >= 0; attempts++ { + tx.Message.Instructions[0].Data = make([]byte, padding) + size, err := txverify.TransactionWireSize(tx) + if err != nil { + tb.Fatal(err) + } + if size != wireSize { + padding += wireSize - size + continue + } + for i := range tx.Message.Instructions[0].Data { + tx.Message.Instructions[0].Data[i] = 'a' + } + message, err := txverify.MessageBytes(tx) + if err != nil { + tb.Fatal(err) + } + copy(tx.Signatures[0][:], ed25519.Sign(private, message)) + if err := txverify.SanitizeTransaction(tx); err != nil { + tb.Fatal(err) + } + return tx + } + tb.Fatalf("cannot construct a %d-byte transaction", wireSize) + return nil +} + +func TestTransactionVerificationFlowFixtureShape(t *testing.T) { + for _, size := range []int{228, 1232} { + first := flowGeneratedTransaction(t, size, 0) + second := flowGeneratedTransaction(t, size, 1) + for _, tx := range []*solana.Transaction{first, second} { + wire, err := tx.MarshalBinary() + if err != nil { + t.Fatal(err) + } + if len(wire) != size || len(tx.Signatures) != 1 { + t.Fatalf("fixture wire=%d signatures=%d, want %d bytes and one signature", len(wire), len(tx.Signatures), size) + } + if err := txverify.VerifyTransaction(tx); err != nil { + t.Fatal(err) + } + } + if first.Signatures[0] == second.Signatures[0] || first.Message.AccountKeys[0] == second.Message.AccountKeys[0] { + t.Fatal("different fixture indices reused a message signature or signer") + } + } +} + +func TestTransactionVerificationFlowComponentBoundaries(t *testing.T) { + txs := make([]*solana.Transaction, 7) + for i := range txs { + txs[i] = flowGeneratedTransaction(t, 228, uint64(i)) + } + components := flowComponents(txs, 500) + if len(components) != 4 { + t.Fatalf("got %d components, want four", len(components)) + } + next := 0 + for i, component := range components { + want := 2 + if i == 3 { + want = 1 + } + if len(component) != want { + t.Fatalf("component %d contains %d transactions, want %d", i, len(component), want) + } + for _, tx := range component { + if tx != txs[next] { + t.Fatal("component split changed transaction order or identity") + } + next++ + } + } + if flowArrivalOffset(0, 4, 200*time.Millisecond) != 0 || flowArrivalOffset(3, 4, 200*time.Millisecond) != 200*time.Millisecond { + t.Fatal("availability schedule does not span the requested interval") + } +} diff --git a/pkg/turbine/transaction_verifier_test.go b/pkg/turbine/transaction_verifier_test.go index 8eb19c63..602fa704 100644 --- a/pkg/turbine/transaction_verifier_test.go +++ b/pkg/turbine/transaction_verifier_test.go @@ -1,9 +1,12 @@ package turbine import ( + "context" + "crypto/ed25519" "errors" "fmt" "strings" + "sync" "sync/atomic" "testing" "time" @@ -43,12 +46,12 @@ func TestTransactionVerifierBoundsConcurrencyAndQueue(t *testing.T) { return nil }) defer verifier.closeAndWait() - if cap(verifier.jobs) != 2*workers { - t.Fatalf("queue capacity = %d, want %d", cap(verifier.jobs), 2*workers) + if got, want := cap(verifier.jobs), 1; got != want { + t.Fatalf("group queue capacity = %d, want %d", got, want) } done := make(chan error, 1) - go func() { done <- verifier.verifyBlock(verifierTestBlock(12)) }() + go func() { done <- verifier.verifyBlock(verifierTestBlock(24)) }() deadline := time.After(3 * time.Second) for active.Load() != workers { select { @@ -76,7 +79,7 @@ func TestTransactionVerifierBoundsConcurrencyAndQueue(t *testing.T) { } func TestTransactionVerifierReturnsLowestFailingIndex(t *testing.T) { - blk := verifierTestBlock(6) + blk := verifierTestBlock(24) lowErr := errors.New("low index failure") highErr := errors.New("high index failure") verifier := newTransactionVerifier(4, 8, func(tx *solana.Transaction) error { @@ -84,7 +87,7 @@ func TestTransactionVerifierReturnsLowestFailingIndex(t *testing.T) { case blk.Transactions[1]: time.Sleep(10 * time.Millisecond) return lowErr - case blk.Transactions[3]: + case blk.Transactions[9]: return highErr default: return nil @@ -132,8 +135,8 @@ func TestTransactionVerifierRejectsNilAtDeterministicIndex(t *testing.T) { // Every transaction in a block must be verified and joined, whatever the count. // Workers group transactions, so a count that divides badly into groups must -// not leave a remainder waiting for company: verifyBlockContext joins each -// wave with done.Wait(), and a stranded job would hang it forever. +// not leave a remainder waiting for company: every tail is dispatched as +// soon as it is available, without waiting for another request. // // A counting verifier is injected so the assertion is on what was actually // verified, not merely on returning without error. @@ -161,3 +164,284 @@ func TestTransactionVerifierVerifiesEveryTransactionForAwkwardCounts(t *testing. }) } } + +func TestTransactionVerifierRefillsWhileEarlierGroupIsBlocked(t *testing.T) { + blk := verifierTestBlock(24) + started := make(chan struct{}) + release := make(chan struct{}) + refilled := make(chan struct{}) + v := newTransactionVerifierWithBatchTarget(2, 16, 8, func(tx *solana.Transaction) error { + switch tx { + case blk.Transactions[0]: + close(started) + <-release + case blk.Transactions[16]: + close(refilled) + } + return nil + }) + defer v.closeAndWait() + defer close(release) + r, err := v.submitTransactions(context.Background(), blk.Transactions) + require.NoError(t, err) + waitSignal(t, started, "slow first group") + waitSignal(t, refilled, "rolling refill before first group finishes") + select { + case <-r.done: + t.Fatal("request finished without joining its blocked group") + default: + } +} + +func TestTransactionVerifierPartialTailStartsWithoutAnotherSubmission(t *testing.T) { + for _, target := range []int{4, 8} { + t.Run(fmt.Sprintf("target=%d", target), func(t *testing.T) { + seen := make(chan struct{}, 3) + v := newTransactionVerifierWithBatchTarget(2, 16, target, func(*solana.Transaction) error { + seen <- struct{}{} + return nil + }) + defer v.closeAndWait() + r, err := v.submitTransactions(context.Background(), verifierTestBlock(3).Transactions) + require.NoError(t, err) + for range 3 { + waitSignal(t, seen, "available partial batch transaction") + } + _, err = r.wait() + require.NoError(t, err) + require.False(t, r.finishedAt.IsZero()) + }) + } +} + +func TestTransactionVerifierLargeRequestDoesNotQueuePastSmallRequest(t *testing.T) { + large := verifierTestBlock(800) + small := verifierTestBlock(1) + started := make(chan struct{}) + release := make(chan struct{}) + var releaseOnce sync.Once + var largeCalls atomic.Int32 + var callsBeforeSmall atomic.Int32 + v := newTransactionVerifierWithBatchTarget(1, 16, 8, func(tx *solana.Transaction) error { + if tx == small.Transactions[0] { + callsBeforeSmall.Store(largeCalls.Load()) + return nil + } + largeCalls.Add(1) + if tx == large.Transactions[0] { + close(started) + <-release + } + return nil + }) + defer v.closeAndWait() + defer releaseOnce.Do(func() { close(release) }) + largeRequest, err := v.submitTransactions(context.Background(), large.Transactions) + require.NoError(t, err) + waitSignal(t, started, "large request first group") + smallRequest, err := v.submitTransactions(context.Background(), small.Transactions) + require.NoError(t, err) + require.Eventually(t, func() bool { return len(v.jobs) == 1 }, 3*time.Second, time.Millisecond) + releaseOnce.Do(func() { close(release) }) + _, err = smallRequest.wait() + require.NoError(t, err) + require.Equal(t, int32(8), callsBeforeSmall.Load(), "large request may only stay one group ahead") + _, err = largeRequest.wait() + require.NoError(t, err) + require.Equal(t, int32(800), largeCalls.Load()) +} + +func TestTransactionVerifierAsyncAdmissionAppliesCancelableBackpressure(t *testing.T) { + started := make(chan struct{}) + release := make(chan struct{}) + var first sync.Once + v := newTransactionVerifierWithBatchTarget(1, 8, 8, func(*solana.Transaction) error { + first.Do(func() { close(started) }) + <-release + return nil + }) + defer v.closeAndWait() + defer close(release) + for range 2 { + _, err := v.submitTransactions(context.Background(), verifierTestBlock(1).Transactions) + require.NoError(t, err) + } + waitSignal(t, started, "occupied request slots") + require.Equal(t, cap(v.requests), len(v.requests)) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + result := make(chan error, 1) + go func() { + _, err := v.submitTransactions(ctx, verifierTestBlock(1).Transactions) + result <- err + }() + select { + case err := <-result: + t.Fatalf("unbounded request admitted instead of waiting: %v", err) + case <-time.After(20 * time.Millisecond): + } + cancel() + select { + case err := <-result: + require.ErrorIs(t, err, context.Canceled) + case <-time.After(3 * time.Second): + t.Fatal("request admission ignored cancellation") + } +} + +func TestTransactionVerificationWaitContextCancelsAndJoins(t *testing.T) { + started := make(chan struct{}) + release := make(chan struct{}) + var releaseOnce sync.Once + var seen atomic.Int32 + v := newTransactionVerifierWithBatchTarget(1, 8, 8, func(*solana.Transaction) error { + if seen.Add(1) == 1 { + close(started) + <-release + } + return nil + }) + defer v.closeAndWait() + defer releaseOnce.Do(func() { close(release) }) + r, err := v.submitTransactions(context.Background(), verifierTestBlock(800).Transactions) + require.NoError(t, err) + waitSignal(t, started, "first admitted group") + ctx, cancel := context.WithCancel(context.Background()) + cancel() + result := make(chan error, 1) + go func() { _, err := r.waitContext(ctx); result <- err }() + select { + case err := <-result: + t.Fatalf("wait returned while transactions still owned by worker: %v", err) + case <-time.After(20 * time.Millisecond): + } + releaseOnce.Do(func() { close(release) }) + select { + case err := <-result: + require.ErrorIs(t, err, context.Canceled) + case <-time.After(3 * time.Second): + t.Fatal("canceled request did not join") + } + require.Equal(t, int32(8), seen.Load(), "cancellation must stop later group admission") +} + +func TestTransactionVerifierCloseRacesAdmissionWithoutStrandingRequests(t *testing.T) { + v := newTransactionVerifier(2, 16, func(*solana.Transaction) error { return nil }) + var callers sync.WaitGroup + for range 32 { + callers.Go(func() { + r, err := v.submitTransactions(context.Background(), verifierTestBlock(17).Transactions) + if err != nil { + if !errors.Is(err, errTransactionVerifierClosed) { + t.Errorf("submit error: %v", err) + } + return + } + _, err = r.wait() + if err != nil { + t.Errorf("admitted request error: %v", err) + } + }) + } + v.closeAndWait() + callers.Wait() + _, err := v.submitTransactions(context.Background(), verifierTestBlock(1).Transactions) + require.ErrorIs(t, err, errTransactionVerifierClosed) +} + +func verifierSignedTransactions(t *testing.T, count int) []*solana.Transaction { + t.Helper() + seed := make([]byte, ed25519.SeedSize) + seed[0] = 71 // Deterministic test-only key; never a validator identity. + key := ed25519.NewKeyFromSeed(seed) + var public solana.PublicKey + copy(public[:], key[32:]) + txs := make([]*solana.Transaction, count) + for i := range txs { + tx := &solana.Transaction{ + Message: solana.Message{ + Header: solana.MessageHeader{NumRequiredSignatures: 1}, + AccountKeys: []solana.PublicKey{public}, + RecentBlockhash: solana.Hash{byte(i), byte(i >> 8)}, + }, + Signatures: make([]solana.Signature, 1), + } + message, err := tx.Message.MarshalBinary() + require.NoError(t, err) + copy(tx.Signatures[0][:], ed25519.Sign(key, message)) + txs[i] = tx + } + return txs +} + +func TestTransactionVerifierRejectsEveryInvalidSignatureLane(t *testing.T) { + v := newTransactionVerifier(2, 16, nil) + defer v.closeAndWait() + for invalid := range 8 { + t.Run(fmt.Sprintf("lane=%d", invalid), func(t *testing.T) { + txs := verifierSignedTransactions(t, 8) + txs[invalid].Signatures[0][13] ^= 0x40 + r, err := v.submitTransactions(context.Background(), txs) + require.NoError(t, err) + index, err := r.wait() + require.ErrorContains(t, err, "invalid signature") + require.Equal(t, invalid, index) + }) + } + r, err := v.submitTransactions(context.Background(), verifierSignedTransactions(t, 17)) + require.NoError(t, err) + _, err = r.wait() + require.NoError(t, err, "valid transactions must still verify after invalid lanes") +} + +func TestTransactionVerifierKeepsMultisignatureTransactionsIntactAcrossTargets(t *testing.T) { + counts := []int{2, 2, 1, 4, 9, 3, 2, 1} + txs := make([]*solana.Transaction, len(counts)) + for i, count := range counts { + keys := make([]ed25519.PrivateKey, count) + public := make([]solana.PublicKey, count) + for signer := range keys { + seed := make([]byte, ed25519.SeedSize) + seed[0], seed[1] = 83, byte(signer) + keys[signer] = ed25519.NewKeyFromSeed(seed) + copy(public[signer][:], keys[signer][32:]) + } + tx := &solana.Transaction{ + Message: solana.Message{ + Header: solana.MessageHeader{ + NumRequiredSignatures: uint8(count), + NumReadonlySignedAccounts: uint8(count - 1), + }, + AccountKeys: public, + RecentBlockhash: solana.Hash{byte(i)}, + }, + Signatures: make([]solana.Signature, count), + } + message, err := tx.Message.MarshalBinary() + require.NoError(t, err) + for signer, key := range keys { + copy(tx.Signatures[signer][:], ed25519.Sign(key, message)) + } + txs[i] = tx + } + for _, target := range []int{4, 8} { + t.Run(fmt.Sprintf("target=%d", target), func(t *testing.T) { + v := newTransactionVerifierWithBatchTarget(2, 16, target, nil) + defer v.closeAndWait() + r, err := v.submitTransactions(context.Background(), txs) + require.NoError(t, err) + _, err = r.wait() + require.NoError(t, err) + + // Corrupt a non-first signer after an oversized (nine-signature) + // transaction. Results must still map to the original tx index. + txs[6].Signatures[1][11] ^= 0x20 + r, err = v.submitTransactions(context.Background(), txs) + require.NoError(t, err) + index, err := r.wait() + require.ErrorContains(t, err, "invalid signature") + require.Equal(t, 6, index) + txs[6].Signatures[1][11] ^= 0x20 + }) + } +} From 9a85ada522b068be0bda0d51f0cbb70c1350179a Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Sat, 12 Sep 2026 01:26:45 -0500 Subject: [PATCH 003/183] Document Zen 5 streaming verification and execution contention results --- .../2026-09-12-zen5/BENCHMARKS.md | 113 + .../2026-09-12-zen5/README.md | 152 + .../2026-09-12-zen5/assembly-1232.log | 29 + .../2026-09-12-zen5/assembly-captured.log | 29 + .../2026-09-12-zen5/assembly-comparison.json | 1602 +++++ .../2026-09-12-zen5/binary-sha256.txt | 3 + .../2026-09-12-zen5/captured-pool-flow.log | 113 + .../2026-09-12-zen5/execution-comparison.json | 1653 +++++ .../2026-09-12-zen5/execution-contention.log | 162 + .../2026-09-12-zen5/execution-raw.log | 576 ++ .../2026-09-12-zen5/final-commands.jsonl | 6 + .../2026-09-12-zen5/final-source-update.json | 30 + .../generated-1232-pool-flow.log | 77 + .../2026-09-12-zen5/health-after-final.txt | 4 + .../2026-09-12-zen5/local-replay.log | 1 + .../2026-09-12-zen5/local-turbine-race.log | 1 + .../2026-09-12-zen5/local-unit.log | 7 + .../2026-09-12-zen5/native-final-race.log | 1 + .../2026-09-12-zen5/native-final-unit.log | 6 + .../2026-09-12-zen5/pool-comparison.json | 5503 +++++++++++++++++ .../run_execution_contention.py | 231 + docs/transaction_sigverify_streaming.md | 3 + 22 files changed, 10302 insertions(+) create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/BENCHMARKS.md create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/README.md create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/assembly-1232.log create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/assembly-captured.log create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/assembly-comparison.json create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/binary-sha256.txt create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/captured-pool-flow.log create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/execution-comparison.json create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/execution-contention.log create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/execution-raw.log create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/final-commands.jsonl create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/final-source-update.json create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/generated-1232-pool-flow.log create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/health-after-final.txt create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/local-replay.log create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/local-turbine-race.log create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/local-unit.log create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/native-final-race.log create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/native-final-unit.log create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/pool-comparison.json create mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/run_execution_contention.py diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/BENCHMARKS.md b/docs/results/sigverify-streaming/2026-09-12-zen5/BENCHMARKS.md new file mode 100644 index 00000000..454f75e3 --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/BENCHMARKS.md @@ -0,0 +1,113 @@ +# Signature batching and overlap benchmark harness + +The repository adds `pkg/turbine/transaction_verifier_flow_benchmark_test.go`. +It uses the production transaction verifier with two/four workers and signature +batch targets four/eight. It verifies every signature and rejects internal native +fallbacks. Generated inputs have distinct, valid signatures and exact serialized +sizes of 228 or 1,232 bytes. Optional captured public block transactions replace +generated inputs. + +These are controlled verifier-pool measurements, **not complete validator replay +or a recorded shred-arrival trace**. Transaction decoding and fixture generation +are outside the timer. Each component is submitted as soon as its scheduled bytes +are available; partial vector groups never wait for another component. + +## Workloads + +- `catchup`: all transactions are available immediately in one request. +- `tip_200ms_after_complete`: components become available across 200 ms, then the + full block is submitted. This isolates the cost of waiting for block completion + with the same improved batching pool. +- `tip_200ms_overlap`: complete components become available across 200 ms and are + submitted immediately. Components contain at most 60 KiB of transaction bytes. + This is a synthetic workload parameter; serialized entry overhead, shred + recovery, and actual cluster component boundaries are omitted. +- `sparse_{4,7,8}tx_200ms_overlap`: at most 256 transactions arrive in tiny complete + components across 200 ms, exposing partial-batch latency without a high-rate + sub-millisecond network timer simulation. + +For each measured run, `cpu-ms/block` is process user+system CPU time summed across +cores, including pool/message preparation, scheduling, allocations and benchmark +bookkeeping. `signatures/s` in 200 ms workloads includes the deliberate network +availability waits; it is delivered workload throughput, not peak crypto speed. + +`ready_p95-ms` measures scheduled component availability to that component's +verification future completing. It is a component latency, not individual +transaction execution latency. `submit_p95-ms` measures time inside bounded pool +submission. `feed_lag_p95-ms` captures lateness between scheduled availability and +calling submission, including timer granularity, CPU contention and backlog from +an earlier blocked submission. `residual_p95-ms` measures final scheduled +availability to the final future completing. Completion timestamps come from the +pool, so a delayed observer goroutine does not inflate completion latency. + +Capture/profile workload delays alongside residual: delayed synthetic arrivals +must not be described as successfully hidden signature work. + +## Build and run on Zen 5 + +Build fresh package test executables from the candidate checkout with the native +Go toolchain; run `-test.run='^$'` when selecting `r51` explicitly so unrelated tests +cannot initialize a different backend first: + +```sh +go test -c ./pkg/turbine -o /tmp/turbine-streaming.test +go test -c ./pkg/replay -o /tmp/replay-streaming.test + +GOMAXPROCS=8 \ +MITHRIL_SIGVERIFY_FLOW_BACKEND=r51 \ +MITHRIL_SIGVERIFY_FLOW_FIXTURES=/srv/mithril-planner-pr257-trial-20260912/fixtures \ +/tmp/turbine-streaming.test \ + -test.run='^$' \ + -test.bench='^BenchmarkTransactionVerificationFlow$/^captured_2622581$' \ + -test.benchtime=3x -test.count=3 +``` + +Omit `MITHRIL_SIGVERIFY_FLOW_FIXTURES` for generated 228/1,232-byte workloads. +`MITHRIL_SIGVERIFY_FLOW_COUNT` changes generated transaction count or limits +captured fixtures to a prefix. Leave it unset for full captured blocks. A fresh +test executable is required when changing native backend. + +Fixture helper checks are `TestTransactionVerificationFlowFixtureShape` and +`TestTransactionVerificationFlowComponentBoundaries`. The former verifies actual +marshaled byte lengths, signature validity, and distinct signer identities. + +## Actual execution contention probe + +`run_execution_contention.py` runs the existing production +`LoadAndExecuteTransaction` benchmark for a signed system transfer +(`BenchmarkLoadAndExecuteTransferResultMode/lean`) before and during signature +verification. It runs two **separate processes**, both restricted to the same eight +physical cores with `GOMAXPROCS=8` each. The runner verifies that the selected CPU +IDs represent eight distinct physical cores; inspect the server's topology before +selecting IDs. + +This execution probe includes the transaction load/execute function. It excludes +account commit, dependency planning, full-block replay, and interaction through a +single shared Go scheduler/heap. It provides evidence of hardware/OS contention; +live whole-validator timings are still needed to choose the production default. + +```sh +python3 run_execution_contention.py \ + --turbine-bin /tmp/turbine-streaming.test \ + --replay-bin /tmp/replay-streaming.test \ + --fixtures /srv/mithril-planner-pr257-trial-20260912/fixtures \ + --slot 2622581 --cpus 0-7 \ + --out /tmp/mithril-execution-contention --samples 3 +``` + +The output directory must be new. Conditions (workers two/four, target four/eight, +catch-up/200 ms overlap) are deterministically shuffled within each repeated +sample. Every condition gets its own immediately preceding execution baseline. +The runner waits for the verifier's warmup/calibration to finish, releases its +explicit rendezvous, then measures concurrent execution. It refuses to use a +sample if verification load ends before the execution probe finishes. Increase +`--catchup-blocks` or `--tip-blocks` if that happens. It stops only its own benchmark +child on failure; it never interacts with the validator service. + +Raw output and commands are preserved in each sample directory. `comparison.json` +records CPU topology, run arguments, execution slowdown ratios, all signature +metrics and medians across repeats. Signature metrics describe the **whole load +window**, while the execution probe occupies a portion of that window; do not +interpret the load-window signature numbers as continuously contended results. +Background server activity remains a possible confounder and must be noted in +any conclusions. diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/README.md b/docs/results/sigverify-streaming/2026-09-12-zen5/README.md new file mode 100644 index 00000000..bf73826a --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/README.md @@ -0,0 +1,152 @@ +# Signature batching and shred-arrival overlap on Zen 5 + +Implementation: `05ded9b0` on `7layer/planner-pr257-trial-20260912`, building on +`8a94482e`. Narya is pinned to `c265ee9667131a556cd332c252b79de0860c7640`. + +The change forms signature groups before dispatch and keeps workers supplied +without wave barriers. It also decodes and verifies complete entry components +while later shreds arrive. The selected default is **two workers, target eight, +no batching timer**. Four available signatures run immediately; they do not wait +for eight. Four workers remain an explicit option for catch-up. + +## Environment and interpretation + +- Ryzen 7 9700X, eight physical cores / sixteen hardware threads; Go 1.26.4, + native Narya `r51`, `GOMAXPROCS=8`, affinity logical CPUs 0–7 (distinct cores). +- Benchmark processes ran at nice 10 while the existing Mithril validator and + Lightbringer continued running. These are shared-host measurements. +- Each assembly condition has three repetitions of three blocks. Tables show + medians of the reported per-repetition values; tail columns elsewhere are + medians of per-repetition p95s, not an aggregate percentile or confidence bound. +- Captured pool measurements include three public testnet blocks, each with + 33,760 one-signature V1 transactions, 228 wire bytes / 164 signed message bytes. + Assembly uses block 2622581's transactions in newly generated valid Merkle + shreds. The maximum-size case uses 33,760 distinct signed generated transactions + of exactly 1,232 wire bytes, including their signatures. +- Tip arrival schedules distribute complete component bursts across 200 ms. + Components use a 60 KiB transaction-byte budget, a benchmark choice rather than + a protocol requirement. Assembly generates real entry overhead and FEC padding. + This is not a recorded arrival trace or a whole-validator replay benchmark. + +## Full assembly: what remains after the final shred + +These cases run production assembly, entry decoding, final Merkle identity +checks, transaction signature verification, and block publication. Shred +construction, packet parsing, and shred-signature authentication are outside the +measurement. Transaction execution and commit are excluded. + +Both sides use the **new batching pool**. “Off” waits for all shreds before +transaction decoding/verification; “on” overlaps that work with arrivals. This +isolates overlap, rather than comparing against an older Narya or batching PR. + +| Wire bytes/tx | Workers | Full-to-ready off → on | Total arrival-to-ready off → on | CPU-ms/block off → on | +|---|---:|---:|---:|---:| +| 228 | 2 | 85.88 → **7.76 ms** | 287.68 → **208.06 ms** | 177.4 → 185.8 | +| 228 | 4 | 49.88 → **7.83 ms** | 250.71 → **207.82 ms** | 177.6 → 186.4 | +| 1,232 | 2 | 118.00 → **28.97 ms** | 318.80 → **229.37 ms** | 242.5 → 266.5 | +| 1,232 | 4 | 77.04 → **25.69 ms** | 276.59 → **227.10 ms** | 241.8 → 264.9 | + +Every row has 33,760 transactions and target eight. Actual shred collection stayed +around 200–202 ms, so the improvement did not come from delaying the synthetic +feed. With two workers, early verification covered all 33,760 captured +transactions and about 33,744 maximum-size transactions before full assembly. +Final signature joins were approximately 0.019 and 0.122 ms, respectively. +The remaining tail lies predominantly in final assembly work; it is not hidden +signature work. Additional overlap costs some CPU and retained memory. + +For all-at-once catch-up, two-worker total assembly was about 93 ms for captured +transactions and 140 ms for maximum-size transactions with overlap enabled. +Four workers yielded roughly 67 and 85 ms. Overlap itself provides little +opportunity when all data is immediately available, and some conditions showed +additional overhead. These results do not justify an automatic mode-switching +policy; the default prioritizes tip behavior. + +## Pool batching: worker and target trade-off + +Decoding is outside these measurements. CPU time sums work across cores, so it +must not be interpreted as single-thread wall time. + +| Transactions | Workers / target | Catch-up wall time | CPU-ms/block | +|---|---:|---:|---:| +| Captured 228 B | 2 / 4 | 155.92 ms | 317.8 | +| Captured 228 B | **2 / 8** | **77.79 ms** | **158.7** | +| Captured 228 B | 4 / 8 | 39.48 ms | 158.5 | +| Generated 1,232 B | 2 / 4 | 165.23 ms | 342.6 | +| Generated 1,232 B | **2 / 8** | **86.11 ms** | **180.0** | +| Generated 1,232 B | 4 / 8 | 56.22 ms | 223.0 | + +At the synthetic tip, the two-worker/eight-target pool's residual p95 was about +1.34 ms for captured transactions and 0.64 ms for maximum-size transactions. +These smaller values exclude the final assembly measured above. Scheduling lag +was around a millisecond, so small differences between worker counts are noisy. +Sparse four-transaction components dispatched immediately at width four even +with target eight. Setting target four globally roughly doubled signature CPU +work in the captured workload without a meaningful tip-latency advantage. + +## Effect on transaction execution + +The real `BenchmarkLoadAndExecuteTransferResultMode/lean` system-transfer probe +ran before and during signature load on the same eight physical cores. Each +condition has three shuffled paired samples. The two workloads use **separate +processes**, so this measures hardware/OS contention and excludes shared Go +scheduler/heap interactions, dependency planning, commit, and full replay. + +| Signature policy | Catch-up execution slowdown | Tip execution slowdown | +|---|---:|---:| +| 2 workers / target 4 | +1.9% | +7.0% | +| **2 workers / target 8** | **+21.8%** | **+1.7%** | +| 4 workers / target 4 | +1.2% | +21.4% | +| **4 workers / target 8** | **+21.5%** | **−0.9%** | + +Values are medians of paired slowdown ratios, not ratios of independently +aggregated times. Background load was variable: tip/target-eight paired ranges +were −5.1% to +3.4% for two workers and −10.1% to +17.9% for four. The small +negative median is noise, not evidence that signature work accelerates +execution. **This test does not show a consistent execution penalty from four +rather than two workers at target eight.** It does show that sustained catch-up +signature work can contend with execution at either worker count. + +Two workers are the conservative default because their tip latency is already +similar and their peak verifier concurrency is lower. Four workers are useful +when catch-up latency matters; the data do not establish that they are unsafe +or universally worse. A live same-process replay comparison would be needed to +measure scheduler, heap, planner and commit interactions. The running validator +was not switched for these tests. + +## Validation + +Native unit tests passed for Turbine, signature verification, transaction +verification, block metadata, statsd, and node configuration. Native repeated +race checks passed for the new streaming, cache, transaction-pool and receiver +paths. Local full Turbine race tests, selected package tests and vet passed. + +Regressions cover early verification before the last shred, gap/duplicate +handling, cross-FEC component boundaries, reset generations, bounded admission, +byte-budget/oversized fallback, shutdown ownership, canceled-completion retry, +exact-byte cache binding, retained invalid signatures, discarded UpdateParent +prefixes, and padded Agave decoding parity. Assembly benchmarks additionally +assert exactly one signature verification per retained transaction and matching +block identity/transaction coverage. No internal native fallback occurred. + +The local replay suite passed on rerun. Its first run hit an existing +`promotion_test.go` assertion requiring a tiny lookup duration to be positive; +the isolated test passed twenty repetitions and the full suite then passed. +No production replay or timing assertion was changed to address that flake. + +See the raw logs and JSON in this directory, the source benchmark comments, and +[BENCHMARKS.md](BENCHMARKS.md) for pool and execution-probe reproduction details. + +To reproduce the maximum-size assembly comparison on an AVX-512 IFMA machine: + +```sh +go test -c ./pkg/turbine -o /tmp/turbine-streaming.test +GOMAXPROCS=8 MITHRIL_SIGVERIFY_FLOW_BACKEND=r51 \ +MITHRIL_SIGVERIFY_FLOW_COUNT=33760 \ +taskset --cpu-list 0-7 /tmp/turbine-streaming.test \ + -test.run='^$' -test.benchtime=3x -test.count=3 \ + -test.bench='^BenchmarkEntryPrefetchAssembly$/^generated_1232B$/^workers_.*$/^target_8$/.*' +``` + +Use the captured fixture environment and `captured_2622581` sub-benchmark instead +for the short-transaction comparison. Select the physical CPU IDs appropriate +for the machine; the CPU IDs above describe this server's topology. diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/assembly-1232.log b/docs/results/sigverify-streaming/2026-09-12-zen5/assembly-1232.log new file mode 100644 index 00000000..986c1ee8 --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/assembly-1232.log @@ -0,0 +1,29 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8 3 132732036 ns/op 1.926 avg_cpu_cores 6.714 collection_p50-ms 6.898 collection_p95-ms 4.501 completion_parse_p50-ms 4.815 completion_parse_p95-ms 89.28 completion_sigverify_p50-ms 102.2 completion_sigverify_p95-ms 691.0 components/block 255.6 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 123.2 full_to_ready_p50-ms 133.2 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260174637 B/op 235471 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8 3 134071642 ns/op 1.969 avg_cpu_cores 8.232 collection_p50-ms 8.625 collection_p95-ms 5.486 completion_parse_p50-ms 5.850 completion_parse_p95-ms 93.22 completion_sigverify_p50-ms 94.08 completion_sigverify_p95-ms 691.0 components/block 264.0 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 128.8 full_to_ready_p50-ms 132.1 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 259991864 B/op 235464 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8 3 118432537 ns/op 1.989 avg_cpu_cores 5.898 collection_p50-ms 6.123 collection_p95-ms 4.634 completion_parse_p50-ms 5.372 completion_parse_p95-ms 82.63 completion_sigverify_p50-ms 82.80 completion_sigverify_p95-ms 691.0 components/block 235.6 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 111.0 full_to_ready_p50-ms 115.7 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260219832 B/op 235471 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8 3 143317986 ns/op 1.993 avg_cpu_cores 10.38 collection_p50-ms 10.94 collection_p95-ms 5.302 completion_parse_p50-ms 5.596 completion_parse_p95-ms 91.17 completion_sigverify_p50-ms 96.29 completion_sigverify_p95-ms 691.0 components/block 285.7 cpu-ms/block 44160 data_shreds/block 2515 early_verified_tx/block 132.7 full_to_ready_p50-ms 136.1 full_to_ready_p95-ms 7.914 mean_width 0.007227 preparation_wait_p50-ms 0.008702 preparation_wait_p95-ms 33760 tx/block 265981290 B/op 236644 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8 3 140105831 ns/op 2.039 avg_cpu_cores 9.935 collection_p50-ms 11.26 collection_p95-ms 5.330 completion_parse_p50-ms 6.534 completion_parse_p95-ms 93.04 completion_sigverify_p50-ms 94.68 completion_sigverify_p95-ms 691.0 components/block 285.6 cpu-ms/block 44160 data_shreds/block 2140 early_verified_tx/block 131.0 full_to_ready_p50-ms 131.5 full_to_ready_p95-ms 7.927 mean_width 0.005670 preparation_wait_p50-ms 0.006587 preparation_wait_p95-ms 33760 tx/block 265780592 B/op 236507 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8 3 118146761 ns/op 2.052 avg_cpu_cores 8.247 collection_p50-ms 11.14 collection_p95-ms 5.074 completion_parse_p50-ms 5.303 completion_parse_p95-ms 79.37 completion_sigverify_p50-ms 79.81 completion_sigverify_p95-ms 691.0 components/block 242.4 cpu-ms/block 44160 data_shreds/block 2091 early_verified_tx/block 106.7 full_to_ready_p50-ms 116.1 full_to_ready_p95-ms 7.929 mean_width 0.003786 preparation_wait_p50-ms 0.007029 preparation_wait_p95-ms 33760 tx/block 265573218 B/op 236474 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8 3 318801116 ns/op 0.7606 avg_cpu_cores 201.0 collection_p50-ms 201.6 collection_p95-ms 4.599 completion_parse_p50-ms 5.045 completion_parse_p95-ms 83.28 completion_sigverify_p50-ms 85.20 completion_sigverify_p95-ms 691.0 components/block 242.5 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 118.3 full_to_ready_p50-ms 122.6 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260036650 B/op 235461 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8 3 314110925 ns/op 0.7601 avg_cpu_cores 201.6 collection_p50-ms 201.7 collection_p95-ms 4.269 completion_parse_p50-ms 4.420 completion_parse_p95-ms 82.73 completion_sigverify_p50-ms 82.83 completion_sigverify_p95-ms 691.0 components/block 238.8 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 113.3 full_to_ready_p50-ms 113.6 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260219818 B/op 235471 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8 3 322511217 ns/op 0.7751 avg_cpu_cores 201.7 collection_p50-ms 202.5 collection_p95-ms 4.627 completion_parse_p50-ms 5.343 completion_parse_p95-ms 84.98 completion_sigverify_p50-ms 88.32 completion_sigverify_p95-ms 691.0 components/block 250.0 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 118.0 full_to_ready_p50-ms 126.6 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260082442 B/op 235464 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8 3 226899169 ns/op 1.167 avg_cpu_cores 201.4 collection_p50-ms 201.4 collection_p95-ms 0 completion_parse_p50-ms 0.01079 completion_parse_p95-ms 0.1220 completion_sigverify_p50-ms 0.3120 completion_sigverify_p95-ms 691.0 components/block 264.7 cpu-ms/block 44160 data_shreds/block 33744 early_verified_tx/block 25.53 full_to_ready_p50-ms 26.34 full_to_ready_p95-ms 7.001 mean_width 0.1206 preparation_wait_p50-ms 0.1241 preparation_wait_p95-ms 33760 tx/block 307640389 B/op 250060 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8 3 229370055 ns/op 1.162 avg_cpu_cores 200.7 collection_p50-ms 201.2 collection_p95-ms 0 completion_parse_p50-ms 0.01841 completion_parse_p95-ms 0.1002 completion_sigverify_p50-ms 0.4560 completion_sigverify_p95-ms 691.0 components/block 266.5 cpu-ms/block 44160 data_shreds/block 33728 early_verified_tx/block 29.75 full_to_ready_p50-ms 30.22 full_to_ready_p95-ms 7.001 mean_width 0.1252 preparation_wait_p50-ms 0.1260 preparation_wait_p95-ms 33760 tx/block 307397858 B/op 250045 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8 3 231567222 ns/op 1.363 avg_cpu_cores 201.1 collection_p50-ms 201.2 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.1245 completion_sigverify_p50-ms 0.1492 completion_sigverify_p95-ms 691.0 components/block 315.7 cpu-ms/block 44160 data_shreds/block 33760 early_verified_tx/block 28.97 full_to_ready_p50-ms 34.61 full_to_ready_p95-ms 7.001 mean_width 0.1317 preparation_wait_p50-ms 0.1370 preparation_wait_p95-ms 33760 tx/block 307432845 B/op 250046 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/catchup/overlap_off-8 3 98393903 ns/op 2.983 avg_cpu_cores 8.190 collection_p50-ms 8.563 collection_p95-ms 4.938 completion_parse_p50-ms 5.485 completion_parse_p95-ms 55.91 completion_sigverify_p50-ms 57.00 completion_sigverify_p95-ms 691.0 components/block 293.5 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 88.12 full_to_ready_p50-ms 95.35 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260266082 B/op 235474 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/catchup/overlap_off-8 3 105755933 ns/op 2.776 avg_cpu_cores 8.602 collection_p50-ms 9.822 collection_p95-ms 6.422 completion_parse_p50-ms 7.668 completion_parse_p95-ms 52.00 completion_sigverify_p50-ms 60.88 completion_sigverify_p95-ms 691.0 components/block 293.6 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 90.69 full_to_ready_p50-ms 112.2 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260174000 B/op 235467 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/catchup/overlap_off-8 3 81434919 ns/op 3.009 avg_cpu_cores 6.353 collection_p50-ms 6.417 collection_p95-ms 4.568 completion_parse_p50-ms 4.630 completion_parse_p95-ms 44.00 completion_sigverify_p50-ms 44.05 completion_sigverify_p95-ms 691.0 components/block 245.1 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 75.94 full_to_ready_p50-ms 77.03 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260402965 B/op 235479 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/catchup/overlap_on-8 3 81921701 ns/op 3.107 avg_cpu_cores 9.142 collection_p50-ms 9.153 collection_p95-ms 4.251 completion_parse_p50-ms 4.784 completion_parse_p95-ms 41.90 completion_sigverify_p50-ms 42.10 completion_sigverify_p95-ms 691.0 components/block 254.5 cpu-ms/block 44160 data_shreds/block 3430 early_verified_tx/block 75.23 full_to_ready_p50-ms 75.61 full_to_ready_p95-ms 7.885 mean_width 0.007166 preparation_wait_p50-ms 0.01060 preparation_wait_p95-ms 33760 tx/block 267789989 B/op 237063 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/catchup/overlap_on-8 3 106211708 ns/op 2.960 avg_cpu_cores 12.72 collection_p50-ms 12.77 collection_p95-ms 6.076 completion_parse_p50-ms 6.677 completion_parse_p95-ms 49.86 completion_sigverify_p50-ms 57.70 completion_sigverify_p95-ms 691.0 components/block 314.4 cpu-ms/block 44160 data_shreds/block 3397 early_verified_tx/block 91.87 full_to_ready_p50-ms 99.87 full_to_ready_p95-ms 7.886 mean_width 0.01751 preparation_wait_p50-ms 0.01784 preparation_wait_p95-ms 33760 tx/block 267653104 B/op 237049 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/catchup/overlap_on-8 3 85283927 ns/op 2.979 avg_cpu_cores 9.315 collection_p50-ms 10.89 collection_p95-ms 3.727 completion_parse_p50-ms 5.583 completion_parse_p95-ms 41.31 completion_sigverify_p50-ms 43.80 completion_sigverify_p95-ms 691.0 components/block 254.1 cpu-ms/block 44160 data_shreds/block 3561 early_verified_tx/block 75.15 full_to_ready_p50-ms 86.25 full_to_ready_p95-ms 7.880 mean_width 0.01225 preparation_wait_p50-ms 0.01287 preparation_wait_p95-ms 33760 tx/block 267515682 B/op 237096 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/tip_200ms/overlap_off-8 3 276365085 ns/op 0.8723 avg_cpu_cores 201.5 collection_p50-ms 201.6 collection_p95-ms 4.437 completion_parse_p50-ms 4.504 completion_parse_p95-ms 43.22 completion_sigverify_p50-ms 43.60 completion_sigverify_p95-ms 691.0 components/block 241.1 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 77.04 full_to_ready_p50-ms 77.05 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260403005 B/op 235479 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/tip_200ms/overlap_off-8 3 280110502 ns/op 0.9259 avg_cpu_cores 200.8 collection_p50-ms 201.1 collection_p95-ms 4.666 completion_parse_p50-ms 4.728 completion_parse_p95-ms 44.11 completion_sigverify_p50-ms 56.80 completion_sigverify_p95-ms 691.0 components/block 259.4 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 77.81 full_to_ready_p50-ms 86.07 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260495133 B/op 235486 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/tip_200ms/overlap_off-8 3 276593977 ns/op 0.8742 avg_cpu_cores 201.6 collection_p50-ms 201.7 collection_p95-ms 4.198 completion_parse_p50-ms 6.163 completion_parse_p95-ms 43.50 completion_sigverify_p50-ms 44.33 completion_sigverify_p95-ms 691.0 components/block 241.8 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 75.26 full_to_ready_p50-ms 79.84 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 259991381 B/op 235460 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/tip_200ms/overlap_on-8 3 227100110 ns/op 1.166 avg_cpu_cores 201.2 collection_p50-ms 201.4 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.1103 completion_sigverify_p50-ms 0.1149 completion_sigverify_p95-ms 691.0 components/block 264.9 cpu-ms/block 44160 data_shreds/block 33760 early_verified_tx/block 25.08 full_to_ready_p50-ms 27.44 full_to_ready_p95-ms 7.001 mean_width 0.1228 preparation_wait_p50-ms 0.1240 preparation_wait_p95-ms 33760 tx/block 307747917 B/op 250014 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/tip_200ms/overlap_on-8 3 241182176 ns/op 1.235 avg_cpu_cores 201.4 collection_p50-ms 202.9 collection_p95-ms 0.01357 completion_parse_p50-ms 0.04438 completion_parse_p95-ms 0.3222 completion_sigverify_p50-ms 0.4977 completion_sigverify_p95-ms 691.0 components/block 297.8 cpu-ms/block 44160 data_shreds/block 33712 early_verified_tx/block 34.46 full_to_ready_p50-ms 51.53 full_to_ready_p95-ms 7.001 mean_width 0.1261 preparation_wait_p50-ms 0.1812 preparation_wait_p95-ms 33760 tx/block 307727008 B/op 250008 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/tip_200ms/overlap_on-8 3 226480518 ns/op 1.167 avg_cpu_cores 200.9 collection_p50-ms 201.3 collection_p95-ms 0.01037 completion_parse_p50-ms 0.01195 completion_parse_p95-ms 0.2797 completion_sigverify_p50-ms 0.3548 completion_sigverify_p95-ms 691.0 components/block 264.2 cpu-ms/block 44160 data_shreds/block 33728 early_verified_tx/block 25.69 full_to_ready_p50-ms 25.87 full_to_ready_p95-ms 7.001 mean_width 0.1226 preparation_wait_p50-ms 0.1242 preparation_wait_p95-ms 33760 tx/block 307612829 B/op 250008 allocs/op +PASS diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/assembly-captured.log b/docs/results/sigverify-streaming/2026-09-12-zen5/assembly-captured.log new file mode 100644 index 00000000..3018e8e5 --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/assembly-captured.log @@ -0,0 +1,29 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/catchup/overlap_off-8 3 105356378 ns/op 1.971 avg_cpu_cores 1.468 collection_p50-ms 1.850 collection_p95-ms 8.134 completion_parse_p50-ms 8.419 completion_parse_p95-ms 91.75 completion_sigverify_p50-ms 93.70 completion_sigverify_p95-ms 128.0 components/block 207.7 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 105.0 full_to_ready_p50-ms 106.8 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 60657304 B/op 276266 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/catchup/overlap_off-8 3 86032987 ns/op 2.002 avg_cpu_cores 1.089 collection_p50-ms 1.203 collection_p95-ms 6.689 completion_parse_p50-ms 6.878 completion_parse_p95-ms 74.21 completion_sigverify_p50-ms 74.64 completion_sigverify_p95-ms 128.0 components/block 172.3 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 85.25 full_to_ready_p50-ms 86.05 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 60840701 B/op 276276 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/catchup/overlap_off-8 3 93330914 ns/op 1.983 avg_cpu_cores 1.146 collection_p50-ms 1.289 collection_p95-ms 7.575 completion_parse_p50-ms 7.927 completion_parse_p95-ms 78.84 completion_sigverify_p50-ms 82.89 completion_sigverify_p95-ms 128.0 components/block 185.0 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 91.61 full_to_ready_p50-ms 96.68 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 60612906 B/op 276264 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/catchup/overlap_on-8 3 98687304 ns/op 2.002 avg_cpu_cores 1.923 collection_p50-ms 2.397 collection_p95-ms 8.068 completion_parse_p50-ms 8.712 completion_parse_p95-ms 84.04 completion_sigverify_p50-ms 84.50 completion_sigverify_p95-ms 128.0 components/block 197.6 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 98.00 full_to_ready_p50-ms 99.33 full_to_ready_p95-ms 7.997 mean_width 0.0009020 preparation_wait_p50-ms 2.642 preparation_wait_p95-ms 33760 tx/block 63544576 B/op 276416 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/catchup/overlap_on-8 3 86908892 ns/op 2.033 avg_cpu_cores 1.582 collection_p50-ms 1.667 collection_p95-ms 6.919 completion_parse_p50-ms 7.541 completion_parse_p95-ms 71.67 completion_sigverify_p50-ms 73.28 completion_sigverify_p95-ms 128.0 components/block 176.7 cpu-ms/block 8128 data_shreds/block 89.67 early_verified_tx/block 85.58 full_to_ready_p50-ms 86.16 full_to_ready_p95-ms 7.996 mean_width 0.0007210 preparation_wait_p50-ms 0.4474 preparation_wait_p95-ms 33760 tx/block 63411160 B/op 276433 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/catchup/overlap_on-8 3 93317165 ns/op 1.995 avg_cpu_cores 1.590 collection_p50-ms 1.976 collection_p95-ms 6.820 completion_parse_p50-ms 7.778 completion_parse_p95-ms 76.41 completion_sigverify_p50-ms 85.36 completion_sigverify_p95-ms 128.0 components/block 186.2 cpu-ms/block 8128 data_shreds/block 89.67 early_verified_tx/block 90.85 full_to_ready_p50-ms 97.05 full_to_ready_p95-ms 7.998 mean_width 0.0005910 preparation_wait_p50-ms 0.0006410 preparation_wait_p95-ms 33760 tx/block 63403101 B/op 276380 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/tip_200ms/overlap_off-8 3 290460961 ns/op 0.6306 avg_cpu_cores 200.6 collection_p50-ms 200.7 collection_p95-ms 6.281 completion_parse_p50-ms 7.566 completion_parse_p95-ms 73.61 completion_sigverify_p50-ms 88.73 completion_sigverify_p95-ms 128.0 components/block 183.2 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 84.53 full_to_ready_p50-ms 101.9 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 60656794 B/op 276264 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/tip_200ms/overlap_off-8 3 287675866 ns/op 0.6167 avg_cpu_cores 200.6 collection_p50-ms 200.6 collection_p95-ms 6.699 completion_parse_p50-ms 6.802 completion_parse_p95-ms 75.07 completion_sigverify_p50-ms 77.73 completion_sigverify_p95-ms 128.0 components/block 177.4 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 86.16 full_to_ready_p50-ms 89.34 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 60519650 B/op 276258 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/tip_200ms/overlap_off-8 3 287110470 ns/op 0.6140 avg_cpu_cores 200.6 collection_p50-ms 201.2 collection_p95-ms 6.565 completion_parse_p50-ms 6.620 completion_parse_p95-ms 74.50 completion_sigverify_p50-ms 77.80 completion_sigverify_p95-ms 128.0 components/block 176.3 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 85.88 full_to_ready_p50-ms 87.16 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 60656832 B/op 276264 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/tip_200ms/overlap_on-8 3 209450474 ns/op 0.9421 avg_cpu_cores 200.7 collection_p50-ms 201.2 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.01935 completion_sigverify_p50-ms 0.03406 completion_sigverify_p95-ms 128.0 components/block 197.3 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 8.638 full_to_ready_p50-ms 9.007 full_to_ready_p95-ms 7.912 mean_width 0.02519 preparation_wait_p50-ms 0.03274 preparation_wait_p95-ms 33760 tx/block 69730546 B/op 279208 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/tip_200ms/overlap_on-8 3 208058833 ns/op 0.8929 avg_cpu_cores 200.7 collection_p50-ms 200.7 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.01704 completion_sigverify_p50-ms 0.02061 completion_sigverify_p95-ms 128.0 components/block 185.8 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 7.636 full_to_ready_p50-ms 9.799 full_to_ready_p95-ms 7.912 mean_width 0.02234 preparation_wait_p50-ms 0.02347 preparation_wait_p95-ms 33760 tx/block 69690704 B/op 279231 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/tip_200ms/overlap_on-8 3 207559046 ns/op 0.8943 avg_cpu_cores 200.6 collection_p50-ms 200.9 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.01885 completion_sigverify_p50-ms 0.01951 completion_sigverify_p95-ms 128.0 components/block 185.6 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 7.755 full_to_ready_p50-ms 8.173 full_to_ready_p95-ms 7.912 mean_width 0.02086 preparation_wait_p50-ms 0.02149 preparation_wait_p95-ms 33760 tx/block 69823114 B/op 279217 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/catchup/overlap_off-8 3 55875291 ns/op 3.314 avg_cpu_cores 1.291 collection_p50-ms 1.709 collection_p95-ms 7.281 completion_parse_p50-ms 7.313 completion_parse_p95-ms 40.25 completion_sigverify_p50-ms 42.81 completion_sigverify_p95-ms 128.0 components/block 185.2 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 55.07 full_to_ready_p50-ms 55.62 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 60611714 B/op 276263 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/catchup/overlap_off-8 3 61860407 ns/op 3.216 avg_cpu_cores 1.169 collection_p50-ms 2.221 collection_p95-ms 7.116 completion_parse_p50-ms 10.84 completion_parse_p95-ms 47.89 completion_sigverify_p50-ms 48.65 completion_sigverify_p95-ms 128.0 components/block 198.9 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 62.07 full_to_ready_p50-ms 67.59 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 60473978 B/op 276254 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/catchup/overlap_off-8 3 55571155 ns/op 3.375 avg_cpu_cores 1.177 collection_p50-ms 1.290 collection_p95-ms 7.277 completion_parse_p50-ms 7.356 completion_parse_p95-ms 42.47 completion_sigverify_p50-ms 44.27 completion_sigverify_p95-ms 128.0 components/block 187.6 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 54.23 full_to_ready_p50-ms 54.69 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 60748730 B/op 276268 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/catchup/overlap_on-8 3 66703191 ns/op 3.379 avg_cpu_cores 2.562 collection_p50-ms 2.726 collection_p95-ms 8.584 completion_parse_p50-ms 10.03 completion_parse_p95-ms 50.79 completion_sigverify_p50-ms 52.88 completion_sigverify_p95-ms 128.0 components/block 225.4 cpu-ms/block 8128 data_shreds/block 448.3 early_verified_tx/block 63.43 full_to_ready_p50-ms 70.57 full_to_ready_p95-ms 7.995 mean_width 0.001262 preparation_wait_p50-ms 0.001913 preparation_wait_p95-ms 33760 tx/block 63510485 B/op 276470 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/catchup/overlap_on-8 3 67443208 ns/op 3.253 avg_cpu_cores 2.138 collection_p50-ms 2.190 collection_p95-ms 9.260 completion_parse_p50-ms 9.645 completion_parse_p95-ms 48.49 completion_sigverify_p50-ms 51.30 completion_sigverify_p95-ms 128.0 components/block 219.4 cpu-ms/block 8128 data_shreds/block 717.3 early_verified_tx/block 66.76 full_to_ready_p50-ms 66.92 full_to_ready_p95-ms 7.996 mean_width 0.0007000 preparation_wait_p50-ms 0.001174 preparation_wait_p95-ms 33760 tx/block 63344117 B/op 276427 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/catchup/overlap_on-8 3 52447666 ns/op 3.460 avg_cpu_cores 1.682 collection_p50-ms 1.766 collection_p95-ms 6.681 completion_parse_p50-ms 7.321 completion_parse_p95-ms 37.96 completion_sigverify_p50-ms 38.18 completion_sigverify_p95-ms 128.0 components/block 181.5 cpu-ms/block 8128 data_shreds/block 358.7 early_verified_tx/block 51.77 full_to_ready_p50-ms 52.04 full_to_ready_p95-ms 7.996 mean_width 0.0009730 preparation_wait_p50-ms 0.001014 preparation_wait_p95-ms 33760 tx/block 63509837 B/op 276467 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/tip_200ms/overlap_off-8 3 251131391 ns/op 0.7197 avg_cpu_cores 200.6 collection_p50-ms 200.8 collection_p95-ms 6.767 completion_parse_p50-ms 7.056 completion_parse_p95-ms 39.38 completion_sigverify_p50-ms 39.88 completion_sigverify_p95-ms 128.0 components/block 180.7 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 50.30 full_to_ready_p50-ms 51.33 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 60474034 B/op 276254 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/tip_200ms/overlap_off-8 3 250708659 ns/op 0.7074 avg_cpu_cores 200.7 collection_p50-ms 200.8 collection_p95-ms 6.285 completion_parse_p50-ms 6.691 completion_parse_p95-ms 39.31 completion_sigverify_p50-ms 40.26 completion_sigverify_p95-ms 128.0 components/block 177.3 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 49.88 full_to_ready_p50-ms 51.60 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 60657186 B/op 276264 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/tip_200ms/overlap_off-8 3 250569171 ns/op 0.7089 avg_cpu_cores 200.7 collection_p50-ms 201.2 collection_p95-ms 6.188 completion_parse_p50-ms 6.469 completion_parse_p95-ms 39.20 completion_sigverify_p50-ms 40.32 completion_sigverify_p95-ms 128.0 components/block 177.6 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 49.62 full_to_ready_p50-ms 50.23 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 60748789 B/op 276269 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/tip_200ms/overlap_on-8 3 208138109 ns/op 0.8932 avg_cpu_cores 201.2 collection_p50-ms 201.2 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.01720 completion_sigverify_p50-ms 0.02235 completion_sigverify_p95-ms 128.0 components/block 185.9 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 7.853 full_to_ready_p50-ms 8.999 full_to_ready_p95-ms 7.912 mean_width 0.02114 preparation_wait_p50-ms 0.02434 preparation_wait_p95-ms 33760 tx/block 69690304 B/op 279213 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/tip_200ms/overlap_on-8 3 207816740 ns/op 0.9928 avg_cpu_cores 200.8 collection_p50-ms 201.1 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.02023 completion_sigverify_p50-ms 0.02548 completion_sigverify_p95-ms 128.0 components/block 206.3 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 7.829 full_to_ready_p50-ms 8.333 full_to_ready_p95-ms 7.912 mean_width 0.01985 preparation_wait_p50-ms 0.02489 preparation_wait_p95-ms 33760 tx/block 69734096 B/op 279203 allocs/op +BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/tip_200ms/overlap_on-8 3 207211686 ns/op 0.8998 avg_cpu_cores 200.3 collection_p50-ms 200.9 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.01778 completion_sigverify_p50-ms 0.02121 completion_sigverify_p95-ms 128.0 components/block 186.4 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 7.442 full_to_ready_p50-ms 8.205 full_to_ready_p95-ms 7.912 mean_width 0.02017 preparation_wait_p50-ms 0.02153 preparation_wait_p95-ms 33760 tx/block 69779202 B/op 279201 allocs/op +PASS diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/assembly-comparison.json b/docs/results/sigverify-streaming/2026-09-12-zen5/assembly-comparison.json new file mode 100644 index 00000000..1e7694d3 --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/assembly-comparison.json @@ -0,0 +1,1602 @@ +[ + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/catchup/overlap_off-8", + "samples": 3, + "median": { + "ns/op": 93330914.0, + "avg_cpu_cores": 1.983, + "collection_p50-ms": 1.146, + "collection_p95-ms": 1.289, + "completion_parse_p50-ms": 7.575, + "completion_parse_p95-ms": 7.927, + "completion_sigverify_p50-ms": 78.84, + "completion_sigverify_p95-ms": 82.89, + "components/block": 128.0, + "cpu-ms/block": 185.0, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 91.61, + "full_to_ready_p95-ms": 96.68, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 60657304.0, + "allocs/op": 276266.0 + }, + "rows": [ + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/catchup/overlap_off-8", + "iterations": 3, + "ns/op": 105356378.0, + "avg_cpu_cores": 1.971, + "collection_p50-ms": 1.468, + "collection_p95-ms": 1.85, + "completion_parse_p50-ms": 8.134, + "completion_parse_p95-ms": 8.419, + "completion_sigverify_p50-ms": 91.75, + "completion_sigverify_p95-ms": 93.7, + "components/block": 128.0, + "cpu-ms/block": 207.7, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 105.0, + "full_to_ready_p95-ms": 106.8, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 60657304.0, + "allocs/op": 276266.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/catchup/overlap_off-8", + "iterations": 3, + "ns/op": 86032987.0, + "avg_cpu_cores": 2.002, + "collection_p50-ms": 1.089, + "collection_p95-ms": 1.203, + "completion_parse_p50-ms": 6.689, + "completion_parse_p95-ms": 6.878, + "completion_sigverify_p50-ms": 74.21, + "completion_sigverify_p95-ms": 74.64, + "components/block": 128.0, + "cpu-ms/block": 172.3, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 85.25, + "full_to_ready_p95-ms": 86.05, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 60840701.0, + "allocs/op": 276276.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/catchup/overlap_off-8", + "iterations": 3, + "ns/op": 93330914.0, + "avg_cpu_cores": 1.983, + "collection_p50-ms": 1.146, + "collection_p95-ms": 1.289, + "completion_parse_p50-ms": 7.575, + "completion_parse_p95-ms": 7.927, + "completion_sigverify_p50-ms": 78.84, + "completion_sigverify_p95-ms": 82.89, + "components/block": 128.0, + "cpu-ms/block": 185.0, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 91.61, + "full_to_ready_p95-ms": 96.68, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 60612906.0, + "allocs/op": 276264.0 + } + ] + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/catchup/overlap_on-8", + "samples": 3, + "median": { + "ns/op": 93317165.0, + "avg_cpu_cores": 2.002, + "collection_p50-ms": 1.59, + "collection_p95-ms": 1.976, + "completion_parse_p50-ms": 6.919, + "completion_parse_p95-ms": 7.778, + "completion_sigverify_p50-ms": 76.41, + "completion_sigverify_p95-ms": 84.5, + "components/block": 128.0, + "cpu-ms/block": 186.2, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 89.67, + "full_to_ready_p50-ms": 90.85, + "full_to_ready_p95-ms": 97.05, + "mean_width": 7.997, + "preparation_wait_p50-ms": 0.000721, + "preparation_wait_p95-ms": 0.4474, + "tx/block": 33760.0, + "B/op": 63411160.0, + "allocs/op": 276416.0 + }, + "rows": [ + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/catchup/overlap_on-8", + "iterations": 3, + "ns/op": 98687304.0, + "avg_cpu_cores": 2.002, + "collection_p50-ms": 1.923, + "collection_p95-ms": 2.397, + "completion_parse_p50-ms": 8.068, + "completion_parse_p95-ms": 8.712, + "completion_sigverify_p50-ms": 84.04, + "completion_sigverify_p95-ms": 84.5, + "components/block": 128.0, + "cpu-ms/block": 197.6, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 98.0, + "full_to_ready_p95-ms": 99.33, + "mean_width": 7.997, + "preparation_wait_p50-ms": 0.000902, + "preparation_wait_p95-ms": 2.642, + "tx/block": 33760.0, + "B/op": 63544576.0, + "allocs/op": 276416.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/catchup/overlap_on-8", + "iterations": 3, + "ns/op": 86908892.0, + "avg_cpu_cores": 2.033, + "collection_p50-ms": 1.582, + "collection_p95-ms": 1.667, + "completion_parse_p50-ms": 6.919, + "completion_parse_p95-ms": 7.541, + "completion_sigverify_p50-ms": 71.67, + "completion_sigverify_p95-ms": 73.28, + "components/block": 128.0, + "cpu-ms/block": 176.7, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 89.67, + "full_to_ready_p50-ms": 85.58, + "full_to_ready_p95-ms": 86.16, + "mean_width": 7.996, + "preparation_wait_p50-ms": 0.000721, + "preparation_wait_p95-ms": 0.4474, + "tx/block": 33760.0, + "B/op": 63411160.0, + "allocs/op": 276433.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/catchup/overlap_on-8", + "iterations": 3, + "ns/op": 93317165.0, + "avg_cpu_cores": 1.995, + "collection_p50-ms": 1.59, + "collection_p95-ms": 1.976, + "completion_parse_p50-ms": 6.82, + "completion_parse_p95-ms": 7.778, + "completion_sigverify_p50-ms": 76.41, + "completion_sigverify_p95-ms": 85.36, + "components/block": 128.0, + "cpu-ms/block": 186.2, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 89.67, + "full_to_ready_p50-ms": 90.85, + "full_to_ready_p95-ms": 97.05, + "mean_width": 7.998, + "preparation_wait_p50-ms": 0.000591, + "preparation_wait_p95-ms": 0.000641, + "tx/block": 33760.0, + "B/op": 63403101.0, + "allocs/op": 276380.0 + } + ] + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/tip_200ms/overlap_off-8", + "samples": 3, + "median": { + "ns/op": 287675866.0, + "avg_cpu_cores": 0.6167, + "collection_p50-ms": 200.6, + "collection_p95-ms": 200.7, + "completion_parse_p50-ms": 6.565, + "completion_parse_p95-ms": 6.802, + "completion_sigverify_p50-ms": 74.5, + "completion_sigverify_p95-ms": 77.8, + "components/block": 128.0, + "cpu-ms/block": 177.4, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 85.88, + "full_to_ready_p95-ms": 89.34, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 60656794.0, + "allocs/op": 276264.0 + }, + "rows": [ + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 3, + "ns/op": 290460961.0, + "avg_cpu_cores": 0.6306, + "collection_p50-ms": 200.6, + "collection_p95-ms": 200.7, + "completion_parse_p50-ms": 6.281, + "completion_parse_p95-ms": 7.566, + "completion_sigverify_p50-ms": 73.61, + "completion_sigverify_p95-ms": 88.73, + "components/block": 128.0, + "cpu-ms/block": 183.2, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 84.53, + "full_to_ready_p95-ms": 101.9, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 60656794.0, + "allocs/op": 276264.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 3, + "ns/op": 287675866.0, + "avg_cpu_cores": 0.6167, + "collection_p50-ms": 200.6, + "collection_p95-ms": 200.6, + "completion_parse_p50-ms": 6.699, + "completion_parse_p95-ms": 6.802, + "completion_sigverify_p50-ms": 75.07, + "completion_sigverify_p95-ms": 77.73, + "components/block": 128.0, + "cpu-ms/block": 177.4, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 86.16, + "full_to_ready_p95-ms": 89.34, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 60519650.0, + "allocs/op": 276258.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 3, + "ns/op": 287110470.0, + "avg_cpu_cores": 0.614, + "collection_p50-ms": 200.6, + "collection_p95-ms": 201.2, + "completion_parse_p50-ms": 6.565, + "completion_parse_p95-ms": 6.62, + "completion_sigverify_p50-ms": 74.5, + "completion_sigverify_p95-ms": 77.8, + "components/block": 128.0, + "cpu-ms/block": 176.3, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 85.88, + "full_to_ready_p95-ms": 87.16, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 60656832.0, + "allocs/op": 276264.0 + } + ] + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/tip_200ms/overlap_on-8", + "samples": 3, + "median": { + "ns/op": 208058833.0, + "avg_cpu_cores": 0.8943, + "collection_p50-ms": 200.7, + "collection_p95-ms": 200.9, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.01885, + "completion_sigverify_p95-ms": 0.02061, + "components/block": 128.0, + "cpu-ms/block": 185.8, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 7.755, + "full_to_ready_p95-ms": 9.007, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.02234, + "preparation_wait_p95-ms": 0.02347, + "tx/block": 33760.0, + "B/op": 69730546.0, + "allocs/op": 279217.0 + }, + "rows": [ + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 3, + "ns/op": 209450474.0, + "avg_cpu_cores": 0.9421, + "collection_p50-ms": 200.7, + "collection_p95-ms": 201.2, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.01935, + "completion_sigverify_p95-ms": 0.03406, + "components/block": 128.0, + "cpu-ms/block": 197.3, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 8.638, + "full_to_ready_p95-ms": 9.007, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.02519, + "preparation_wait_p95-ms": 0.03274, + "tx/block": 33760.0, + "B/op": 69730546.0, + "allocs/op": 279208.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 3, + "ns/op": 208058833.0, + "avg_cpu_cores": 0.8929, + "collection_p50-ms": 200.7, + "collection_p95-ms": 200.7, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.01704, + "completion_sigverify_p95-ms": 0.02061, + "components/block": 128.0, + "cpu-ms/block": 185.8, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 7.636, + "full_to_ready_p95-ms": 9.799, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.02234, + "preparation_wait_p95-ms": 0.02347, + "tx/block": 33760.0, + "B/op": 69690704.0, + "allocs/op": 279231.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 3, + "ns/op": 207559046.0, + "avg_cpu_cores": 0.8943, + "collection_p50-ms": 200.6, + "collection_p95-ms": 200.9, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.01885, + "completion_sigverify_p95-ms": 0.01951, + "components/block": 128.0, + "cpu-ms/block": 185.6, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 7.755, + "full_to_ready_p95-ms": 8.173, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.02086, + "preparation_wait_p95-ms": 0.02149, + "tx/block": 33760.0, + "B/op": 69823114.0, + "allocs/op": 279217.0 + } + ] + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/catchup/overlap_off-8", + "samples": 3, + "median": { + "ns/op": 55875291.0, + "avg_cpu_cores": 3.314, + "collection_p50-ms": 1.177, + "collection_p95-ms": 1.709, + "completion_parse_p50-ms": 7.277, + "completion_parse_p95-ms": 7.356, + "completion_sigverify_p50-ms": 42.47, + "completion_sigverify_p95-ms": 44.27, + "components/block": 128.0, + "cpu-ms/block": 187.6, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 55.07, + "full_to_ready_p95-ms": 55.62, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 60611714.0, + "allocs/op": 276263.0 + }, + "rows": [ + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/catchup/overlap_off-8", + "iterations": 3, + "ns/op": 55875291.0, + "avg_cpu_cores": 3.314, + "collection_p50-ms": 1.291, + "collection_p95-ms": 1.709, + "completion_parse_p50-ms": 7.281, + "completion_parse_p95-ms": 7.313, + "completion_sigverify_p50-ms": 40.25, + "completion_sigverify_p95-ms": 42.81, + "components/block": 128.0, + "cpu-ms/block": 185.2, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 55.07, + "full_to_ready_p95-ms": 55.62, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 60611714.0, + "allocs/op": 276263.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/catchup/overlap_off-8", + "iterations": 3, + "ns/op": 61860407.0, + "avg_cpu_cores": 3.216, + "collection_p50-ms": 1.169, + "collection_p95-ms": 2.221, + "completion_parse_p50-ms": 7.116, + "completion_parse_p95-ms": 10.84, + "completion_sigverify_p50-ms": 47.89, + "completion_sigverify_p95-ms": 48.65, + "components/block": 128.0, + "cpu-ms/block": 198.9, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 62.07, + "full_to_ready_p95-ms": 67.59, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 60473978.0, + "allocs/op": 276254.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/catchup/overlap_off-8", + "iterations": 3, + "ns/op": 55571155.0, + "avg_cpu_cores": 3.375, + "collection_p50-ms": 1.177, + "collection_p95-ms": 1.29, + "completion_parse_p50-ms": 7.277, + "completion_parse_p95-ms": 7.356, + "completion_sigverify_p50-ms": 42.47, + "completion_sigverify_p95-ms": 44.27, + "components/block": 128.0, + "cpu-ms/block": 187.6, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 54.23, + "full_to_ready_p95-ms": 54.69, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 60748730.0, + "allocs/op": 276268.0 + } + ] + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/catchup/overlap_on-8", + "samples": 3, + "median": { + "ns/op": 66703191.0, + "avg_cpu_cores": 3.379, + "collection_p50-ms": 2.138, + "collection_p95-ms": 2.19, + "completion_parse_p50-ms": 8.584, + "completion_parse_p95-ms": 9.645, + "completion_sigverify_p50-ms": 48.49, + "completion_sigverify_p95-ms": 51.3, + "components/block": 128.0, + "cpu-ms/block": 219.4, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 448.3, + "full_to_ready_p50-ms": 63.43, + "full_to_ready_p95-ms": 66.92, + "mean_width": 7.996, + "preparation_wait_p50-ms": 0.000973, + "preparation_wait_p95-ms": 0.001174, + "tx/block": 33760.0, + "B/op": 63509837.0, + "allocs/op": 276467.0 + }, + "rows": [ + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/catchup/overlap_on-8", + "iterations": 3, + "ns/op": 66703191.0, + "avg_cpu_cores": 3.379, + "collection_p50-ms": 2.562, + "collection_p95-ms": 2.726, + "completion_parse_p50-ms": 8.584, + "completion_parse_p95-ms": 10.03, + "completion_sigverify_p50-ms": 50.79, + "completion_sigverify_p95-ms": 52.88, + "components/block": 128.0, + "cpu-ms/block": 225.4, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 448.3, + "full_to_ready_p50-ms": 63.43, + "full_to_ready_p95-ms": 70.57, + "mean_width": 7.995, + "preparation_wait_p50-ms": 0.001262, + "preparation_wait_p95-ms": 0.001913, + "tx/block": 33760.0, + "B/op": 63510485.0, + "allocs/op": 276470.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/catchup/overlap_on-8", + "iterations": 3, + "ns/op": 67443208.0, + "avg_cpu_cores": 3.253, + "collection_p50-ms": 2.138, + "collection_p95-ms": 2.19, + "completion_parse_p50-ms": 9.26, + "completion_parse_p95-ms": 9.645, + "completion_sigverify_p50-ms": 48.49, + "completion_sigverify_p95-ms": 51.3, + "components/block": 128.0, + "cpu-ms/block": 219.4, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 717.3, + "full_to_ready_p50-ms": 66.76, + "full_to_ready_p95-ms": 66.92, + "mean_width": 7.996, + "preparation_wait_p50-ms": 0.0007, + "preparation_wait_p95-ms": 0.001174, + "tx/block": 33760.0, + "B/op": 63344117.0, + "allocs/op": 276427.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/catchup/overlap_on-8", + "iterations": 3, + "ns/op": 52447666.0, + "avg_cpu_cores": 3.46, + "collection_p50-ms": 1.682, + "collection_p95-ms": 1.766, + "completion_parse_p50-ms": 6.681, + "completion_parse_p95-ms": 7.321, + "completion_sigverify_p50-ms": 37.96, + "completion_sigverify_p95-ms": 38.18, + "components/block": 128.0, + "cpu-ms/block": 181.5, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 358.7, + "full_to_ready_p50-ms": 51.77, + "full_to_ready_p95-ms": 52.04, + "mean_width": 7.996, + "preparation_wait_p50-ms": 0.000973, + "preparation_wait_p95-ms": 0.001014, + "tx/block": 33760.0, + "B/op": 63509837.0, + "allocs/op": 276467.0 + } + ] + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/tip_200ms/overlap_off-8", + "samples": 3, + "median": { + "ns/op": 250708659.0, + "avg_cpu_cores": 0.7089, + "collection_p50-ms": 200.7, + "collection_p95-ms": 200.8, + "completion_parse_p50-ms": 6.285, + "completion_parse_p95-ms": 6.691, + "completion_sigverify_p50-ms": 39.31, + "completion_sigverify_p95-ms": 40.26, + "components/block": 128.0, + "cpu-ms/block": 177.6, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 49.88, + "full_to_ready_p95-ms": 51.33, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 60657186.0, + "allocs/op": 276264.0 + }, + "rows": [ + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/tip_200ms/overlap_off-8", + "iterations": 3, + "ns/op": 251131391.0, + "avg_cpu_cores": 0.7197, + "collection_p50-ms": 200.6, + "collection_p95-ms": 200.8, + "completion_parse_p50-ms": 6.767, + "completion_parse_p95-ms": 7.056, + "completion_sigverify_p50-ms": 39.38, + "completion_sigverify_p95-ms": 39.88, + "components/block": 128.0, + "cpu-ms/block": 180.7, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 50.3, + "full_to_ready_p95-ms": 51.33, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 60474034.0, + "allocs/op": 276254.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/tip_200ms/overlap_off-8", + "iterations": 3, + "ns/op": 250708659.0, + "avg_cpu_cores": 0.7074, + "collection_p50-ms": 200.7, + "collection_p95-ms": 200.8, + "completion_parse_p50-ms": 6.285, + "completion_parse_p95-ms": 6.691, + "completion_sigverify_p50-ms": 39.31, + "completion_sigverify_p95-ms": 40.26, + "components/block": 128.0, + "cpu-ms/block": 177.3, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 49.88, + "full_to_ready_p95-ms": 51.6, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 60657186.0, + "allocs/op": 276264.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/tip_200ms/overlap_off-8", + "iterations": 3, + "ns/op": 250569171.0, + "avg_cpu_cores": 0.7089, + "collection_p50-ms": 200.7, + "collection_p95-ms": 201.2, + "completion_parse_p50-ms": 6.188, + "completion_parse_p95-ms": 6.469, + "completion_sigverify_p50-ms": 39.2, + "completion_sigverify_p95-ms": 40.32, + "components/block": 128.0, + "cpu-ms/block": 177.6, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 49.62, + "full_to_ready_p95-ms": 50.23, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 60748789.0, + "allocs/op": 276269.0 + } + ] + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/tip_200ms/overlap_on-8", + "samples": 3, + "median": { + "ns/op": 207816740.0, + "avg_cpu_cores": 0.8998, + "collection_p50-ms": 200.8, + "collection_p95-ms": 201.1, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.01778, + "completion_sigverify_p95-ms": 0.02235, + "components/block": 128.0, + "cpu-ms/block": 186.4, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 7.829, + "full_to_ready_p95-ms": 8.333, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.02017, + "preparation_wait_p95-ms": 0.02434, + "tx/block": 33760.0, + "B/op": 69734096.0, + "allocs/op": 279203.0 + }, + "rows": [ + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/tip_200ms/overlap_on-8", + "iterations": 3, + "ns/op": 208138109.0, + "avg_cpu_cores": 0.8932, + "collection_p50-ms": 201.2, + "collection_p95-ms": 201.2, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.0172, + "completion_sigverify_p95-ms": 0.02235, + "components/block": 128.0, + "cpu-ms/block": 185.9, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 7.853, + "full_to_ready_p95-ms": 8.999, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.02114, + "preparation_wait_p95-ms": 0.02434, + "tx/block": 33760.0, + "B/op": 69690304.0, + "allocs/op": 279213.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/tip_200ms/overlap_on-8", + "iterations": 3, + "ns/op": 207816740.0, + "avg_cpu_cores": 0.9928, + "collection_p50-ms": 200.8, + "collection_p95-ms": 201.1, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.02023, + "completion_sigverify_p95-ms": 0.02548, + "components/block": 128.0, + "cpu-ms/block": 206.3, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 7.829, + "full_to_ready_p95-ms": 8.333, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.01985, + "preparation_wait_p95-ms": 0.02489, + "tx/block": 33760.0, + "B/op": 69734096.0, + "allocs/op": 279203.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/captured_2622581/workers_4/target_8/tip_200ms/overlap_on-8", + "iterations": 3, + "ns/op": 207211686.0, + "avg_cpu_cores": 0.8998, + "collection_p50-ms": 200.3, + "collection_p95-ms": 200.9, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.01778, + "completion_sigverify_p95-ms": 0.02121, + "components/block": 128.0, + "cpu-ms/block": 186.4, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 7.442, + "full_to_ready_p95-ms": 8.205, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.02017, + "preparation_wait_p95-ms": 0.02153, + "tx/block": 33760.0, + "B/op": 69779202.0, + "allocs/op": 279201.0 + } + ] + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8", + "samples": 3, + "median": { + "ns/op": 132732036.0, + "avg_cpu_cores": 1.969, + "collection_p50-ms": 6.714, + "collection_p95-ms": 6.898, + "completion_parse_p50-ms": 4.634, + "completion_parse_p95-ms": 5.372, + "completion_sigverify_p50-ms": 89.28, + "completion_sigverify_p95-ms": 94.08, + "components/block": 691.0, + "cpu-ms/block": 255.6, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 123.2, + "full_to_ready_p95-ms": 132.1, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260174637.0, + "allocs/op": 235471.0 + }, + "rows": [ + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 3, + "ns/op": 132732036.0, + "avg_cpu_cores": 1.926, + "collection_p50-ms": 6.714, + "collection_p95-ms": 6.898, + "completion_parse_p50-ms": 4.501, + "completion_parse_p95-ms": 4.815, + "completion_sigverify_p50-ms": 89.28, + "completion_sigverify_p95-ms": 102.2, + "components/block": 691.0, + "cpu-ms/block": 255.6, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 123.2, + "full_to_ready_p95-ms": 133.2, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260174637.0, + "allocs/op": 235471.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 3, + "ns/op": 134071642.0, + "avg_cpu_cores": 1.969, + "collection_p50-ms": 8.232, + "collection_p95-ms": 8.625, + "completion_parse_p50-ms": 5.486, + "completion_parse_p95-ms": 5.85, + "completion_sigverify_p50-ms": 93.22, + "completion_sigverify_p95-ms": 94.08, + "components/block": 691.0, + "cpu-ms/block": 264.0, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 128.8, + "full_to_ready_p95-ms": 132.1, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 259991864.0, + "allocs/op": 235464.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 3, + "ns/op": 118432537.0, + "avg_cpu_cores": 1.989, + "collection_p50-ms": 5.898, + "collection_p95-ms": 6.123, + "completion_parse_p50-ms": 4.634, + "completion_parse_p95-ms": 5.372, + "completion_sigverify_p50-ms": 82.63, + "completion_sigverify_p95-ms": 82.8, + "components/block": 691.0, + "cpu-ms/block": 235.6, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 111.0, + "full_to_ready_p95-ms": 115.7, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260219832.0, + "allocs/op": 235471.0 + } + ] + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8", + "samples": 3, + "median": { + "ns/op": 140105831.0, + "avg_cpu_cores": 2.039, + "collection_p50-ms": 9.935, + "collection_p95-ms": 11.14, + "completion_parse_p50-ms": 5.302, + "completion_parse_p95-ms": 5.596, + "completion_sigverify_p50-ms": 91.17, + "completion_sigverify_p95-ms": 94.68, + "components/block": 691.0, + "cpu-ms/block": 285.6, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 2140.0, + "full_to_ready_p50-ms": 131.0, + "full_to_ready_p95-ms": 131.5, + "mean_width": 7.927, + "preparation_wait_p50-ms": 0.00567, + "preparation_wait_p95-ms": 0.007029, + "tx/block": 33760.0, + "B/op": 265780592.0, + "allocs/op": 236507.0 + }, + "rows": [ + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 3, + "ns/op": 143317986.0, + "avg_cpu_cores": 1.993, + "collection_p50-ms": 10.38, + "collection_p95-ms": 10.94, + "completion_parse_p50-ms": 5.302, + "completion_parse_p95-ms": 5.596, + "completion_sigverify_p50-ms": 91.17, + "completion_sigverify_p95-ms": 96.29, + "components/block": 691.0, + "cpu-ms/block": 285.7, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 2515.0, + "full_to_ready_p50-ms": 132.7, + "full_to_ready_p95-ms": 136.1, + "mean_width": 7.914, + "preparation_wait_p50-ms": 0.007227, + "preparation_wait_p95-ms": 0.008702, + "tx/block": 33760.0, + "B/op": 265981290.0, + "allocs/op": 236644.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 3, + "ns/op": 140105831.0, + "avg_cpu_cores": 2.039, + "collection_p50-ms": 9.935, + "collection_p95-ms": 11.26, + "completion_parse_p50-ms": 5.33, + "completion_parse_p95-ms": 6.534, + "completion_sigverify_p50-ms": 93.04, + "completion_sigverify_p95-ms": 94.68, + "components/block": 691.0, + "cpu-ms/block": 285.6, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 2140.0, + "full_to_ready_p50-ms": 131.0, + "full_to_ready_p95-ms": 131.5, + "mean_width": 7.927, + "preparation_wait_p50-ms": 0.00567, + "preparation_wait_p95-ms": 0.006587, + "tx/block": 33760.0, + "B/op": 265780592.0, + "allocs/op": 236507.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 3, + "ns/op": 118146761.0, + "avg_cpu_cores": 2.052, + "collection_p50-ms": 8.247, + "collection_p95-ms": 11.14, + "completion_parse_p50-ms": 5.074, + "completion_parse_p95-ms": 5.303, + "completion_sigverify_p50-ms": 79.37, + "completion_sigverify_p95-ms": 79.81, + "components/block": 691.0, + "cpu-ms/block": 242.4, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 2091.0, + "full_to_ready_p50-ms": 106.7, + "full_to_ready_p95-ms": 116.1, + "mean_width": 7.929, + "preparation_wait_p50-ms": 0.003786, + "preparation_wait_p95-ms": 0.007029, + "tx/block": 33760.0, + "B/op": 265573218.0, + "allocs/op": 236474.0 + } + ] + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8", + "samples": 3, + "median": { + "ns/op": 318801116.0, + "avg_cpu_cores": 0.7606, + "collection_p50-ms": 201.6, + "collection_p95-ms": 201.7, + "completion_parse_p50-ms": 4.599, + "completion_parse_p95-ms": 5.045, + "completion_sigverify_p50-ms": 83.28, + "completion_sigverify_p95-ms": 85.2, + "components/block": 691.0, + "cpu-ms/block": 242.5, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 118.0, + "full_to_ready_p95-ms": 122.6, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260082442.0, + "allocs/op": 235464.0 + }, + "rows": [ + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 3, + "ns/op": 318801116.0, + "avg_cpu_cores": 0.7606, + "collection_p50-ms": 201.0, + "collection_p95-ms": 201.6, + "completion_parse_p50-ms": 4.599, + "completion_parse_p95-ms": 5.045, + "completion_sigverify_p50-ms": 83.28, + "completion_sigverify_p95-ms": 85.2, + "components/block": 691.0, + "cpu-ms/block": 242.5, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 118.3, + "full_to_ready_p95-ms": 122.6, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260036650.0, + "allocs/op": 235461.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 3, + "ns/op": 314110925.0, + "avg_cpu_cores": 0.7601, + "collection_p50-ms": 201.6, + "collection_p95-ms": 201.7, + "completion_parse_p50-ms": 4.269, + "completion_parse_p95-ms": 4.42, + "completion_sigverify_p50-ms": 82.73, + "completion_sigverify_p95-ms": 82.83, + "components/block": 691.0, + "cpu-ms/block": 238.8, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 113.3, + "full_to_ready_p95-ms": 113.6, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260219818.0, + "allocs/op": 235471.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 3, + "ns/op": 322511217.0, + "avg_cpu_cores": 0.7751, + "collection_p50-ms": 201.7, + "collection_p95-ms": 202.5, + "completion_parse_p50-ms": 4.627, + "completion_parse_p95-ms": 5.343, + "completion_sigverify_p50-ms": 84.98, + "completion_sigverify_p95-ms": 88.32, + "components/block": 691.0, + "cpu-ms/block": 250.0, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 118.0, + "full_to_ready_p95-ms": 126.6, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260082442.0, + "allocs/op": 235464.0 + } + ] + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8", + "samples": 3, + "median": { + "ns/op": 229370055.0, + "avg_cpu_cores": 1.167, + "collection_p50-ms": 201.1, + "collection_p95-ms": 201.2, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.01079, + "completion_sigverify_p50-ms": 0.122, + "completion_sigverify_p95-ms": 0.312, + "components/block": 691.0, + "cpu-ms/block": 266.5, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33744.0, + "full_to_ready_p50-ms": 28.97, + "full_to_ready_p95-ms": 30.22, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1252, + "preparation_wait_p95-ms": 0.126, + "tx/block": 33760.0, + "B/op": 307432845.0, + "allocs/op": 250046.0 + }, + "rows": [ + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 3, + "ns/op": 226899169.0, + "avg_cpu_cores": 1.167, + "collection_p50-ms": 201.4, + "collection_p95-ms": 201.4, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.01079, + "completion_sigverify_p50-ms": 0.122, + "completion_sigverify_p95-ms": 0.312, + "components/block": 691.0, + "cpu-ms/block": 264.7, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33744.0, + "full_to_ready_p50-ms": 25.53, + "full_to_ready_p95-ms": 26.34, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1206, + "preparation_wait_p95-ms": 0.1241, + "tx/block": 33760.0, + "B/op": 307640389.0, + "allocs/op": 250060.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 3, + "ns/op": 229370055.0, + "avg_cpu_cores": 1.162, + "collection_p50-ms": 200.7, + "collection_p95-ms": 201.2, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.01841, + "completion_sigverify_p50-ms": 0.1002, + "completion_sigverify_p95-ms": 0.456, + "components/block": 691.0, + "cpu-ms/block": 266.5, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33728.0, + "full_to_ready_p50-ms": 29.75, + "full_to_ready_p95-ms": 30.22, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1252, + "preparation_wait_p95-ms": 0.126, + "tx/block": 33760.0, + "B/op": 307397858.0, + "allocs/op": 250045.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 3, + "ns/op": 231567222.0, + "avg_cpu_cores": 1.363, + "collection_p50-ms": 201.1, + "collection_p95-ms": 201.2, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.1245, + "completion_sigverify_p95-ms": 0.1492, + "components/block": 691.0, + "cpu-ms/block": 315.7, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 28.97, + "full_to_ready_p95-ms": 34.61, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1317, + "preparation_wait_p95-ms": 0.137, + "tx/block": 33760.0, + "B/op": 307432845.0, + "allocs/op": 250046.0 + } + ] + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/catchup/overlap_off-8", + "samples": 3, + "median": { + "ns/op": 98393903.0, + "avg_cpu_cores": 2.983, + "collection_p50-ms": 8.19, + "collection_p95-ms": 8.563, + "completion_parse_p50-ms": 4.938, + "completion_parse_p95-ms": 5.485, + "completion_sigverify_p50-ms": 52.0, + "completion_sigverify_p95-ms": 57.0, + "components/block": 691.0, + "cpu-ms/block": 293.5, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 88.12, + "full_to_ready_p95-ms": 95.35, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260266082.0, + "allocs/op": 235474.0 + }, + "rows": [ + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/catchup/overlap_off-8", + "iterations": 3, + "ns/op": 98393903.0, + "avg_cpu_cores": 2.983, + "collection_p50-ms": 8.19, + "collection_p95-ms": 8.563, + "completion_parse_p50-ms": 4.938, + "completion_parse_p95-ms": 5.485, + "completion_sigverify_p50-ms": 55.91, + "completion_sigverify_p95-ms": 57.0, + "components/block": 691.0, + "cpu-ms/block": 293.5, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 88.12, + "full_to_ready_p95-ms": 95.35, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260266082.0, + "allocs/op": 235474.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/catchup/overlap_off-8", + "iterations": 3, + "ns/op": 105755933.0, + "avg_cpu_cores": 2.776, + "collection_p50-ms": 8.602, + "collection_p95-ms": 9.822, + "completion_parse_p50-ms": 6.422, + "completion_parse_p95-ms": 7.668, + "completion_sigverify_p50-ms": 52.0, + "completion_sigverify_p95-ms": 60.88, + "components/block": 691.0, + "cpu-ms/block": 293.6, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 90.69, + "full_to_ready_p95-ms": 112.2, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260174000.0, + "allocs/op": 235467.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/catchup/overlap_off-8", + "iterations": 3, + "ns/op": 81434919.0, + "avg_cpu_cores": 3.009, + "collection_p50-ms": 6.353, + "collection_p95-ms": 6.417, + "completion_parse_p50-ms": 4.568, + "completion_parse_p95-ms": 4.63, + "completion_sigverify_p50-ms": 44.0, + "completion_sigverify_p95-ms": 44.05, + "components/block": 691.0, + "cpu-ms/block": 245.1, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 75.94, + "full_to_ready_p95-ms": 77.03, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260402965.0, + "allocs/op": 235479.0 + } + ] + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/catchup/overlap_on-8", + "samples": 3, + "median": { + "ns/op": 85283927.0, + "avg_cpu_cores": 2.979, + "collection_p50-ms": 9.315, + "collection_p95-ms": 10.89, + "completion_parse_p50-ms": 4.251, + "completion_parse_p95-ms": 5.583, + "completion_sigverify_p50-ms": 41.9, + "completion_sigverify_p95-ms": 43.8, + "components/block": 691.0, + "cpu-ms/block": 254.5, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 3430.0, + "full_to_ready_p50-ms": 75.23, + "full_to_ready_p95-ms": 86.25, + "mean_width": 7.885, + "preparation_wait_p50-ms": 0.01225, + "preparation_wait_p95-ms": 0.01287, + "tx/block": 33760.0, + "B/op": 267653104.0, + "allocs/op": 237063.0 + }, + "rows": [ + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/catchup/overlap_on-8", + "iterations": 3, + "ns/op": 81921701.0, + "avg_cpu_cores": 3.107, + "collection_p50-ms": 9.142, + "collection_p95-ms": 9.153, + "completion_parse_p50-ms": 4.251, + "completion_parse_p95-ms": 4.784, + "completion_sigverify_p50-ms": 41.9, + "completion_sigverify_p95-ms": 42.1, + "components/block": 691.0, + "cpu-ms/block": 254.5, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 3430.0, + "full_to_ready_p50-ms": 75.23, + "full_to_ready_p95-ms": 75.61, + "mean_width": 7.885, + "preparation_wait_p50-ms": 0.007166, + "preparation_wait_p95-ms": 0.0106, + "tx/block": 33760.0, + "B/op": 267789989.0, + "allocs/op": 237063.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/catchup/overlap_on-8", + "iterations": 3, + "ns/op": 106211708.0, + "avg_cpu_cores": 2.96, + "collection_p50-ms": 12.72, + "collection_p95-ms": 12.77, + "completion_parse_p50-ms": 6.076, + "completion_parse_p95-ms": 6.677, + "completion_sigverify_p50-ms": 49.86, + "completion_sigverify_p95-ms": 57.7, + "components/block": 691.0, + "cpu-ms/block": 314.4, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 3397.0, + "full_to_ready_p50-ms": 91.87, + "full_to_ready_p95-ms": 99.87, + "mean_width": 7.886, + "preparation_wait_p50-ms": 0.01751, + "preparation_wait_p95-ms": 0.01784, + "tx/block": 33760.0, + "B/op": 267653104.0, + "allocs/op": 237049.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/catchup/overlap_on-8", + "iterations": 3, + "ns/op": 85283927.0, + "avg_cpu_cores": 2.979, + "collection_p50-ms": 9.315, + "collection_p95-ms": 10.89, + "completion_parse_p50-ms": 3.727, + "completion_parse_p95-ms": 5.583, + "completion_sigverify_p50-ms": 41.31, + "completion_sigverify_p95-ms": 43.8, + "components/block": 691.0, + "cpu-ms/block": 254.1, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 3561.0, + "full_to_ready_p50-ms": 75.15, + "full_to_ready_p95-ms": 86.25, + "mean_width": 7.88, + "preparation_wait_p50-ms": 0.01225, + "preparation_wait_p95-ms": 0.01287, + "tx/block": 33760.0, + "B/op": 267515682.0, + "allocs/op": 237096.0 + } + ] + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/tip_200ms/overlap_off-8", + "samples": 3, + "median": { + "ns/op": 276593977.0, + "avg_cpu_cores": 0.8742, + "collection_p50-ms": 201.5, + "collection_p95-ms": 201.6, + "completion_parse_p50-ms": 4.437, + "completion_parse_p95-ms": 4.728, + "completion_sigverify_p50-ms": 43.5, + "completion_sigverify_p95-ms": 44.33, + "components/block": 691.0, + "cpu-ms/block": 241.8, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 77.04, + "full_to_ready_p95-ms": 79.84, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260403005.0, + "allocs/op": 235479.0 + }, + "rows": [ + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/tip_200ms/overlap_off-8", + "iterations": 3, + "ns/op": 276365085.0, + "avg_cpu_cores": 0.8723, + "collection_p50-ms": 201.5, + "collection_p95-ms": 201.6, + "completion_parse_p50-ms": 4.437, + "completion_parse_p95-ms": 4.504, + "completion_sigverify_p50-ms": 43.22, + "completion_sigverify_p95-ms": 43.6, + "components/block": 691.0, + "cpu-ms/block": 241.1, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 77.04, + "full_to_ready_p95-ms": 77.05, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260403005.0, + "allocs/op": 235479.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/tip_200ms/overlap_off-8", + "iterations": 3, + "ns/op": 280110502.0, + "avg_cpu_cores": 0.9259, + "collection_p50-ms": 200.8, + "collection_p95-ms": 201.1, + "completion_parse_p50-ms": 4.666, + "completion_parse_p95-ms": 4.728, + "completion_sigverify_p50-ms": 44.11, + "completion_sigverify_p95-ms": 56.8, + "components/block": 691.0, + "cpu-ms/block": 259.4, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 77.81, + "full_to_ready_p95-ms": 86.07, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260495133.0, + "allocs/op": 235486.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/tip_200ms/overlap_off-8", + "iterations": 3, + "ns/op": 276593977.0, + "avg_cpu_cores": 0.8742, + "collection_p50-ms": 201.6, + "collection_p95-ms": 201.7, + "completion_parse_p50-ms": 4.198, + "completion_parse_p95-ms": 6.163, + "completion_sigverify_p50-ms": 43.5, + "completion_sigverify_p95-ms": 44.33, + "components/block": 691.0, + "cpu-ms/block": 241.8, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 75.26, + "full_to_ready_p95-ms": 79.84, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 259991381.0, + "allocs/op": 235460.0 + } + ] + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/tip_200ms/overlap_on-8", + "samples": 3, + "median": { + "ns/op": 227100110.0, + "avg_cpu_cores": 1.167, + "collection_p50-ms": 201.2, + "collection_p95-ms": 201.4, + "completion_parse_p50-ms": 0.01037, + "completion_parse_p95-ms": 0.01195, + "completion_sigverify_p50-ms": 0.2797, + "completion_sigverify_p95-ms": 0.3548, + "components/block": 691.0, + "cpu-ms/block": 264.9, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33728.0, + "full_to_ready_p50-ms": 25.69, + "full_to_ready_p95-ms": 27.44, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1228, + "preparation_wait_p95-ms": 0.1242, + "tx/block": 33760.0, + "B/op": 307727008.0, + "allocs/op": 250008.0 + }, + "rows": [ + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/tip_200ms/overlap_on-8", + "iterations": 3, + "ns/op": 227100110.0, + "avg_cpu_cores": 1.166, + "collection_p50-ms": 201.2, + "collection_p95-ms": 201.4, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.1103, + "completion_sigverify_p95-ms": 0.1149, + "components/block": 691.0, + "cpu-ms/block": 264.9, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 25.08, + "full_to_ready_p95-ms": 27.44, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1228, + "preparation_wait_p95-ms": 0.124, + "tx/block": 33760.0, + "B/op": 307747917.0, + "allocs/op": 250014.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/tip_200ms/overlap_on-8", + "iterations": 3, + "ns/op": 241182176.0, + "avg_cpu_cores": 1.235, + "collection_p50-ms": 201.4, + "collection_p95-ms": 202.9, + "completion_parse_p50-ms": 0.01357, + "completion_parse_p95-ms": 0.04438, + "completion_sigverify_p50-ms": 0.3222, + "completion_sigverify_p95-ms": 0.4977, + "components/block": 691.0, + "cpu-ms/block": 297.8, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33712.0, + "full_to_ready_p50-ms": 34.46, + "full_to_ready_p95-ms": 51.53, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1261, + "preparation_wait_p95-ms": 0.1812, + "tx/block": 33760.0, + "B/op": 307727008.0, + "allocs/op": 250008.0 + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_4/target_8/tip_200ms/overlap_on-8", + "iterations": 3, + "ns/op": 226480518.0, + "avg_cpu_cores": 1.167, + "collection_p50-ms": 200.9, + "collection_p95-ms": 201.3, + "completion_parse_p50-ms": 0.01037, + "completion_parse_p95-ms": 0.01195, + "completion_sigverify_p50-ms": 0.2797, + "completion_sigverify_p95-ms": 0.3548, + "components/block": 691.0, + "cpu-ms/block": 264.2, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33728.0, + "full_to_ready_p50-ms": 25.69, + "full_to_ready_p95-ms": 25.87, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1226, + "preparation_wait_p95-ms": 0.1242, + "tx/block": 33760.0, + "B/op": 307612829.0, + "allocs/op": 250008.0 + } + ] + } +] diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/binary-sha256.txt b/docs/results/sigverify-streaming/2026-09-12-zen5/binary-sha256.txt new file mode 100644 index 00000000..41f7f057 --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/binary-sha256.txt @@ -0,0 +1,3 @@ +2cf2d2baeeaba0bf1218a36bee05dd9fc7323db5becef125baafb898e4d42b02 /srv/mithril-sigverify-streaming-20260912/bin/turbine.test +f36508c1d113ea8048ba8b516f4a62b0c15b54369efa41c6211bd4bd491c2da8 /srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test +6d72002ecbc772bafd7ac39a965403e5694b3f83c21cc65bfcf0d9321aaeb7f2 /srv/mithril-sigverify-streaming-20260912/bin/replay.test diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/captured-pool-flow.log b/docs/results/sigverify-streaming/2026-09-12-zen5/captured-pool-flow.log new file mode 100644 index 00000000..43a35eef --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/captured-pool-flow.log @@ -0,0 +1,113 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/catchup-8 3 156715891 ns/op 2.043 avg_cpu_cores 1.000 components/block 320.2 cpu-ms/block 0.0002710 feed_lag_p50-ms 0.001282 feed_lag_p95-ms 4.000 mean_width 158.0 ready_p50-ms 164.2 ready_p95-ms 158.0 residual_p50-ms 164.2 residual_p95-ms 33760 signatures/block 215422 signatures/s 0.01062 submit_p50-ms 0.02492 submit_p95-ms 7023138 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/catchup-8 3 155986070 ns/op 2.047 avg_cpu_cores 1.000 components/block 319.2 cpu-ms/block 0.0002510 feed_lag_p50-ms 0.0007810 feed_lag_p95-ms 4.000 mean_width 151.6 ready_p50-ms 171.1 ready_p95-ms 151.6 residual_p50-ms 171.1 residual_p95-ms 33760 signatures/block 216430 signatures/s 0.006532 submit_p50-ms 0.007404 submit_p95-ms 7023144 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/catchup-8 3 145764753 ns/op 2.047 avg_cpu_cores 1.000 components/block 298.4 cpu-ms/block 0.0002810 feed_lag_p50-ms 0.0006810 feed_lag_p95-ms 4.000 mean_width 145.4 ready_p50-ms 146.6 ready_p95-ms 145.4 residual_p50-ms 146.6 residual_p95-ms 33760 signatures/block 231606 signatures/s 0.004178 submit_p50-ms 0.007975 submit_p95-ms 7023133 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_after_complete-8 3 344523723 ns/op 0.8561 avg_cpu_cores 126.0 components/block 295.0 cpu-ms/block 100.2 feed_lag_p50-ms 191.4 feed_lag_p95-ms 4.000 mean_width 244.4 ready_p50-ms 335.6 ready_p95-ms 144.7 residual_p50-ms 145.2 residual_p95-ms 33760 signatures/block 97990 signatures/s 0.01582 submit_p50-ms 0.01597 submit_p95-ms 7033338 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_after_complete-8 3 352992831 ns/op 0.8764 avg_cpu_cores 126.0 components/block 309.4 cpu-ms/block 100.2 feed_lag_p50-ms 191.4 feed_lag_p95-ms 4.000 mean_width 252.4 ready_p50-ms 343.6 ready_p95-ms 144.6 residual_p50-ms 170.7 residual_p95-ms 33760 signatures/block 95639 signatures/s 0.01750 submit_p50-ms 0.01914 submit_p95-ms 7033616 B/op 67540 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_after_complete-8 3 363417787 ns/op 0.9118 avg_cpu_cores 126.0 components/block 331.4 cpu-ms/block 99.82 feed_lag_p50-ms 191.0 feed_lag_p95-ms 4.000 mean_width 263.0 ready_p50-ms 355.8 ready_p95-ms 163.8 residual_p50-ms 175.6 residual_p95-ms 33760 signatures/block 92896 signatures/s 0.02098 submit_p50-ms 0.02324 submit_p95-ms 7033530 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_overlap-8 3 201111285 ns/op 1.522 avg_cpu_cores 126.0 components/block 306.1 cpu-ms/block 0.03627 feed_lag_p50-ms 0.8607 feed_lag_p95-ms 3.956 mean_width 1.602 ready_p50-ms 2.473 ready_p95-ms 1.080 residual_p50-ms 1.219 residual_p95-ms 33760 signatures/block 167867 signatures/s 0.001032 submit_p50-ms 0.003166 submit_p95-ms 7165506 B/op 68945 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_overlap-8 3 201378639 ns/op 1.498 avg_cpu_cores 126.0 components/block 301.7 cpu-ms/block 0.2205 feed_lag_p50-ms 0.8775 feed_lag_p95-ms 3.956 mean_width 1.582 ready_p50-ms 2.532 ready_p95-ms 1.361 residual_p50-ms 1.407 residual_p95-ms 33760 signatures/block 167644 signatures/s 0.001123 submit_p50-ms 0.002805 submit_p95-ms 7167869 B/op 68945 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_overlap-8 3 201155070 ns/op 1.486 avg_cpu_cores 126.0 components/block 299.0 cpu-ms/block 0.05468 feed_lag_p50-ms 0.8310 feed_lag_p95-ms 3.956 mean_width 1.579 ready_p50-ms 2.456 ready_p95-ms 1.334 residual_p50-ms 1.380 residual_p95-ms 33760 signatures/block 167831 signatures/s 0.001042 submit_p50-ms 0.002434 submit_p95-ms 7159269 B/op 68921 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/catchup-8 3 74916706 ns/op 2.041 avg_cpu_cores 1.000 components/block 152.9 cpu-ms/block 0.0002510 feed_lag_p50-ms 0.0004810 feed_lag_p95-ms 8.000 mean_width 74.90 ready_p50-ms 75.95 ready_p95-ms 74.90 residual_p50-ms 75.95 residual_p95-ms 33760 signatures/block 450634 signatures/s 0.004738 submit_p50-ms 0.006292 submit_p95-ms 7023266 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/catchup-8 3 75787979 ns/op 2.041 avg_cpu_cores 1.000 components/block 154.7 cpu-ms/block 0.0003900 feed_lag_p50-ms 0.0005310 feed_lag_p95-ms 8.000 mean_width 75.44 ready_p50-ms 76.90 ready_p95-ms 75.44 residual_p50-ms 76.90 residual_p95-ms 33760 signatures/block 445453 signatures/s 0.006492 submit_p50-ms 0.006763 submit_p95-ms 7023258 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/catchup-8 3 83724900 ns/op 2.025 avg_cpu_cores 1.000 components/block 169.5 cpu-ms/block 0.0003300 feed_lag_p50-ms 0.0004310 feed_lag_p95-ms 8.000 mean_width 86.47 ready_p50-ms 87.41 ready_p95-ms 86.47 residual_p50-ms 87.41 residual_p95-ms 33760 signatures/block 403225 signatures/s 0.007554 submit_p50-ms 0.007595 submit_p95-ms 7023253 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_after_complete-8 3 275675193 ns/op 0.5545 avg_cpu_cores 126.0 components/block 152.9 cpu-ms/block 100.2 feed_lag_p50-ms 191.4 feed_lag_p95-ms 8.000 mean_width 175.6 ready_p50-ms 266.8 ready_p95-ms 75.25 residual_p50-ms 76.98 residual_p95-ms 33760 signatures/block 122463 signatures/s 0.01418 submit_p50-ms 0.01462 submit_p95-ms 7033472 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_after_complete-8 3 288578162 ns/op 0.6196 avg_cpu_cores 126.0 components/block 178.8 cpu-ms/block 100.2 feed_lag_p50-ms 191.4 feed_lag_p95-ms 8.000 mean_width 188.3 ready_p50-ms 279.5 ready_p95-ms 86.33 residual_p50-ms 98.29 residual_p95-ms 33760 signatures/block 116987 signatures/s 0.01635 submit_p50-ms 0.01759 submit_p95-ms 7033461 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_after_complete-8 3 275152604 ns/op 0.5544 avg_cpu_cores 126.0 components/block 152.5 cpu-ms/block 100.1 feed_lag_p50-ms 191.3 feed_lag_p95-ms 8.000 mean_width 175.0 ready_p50-ms 266.2 ready_p95-ms 75.23 residual_p50-ms 76.00 residual_p95-ms 33760 signatures/block 122696 signatures/s 0.01576 submit_p50-ms 0.01683 submit_p95-ms 7079245 B/op 67541 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_overlap-8 3 201070435 ns/op 0.8694 avg_cpu_cores 126.0 components/block 174.8 cpu-ms/block 0.4408 feed_lag_p50-ms 0.9889 feed_lag_p95-ms 7.912 mean_width 1.219 ready_p50-ms 1.939 ready_p95-ms 1.278 residual_p50-ms 1.368 residual_p95-ms 33760 signatures/block 167901 signatures/s 0.001523 submit_p50-ms 0.005731 submit_p95-ms 7175717 B/op 68921 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_overlap-8 3 201082624 ns/op 0.7981 avg_cpu_cores 126.0 components/block 160.5 cpu-ms/block 0.5138 feed_lag_p50-ms 1.002 feed_lag_p95-ms 7.912 mean_width 1.116 ready_p50-ms 1.674 ready_p95-ms 1.053 residual_p50-ms 1.128 residual_p95-ms 33760 signatures/block 167891 signatures/s 0.001002 submit_p50-ms 0.002716 submit_p95-ms 7175933 B/op 68923 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_overlap-8 3 201301027 ns/op 0.7960 avg_cpu_cores 126.0 components/block 160.2 cpu-ms/block 0.5253 feed_lag_p50-ms 0.9638 feed_lag_p95-ms 7.912 mean_width 1.160 ready_p50-ms 1.610 ready_p95-ms 1.264 residual_p50-ms 1.409 residual_p95-ms 33760 signatures/block 167709 signatures/s 0.001052 submit_p50-ms 0.002464 submit_p95-ms 7176285 B/op 68929 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/catchup-8 3 79099409 ns/op 3.964 avg_cpu_cores 1.000 components/block 313.6 cpu-ms/block 0.0002610 feed_lag_p50-ms 0.0008310 feed_lag_p95-ms 4.000 mean_width 76.63 ready_p50-ms 85.46 ready_p95-ms 76.63 residual_p50-ms 85.46 residual_p95-ms 33760 signatures/block 426805 signatures/s 0.006302 submit_p50-ms 0.006773 submit_p95-ms 7023410 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/catchup-8 3 80922132 ns/op 3.958 avg_cpu_cores 1.000 components/block 320.3 cpu-ms/block 0.0003000 feed_lag_p50-ms 0.0006520 feed_lag_p95-ms 4.000 mean_width 77.50 ready_p50-ms 87.97 ready_p95-ms 77.50 residual_p50-ms 87.97 residual_p95-ms 33760 signatures/block 417191 signatures/s 0.006211 submit_p50-ms 0.01736 submit_p95-ms 7023410 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/catchup-8 3 75579922 ns/op 4.026 avg_cpu_cores 1.000 components/block 304.3 cpu-ms/block 0.0003910 feed_lag_p50-ms 0.0004910 feed_lag_p95-ms 4.000 mean_width 75.53 ready_p50-ms 75.76 ready_p95-ms 75.53 residual_p50-ms 75.76 residual_p95-ms 33760 signatures/block 446679 signatures/s 0.004758 submit_p50-ms 0.005430 submit_p95-ms 7023405 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_after_complete-8 3 277358928 ns/op 1.110 avg_cpu_cores 126.0 components/block 307.9 cpu-ms/block 99.99 feed_lag_p50-ms 191.2 feed_lag_p95-ms 4.000 mean_width 176.8 ready_p50-ms 268.0 ready_p95-ms 76.98 residual_p50-ms 79.21 residual_p95-ms 33760 signatures/block 121720 signatures/s 0.01168 submit_p50-ms 0.01332 submit_p95-ms 7033597 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_after_complete-8 3 281786997 ns/op 1.134 avg_cpu_cores 126.0 components/block 319.5 cpu-ms/block 100.1 feed_lag_p50-ms 191.3 feed_lag_p95-ms 4.000 mean_width 181.5 ready_p50-ms 272.7 ready_p95-ms 77.53 residual_p50-ms 90.55 residual_p95-ms 33760 signatures/block 119807 signatures/s 0.01547 submit_p50-ms 0.01700 submit_p95-ms 7033605 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_after_complete-8 3 275851016 ns/op 1.100 avg_cpu_cores 126.0 components/block 303.6 cpu-ms/block 100.1 feed_lag_p50-ms 191.3 feed_lag_p95-ms 4.000 mean_width 175.8 ready_p50-ms 267.0 ready_p95-ms 75.74 residual_p50-ms 76.57 residual_p95-ms 33760 signatures/block 122385 signatures/s 0.01534 submit_p50-ms 0.01584 submit_p95-ms 7033605 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_overlap-8 3 200706590 ns/op 1.498 avg_cpu_cores 126.0 components/block 300.7 cpu-ms/block 0.5031 feed_lag_p50-ms 0.9977 feed_lag_p95-ms 3.956 mean_width 1.105 ready_p50-ms 1.659 ready_p95-ms 0.5523 residual_p50-ms 1.056 residual_p95-ms 33760 signatures/block 168206 signatures/s 0.001102 submit_p50-ms 0.003366 submit_p95-ms 7200192 B/op 68942 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_overlap-8 3 200821431 ns/op 1.836 avg_cpu_cores 126.0 components/block 368.8 cpu-ms/block 0.3622 feed_lag_p50-ms 1.002 feed_lag_p95-ms 3.956 mean_width 1.224 ready_p50-ms 2.145 ready_p95-ms 0.9866 residual_p50-ms 1.055 residual_p95-ms 33760 signatures/block 168110 signatures/s 0.002164 submit_p50-ms 0.004518 submit_p95-ms 7200909 B/op 68946 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_overlap-8 3 201025437 ns/op 1.586 avg_cpu_cores 126.0 components/block 318.8 cpu-ms/block 0.4136 feed_lag_p50-ms 0.9729 feed_lag_p95-ms 3.956 mean_width 1.214 ready_p50-ms 1.677 ready_p95-ms 1.053 residual_p50-ms 1.325 residual_p95-ms 33760 signatures/block 167939 signatures/s 0.001483 submit_p50-ms 0.004278 submit_p95-ms 7195901 B/op 68936 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/catchup-8 3 38632690 ns/op 4.029 avg_cpu_cores 1.000 components/block 155.7 cpu-ms/block 0.0001700 feed_lag_p50-ms 0.0004600 feed_lag_p95-ms 8.000 mean_width 38.50 ready_p50-ms 38.98 ready_p95-ms 38.50 residual_p50-ms 38.98 residual_p95-ms 33760 signatures/block 873871 signatures/s 0.004749 submit_p50-ms 0.004749 submit_p95-ms 7023658 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/catchup-8 3 38613093 ns/op 4.016 avg_cpu_cores 1.000 components/block 155.1 cpu-ms/block 0.0002600 feed_lag_p50-ms 0.0005910 feed_lag_p95-ms 8.000 mean_width 38.29 ready_p50-ms 39.67 ready_p95-ms 38.29 residual_p50-ms 39.67 residual_p95-ms 33760 signatures/block 874315 signatures/s 0.004198 submit_p50-ms 0.005150 submit_p95-ms 7023658 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/catchup-8 3 40094161 ns/op 3.977 avg_cpu_cores 1.000 components/block 159.5 cpu-ms/block 0.0002410 feed_lag_p50-ms 0.0003910 feed_lag_p95-ms 8.000 mean_width 40.29 ready_p50-ms 40.86 ready_p95-ms 40.29 residual_p50-ms 40.86 residual_p95-ms 33760 signatures/block 842018 signatures/s 0.004117 submit_p50-ms 0.004779 submit_p95-ms 7023653 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_after_complete-8 3 240210161 ns/op 0.6517 avg_cpu_cores 126.0 components/block 156.5 cpu-ms/block 100.2 feed_lag_p50-ms 191.4 feed_lag_p95-ms 8.000 mean_width 139.7 ready_p50-ms 230.9 ready_p95-ms 39.96 residual_p50-ms 41.70 residual_p95-ms 33760 signatures/block 140544 signatures/s 0.01466 submit_p50-ms 0.01629 submit_p95-ms 7033861 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_after_complete-8 3 244046162 ns/op 0.6703 avg_cpu_cores 126.0 components/block 163.6 cpu-ms/block 100.1 feed_lag_p50-ms 191.3 feed_lag_p95-ms 8.000 mean_width 143.7 ready_p50-ms 234.9 ready_p95-ms 41.63 residual_p50-ms 50.78 residual_p95-ms 33760 signatures/block 138334 signatures/s 0.01559 submit_p50-ms 0.1937 submit_p95-ms 7033853 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_after_complete-8 3 250358365 ns/op 0.7621 avg_cpu_cores 126.0 components/block 190.8 cpu-ms/block 100.1 feed_lag_p50-ms 191.3 feed_lag_p95-ms 8.000 mean_width 150.0 ready_p50-ms 241.2 ready_p95-ms 50.84 residual_p50-ms 52.16 residual_p95-ms 33760 signatures/block 134847 signatures/s 0.01572 submit_p50-ms 0.01687 submit_p95-ms 7033853 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_overlap-8 3 200893667 ns/op 0.8816 avg_cpu_cores 126.0 components/block 177.1 cpu-ms/block 0.4989 feed_lag_p50-ms 0.9857 feed_lag_p95-ms 7.912 mean_width 0.9093 ready_p50-ms 1.428 ready_p95-ms 0.8878 residual_p50-ms 1.069 residual_p95-ms 33760 signatures/block 168049 signatures/s 0.001713 submit_p50-ms 0.005570 submit_p95-ms 7225490 B/op 68918 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_overlap-8 3 201019836 ns/op 0.8626 avg_cpu_cores 126.0 components/block 173.4 cpu-ms/block 0.5209 feed_lag_p50-ms 1.002 feed_lag_p95-ms 7.912 mean_width 0.9120 ready_p50-ms 1.381 ready_p95-ms 1.081 residual_p50-ms 1.125 residual_p95-ms 33760 signatures/block 167944 signatures/s 0.001563 submit_p50-ms 0.004458 submit_p95-ms 7226130 B/op 68919 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_overlap-8 3 200749032 ns/op 0.8810 avg_cpu_cores 126.0 components/block 176.9 cpu-ms/block 0.5054 feed_lag_p50-ms 0.9943 feed_lag_p95-ms 7.912 mean_width 0.9516 ready_p50-ms 1.431 ready_p95-ms 0.5820 residual_p50-ms 1.073 residual_p95-ms 33760 signatures/block 168170 signatures/s 0.001633 submit_p50-ms 0.005690 submit_p95-ms 7226581 B/op 68928 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/catchup-8 3 155918266 ns/op 2.038 avg_cpu_cores 1.000 components/block 317.8 cpu-ms/block 0.0004010 feed_lag_p50-ms 0.0004910 feed_lag_p95-ms 4.000 mean_width 156.2 ready_p50-ms 157.5 ready_p95-ms 156.2 residual_p50-ms 157.5 residual_p95-ms 33760 signatures/block 216524 signatures/s 0.007043 submit_p50-ms 0.007063 submit_p95-ms 7023138 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/catchup-8 3 144724837 ns/op 2.047 avg_cpu_cores 1.000 components/block 296.2 cpu-ms/block 0.0002410 feed_lag_p50-ms 0.0004610 feed_lag_p95-ms 4.000 mean_width 144.7 ready_p50-ms 145.3 ready_p95-ms 144.7 residual_p50-ms 145.3 residual_p95-ms 33760 signatures/block 233270 signatures/s 0.004688 submit_p50-ms 0.006221 submit_p95-ms 7023133 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/catchup-8 3 167371225 ns/op 2.049 avg_cpu_cores 1.000 components/block 343.0 cpu-ms/block 0.0002700 feed_lag_p50-ms 0.0007810 feed_lag_p95-ms 4.000 mean_width 168.7 ready_p50-ms 179.5 ready_p95-ms 168.7 residual_p50-ms 179.5 residual_p95-ms 33760 signatures/block 201707 signatures/s 0.005831 submit_p50-ms 0.006833 submit_p95-ms 7023133 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/tip_200ms_after_complete-8 3 348985373 ns/op 0.8724 avg_cpu_cores 126.0 components/block 304.4 cpu-ms/block 100.1 feed_lag_p50-ms 191.3 feed_lag_p95-ms 4.000 mean_width 248.9 ready_p50-ms 340.1 ready_p95-ms 150.1 residual_p50-ms 152.0 residual_p95-ms 33760 signatures/block 96738 signatures/s 0.01628 submit_p50-ms 0.01804 submit_p95-ms 7033333 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/tip_200ms_after_complete-8 3 353413098 ns/op 0.8855 avg_cpu_cores 126.0 components/block 312.9 cpu-ms/block 100.1 feed_lag_p50-ms 191.3 feed_lag_p95-ms 4.000 mean_width 253.3 ready_p50-ms 344.5 ready_p95-ms 155.7 residual_p50-ms 158.2 residual_p95-ms 33760 signatures/block 95526 signatures/s 0.02336 submit_p50-ms 0.03805 submit_p95-ms 7079125 B/op 67541 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/tip_200ms_after_complete-8 3 349811570 ns/op 0.8763 avg_cpu_cores 126.0 components/block 306.6 cpu-ms/block 99.80 feed_lag_p50-ms 191.0 feed_lag_p95-ms 4.000 mean_width 249.2 ready_p50-ms 340.4 ready_p95-ms 151.6 residual_p50-ms 153.0 residual_p95-ms 33760 signatures/block 96509 signatures/s 0.01705 submit_p50-ms 0.01774 submit_p95-ms 7033333 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/tip_200ms_overlap-8 3 200998043 ns/op 1.604 avg_cpu_cores 126.0 components/block 322.3 cpu-ms/block 0.03342 feed_lag_p50-ms 0.8444 feed_lag_p95-ms 3.956 mean_width 1.732 ready_p50-ms 3.310 ready_p95-ms 0.7673 residual_p50-ms 1.469 residual_p95-ms 33760 signatures/block 167962 signatures/s 0.001633 submit_p50-ms 0.004388 submit_p95-ms 7159493 B/op 68923 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/tip_200ms_overlap-8 3 200881915 ns/op 1.491 avg_cpu_cores 126.0 components/block 299.4 cpu-ms/block 0.2175 feed_lag_p50-ms 0.8653 feed_lag_p95-ms 3.956 mean_width 1.578 ready_p50-ms 2.468 ready_p95-ms 0.9112 residual_p50-ms 1.054 residual_p95-ms 33760 signatures/block 168059 signatures/s 0.001072 submit_p50-ms 0.002876 submit_p95-ms 7159410 B/op 68922 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/tip_200ms_overlap-8 3 200919959 ns/op 1.509 avg_cpu_cores 126.0 components/block 303.1 cpu-ms/block 0.04134 feed_lag_p50-ms 0.8647 feed_lag_p95-ms 3.956 mean_width 1.588 ready_p50-ms 2.515 ready_p95-ms 0.6775 residual_p50-ms 1.408 residual_p95-ms 33760 signatures/block 168027 signatures/s 0.001152 submit_p50-ms 0.002685 submit_p95-ms 7160456 B/op 68931 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/catchup-8 3 78536665 ns/op 2.043 avg_cpu_cores 1.000 components/block 160.4 cpu-ms/block 0.0002010 feed_lag_p50-ms 0.001353 feed_lag_p95-ms 8.000 mean_width 76.40 ready_p50-ms 84.11 ready_p95-ms 76.40 residual_p50-ms 84.11 residual_p95-ms 33760 signatures/block 429863 signatures/s 0.005971 submit_p50-ms 0.01674 submit_p95-ms 7023253 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/catchup-8 3 74931420 ns/op 2.045 avg_cpu_cores 1.000 components/block 153.2 cpu-ms/block 0.0002610 feed_lag_p50-ms 0.0004910 feed_lag_p95-ms 8.000 mean_width 73.86 ready_p50-ms 77.19 ready_p95-ms 73.86 residual_p50-ms 77.19 residual_p95-ms 33760 signatures/block 450545 signatures/s 0.005530 submit_p50-ms 0.005611 submit_p95-ms 7069050 B/op 67540 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/catchup-8 3 74095918 ns/op 2.048 avg_cpu_cores 1.000 components/block 151.7 cpu-ms/block 0.0002610 feed_lag_p50-ms 0.0005510 feed_lag_p95-ms 8.000 mean_width 74.05 ready_p50-ms 74.35 ready_p95-ms 74.05 residual_p50-ms 74.35 residual_p95-ms 33760 signatures/block 455626 signatures/s 0.005040 submit_p50-ms 0.005761 submit_p95-ms 7023266 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/tip_200ms_after_complete-8 3 276093363 ns/op 0.5578 avg_cpu_cores 126.0 components/block 154.0 cpu-ms/block 100.1 feed_lag_p50-ms 191.3 feed_lag_p95-ms 8.000 mean_width 176.0 ready_p50-ms 267.2 ready_p95-ms 75.77 residual_p50-ms 77.27 residual_p95-ms 33760 signatures/block 122277 signatures/s 0.01560 submit_p50-ms 0.01629 submit_p95-ms 7033453 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/tip_200ms_after_complete-8 3 275962471 ns/op 0.5557 avg_cpu_cores 126.0 components/block 153.3 cpu-ms/block 100.2 feed_lag_p50-ms 191.4 feed_lag_p95-ms 8.000 mean_width 175.6 ready_p50-ms 266.8 ready_p95-ms 75.18 residual_p50-ms 77.82 residual_p95-ms 33760 signatures/block 122335 signatures/s 0.01006 submit_p50-ms 0.01518 submit_p95-ms 7033461 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/tip_200ms_after_complete-8 3 276459279 ns/op 0.5617 avg_cpu_cores 126.0 components/block 155.3 cpu-ms/block 99.96 feed_lag_p50-ms 191.2 feed_lag_p95-ms 8.000 mean_width 176.3 ready_p50-ms 267.5 ready_p95-ms 76.20 residual_p50-ms 77.62 residual_p95-ms 33760 signatures/block 122116 signatures/s 0.01565 submit_p50-ms 0.02936 submit_p95-ms 7033461 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/tip_200ms_overlap-8 3 201053633 ns/op 0.7943 avg_cpu_cores 126.0 components/block 159.7 cpu-ms/block 0.5123 feed_lag_p50-ms 0.9677 feed_lag_p95-ms 7.912 mean_width 1.131 ready_p50-ms 1.609 ready_p95-ms 1.133 residual_p50-ms 1.338 residual_p95-ms 33760 signatures/block 167915 signatures/s 0.0009820 submit_p50-ms 0.002364 submit_p95-ms 7175658 B/op 68923 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/tip_200ms_overlap-8 3 200775689 ns/op 0.8035 avg_cpu_cores 126.0 components/block 161.3 cpu-ms/block 0.4791 feed_lag_p50-ms 0.9798 feed_lag_p95-ms 7.912 mean_width 1.141 ready_p50-ms 1.630 ready_p95-ms 0.8427 residual_p50-ms 1.052 residual_p95-ms 33760 signatures/block 168148 signatures/s 0.001102 submit_p50-ms 0.002976 submit_p95-ms 7179669 B/op 68929 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/tip_200ms_overlap-8 3 200811376 ns/op 0.8110 avg_cpu_cores 126.0 components/block 162.9 cpu-ms/block 0.5077 feed_lag_p50-ms 0.9730 feed_lag_p95-ms 7.912 mean_width 1.170 ready_p50-ms 1.645 ready_p95-ms 0.6530 residual_p50-ms 1.185 residual_p95-ms 33760 signatures/block 168118 signatures/s 0.001042 submit_p50-ms 0.003306 submit_p95-ms 7175690 B/op 68923 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/catchup-8 3 75328778 ns/op 4.020 avg_cpu_cores 1.000 components/block 302.8 cpu-ms/block 0.0002010 feed_lag_p50-ms 0.0004810 feed_lag_p95-ms 4.000 mean_width 75.78 ready_p50-ms 75.98 ready_p95-ms 75.78 residual_p50-ms 75.98 residual_p95-ms 33760 signatures/block 448169 signatures/s 0.005461 submit_p50-ms 0.006863 submit_p95-ms 7023397 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/catchup-8 3 75774293 ns/op 4.044 avg_cpu_cores 1.000 components/block 306.4 cpu-ms/block 0.0004800 feed_lag_p50-ms 0.0004810 feed_lag_p95-ms 4.000 mean_width 76.23 ready_p50-ms 76.72 ready_p95-ms 76.23 residual_p50-ms 76.72 residual_p95-ms 33760 signatures/block 445534 signatures/s 0.005711 submit_p50-ms 0.006102 submit_p95-ms 7023402 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/catchup-8 3 78168545 ns/op 3.951 avg_cpu_cores 1.000 components/block 308.8 cpu-ms/block 0.0002400 feed_lag_p50-ms 0.0005810 feed_lag_p95-ms 4.000 mean_width 77.58 ready_p50-ms 80.96 ready_p95-ms 77.58 residual_p50-ms 80.96 residual_p95-ms 33760 signatures/block 431887 signatures/s 0.004168 submit_p50-ms 0.005010 submit_p95-ms 7023397 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/tip_200ms_after_complete-8 3 275602430 ns/op 1.092 avg_cpu_cores 126.0 components/block 301.1 cpu-ms/block 100.2 feed_lag_p50-ms 191.4 feed_lag_p95-ms 4.000 mean_width 175.7 ready_p50-ms 266.9 ready_p95-ms 75.17 residual_p50-ms 76.46 residual_p95-ms 33760 signatures/block 122495 signatures/s 0.01314 submit_p50-ms 0.01613 submit_p95-ms 7033605 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/tip_200ms_after_complete-8 3 279023273 ns/op 1.120 avg_cpu_cores 126.0 components/block 312.5 cpu-ms/block 100.2 feed_lag_p50-ms 191.4 feed_lag_p95-ms 4.000 mean_width 178.6 ready_p50-ms 269.8 ready_p95-ms 74.63 residual_p50-ms 88.00 residual_p95-ms 33760 signatures/block 120993 signatures/s 0.01526 submit_p50-ms 0.01800 submit_p95-ms 7033597 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/tip_200ms_after_complete-8 3 274951714 ns/op 1.090 avg_cpu_cores 126.0 components/block 299.7 cpu-ms/block 100.2 feed_lag_p50-ms 191.4 feed_lag_p95-ms 4.000 mean_width 174.6 ready_p50-ms 265.8 ready_p95-ms 74.09 residual_p50-ms 76.92 residual_p95-ms 33760 signatures/block 122785 signatures/s 0.01396 submit_p50-ms 0.01562 submit_p95-ms 7033605 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/tip_200ms_overlap-8 3 201098547 ns/op 1.493 avg_cpu_cores 126.0 components/block 300.2 cpu-ms/block 0.5184 feed_lag_p50-ms 0.9810 feed_lag_p95-ms 3.956 mean_width 1.117 ready_p50-ms 1.603 ready_p95-ms 1.053 residual_p50-ms 1.298 residual_p95-ms 33760 signatures/block 167878 signatures/s 0.001042 submit_p50-ms 0.002425 submit_p95-ms 7193832 B/op 68923 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/tip_200ms_overlap-8 3 200804503 ns/op 1.504 avg_cpu_cores 126.0 components/block 302.0 cpu-ms/block 0.4528 feed_lag_p50-ms 0.9812 feed_lag_p95-ms 3.956 mean_width 1.073 ready_p50-ms 1.596 ready_p95-ms 0.6861 residual_p50-ms 1.062 residual_p95-ms 33760 signatures/block 168124 signatures/s 0.001172 submit_p50-ms 0.003016 submit_p95-ms 7193242 B/op 68918 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/tip_200ms_overlap-8 3 201170435 ns/op 1.496 avg_cpu_cores 126.0 components/block 300.9 cpu-ms/block 0.5088 feed_lag_p50-ms 0.9289 feed_lag_p95-ms 3.956 mean_width 1.085 ready_p50-ms 1.534 ready_p95-ms 1.085 residual_p50-ms 1.335 residual_p95-ms 33760 signatures/block 167818 signatures/s 0.001072 submit_p50-ms 0.002414 submit_p95-ms 7193242 B/op 68918 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/catchup-8 3 39479657 ns/op 3.975 avg_cpu_cores 1.000 components/block 157.0 cpu-ms/block 0.0002710 feed_lag_p50-ms 0.0004810 feed_lag_p95-ms 8.000 mean_width 39.13 ready_p50-ms 41.02 ready_p95-ms 39.13 residual_p50-ms 41.02 residual_p95-ms 33760 signatures/block 855124 signatures/s 0.007464 submit_p50-ms 0.008786 submit_p95-ms 7023658 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/catchup-8 3 38341975 ns/op 4.014 avg_cpu_cores 1.000 components/block 153.9 cpu-ms/block 0.0005810 feed_lag_p50-ms 0.0006410 feed_lag_p95-ms 8.000 mean_width 38.31 ready_p50-ms 38.39 ready_p95-ms 38.31 residual_p50-ms 38.39 residual_p95-ms 33760 signatures/block 880497 signatures/s 0.004508 submit_p50-ms 0.004959 submit_p95-ms 7023666 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/catchup-8 3 39294804 ns/op 4.040 avg_cpu_cores 1.000 components/block 158.7 cpu-ms/block 0.0003910 feed_lag_p50-ms 0.0005510 feed_lag_p95-ms 8.000 mean_width 39.31 ready_p50-ms 39.43 ready_p95-ms 39.31 residual_p50-ms 39.43 residual_p95-ms 33760 signatures/block 859147 signatures/s 0.005029 submit_p50-ms 0.005861 submit_p95-ms 7023658 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/tip_200ms_after_complete-8 3 241004536 ns/op 0.6672 avg_cpu_cores 126.0 components/block 160.8 cpu-ms/block 100.1 feed_lag_p50-ms 191.3 feed_lag_p95-ms 8.000 mean_width 141.0 ready_p50-ms 232.2 ready_p95-ms 40.60 residual_p50-ms 43.41 residual_p95-ms 33760 signatures/block 140080 signatures/s 0.01375 submit_p50-ms 0.01582 submit_p95-ms 7033853 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/tip_200ms_after_complete-8 3 240866782 ns/op 0.6463 avg_cpu_cores 126.0 components/block 155.7 cpu-ms/block 100.2 feed_lag_p50-ms 191.4 feed_lag_p95-ms 8.000 mean_width 140.6 ready_p50-ms 231.8 ready_p95-ms 41.37 residual_p50-ms 41.44 residual_p95-ms 33760 signatures/block 140160 signatures/s 0.01499 submit_p50-ms 0.01555 submit_p95-ms 7033853 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/tip_200ms_after_complete-8 3 245990041 ns/op 0.7043 avg_cpu_cores 126.0 components/block 173.2 cpu-ms/block 99.92 feed_lag_p50-ms 191.1 feed_lag_p95-ms 8.000 mean_width 145.8 ready_p50-ms 237.0 ready_p95-ms 46.04 residual_p50-ms 51.40 residual_p95-ms 33760 signatures/block 137241 signatures/s 0.01647 submit_p50-ms 0.01882 submit_p95-ms 7033853 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/tip_200ms_overlap-8 3 200623083 ns/op 0.9263 avg_cpu_cores 126.0 components/block 185.8 cpu-ms/block 0.5196 feed_lag_p50-ms 1.002 feed_lag_p95-ms 7.912 mean_width 0.9626 ready_p50-ms 1.463 ready_p95-ms 0.6115 residual_p50-ms 0.9216 residual_p95-ms 33760 signatures/block 168276 signatures/s 0.001794 submit_p50-ms 0.004097 submit_p95-ms 7226498 B/op 68927 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/tip_200ms_overlap-8 3 200897397 ns/op 0.8262 avg_cpu_cores 126.0 components/block 166.0 cpu-ms/block 0.5245 feed_lag_p50-ms 1.013 feed_lag_p95-ms 7.912 mean_width 0.9103 ready_p50-ms 1.390 ready_p95-ms 1.083 residual_p50-ms 1.198 residual_p95-ms 33760 signatures/block 168046 signatures/s 0.001183 submit_p50-ms 0.003416 submit_p95-ms 7225789 B/op 68921 allocs/op +BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/tip_200ms_overlap-8 3 200745122 ns/op 0.8122 avg_cpu_cores 126.0 components/block 163.0 cpu-ms/block 0.5160 feed_lag_p50-ms 0.9821 feed_lag_p95-ms 7.912 mean_width 0.8819 ready_p50-ms 1.329 ready_p95-ms 0.6724 residual_p50-ms 1.132 residual_p95-ms 33760 signatures/block 168173 signatures/s 0.001112 submit_p50-ms 0.002685 submit_p95-ms 7225640 B/op 68919 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/catchup-8 3 143957884 ns/op 2.052 avg_cpu_cores 1.000 components/block 295.4 cpu-ms/block 0.0002410 feed_lag_p50-ms 0.0004910 feed_lag_p95-ms 4.000 mean_width 144.0 ready_p50-ms 144.7 ready_p95-ms 144.0 residual_p50-ms 144.7 residual_p95-ms 33760 signatures/block 234513 signatures/s 0.005019 submit_p50-ms 0.006172 submit_p95-ms 7023133 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/catchup-8 3 155693549 ns/op 2.032 avg_cpu_cores 1.000 components/block 316.4 cpu-ms/block 0.0003000 feed_lag_p50-ms 0.0003110 feed_lag_p95-ms 4.000 mean_width 158.7 ready_p50-ms 162.0 ready_p95-ms 158.7 residual_p50-ms 162.0 residual_p95-ms 33760 signatures/block 216836 signatures/s 0.004819 submit_p50-ms 0.007064 submit_p95-ms 7023125 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/catchup-8 3 175713321 ns/op 2.044 avg_cpu_cores 1.000 components/block 359.1 cpu-ms/block 0.0002110 feed_lag_p50-ms 0.0004810 feed_lag_p95-ms 4.000 mean_width 175.6 ready_p50-ms 178.9 ready_p95-ms 175.6 residual_p50-ms 178.9 residual_p95-ms 33760 signatures/block 192131 signatures/s 0.005420 submit_p50-ms 0.006953 submit_p95-ms 7023141 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/tip_200ms_after_complete-8 3 346489723 ns/op 0.8637 avg_cpu_cores 126.0 components/block 299.3 cpu-ms/block 99.82 feed_lag_p50-ms 191.0 feed_lag_p95-ms 4.000 mean_width 246.5 ready_p50-ms 337.7 ready_p95-ms 145.9 residual_p50-ms 147.9 residual_p95-ms 33760 signatures/block 97434 signatures/s 0.01410 submit_p50-ms 0.02031 submit_p95-ms 7033333 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/tip_200ms_after_complete-8 3 345618207 ns/op 0.8597 avg_cpu_cores 126.0 components/block 297.1 cpu-ms/block 99.96 feed_lag_p50-ms 191.2 feed_lag_p95-ms 4.000 mean_width 245.1 ready_p50-ms 336.3 ready_p95-ms 145.9 residual_p50-ms 145.9 residual_p95-ms 33760 signatures/block 97680 signatures/s 0.01199 submit_p50-ms 0.01378 submit_p95-ms 7033333 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/tip_200ms_after_complete-8 3 371354060 ns/op 0.9267 avg_cpu_cores 126.0 components/block 344.1 cpu-ms/block 99.54 feed_lag_p50-ms 190.7 feed_lag_p95-ms 4.000 mean_width 271.4 ready_p50-ms 362.6 ready_p95-ms 172.2 residual_p50-ms 177.1 residual_p95-ms 33760 signatures/block 90911 signatures/s 0.01910 submit_p50-ms 0.02254 submit_p95-ms 7033333 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/tip_200ms_overlap-8 3 201052815 ns/op 1.483 avg_cpu_cores 126.0 components/block 298.1 cpu-ms/block 0.2236 feed_lag_p50-ms 0.8478 feed_lag_p95-ms 3.956 mean_width 1.585 ready_p50-ms 2.432 ready_p95-ms 0.9514 residual_p50-ms 1.353 residual_p95-ms 33760 signatures/block 167916 signatures/s 0.0009520 submit_p50-ms 0.002114 submit_p95-ms 7161128 B/op 68937 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/tip_200ms_overlap-8 3 200977968 ns/op 1.811 avg_cpu_cores 126.0 components/block 363.9 cpu-ms/block 0.02301 feed_lag_p50-ms 0.7957 feed_lag_p95-ms 3.956 mean_width 1.998 ready_p50-ms 3.094 ready_p95-ms 0.8770 residual_p50-ms 1.215 residual_p95-ms 33760 signatures/block 167979 signatures/s 0.002054 submit_p50-ms 0.004097 submit_p95-ms 7159746 B/op 68925 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/tip_200ms_overlap-8 3 201118531 ns/op 1.488 avg_cpu_cores 126.0 components/block 299.2 cpu-ms/block 0.2092 feed_lag_p50-ms 0.8745 feed_lag_p95-ms 3.956 mean_width 1.589 ready_p50-ms 2.484 ready_p95-ms 1.204 residual_p50-ms 1.456 residual_p95-ms 33760 signatures/block 167861 signatures/s 0.001001 submit_p50-ms 0.002295 submit_p95-ms 7160709 B/op 68934 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/catchup-8 3 79597279 ns/op 2.042 avg_cpu_cores 1.000 components/block 162.5 cpu-ms/block 0.0002600 feed_lag_p50-ms 0.0004710 feed_lag_p95-ms 8.000 mean_width 81.98 ready_p50-ms 82.10 ready_p95-ms 81.98 residual_p50-ms 82.10 residual_p95-ms 33760 signatures/block 424135 signatures/s 0.005170 submit_p50-ms 0.006362 submit_p95-ms 7023253 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/catchup-8 3 92160738 ns/op 2.042 avg_cpu_cores 1.000 components/block 188.1 cpu-ms/block 0.0005010 feed_lag_p50-ms 0.0005710 feed_lag_p95-ms 8.000 mean_width 91.84 ready_p50-ms 96.76 ready_p95-ms 91.84 residual_p50-ms 96.76 residual_p95-ms 33760 signatures/block 366317 signatures/s 0.007174 submit_p50-ms 0.008115 submit_p95-ms 7023266 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/catchup-8 3 77785688 ns/op 2.040 avg_cpu_cores 1.000 components/block 158.7 cpu-ms/block 0.0002110 feed_lag_p50-ms 0.0008720 feed_lag_p95-ms 8.000 mean_width 76.89 ready_p50-ms 81.28 ready_p95-ms 76.89 residual_p50-ms 81.28 residual_p95-ms 33760 signatures/block 434013 signatures/s 0.005009 submit_p50-ms 0.006552 submit_p95-ms 7023261 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/tip_200ms_after_complete-8 3 279921937 ns/op 0.5736 avg_cpu_cores 126.0 components/block 160.6 cpu-ms/block 100.1 feed_lag_p50-ms 191.3 feed_lag_p95-ms 8.000 mean_width 179.3 ready_p50-ms 270.5 ready_p95-ms 76.93 residual_p50-ms 87.45 residual_p95-ms 33760 signatures/block 120605 signatures/s 0.01510 submit_p50-ms 0.01745 submit_p95-ms 7033453 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/tip_200ms_after_complete-8 3 280609110 ns/op 0.5790 avg_cpu_cores 126.0 components/block 162.5 cpu-ms/block 100.8 feed_lag_p50-ms 192.0 feed_lag_p95-ms 8.000 mean_width 180.0 ready_p50-ms 271.2 ready_p95-ms 80.28 residual_p50-ms 85.53 residual_p95-ms 33760 signatures/block 120310 signatures/s 0.01629 submit_p50-ms 0.05750 submit_p95-ms 7079253 B/op 67541 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/tip_200ms_after_complete-8 3 275007675 ns/op 0.5550 avg_cpu_cores 126.0 components/block 152.6 cpu-ms/block 100.1 feed_lag_p50-ms 191.3 feed_lag_p95-ms 8.000 mean_width 174.7 ready_p50-ms 265.9 ready_p95-ms 75.43 residual_p50-ms 75.48 residual_p95-ms 33760 signatures/block 122760 signatures/s 0.01441 submit_p50-ms 0.01488 submit_p95-ms 7033474 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/tip_200ms_overlap-8 3 200553309 ns/op 0.8722 avg_cpu_cores 126.0 components/block 174.9 cpu-ms/block 0.4164 feed_lag_p50-ms 0.9441 feed_lag_p95-ms 7.912 mean_width 1.193 ready_p50-ms 1.708 ready_p95-ms 0.5627 residual_p50-ms 0.5720 residual_p95-ms 33760 signatures/block 168334 signatures/s 0.001743 submit_p50-ms 0.004909 submit_p95-ms 7175850 B/op 68920 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/tip_200ms_overlap-8 3 201115062 ns/op 0.8365 avg_cpu_cores 126.0 components/block 168.2 cpu-ms/block 0.4905 feed_lag_p50-ms 0.9819 feed_lag_p95-ms 7.912 mean_width 1.142 ready_p50-ms 1.804 ready_p95-ms 1.348 residual_p50-ms 1.353 residual_p95-ms 33760 signatures/block 167864 signatures/s 0.001302 submit_p50-ms 0.003086 submit_p95-ms 7175330 B/op 68920 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/tip_200ms_overlap-8 3 200875209 ns/op 0.9083 avg_cpu_cores 126.0 components/block 182.5 cpu-ms/block 0.4053 feed_lag_p50-ms 0.9401 feed_lag_p95-ms 7.912 mean_width 1.210 ready_p50-ms 1.734 ready_p95-ms 0.7018 residual_p50-ms 1.361 residual_p95-ms 33760 signatures/block 168065 signatures/s 0.001733 submit_p50-ms 0.004358 submit_p95-ms 7176061 B/op 68927 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/catchup-8 3 84397967 ns/op 3.886 avg_cpu_cores 1.000 components/block 328.0 cpu-ms/block 0.0002700 feed_lag_p50-ms 0.0006510 feed_lag_p95-ms 4.000 mean_width 80.13 ready_p50-ms 96.48 ready_p95-ms 80.13 residual_p50-ms 96.48 residual_p95-ms 33760 signatures/block 400010 signatures/s 0.004749 submit_p50-ms 0.008185 submit_p95-ms 7023397 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/catchup-8 3 84545510 ns/op 3.891 avg_cpu_cores 1.000 components/block 328.9 cpu-ms/block 0.0002200 feed_lag_p50-ms 0.0007220 feed_lag_p95-ms 4.000 mean_width 81.04 ready_p50-ms 94.42 ready_p95-ms 81.04 residual_p50-ms 94.42 residual_p95-ms 33760 signatures/block 399312 signatures/s 0.007054 submit_p50-ms 0.007925 submit_p95-ms 7023402 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/catchup-8 3 77376355 ns/op 3.992 avg_cpu_cores 1.000 components/block 308.9 cpu-ms/block 0.0002100 feed_lag_p50-ms 0.0006110 feed_lag_p95-ms 4.000 mean_width 76.57 ready_p50-ms 79.75 ready_p95-ms 76.57 residual_p50-ms 79.75 residual_p95-ms 33760 signatures/block 436309 signatures/s 0.01021 submit_p50-ms 0.01104 submit_p95-ms 7023402 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/tip_200ms_after_complete-8 3 276775942 ns/op 1.101 avg_cpu_cores 126.0 components/block 304.8 cpu-ms/block 100.1 feed_lag_p50-ms 191.3 feed_lag_p95-ms 4.000 mean_width 176.7 ready_p50-ms 267.9 ready_p95-ms 76.69 residual_p50-ms 77.72 residual_p95-ms 33760 signatures/block 121976 signatures/s 0.01302 submit_p50-ms 0.01303 submit_p95-ms 7033605 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/tip_200ms_after_complete-8 3 286266781 ns/op 1.147 avg_cpu_cores 126.0 components/block 328.2 cpu-ms/block 100.1 feed_lag_p50-ms 191.3 feed_lag_p95-ms 4.000 mean_width 186.0 ready_p50-ms 277.2 ready_p95-ms 88.39 residual_p50-ms 92.31 residual_p95-ms 33760 signatures/block 117932 signatures/s 0.01630 submit_p50-ms 0.03380 submit_p95-ms 7033597 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/tip_200ms_after_complete-8 3 280082230 ns/op 1.127 avg_cpu_cores 126.0 components/block 315.7 cpu-ms/block 100.1 feed_lag_p50-ms 191.3 feed_lag_p95-ms 4.000 mean_width 180.2 ready_p50-ms 271.4 ready_p95-ms 81.38 residual_p50-ms 82.65 residual_p95-ms 33760 signatures/block 120536 signatures/s 0.01659 submit_p50-ms 0.02034 submit_p95-ms 7033605 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/tip_200ms_overlap-8 3 200915755 ns/op 1.500 avg_cpu_cores 126.0 components/block 301.4 cpu-ms/block 0.5144 feed_lag_p50-ms 0.9691 feed_lag_p95-ms 3.956 mean_width 1.113 ready_p50-ms 1.588 ready_p95-ms 0.9998 residual_p50-ms 1.239 residual_p95-ms 33760 signatures/block 168031 signatures/s 0.001022 submit_p50-ms 0.002404 submit_p95-ms 7193234 B/op 68918 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/tip_200ms_overlap-8 3 200718712 ns/op 1.523 avg_cpu_cores 126.0 components/block 305.7 cpu-ms/block 0.4580 feed_lag_p50-ms 0.9962 feed_lag_p95-ms 3.956 mean_width 1.154 ready_p50-ms 1.675 ready_p95-ms 0.4901 residual_p50-ms 1.164 residual_p95-ms 33760 signatures/block 168196 signatures/s 0.001242 submit_p50-ms 0.002976 submit_p95-ms 7194797 B/op 68932 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/tip_200ms_overlap-8 3 200572819 ns/op 1.531 avg_cpu_cores 126.0 components/block 307.1 cpu-ms/block 0.4611 feed_lag_p50-ms 0.9844 feed_lag_p95-ms 3.956 mean_width 1.135 ready_p50-ms 1.701 ready_p95-ms 0.6289 residual_p50-ms 0.6701 residual_p95-ms 33760 signatures/block 168318 signatures/s 0.001202 submit_p50-ms 0.003256 submit_p95-ms 7193720 B/op 68922 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/catchup-8 3 39509312 ns/op 4.011 avg_cpu_cores 1.000 components/block 158.5 cpu-ms/block 0.0002500 feed_lag_p50-ms 0.0004110 feed_lag_p95-ms 8.000 mean_width 39.88 ready_p50-ms 40.18 ready_p95-ms 39.88 residual_p50-ms 40.18 residual_p95-ms 33760 signatures/block 854482 signatures/s 0.004759 submit_p50-ms 0.005010 submit_p95-ms 7023658 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/catchup-8 3 44691175 ns/op 3.832 avg_cpu_cores 1.000 components/block 171.2 cpu-ms/block 0.0005010 feed_lag_p50-ms 0.0007710 feed_lag_p95-ms 8.000 mean_width 42.16 ready_p50-ms 52.97 ready_p95-ms 42.16 residual_p50-ms 52.97 residual_p95-ms 33760 signatures/block 755406 signatures/s 0.005119 submit_p50-ms 0.008055 submit_p95-ms 7023653 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/catchup-8 3 44816763 ns/op 3.923 avg_cpu_cores 1.000 components/block 175.8 cpu-ms/block 0.0003010 feed_lag_p50-ms 0.0004810 feed_lag_p95-ms 8.000 mean_width 42.65 ready_p50-ms 51.93 ready_p95-ms 42.65 residual_p50-ms 51.93 residual_p95-ms 33760 signatures/block 753290 signatures/s 0.003908 submit_p50-ms 0.006643 submit_p95-ms 7023653 B/op 67538 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/tip_200ms_after_complete-8 3 242531854 ns/op 0.6854 avg_cpu_cores 126.0 components/block 166.2 cpu-ms/block 99.89 feed_lag_p50-ms 191.1 feed_lag_p95-ms 8.000 mean_width 142.2 ready_p50-ms 233.4 ready_p95-ms 41.44 residual_p50-ms 44.73 residual_p95-ms 33760 signatures/block 139198 signatures/s 0.01571 submit_p50-ms 0.01829 submit_p95-ms 7033861 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/tip_200ms_after_complete-8 3 239652146 ns/op 0.6493 avg_cpu_cores 126.0 components/block 155.6 cpu-ms/block 100.2 feed_lag_p50-ms 191.4 feed_lag_p95-ms 8.000 mean_width 139.2 ready_p50-ms 230.4 ready_p95-ms 39.49 residual_p50-ms 40.03 residual_p95-ms 33760 signatures/block 140871 signatures/s 0.01441 submit_p50-ms 0.01704 submit_p95-ms 7033861 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/tip_200ms_after_complete-8 3 240787126 ns/op 0.6555 avg_cpu_cores 126.0 components/block 157.8 cpu-ms/block 100.2 feed_lag_p50-ms 191.4 feed_lag_p95-ms 8.000 mean_width 140.6 ready_p50-ms 231.8 ready_p95-ms 40.74 residual_p50-ms 41.39 residual_p95-ms 33760 signatures/block 140207 signatures/s 0.01393 submit_p50-ms 0.01417 submit_p95-ms 7033861 B/op 67539 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/tip_200ms_overlap-8 3 200949184 ns/op 0.9006 avg_cpu_cores 126.0 components/block 181.0 cpu-ms/block 0.4993 feed_lag_p50-ms 0.9768 feed_lag_p95-ms 7.912 mean_width 0.9266 ready_p50-ms 1.401 ready_p95-ms 1.066 residual_p50-ms 1.141 residual_p95-ms 33760 signatures/block 168003 signatures/s 0.001683 submit_p50-ms 0.006322 submit_p95-ms 7225536 B/op 68919 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/tip_200ms_overlap-8 3 200864502 ns/op 0.8069 avg_cpu_cores 126.0 components/block 162.1 cpu-ms/block 0.5202 feed_lag_p50-ms 1.012 feed_lag_p95-ms 7.912 mean_width 0.8813 ready_p50-ms 1.380 ready_p95-ms 1.090 residual_p50-ms 1.206 residual_p95-ms 33760 signatures/block 168074 signatures/s 0.001102 submit_p50-ms 0.002535 submit_p95-ms 7227181 B/op 68933 allocs/op +BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/tip_200ms_overlap-8 3 200828651 ns/op 0.8102 avg_cpu_cores 126.0 components/block 162.7 cpu-ms/block 0.5170 feed_lag_p50-ms 1.016 feed_lag_p95-ms 7.912 mean_width 0.8773 ready_p50-ms 1.385 ready_p95-ms 0.9549 residual_p50-ms 1.219 residual_p95-ms 33760 signatures/block 168104 signatures/s 0.001112 submit_p50-ms 0.002545 submit_p95-ms 7226312 B/op 68925 allocs/op +PASS diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/execution-comparison.json b/docs/results/sigverify-streaming/2026-09-12-zen5/execution-comparison.json new file mode 100644 index 00000000..488e0481 --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/execution-comparison.json @@ -0,0 +1,1653 @@ +{ + "description": "Compare actual transfer load/execute under separate-process sigverify load.\n\nThis does not benchmark complete block replay, the shared Go scheduler, account\ncommit, or the dependency planner. Both processes use the same explicitly chosen\neight physical CPU cores. The signature workload uses the production verifier\npool; 200 ms availability is simulated, not a captured network trace.\n", + "arguments": { + "turbine_bin": "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "replay_bin": "/srv/mithril-sigverify-streaming-20260912/bin/replay.test", + "fixtures": "/srv/mithril-planner-pr257-trial-20260912/fixtures", + "slot": 2622581, + "cpus": "0-7", + "out": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention", + "samples": 3, + "probe_time": "500ms", + "catchup_blocks": 96, + "tip_blocks": 20, + "warmup_ms": 400, + "backend": "r51", + "seed": 1, + "timeout": 120 + }, + "topology": [ + { + "cpu": 0, + "package": 0, + "core": 0 + }, + { + "cpu": 1, + "package": 0, + "core": 1 + }, + { + "cpu": 2, + "package": 0, + "core": 2 + }, + { + "cpu": 3, + "package": 0, + "core": 3 + }, + { + "cpu": 4, + "package": 0, + "core": 4 + }, + { + "cpu": 5, + "package": 0, + "core": 5 + }, + { + "cpu": 6, + "package": 0, + "core": 6 + }, + { + "cpu": 7, + "package": 0, + "core": 7 + } + ], + "gomaxprocs_each_process": 8, + "execution_probe_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/replay.test", + "-test.run=^$", + "-test.bench=^BenchmarkLoadAndExecuteTransferResultMode$/^lean$", + "-test.benchtime=500ms", + "-test.count=1", + "-test.timeout=120s" + ], + "runs": [ + { + "sample": 1, + "workers": 2, + "target": 8, + "mode": "tip_200ms_overlap", + "baseline": { + "wall_seconds": 0.6645082151517272, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 167744, + "ns/op": 3471.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-tip_200ms_overlap-workers2-target8/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.6648174938745797, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 171600, + "ns/op": 3530.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-tip_200ms_overlap-workers2-target8/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.0169979832901181, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_overlap-8", + "iterations": 20, + "ns/op": 200924240.0, + "avg_cpu_cores": 0.8916, + "components/block": 126.0, + "cpu-ms/block": 179.2, + "feed_lag_p50-ms": 0.4462, + "feed_lag_p95-ms": 0.9733, + "mean_width": 7.912, + "ready_p50-ms": 1.19, + "ready_p95-ms": 1.808, + "residual_p50-ms": 0.9351, + "residual_p95-ms": 1.356, + "signatures/block": 33760.0, + "signatures/s": 168024.0, + "submit_p50-ms": 0.001734, + "submit_p95-ms": 0.004288, + "B/op": 7208732.0, + "allocs/op": 68935.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_2$/^target_8$/^tip_200ms_overlap$", + "-test.benchtime=20x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-tip_200ms_overlap-workers2-target8/sigverify-load.log" + }, + { + "sample": 1, + "workers": 4, + "target": 8, + "mode": "catchup", + "baseline": { + "wall_seconds": 0.6647921879775822, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 170856, + "ns/op": 3547.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-catchup-workers4-target8/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.6148647838272154, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 139512, + "ns/op": 4060.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-catchup-workers4-target8/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.1446292641669016, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/catchup-8", + "iterations": 96, + "ns/op": 40210294.0, + "avg_cpu_cores": 3.993, + "components/block": 1.0, + "cpu-ms/block": 160.6, + "feed_lag_p50-ms": 0.000211, + "feed_lag_p95-ms": 0.00043, + "mean_width": 8.0, + "ready_p50-ms": 39.57, + "ready_p95-ms": 43.68, + "residual_p50-ms": 39.57, + "residual_p95-ms": 43.68, + "signatures/block": 33760.0, + "signatures/s": 839586.0, + "submit_p50-ms": 0.003306, + "submit_p95-ms": 0.005891, + "B/op": 7058192.0, + "allocs/op": 67537.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_4$/^target_8$/^catchup$", + "-test.benchtime=96x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-catchup-workers4-target8/sigverify-load.log" + }, + { + "sample": 1, + "workers": 2, + "target": 4, + "mode": "tip_200ms_overlap", + "baseline": { + "wall_seconds": 0.6646570740267634, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 172561, + "ns/op": 3462.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-tip_200ms_overlap-workers2-target4/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.6148028671741486, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 156918, + "ns/op": 3704.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-tip_200ms_overlap-workers2-target4/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.069901790872328, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_overlap-8", + "iterations": 20, + "ns/op": 201168852.0, + "avg_cpu_cores": 1.563, + "components/block": 126.0, + "cpu-ms/block": 314.3, + "feed_lag_p50-ms": 0.04094, + "feed_lag_p95-ms": 0.8651, + "mean_width": 3.956, + "ready_p50-ms": 1.616, + "ready_p95-ms": 2.755, + "residual_p50-ms": 1.196, + "residual_p95-ms": 1.497, + "signatures/block": 33760.0, + "signatures/s": 167819.0, + "submit_p50-ms": 0.001432, + "submit_p95-ms": 0.004018, + "B/op": 7234818.0, + "allocs/op": 68941.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_2$/^target_4$/^tip_200ms_overlap$", + "-test.benchtime=20x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-tip_200ms_overlap-workers2-target4/sigverify-load.log" + }, + { + "sample": 1, + "workers": 4, + "target": 4, + "mode": "tip_200ms_overlap", + "baseline": { + "wall_seconds": 0.6144880480132997, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 165466, + "ns/op": 3489.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-tip_200ms_overlap-workers4-target4/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.7155657866969705, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 155095, + "ns/op": 4302.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-tip_200ms_overlap-workers4-target4/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.233018056749785, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_overlap-8", + "iterations": 20, + "ns/op": 201022700.0, + "avg_cpu_cores": 1.651, + "components/block": 126.0, + "cpu-ms/block": 332.0, + "feed_lag_p50-ms": 0.4337, + "feed_lag_p95-ms": 0.9876, + "mean_width": 3.956, + "ready_p50-ms": 1.206, + "ready_p95-ms": 1.982, + "residual_p50-ms": 1.099, + "residual_p95-ms": 1.257, + "signatures/block": 33760.0, + "signatures/s": 167941.0, + "submit_p50-ms": 0.001674, + "submit_p95-ms": 0.004459, + "B/op": 7241454.0, + "allocs/op": 68940.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_4$/^target_4$/^tip_200ms_overlap$", + "-test.benchtime=20x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-tip_200ms_overlap-workers4-target4/sigverify-load.log" + }, + { + "sample": 1, + "workers": 4, + "target": 8, + "mode": "tip_200ms_overlap", + "baseline": { + "wall_seconds": 0.6647598869167268, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 165728, + "ns/op": 3596.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-tip_200ms_overlap-workers4-target8/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.6647413833998144, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 167448, + "ns/op": 3564.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-tip_200ms_overlap-workers4-target8/execution-concurrent.log" + }, + "execution_slowdown_ratio": 0.9911012235817576, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_overlap-8", + "iterations": 20, + "ns/op": 200934390.0, + "avg_cpu_cores": 0.8582, + "components/block": 126.0, + "cpu-ms/block": 172.4, + "feed_lag_p50-ms": 0.517, + "feed_lag_p95-ms": 1.006, + "mean_width": 7.912, + "ready_p50-ms": 0.9062, + "ready_p95-ms": 1.396, + "residual_p50-ms": 1.041, + "residual_p95-ms": 1.256, + "signatures/block": 33760.0, + "signatures/s": 168015.0, + "submit_p50-ms": 0.001383, + "submit_p95-ms": 0.003878, + "B/op": 7274370.0, + "allocs/op": 68941.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_4$/^target_8$/^tip_200ms_overlap$", + "-test.benchtime=20x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-tip_200ms_overlap-workers4-target8/sigverify-load.log" + }, + { + "sample": 1, + "workers": 2, + "target": 4, + "mode": "catchup", + "baseline": { + "wall_seconds": 0.6649067718535662, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 149238, + "ns/op": 4008.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-catchup-workers2-target4/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.6675727372057736, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 146756, + "ns/op": 4085.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-catchup-workers2-target4/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.0192115768463075, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/catchup-8", + "iterations": 96, + "ns/op": 153189266.0, + "avg_cpu_cores": 2.048, + "components/block": 1.0, + "cpu-ms/block": 313.8, + "feed_lag_p50-ms": 0.000211, + "feed_lag_p95-ms": 0.000481, + "mean_width": 4.0, + "ready_p50-ms": 149.6, + "ready_p95-ms": 174.2, + "residual_p50-ms": 149.6, + "residual_p95-ms": 174.2, + "signatures/block": 33760.0, + "signatures/s": 220381.0, + "submit_p50-ms": 0.003657, + "submit_p95-ms": 0.01091, + "B/op": 7054772.0, + "allocs/op": 67536.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_2$/^target_4$/^catchup$", + "-test.benchtime=96x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-catchup-workers2-target4/sigverify-load.log" + }, + { + "sample": 1, + "workers": 4, + "target": 4, + "mode": "catchup", + "baseline": { + "wall_seconds": 0.7147685927338898, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 164997, + "ns/op": 3958.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-catchup-workers4-target4/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.6648671478033066, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 152398, + "ns/op": 4006.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-catchup-workers4-target4/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.0121273370389086, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/catchup-8", + "iterations": 96, + "ns/op": 79167070.0, + "avg_cpu_cores": 3.991, + "components/block": 1.0, + "cpu-ms/block": 316.0, + "feed_lag_p50-ms": 0.00023, + "feed_lag_p95-ms": 0.00037, + "mean_width": 4.0, + "ready_p50-ms": 76.56, + "ready_p95-ms": 96.7, + "residual_p50-ms": 76.56, + "residual_p95-ms": 96.7, + "signatures/block": 33760.0, + "signatures/s": 426440.0, + "submit_p50-ms": 0.003706, + "submit_p95-ms": 0.011, + "B/op": 7060780.0, + "allocs/op": 67537.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_4$/^target_4$/^catchup$", + "-test.benchtime=96x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-catchup-workers4-target4/sigverify-load.log" + }, + { + "sample": 1, + "workers": 2, + "target": 8, + "mode": "catchup", + "baseline": { + "wall_seconds": 0.6647211848758161, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 174750, + "ns/op": 3542.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-catchup-workers2-target8/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.7656238148920238, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 159576, + "ns/op": 4432.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-catchup-workers2-target8/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.251270468661773, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/catchup-8", + "iterations": 96, + "ns/op": 78756306.0, + "avg_cpu_cores": 2.051, + "components/block": 1.0, + "cpu-ms/block": 161.6, + "feed_lag_p50-ms": 0.00022, + "feed_lag_p95-ms": 0.000491, + "mean_width": 8.0, + "ready_p50-ms": 75.68, + "ready_p95-ms": 90.65, + "residual_p50-ms": 75.68, + "residual_p95-ms": 90.65, + "signatures/block": 33760.0, + "signatures/s": 428664.0, + "submit_p50-ms": 0.003326, + "submit_p95-ms": 0.01184, + "B/op": 7060612.0, + "allocs/op": 67536.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_2$/^target_8$/^catchup$", + "-test.benchtime=96x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-1-catchup-workers2-target8/sigverify-load.log" + }, + { + "sample": 2, + "workers": 2, + "target": 8, + "mode": "catchup", + "baseline": { + "wall_seconds": 0.6144605274312198, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 168331, + "ns/op": 3448.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-catchup-workers2-target8/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.6650009588338435, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 142396, + "ns/op": 4201.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-catchup-workers2-target8/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.2183874709976799, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/catchup-8", + "iterations": 96, + "ns/op": 77871825.0, + "avg_cpu_cores": 2.052, + "components/block": 1.0, + "cpu-ms/block": 159.8, + "feed_lag_p50-ms": 0.0002, + "feed_lag_p95-ms": 0.00038, + "mean_width": 8.0, + "ready_p50-ms": 76.13, + "ready_p95-ms": 88.31, + "residual_p50-ms": 76.13, + "residual_p95-ms": 88.31, + "signatures/block": 33760.0, + "signatures/s": 433533.0, + "submit_p50-ms": 0.003436, + "submit_p95-ms": 0.007464, + "B/op": 7056320.0, + "allocs/op": 67536.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_2$/^target_8$/^catchup$", + "-test.benchtime=96x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-catchup-workers2-target8/sigverify-load.log" + }, + { + "sample": 2, + "workers": 4, + "target": 8, + "mode": "catchup", + "baseline": { + "wall_seconds": 0.6145014832727611, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 168381, + "ns/op": 3462.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-catchup-workers4-target8/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.7652924442663789, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 141712, + "ns/op": 4887.0, + "B/op": 4145.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-catchup-workers4-target8/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.4116117850953207, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/catchup-8", + "iterations": 96, + "ns/op": 42898713.0, + "avg_cpu_cores": 3.925, + "components/block": 1.0, + "cpu-ms/block": 168.4, + "feed_lag_p50-ms": 0.00023, + "feed_lag_p95-ms": 0.000471, + "mean_width": 8.0, + "ready_p50-ms": 41.07, + "ready_p95-ms": 54.05, + "residual_p50-ms": 41.07, + "residual_p95-ms": 54.05, + "signatures/block": 33760.0, + "signatures/s": 786970.0, + "submit_p50-ms": 0.003397, + "submit_p95-ms": 0.01086, + "B/op": 7053910.0, + "allocs/op": 67536.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_4$/^target_8$/^catchup$", + "-test.benchtime=96x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-catchup-workers4-target8/sigverify-load.log" + }, + { + "sample": 2, + "workers": 4, + "target": 4, + "mode": "catchup", + "baseline": { + "wall_seconds": 0.7149186637252569, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 155592, + "ns/op": 4248.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-catchup-workers4-target4/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.6148898312821984, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 134372, + "ns/op": 4182.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-catchup-workers4-target4/execution-concurrent.log" + }, + "execution_slowdown_ratio": 0.9844632768361582, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/catchup-8", + "iterations": 96, + "ns/op": 79047165.0, + "avg_cpu_cores": 3.999, + "components/block": 1.0, + "cpu-ms/block": 316.1, + "feed_lag_p50-ms": 0.0002, + "feed_lag_p95-ms": 0.000291, + "mean_width": 4.0, + "ready_p50-ms": 76.57, + "ready_p95-ms": 94.24, + "residual_p50-ms": 76.57, + "residual_p95-ms": 94.24, + "signatures/block": 33760.0, + "signatures/s": 427087.0, + "submit_p50-ms": 0.003747, + "submit_p95-ms": 0.01152, + "B/op": 7056514.0, + "allocs/op": 67537.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_4$/^target_4$/^catchup$", + "-test.benchtime=96x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-catchup-workers4-target4/sigverify-load.log" + }, + { + "sample": 2, + "workers": 2, + "target": 4, + "mode": "catchup", + "baseline": { + "wall_seconds": 0.6647634031251073, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 170058, + "ns/op": 3624.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-catchup-workers2-target4/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.7149660927243531, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 160458, + "ns/op": 4021.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-catchup-workers2-target4/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.1095474613686533, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/catchup-8", + "iterations": 96, + "ns/op": 151919970.0, + "avg_cpu_cores": 2.051, + "components/block": 1.0, + "cpu-ms/block": 311.5, + "feed_lag_p50-ms": 0.00022, + "feed_lag_p95-ms": 0.000461, + "mean_width": 4.0, + "ready_p50-ms": 147.5, + "ready_p95-ms": 175.5, + "residual_p50-ms": 147.5, + "residual_p95-ms": 175.5, + "signatures/block": 33760.0, + "signatures/s": 222222.0, + "submit_p50-ms": 0.003677, + "submit_p95-ms": 0.007574, + "B/op": 7061922.0, + "allocs/op": 67537.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_2$/^target_4$/^catchup$", + "-test.benchtime=96x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-catchup-workers2-target4/sigverify-load.log" + }, + { + "sample": 2, + "workers": 2, + "target": 4, + "mode": "tip_200ms_overlap", + "baseline": { + "wall_seconds": 0.6146299438551068, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 166706, + "ns/op": 3502.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-tip_200ms_overlap-workers2-target4/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.5672630779445171, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 107145, + "ns/op": 4799.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-tip_200ms_overlap-workers2-target4/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.3703597944031982, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_overlap-8", + "iterations": 20, + "ns/op": 201262863.0, + "avg_cpu_cores": 1.606, + "components/block": 126.0, + "cpu-ms/block": 323.2, + "feed_lag_p50-ms": 0.03106, + "feed_lag_p95-ms": 0.8493, + "mean_width": 3.956, + "ready_p50-ms": 1.723, + "ready_p95-ms": 2.871, + "residual_p50-ms": 1.114, + "residual_p95-ms": 1.802, + "signatures/block": 33760.0, + "signatures/s": 167741.0, + "submit_p50-ms": 0.001453, + "submit_p95-ms": 0.004058, + "B/op": 7212730.0, + "allocs/op": 68935.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_2$/^target_4$/^tip_200ms_overlap$", + "-test.benchtime=20x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-tip_200ms_overlap-workers2-target4/sigverify-load.log" + }, + { + "sample": 2, + "workers": 2, + "target": 8, + "mode": "tip_200ms_overlap", + "baseline": { + "wall_seconds": 0.7147977370768785, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 174418, + "ns/op": 3727.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-tip_200ms_overlap-workers2-target8/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.6647711875848472, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 167622, + "ns/op": 3536.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-tip_200ms_overlap-workers2-target8/execution-concurrent.log" + }, + "execution_slowdown_ratio": 0.948752347732761, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_overlap-8", + "iterations": 20, + "ns/op": 200967117.0, + "avg_cpu_cores": 0.8453, + "components/block": 126.0, + "cpu-ms/block": 169.9, + "feed_lag_p50-ms": 0.4835, + "feed_lag_p95-ms": 0.9802, + "mean_width": 7.912, + "ready_p50-ms": 1.166, + "ready_p95-ms": 1.747, + "residual_p50-ms": 0.9879, + "residual_p95-ms": 1.377, + "signatures/block": 33760.0, + "signatures/s": 167988.0, + "submit_p50-ms": 0.001313, + "submit_p95-ms": 0.003486, + "B/op": 7222552.0, + "allocs/op": 68937.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_2$/^target_8$/^tip_200ms_overlap$", + "-test.benchtime=20x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-tip_200ms_overlap-workers2-target8/sigverify-load.log" + }, + { + "sample": 2, + "workers": 4, + "target": 4, + "mode": "tip_200ms_overlap", + "baseline": { + "wall_seconds": 0.6646457533352077, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 174780, + "ns/op": 3601.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-tip_200ms_overlap-workers4-target4/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.6648325030691922, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 162474, + "ns/op": 3740.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-tip_200ms_overlap-workers4-target4/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.0386003887808941, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_overlap-8", + "iterations": 20, + "ns/op": 200928113.0, + "avg_cpu_cores": 1.526, + "components/block": 126.0, + "cpu-ms/block": 306.7, + "feed_lag_p50-ms": 0.476, + "feed_lag_p95-ms": 0.9896, + "mean_width": 3.956, + "ready_p50-ms": 1.136, + "ready_p95-ms": 1.672, + "residual_p50-ms": 1.002, + "residual_p95-ms": 1.263, + "signatures/block": 33760.0, + "signatures/s": 168020.0, + "submit_p50-ms": 0.001252, + "submit_p95-ms": 0.003527, + "B/op": 7256845.0, + "allocs/op": 68947.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_4$/^target_4$/^tip_200ms_overlap$", + "-test.benchtime=20x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-tip_200ms_overlap-workers4-target4/sigverify-load.log" + }, + { + "sample": 2, + "workers": 4, + "target": 8, + "mode": "tip_200ms_overlap", + "baseline": { + "wall_seconds": 0.6147988210432231, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 137796, + "ns/op": 3945.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-tip_200ms_overlap-workers4-target8/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.6647517010569572, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 171933, + "ns/op": 3546.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-tip_200ms_overlap-workers4-target8/execution-concurrent.log" + }, + "execution_slowdown_ratio": 0.8988593155893536, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_overlap-8", + "iterations": 20, + "ns/op": 200756778.0, + "avg_cpu_cores": 0.8979, + "components/block": 126.0, + "cpu-ms/block": 180.3, + "feed_lag_p50-ms": 0.5109, + "feed_lag_p95-ms": 0.9931, + "mean_width": 7.912, + "ready_p50-ms": 0.9308, + "ready_p95-ms": 1.413, + "residual_p50-ms": 0.7481, + "residual_p95-ms": 1.147, + "signatures/block": 33760.0, + "signatures/s": 168164.0, + "submit_p50-ms": 0.001683, + "submit_p95-ms": 0.004809, + "B/op": 7287646.0, + "allocs/op": 68938.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_4$/^target_8$/^tip_200ms_overlap$", + "-test.benchtime=20x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-2-tip_200ms_overlap-workers4-target8/sigverify-load.log" + }, + { + "sample": 3, + "workers": 2, + "target": 8, + "mode": "catchup", + "baseline": { + "wall_seconds": 0.6647746949456632, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 164358, + "ns/op": 3884.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-catchup-workers2-target8/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.6149854301474988, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 126450, + "ns/op": 4148.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-catchup-workers2-target8/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.0679711637487126, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/catchup-8", + "iterations": 96, + "ns/op": 78410504.0, + "avg_cpu_cores": 2.05, + "components/block": 1.0, + "cpu-ms/block": 160.8, + "feed_lag_p50-ms": 0.00023, + "feed_lag_p95-ms": 0.000481, + "mean_width": 8.0, + "ready_p50-ms": 75.31, + "ready_p95-ms": 90.25, + "residual_p50-ms": 75.31, + "residual_p95-ms": 90.25, + "signatures/block": 33760.0, + "signatures/s": 430555.0, + "submit_p50-ms": 0.003577, + "submit_p95-ms": 0.007614, + "B/op": 7057749.0, + "allocs/op": 67536.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_2$/^target_8$/^catchup$", + "-test.benchtime=96x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-catchup-workers2-target8/sigverify-load.log" + }, + { + "sample": 3, + "workers": 4, + "target": 4, + "mode": "tip_200ms_overlap", + "baseline": { + "wall_seconds": 0.6145468889735639, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 167756, + "ns/op": 3486.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-tip_200ms_overlap-workers4-target4/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.665121624711901, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 141630, + "ns/op": 4231.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-tip_200ms_overlap-workers4-target4/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.2137119908204246, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_overlap-8", + "iterations": 20, + "ns/op": 200751013.0, + "avg_cpu_cores": 1.678, + "components/block": 126.0, + "cpu-ms/block": 336.9, + "feed_lag_p50-ms": 0.4283, + "feed_lag_p95-ms": 0.9902, + "mean_width": 3.956, + "ready_p50-ms": 1.217, + "ready_p95-ms": 2.032, + "residual_p50-ms": 0.5827, + "residual_p95-ms": 1.286, + "signatures/block": 33760.0, + "signatures/s": 168169.0, + "submit_p50-ms": 0.001764, + "submit_p95-ms": 0.004468, + "B/op": 7235916.0, + "allocs/op": 68943.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_4$/^target_4$/^tip_200ms_overlap$", + "-test.benchtime=20x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-tip_200ms_overlap-workers4-target4/sigverify-load.log" + }, + { + "sample": 3, + "workers": 2, + "target": 4, + "mode": "tip_200ms_overlap", + "baseline": { + "wall_seconds": 0.5645706839859486, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 140451, + "ns/op": 3666.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-tip_200ms_overlap-workers2-target4/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.6147960559464991, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 155277, + "ns/op": 3597.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-tip_200ms_overlap-workers2-target4/execution-concurrent.log" + }, + "execution_slowdown_ratio": 0.9811783960720131, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_overlap-8", + "iterations": 20, + "ns/op": 201192091.0, + "avg_cpu_cores": 1.506, + "components/block": 126.0, + "cpu-ms/block": 303.0, + "feed_lag_p50-ms": 0.0687, + "feed_lag_p95-ms": 0.8534, + "mean_width": 3.956, + "ready_p50-ms": 1.591, + "ready_p95-ms": 2.54, + "residual_p50-ms": 1.178, + "residual_p95-ms": 1.465, + "signatures/block": 33760.0, + "signatures/s": 167800.0, + "submit_p50-ms": 0.001112, + "submit_p95-ms": 0.002705, + "B/op": 7200373.0, + "allocs/op": 68940.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_2$/^target_4$/^tip_200ms_overlap$", + "-test.benchtime=20x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-tip_200ms_overlap-workers2-target4/sigverify-load.log" + }, + { + "sample": 3, + "workers": 4, + "target": 8, + "mode": "tip_200ms_overlap", + "baseline": { + "wall_seconds": 0.6645939256995916, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 170604, + "ns/op": 3472.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-tip_200ms_overlap-workers4-target8/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.7150162868201733, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 159267, + "ns/op": 4093.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-tip_200ms_overlap-workers4-target8/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.1788594470046083, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_overlap-8", + "iterations": 20, + "ns/op": 200971694.0, + "avg_cpu_cores": 0.8761, + "components/block": 126.0, + "cpu-ms/block": 176.1, + "feed_lag_p50-ms": 0.5208, + "feed_lag_p95-ms": 1.015, + "mean_width": 7.912, + "ready_p50-ms": 0.9286, + "ready_p95-ms": 1.43, + "residual_p50-ms": 1.097, + "residual_p95-ms": 1.294, + "signatures/block": 33760.0, + "signatures/s": 167984.0, + "submit_p50-ms": 0.001553, + "submit_p95-ms": 0.004518, + "B/op": 7272930.0, + "allocs/op": 68937.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_4$/^target_8$/^tip_200ms_overlap$", + "-test.benchtime=20x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-tip_200ms_overlap-workers4-target8/sigverify-load.log" + }, + { + "sample": 3, + "workers": 2, + "target": 4, + "mode": "catchup", + "baseline": { + "wall_seconds": 0.6646965383552015, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 166202, + "ns/op": 3817.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-catchup-workers2-target4/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.6147506199777126, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 160532, + "ns/op": 3624.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-catchup-workers2-target4/execution-concurrent.log" + }, + "execution_slowdown_ratio": 0.9494367304165575, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/catchup-8", + "iterations": 96, + "ns/op": 147847296.0, + "avg_cpu_cores": 2.051, + "components/block": 1.0, + "cpu-ms/block": 303.2, + "feed_lag_p50-ms": 0.00023, + "feed_lag_p95-ms": 0.000491, + "mean_width": 4.0, + "ready_p50-ms": 145.3, + "ready_p95-ms": 159.8, + "residual_p50-ms": 145.3, + "residual_p95-ms": 159.8, + "signatures/block": 33760.0, + "signatures/s": 228344.0, + "submit_p50-ms": 0.003817, + "submit_p95-ms": 0.007323, + "B/op": 7057630.0, + "allocs/op": 67536.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_2$/^target_4$/^catchup$", + "-test.benchtime=96x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-catchup-workers2-target4/sigverify-load.log" + }, + { + "sample": 3, + "workers": 4, + "target": 4, + "mode": "catchup", + "baseline": { + "wall_seconds": 0.664639541413635, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 169953, + "ns/op": 3669.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-catchup-workers4-target4/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.6653050077147782, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 145288, + "ns/op": 4207.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-catchup-workers4-target4/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.146633960207141, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/catchup-8", + "iterations": 96, + "ns/op": 80096206.0, + "avg_cpu_cores": 3.978, + "components/block": 1.0, + "cpu-ms/block": 318.6, + "feed_lag_p50-ms": 0.00023, + "feed_lag_p95-ms": 0.000691, + "mean_width": 4.0, + "ready_p50-ms": 77.65, + "ready_p95-ms": 92.49, + "residual_p50-ms": 77.65, + "residual_p95-ms": 92.49, + "signatures/block": 33760.0, + "signatures/s": 421493.0, + "submit_p50-ms": 0.004018, + "submit_p95-ms": 0.01255, + "B/op": 7057922.0, + "allocs/op": 67536.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_4$/^target_4$/^catchup$", + "-test.benchtime=96x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-catchup-workers4-target4/sigverify-load.log" + }, + { + "sample": 3, + "workers": 2, + "target": 8, + "mode": "tip_200ms_overlap", + "baseline": { + "wall_seconds": 0.614480503834784, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 168775, + "ns/op": 3465.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-tip_200ms_overlap-workers2-target8/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.6648324020206928, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 167258, + "ns/op": 3583.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-tip_200ms_overlap-workers2-target8/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.0340548340548341, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_overlap-8", + "iterations": 20, + "ns/op": 200968000.0, + "avg_cpu_cores": 0.842, + "components/block": 126.0, + "cpu-ms/block": 169.2, + "feed_lag_p50-ms": 0.4334, + "feed_lag_p95-ms": 0.9712, + "mean_width": 7.912, + "ready_p50-ms": 1.178, + "ready_p95-ms": 1.715, + "residual_p50-ms": 1.039, + "residual_p95-ms": 1.357, + "signatures/block": 33760.0, + "signatures/s": 167987.0, + "submit_p50-ms": 0.001403, + "submit_p95-ms": 0.004248, + "B/op": 7250793.0, + "allocs/op": 68941.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_2$/^target_8$/^tip_200ms_overlap$", + "-test.benchtime=20x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-tip_200ms_overlap-workers2-target8/sigverify-load.log" + }, + { + "sample": 3, + "workers": 4, + "target": 8, + "mode": "catchup", + "baseline": { + "wall_seconds": 0.6646514940075576, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 167019, + "ns/op": 3809.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-catchup-workers4-target8/execution-baseline.log" + }, + "concurrent": { + "wall_seconds": 0.7654618811793625, + "benchmark": { + "name": "BenchmarkLoadAndExecuteTransferResultMode/lean-8", + "iterations": 148914, + "ns/op": 4629.0, + "B/op": 4146.0, + "allocs/op": 59.0 + }, + "log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-catchup-workers4-target8/execution-concurrent.log" + }, + "execution_slowdown_ratio": 1.2152796009451299, + "sigverify": { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/catchup-8", + "iterations": 96, + "ns/op": 44540126.0, + "avg_cpu_cores": 3.899, + "components/block": 1.0, + "cpu-ms/block": 173.7, + "feed_lag_p50-ms": 0.00024, + "feed_lag_p95-ms": 0.00033, + "mean_width": 8.0, + "ready_p50-ms": 42.49, + "ready_p95-ms": 55.03, + "residual_p50-ms": 42.49, + "residual_p95-ms": 55.03, + "signatures/block": 33760.0, + "signatures/s": 757968.0, + "submit_p50-ms": 0.003727, + "submit_p95-ms": 0.01137, + "B/op": 7053895.0, + "allocs/op": 67536.0 + }, + "sigverify_command": [ + "taskset", + "--cpu-list", + "0-7", + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", + "-test.run=^$", + "-test.bench=^BenchmarkTransactionVerificationFlow$/^captured_2622581$/^workers_4$/^target_8$/^catchup$", + "-test.benchtime=96x", + "-test.count=1", + "-test.timeout=120s" + ], + "sigverify_log": "/srv/mithril-sigverify-streaming-20260912/results/execution-contention/sample-3-catchup-workers4-target8/sigverify-load.log" + } + ], + "summary": [ + { + "workers": 2, + "target": 4, + "mode": "catchup", + "samples": 3, + "median_execution_slowdown_ratio": 1.0192115768463075, + "median_execution_baseline_ns": 3817.0, + "median_execution_concurrent_ns": 4021.0, + "median_sigverify_residual_p95_ms": 174.2, + "median_sigverify_cpu_ms_per_block": 311.5 + }, + { + "workers": 2, + "target": 4, + "mode": "tip_200ms_overlap", + "samples": 3, + "median_execution_slowdown_ratio": 1.069901790872328, + "median_execution_baseline_ns": 3502.0, + "median_execution_concurrent_ns": 3704.0, + "median_sigverify_residual_p95_ms": 1.497, + "median_sigverify_cpu_ms_per_block": 314.3 + }, + { + "workers": 2, + "target": 8, + "mode": "catchup", + "samples": 3, + "median_execution_slowdown_ratio": 1.2183874709976799, + "median_execution_baseline_ns": 3542.0, + "median_execution_concurrent_ns": 4201.0, + "median_sigverify_residual_p95_ms": 90.25, + "median_sigverify_cpu_ms_per_block": 160.8 + }, + { + "workers": 2, + "target": 8, + "mode": "tip_200ms_overlap", + "samples": 3, + "median_execution_slowdown_ratio": 1.0169979832901181, + "median_execution_baseline_ns": 3471.0, + "median_execution_concurrent_ns": 3536.0, + "median_sigverify_residual_p95_ms": 1.357, + "median_sigverify_cpu_ms_per_block": 169.9 + }, + { + "workers": 4, + "target": 4, + "mode": "catchup", + "samples": 3, + "median_execution_slowdown_ratio": 1.0121273370389086, + "median_execution_baseline_ns": 3958.0, + "median_execution_concurrent_ns": 4182.0, + "median_sigverify_residual_p95_ms": 94.24, + "median_sigverify_cpu_ms_per_block": 316.1 + }, + { + "workers": 4, + "target": 4, + "mode": "tip_200ms_overlap", + "samples": 3, + "median_execution_slowdown_ratio": 1.2137119908204246, + "median_execution_baseline_ns": 3489.0, + "median_execution_concurrent_ns": 4231.0, + "median_sigverify_residual_p95_ms": 1.263, + "median_sigverify_cpu_ms_per_block": 332.0 + }, + { + "workers": 4, + "target": 8, + "mode": "catchup", + "samples": 3, + "median_execution_slowdown_ratio": 1.2152796009451299, + "median_execution_baseline_ns": 3547.0, + "median_execution_concurrent_ns": 4629.0, + "median_sigverify_residual_p95_ms": 54.05, + "median_sigverify_cpu_ms_per_block": 168.4 + }, + { + "workers": 4, + "target": 8, + "mode": "tip_200ms_overlap", + "samples": 3, + "median_execution_slowdown_ratio": 0.9911012235817576, + "median_execution_baseline_ns": 3596.0, + "median_execution_concurrent_ns": 3564.0, + "median_sigverify_residual_p95_ms": 1.256, + "median_sigverify_cpu_ms_per_block": 176.1 + } + ] +} diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/execution-contention.log b/docs/results/sigverify-streaming/2026-09-12-zen5/execution-contention.log new file mode 100644 index 00000000..7f2cd0ca --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/execution-contention.log @@ -0,0 +1,162 @@ +sample-1-tip_200ms_overlap-workers2-target8: baseline execution +sample-1-tip_200ms_overlap-workers2-target8: concurrent execution +sample-1-tip_200ms_overlap-workers2-target8: execution ratio 1.017x +sample-1-catchup-workers4-target8: baseline execution +sample-1-catchup-workers4-target8: concurrent execution +sample-1-catchup-workers4-target8: execution ratio 1.145x +sample-1-tip_200ms_overlap-workers2-target4: baseline execution +sample-1-tip_200ms_overlap-workers2-target4: concurrent execution +sample-1-tip_200ms_overlap-workers2-target4: execution ratio 1.070x +sample-1-tip_200ms_overlap-workers4-target4: baseline execution +sample-1-tip_200ms_overlap-workers4-target4: concurrent execution +sample-1-tip_200ms_overlap-workers4-target4: execution ratio 1.233x +sample-1-tip_200ms_overlap-workers4-target8: baseline execution +sample-1-tip_200ms_overlap-workers4-target8: concurrent execution +sample-1-tip_200ms_overlap-workers4-target8: execution ratio 0.991x +sample-1-catchup-workers2-target4: baseline execution +sample-1-catchup-workers2-target4: concurrent execution +sample-1-catchup-workers2-target4: execution ratio 1.019x +sample-1-catchup-workers4-target4: baseline execution +sample-1-catchup-workers4-target4: concurrent execution +sample-1-catchup-workers4-target4: execution ratio 1.012x +sample-1-catchup-workers2-target8: baseline execution +sample-1-catchup-workers2-target8: concurrent execution +sample-1-catchup-workers2-target8: execution ratio 1.251x +sample-2-catchup-workers2-target8: baseline execution +sample-2-catchup-workers2-target8: concurrent execution +sample-2-catchup-workers2-target8: execution ratio 1.218x +sample-2-catchup-workers4-target8: baseline execution +sample-2-catchup-workers4-target8: concurrent execution +sample-2-catchup-workers4-target8: execution ratio 1.412x +sample-2-catchup-workers4-target4: baseline execution +sample-2-catchup-workers4-target4: concurrent execution +sample-2-catchup-workers4-target4: execution ratio 0.984x +sample-2-catchup-workers2-target4: baseline execution +sample-2-catchup-workers2-target4: concurrent execution +sample-2-catchup-workers2-target4: execution ratio 1.110x +sample-2-tip_200ms_overlap-workers2-target4: baseline execution +sample-2-tip_200ms_overlap-workers2-target4: concurrent execution +sample-2-tip_200ms_overlap-workers2-target4: execution ratio 1.370x +sample-2-tip_200ms_overlap-workers2-target8: baseline execution +sample-2-tip_200ms_overlap-workers2-target8: concurrent execution +sample-2-tip_200ms_overlap-workers2-target8: execution ratio 0.949x +sample-2-tip_200ms_overlap-workers4-target4: baseline execution +sample-2-tip_200ms_overlap-workers4-target4: concurrent execution +sample-2-tip_200ms_overlap-workers4-target4: execution ratio 1.039x +sample-2-tip_200ms_overlap-workers4-target8: baseline execution +sample-2-tip_200ms_overlap-workers4-target8: concurrent execution +sample-2-tip_200ms_overlap-workers4-target8: execution ratio 0.899x +sample-3-catchup-workers2-target8: baseline execution +sample-3-catchup-workers2-target8: concurrent execution +sample-3-catchup-workers2-target8: execution ratio 1.068x +sample-3-tip_200ms_overlap-workers4-target4: baseline execution +sample-3-tip_200ms_overlap-workers4-target4: concurrent execution +sample-3-tip_200ms_overlap-workers4-target4: execution ratio 1.214x +sample-3-tip_200ms_overlap-workers2-target4: baseline execution +sample-3-tip_200ms_overlap-workers2-target4: concurrent execution +sample-3-tip_200ms_overlap-workers2-target4: execution ratio 0.981x +sample-3-tip_200ms_overlap-workers4-target8: baseline execution +sample-3-tip_200ms_overlap-workers4-target8: concurrent execution +sample-3-tip_200ms_overlap-workers4-target8: execution ratio 1.179x +sample-3-catchup-workers2-target4: baseline execution +sample-3-catchup-workers2-target4: concurrent execution +sample-3-catchup-workers2-target4: execution ratio 0.949x +sample-3-catchup-workers4-target4: baseline execution +sample-3-catchup-workers4-target4: concurrent execution +sample-3-catchup-workers4-target4: execution ratio 1.147x +sample-3-tip_200ms_overlap-workers2-target8: baseline execution +sample-3-tip_200ms_overlap-workers2-target8: concurrent execution +sample-3-tip_200ms_overlap-workers2-target8: execution ratio 1.034x +sample-3-catchup-workers4-target8: baseline execution +sample-3-catchup-workers4-target8: concurrent execution +sample-3-catchup-workers4-target8: execution ratio 1.215x +[ + { + "workers": 2, + "target": 4, + "mode": "catchup", + "samples": 3, + "median_execution_slowdown_ratio": 1.0192115768463075, + "median_execution_baseline_ns": 3817.0, + "median_execution_concurrent_ns": 4021.0, + "median_sigverify_residual_p95_ms": 174.2, + "median_sigverify_cpu_ms_per_block": 311.5 + }, + { + "workers": 2, + "target": 4, + "mode": "tip_200ms_overlap", + "samples": 3, + "median_execution_slowdown_ratio": 1.069901790872328, + "median_execution_baseline_ns": 3502.0, + "median_execution_concurrent_ns": 3704.0, + "median_sigverify_residual_p95_ms": 1.497, + "median_sigverify_cpu_ms_per_block": 314.3 + }, + { + "workers": 2, + "target": 8, + "mode": "catchup", + "samples": 3, + "median_execution_slowdown_ratio": 1.2183874709976799, + "median_execution_baseline_ns": 3542.0, + "median_execution_concurrent_ns": 4201.0, + "median_sigverify_residual_p95_ms": 90.25, + "median_sigverify_cpu_ms_per_block": 160.8 + }, + { + "workers": 2, + "target": 8, + "mode": "tip_200ms_overlap", + "samples": 3, + "median_execution_slowdown_ratio": 1.0169979832901181, + "median_execution_baseline_ns": 3471.0, + "median_execution_concurrent_ns": 3536.0, + "median_sigverify_residual_p95_ms": 1.357, + "median_sigverify_cpu_ms_per_block": 169.9 + }, + { + "workers": 4, + "target": 4, + "mode": "catchup", + "samples": 3, + "median_execution_slowdown_ratio": 1.0121273370389086, + "median_execution_baseline_ns": 3958.0, + "median_execution_concurrent_ns": 4182.0, + "median_sigverify_residual_p95_ms": 94.24, + "median_sigverify_cpu_ms_per_block": 316.1 + }, + { + "workers": 4, + "target": 4, + "mode": "tip_200ms_overlap", + "samples": 3, + "median_execution_slowdown_ratio": 1.2137119908204246, + "median_execution_baseline_ns": 3489.0, + "median_execution_concurrent_ns": 4231.0, + "median_sigverify_residual_p95_ms": 1.263, + "median_sigverify_cpu_ms_per_block": 332.0 + }, + { + "workers": 4, + "target": 8, + "mode": "catchup", + "samples": 3, + "median_execution_slowdown_ratio": 1.2152796009451299, + "median_execution_baseline_ns": 3547.0, + "median_execution_concurrent_ns": 4629.0, + "median_sigverify_residual_p95_ms": 54.05, + "median_sigverify_cpu_ms_per_block": 168.4 + }, + { + "workers": 4, + "target": 8, + "mode": "tip_200ms_overlap", + "samples": 3, + "median_execution_slowdown_ratio": 0.9911012235817576, + "median_execution_baseline_ns": 3596.0, + "median_execution_concurrent_ns": 3564.0, + "median_sigverify_residual_p95_ms": 1.256, + "median_sigverify_cpu_ms_per_block": 176.1 + } +] diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/execution-raw.log b/docs/results/sigverify-streaming/2026-09-12-zen5/execution-raw.log new file mode 100644 index 00000000..e5fbb1e8 --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/execution-raw.log @@ -0,0 +1,576 @@ + +=== sample-1-catchup-workers2-target4/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 149238 4008 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-1-catchup-workers2-target4/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 146756 4085 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-1-catchup-workers2-target4/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/catchup-8 96 153189266 ns/op 2.048 avg_cpu_cores 1.000 components/block 313.8 cpu-ms/block 0.0002110 feed_lag_p50-ms 0.0004810 feed_lag_p95-ms 4.000 mean_width 149.6 ready_p50-ms 174.2 ready_p95-ms 149.6 residual_p50-ms 174.2 residual_p95-ms 33760 signatures/block 220381 signatures/s 0.003657 submit_p50-ms 0.01091 submit_p95-ms 7054772 B/op 67536 allocs/op +PASS + +=== sample-1-catchup-workers2-target8/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 174750 3542 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-1-catchup-workers2-target8/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 159576 4432 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-1-catchup-workers2-target8/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/catchup-8 96 78756306 ns/op 2.051 avg_cpu_cores 1.000 components/block 161.6 cpu-ms/block 0.0002200 feed_lag_p50-ms 0.0004910 feed_lag_p95-ms 8.000 mean_width 75.68 ready_p50-ms 90.65 ready_p95-ms 75.68 residual_p50-ms 90.65 residual_p95-ms 33760 signatures/block 428664 signatures/s 0.003326 submit_p50-ms 0.01184 submit_p95-ms 7060612 B/op 67536 allocs/op +PASS + +=== sample-1-catchup-workers4-target4/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 164997 3958 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-1-catchup-workers4-target4/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 152398 4006 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-1-catchup-workers4-target4/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/catchup-8 96 79167070 ns/op 3.991 avg_cpu_cores 1.000 components/block 316.0 cpu-ms/block 0.0002300 feed_lag_p50-ms 0.0003700 feed_lag_p95-ms 4.000 mean_width 76.56 ready_p50-ms 96.70 ready_p95-ms 76.56 residual_p50-ms 96.70 residual_p95-ms 33760 signatures/block 426440 signatures/s 0.003706 submit_p50-ms 0.01100 submit_p95-ms 7060780 B/op 67537 allocs/op +PASS + +=== sample-1-catchup-workers4-target8/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 170856 3547 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-1-catchup-workers4-target8/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 139512 4060 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-1-catchup-workers4-target8/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/catchup-8 96 40210294 ns/op 3.993 avg_cpu_cores 1.000 components/block 160.6 cpu-ms/block 0.0002110 feed_lag_p50-ms 0.0004300 feed_lag_p95-ms 8.000 mean_width 39.57 ready_p50-ms 43.68 ready_p95-ms 39.57 residual_p50-ms 43.68 residual_p95-ms 33760 signatures/block 839586 signatures/s 0.003306 submit_p50-ms 0.005891 submit_p95-ms 7058192 B/op 67537 allocs/op +PASS + +=== sample-1-tip_200ms_overlap-workers2-target4/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 172561 3462 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-1-tip_200ms_overlap-workers2-target4/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 156918 3704 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-1-tip_200ms_overlap-workers2-target4/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_overlap-8 20 201168852 ns/op 1.563 avg_cpu_cores 126.0 components/block 314.3 cpu-ms/block 0.04094 feed_lag_p50-ms 0.8651 feed_lag_p95-ms 3.956 mean_width 1.616 ready_p50-ms 2.755 ready_p95-ms 1.196 residual_p50-ms 1.497 residual_p95-ms 33760 signatures/block 167819 signatures/s 0.001432 submit_p50-ms 0.004018 submit_p95-ms 7234818 B/op 68941 allocs/op +PASS + +=== sample-1-tip_200ms_overlap-workers2-target8/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 167744 3471 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-1-tip_200ms_overlap-workers2-target8/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 171600 3530 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-1-tip_200ms_overlap-workers2-target8/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_overlap-8 20 200924240 ns/op 0.8916 avg_cpu_cores 126.0 components/block 179.2 cpu-ms/block 0.4462 feed_lag_p50-ms 0.9733 feed_lag_p95-ms 7.912 mean_width 1.190 ready_p50-ms 1.808 ready_p95-ms 0.9351 residual_p50-ms 1.356 residual_p95-ms 33760 signatures/block 168024 signatures/s 0.001734 submit_p50-ms 0.004288 submit_p95-ms 7208732 B/op 68935 allocs/op +PASS + +=== sample-1-tip_200ms_overlap-workers4-target4/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 165466 3489 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-1-tip_200ms_overlap-workers4-target4/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 155095 4302 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-1-tip_200ms_overlap-workers4-target4/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_overlap-8 20 201022700 ns/op 1.651 avg_cpu_cores 126.0 components/block 332.0 cpu-ms/block 0.4337 feed_lag_p50-ms 0.9876 feed_lag_p95-ms 3.956 mean_width 1.206 ready_p50-ms 1.982 ready_p95-ms 1.099 residual_p50-ms 1.257 residual_p95-ms 33760 signatures/block 167941 signatures/s 0.001674 submit_p50-ms 0.004459 submit_p95-ms 7241454 B/op 68940 allocs/op +PASS + +=== sample-1-tip_200ms_overlap-workers4-target8/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 165728 3596 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-1-tip_200ms_overlap-workers4-target8/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 167448 3564 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-1-tip_200ms_overlap-workers4-target8/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_overlap-8 20 200934390 ns/op 0.8582 avg_cpu_cores 126.0 components/block 172.4 cpu-ms/block 0.5170 feed_lag_p50-ms 1.006 feed_lag_p95-ms 7.912 mean_width 0.9062 ready_p50-ms 1.396 ready_p95-ms 1.041 residual_p50-ms 1.256 residual_p95-ms 33760 signatures/block 168015 signatures/s 0.001383 submit_p50-ms 0.003878 submit_p95-ms 7274370 B/op 68941 allocs/op +PASS + +=== sample-2-catchup-workers2-target4/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 170058 3624 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-2-catchup-workers2-target4/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 160458 4021 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-2-catchup-workers2-target4/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/catchup-8 96 151919970 ns/op 2.051 avg_cpu_cores 1.000 components/block 311.5 cpu-ms/block 0.0002200 feed_lag_p50-ms 0.0004610 feed_lag_p95-ms 4.000 mean_width 147.5 ready_p50-ms 175.5 ready_p95-ms 147.5 residual_p50-ms 175.5 residual_p95-ms 33760 signatures/block 222222 signatures/s 0.003677 submit_p50-ms 0.007574 submit_p95-ms 7061922 B/op 67537 allocs/op +PASS + +=== sample-2-catchup-workers2-target8/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 168331 3448 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-2-catchup-workers2-target8/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 142396 4201 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-2-catchup-workers2-target8/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/catchup-8 96 77871825 ns/op 2.052 avg_cpu_cores 1.000 components/block 159.8 cpu-ms/block 0.0002000 feed_lag_p50-ms 0.0003800 feed_lag_p95-ms 8.000 mean_width 76.13 ready_p50-ms 88.31 ready_p95-ms 76.13 residual_p50-ms 88.31 residual_p95-ms 33760 signatures/block 433533 signatures/s 0.003436 submit_p50-ms 0.007464 submit_p95-ms 7056320 B/op 67536 allocs/op +PASS + +=== sample-2-catchup-workers4-target4/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 155592 4248 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-2-catchup-workers4-target4/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 134372 4182 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-2-catchup-workers4-target4/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/catchup-8 96 79047165 ns/op 3.999 avg_cpu_cores 1.000 components/block 316.1 cpu-ms/block 0.0002000 feed_lag_p50-ms 0.0002910 feed_lag_p95-ms 4.000 mean_width 76.57 ready_p50-ms 94.24 ready_p95-ms 76.57 residual_p50-ms 94.24 residual_p95-ms 33760 signatures/block 427087 signatures/s 0.003747 submit_p50-ms 0.01152 submit_p95-ms 7056514 B/op 67537 allocs/op +PASS + +=== sample-2-catchup-workers4-target8/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 168381 3462 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-2-catchup-workers4-target8/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 141712 4887 ns/op 4145 B/op 59 allocs/op +PASS + +=== sample-2-catchup-workers4-target8/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/catchup-8 96 42898713 ns/op 3.925 avg_cpu_cores 1.000 components/block 168.4 cpu-ms/block 0.0002300 feed_lag_p50-ms 0.0004710 feed_lag_p95-ms 8.000 mean_width 41.07 ready_p50-ms 54.05 ready_p95-ms 41.07 residual_p50-ms 54.05 residual_p95-ms 33760 signatures/block 786970 signatures/s 0.003397 submit_p50-ms 0.01086 submit_p95-ms 7053910 B/op 67536 allocs/op +PASS + +=== sample-2-tip_200ms_overlap-workers2-target4/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 166706 3502 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-2-tip_200ms_overlap-workers2-target4/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 107145 4799 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-2-tip_200ms_overlap-workers2-target4/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_overlap-8 20 201262863 ns/op 1.606 avg_cpu_cores 126.0 components/block 323.2 cpu-ms/block 0.03106 feed_lag_p50-ms 0.8493 feed_lag_p95-ms 3.956 mean_width 1.723 ready_p50-ms 2.871 ready_p95-ms 1.114 residual_p50-ms 1.802 residual_p95-ms 33760 signatures/block 167741 signatures/s 0.001453 submit_p50-ms 0.004058 submit_p95-ms 7212730 B/op 68935 allocs/op +PASS + +=== sample-2-tip_200ms_overlap-workers2-target8/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 174418 3727 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-2-tip_200ms_overlap-workers2-target8/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 167622 3536 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-2-tip_200ms_overlap-workers2-target8/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_overlap-8 20 200967117 ns/op 0.8453 avg_cpu_cores 126.0 components/block 169.9 cpu-ms/block 0.4835 feed_lag_p50-ms 0.9802 feed_lag_p95-ms 7.912 mean_width 1.166 ready_p50-ms 1.747 ready_p95-ms 0.9879 residual_p50-ms 1.377 residual_p95-ms 33760 signatures/block 167988 signatures/s 0.001313 submit_p50-ms 0.003486 submit_p95-ms 7222552 B/op 68937 allocs/op +PASS + +=== sample-2-tip_200ms_overlap-workers4-target4/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 174780 3601 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-2-tip_200ms_overlap-workers4-target4/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 162474 3740 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-2-tip_200ms_overlap-workers4-target4/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_overlap-8 20 200928113 ns/op 1.526 avg_cpu_cores 126.0 components/block 306.7 cpu-ms/block 0.4760 feed_lag_p50-ms 0.9896 feed_lag_p95-ms 3.956 mean_width 1.136 ready_p50-ms 1.672 ready_p95-ms 1.002 residual_p50-ms 1.263 residual_p95-ms 33760 signatures/block 168020 signatures/s 0.001252 submit_p50-ms 0.003527 submit_p95-ms 7256845 B/op 68947 allocs/op +PASS + +=== sample-2-tip_200ms_overlap-workers4-target8/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 137796 3945 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-2-tip_200ms_overlap-workers4-target8/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 171933 3546 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-2-tip_200ms_overlap-workers4-target8/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_overlap-8 20 200756778 ns/op 0.8979 avg_cpu_cores 126.0 components/block 180.3 cpu-ms/block 0.5109 feed_lag_p50-ms 0.9931 feed_lag_p95-ms 7.912 mean_width 0.9308 ready_p50-ms 1.413 ready_p95-ms 0.7481 residual_p50-ms 1.147 residual_p95-ms 33760 signatures/block 168164 signatures/s 0.001683 submit_p50-ms 0.004809 submit_p95-ms 7287646 B/op 68938 allocs/op +PASS + +=== sample-3-catchup-workers2-target4/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 166202 3817 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-3-catchup-workers2-target4/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 160532 3624 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-3-catchup-workers2-target4/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/catchup-8 96 147847296 ns/op 2.051 avg_cpu_cores 1.000 components/block 303.2 cpu-ms/block 0.0002300 feed_lag_p50-ms 0.0004910 feed_lag_p95-ms 4.000 mean_width 145.3 ready_p50-ms 159.8 ready_p95-ms 145.3 residual_p50-ms 159.8 residual_p95-ms 33760 signatures/block 228344 signatures/s 0.003817 submit_p50-ms 0.007323 submit_p95-ms 7057630 B/op 67536 allocs/op +PASS + +=== sample-3-catchup-workers2-target8/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 164358 3884 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-3-catchup-workers2-target8/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 126450 4148 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-3-catchup-workers2-target8/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/catchup-8 96 78410504 ns/op 2.050 avg_cpu_cores 1.000 components/block 160.8 cpu-ms/block 0.0002300 feed_lag_p50-ms 0.0004810 feed_lag_p95-ms 8.000 mean_width 75.31 ready_p50-ms 90.25 ready_p95-ms 75.31 residual_p50-ms 90.25 residual_p95-ms 33760 signatures/block 430555 signatures/s 0.003577 submit_p50-ms 0.007614 submit_p95-ms 7057749 B/op 67536 allocs/op +PASS + +=== sample-3-catchup-workers4-target4/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 169953 3669 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-3-catchup-workers4-target4/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 145288 4207 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-3-catchup-workers4-target4/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/catchup-8 96 80096206 ns/op 3.978 avg_cpu_cores 1.000 components/block 318.6 cpu-ms/block 0.0002300 feed_lag_p50-ms 0.0006910 feed_lag_p95-ms 4.000 mean_width 77.65 ready_p50-ms 92.49 ready_p95-ms 77.65 residual_p50-ms 92.49 residual_p95-ms 33760 signatures/block 421493 signatures/s 0.004018 submit_p50-ms 0.01255 submit_p95-ms 7057922 B/op 67536 allocs/op +PASS + +=== sample-3-catchup-workers4-target8/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 167019 3809 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-3-catchup-workers4-target8/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 148914 4629 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-3-catchup-workers4-target8/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/catchup-8 96 44540126 ns/op 3.899 avg_cpu_cores 1.000 components/block 173.7 cpu-ms/block 0.0002400 feed_lag_p50-ms 0.0003300 feed_lag_p95-ms 8.000 mean_width 42.49 ready_p50-ms 55.03 ready_p95-ms 42.49 residual_p50-ms 55.03 residual_p95-ms 33760 signatures/block 757968 signatures/s 0.003727 submit_p50-ms 0.01137 submit_p95-ms 7053895 B/op 67536 allocs/op +PASS + +=== sample-3-tip_200ms_overlap-workers2-target4/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 140451 3666 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-3-tip_200ms_overlap-workers2-target4/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 155277 3597 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-3-tip_200ms_overlap-workers2-target4/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_overlap-8 20 201192091 ns/op 1.506 avg_cpu_cores 126.0 components/block 303.0 cpu-ms/block 0.06870 feed_lag_p50-ms 0.8534 feed_lag_p95-ms 3.956 mean_width 1.591 ready_p50-ms 2.540 ready_p95-ms 1.178 residual_p50-ms 1.465 residual_p95-ms 33760 signatures/block 167800 signatures/s 0.001112 submit_p50-ms 0.002705 submit_p95-ms 7200373 B/op 68940 allocs/op +PASS + +=== sample-3-tip_200ms_overlap-workers2-target8/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 168775 3465 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-3-tip_200ms_overlap-workers2-target8/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 167258 3583 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-3-tip_200ms_overlap-workers2-target8/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_overlap-8 20 200968000 ns/op 0.8420 avg_cpu_cores 126.0 components/block 169.2 cpu-ms/block 0.4334 feed_lag_p50-ms 0.9712 feed_lag_p95-ms 7.912 mean_width 1.178 ready_p50-ms 1.715 ready_p95-ms 1.039 residual_p50-ms 1.357 residual_p95-ms 33760 signatures/block 167987 signatures/s 0.001403 submit_p50-ms 0.004248 submit_p95-ms 7250793 B/op 68941 allocs/op +PASS + +=== sample-3-tip_200ms_overlap-workers4-target4/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 167756 3486 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-3-tip_200ms_overlap-workers4-target4/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 141630 4231 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-3-tip_200ms_overlap-workers4-target4/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_overlap-8 20 200751013 ns/op 1.678 avg_cpu_cores 126.0 components/block 336.9 cpu-ms/block 0.4283 feed_lag_p50-ms 0.9902 feed_lag_p95-ms 3.956 mean_width 1.217 ready_p50-ms 2.032 ready_p95-ms 0.5827 residual_p50-ms 1.286 residual_p95-ms 33760 signatures/block 168169 signatures/s 0.001764 submit_p50-ms 0.004468 submit_p95-ms 7235916 B/op 68943 allocs/op +PASS + +=== sample-3-tip_200ms_overlap-workers4-target8/execution-baseline.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 170604 3472 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-3-tip_200ms_overlap-workers4-target8/execution-concurrent.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/replay +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkLoadAndExecuteTransferResultMode/lean-8 159267 4093 ns/op 4146 B/op 59 allocs/op +PASS + +=== sample-3-tip_200ms_overlap-workers4-target8/sigverify-load.log === +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_overlap-8 20 200971694 ns/op 0.8761 avg_cpu_cores 126.0 components/block 176.1 cpu-ms/block 0.5208 feed_lag_p50-ms 1.015 feed_lag_p95-ms 7.912 mean_width 0.9286 ready_p50-ms 1.430 ready_p95-ms 1.097 residual_p50-ms 1.294 residual_p95-ms 33760 signatures/block 167984 signatures/s 0.001553 submit_p50-ms 0.004518 submit_p95-ms 7272930 B/op 68937 allocs/op +PASS diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/final-commands.jsonl b/docs/results/sigverify-streaming/2026-09-12-zen5/final-commands.jsonl new file mode 100644 index 00000000..b63468b4 --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/final-commands.jsonl @@ -0,0 +1,6 @@ +{"name": "native-final-unit", "command": ["nice", "-n", "10", "/usr/local/go/bin/go", "test", "-p", "2", "./pkg/turbine", "./pkg/sigverify", "./pkg/txverify", "./pkg/block", "./pkg/statsd", "./cmd/mithril/node"], "extra_env": {}, "seconds": 4.821521997451782, "exit_code": 0} +{"name": "native-final-race", "command": ["nice", "-n", "10", "/usr/local/go/bin/go", "test", "-race", "-p", "2", "./pkg/turbine", "-run", "TestEntryPrefetch|TestEntryDecode|TestTransactionVerifi|TestUDPReceiver", "-count=2"], "extra_env": {}, "seconds": 7.025081634521484, "exit_code": 0} +{"name": "build-turbine-final", "command": ["nice", "-n", "10", "/usr/local/go/bin/go", "test", "-c", "-p", "2", "-o", "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", "./pkg/turbine"], "extra_env": {}, "seconds": 1.566469430923462, "exit_code": 0} +{"name": "assembly-captured", "command": ["nice", "-n", "10", "taskset", "--cpu-list", "0-7", "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", "-test.run=^$", "-test.benchtime=3x", "-test.count=3", "-test.timeout=240s", "-test.bench=^BenchmarkEntryPrefetchAssembly$/^captured_2622581$/^workers_.*$/^target_8$/.*"], "extra_env": {"MITHRIL_SIGVERIFY_FLOW_BACKEND": "r51", "MITHRIL_SIGVERIFY_FLOW_FIXTURES": "/srv/mithril-planner-pr257-trial-20260912/fixtures"}, "seconds": 18.89488172531128, "exit_code": 0} +{"name": "assembly-1232", "command": ["nice", "-n", "10", "taskset", "--cpu-list", "0-7", "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", "-test.run=^$", "-test.benchtime=3x", "-test.count=3", "-test.timeout=240s", "-test.bench=^BenchmarkEntryPrefetchAssembly$/^generated_1232B$/^workers_.*$/^target_8$/.*"], "extra_env": {"MITHRIL_SIGVERIFY_FLOW_BACKEND": "r51", "MITHRIL_SIGVERIFY_FLOW_COUNT": "33760"}, "seconds": 24.252999305725098, "exit_code": 0} +{"name": "execution-contention", "command": ["nice", "-n", "10", "python3", "/srv/mithril-sigverify-streaming-20260912/run_execution_contention.py", "--turbine-bin", "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", "--replay-bin", "/srv/mithril-sigverify-streaming-20260912/bin/replay.test", "--fixtures", "/srv/mithril-planner-pr257-trial-20260912/fixtures", "--slot", "2622581", "--cpus", "0-7", "--out", "/srv/mithril-sigverify-streaming-20260912/results/execution-contention", "--samples", "3", "--catchup-blocks", "96", "--tip-blocks", "20"], "extra_env": {}, "seconds": 179.08553171157837, "exit_code": 0} diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/final-source-update.json b/docs/results/sigverify-streaming/2026-09-12-zen5/final-source-update.json new file mode 100644 index 00000000..aaa6fe97 --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/final-source-update.json @@ -0,0 +1,30 @@ +[ + { + "path": "config.example.toml", + "sha256": "ed208df9d174ab939160353779715209c8e2c82a6acc0a88dbc50c83dbad0c9b" + }, + { + "path": "docs/transaction_sigverify_streaming.md", + "sha256": "75968dbf5479adb7d25af6648e2b7ab33115534617f5551bde30a96a218332e4" + }, + { + "path": "pkg/turbine/entry_prefetch.go", + "sha256": "b69d9b559daccf85c042c01e06f93038f4d8a39fdc07a40397904935d84c4f3f" + }, + { + "path": "pkg/turbine/entry_prefetch_benchmark_test.go", + "sha256": "c360fc332437e8f2515d45dce9d0e798246a5bf1a087f64e5e82fa83e1fb0bd2" + }, + { + "path": "pkg/turbine/entry_prefetch_bounds_test.go", + "sha256": "541fea19a6f3edaaba3e10945b4676342a4802c418a7317944a4e93c653dcd4b" + }, + { + "path": "pkg/turbine/entry_prefetch_test.go", + "sha256": "edcd844eb622124c181670b696174f3dde427e95570b45f012a20e62fb8e6dc8" + }, + { + "path": "pkg/turbine/receiver.go", + "sha256": "73a7b55e6efcc9b54e11e1b882840992263f90b350e71d2d8a69306a1f124066" + } +] \ No newline at end of file diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/generated-1232-pool-flow.log b/docs/results/sigverify-streaming/2026-09-12-zen5/generated-1232-pool-flow.log new file mode 100644 index 00000000..d6f8f950 --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/generated-1232-pool-flow.log @@ -0,0 +1,77 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/catchup-8 3 165232107 ns/op 2.073 avg_cpu_cores 1.000 components/block 342.6 cpu-ms/block 0.0002410 feed_lag_p50-ms 0.0004810 feed_lag_p95-ms 4.000 mean_width 163.8 ready_p50-ms 171.9 ready_p95-ms 163.8 residual_p50-ms 171.9 residual_p95-ms 33760 signatures/block 204319 signatures/s 0.004889 submit_p50-ms 0.005961 submit_p95-ms 44570082 B/op 67557 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/catchup-8 3 166036574 ns/op 2.074 avg_cpu_cores 1.000 components/block 344.4 cpu-ms/block 0.0002110 feed_lag_p50-ms 0.0004710 feed_lag_p95-ms 4.000 mean_width 164.3 ready_p50-ms 172.6 ready_p95-ms 164.3 residual_p50-ms 172.6 residual_p95-ms 33760 signatures/block 203329 signatures/s 0.004078 submit_p50-ms 0.006131 submit_p95-ms 44615709 B/op 67558 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/catchup-8 3 158962907 ns/op 2.075 avg_cpu_cores 1.000 components/block 329.9 cpu-ms/block 0.0002500 feed_lag_p50-ms 0.0004610 feed_lag_p95-ms 4.000 mean_width 159.6 ready_p50-ms 160.2 ready_p95-ms 159.6 residual_p50-ms 160.2 residual_p95-ms 33760 signatures/block 212377 signatures/s 0.004829 submit_p50-ms 0.005470 submit_p95-ms 44707154 B/op 67561 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/tip_200ms_after_complete-8 3 359264432 ns/op 0.9167 avg_cpu_cores 689.0 components/block 329.3 cpu-ms/block 100.5 feed_lag_p50-ms 190.7 feed_lag_p95-ms 4.000 mean_width 259.3 ready_p50-ms 349.4 ready_p95-ms 159.3 residual_p50-ms 160.9 residual_p95-ms 33760 signatures/block 93970 signatures/s 0.01357 submit_p50-ms 0.01492 submit_p95-ms 44535416 B/op 67551 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/tip_200ms_after_complete-8 3 359629949 ns/op 0.9180 avg_cpu_cores 689.0 components/block 330.1 cpu-ms/block 100.7 feed_lag_p50-ms 190.8 feed_lag_p95-ms 4.000 mean_width 259.7 ready_p50-ms 349.8 ready_p95-ms 159.4 residual_p50-ms 161.5 residual_p95-ms 33760 signatures/block 93874 signatures/s 0.01362 submit_p50-ms 0.01513 submit_p95-ms 44535658 B/op 67552 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/tip_200ms_after_complete-8 3 359479815 ns/op 0.9171 avg_cpu_cores 689.0 components/block 329.7 cpu-ms/block 100.4 feed_lag_p50-ms 190.5 feed_lag_p95-ms 4.000 mean_width 259.5 ready_p50-ms 349.6 ready_p95-ms 159.9 residual_p50-ms 160.2 residual_p95-ms 33760 signatures/block 93913 signatures/s 0.01571 submit_p50-ms 0.01585 submit_p95-ms 44489704 B/op 67550 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/tip_200ms_overlap-8 3 200661932 ns/op 1.879 avg_cpu_cores 689.0 components/block 377.1 cpu-ms/block 0.04898 feed_lag_p50-ms 3.657 feed_lag_p95-ms 3.770 mean_width 0.9535 ready_p50-ms 5.077 ready_p95-ms 0.6731 residual_p50-ms 0.9156 residual_p95-ms 33760 signatures/block 168243 signatures/s 0.001192 submit_p50-ms 0.5149 submit_p95-ms 45346429 B/op 75220 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/tip_200ms_overlap-8 3 200375326 ns/op 1.856 avg_cpu_cores 689.0 components/block 371.8 cpu-ms/block 0.04542 feed_lag_p50-ms 2.251 feed_lag_p95-ms 3.770 mean_width 0.9154 ready_p50-ms 3.697 ready_p95-ms 0.3591 residual_p50-ms 0.4024 residual_p95-ms 33760 signatures/block 168484 signatures/s 0.001102 submit_p50-ms 0.5519 submit_p95-ms 45279114 B/op 75174 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/tip_200ms_overlap-8 3 200405779 ns/op 1.798 avg_cpu_cores 689.0 components/block 360.4 cpu-ms/block 0.03941 feed_lag_p50-ms 1.051 feed_lag_p95-ms 3.770 mean_width 0.8241 ready_p50-ms 2.498 ready_p95-ms 0.3923 residual_p50-ms 0.5034 residual_p95-ms 33760 signatures/block 168458 signatures/s 0.0008520 submit_p50-ms 0.5208 submit_p95-ms 45287578 B/op 75182 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_4tx_200ms_overlap-8 3 200381187 ns/op 0.02000 avg_cpu_cores 64.00 components/block 4.008 cpu-ms/block 0.5205 feed_lag_p50-ms 0.9542 feed_lag_p95-ms 4.000 mean_width 0.5746 ready_p50-ms 1.006 ready_p95-ms 0.06565 residual_p50-ms 1.008 residual_p95-ms 256.0 signatures/block 1278 signatures/s 0.001062 submit_p50-ms 0.003106 submit_p95-ms 405549 B/op 1227 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_4tx_200ms_overlap-8 3 200548807 ns/op 0.03358 avg_cpu_cores 64.00 components/block 6.734 cpu-ms/block 0.5788 feed_lag_p50-ms 0.9736 feed_lag_p95-ms 4.000 mean_width 0.6502 ready_p50-ms 1.057 ready_p95-ms 0.4003 residual_p50-ms 0.8991 residual_p95-ms 256.0 signatures/block 1276 signatures/s 0.002535 submit_p50-ms 0.01151 submit_p95-ms 405570 B/op 1228 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_4tx_200ms_overlap-8 3 200692627 ns/op 0.02155 avg_cpu_cores 64.00 components/block 4.324 cpu-ms/block 0.5307 feed_lag_p50-ms 0.9496 feed_lag_p95-ms 4.000 mean_width 0.5792 ready_p50-ms 1.004 ready_p95-ms 0.7962 residual_p50-ms 0.9766 residual_p95-ms 256.0 signatures/block 1276 signatures/s 0.001232 submit_p50-ms 0.003516 submit_p95-ms 405549 B/op 1227 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_7tx_200ms_overlap-8 3 200734923 ns/op 0.02505 avg_cpu_cores 37.00 components/block 5.029 cpu-ms/block 0.5435 feed_lag_p50-ms 0.9882 feed_lag_p95-ms 3.507 mean_width 0.6193 ready_p50-ms 1.055 ready_p95-ms 0.8195 residual_p50-ms 1.028 residual_p95-ms 256.0 signatures/block 1275 signatures/s 0.001703 submit_p50-ms 0.005821 submit_p95-ms 376309 B/op 931 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_7tx_200ms_overlap-8 3 200839933 ns/op 0.02110 avg_cpu_cores 37.00 components/block 4.237 cpu-ms/block 0.5533 feed_lag_p50-ms 1.006 feed_lag_p95-ms 3.507 mean_width 0.6087 ready_p50-ms 1.060 ready_p95-ms 0.9924 residual_p50-ms 1.071 residual_p95-ms 256.0 signatures/block 1275 signatures/s 0.001212 submit_p50-ms 0.003216 submit_p95-ms 376301 B/op 930 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_7tx_200ms_overlap-8 3 200166050 ns/op 0.02238 avg_cpu_cores 37.00 components/block 4.480 cpu-ms/block 0.5576 feed_lag_p50-ms 1.003 feed_lag_p95-ms 3.507 mean_width 0.6392 ready_p50-ms 1.089 ready_p95-ms 0.1596 residual_p50-ms 0.1676 residual_p95-ms 256.0 signatures/block 1279 signatures/s 0.001563 submit_p50-ms 0.003787 submit_p95-ms 376301 B/op 930 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_8tx_200ms_overlap-8 3 200891132 ns/op 0.02598 avg_cpu_cores 32.00 components/block 5.220 cpu-ms/block 0.6103 feed_lag_p50-ms 1.029 feed_lag_p95-ms 4.000 mean_width 0.6923 ready_p50-ms 1.127 ready_p95-ms 0.9305 residual_p50-ms 1.072 residual_p95-ms 256.0 signatures/block 1274 signatures/s 0.002044 submit_p50-ms 0.01812 submit_p95-ms 370733 B/op 875 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_8tx_200ms_overlap-8 3 200748211 ns/op 0.01877 avg_cpu_cores 32.00 components/block 3.768 cpu-ms/block 0.4370 feed_lag_p50-ms 1.023 feed_lag_p95-ms 4.000 mean_width 0.5164 ready_p50-ms 1.080 ready_p95-ms 0.7419 residual_p50-ms 0.7640 residual_p95-ms 256.0 signatures/block 1275 signatures/s 0.001562 submit_p50-ms 0.003406 submit_p95-ms 370733 B/op 875 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_8tx_200ms_overlap-8 3 200821061 ns/op 0.02266 avg_cpu_cores 32.00 components/block 4.551 cpu-ms/block 0.6271 feed_lag_p50-ms 1.025 feed_lag_p95-ms 4.000 mean_width 0.6833 ready_p50-ms 1.099 ready_p95-ms 0.8705 residual_p50-ms 0.9203 residual_p95-ms 256.0 signatures/block 1275 signatures/s 0.001843 submit_p50-ms 0.01049 submit_p95-ms 370733 B/op 875 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/catchup-8 3 88134578 ns/op 2.097 avg_cpu_cores 1.000 components/block 184.8 cpu-ms/block 0.0004010 feed_lag_p50-ms 0.0008320 feed_lag_p95-ms 8.000 mean_width 89.14 ready_p50-ms 92.15 ready_p95-ms 89.14 residual_p50-ms 92.15 residual_p95-ms 33760 signatures/block 383051 signatures/s 0.005991 submit_p50-ms 0.01270 submit_p95-ms 44478298 B/op 67549 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/catchup-8 3 86113936 ns/op 2.090 avg_cpu_cores 1.000 components/block 180.0 cpu-ms/block 0.0002600 feed_lag_p50-ms 0.0007320 feed_lag_p95-ms 8.000 mean_width 84.68 ready_p50-ms 89.35 ready_p95-ms 84.68 residual_p50-ms 89.35 residual_p95-ms 33760 signatures/block 392039 signatures/s 0.004137 submit_p50-ms 0.005370 submit_p95-ms 44386656 B/op 67544 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/catchup-8 3 84405778 ns/op 2.098 avg_cpu_cores 1.000 components/block 177.1 cpu-ms/block 0.0002500 feed_lag_p50-ms 0.0004810 feed_lag_p95-ms 8.000 mean_width 84.06 ready_p50-ms 85.34 ready_p95-ms 84.06 residual_p50-ms 85.34 residual_p95-ms 33760 signatures/block 399973 signatures/s 0.004048 submit_p50-ms 0.004588 submit_p95-ms 44569941 B/op 67554 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/tip_200ms_after_complete-8 3 284620670 ns/op 0.6238 avg_cpu_cores 689.0 components/block 177.6 cpu-ms/block 100.2 feed_lag_p50-ms 190.3 feed_lag_p95-ms 8.000 mean_width 184.6 ready_p50-ms 274.8 ready_p95-ms 84.69 residual_p50-ms 85.06 residual_p95-ms 33760 signatures/block 118614 signatures/s 0.01488 submit_p50-ms 0.01676 submit_p95-ms 44489685 B/op 67548 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/tip_200ms_after_complete-8 3 285857000 ns/op 0.6282 avg_cpu_cores 689.0 components/block 179.6 cpu-ms/block 100.4 feed_lag_p50-ms 190.5 feed_lag_p95-ms 8.000 mean_width 185.9 ready_p50-ms 276.0 ready_p95-ms 85.29 residual_p50-ms 87.23 residual_p95-ms 33760 signatures/block 118101 signatures/s 0.01511 submit_p50-ms 0.01781 submit_p95-ms 44627120 B/op 67555 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/tip_200ms_after_complete-8 3 290218004 ns/op 0.6484 avg_cpu_cores 689.0 components/block 188.2 cpu-ms/block 100.7 feed_lag_p50-ms 190.8 feed_lag_p95-ms 8.000 mean_width 190.1 ready_p50-ms 280.3 ready_p95-ms 91.02 residual_p50-ms 96.42 residual_p95-ms 33760 signatures/block 116326 signatures/s 0.01466 submit_p50-ms 0.02630 submit_p95-ms 44535536 B/op 67551 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/tip_200ms_overlap-8 3 200393747 ns/op 0.9599 avg_cpu_cores 689.0 components/block 192.4 cpu-ms/block 0.1208 feed_lag_p50-ms 0.6496 feed_lag_p95-ms 7.001 mean_width 0.5021 ready_p50-ms 1.098 ready_p95-ms 0.3487 residual_p50-ms 0.6362 residual_p95-ms 33760 signatures/block 168468 signatures/s 0.0006010 submit_p50-ms 0.002294 submit_p95-ms 45456104 B/op 75154 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/tip_200ms_overlap-8 3 200299620 ns/op 0.9555 avg_cpu_cores 689.0 components/block 191.4 cpu-ms/block 0.1164 feed_lag_p50-ms 0.6451 feed_lag_p95-ms 7.001 mean_width 0.4922 ready_p50-ms 1.083 ready_p95-ms 0.2595 residual_p50-ms 0.3970 residual_p95-ms 33760 signatures/block 168547 signatures/s 0.0005810 submit_p50-ms 0.001764 submit_p95-ms 45500650 B/op 75145 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/tip_200ms_overlap-8 3 200435552 ns/op 1.129 avg_cpu_cores 689.0 components/block 226.3 cpu-ms/block 0.08438 feed_lag_p50-ms 0.7172 feed_lag_p95-ms 7.001 mean_width 0.5504 ready_p50-ms 1.334 ready_p95-ms 0.3419 residual_p50-ms 0.6538 residual_p95-ms 33760 signatures/block 168433 signatures/s 0.0009020 submit_p50-ms 0.08766 submit_p95-ms 45547920 B/op 75161 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_4tx_200ms_overlap-8 3 200244671 ns/op 0.03331 avg_cpu_cores 64.00 components/block 6.669 cpu-ms/block 0.5335 feed_lag_p50-ms 0.9768 feed_lag_p95-ms 4.000 mean_width 0.6135 ready_p50-ms 1.060 ready_p95-ms 0.2598 residual_p50-ms 0.2713 residual_p95-ms 256.0 signatures/block 1278 signatures/s 0.002525 submit_p50-ms 0.008676 submit_p95-ms 413741 B/op 1227 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_4tx_200ms_overlap-8 3 200802763 ns/op 0.02071 avg_cpu_cores 64.00 components/block 4.159 cpu-ms/block 0.5448 feed_lag_p50-ms 0.9858 feed_lag_p95-ms 4.000 mean_width 0.5937 ready_p50-ms 1.037 ready_p95-ms 1.016 residual_p50-ms 1.070 residual_p95-ms 256.0 signatures/block 1275 signatures/s 0.001102 submit_p50-ms 0.002816 submit_p95-ms 413741 B/op 1227 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_4tx_200ms_overlap-8 3 200470397 ns/op 0.02005 avg_cpu_cores 64.00 components/block 4.019 cpu-ms/block 0.5300 feed_lag_p50-ms 0.9483 feed_lag_p95-ms 4.000 mean_width 0.5769 ready_p50-ms 1.000 ready_p95-ms 0.3612 residual_p50-ms 0.8751 residual_p95-ms 256.0 signatures/block 1277 signatures/s 0.001022 submit_p50-ms 0.003106 submit_p95-ms 413741 B/op 1227 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_7tx_200ms_overlap-8 3 200530663 ns/op 0.02064 avg_cpu_cores 37.00 components/block 4.138 cpu-ms/block 0.5475 feed_lag_p50-ms 1.006 feed_lag_p95-ms 6.919 mean_width 0.6508 ready_p50-ms 1.095 ready_p95-ms 0.2603 residual_p50-ms 1.101 residual_p95-ms 256.0 signatures/block 1277 signatures/s 0.001413 submit_p50-ms 0.003417 submit_p95-ms 381074 B/op 931 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_7tx_200ms_overlap-8 3 200704225 ns/op 0.02970 avg_cpu_cores 37.00 components/block 5.961 cpu-ms/block 0.5458 feed_lag_p50-ms 0.9953 feed_lag_p95-ms 6.919 mean_width 0.6663 ready_p50-ms 1.147 ready_p95-ms 0.6189 residual_p50-ms 1.129 residual_p95-ms 256.0 signatures/block 1276 signatures/s 0.003116 submit_p50-ms 0.008637 submit_p95-ms 381186 B/op 932 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_7tx_200ms_overlap-8 3 200734505 ns/op 0.01986 avg_cpu_cores 37.00 components/block 3.987 cpu-ms/block 0.5511 feed_lag_p50-ms 0.9991 feed_lag_p95-ms 6.919 mean_width 0.6354 ready_p50-ms 1.085 ready_p95-ms 0.8372 residual_p50-ms 1.059 residual_p95-ms 256.0 signatures/block 1275 signatures/s 0.001192 submit_p50-ms 0.003176 submit_p95-ms 381037 B/op 930 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_8tx_200ms_overlap-8 3 200612984 ns/op 0.01255 avg_cpu_cores 32.00 components/block 2.517 cpu-ms/block 0.5718 feed_lag_p50-ms 1.002 feed_lag_p95-ms 8.000 mean_width 0.6479 ready_p50-ms 1.064 ready_p95-ms 0.4956 residual_p50-ms 0.9127 residual_p95-ms 256.0 signatures/block 1276 signatures/s 0.001432 submit_p50-ms 0.005420 submit_p95-ms 420621 B/op 878 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_8tx_200ms_overlap-8 3 200664651 ns/op 0.01322 avg_cpu_cores 32.00 components/block 2.652 cpu-ms/block 0.6362 feed_lag_p50-ms 1.010 feed_lag_p95-ms 8.000 mean_width 0.6894 ready_p50-ms 1.085 ready_p95-ms 0.6880 residual_p50-ms 0.7389 residual_p95-ms 256.0 signatures/block 1276 signatures/s 0.001503 submit_p50-ms 0.006863 submit_p95-ms 374829 B/op 875 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_8tx_200ms_overlap-8 3 200621059 ns/op 0.01625 avg_cpu_cores 32.00 components/block 3.260 cpu-ms/block 0.6089 feed_lag_p50-ms 1.027 feed_lag_p95-ms 8.000 mean_width 0.6781 ready_p50-ms 1.091 ready_p95-ms 0.6671 residual_p50-ms 0.8341 residual_p95-ms 256.0 signatures/block 1276 signatures/s 0.002575 submit_p50-ms 0.008015 submit_p95-ms 374941 B/op 876 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/catchup-8 3 95848314 ns/op 3.962 avg_cpu_cores 1.000 components/block 379.7 cpu-ms/block 0.0005010 feed_lag_p50-ms 0.0008820 feed_lag_p95-ms 4.000 mean_width 97.21 ready_p50-ms 97.49 ready_p95-ms 97.21 residual_p50-ms 97.49 residual_p95-ms 33760 signatures/block 352223 signatures/s 0.006161 submit_p50-ms 0.01999 submit_p95-ms 44616002 B/op 67558 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/catchup-8 3 93784047 ns/op 3.933 avg_cpu_cores 1.000 components/block 368.9 cpu-ms/block 0.0002600 feed_lag_p50-ms 0.0005810 feed_lag_p95-ms 4.000 mean_width 97.49 ready_p50-ms 98.78 ready_p95-ms 97.49 residual_p50-ms 98.78 residual_p95-ms 33760 signatures/block 359976 signatures/s 0.004298 submit_p50-ms 0.005380 submit_p95-ms 44570261 B/op 67556 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/catchup-8 3 83340419 ns/op 4.080 avg_cpu_cores 1.000 components/block 340.1 cpu-ms/block 0.0002600 feed_lag_p50-ms 0.0004810 feed_lag_p95-ms 4.000 mean_width 83.48 ready_p50-ms 84.27 ready_p95-ms 83.48 residual_p50-ms 84.27 residual_p95-ms 33760 signatures/block 405086 signatures/s 0.004358 submit_p50-ms 0.004779 submit_p95-ms 44615936 B/op 67557 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/tip_200ms_after_complete-8 3 284770040 ns/op 1.189 avg_cpu_cores 689.0 components/block 338.7 cpu-ms/block 100.2 feed_lag_p50-ms 190.3 feed_lag_p95-ms 4.000 mean_width 184.7 ready_p50-ms 274.8 ready_p95-ms 84.70 residual_p50-ms 84.90 residual_p95-ms 33760 signatures/block 118552 signatures/s 0.01420 submit_p50-ms 0.01501 submit_p95-ms 44627381 B/op 67557 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/tip_200ms_after_complete-8 3 283332704 ns/op 1.187 avg_cpu_cores 689.0 components/block 336.2 cpu-ms/block 100.4 feed_lag_p50-ms 190.5 feed_lag_p95-ms 4.000 mean_width 183.3 ready_p50-ms 273.5 ready_p95-ms 83.42 residual_p50-ms 83.48 residual_p95-ms 33760 signatures/block 119153 signatures/s 0.01509 submit_p50-ms 0.01671 submit_p95-ms 44764728 B/op 67563 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/tip_200ms_after_complete-8 3 288602671 ns/op 1.226 avg_cpu_cores 689.0 components/block 353.9 cpu-ms/block 100.4 feed_lag_p50-ms 190.5 feed_lag_p95-ms 4.000 mean_width 188.6 ready_p50-ms 278.7 ready_p95-ms 82.52 residual_p50-ms 101.5 residual_p95-ms 33760 signatures/block 116977 signatures/s 0.01444 submit_p50-ms 0.01669 submit_p95-ms 44627397 B/op 67557 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/tip_200ms_overlap-8 3 200391623 ns/op 1.700 avg_cpu_cores 689.0 components/block 340.6 cpu-ms/block 0.1294 feed_lag_p50-ms 0.6600 feed_lag_p95-ms 3.770 mean_width 0.4949 ready_p50-ms 1.080 ready_p95-ms 0.3539 residual_p50-ms 0.5576 residual_p95-ms 33760 signatures/block 168470 signatures/s 0.0006110 submit_p50-ms 0.001674 submit_p95-ms 45465394 B/op 75165 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/tip_200ms_overlap-8 3 200606793 ns/op 1.834 avg_cpu_cores 689.0 components/block 368.0 cpu-ms/block 0.09882 feed_lag_p50-ms 0.6699 feed_lag_p95-ms 3.770 mean_width 0.5168 ready_p50-ms 1.161 ready_p95-ms 0.5678 residual_p50-ms 0.7021 residual_p95-ms 33760 signatures/block 168289 signatures/s 0.0007420 submit_p50-ms 0.002705 submit_p95-ms 45554293 B/op 75146 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/tip_200ms_overlap-8 3 200390250 ns/op 1.799 avg_cpu_cores 689.0 components/block 360.4 cpu-ms/block 0.1082 feed_lag_p50-ms 0.6858 feed_lag_p95-ms 3.770 mean_width 0.5309 ready_p50-ms 1.290 ready_p95-ms 0.2986 residual_p50-ms 0.5996 residual_p95-ms 33760 signatures/block 168471 signatures/s 0.0007310 submit_p50-ms 0.002485 submit_p95-ms 45417898 B/op 75147 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_4tx_200ms_overlap-8 3 200708870 ns/op 0.02342 avg_cpu_cores 64.00 components/block 4.700 cpu-ms/block 0.5677 feed_lag_p50-ms 0.9727 feed_lag_p95-ms 4.000 mean_width 0.6206 ready_p50-ms 1.032 ready_p95-ms 0.5738 residual_p50-ms 1.110 residual_p95-ms 256.0 signatures/block 1275 signatures/s 0.001583 submit_p50-ms 0.004359 submit_p95-ms 423106 B/op 1229 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_4tx_200ms_overlap-8 3 200711469 ns/op 0.02988 avg_cpu_cores 64.00 components/block 5.998 cpu-ms/block 0.5955 feed_lag_p50-ms 1.001 feed_lag_p95-ms 4.000 mean_width 0.6690 ready_p50-ms 1.073 ready_p95-ms 0.6728 residual_p50-ms 0.8759 residual_p95-ms 256.0 signatures/block 1275 signatures/s 0.002254 submit_p50-ms 0.005320 submit_p95-ms 422957 B/op 1227 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_4tx_200ms_overlap-8 3 200458906 ns/op 0.02460 avg_cpu_cores 64.00 components/block 4.931 cpu-ms/block 0.5634 feed_lag_p50-ms 0.9819 feed_lag_p95-ms 4.000 mean_width 0.6169 ready_p50-ms 1.037 ready_p95-ms 0.4628 residual_p50-ms 0.6882 residual_p95-ms 256.0 signatures/block 1277 signatures/s 0.001663 submit_p50-ms 0.004278 submit_p95-ms 422957 B/op 1227 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_7tx_200ms_overlap-8 3 200411787 ns/op 0.02500 avg_cpu_cores 37.00 components/block 5.011 cpu-ms/block 0.5475 feed_lag_p50-ms 0.9961 feed_lag_p95-ms 3.507 mean_width 0.6059 ready_p50-ms 1.064 ready_p95-ms 0.2112 residual_p50-ms 0.8439 residual_p95-ms 256.0 signatures/block 1277 signatures/s 0.001603 submit_p50-ms 0.008125 submit_p95-ms 386365 B/op 930 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_7tx_200ms_overlap-8 3 200155541 ns/op 0.02172 avg_cpu_cores 37.00 components/block 4.348 cpu-ms/block 0.5305 feed_lag_p50-ms 0.9950 feed_lag_p95-ms 3.507 mean_width 0.5883 ready_p50-ms 1.045 ready_p95-ms 0.1636 residual_p50-ms 0.1931 residual_p95-ms 256.0 signatures/block 1279 signatures/s 0.001372 submit_p50-ms 0.003166 submit_p95-ms 386365 B/op 930 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_7tx_200ms_overlap-8 3 200521630 ns/op 0.02820 avg_cpu_cores 37.00 components/block 5.655 cpu-ms/block 0.5292 feed_lag_p50-ms 0.9752 feed_lag_p95-ms 3.507 mean_width 0.5981 ready_p50-ms 1.088 ready_p95-ms 0.5204 residual_p50-ms 0.7328 residual_p95-ms 256.0 signatures/block 1277 signatures/s 0.001944 submit_p50-ms 0.01280 submit_p95-ms 386365 B/op 930 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_8tx_200ms_overlap-8 3 200734011 ns/op 0.01795 avg_cpu_cores 32.00 components/block 3.602 cpu-ms/block 0.6295 feed_lag_p50-ms 1.028 feed_lag_p95-ms 4.000 mean_width 0.6833 ready_p50-ms 1.083 ready_p95-ms 0.6833 residual_p50-ms 0.8221 residual_p95-ms 256.0 signatures/block 1275 signatures/s 0.001363 submit_p50-ms 0.002945 submit_p95-ms 379437 B/op 875 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_8tx_200ms_overlap-8 3 201052107 ns/op 0.02754 avg_cpu_cores 32.00 components/block 5.536 cpu-ms/block 0.6295 feed_lag_p50-ms 1.034 feed_lag_p95-ms 4.000 mean_width 0.7177 ready_p50-ms 1.115 ready_p95-ms 1.048 residual_p50-ms 1.051 residual_p95-ms 256.0 signatures/block 1273 signatures/s 0.001994 submit_p50-ms 0.02698 submit_p95-ms 379437 B/op 875 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_8tx_200ms_overlap-8 3 200711809 ns/op 0.01892 avg_cpu_cores 32.00 components/block 3.797 cpu-ms/block 0.6447 feed_lag_p50-ms 1.037 feed_lag_p95-ms 4.000 mean_width 0.6915 ready_p50-ms 1.093 ready_p95-ms 0.6820 residual_p50-ms 0.8024 residual_p95-ms 256.0 signatures/block 1275 signatures/s 0.001643 submit_p50-ms 0.003516 submit_p95-ms 379624 B/op 877 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/catchup-8 3 45816383 ns/op 4.073 avg_cpu_cores 1.000 components/block 186.6 cpu-ms/block 0.0002000 feed_lag_p50-ms 0.0004910 feed_lag_p95-ms 8.000 mean_width 45.06 ready_p50-ms 48.98 ready_p95-ms 45.06 residual_p50-ms 48.98 residual_p95-ms 33760 signatures/block 736854 signatures/s 0.004338 submit_p50-ms 0.004658 submit_p95-ms 44570576 B/op 67557 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/catchup-8 3 56218950 ns/op 3.966 avg_cpu_cores 1.000 components/block 223.0 cpu-ms/block 0.0005010 feed_lag_p50-ms 0.0005510 feed_lag_p95-ms 8.000 mean_width 55.44 ready_p50-ms 58.07 ready_p95-ms 55.44 residual_p50-ms 58.07 residual_p95-ms 33760 signatures/block 600509 signatures/s 0.006312 submit_p50-ms 0.01470 submit_p95-ms 44524608 B/op 67553 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/catchup-8 3 61550045 ns/op 3.871 avg_cpu_cores 1.000 components/block 238.3 cpu-ms/block 0.0003010 feed_lag_p50-ms 0.0009120 feed_lag_p95-ms 8.000 mean_width 60.95 ready_p50-ms 62.93 ready_p95-ms 60.95 residual_p50-ms 62.93 residual_p95-ms 33760 signatures/block 548497 signatures/s 0.007384 submit_p50-ms 0.01248 submit_p95-ms 44662146 B/op 67562 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/tip_200ms_after_complete-8 3 248039377 ns/op 0.7751 avg_cpu_cores 689.0 components/block 192.2 cpu-ms/block 100.4 feed_lag_p50-ms 190.5 feed_lag_p95-ms 8.000 mean_width 148.0 ready_p50-ms 238.1 ready_p95-ms 46.77 residual_p50-ms 54.35 residual_p95-ms 33760 signatures/block 136107 signatures/s 0.01645 submit_p50-ms 0.04039 submit_p95-ms 44398781 B/op 67546 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/tip_200ms_after_complete-8 3 244855756 ns/op 0.7431 avg_cpu_cores 689.0 components/block 182.0 cpu-ms/block 100.4 feed_lag_p50-ms 190.5 feed_lag_p95-ms 8.000 mean_width 144.8 ready_p50-ms 234.9 ready_p95-ms 44.62 residual_p50-ms 45.36 residual_p95-ms 33760 signatures/block 137877 signatures/s 0.01356 submit_p50-ms 0.01404 submit_p95-ms 44627629 B/op 67556 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/tip_200ms_after_complete-8 3 246211332 ns/op 0.7541 avg_cpu_cores 689.0 components/block 185.7 cpu-ms/block 100.4 feed_lag_p50-ms 190.5 feed_lag_p95-ms 8.000 mean_width 146.2 ready_p50-ms 236.3 ready_p95-ms 46.81 residual_p50-ms 47.71 residual_p95-ms 33760 signatures/block 137118 signatures/s 0.01444 submit_p50-ms 0.01546 submit_p95-ms 44490194 B/op 67549 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/tip_200ms_overlap-8 3 200653199 ns/op 1.155 avg_cpu_cores 689.0 components/block 231.7 cpu-ms/block 0.2466 feed_lag_p50-ms 0.7849 feed_lag_p95-ms 7.001 mean_width 0.5281 ready_p50-ms 1.123 ready_p95-ms 0.6670 residual_p50-ms 0.9134 residual_p95-ms 33760 signatures/block 168250 signatures/s 0.0008210 submit_p50-ms 0.002454 submit_p95-ms 45684682 B/op 75142 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/tip_200ms_overlap-8 3 200414118 ns/op 0.9499 avg_cpu_cores 689.0 components/block 190.4 cpu-ms/block 0.2950 feed_lag_p50-ms 0.7820 feed_lag_p95-ms 7.001 mean_width 0.5114 ready_p50-ms 1.017 ready_p95-ms 0.2302 residual_p50-ms 0.8310 residual_p95-ms 33760 signatures/block 168451 signatures/s 0.0005310 submit_p50-ms 0.001473 submit_p95-ms 45775912 B/op 75143 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/tip_200ms_overlap-8 3 200256049 ns/op 0.9622 avg_cpu_cores 689.0 components/block 192.7 cpu-ms/block 0.2963 feed_lag_p50-ms 0.7859 feed_lag_p95-ms 7.001 mean_width 0.5143 ready_p50-ms 1.015 ready_p95-ms 0.1938 residual_p50-ms 0.4353 residual_p95-ms 33760 signatures/block 168584 signatures/s 0.0005610 submit_p50-ms 0.001704 submit_p95-ms 45825840 B/op 75182 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_4tx_200ms_overlap-8 3 200387649 ns/op 0.02538 avg_cpu_cores 64.00 components/block 5.086 cpu-ms/block 0.5414 feed_lag_p50-ms 0.9647 feed_lag_p95-ms 4.000 mean_width 0.5928 ready_p50-ms 1.033 ready_p95-ms 0.5171 residual_p50-ms 0.5489 residual_p95-ms 256.0 signatures/block 1278 signatures/s 0.001523 submit_p50-ms 0.005641 submit_p95-ms 439648 B/op 1230 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_4tx_200ms_overlap-8 3 200883060 ns/op 0.03008 avg_cpu_cores 64.00 components/block 6.043 cpu-ms/block 0.5974 feed_lag_p50-ms 0.9731 feed_lag_p95-ms 4.000 mean_width 0.6814 ready_p50-ms 1.066 ready_p95-ms 1.116 residual_p50-ms 1.146 residual_p95-ms 256.0 signatures/block 1274 signatures/s 0.002054 submit_p50-ms 0.007835 submit_p95-ms 439349 B/op 1228 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_4tx_200ms_overlap-8 3 200468704 ns/op 0.02652 avg_cpu_cores 64.00 components/block 5.317 cpu-ms/block 0.5614 feed_lag_p50-ms 0.9687 feed_lag_p95-ms 4.000 mean_width 0.6253 ready_p50-ms 1.041 ready_p95-ms 0.3181 residual_p50-ms 0.7522 residual_p95-ms 256.0 signatures/block 1277 signatures/s 0.002074 submit_p50-ms 0.004910 submit_p95-ms 439341 B/op 1227 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_7tx_200ms_overlap-8 3 200580146 ns/op 0.02269 avg_cpu_cores 37.00 components/block 4.551 cpu-ms/block 0.5230 feed_lag_p50-ms 1.004 feed_lag_p95-ms 6.919 mean_width 0.6231 ready_p50-ms 1.099 ready_p95-ms 0.4480 residual_p50-ms 1.093 residual_p95-ms 256.0 signatures/block 1276 signatures/s 0.001423 submit_p50-ms 0.004990 submit_p95-ms 395837 B/op 930 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_7tx_200ms_overlap-8 3 200704543 ns/op 0.02296 avg_cpu_cores 37.00 components/block 4.607 cpu-ms/block 0.5328 feed_lag_p50-ms 1.022 feed_lag_p95-ms 6.919 mean_width 0.6489 ready_p50-ms 1.107 ready_p95-ms 0.6480 residual_p50-ms 1.079 residual_p95-ms 256.0 signatures/block 1276 signatures/s 0.001783 submit_p50-ms 0.008186 submit_p95-ms 395837 B/op 930 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_7tx_200ms_overlap-8 3 200601736 ns/op 0.02604 avg_cpu_cores 37.00 components/block 5.224 cpu-ms/block 0.5685 feed_lag_p50-ms 1.009 feed_lag_p95-ms 6.919 mean_width 0.6868 ready_p50-ms 1.128 ready_p95-ms 0.6345 residual_p50-ms 0.9120 residual_p95-ms 256.0 signatures/block 1276 signatures/s 0.001794 submit_p50-ms 0.01362 submit_p95-ms 395912 B/op 931 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_8tx_200ms_overlap-8 3 200649189 ns/op 0.02026 avg_cpu_cores 32.00 components/block 4.065 cpu-ms/block 0.5870 feed_lag_p50-ms 1.023 feed_lag_p95-ms 8.000 mean_width 0.6574 ready_p50-ms 1.106 ready_p95-ms 0.5239 residual_p50-ms 0.9372 residual_p95-ms 256.0 signatures/block 1276 signatures/s 0.002274 submit_p50-ms 0.02225 submit_p95-ms 387637 B/op 876 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_8tx_200ms_overlap-8 3 200762942 ns/op 0.01440 avg_cpu_cores 32.00 components/block 2.890 cpu-ms/block 0.5812 feed_lag_p50-ms 1.006 feed_lag_p95-ms 8.000 mean_width 0.6570 ready_p50-ms 1.083 ready_p95-ms 0.6634 residual_p50-ms 1.040 residual_p95-ms 256.0 signatures/block 1275 signatures/s 0.001613 submit_p50-ms 0.01741 submit_p95-ms 387629 B/op 875 allocs/op +BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_8tx_200ms_overlap-8 3 200762972 ns/op 0.01549 avg_cpu_cores 32.00 components/block 3.109 cpu-ms/block 0.6425 feed_lag_p50-ms 1.017 feed_lag_p95-ms 8.000 mean_width 0.6983 ready_p50-ms 1.092 ready_p95-ms 0.6307 residual_p50-ms 1.064 residual_p95-ms 256.0 signatures/block 1275 signatures/s 0.001583 submit_p50-ms 0.01700 submit_p95-ms 387629 B/op 875 allocs/op +PASS diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/health-after-final.txt b/docs/results/sigverify-streaming/2026-09-12-zen5/health-after-final.txt new file mode 100644 index 00000000..2cc76eee --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/health-after-final.txt @@ -0,0 +1,4 @@ +ActiveState=active +SubState=running +MainPID=3343610 +ExecMainStartTimestamp=Sat 2026-09-12 05:41:10 UTC diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/local-replay.log b/docs/results/sigverify-streaming/2026-09-12-zen5/local-replay.log new file mode 100644 index 00000000..88af8e8a --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/local-replay.log @@ -0,0 +1 @@ +ok github.com/Overclock-Validator/mithril/pkg/replay 1.251s diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/local-turbine-race.log b/docs/results/sigverify-streaming/2026-09-12-zen5/local-turbine-race.log new file mode 100644 index 00000000..8ff7b29e --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/local-turbine-race.log @@ -0,0 +1 @@ +ok github.com/Overclock-Validator/mithril/pkg/turbine 8.226s diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/local-unit.log b/docs/results/sigverify-streaming/2026-09-12-zen5/local-unit.log new file mode 100644 index 00000000..5d57f161 --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/local-unit.log @@ -0,0 +1,7 @@ +ok github.com/Overclock-Validator/mithril/pkg/turbine 1.442s +ok github.com/Overclock-Validator/mithril/pkg/sigverify (cached) +ok github.com/Overclock-Validator/mithril/pkg/txverify (cached) +ok github.com/Overclock-Validator/mithril/pkg/tpu/sigverify (cached) +ok github.com/Overclock-Validator/mithril/cmd/mithril/node 0.653s +ok github.com/Overclock-Validator/mithril/pkg/block (cached) +ok github.com/Overclock-Validator/mithril/pkg/statsd (cached) diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/native-final-race.log b/docs/results/sigverify-streaming/2026-09-12-zen5/native-final-race.log new file mode 100644 index 00000000..356c3b4b --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/native-final-race.log @@ -0,0 +1 @@ +ok github.com/Overclock-Validator/mithril/pkg/turbine 2.051s diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/native-final-unit.log b/docs/results/sigverify-streaming/2026-09-12-zen5/native-final-unit.log new file mode 100644 index 00000000..cf82467a --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/native-final-unit.log @@ -0,0 +1,6 @@ +ok github.com/Overclock-Validator/mithril/pkg/turbine 0.966s +ok github.com/Overclock-Validator/mithril/pkg/sigverify 0.634s +ok github.com/Overclock-Validator/mithril/pkg/txverify 0.003s +ok github.com/Overclock-Validator/mithril/pkg/block 0.025s +ok github.com/Overclock-Validator/mithril/pkg/statsd 0.003s +ok github.com/Overclock-Validator/mithril/cmd/mithril/node 0.029s diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/pool-comparison.json b/docs/results/sigverify-streaming/2026-09-12-zen5/pool-comparison.json new file mode 100644 index 00000000..e90d1508 --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/pool-comparison.json @@ -0,0 +1,5503 @@ +{ + "description": "Medians across repeated samples; captured rows aggregate three equal-transaction-count blocks. Arrival schedules are synthetic. Process CPU excludes the separate execution probe.", + "rows": [ + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/catchup-8", + "iterations": 3, + "ns/op": 156715891.0, + "avg_cpu_cores": 2.043, + "components/block": 1.0, + "cpu-ms/block": 320.2, + "feed_lag_p50-ms": 0.000271, + "feed_lag_p95-ms": 0.001282, + "mean_width": 4.0, + "ready_p50-ms": 158.0, + "ready_p95-ms": 164.2, + "residual_p50-ms": 158.0, + "residual_p95-ms": 164.2, + "signatures/block": 33760.0, + "signatures/s": 215422.0, + "submit_p50-ms": 0.01062, + "submit_p95-ms": 0.02492, + "B/op": 7023138.0, + "allocs/op": 67538.0, + "source": "captured_2622581", + "workers": 2, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/catchup-8", + "iterations": 3, + "ns/op": 155986070.0, + "avg_cpu_cores": 2.047, + "components/block": 1.0, + "cpu-ms/block": 319.2, + "feed_lag_p50-ms": 0.000251, + "feed_lag_p95-ms": 0.000781, + "mean_width": 4.0, + "ready_p50-ms": 151.6, + "ready_p95-ms": 171.1, + "residual_p50-ms": 151.6, + "residual_p95-ms": 171.1, + "signatures/block": 33760.0, + "signatures/s": 216430.0, + "submit_p50-ms": 0.006532, + "submit_p95-ms": 0.007404, + "B/op": 7023144.0, + "allocs/op": 67538.0, + "source": "captured_2622581", + "workers": 2, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/catchup-8", + "iterations": 3, + "ns/op": 145764753.0, + "avg_cpu_cores": 2.047, + "components/block": 1.0, + "cpu-ms/block": 298.4, + "feed_lag_p50-ms": 0.000281, + "feed_lag_p95-ms": 0.000681, + "mean_width": 4.0, + "ready_p50-ms": 145.4, + "ready_p95-ms": 146.6, + "residual_p50-ms": 145.4, + "residual_p95-ms": 146.6, + "signatures/block": 33760.0, + "signatures/s": 231606.0, + "submit_p50-ms": 0.004178, + "submit_p95-ms": 0.007975, + "B/op": 7023133.0, + "allocs/op": 67538.0, + "source": "captured_2622581", + "workers": 2, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 344523723.0, + "avg_cpu_cores": 0.8561, + "components/block": 126.0, + "cpu-ms/block": 295.0, + "feed_lag_p50-ms": 100.2, + "feed_lag_p95-ms": 191.4, + "mean_width": 4.0, + "ready_p50-ms": 244.4, + "ready_p95-ms": 335.6, + "residual_p50-ms": 144.7, + "residual_p95-ms": 145.2, + "signatures/block": 33760.0, + "signatures/s": 97990.0, + "submit_p50-ms": 0.01582, + "submit_p95-ms": 0.01597, + "B/op": 7033338.0, + "allocs/op": 67539.0, + "source": "captured_2622581", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 352992831.0, + "avg_cpu_cores": 0.8764, + "components/block": 126.0, + "cpu-ms/block": 309.4, + "feed_lag_p50-ms": 100.2, + "feed_lag_p95-ms": 191.4, + "mean_width": 4.0, + "ready_p50-ms": 252.4, + "ready_p95-ms": 343.6, + "residual_p50-ms": 144.6, + "residual_p95-ms": 170.7, + "signatures/block": 33760.0, + "signatures/s": 95639.0, + "submit_p50-ms": 0.0175, + "submit_p95-ms": 0.01914, + "B/op": 7033616.0, + "allocs/op": 67540.0, + "source": "captured_2622581", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 363417787.0, + "avg_cpu_cores": 0.9118, + "components/block": 126.0, + "cpu-ms/block": 331.4, + "feed_lag_p50-ms": 99.82, + "feed_lag_p95-ms": 191.0, + "mean_width": 4.0, + "ready_p50-ms": 263.0, + "ready_p95-ms": 355.8, + "residual_p50-ms": 163.8, + "residual_p95-ms": 175.6, + "signatures/block": 33760.0, + "signatures/s": 92896.0, + "submit_p50-ms": 0.02098, + "submit_p95-ms": 0.02324, + "B/op": 7033530.0, + "allocs/op": 67539.0, + "source": "captured_2622581", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 201111285.0, + "avg_cpu_cores": 1.522, + "components/block": 126.0, + "cpu-ms/block": 306.1, + "feed_lag_p50-ms": 0.03627, + "feed_lag_p95-ms": 0.8607, + "mean_width": 3.956, + "ready_p50-ms": 1.602, + "ready_p95-ms": 2.473, + "residual_p50-ms": 1.08, + "residual_p95-ms": 1.219, + "signatures/block": 33760.0, + "signatures/s": 167867.0, + "submit_p50-ms": 0.001032, + "submit_p95-ms": 0.003166, + "B/op": 7165506.0, + "allocs/op": 68945.0, + "source": "captured_2622581", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 201378639.0, + "avg_cpu_cores": 1.498, + "components/block": 126.0, + "cpu-ms/block": 301.7, + "feed_lag_p50-ms": 0.2205, + "feed_lag_p95-ms": 0.8775, + "mean_width": 3.956, + "ready_p50-ms": 1.582, + "ready_p95-ms": 2.532, + "residual_p50-ms": 1.361, + "residual_p95-ms": 1.407, + "signatures/block": 33760.0, + "signatures/s": 167644.0, + "submit_p50-ms": 0.001123, + "submit_p95-ms": 0.002805, + "B/op": 7167869.0, + "allocs/op": 68945.0, + "source": "captured_2622581", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 201155070.0, + "avg_cpu_cores": 1.486, + "components/block": 126.0, + "cpu-ms/block": 299.0, + "feed_lag_p50-ms": 0.05468, + "feed_lag_p95-ms": 0.831, + "mean_width": 3.956, + "ready_p50-ms": 1.579, + "ready_p95-ms": 2.456, + "residual_p50-ms": 1.334, + "residual_p95-ms": 1.38, + "signatures/block": 33760.0, + "signatures/s": 167831.0, + "submit_p50-ms": 0.001042, + "submit_p95-ms": 0.002434, + "B/op": 7159269.0, + "allocs/op": 68921.0, + "source": "captured_2622581", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/catchup-8", + "iterations": 3, + "ns/op": 74916706.0, + "avg_cpu_cores": 2.041, + "components/block": 1.0, + "cpu-ms/block": 152.9, + "feed_lag_p50-ms": 0.000251, + "feed_lag_p95-ms": 0.000481, + "mean_width": 8.0, + "ready_p50-ms": 74.9, + "ready_p95-ms": 75.95, + "residual_p50-ms": 74.9, + "residual_p95-ms": 75.95, + "signatures/block": 33760.0, + "signatures/s": 450634.0, + "submit_p50-ms": 0.004738, + "submit_p95-ms": 0.006292, + "B/op": 7023266.0, + "allocs/op": 67538.0, + "source": "captured_2622581", + "workers": 2, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/catchup-8", + "iterations": 3, + "ns/op": 75787979.0, + "avg_cpu_cores": 2.041, + "components/block": 1.0, + "cpu-ms/block": 154.7, + "feed_lag_p50-ms": 0.00039, + "feed_lag_p95-ms": 0.000531, + "mean_width": 8.0, + "ready_p50-ms": 75.44, + "ready_p95-ms": 76.9, + "residual_p50-ms": 75.44, + "residual_p95-ms": 76.9, + "signatures/block": 33760.0, + "signatures/s": 445453.0, + "submit_p50-ms": 0.006492, + "submit_p95-ms": 0.006763, + "B/op": 7023258.0, + "allocs/op": 67538.0, + "source": "captured_2622581", + "workers": 2, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/catchup-8", + "iterations": 3, + "ns/op": 83724900.0, + "avg_cpu_cores": 2.025, + "components/block": 1.0, + "cpu-ms/block": 169.5, + "feed_lag_p50-ms": 0.00033, + "feed_lag_p95-ms": 0.000431, + "mean_width": 8.0, + "ready_p50-ms": 86.47, + "ready_p95-ms": 87.41, + "residual_p50-ms": 86.47, + "residual_p95-ms": 87.41, + "signatures/block": 33760.0, + "signatures/s": 403225.0, + "submit_p50-ms": 0.007554, + "submit_p95-ms": 0.007595, + "B/op": 7023253.0, + "allocs/op": 67538.0, + "source": "captured_2622581", + "workers": 2, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 275675193.0, + "avg_cpu_cores": 0.5545, + "components/block": 126.0, + "cpu-ms/block": 152.9, + "feed_lag_p50-ms": 100.2, + "feed_lag_p95-ms": 191.4, + "mean_width": 8.0, + "ready_p50-ms": 175.6, + "ready_p95-ms": 266.8, + "residual_p50-ms": 75.25, + "residual_p95-ms": 76.98, + "signatures/block": 33760.0, + "signatures/s": 122463.0, + "submit_p50-ms": 0.01418, + "submit_p95-ms": 0.01462, + "B/op": 7033472.0, + "allocs/op": 67539.0, + "source": "captured_2622581", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 288578162.0, + "avg_cpu_cores": 0.6196, + "components/block": 126.0, + "cpu-ms/block": 178.8, + "feed_lag_p50-ms": 100.2, + "feed_lag_p95-ms": 191.4, + "mean_width": 8.0, + "ready_p50-ms": 188.3, + "ready_p95-ms": 279.5, + "residual_p50-ms": 86.33, + "residual_p95-ms": 98.29, + "signatures/block": 33760.0, + "signatures/s": 116987.0, + "submit_p50-ms": 0.01635, + "submit_p95-ms": 0.01759, + "B/op": 7033461.0, + "allocs/op": 67539.0, + "source": "captured_2622581", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 275152604.0, + "avg_cpu_cores": 0.5544, + "components/block": 126.0, + "cpu-ms/block": 152.5, + "feed_lag_p50-ms": 100.1, + "feed_lag_p95-ms": 191.3, + "mean_width": 8.0, + "ready_p50-ms": 175.0, + "ready_p95-ms": 266.2, + "residual_p50-ms": 75.23, + "residual_p95-ms": 76.0, + "signatures/block": 33760.0, + "signatures/s": 122696.0, + "submit_p50-ms": 0.01576, + "submit_p95-ms": 0.01683, + "B/op": 7079245.0, + "allocs/op": 67541.0, + "source": "captured_2622581", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 201070435.0, + "avg_cpu_cores": 0.8694, + "components/block": 126.0, + "cpu-ms/block": 174.8, + "feed_lag_p50-ms": 0.4408, + "feed_lag_p95-ms": 0.9889, + "mean_width": 7.912, + "ready_p50-ms": 1.219, + "ready_p95-ms": 1.939, + "residual_p50-ms": 1.278, + "residual_p95-ms": 1.368, + "signatures/block": 33760.0, + "signatures/s": 167901.0, + "submit_p50-ms": 0.001523, + "submit_p95-ms": 0.005731, + "B/op": 7175717.0, + "allocs/op": 68921.0, + "source": "captured_2622581", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 201082624.0, + "avg_cpu_cores": 0.7981, + "components/block": 126.0, + "cpu-ms/block": 160.5, + "feed_lag_p50-ms": 0.5138, + "feed_lag_p95-ms": 1.002, + "mean_width": 7.912, + "ready_p50-ms": 1.116, + "ready_p95-ms": 1.674, + "residual_p50-ms": 1.053, + "residual_p95-ms": 1.128, + "signatures/block": 33760.0, + "signatures/s": 167891.0, + "submit_p50-ms": 0.001002, + "submit_p95-ms": 0.002716, + "B/op": 7175933.0, + "allocs/op": 68923.0, + "source": "captured_2622581", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_2/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 201301027.0, + "avg_cpu_cores": 0.796, + "components/block": 126.0, + "cpu-ms/block": 160.2, + "feed_lag_p50-ms": 0.5253, + "feed_lag_p95-ms": 0.9638, + "mean_width": 7.912, + "ready_p50-ms": 1.16, + "ready_p95-ms": 1.61, + "residual_p50-ms": 1.264, + "residual_p95-ms": 1.409, + "signatures/block": 33760.0, + "signatures/s": 167709.0, + "submit_p50-ms": 0.001052, + "submit_p95-ms": 0.002464, + "B/op": 7176285.0, + "allocs/op": 68929.0, + "source": "captured_2622581", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/catchup-8", + "iterations": 3, + "ns/op": 79099409.0, + "avg_cpu_cores": 3.964, + "components/block": 1.0, + "cpu-ms/block": 313.6, + "feed_lag_p50-ms": 0.000261, + "feed_lag_p95-ms": 0.000831, + "mean_width": 4.0, + "ready_p50-ms": 76.63, + "ready_p95-ms": 85.46, + "residual_p50-ms": 76.63, + "residual_p95-ms": 85.46, + "signatures/block": 33760.0, + "signatures/s": 426805.0, + "submit_p50-ms": 0.006302, + "submit_p95-ms": 0.006773, + "B/op": 7023410.0, + "allocs/op": 67538.0, + "source": "captured_2622581", + "workers": 4, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/catchup-8", + "iterations": 3, + "ns/op": 80922132.0, + "avg_cpu_cores": 3.958, + "components/block": 1.0, + "cpu-ms/block": 320.3, + "feed_lag_p50-ms": 0.0003, + "feed_lag_p95-ms": 0.000652, + "mean_width": 4.0, + "ready_p50-ms": 77.5, + "ready_p95-ms": 87.97, + "residual_p50-ms": 77.5, + "residual_p95-ms": 87.97, + "signatures/block": 33760.0, + "signatures/s": 417191.0, + "submit_p50-ms": 0.006211, + "submit_p95-ms": 0.01736, + "B/op": 7023410.0, + "allocs/op": 67538.0, + "source": "captured_2622581", + "workers": 4, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/catchup-8", + "iterations": 3, + "ns/op": 75579922.0, + "avg_cpu_cores": 4.026, + "components/block": 1.0, + "cpu-ms/block": 304.3, + "feed_lag_p50-ms": 0.000391, + "feed_lag_p95-ms": 0.000491, + "mean_width": 4.0, + "ready_p50-ms": 75.53, + "ready_p95-ms": 75.76, + "residual_p50-ms": 75.53, + "residual_p95-ms": 75.76, + "signatures/block": 33760.0, + "signatures/s": 446679.0, + "submit_p50-ms": 0.004758, + "submit_p95-ms": 0.00543, + "B/op": 7023405.0, + "allocs/op": 67538.0, + "source": "captured_2622581", + "workers": 4, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 277358928.0, + "avg_cpu_cores": 1.11, + "components/block": 126.0, + "cpu-ms/block": 307.9, + "feed_lag_p50-ms": 99.99, + "feed_lag_p95-ms": 191.2, + "mean_width": 4.0, + "ready_p50-ms": 176.8, + "ready_p95-ms": 268.0, + "residual_p50-ms": 76.98, + "residual_p95-ms": 79.21, + "signatures/block": 33760.0, + "signatures/s": 121720.0, + "submit_p50-ms": 0.01168, + "submit_p95-ms": 0.01332, + "B/op": 7033597.0, + "allocs/op": 67538.0, + "source": "captured_2622581", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 281786997.0, + "avg_cpu_cores": 1.134, + "components/block": 126.0, + "cpu-ms/block": 319.5, + "feed_lag_p50-ms": 100.1, + "feed_lag_p95-ms": 191.3, + "mean_width": 4.0, + "ready_p50-ms": 181.5, + "ready_p95-ms": 272.7, + "residual_p50-ms": 77.53, + "residual_p95-ms": 90.55, + "signatures/block": 33760.0, + "signatures/s": 119807.0, + "submit_p50-ms": 0.01547, + "submit_p95-ms": 0.017, + "B/op": 7033605.0, + "allocs/op": 67539.0, + "source": "captured_2622581", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 275851016.0, + "avg_cpu_cores": 1.1, + "components/block": 126.0, + "cpu-ms/block": 303.6, + "feed_lag_p50-ms": 100.1, + "feed_lag_p95-ms": 191.3, + "mean_width": 4.0, + "ready_p50-ms": 175.8, + "ready_p95-ms": 267.0, + "residual_p50-ms": 75.74, + "residual_p95-ms": 76.57, + "signatures/block": 33760.0, + "signatures/s": 122385.0, + "submit_p50-ms": 0.01534, + "submit_p95-ms": 0.01584, + "B/op": 7033605.0, + "allocs/op": 67539.0, + "source": "captured_2622581", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200706590.0, + "avg_cpu_cores": 1.498, + "components/block": 126.0, + "cpu-ms/block": 300.7, + "feed_lag_p50-ms": 0.5031, + "feed_lag_p95-ms": 0.9977, + "mean_width": 3.956, + "ready_p50-ms": 1.105, + "ready_p95-ms": 1.659, + "residual_p50-ms": 0.5523, + "residual_p95-ms": 1.056, + "signatures/block": 33760.0, + "signatures/s": 168206.0, + "submit_p50-ms": 0.001102, + "submit_p95-ms": 0.003366, + "B/op": 7200192.0, + "allocs/op": 68942.0, + "source": "captured_2622581", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200821431.0, + "avg_cpu_cores": 1.836, + "components/block": 126.0, + "cpu-ms/block": 368.8, + "feed_lag_p50-ms": 0.3622, + "feed_lag_p95-ms": 1.002, + "mean_width": 3.956, + "ready_p50-ms": 1.224, + "ready_p95-ms": 2.145, + "residual_p50-ms": 0.9866, + "residual_p95-ms": 1.055, + "signatures/block": 33760.0, + "signatures/s": 168110.0, + "submit_p50-ms": 0.002164, + "submit_p95-ms": 0.004518, + "B/op": 7200909.0, + "allocs/op": 68946.0, + "source": "captured_2622581", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 201025437.0, + "avg_cpu_cores": 1.586, + "components/block": 126.0, + "cpu-ms/block": 318.8, + "feed_lag_p50-ms": 0.4136, + "feed_lag_p95-ms": 0.9729, + "mean_width": 3.956, + "ready_p50-ms": 1.214, + "ready_p95-ms": 1.677, + "residual_p50-ms": 1.053, + "residual_p95-ms": 1.325, + "signatures/block": 33760.0, + "signatures/s": 167939.0, + "submit_p50-ms": 0.001483, + "submit_p95-ms": 0.004278, + "B/op": 7195901.0, + "allocs/op": 68936.0, + "source": "captured_2622581", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/catchup-8", + "iterations": 3, + "ns/op": 38632690.0, + "avg_cpu_cores": 4.029, + "components/block": 1.0, + "cpu-ms/block": 155.7, + "feed_lag_p50-ms": 0.00017, + "feed_lag_p95-ms": 0.00046, + "mean_width": 8.0, + "ready_p50-ms": 38.5, + "ready_p95-ms": 38.98, + "residual_p50-ms": 38.5, + "residual_p95-ms": 38.98, + "signatures/block": 33760.0, + "signatures/s": 873871.0, + "submit_p50-ms": 0.004749, + "submit_p95-ms": 0.004749, + "B/op": 7023658.0, + "allocs/op": 67538.0, + "source": "captured_2622581", + "workers": 4, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/catchup-8", + "iterations": 3, + "ns/op": 38613093.0, + "avg_cpu_cores": 4.016, + "components/block": 1.0, + "cpu-ms/block": 155.1, + "feed_lag_p50-ms": 0.00026, + "feed_lag_p95-ms": 0.000591, + "mean_width": 8.0, + "ready_p50-ms": 38.29, + "ready_p95-ms": 39.67, + "residual_p50-ms": 38.29, + "residual_p95-ms": 39.67, + "signatures/block": 33760.0, + "signatures/s": 874315.0, + "submit_p50-ms": 0.004198, + "submit_p95-ms": 0.00515, + "B/op": 7023658.0, + "allocs/op": 67538.0, + "source": "captured_2622581", + "workers": 4, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/catchup-8", + "iterations": 3, + "ns/op": 40094161.0, + "avg_cpu_cores": 3.977, + "components/block": 1.0, + "cpu-ms/block": 159.5, + "feed_lag_p50-ms": 0.000241, + "feed_lag_p95-ms": 0.000391, + "mean_width": 8.0, + "ready_p50-ms": 40.29, + "ready_p95-ms": 40.86, + "residual_p50-ms": 40.29, + "residual_p95-ms": 40.86, + "signatures/block": 33760.0, + "signatures/s": 842018.0, + "submit_p50-ms": 0.004117, + "submit_p95-ms": 0.004779, + "B/op": 7023653.0, + "allocs/op": 67538.0, + "source": "captured_2622581", + "workers": 4, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 240210161.0, + "avg_cpu_cores": 0.6517, + "components/block": 126.0, + "cpu-ms/block": 156.5, + "feed_lag_p50-ms": 100.2, + "feed_lag_p95-ms": 191.4, + "mean_width": 8.0, + "ready_p50-ms": 139.7, + "ready_p95-ms": 230.9, + "residual_p50-ms": 39.96, + "residual_p95-ms": 41.7, + "signatures/block": 33760.0, + "signatures/s": 140544.0, + "submit_p50-ms": 0.01466, + "submit_p95-ms": 0.01629, + "B/op": 7033861.0, + "allocs/op": 67539.0, + "source": "captured_2622581", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 244046162.0, + "avg_cpu_cores": 0.6703, + "components/block": 126.0, + "cpu-ms/block": 163.6, + "feed_lag_p50-ms": 100.1, + "feed_lag_p95-ms": 191.3, + "mean_width": 8.0, + "ready_p50-ms": 143.7, + "ready_p95-ms": 234.9, + "residual_p50-ms": 41.63, + "residual_p95-ms": 50.78, + "signatures/block": 33760.0, + "signatures/s": 138334.0, + "submit_p50-ms": 0.01559, + "submit_p95-ms": 0.1937, + "B/op": 7033853.0, + "allocs/op": 67538.0, + "source": "captured_2622581", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 250358365.0, + "avg_cpu_cores": 0.7621, + "components/block": 126.0, + "cpu-ms/block": 190.8, + "feed_lag_p50-ms": 100.1, + "feed_lag_p95-ms": 191.3, + "mean_width": 8.0, + "ready_p50-ms": 150.0, + "ready_p95-ms": 241.2, + "residual_p50-ms": 50.84, + "residual_p95-ms": 52.16, + "signatures/block": 33760.0, + "signatures/s": 134847.0, + "submit_p50-ms": 0.01572, + "submit_p95-ms": 0.01687, + "B/op": 7033853.0, + "allocs/op": 67538.0, + "source": "captured_2622581", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200893667.0, + "avg_cpu_cores": 0.8816, + "components/block": 126.0, + "cpu-ms/block": 177.1, + "feed_lag_p50-ms": 0.4989, + "feed_lag_p95-ms": 0.9857, + "mean_width": 7.912, + "ready_p50-ms": 0.9093, + "ready_p95-ms": 1.428, + "residual_p50-ms": 0.8878, + "residual_p95-ms": 1.069, + "signatures/block": 33760.0, + "signatures/s": 168049.0, + "submit_p50-ms": 0.001713, + "submit_p95-ms": 0.00557, + "B/op": 7225490.0, + "allocs/op": 68918.0, + "source": "captured_2622581", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 201019836.0, + "avg_cpu_cores": 0.8626, + "components/block": 126.0, + "cpu-ms/block": 173.4, + "feed_lag_p50-ms": 0.5209, + "feed_lag_p95-ms": 1.002, + "mean_width": 7.912, + "ready_p50-ms": 0.912, + "ready_p95-ms": 1.381, + "residual_p50-ms": 1.081, + "residual_p95-ms": 1.125, + "signatures/block": 33760.0, + "signatures/s": 167944.0, + "submit_p50-ms": 0.001563, + "submit_p95-ms": 0.004458, + "B/op": 7226130.0, + "allocs/op": 68919.0, + "source": "captured_2622581", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622581/workers_4/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200749032.0, + "avg_cpu_cores": 0.881, + "components/block": 126.0, + "cpu-ms/block": 176.9, + "feed_lag_p50-ms": 0.5054, + "feed_lag_p95-ms": 0.9943, + "mean_width": 7.912, + "ready_p50-ms": 0.9516, + "ready_p95-ms": 1.431, + "residual_p50-ms": 0.582, + "residual_p95-ms": 1.073, + "signatures/block": 33760.0, + "signatures/s": 168170.0, + "submit_p50-ms": 0.001633, + "submit_p95-ms": 0.00569, + "B/op": 7226581.0, + "allocs/op": 68928.0, + "source": "captured_2622581", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/catchup-8", + "iterations": 3, + "ns/op": 155918266.0, + "avg_cpu_cores": 2.038, + "components/block": 1.0, + "cpu-ms/block": 317.8, + "feed_lag_p50-ms": 0.000401, + "feed_lag_p95-ms": 0.000491, + "mean_width": 4.0, + "ready_p50-ms": 156.2, + "ready_p95-ms": 157.5, + "residual_p50-ms": 156.2, + "residual_p95-ms": 157.5, + "signatures/block": 33760.0, + "signatures/s": 216524.0, + "submit_p50-ms": 0.007043, + "submit_p95-ms": 0.007063, + "B/op": 7023138.0, + "allocs/op": 67538.0, + "source": "captured_2622653", + "workers": 2, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/catchup-8", + "iterations": 3, + "ns/op": 144724837.0, + "avg_cpu_cores": 2.047, + "components/block": 1.0, + "cpu-ms/block": 296.2, + "feed_lag_p50-ms": 0.000241, + "feed_lag_p95-ms": 0.000461, + "mean_width": 4.0, + "ready_p50-ms": 144.7, + "ready_p95-ms": 145.3, + "residual_p50-ms": 144.7, + "residual_p95-ms": 145.3, + "signatures/block": 33760.0, + "signatures/s": 233270.0, + "submit_p50-ms": 0.004688, + "submit_p95-ms": 0.006221, + "B/op": 7023133.0, + "allocs/op": 67538.0, + "source": "captured_2622653", + "workers": 2, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/catchup-8", + "iterations": 3, + "ns/op": 167371225.0, + "avg_cpu_cores": 2.049, + "components/block": 1.0, + "cpu-ms/block": 343.0, + "feed_lag_p50-ms": 0.00027, + "feed_lag_p95-ms": 0.000781, + "mean_width": 4.0, + "ready_p50-ms": 168.7, + "ready_p95-ms": 179.5, + "residual_p50-ms": 168.7, + "residual_p95-ms": 179.5, + "signatures/block": 33760.0, + "signatures/s": 201707.0, + "submit_p50-ms": 0.005831, + "submit_p95-ms": 0.006833, + "B/op": 7023133.0, + "allocs/op": 67538.0, + "source": "captured_2622653", + "workers": 2, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 348985373.0, + "avg_cpu_cores": 0.8724, + "components/block": 126.0, + "cpu-ms/block": 304.4, + "feed_lag_p50-ms": 100.1, + "feed_lag_p95-ms": 191.3, + "mean_width": 4.0, + "ready_p50-ms": 248.9, + "ready_p95-ms": 340.1, + "residual_p50-ms": 150.1, + "residual_p95-ms": 152.0, + "signatures/block": 33760.0, + "signatures/s": 96738.0, + "submit_p50-ms": 0.01628, + "submit_p95-ms": 0.01804, + "B/op": 7033333.0, + "allocs/op": 67539.0, + "source": "captured_2622653", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 353413098.0, + "avg_cpu_cores": 0.8855, + "components/block": 126.0, + "cpu-ms/block": 312.9, + "feed_lag_p50-ms": 100.1, + "feed_lag_p95-ms": 191.3, + "mean_width": 4.0, + "ready_p50-ms": 253.3, + "ready_p95-ms": 344.5, + "residual_p50-ms": 155.7, + "residual_p95-ms": 158.2, + "signatures/block": 33760.0, + "signatures/s": 95526.0, + "submit_p50-ms": 0.02336, + "submit_p95-ms": 0.03805, + "B/op": 7079125.0, + "allocs/op": 67541.0, + "source": "captured_2622653", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 349811570.0, + "avg_cpu_cores": 0.8763, + "components/block": 126.0, + "cpu-ms/block": 306.6, + "feed_lag_p50-ms": 99.8, + "feed_lag_p95-ms": 191.0, + "mean_width": 4.0, + "ready_p50-ms": 249.2, + "ready_p95-ms": 340.4, + "residual_p50-ms": 151.6, + "residual_p95-ms": 153.0, + "signatures/block": 33760.0, + "signatures/s": 96509.0, + "submit_p50-ms": 0.01705, + "submit_p95-ms": 0.01774, + "B/op": 7033333.0, + "allocs/op": 67539.0, + "source": "captured_2622653", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200998043.0, + "avg_cpu_cores": 1.604, + "components/block": 126.0, + "cpu-ms/block": 322.3, + "feed_lag_p50-ms": 0.03342, + "feed_lag_p95-ms": 0.8444, + "mean_width": 3.956, + "ready_p50-ms": 1.732, + "ready_p95-ms": 3.31, + "residual_p50-ms": 0.7673, + "residual_p95-ms": 1.469, + "signatures/block": 33760.0, + "signatures/s": 167962.0, + "submit_p50-ms": 0.001633, + "submit_p95-ms": 0.004388, + "B/op": 7159493.0, + "allocs/op": 68923.0, + "source": "captured_2622653", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200881915.0, + "avg_cpu_cores": 1.491, + "components/block": 126.0, + "cpu-ms/block": 299.4, + "feed_lag_p50-ms": 0.2175, + "feed_lag_p95-ms": 0.8653, + "mean_width": 3.956, + "ready_p50-ms": 1.578, + "ready_p95-ms": 2.468, + "residual_p50-ms": 0.9112, + "residual_p95-ms": 1.054, + "signatures/block": 33760.0, + "signatures/s": 168059.0, + "submit_p50-ms": 0.001072, + "submit_p95-ms": 0.002876, + "B/op": 7159410.0, + "allocs/op": 68922.0, + "source": "captured_2622653", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200919959.0, + "avg_cpu_cores": 1.509, + "components/block": 126.0, + "cpu-ms/block": 303.1, + "feed_lag_p50-ms": 0.04134, + "feed_lag_p95-ms": 0.8647, + "mean_width": 3.956, + "ready_p50-ms": 1.588, + "ready_p95-ms": 2.515, + "residual_p50-ms": 0.6775, + "residual_p95-ms": 1.408, + "signatures/block": 33760.0, + "signatures/s": 168027.0, + "submit_p50-ms": 0.001152, + "submit_p95-ms": 0.002685, + "B/op": 7160456.0, + "allocs/op": 68931.0, + "source": "captured_2622653", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/catchup-8", + "iterations": 3, + "ns/op": 78536665.0, + "avg_cpu_cores": 2.043, + "components/block": 1.0, + "cpu-ms/block": 160.4, + "feed_lag_p50-ms": 0.000201, + "feed_lag_p95-ms": 0.001353, + "mean_width": 8.0, + "ready_p50-ms": 76.4, + "ready_p95-ms": 84.11, + "residual_p50-ms": 76.4, + "residual_p95-ms": 84.11, + "signatures/block": 33760.0, + "signatures/s": 429863.0, + "submit_p50-ms": 0.005971, + "submit_p95-ms": 0.01674, + "B/op": 7023253.0, + "allocs/op": 67538.0, + "source": "captured_2622653", + "workers": 2, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/catchup-8", + "iterations": 3, + "ns/op": 74931420.0, + "avg_cpu_cores": 2.045, + "components/block": 1.0, + "cpu-ms/block": 153.2, + "feed_lag_p50-ms": 0.000261, + "feed_lag_p95-ms": 0.000491, + "mean_width": 8.0, + "ready_p50-ms": 73.86, + "ready_p95-ms": 77.19, + "residual_p50-ms": 73.86, + "residual_p95-ms": 77.19, + "signatures/block": 33760.0, + "signatures/s": 450545.0, + "submit_p50-ms": 0.00553, + "submit_p95-ms": 0.005611, + "B/op": 7069050.0, + "allocs/op": 67540.0, + "source": "captured_2622653", + "workers": 2, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/catchup-8", + "iterations": 3, + "ns/op": 74095918.0, + "avg_cpu_cores": 2.048, + "components/block": 1.0, + "cpu-ms/block": 151.7, + "feed_lag_p50-ms": 0.000261, + "feed_lag_p95-ms": 0.000551, + "mean_width": 8.0, + "ready_p50-ms": 74.05, + "ready_p95-ms": 74.35, + "residual_p50-ms": 74.05, + "residual_p95-ms": 74.35, + "signatures/block": 33760.0, + "signatures/s": 455626.0, + "submit_p50-ms": 0.00504, + "submit_p95-ms": 0.005761, + "B/op": 7023266.0, + "allocs/op": 67538.0, + "source": "captured_2622653", + "workers": 2, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 276093363.0, + "avg_cpu_cores": 0.5578, + "components/block": 126.0, + "cpu-ms/block": 154.0, + "feed_lag_p50-ms": 100.1, + "feed_lag_p95-ms": 191.3, + "mean_width": 8.0, + "ready_p50-ms": 176.0, + "ready_p95-ms": 267.2, + "residual_p50-ms": 75.77, + "residual_p95-ms": 77.27, + "signatures/block": 33760.0, + "signatures/s": 122277.0, + "submit_p50-ms": 0.0156, + "submit_p95-ms": 0.01629, + "B/op": 7033453.0, + "allocs/op": 67538.0, + "source": "captured_2622653", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 275962471.0, + "avg_cpu_cores": 0.5557, + "components/block": 126.0, + "cpu-ms/block": 153.3, + "feed_lag_p50-ms": 100.2, + "feed_lag_p95-ms": 191.4, + "mean_width": 8.0, + "ready_p50-ms": 175.6, + "ready_p95-ms": 266.8, + "residual_p50-ms": 75.18, + "residual_p95-ms": 77.82, + "signatures/block": 33760.0, + "signatures/s": 122335.0, + "submit_p50-ms": 0.01006, + "submit_p95-ms": 0.01518, + "B/op": 7033461.0, + "allocs/op": 67539.0, + "source": "captured_2622653", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 276459279.0, + "avg_cpu_cores": 0.5617, + "components/block": 126.0, + "cpu-ms/block": 155.3, + "feed_lag_p50-ms": 99.96, + "feed_lag_p95-ms": 191.2, + "mean_width": 8.0, + "ready_p50-ms": 176.3, + "ready_p95-ms": 267.5, + "residual_p50-ms": 76.2, + "residual_p95-ms": 77.62, + "signatures/block": 33760.0, + "signatures/s": 122116.0, + "submit_p50-ms": 0.01565, + "submit_p95-ms": 0.02936, + "B/op": 7033461.0, + "allocs/op": 67539.0, + "source": "captured_2622653", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 201053633.0, + "avg_cpu_cores": 0.7943, + "components/block": 126.0, + "cpu-ms/block": 159.7, + "feed_lag_p50-ms": 0.5123, + "feed_lag_p95-ms": 0.9677, + "mean_width": 7.912, + "ready_p50-ms": 1.131, + "ready_p95-ms": 1.609, + "residual_p50-ms": 1.133, + "residual_p95-ms": 1.338, + "signatures/block": 33760.0, + "signatures/s": 167915.0, + "submit_p50-ms": 0.000982, + "submit_p95-ms": 0.002364, + "B/op": 7175658.0, + "allocs/op": 68923.0, + "source": "captured_2622653", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200775689.0, + "avg_cpu_cores": 0.8035, + "components/block": 126.0, + "cpu-ms/block": 161.3, + "feed_lag_p50-ms": 0.4791, + "feed_lag_p95-ms": 0.9798, + "mean_width": 7.912, + "ready_p50-ms": 1.141, + "ready_p95-ms": 1.63, + "residual_p50-ms": 0.8427, + "residual_p95-ms": 1.052, + "signatures/block": 33760.0, + "signatures/s": 168148.0, + "submit_p50-ms": 0.001102, + "submit_p95-ms": 0.002976, + "B/op": 7179669.0, + "allocs/op": 68929.0, + "source": "captured_2622653", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_2/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200811376.0, + "avg_cpu_cores": 0.811, + "components/block": 126.0, + "cpu-ms/block": 162.9, + "feed_lag_p50-ms": 0.5077, + "feed_lag_p95-ms": 0.973, + "mean_width": 7.912, + "ready_p50-ms": 1.17, + "ready_p95-ms": 1.645, + "residual_p50-ms": 0.653, + "residual_p95-ms": 1.185, + "signatures/block": 33760.0, + "signatures/s": 168118.0, + "submit_p50-ms": 0.001042, + "submit_p95-ms": 0.003306, + "B/op": 7175690.0, + "allocs/op": 68923.0, + "source": "captured_2622653", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/catchup-8", + "iterations": 3, + "ns/op": 75328778.0, + "avg_cpu_cores": 4.02, + "components/block": 1.0, + "cpu-ms/block": 302.8, + "feed_lag_p50-ms": 0.000201, + "feed_lag_p95-ms": 0.000481, + "mean_width": 4.0, + "ready_p50-ms": 75.78, + "ready_p95-ms": 75.98, + "residual_p50-ms": 75.78, + "residual_p95-ms": 75.98, + "signatures/block": 33760.0, + "signatures/s": 448169.0, + "submit_p50-ms": 0.005461, + "submit_p95-ms": 0.006863, + "B/op": 7023397.0, + "allocs/op": 67538.0, + "source": "captured_2622653", + "workers": 4, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/catchup-8", + "iterations": 3, + "ns/op": 75774293.0, + "avg_cpu_cores": 4.044, + "components/block": 1.0, + "cpu-ms/block": 306.4, + "feed_lag_p50-ms": 0.00048, + "feed_lag_p95-ms": 0.000481, + "mean_width": 4.0, + "ready_p50-ms": 76.23, + "ready_p95-ms": 76.72, + "residual_p50-ms": 76.23, + "residual_p95-ms": 76.72, + "signatures/block": 33760.0, + "signatures/s": 445534.0, + "submit_p50-ms": 0.005711, + "submit_p95-ms": 0.006102, + "B/op": 7023402.0, + "allocs/op": 67538.0, + "source": "captured_2622653", + "workers": 4, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/catchup-8", + "iterations": 3, + "ns/op": 78168545.0, + "avg_cpu_cores": 3.951, + "components/block": 1.0, + "cpu-ms/block": 308.8, + "feed_lag_p50-ms": 0.00024, + "feed_lag_p95-ms": 0.000581, + "mean_width": 4.0, + "ready_p50-ms": 77.58, + "ready_p95-ms": 80.96, + "residual_p50-ms": 77.58, + "residual_p95-ms": 80.96, + "signatures/block": 33760.0, + "signatures/s": 431887.0, + "submit_p50-ms": 0.004168, + "submit_p95-ms": 0.00501, + "B/op": 7023397.0, + "allocs/op": 67538.0, + "source": "captured_2622653", + "workers": 4, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 275602430.0, + "avg_cpu_cores": 1.092, + "components/block": 126.0, + "cpu-ms/block": 301.1, + "feed_lag_p50-ms": 100.2, + "feed_lag_p95-ms": 191.4, + "mean_width": 4.0, + "ready_p50-ms": 175.7, + "ready_p95-ms": 266.9, + "residual_p50-ms": 75.17, + "residual_p95-ms": 76.46, + "signatures/block": 33760.0, + "signatures/s": 122495.0, + "submit_p50-ms": 0.01314, + "submit_p95-ms": 0.01613, + "B/op": 7033605.0, + "allocs/op": 67539.0, + "source": "captured_2622653", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 279023273.0, + "avg_cpu_cores": 1.12, + "components/block": 126.0, + "cpu-ms/block": 312.5, + "feed_lag_p50-ms": 100.2, + "feed_lag_p95-ms": 191.4, + "mean_width": 4.0, + "ready_p50-ms": 178.6, + "ready_p95-ms": 269.8, + "residual_p50-ms": 74.63, + "residual_p95-ms": 88.0, + "signatures/block": 33760.0, + "signatures/s": 120993.0, + "submit_p50-ms": 0.01526, + "submit_p95-ms": 0.018, + "B/op": 7033597.0, + "allocs/op": 67538.0, + "source": "captured_2622653", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 274951714.0, + "avg_cpu_cores": 1.09, + "components/block": 126.0, + "cpu-ms/block": 299.7, + "feed_lag_p50-ms": 100.2, + "feed_lag_p95-ms": 191.4, + "mean_width": 4.0, + "ready_p50-ms": 174.6, + "ready_p95-ms": 265.8, + "residual_p50-ms": 74.09, + "residual_p95-ms": 76.92, + "signatures/block": 33760.0, + "signatures/s": 122785.0, + "submit_p50-ms": 0.01396, + "submit_p95-ms": 0.01562, + "B/op": 7033605.0, + "allocs/op": 67539.0, + "source": "captured_2622653", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 201098547.0, + "avg_cpu_cores": 1.493, + "components/block": 126.0, + "cpu-ms/block": 300.2, + "feed_lag_p50-ms": 0.5184, + "feed_lag_p95-ms": 0.981, + "mean_width": 3.956, + "ready_p50-ms": 1.117, + "ready_p95-ms": 1.603, + "residual_p50-ms": 1.053, + "residual_p95-ms": 1.298, + "signatures/block": 33760.0, + "signatures/s": 167878.0, + "submit_p50-ms": 0.001042, + "submit_p95-ms": 0.002425, + "B/op": 7193832.0, + "allocs/op": 68923.0, + "source": "captured_2622653", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200804503.0, + "avg_cpu_cores": 1.504, + "components/block": 126.0, + "cpu-ms/block": 302.0, + "feed_lag_p50-ms": 0.4528, + "feed_lag_p95-ms": 0.9812, + "mean_width": 3.956, + "ready_p50-ms": 1.073, + "ready_p95-ms": 1.596, + "residual_p50-ms": 0.6861, + "residual_p95-ms": 1.062, + "signatures/block": 33760.0, + "signatures/s": 168124.0, + "submit_p50-ms": 0.001172, + "submit_p95-ms": 0.003016, + "B/op": 7193242.0, + "allocs/op": 68918.0, + "source": "captured_2622653", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 201170435.0, + "avg_cpu_cores": 1.496, + "components/block": 126.0, + "cpu-ms/block": 300.9, + "feed_lag_p50-ms": 0.5088, + "feed_lag_p95-ms": 0.9289, + "mean_width": 3.956, + "ready_p50-ms": 1.085, + "ready_p95-ms": 1.534, + "residual_p50-ms": 1.085, + "residual_p95-ms": 1.335, + "signatures/block": 33760.0, + "signatures/s": 167818.0, + "submit_p50-ms": 0.001072, + "submit_p95-ms": 0.002414, + "B/op": 7193242.0, + "allocs/op": 68918.0, + "source": "captured_2622653", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/catchup-8", + "iterations": 3, + "ns/op": 39479657.0, + "avg_cpu_cores": 3.975, + "components/block": 1.0, + "cpu-ms/block": 157.0, + "feed_lag_p50-ms": 0.000271, + "feed_lag_p95-ms": 0.000481, + "mean_width": 8.0, + "ready_p50-ms": 39.13, + "ready_p95-ms": 41.02, + "residual_p50-ms": 39.13, + "residual_p95-ms": 41.02, + "signatures/block": 33760.0, + "signatures/s": 855124.0, + "submit_p50-ms": 0.007464, + "submit_p95-ms": 0.008786, + "B/op": 7023658.0, + "allocs/op": 67538.0, + "source": "captured_2622653", + "workers": 4, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/catchup-8", + "iterations": 3, + "ns/op": 38341975.0, + "avg_cpu_cores": 4.014, + "components/block": 1.0, + "cpu-ms/block": 153.9, + "feed_lag_p50-ms": 0.000581, + "feed_lag_p95-ms": 0.000641, + "mean_width": 8.0, + "ready_p50-ms": 38.31, + "ready_p95-ms": 38.39, + "residual_p50-ms": 38.31, + "residual_p95-ms": 38.39, + "signatures/block": 33760.0, + "signatures/s": 880497.0, + "submit_p50-ms": 0.004508, + "submit_p95-ms": 0.004959, + "B/op": 7023666.0, + "allocs/op": 67538.0, + "source": "captured_2622653", + "workers": 4, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/catchup-8", + "iterations": 3, + "ns/op": 39294804.0, + "avg_cpu_cores": 4.04, + "components/block": 1.0, + "cpu-ms/block": 158.7, + "feed_lag_p50-ms": 0.000391, + "feed_lag_p95-ms": 0.000551, + "mean_width": 8.0, + "ready_p50-ms": 39.31, + "ready_p95-ms": 39.43, + "residual_p50-ms": 39.31, + "residual_p95-ms": 39.43, + "signatures/block": 33760.0, + "signatures/s": 859147.0, + "submit_p50-ms": 0.005029, + "submit_p95-ms": 0.005861, + "B/op": 7023658.0, + "allocs/op": 67538.0, + "source": "captured_2622653", + "workers": 4, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 241004536.0, + "avg_cpu_cores": 0.6672, + "components/block": 126.0, + "cpu-ms/block": 160.8, + "feed_lag_p50-ms": 100.1, + "feed_lag_p95-ms": 191.3, + "mean_width": 8.0, + "ready_p50-ms": 141.0, + "ready_p95-ms": 232.2, + "residual_p50-ms": 40.6, + "residual_p95-ms": 43.41, + "signatures/block": 33760.0, + "signatures/s": 140080.0, + "submit_p50-ms": 0.01375, + "submit_p95-ms": 0.01582, + "B/op": 7033853.0, + "allocs/op": 67538.0, + "source": "captured_2622653", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 240866782.0, + "avg_cpu_cores": 0.6463, + "components/block": 126.0, + "cpu-ms/block": 155.7, + "feed_lag_p50-ms": 100.2, + "feed_lag_p95-ms": 191.4, + "mean_width": 8.0, + "ready_p50-ms": 140.6, + "ready_p95-ms": 231.8, + "residual_p50-ms": 41.37, + "residual_p95-ms": 41.44, + "signatures/block": 33760.0, + "signatures/s": 140160.0, + "submit_p50-ms": 0.01499, + "submit_p95-ms": 0.01555, + "B/op": 7033853.0, + "allocs/op": 67538.0, + "source": "captured_2622653", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 245990041.0, + "avg_cpu_cores": 0.7043, + "components/block": 126.0, + "cpu-ms/block": 173.2, + "feed_lag_p50-ms": 99.92, + "feed_lag_p95-ms": 191.1, + "mean_width": 8.0, + "ready_p50-ms": 145.8, + "ready_p95-ms": 237.0, + "residual_p50-ms": 46.04, + "residual_p95-ms": 51.4, + "signatures/block": 33760.0, + "signatures/s": 137241.0, + "submit_p50-ms": 0.01647, + "submit_p95-ms": 0.01882, + "B/op": 7033853.0, + "allocs/op": 67538.0, + "source": "captured_2622653", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200623083.0, + "avg_cpu_cores": 0.9263, + "components/block": 126.0, + "cpu-ms/block": 185.8, + "feed_lag_p50-ms": 0.5196, + "feed_lag_p95-ms": 1.002, + "mean_width": 7.912, + "ready_p50-ms": 0.9626, + "ready_p95-ms": 1.463, + "residual_p50-ms": 0.6115, + "residual_p95-ms": 0.9216, + "signatures/block": 33760.0, + "signatures/s": 168276.0, + "submit_p50-ms": 0.001794, + "submit_p95-ms": 0.004097, + "B/op": 7226498.0, + "allocs/op": 68927.0, + "source": "captured_2622653", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200897397.0, + "avg_cpu_cores": 0.8262, + "components/block": 126.0, + "cpu-ms/block": 166.0, + "feed_lag_p50-ms": 0.5245, + "feed_lag_p95-ms": 1.013, + "mean_width": 7.912, + "ready_p50-ms": 0.9103, + "ready_p95-ms": 1.39, + "residual_p50-ms": 1.083, + "residual_p95-ms": 1.198, + "signatures/block": 33760.0, + "signatures/s": 168046.0, + "submit_p50-ms": 0.001183, + "submit_p95-ms": 0.003416, + "B/op": 7225789.0, + "allocs/op": 68921.0, + "source": "captured_2622653", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2622653/workers_4/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200745122.0, + "avg_cpu_cores": 0.8122, + "components/block": 126.0, + "cpu-ms/block": 163.0, + "feed_lag_p50-ms": 0.516, + "feed_lag_p95-ms": 0.9821, + "mean_width": 7.912, + "ready_p50-ms": 0.8819, + "ready_p95-ms": 1.329, + "residual_p50-ms": 0.6724, + "residual_p95-ms": 1.132, + "signatures/block": 33760.0, + "signatures/s": 168173.0, + "submit_p50-ms": 0.001112, + "submit_p95-ms": 0.002685, + "B/op": 7225640.0, + "allocs/op": 68919.0, + "source": "captured_2622653", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/catchup-8", + "iterations": 3, + "ns/op": 143957884.0, + "avg_cpu_cores": 2.052, + "components/block": 1.0, + "cpu-ms/block": 295.4, + "feed_lag_p50-ms": 0.000241, + "feed_lag_p95-ms": 0.000491, + "mean_width": 4.0, + "ready_p50-ms": 144.0, + "ready_p95-ms": 144.7, + "residual_p50-ms": 144.0, + "residual_p95-ms": 144.7, + "signatures/block": 33760.0, + "signatures/s": 234513.0, + "submit_p50-ms": 0.005019, + "submit_p95-ms": 0.006172, + "B/op": 7023133.0, + "allocs/op": 67538.0, + "source": "captured_2624657", + "workers": 2, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/catchup-8", + "iterations": 3, + "ns/op": 155693549.0, + "avg_cpu_cores": 2.032, + "components/block": 1.0, + "cpu-ms/block": 316.4, + "feed_lag_p50-ms": 0.0003, + "feed_lag_p95-ms": 0.000311, + "mean_width": 4.0, + "ready_p50-ms": 158.7, + "ready_p95-ms": 162.0, + "residual_p50-ms": 158.7, + "residual_p95-ms": 162.0, + "signatures/block": 33760.0, + "signatures/s": 216836.0, + "submit_p50-ms": 0.004819, + "submit_p95-ms": 0.007064, + "B/op": 7023125.0, + "allocs/op": 67538.0, + "source": "captured_2624657", + "workers": 2, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/catchup-8", + "iterations": 3, + "ns/op": 175713321.0, + "avg_cpu_cores": 2.044, + "components/block": 1.0, + "cpu-ms/block": 359.1, + "feed_lag_p50-ms": 0.000211, + "feed_lag_p95-ms": 0.000481, + "mean_width": 4.0, + "ready_p50-ms": 175.6, + "ready_p95-ms": 178.9, + "residual_p50-ms": 175.6, + "residual_p95-ms": 178.9, + "signatures/block": 33760.0, + "signatures/s": 192131.0, + "submit_p50-ms": 0.00542, + "submit_p95-ms": 0.006953, + "B/op": 7023141.0, + "allocs/op": 67538.0, + "source": "captured_2624657", + "workers": 2, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 346489723.0, + "avg_cpu_cores": 0.8637, + "components/block": 126.0, + "cpu-ms/block": 299.3, + "feed_lag_p50-ms": 99.82, + "feed_lag_p95-ms": 191.0, + "mean_width": 4.0, + "ready_p50-ms": 246.5, + "ready_p95-ms": 337.7, + "residual_p50-ms": 145.9, + "residual_p95-ms": 147.9, + "signatures/block": 33760.0, + "signatures/s": 97434.0, + "submit_p50-ms": 0.0141, + "submit_p95-ms": 0.02031, + "B/op": 7033333.0, + "allocs/op": 67539.0, + "source": "captured_2624657", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 345618207.0, + "avg_cpu_cores": 0.8597, + "components/block": 126.0, + "cpu-ms/block": 297.1, + "feed_lag_p50-ms": 99.96, + "feed_lag_p95-ms": 191.2, + "mean_width": 4.0, + "ready_p50-ms": 245.1, + "ready_p95-ms": 336.3, + "residual_p50-ms": 145.9, + "residual_p95-ms": 145.9, + "signatures/block": 33760.0, + "signatures/s": 97680.0, + "submit_p50-ms": 0.01199, + "submit_p95-ms": 0.01378, + "B/op": 7033333.0, + "allocs/op": 67539.0, + "source": "captured_2624657", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 371354060.0, + "avg_cpu_cores": 0.9267, + "components/block": 126.0, + "cpu-ms/block": 344.1, + "feed_lag_p50-ms": 99.54, + "feed_lag_p95-ms": 190.7, + "mean_width": 4.0, + "ready_p50-ms": 271.4, + "ready_p95-ms": 362.6, + "residual_p50-ms": 172.2, + "residual_p95-ms": 177.1, + "signatures/block": 33760.0, + "signatures/s": 90911.0, + "submit_p50-ms": 0.0191, + "submit_p95-ms": 0.02254, + "B/op": 7033333.0, + "allocs/op": 67539.0, + "source": "captured_2624657", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 201052815.0, + "avg_cpu_cores": 1.483, + "components/block": 126.0, + "cpu-ms/block": 298.1, + "feed_lag_p50-ms": 0.2236, + "feed_lag_p95-ms": 0.8478, + "mean_width": 3.956, + "ready_p50-ms": 1.585, + "ready_p95-ms": 2.432, + "residual_p50-ms": 0.9514, + "residual_p95-ms": 1.353, + "signatures/block": 33760.0, + "signatures/s": 167916.0, + "submit_p50-ms": 0.000952, + "submit_p95-ms": 0.002114, + "B/op": 7161128.0, + "allocs/op": 68937.0, + "source": "captured_2624657", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200977968.0, + "avg_cpu_cores": 1.811, + "components/block": 126.0, + "cpu-ms/block": 363.9, + "feed_lag_p50-ms": 0.02301, + "feed_lag_p95-ms": 0.7957, + "mean_width": 3.956, + "ready_p50-ms": 1.998, + "ready_p95-ms": 3.094, + "residual_p50-ms": 0.877, + "residual_p95-ms": 1.215, + "signatures/block": 33760.0, + "signatures/s": 167979.0, + "submit_p50-ms": 0.002054, + "submit_p95-ms": 0.004097, + "B/op": 7159746.0, + "allocs/op": 68925.0, + "source": "captured_2624657", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 201118531.0, + "avg_cpu_cores": 1.488, + "components/block": 126.0, + "cpu-ms/block": 299.2, + "feed_lag_p50-ms": 0.2092, + "feed_lag_p95-ms": 0.8745, + "mean_width": 3.956, + "ready_p50-ms": 1.589, + "ready_p95-ms": 2.484, + "residual_p50-ms": 1.204, + "residual_p95-ms": 1.456, + "signatures/block": 33760.0, + "signatures/s": 167861.0, + "submit_p50-ms": 0.001001, + "submit_p95-ms": 0.002295, + "B/op": 7160709.0, + "allocs/op": 68934.0, + "source": "captured_2624657", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/catchup-8", + "iterations": 3, + "ns/op": 79597279.0, + "avg_cpu_cores": 2.042, + "components/block": 1.0, + "cpu-ms/block": 162.5, + "feed_lag_p50-ms": 0.00026, + "feed_lag_p95-ms": 0.000471, + "mean_width": 8.0, + "ready_p50-ms": 81.98, + "ready_p95-ms": 82.1, + "residual_p50-ms": 81.98, + "residual_p95-ms": 82.1, + "signatures/block": 33760.0, + "signatures/s": 424135.0, + "submit_p50-ms": 0.00517, + "submit_p95-ms": 0.006362, + "B/op": 7023253.0, + "allocs/op": 67538.0, + "source": "captured_2624657", + "workers": 2, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/catchup-8", + "iterations": 3, + "ns/op": 92160738.0, + "avg_cpu_cores": 2.042, + "components/block": 1.0, + "cpu-ms/block": 188.1, + "feed_lag_p50-ms": 0.000501, + "feed_lag_p95-ms": 0.000571, + "mean_width": 8.0, + "ready_p50-ms": 91.84, + "ready_p95-ms": 96.76, + "residual_p50-ms": 91.84, + "residual_p95-ms": 96.76, + "signatures/block": 33760.0, + "signatures/s": 366317.0, + "submit_p50-ms": 0.007174, + "submit_p95-ms": 0.008115, + "B/op": 7023266.0, + "allocs/op": 67538.0, + "source": "captured_2624657", + "workers": 2, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/catchup-8", + "iterations": 3, + "ns/op": 77785688.0, + "avg_cpu_cores": 2.04, + "components/block": 1.0, + "cpu-ms/block": 158.7, + "feed_lag_p50-ms": 0.000211, + "feed_lag_p95-ms": 0.000872, + "mean_width": 8.0, + "ready_p50-ms": 76.89, + "ready_p95-ms": 81.28, + "residual_p50-ms": 76.89, + "residual_p95-ms": 81.28, + "signatures/block": 33760.0, + "signatures/s": 434013.0, + "submit_p50-ms": 0.005009, + "submit_p95-ms": 0.006552, + "B/op": 7023261.0, + "allocs/op": 67538.0, + "source": "captured_2624657", + "workers": 2, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 279921937.0, + "avg_cpu_cores": 0.5736, + "components/block": 126.0, + "cpu-ms/block": 160.6, + "feed_lag_p50-ms": 100.1, + "feed_lag_p95-ms": 191.3, + "mean_width": 8.0, + "ready_p50-ms": 179.3, + "ready_p95-ms": 270.5, + "residual_p50-ms": 76.93, + "residual_p95-ms": 87.45, + "signatures/block": 33760.0, + "signatures/s": 120605.0, + "submit_p50-ms": 0.0151, + "submit_p95-ms": 0.01745, + "B/op": 7033453.0, + "allocs/op": 67538.0, + "source": "captured_2624657", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 280609110.0, + "avg_cpu_cores": 0.579, + "components/block": 126.0, + "cpu-ms/block": 162.5, + "feed_lag_p50-ms": 100.8, + "feed_lag_p95-ms": 192.0, + "mean_width": 8.0, + "ready_p50-ms": 180.0, + "ready_p95-ms": 271.2, + "residual_p50-ms": 80.28, + "residual_p95-ms": 85.53, + "signatures/block": 33760.0, + "signatures/s": 120310.0, + "submit_p50-ms": 0.01629, + "submit_p95-ms": 0.0575, + "B/op": 7079253.0, + "allocs/op": 67541.0, + "source": "captured_2624657", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 275007675.0, + "avg_cpu_cores": 0.555, + "components/block": 126.0, + "cpu-ms/block": 152.6, + "feed_lag_p50-ms": 100.1, + "feed_lag_p95-ms": 191.3, + "mean_width": 8.0, + "ready_p50-ms": 174.7, + "ready_p95-ms": 265.9, + "residual_p50-ms": 75.43, + "residual_p95-ms": 75.48, + "signatures/block": 33760.0, + "signatures/s": 122760.0, + "submit_p50-ms": 0.01441, + "submit_p95-ms": 0.01488, + "B/op": 7033474.0, + "allocs/op": 67539.0, + "source": "captured_2624657", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200553309.0, + "avg_cpu_cores": 0.8722, + "components/block": 126.0, + "cpu-ms/block": 174.9, + "feed_lag_p50-ms": 0.4164, + "feed_lag_p95-ms": 0.9441, + "mean_width": 7.912, + "ready_p50-ms": 1.193, + "ready_p95-ms": 1.708, + "residual_p50-ms": 0.5627, + "residual_p95-ms": 0.572, + "signatures/block": 33760.0, + "signatures/s": 168334.0, + "submit_p50-ms": 0.001743, + "submit_p95-ms": 0.004909, + "B/op": 7175850.0, + "allocs/op": 68920.0, + "source": "captured_2624657", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 201115062.0, + "avg_cpu_cores": 0.8365, + "components/block": 126.0, + "cpu-ms/block": 168.2, + "feed_lag_p50-ms": 0.4905, + "feed_lag_p95-ms": 0.9819, + "mean_width": 7.912, + "ready_p50-ms": 1.142, + "ready_p95-ms": 1.804, + "residual_p50-ms": 1.348, + "residual_p95-ms": 1.353, + "signatures/block": 33760.0, + "signatures/s": 167864.0, + "submit_p50-ms": 0.001302, + "submit_p95-ms": 0.003086, + "B/op": 7175330.0, + "allocs/op": 68920.0, + "source": "captured_2624657", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_2/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200875209.0, + "avg_cpu_cores": 0.9083, + "components/block": 126.0, + "cpu-ms/block": 182.5, + "feed_lag_p50-ms": 0.4053, + "feed_lag_p95-ms": 0.9401, + "mean_width": 7.912, + "ready_p50-ms": 1.21, + "ready_p95-ms": 1.734, + "residual_p50-ms": 0.7018, + "residual_p95-ms": 1.361, + "signatures/block": 33760.0, + "signatures/s": 168065.0, + "submit_p50-ms": 0.001733, + "submit_p95-ms": 0.004358, + "B/op": 7176061.0, + "allocs/op": 68927.0, + "source": "captured_2624657", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/catchup-8", + "iterations": 3, + "ns/op": 84397967.0, + "avg_cpu_cores": 3.886, + "components/block": 1.0, + "cpu-ms/block": 328.0, + "feed_lag_p50-ms": 0.00027, + "feed_lag_p95-ms": 0.000651, + "mean_width": 4.0, + "ready_p50-ms": 80.13, + "ready_p95-ms": 96.48, + "residual_p50-ms": 80.13, + "residual_p95-ms": 96.48, + "signatures/block": 33760.0, + "signatures/s": 400010.0, + "submit_p50-ms": 0.004749, + "submit_p95-ms": 0.008185, + "B/op": 7023397.0, + "allocs/op": 67538.0, + "source": "captured_2624657", + "workers": 4, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/catchup-8", + "iterations": 3, + "ns/op": 84545510.0, + "avg_cpu_cores": 3.891, + "components/block": 1.0, + "cpu-ms/block": 328.9, + "feed_lag_p50-ms": 0.00022, + "feed_lag_p95-ms": 0.000722, + "mean_width": 4.0, + "ready_p50-ms": 81.04, + "ready_p95-ms": 94.42, + "residual_p50-ms": 81.04, + "residual_p95-ms": 94.42, + "signatures/block": 33760.0, + "signatures/s": 399312.0, + "submit_p50-ms": 0.007054, + "submit_p95-ms": 0.007925, + "B/op": 7023402.0, + "allocs/op": 67538.0, + "source": "captured_2624657", + "workers": 4, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/catchup-8", + "iterations": 3, + "ns/op": 77376355.0, + "avg_cpu_cores": 3.992, + "components/block": 1.0, + "cpu-ms/block": 308.9, + "feed_lag_p50-ms": 0.00021, + "feed_lag_p95-ms": 0.000611, + "mean_width": 4.0, + "ready_p50-ms": 76.57, + "ready_p95-ms": 79.75, + "residual_p50-ms": 76.57, + "residual_p95-ms": 79.75, + "signatures/block": 33760.0, + "signatures/s": 436309.0, + "submit_p50-ms": 0.01021, + "submit_p95-ms": 0.01104, + "B/op": 7023402.0, + "allocs/op": 67538.0, + "source": "captured_2624657", + "workers": 4, + "target": 4, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 276775942.0, + "avg_cpu_cores": 1.101, + "components/block": 126.0, + "cpu-ms/block": 304.8, + "feed_lag_p50-ms": 100.1, + "feed_lag_p95-ms": 191.3, + "mean_width": 4.0, + "ready_p50-ms": 176.7, + "ready_p95-ms": 267.9, + "residual_p50-ms": 76.69, + "residual_p95-ms": 77.72, + "signatures/block": 33760.0, + "signatures/s": 121976.0, + "submit_p50-ms": 0.01302, + "submit_p95-ms": 0.01303, + "B/op": 7033605.0, + "allocs/op": 67539.0, + "source": "captured_2624657", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 286266781.0, + "avg_cpu_cores": 1.147, + "components/block": 126.0, + "cpu-ms/block": 328.2, + "feed_lag_p50-ms": 100.1, + "feed_lag_p95-ms": 191.3, + "mean_width": 4.0, + "ready_p50-ms": 186.0, + "ready_p95-ms": 277.2, + "residual_p50-ms": 88.39, + "residual_p95-ms": 92.31, + "signatures/block": 33760.0, + "signatures/s": 117932.0, + "submit_p50-ms": 0.0163, + "submit_p95-ms": 0.0338, + "B/op": 7033597.0, + "allocs/op": 67538.0, + "source": "captured_2624657", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 280082230.0, + "avg_cpu_cores": 1.127, + "components/block": 126.0, + "cpu-ms/block": 315.7, + "feed_lag_p50-ms": 100.1, + "feed_lag_p95-ms": 191.3, + "mean_width": 4.0, + "ready_p50-ms": 180.2, + "ready_p95-ms": 271.4, + "residual_p50-ms": 81.38, + "residual_p95-ms": 82.65, + "signatures/block": 33760.0, + "signatures/s": 120536.0, + "submit_p50-ms": 0.01659, + "submit_p95-ms": 0.02034, + "B/op": 7033605.0, + "allocs/op": 67539.0, + "source": "captured_2624657", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200915755.0, + "avg_cpu_cores": 1.5, + "components/block": 126.0, + "cpu-ms/block": 301.4, + "feed_lag_p50-ms": 0.5144, + "feed_lag_p95-ms": 0.9691, + "mean_width": 3.956, + "ready_p50-ms": 1.113, + "ready_p95-ms": 1.588, + "residual_p50-ms": 0.9998, + "residual_p95-ms": 1.239, + "signatures/block": 33760.0, + "signatures/s": 168031.0, + "submit_p50-ms": 0.001022, + "submit_p95-ms": 0.002404, + "B/op": 7193234.0, + "allocs/op": 68918.0, + "source": "captured_2624657", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200718712.0, + "avg_cpu_cores": 1.523, + "components/block": 126.0, + "cpu-ms/block": 305.7, + "feed_lag_p50-ms": 0.458, + "feed_lag_p95-ms": 0.9962, + "mean_width": 3.956, + "ready_p50-ms": 1.154, + "ready_p95-ms": 1.675, + "residual_p50-ms": 0.4901, + "residual_p95-ms": 1.164, + "signatures/block": 33760.0, + "signatures/s": 168196.0, + "submit_p50-ms": 0.001242, + "submit_p95-ms": 0.002976, + "B/op": 7194797.0, + "allocs/op": 68932.0, + "source": "captured_2624657", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200572819.0, + "avg_cpu_cores": 1.531, + "components/block": 126.0, + "cpu-ms/block": 307.1, + "feed_lag_p50-ms": 0.4611, + "feed_lag_p95-ms": 0.9844, + "mean_width": 3.956, + "ready_p50-ms": 1.135, + "ready_p95-ms": 1.701, + "residual_p50-ms": 0.6289, + "residual_p95-ms": 0.6701, + "signatures/block": 33760.0, + "signatures/s": 168318.0, + "submit_p50-ms": 0.001202, + "submit_p95-ms": 0.003256, + "B/op": 7193720.0, + "allocs/op": 68922.0, + "source": "captured_2624657", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/catchup-8", + "iterations": 3, + "ns/op": 39509312.0, + "avg_cpu_cores": 4.011, + "components/block": 1.0, + "cpu-ms/block": 158.5, + "feed_lag_p50-ms": 0.00025, + "feed_lag_p95-ms": 0.000411, + "mean_width": 8.0, + "ready_p50-ms": 39.88, + "ready_p95-ms": 40.18, + "residual_p50-ms": 39.88, + "residual_p95-ms": 40.18, + "signatures/block": 33760.0, + "signatures/s": 854482.0, + "submit_p50-ms": 0.004759, + "submit_p95-ms": 0.00501, + "B/op": 7023658.0, + "allocs/op": 67538.0, + "source": "captured_2624657", + "workers": 4, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/catchup-8", + "iterations": 3, + "ns/op": 44691175.0, + "avg_cpu_cores": 3.832, + "components/block": 1.0, + "cpu-ms/block": 171.2, + "feed_lag_p50-ms": 0.000501, + "feed_lag_p95-ms": 0.000771, + "mean_width": 8.0, + "ready_p50-ms": 42.16, + "ready_p95-ms": 52.97, + "residual_p50-ms": 42.16, + "residual_p95-ms": 52.97, + "signatures/block": 33760.0, + "signatures/s": 755406.0, + "submit_p50-ms": 0.005119, + "submit_p95-ms": 0.008055, + "B/op": 7023653.0, + "allocs/op": 67538.0, + "source": "captured_2624657", + "workers": 4, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/catchup-8", + "iterations": 3, + "ns/op": 44816763.0, + "avg_cpu_cores": 3.923, + "components/block": 1.0, + "cpu-ms/block": 175.8, + "feed_lag_p50-ms": 0.000301, + "feed_lag_p95-ms": 0.000481, + "mean_width": 8.0, + "ready_p50-ms": 42.65, + "ready_p95-ms": 51.93, + "residual_p50-ms": 42.65, + "residual_p95-ms": 51.93, + "signatures/block": 33760.0, + "signatures/s": 753290.0, + "submit_p50-ms": 0.003908, + "submit_p95-ms": 0.006643, + "B/op": 7023653.0, + "allocs/op": 67538.0, + "source": "captured_2624657", + "workers": 4, + "target": 8, + "scenario": "catchup", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 242531854.0, + "avg_cpu_cores": 0.6854, + "components/block": 126.0, + "cpu-ms/block": 166.2, + "feed_lag_p50-ms": 99.89, + "feed_lag_p95-ms": 191.1, + "mean_width": 8.0, + "ready_p50-ms": 142.2, + "ready_p95-ms": 233.4, + "residual_p50-ms": 41.44, + "residual_p95-ms": 44.73, + "signatures/block": 33760.0, + "signatures/s": 139198.0, + "submit_p50-ms": 0.01571, + "submit_p95-ms": 0.01829, + "B/op": 7033861.0, + "allocs/op": 67539.0, + "source": "captured_2624657", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 239652146.0, + "avg_cpu_cores": 0.6493, + "components/block": 126.0, + "cpu-ms/block": 155.6, + "feed_lag_p50-ms": 100.2, + "feed_lag_p95-ms": 191.4, + "mean_width": 8.0, + "ready_p50-ms": 139.2, + "ready_p95-ms": 230.4, + "residual_p50-ms": 39.49, + "residual_p95-ms": 40.03, + "signatures/block": 33760.0, + "signatures/s": 140871.0, + "submit_p50-ms": 0.01441, + "submit_p95-ms": 0.01704, + "B/op": 7033861.0, + "allocs/op": 67539.0, + "source": "captured_2624657", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 240787126.0, + "avg_cpu_cores": 0.6555, + "components/block": 126.0, + "cpu-ms/block": 157.8, + "feed_lag_p50-ms": 100.2, + "feed_lag_p95-ms": 191.4, + "mean_width": 8.0, + "ready_p50-ms": 140.6, + "ready_p95-ms": 231.8, + "residual_p50-ms": 40.74, + "residual_p95-ms": 41.39, + "signatures/block": 33760.0, + "signatures/s": 140207.0, + "submit_p50-ms": 0.01393, + "submit_p95-ms": 0.01417, + "B/op": 7033861.0, + "allocs/op": 67539.0, + "source": "captured_2624657", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200949184.0, + "avg_cpu_cores": 0.9006, + "components/block": 126.0, + "cpu-ms/block": 181.0, + "feed_lag_p50-ms": 0.4993, + "feed_lag_p95-ms": 0.9768, + "mean_width": 7.912, + "ready_p50-ms": 0.9266, + "ready_p95-ms": 1.401, + "residual_p50-ms": 1.066, + "residual_p95-ms": 1.141, + "signatures/block": 33760.0, + "signatures/s": 168003.0, + "submit_p50-ms": 0.001683, + "submit_p95-ms": 0.006322, + "B/op": 7225536.0, + "allocs/op": 68919.0, + "source": "captured_2624657", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200864502.0, + "avg_cpu_cores": 0.8069, + "components/block": 126.0, + "cpu-ms/block": 162.1, + "feed_lag_p50-ms": 0.5202, + "feed_lag_p95-ms": 1.012, + "mean_width": 7.912, + "ready_p50-ms": 0.8813, + "ready_p95-ms": 1.38, + "residual_p50-ms": 1.09, + "residual_p95-ms": 1.206, + "signatures/block": 33760.0, + "signatures/s": 168074.0, + "submit_p50-ms": 0.001102, + "submit_p95-ms": 0.002535, + "B/op": 7227181.0, + "allocs/op": 68933.0, + "source": "captured_2624657", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/captured_2624657/workers_4/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200828651.0, + "avg_cpu_cores": 0.8102, + "components/block": 126.0, + "cpu-ms/block": 162.7, + "feed_lag_p50-ms": 0.517, + "feed_lag_p95-ms": 1.016, + "mean_width": 7.912, + "ready_p50-ms": 0.8773, + "ready_p95-ms": 1.385, + "residual_p50-ms": 0.9549, + "residual_p95-ms": 1.219, + "signatures/block": 33760.0, + "signatures/s": 168104.0, + "submit_p50-ms": 0.001112, + "submit_p95-ms": 0.002545, + "B/op": 7226312.0, + "allocs/op": 68925.0, + "source": "captured_2624657", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "captured-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/catchup-8", + "iterations": 3, + "ns/op": 165232107.0, + "avg_cpu_cores": 2.073, + "components/block": 1.0, + "cpu-ms/block": 342.6, + "feed_lag_p50-ms": 0.000241, + "feed_lag_p95-ms": 0.000481, + "mean_width": 4.0, + "ready_p50-ms": 163.8, + "ready_p95-ms": 171.9, + "residual_p50-ms": 163.8, + "residual_p95-ms": 171.9, + "signatures/block": 33760.0, + "signatures/s": 204319.0, + "submit_p50-ms": 0.004889, + "submit_p95-ms": 0.005961, + "B/op": 44570082.0, + "allocs/op": 67557.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "catchup", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/catchup-8", + "iterations": 3, + "ns/op": 166036574.0, + "avg_cpu_cores": 2.074, + "components/block": 1.0, + "cpu-ms/block": 344.4, + "feed_lag_p50-ms": 0.000211, + "feed_lag_p95-ms": 0.000471, + "mean_width": 4.0, + "ready_p50-ms": 164.3, + "ready_p95-ms": 172.6, + "residual_p50-ms": 164.3, + "residual_p95-ms": 172.6, + "signatures/block": 33760.0, + "signatures/s": 203329.0, + "submit_p50-ms": 0.004078, + "submit_p95-ms": 0.006131, + "B/op": 44615709.0, + "allocs/op": 67558.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "catchup", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/catchup-8", + "iterations": 3, + "ns/op": 158962907.0, + "avg_cpu_cores": 2.075, + "components/block": 1.0, + "cpu-ms/block": 329.9, + "feed_lag_p50-ms": 0.00025, + "feed_lag_p95-ms": 0.000461, + "mean_width": 4.0, + "ready_p50-ms": 159.6, + "ready_p95-ms": 160.2, + "residual_p50-ms": 159.6, + "residual_p95-ms": 160.2, + "signatures/block": 33760.0, + "signatures/s": 212377.0, + "submit_p50-ms": 0.004829, + "submit_p95-ms": 0.00547, + "B/op": 44707154.0, + "allocs/op": 67561.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "catchup", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 359264432.0, + "avg_cpu_cores": 0.9167, + "components/block": 689.0, + "cpu-ms/block": 329.3, + "feed_lag_p50-ms": 100.5, + "feed_lag_p95-ms": 190.7, + "mean_width": 4.0, + "ready_p50-ms": 259.3, + "ready_p95-ms": 349.4, + "residual_p50-ms": 159.3, + "residual_p95-ms": 160.9, + "signatures/block": 33760.0, + "signatures/s": 93970.0, + "submit_p50-ms": 0.01357, + "submit_p95-ms": 0.01492, + "B/op": 44535416.0, + "allocs/op": 67551.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 359629949.0, + "avg_cpu_cores": 0.918, + "components/block": 689.0, + "cpu-ms/block": 330.1, + "feed_lag_p50-ms": 100.7, + "feed_lag_p95-ms": 190.8, + "mean_width": 4.0, + "ready_p50-ms": 259.7, + "ready_p95-ms": 349.8, + "residual_p50-ms": 159.4, + "residual_p95-ms": 161.5, + "signatures/block": 33760.0, + "signatures/s": 93874.0, + "submit_p50-ms": 0.01362, + "submit_p95-ms": 0.01513, + "B/op": 44535658.0, + "allocs/op": 67552.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 359479815.0, + "avg_cpu_cores": 0.9171, + "components/block": 689.0, + "cpu-ms/block": 329.7, + "feed_lag_p50-ms": 100.4, + "feed_lag_p95-ms": 190.5, + "mean_width": 4.0, + "ready_p50-ms": 259.5, + "ready_p95-ms": 349.6, + "residual_p50-ms": 159.9, + "residual_p95-ms": 160.2, + "signatures/block": 33760.0, + "signatures/s": 93913.0, + "submit_p50-ms": 0.01571, + "submit_p95-ms": 0.01585, + "B/op": 44489704.0, + "allocs/op": 67550.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200661932.0, + "avg_cpu_cores": 1.879, + "components/block": 689.0, + "cpu-ms/block": 377.1, + "feed_lag_p50-ms": 0.04898, + "feed_lag_p95-ms": 3.657, + "mean_width": 3.77, + "ready_p50-ms": 0.9535, + "ready_p95-ms": 5.077, + "residual_p50-ms": 0.6731, + "residual_p95-ms": 0.9156, + "signatures/block": 33760.0, + "signatures/s": 168243.0, + "submit_p50-ms": 0.001192, + "submit_p95-ms": 0.5149, + "B/op": 45346429.0, + "allocs/op": 75220.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200375326.0, + "avg_cpu_cores": 1.856, + "components/block": 689.0, + "cpu-ms/block": 371.8, + "feed_lag_p50-ms": 0.04542, + "feed_lag_p95-ms": 2.251, + "mean_width": 3.77, + "ready_p50-ms": 0.9154, + "ready_p95-ms": 3.697, + "residual_p50-ms": 0.3591, + "residual_p95-ms": 0.4024, + "signatures/block": 33760.0, + "signatures/s": 168484.0, + "submit_p50-ms": 0.001102, + "submit_p95-ms": 0.5519, + "B/op": 45279114.0, + "allocs/op": 75174.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200405779.0, + "avg_cpu_cores": 1.798, + "components/block": 689.0, + "cpu-ms/block": 360.4, + "feed_lag_p50-ms": 0.03941, + "feed_lag_p95-ms": 1.051, + "mean_width": 3.77, + "ready_p50-ms": 0.8241, + "ready_p95-ms": 2.498, + "residual_p50-ms": 0.3923, + "residual_p95-ms": 0.5034, + "signatures/block": 33760.0, + "signatures/s": 168458.0, + "submit_p50-ms": 0.000852, + "submit_p95-ms": 0.5208, + "B/op": 45287578.0, + "allocs/op": 75182.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_4tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200381187.0, + "avg_cpu_cores": 0.02, + "components/block": 64.0, + "cpu-ms/block": 4.008, + "feed_lag_p50-ms": 0.5205, + "feed_lag_p95-ms": 0.9542, + "mean_width": 4.0, + "ready_p50-ms": 0.5746, + "ready_p95-ms": 1.006, + "residual_p50-ms": 0.06565, + "residual_p95-ms": 1.008, + "signatures/block": 256.0, + "signatures/s": 1278.0, + "submit_p50-ms": 0.001062, + "submit_p95-ms": 0.003106, + "B/op": 405549.0, + "allocs/op": 1227.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "sparse_4tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_4tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200548807.0, + "avg_cpu_cores": 0.03358, + "components/block": 64.0, + "cpu-ms/block": 6.734, + "feed_lag_p50-ms": 0.5788, + "feed_lag_p95-ms": 0.9736, + "mean_width": 4.0, + "ready_p50-ms": 0.6502, + "ready_p95-ms": 1.057, + "residual_p50-ms": 0.4003, + "residual_p95-ms": 0.8991, + "signatures/block": 256.0, + "signatures/s": 1276.0, + "submit_p50-ms": 0.002535, + "submit_p95-ms": 0.01151, + "B/op": 405570.0, + "allocs/op": 1228.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "sparse_4tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_4tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200692627.0, + "avg_cpu_cores": 0.02155, + "components/block": 64.0, + "cpu-ms/block": 4.324, + "feed_lag_p50-ms": 0.5307, + "feed_lag_p95-ms": 0.9496, + "mean_width": 4.0, + "ready_p50-ms": 0.5792, + "ready_p95-ms": 1.004, + "residual_p50-ms": 0.7962, + "residual_p95-ms": 0.9766, + "signatures/block": 256.0, + "signatures/s": 1276.0, + "submit_p50-ms": 0.001232, + "submit_p95-ms": 0.003516, + "B/op": 405549.0, + "allocs/op": 1227.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "sparse_4tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_7tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200734923.0, + "avg_cpu_cores": 0.02505, + "components/block": 37.0, + "cpu-ms/block": 5.029, + "feed_lag_p50-ms": 0.5435, + "feed_lag_p95-ms": 0.9882, + "mean_width": 3.507, + "ready_p50-ms": 0.6193, + "ready_p95-ms": 1.055, + "residual_p50-ms": 0.8195, + "residual_p95-ms": 1.028, + "signatures/block": 256.0, + "signatures/s": 1275.0, + "submit_p50-ms": 0.001703, + "submit_p95-ms": 0.005821, + "B/op": 376309.0, + "allocs/op": 931.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "sparse_7tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_7tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200839933.0, + "avg_cpu_cores": 0.0211, + "components/block": 37.0, + "cpu-ms/block": 4.237, + "feed_lag_p50-ms": 0.5533, + "feed_lag_p95-ms": 1.006, + "mean_width": 3.507, + "ready_p50-ms": 0.6087, + "ready_p95-ms": 1.06, + "residual_p50-ms": 0.9924, + "residual_p95-ms": 1.071, + "signatures/block": 256.0, + "signatures/s": 1275.0, + "submit_p50-ms": 0.001212, + "submit_p95-ms": 0.003216, + "B/op": 376301.0, + "allocs/op": 930.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "sparse_7tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_7tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200166050.0, + "avg_cpu_cores": 0.02238, + "components/block": 37.0, + "cpu-ms/block": 4.48, + "feed_lag_p50-ms": 0.5576, + "feed_lag_p95-ms": 1.003, + "mean_width": 3.507, + "ready_p50-ms": 0.6392, + "ready_p95-ms": 1.089, + "residual_p50-ms": 0.1596, + "residual_p95-ms": 0.1676, + "signatures/block": 256.0, + "signatures/s": 1279.0, + "submit_p50-ms": 0.001563, + "submit_p95-ms": 0.003787, + "B/op": 376301.0, + "allocs/op": 930.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "sparse_7tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_8tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200891132.0, + "avg_cpu_cores": 0.02598, + "components/block": 32.0, + "cpu-ms/block": 5.22, + "feed_lag_p50-ms": 0.6103, + "feed_lag_p95-ms": 1.029, + "mean_width": 4.0, + "ready_p50-ms": 0.6923, + "ready_p95-ms": 1.127, + "residual_p50-ms": 0.9305, + "residual_p95-ms": 1.072, + "signatures/block": 256.0, + "signatures/s": 1274.0, + "submit_p50-ms": 0.002044, + "submit_p95-ms": 0.01812, + "B/op": 370733.0, + "allocs/op": 875.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "sparse_8tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_8tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200748211.0, + "avg_cpu_cores": 0.01877, + "components/block": 32.0, + "cpu-ms/block": 3.768, + "feed_lag_p50-ms": 0.437, + "feed_lag_p95-ms": 1.023, + "mean_width": 4.0, + "ready_p50-ms": 0.5164, + "ready_p95-ms": 1.08, + "residual_p50-ms": 0.7419, + "residual_p95-ms": 0.764, + "signatures/block": 256.0, + "signatures/s": 1275.0, + "submit_p50-ms": 0.001562, + "submit_p95-ms": 0.003406, + "B/op": 370733.0, + "allocs/op": 875.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "sparse_8tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_4/sparse_8tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200821061.0, + "avg_cpu_cores": 0.02266, + "components/block": 32.0, + "cpu-ms/block": 4.551, + "feed_lag_p50-ms": 0.6271, + "feed_lag_p95-ms": 1.025, + "mean_width": 4.0, + "ready_p50-ms": 0.6833, + "ready_p95-ms": 1.099, + "residual_p50-ms": 0.8705, + "residual_p95-ms": 0.9203, + "signatures/block": 256.0, + "signatures/s": 1275.0, + "submit_p50-ms": 0.001843, + "submit_p95-ms": 0.01049, + "B/op": 370733.0, + "allocs/op": 875.0, + "source": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "sparse_8tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/catchup-8", + "iterations": 3, + "ns/op": 88134578.0, + "avg_cpu_cores": 2.097, + "components/block": 1.0, + "cpu-ms/block": 184.8, + "feed_lag_p50-ms": 0.000401, + "feed_lag_p95-ms": 0.000832, + "mean_width": 8.0, + "ready_p50-ms": 89.14, + "ready_p95-ms": 92.15, + "residual_p50-ms": 89.14, + "residual_p95-ms": 92.15, + "signatures/block": 33760.0, + "signatures/s": 383051.0, + "submit_p50-ms": 0.005991, + "submit_p95-ms": 0.0127, + "B/op": 44478298.0, + "allocs/op": 67549.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "catchup", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/catchup-8", + "iterations": 3, + "ns/op": 86113936.0, + "avg_cpu_cores": 2.09, + "components/block": 1.0, + "cpu-ms/block": 180.0, + "feed_lag_p50-ms": 0.00026, + "feed_lag_p95-ms": 0.000732, + "mean_width": 8.0, + "ready_p50-ms": 84.68, + "ready_p95-ms": 89.35, + "residual_p50-ms": 84.68, + "residual_p95-ms": 89.35, + "signatures/block": 33760.0, + "signatures/s": 392039.0, + "submit_p50-ms": 0.004137, + "submit_p95-ms": 0.00537, + "B/op": 44386656.0, + "allocs/op": 67544.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "catchup", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/catchup-8", + "iterations": 3, + "ns/op": 84405778.0, + "avg_cpu_cores": 2.098, + "components/block": 1.0, + "cpu-ms/block": 177.1, + "feed_lag_p50-ms": 0.00025, + "feed_lag_p95-ms": 0.000481, + "mean_width": 8.0, + "ready_p50-ms": 84.06, + "ready_p95-ms": 85.34, + "residual_p50-ms": 84.06, + "residual_p95-ms": 85.34, + "signatures/block": 33760.0, + "signatures/s": 399973.0, + "submit_p50-ms": 0.004048, + "submit_p95-ms": 0.004588, + "B/op": 44569941.0, + "allocs/op": 67554.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "catchup", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 284620670.0, + "avg_cpu_cores": 0.6238, + "components/block": 689.0, + "cpu-ms/block": 177.6, + "feed_lag_p50-ms": 100.2, + "feed_lag_p95-ms": 190.3, + "mean_width": 8.0, + "ready_p50-ms": 184.6, + "ready_p95-ms": 274.8, + "residual_p50-ms": 84.69, + "residual_p95-ms": 85.06, + "signatures/block": 33760.0, + "signatures/s": 118614.0, + "submit_p50-ms": 0.01488, + "submit_p95-ms": 0.01676, + "B/op": 44489685.0, + "allocs/op": 67548.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 285857000.0, + "avg_cpu_cores": 0.6282, + "components/block": 689.0, + "cpu-ms/block": 179.6, + "feed_lag_p50-ms": 100.4, + "feed_lag_p95-ms": 190.5, + "mean_width": 8.0, + "ready_p50-ms": 185.9, + "ready_p95-ms": 276.0, + "residual_p50-ms": 85.29, + "residual_p95-ms": 87.23, + "signatures/block": 33760.0, + "signatures/s": 118101.0, + "submit_p50-ms": 0.01511, + "submit_p95-ms": 0.01781, + "B/op": 44627120.0, + "allocs/op": 67555.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 290218004.0, + "avg_cpu_cores": 0.6484, + "components/block": 689.0, + "cpu-ms/block": 188.2, + "feed_lag_p50-ms": 100.7, + "feed_lag_p95-ms": 190.8, + "mean_width": 8.0, + "ready_p50-ms": 190.1, + "ready_p95-ms": 280.3, + "residual_p50-ms": 91.02, + "residual_p95-ms": 96.42, + "signatures/block": 33760.0, + "signatures/s": 116326.0, + "submit_p50-ms": 0.01466, + "submit_p95-ms": 0.0263, + "B/op": 44535536.0, + "allocs/op": 67551.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200393747.0, + "avg_cpu_cores": 0.9599, + "components/block": 689.0, + "cpu-ms/block": 192.4, + "feed_lag_p50-ms": 0.1208, + "feed_lag_p95-ms": 0.6496, + "mean_width": 7.001, + "ready_p50-ms": 0.5021, + "ready_p95-ms": 1.098, + "residual_p50-ms": 0.3487, + "residual_p95-ms": 0.6362, + "signatures/block": 33760.0, + "signatures/s": 168468.0, + "submit_p50-ms": 0.000601, + "submit_p95-ms": 0.002294, + "B/op": 45456104.0, + "allocs/op": 75154.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200299620.0, + "avg_cpu_cores": 0.9555, + "components/block": 689.0, + "cpu-ms/block": 191.4, + "feed_lag_p50-ms": 0.1164, + "feed_lag_p95-ms": 0.6451, + "mean_width": 7.001, + "ready_p50-ms": 0.4922, + "ready_p95-ms": 1.083, + "residual_p50-ms": 0.2595, + "residual_p95-ms": 0.397, + "signatures/block": 33760.0, + "signatures/s": 168547.0, + "submit_p50-ms": 0.000581, + "submit_p95-ms": 0.001764, + "B/op": 45500650.0, + "allocs/op": 75145.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200435552.0, + "avg_cpu_cores": 1.129, + "components/block": 689.0, + "cpu-ms/block": 226.3, + "feed_lag_p50-ms": 0.08438, + "feed_lag_p95-ms": 0.7172, + "mean_width": 7.001, + "ready_p50-ms": 0.5504, + "ready_p95-ms": 1.334, + "residual_p50-ms": 0.3419, + "residual_p95-ms": 0.6538, + "signatures/block": 33760.0, + "signatures/s": 168433.0, + "submit_p50-ms": 0.000902, + "submit_p95-ms": 0.08766, + "B/op": 45547920.0, + "allocs/op": 75161.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_4tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200244671.0, + "avg_cpu_cores": 0.03331, + "components/block": 64.0, + "cpu-ms/block": 6.669, + "feed_lag_p50-ms": 0.5335, + "feed_lag_p95-ms": 0.9768, + "mean_width": 4.0, + "ready_p50-ms": 0.6135, + "ready_p95-ms": 1.06, + "residual_p50-ms": 0.2598, + "residual_p95-ms": 0.2713, + "signatures/block": 256.0, + "signatures/s": 1278.0, + "submit_p50-ms": 0.002525, + "submit_p95-ms": 0.008676, + "B/op": 413741.0, + "allocs/op": 1227.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "sparse_4tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_4tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200802763.0, + "avg_cpu_cores": 0.02071, + "components/block": 64.0, + "cpu-ms/block": 4.159, + "feed_lag_p50-ms": 0.5448, + "feed_lag_p95-ms": 0.9858, + "mean_width": 4.0, + "ready_p50-ms": 0.5937, + "ready_p95-ms": 1.037, + "residual_p50-ms": 1.016, + "residual_p95-ms": 1.07, + "signatures/block": 256.0, + "signatures/s": 1275.0, + "submit_p50-ms": 0.001102, + "submit_p95-ms": 0.002816, + "B/op": 413741.0, + "allocs/op": 1227.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "sparse_4tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_4tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200470397.0, + "avg_cpu_cores": 0.02005, + "components/block": 64.0, + "cpu-ms/block": 4.019, + "feed_lag_p50-ms": 0.53, + "feed_lag_p95-ms": 0.9483, + "mean_width": 4.0, + "ready_p50-ms": 0.5769, + "ready_p95-ms": 1.0, + "residual_p50-ms": 0.3612, + "residual_p95-ms": 0.8751, + "signatures/block": 256.0, + "signatures/s": 1277.0, + "submit_p50-ms": 0.001022, + "submit_p95-ms": 0.003106, + "B/op": 413741.0, + "allocs/op": 1227.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "sparse_4tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_7tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200530663.0, + "avg_cpu_cores": 0.02064, + "components/block": 37.0, + "cpu-ms/block": 4.138, + "feed_lag_p50-ms": 0.5475, + "feed_lag_p95-ms": 1.006, + "mean_width": 6.919, + "ready_p50-ms": 0.6508, + "ready_p95-ms": 1.095, + "residual_p50-ms": 0.2603, + "residual_p95-ms": 1.101, + "signatures/block": 256.0, + "signatures/s": 1277.0, + "submit_p50-ms": 0.001413, + "submit_p95-ms": 0.003417, + "B/op": 381074.0, + "allocs/op": 931.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "sparse_7tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_7tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200704225.0, + "avg_cpu_cores": 0.0297, + "components/block": 37.0, + "cpu-ms/block": 5.961, + "feed_lag_p50-ms": 0.5458, + "feed_lag_p95-ms": 0.9953, + "mean_width": 6.919, + "ready_p50-ms": 0.6663, + "ready_p95-ms": 1.147, + "residual_p50-ms": 0.6189, + "residual_p95-ms": 1.129, + "signatures/block": 256.0, + "signatures/s": 1276.0, + "submit_p50-ms": 0.003116, + "submit_p95-ms": 0.008637, + "B/op": 381186.0, + "allocs/op": 932.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "sparse_7tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_7tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200734505.0, + "avg_cpu_cores": 0.01986, + "components/block": 37.0, + "cpu-ms/block": 3.987, + "feed_lag_p50-ms": 0.5511, + "feed_lag_p95-ms": 0.9991, + "mean_width": 6.919, + "ready_p50-ms": 0.6354, + "ready_p95-ms": 1.085, + "residual_p50-ms": 0.8372, + "residual_p95-ms": 1.059, + "signatures/block": 256.0, + "signatures/s": 1275.0, + "submit_p50-ms": 0.001192, + "submit_p95-ms": 0.003176, + "B/op": 381037.0, + "allocs/op": 930.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "sparse_7tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_8tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200612984.0, + "avg_cpu_cores": 0.01255, + "components/block": 32.0, + "cpu-ms/block": 2.517, + "feed_lag_p50-ms": 0.5718, + "feed_lag_p95-ms": 1.002, + "mean_width": 8.0, + "ready_p50-ms": 0.6479, + "ready_p95-ms": 1.064, + "residual_p50-ms": 0.4956, + "residual_p95-ms": 0.9127, + "signatures/block": 256.0, + "signatures/s": 1276.0, + "submit_p50-ms": 0.001432, + "submit_p95-ms": 0.00542, + "B/op": 420621.0, + "allocs/op": 878.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "sparse_8tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_8tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200664651.0, + "avg_cpu_cores": 0.01322, + "components/block": 32.0, + "cpu-ms/block": 2.652, + "feed_lag_p50-ms": 0.6362, + "feed_lag_p95-ms": 1.01, + "mean_width": 8.0, + "ready_p50-ms": 0.6894, + "ready_p95-ms": 1.085, + "residual_p50-ms": 0.688, + "residual_p95-ms": 0.7389, + "signatures/block": 256.0, + "signatures/s": 1276.0, + "submit_p50-ms": 0.001503, + "submit_p95-ms": 0.006863, + "B/op": 374829.0, + "allocs/op": 875.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "sparse_8tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_2/target_8/sparse_8tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200621059.0, + "avg_cpu_cores": 0.01625, + "components/block": 32.0, + "cpu-ms/block": 3.26, + "feed_lag_p50-ms": 0.6089, + "feed_lag_p95-ms": 1.027, + "mean_width": 8.0, + "ready_p50-ms": 0.6781, + "ready_p95-ms": 1.091, + "residual_p50-ms": 0.6671, + "residual_p95-ms": 0.8341, + "signatures/block": 256.0, + "signatures/s": 1276.0, + "submit_p50-ms": 0.002575, + "submit_p95-ms": 0.008015, + "B/op": 374941.0, + "allocs/op": 876.0, + "source": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "sparse_8tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/catchup-8", + "iterations": 3, + "ns/op": 95848314.0, + "avg_cpu_cores": 3.962, + "components/block": 1.0, + "cpu-ms/block": 379.7, + "feed_lag_p50-ms": 0.000501, + "feed_lag_p95-ms": 0.000882, + "mean_width": 4.0, + "ready_p50-ms": 97.21, + "ready_p95-ms": 97.49, + "residual_p50-ms": 97.21, + "residual_p95-ms": 97.49, + "signatures/block": 33760.0, + "signatures/s": 352223.0, + "submit_p50-ms": 0.006161, + "submit_p95-ms": 0.01999, + "B/op": 44616002.0, + "allocs/op": 67558.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "catchup", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/catchup-8", + "iterations": 3, + "ns/op": 93784047.0, + "avg_cpu_cores": 3.933, + "components/block": 1.0, + "cpu-ms/block": 368.9, + "feed_lag_p50-ms": 0.00026, + "feed_lag_p95-ms": 0.000581, + "mean_width": 4.0, + "ready_p50-ms": 97.49, + "ready_p95-ms": 98.78, + "residual_p50-ms": 97.49, + "residual_p95-ms": 98.78, + "signatures/block": 33760.0, + "signatures/s": 359976.0, + "submit_p50-ms": 0.004298, + "submit_p95-ms": 0.00538, + "B/op": 44570261.0, + "allocs/op": 67556.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "catchup", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/catchup-8", + "iterations": 3, + "ns/op": 83340419.0, + "avg_cpu_cores": 4.08, + "components/block": 1.0, + "cpu-ms/block": 340.1, + "feed_lag_p50-ms": 0.00026, + "feed_lag_p95-ms": 0.000481, + "mean_width": 4.0, + "ready_p50-ms": 83.48, + "ready_p95-ms": 84.27, + "residual_p50-ms": 83.48, + "residual_p95-ms": 84.27, + "signatures/block": 33760.0, + "signatures/s": 405086.0, + "submit_p50-ms": 0.004358, + "submit_p95-ms": 0.004779, + "B/op": 44615936.0, + "allocs/op": 67557.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "catchup", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 284770040.0, + "avg_cpu_cores": 1.189, + "components/block": 689.0, + "cpu-ms/block": 338.7, + "feed_lag_p50-ms": 100.2, + "feed_lag_p95-ms": 190.3, + "mean_width": 4.0, + "ready_p50-ms": 184.7, + "ready_p95-ms": 274.8, + "residual_p50-ms": 84.7, + "residual_p95-ms": 84.9, + "signatures/block": 33760.0, + "signatures/s": 118552.0, + "submit_p50-ms": 0.0142, + "submit_p95-ms": 0.01501, + "B/op": 44627381.0, + "allocs/op": 67557.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 283332704.0, + "avg_cpu_cores": 1.187, + "components/block": 689.0, + "cpu-ms/block": 336.2, + "feed_lag_p50-ms": 100.4, + "feed_lag_p95-ms": 190.5, + "mean_width": 4.0, + "ready_p50-ms": 183.3, + "ready_p95-ms": 273.5, + "residual_p50-ms": 83.42, + "residual_p95-ms": 83.48, + "signatures/block": 33760.0, + "signatures/s": 119153.0, + "submit_p50-ms": 0.01509, + "submit_p95-ms": 0.01671, + "B/op": 44764728.0, + "allocs/op": 67563.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 288602671.0, + "avg_cpu_cores": 1.226, + "components/block": 689.0, + "cpu-ms/block": 353.9, + "feed_lag_p50-ms": 100.4, + "feed_lag_p95-ms": 190.5, + "mean_width": 4.0, + "ready_p50-ms": 188.6, + "ready_p95-ms": 278.7, + "residual_p50-ms": 82.52, + "residual_p95-ms": 101.5, + "signatures/block": 33760.0, + "signatures/s": 116977.0, + "submit_p50-ms": 0.01444, + "submit_p95-ms": 0.01669, + "B/op": 44627397.0, + "allocs/op": 67557.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_after_complete", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200391623.0, + "avg_cpu_cores": 1.7, + "components/block": 689.0, + "cpu-ms/block": 340.6, + "feed_lag_p50-ms": 0.1294, + "feed_lag_p95-ms": 0.66, + "mean_width": 3.77, + "ready_p50-ms": 0.4949, + "ready_p95-ms": 1.08, + "residual_p50-ms": 0.3539, + "residual_p95-ms": 0.5576, + "signatures/block": 33760.0, + "signatures/s": 168470.0, + "submit_p50-ms": 0.000611, + "submit_p95-ms": 0.001674, + "B/op": 45465394.0, + "allocs/op": 75165.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200606793.0, + "avg_cpu_cores": 1.834, + "components/block": 689.0, + "cpu-ms/block": 368.0, + "feed_lag_p50-ms": 0.09882, + "feed_lag_p95-ms": 0.6699, + "mean_width": 3.77, + "ready_p50-ms": 0.5168, + "ready_p95-ms": 1.161, + "residual_p50-ms": 0.5678, + "residual_p95-ms": 0.7021, + "signatures/block": 33760.0, + "signatures/s": 168289.0, + "submit_p50-ms": 0.000742, + "submit_p95-ms": 0.002705, + "B/op": 45554293.0, + "allocs/op": 75146.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200390250.0, + "avg_cpu_cores": 1.799, + "components/block": 689.0, + "cpu-ms/block": 360.4, + "feed_lag_p50-ms": 0.1082, + "feed_lag_p95-ms": 0.6858, + "mean_width": 3.77, + "ready_p50-ms": 0.5309, + "ready_p95-ms": 1.29, + "residual_p50-ms": 0.2986, + "residual_p95-ms": 0.5996, + "signatures/block": 33760.0, + "signatures/s": 168471.0, + "submit_p50-ms": 0.000731, + "submit_p95-ms": 0.002485, + "B/op": 45417898.0, + "allocs/op": 75147.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_4tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200708870.0, + "avg_cpu_cores": 0.02342, + "components/block": 64.0, + "cpu-ms/block": 4.7, + "feed_lag_p50-ms": 0.5677, + "feed_lag_p95-ms": 0.9727, + "mean_width": 4.0, + "ready_p50-ms": 0.6206, + "ready_p95-ms": 1.032, + "residual_p50-ms": 0.5738, + "residual_p95-ms": 1.11, + "signatures/block": 256.0, + "signatures/s": 1275.0, + "submit_p50-ms": 0.001583, + "submit_p95-ms": 0.004359, + "B/op": 423106.0, + "allocs/op": 1229.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "sparse_4tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_4tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200711469.0, + "avg_cpu_cores": 0.02988, + "components/block": 64.0, + "cpu-ms/block": 5.998, + "feed_lag_p50-ms": 0.5955, + "feed_lag_p95-ms": 1.001, + "mean_width": 4.0, + "ready_p50-ms": 0.669, + "ready_p95-ms": 1.073, + "residual_p50-ms": 0.6728, + "residual_p95-ms": 0.8759, + "signatures/block": 256.0, + "signatures/s": 1275.0, + "submit_p50-ms": 0.002254, + "submit_p95-ms": 0.00532, + "B/op": 422957.0, + "allocs/op": 1227.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "sparse_4tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_4tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200458906.0, + "avg_cpu_cores": 0.0246, + "components/block": 64.0, + "cpu-ms/block": 4.931, + "feed_lag_p50-ms": 0.5634, + "feed_lag_p95-ms": 0.9819, + "mean_width": 4.0, + "ready_p50-ms": 0.6169, + "ready_p95-ms": 1.037, + "residual_p50-ms": 0.4628, + "residual_p95-ms": 0.6882, + "signatures/block": 256.0, + "signatures/s": 1277.0, + "submit_p50-ms": 0.001663, + "submit_p95-ms": 0.004278, + "B/op": 422957.0, + "allocs/op": 1227.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "sparse_4tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_7tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200411787.0, + "avg_cpu_cores": 0.025, + "components/block": 37.0, + "cpu-ms/block": 5.011, + "feed_lag_p50-ms": 0.5475, + "feed_lag_p95-ms": 0.9961, + "mean_width": 3.507, + "ready_p50-ms": 0.6059, + "ready_p95-ms": 1.064, + "residual_p50-ms": 0.2112, + "residual_p95-ms": 0.8439, + "signatures/block": 256.0, + "signatures/s": 1277.0, + "submit_p50-ms": 0.001603, + "submit_p95-ms": 0.008125, + "B/op": 386365.0, + "allocs/op": 930.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "sparse_7tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_7tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200155541.0, + "avg_cpu_cores": 0.02172, + "components/block": 37.0, + "cpu-ms/block": 4.348, + "feed_lag_p50-ms": 0.5305, + "feed_lag_p95-ms": 0.995, + "mean_width": 3.507, + "ready_p50-ms": 0.5883, + "ready_p95-ms": 1.045, + "residual_p50-ms": 0.1636, + "residual_p95-ms": 0.1931, + "signatures/block": 256.0, + "signatures/s": 1279.0, + "submit_p50-ms": 0.001372, + "submit_p95-ms": 0.003166, + "B/op": 386365.0, + "allocs/op": 930.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "sparse_7tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_7tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200521630.0, + "avg_cpu_cores": 0.0282, + "components/block": 37.0, + "cpu-ms/block": 5.655, + "feed_lag_p50-ms": 0.5292, + "feed_lag_p95-ms": 0.9752, + "mean_width": 3.507, + "ready_p50-ms": 0.5981, + "ready_p95-ms": 1.088, + "residual_p50-ms": 0.5204, + "residual_p95-ms": 0.7328, + "signatures/block": 256.0, + "signatures/s": 1277.0, + "submit_p50-ms": 0.001944, + "submit_p95-ms": 0.0128, + "B/op": 386365.0, + "allocs/op": 930.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "sparse_7tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_8tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200734011.0, + "avg_cpu_cores": 0.01795, + "components/block": 32.0, + "cpu-ms/block": 3.602, + "feed_lag_p50-ms": 0.6295, + "feed_lag_p95-ms": 1.028, + "mean_width": 4.0, + "ready_p50-ms": 0.6833, + "ready_p95-ms": 1.083, + "residual_p50-ms": 0.6833, + "residual_p95-ms": 0.8221, + "signatures/block": 256.0, + "signatures/s": 1275.0, + "submit_p50-ms": 0.001363, + "submit_p95-ms": 0.002945, + "B/op": 379437.0, + "allocs/op": 875.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "sparse_8tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_8tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 201052107.0, + "avg_cpu_cores": 0.02754, + "components/block": 32.0, + "cpu-ms/block": 5.536, + "feed_lag_p50-ms": 0.6295, + "feed_lag_p95-ms": 1.034, + "mean_width": 4.0, + "ready_p50-ms": 0.7177, + "ready_p95-ms": 1.115, + "residual_p50-ms": 1.048, + "residual_p95-ms": 1.051, + "signatures/block": 256.0, + "signatures/s": 1273.0, + "submit_p50-ms": 0.001994, + "submit_p95-ms": 0.02698, + "B/op": 379437.0, + "allocs/op": 875.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "sparse_8tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_4/sparse_8tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200711809.0, + "avg_cpu_cores": 0.01892, + "components/block": 32.0, + "cpu-ms/block": 3.797, + "feed_lag_p50-ms": 0.6447, + "feed_lag_p95-ms": 1.037, + "mean_width": 4.0, + "ready_p50-ms": 0.6915, + "ready_p95-ms": 1.093, + "residual_p50-ms": 0.682, + "residual_p95-ms": 0.8024, + "signatures/block": 256.0, + "signatures/s": 1275.0, + "submit_p50-ms": 0.001643, + "submit_p95-ms": 0.003516, + "B/op": 379624.0, + "allocs/op": 877.0, + "source": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "sparse_8tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/catchup-8", + "iterations": 3, + "ns/op": 45816383.0, + "avg_cpu_cores": 4.073, + "components/block": 1.0, + "cpu-ms/block": 186.6, + "feed_lag_p50-ms": 0.0002, + "feed_lag_p95-ms": 0.000491, + "mean_width": 8.0, + "ready_p50-ms": 45.06, + "ready_p95-ms": 48.98, + "residual_p50-ms": 45.06, + "residual_p95-ms": 48.98, + "signatures/block": 33760.0, + "signatures/s": 736854.0, + "submit_p50-ms": 0.004338, + "submit_p95-ms": 0.004658, + "B/op": 44570576.0, + "allocs/op": 67557.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "catchup", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/catchup-8", + "iterations": 3, + "ns/op": 56218950.0, + "avg_cpu_cores": 3.966, + "components/block": 1.0, + "cpu-ms/block": 223.0, + "feed_lag_p50-ms": 0.000501, + "feed_lag_p95-ms": 0.000551, + "mean_width": 8.0, + "ready_p50-ms": 55.44, + "ready_p95-ms": 58.07, + "residual_p50-ms": 55.44, + "residual_p95-ms": 58.07, + "signatures/block": 33760.0, + "signatures/s": 600509.0, + "submit_p50-ms": 0.006312, + "submit_p95-ms": 0.0147, + "B/op": 44524608.0, + "allocs/op": 67553.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "catchup", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/catchup-8", + "iterations": 3, + "ns/op": 61550045.0, + "avg_cpu_cores": 3.871, + "components/block": 1.0, + "cpu-ms/block": 238.3, + "feed_lag_p50-ms": 0.000301, + "feed_lag_p95-ms": 0.000912, + "mean_width": 8.0, + "ready_p50-ms": 60.95, + "ready_p95-ms": 62.93, + "residual_p50-ms": 60.95, + "residual_p95-ms": 62.93, + "signatures/block": 33760.0, + "signatures/s": 548497.0, + "submit_p50-ms": 0.007384, + "submit_p95-ms": 0.01248, + "B/op": 44662146.0, + "allocs/op": 67562.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "catchup", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 248039377.0, + "avg_cpu_cores": 0.7751, + "components/block": 689.0, + "cpu-ms/block": 192.2, + "feed_lag_p50-ms": 100.4, + "feed_lag_p95-ms": 190.5, + "mean_width": 8.0, + "ready_p50-ms": 148.0, + "ready_p95-ms": 238.1, + "residual_p50-ms": 46.77, + "residual_p95-ms": 54.35, + "signatures/block": 33760.0, + "signatures/s": 136107.0, + "submit_p50-ms": 0.01645, + "submit_p95-ms": 0.04039, + "B/op": 44398781.0, + "allocs/op": 67546.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 244855756.0, + "avg_cpu_cores": 0.7431, + "components/block": 689.0, + "cpu-ms/block": 182.0, + "feed_lag_p50-ms": 100.4, + "feed_lag_p95-ms": 190.5, + "mean_width": 8.0, + "ready_p50-ms": 144.8, + "ready_p95-ms": 234.9, + "residual_p50-ms": 44.62, + "residual_p95-ms": 45.36, + "signatures/block": 33760.0, + "signatures/s": 137877.0, + "submit_p50-ms": 0.01356, + "submit_p95-ms": 0.01404, + "B/op": 44627629.0, + "allocs/op": 67556.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/tip_200ms_after_complete-8", + "iterations": 3, + "ns/op": 246211332.0, + "avg_cpu_cores": 0.7541, + "components/block": 689.0, + "cpu-ms/block": 185.7, + "feed_lag_p50-ms": 100.4, + "feed_lag_p95-ms": 190.5, + "mean_width": 8.0, + "ready_p50-ms": 146.2, + "ready_p95-ms": 236.3, + "residual_p50-ms": 46.81, + "residual_p95-ms": 47.71, + "signatures/block": 33760.0, + "signatures/s": 137118.0, + "submit_p50-ms": 0.01444, + "submit_p95-ms": 0.01546, + "B/op": 44490194.0, + "allocs/op": 67549.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_after_complete", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200653199.0, + "avg_cpu_cores": 1.155, + "components/block": 689.0, + "cpu-ms/block": 231.7, + "feed_lag_p50-ms": 0.2466, + "feed_lag_p95-ms": 0.7849, + "mean_width": 7.001, + "ready_p50-ms": 0.5281, + "ready_p95-ms": 1.123, + "residual_p50-ms": 0.667, + "residual_p95-ms": 0.9134, + "signatures/block": 33760.0, + "signatures/s": 168250.0, + "submit_p50-ms": 0.000821, + "submit_p95-ms": 0.002454, + "B/op": 45684682.0, + "allocs/op": 75142.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200414118.0, + "avg_cpu_cores": 0.9499, + "components/block": 689.0, + "cpu-ms/block": 190.4, + "feed_lag_p50-ms": 0.295, + "feed_lag_p95-ms": 0.782, + "mean_width": 7.001, + "ready_p50-ms": 0.5114, + "ready_p95-ms": 1.017, + "residual_p50-ms": 0.2302, + "residual_p95-ms": 0.831, + "signatures/block": 33760.0, + "signatures/s": 168451.0, + "submit_p50-ms": 0.000531, + "submit_p95-ms": 0.001473, + "B/op": 45775912.0, + "allocs/op": 75143.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/tip_200ms_overlap-8", + "iterations": 3, + "ns/op": 200256049.0, + "avg_cpu_cores": 0.9622, + "components/block": 689.0, + "cpu-ms/block": 192.7, + "feed_lag_p50-ms": 0.2963, + "feed_lag_p95-ms": 0.7859, + "mean_width": 7.001, + "ready_p50-ms": 0.5143, + "ready_p95-ms": 1.015, + "residual_p50-ms": 0.1938, + "residual_p95-ms": 0.4353, + "signatures/block": 33760.0, + "signatures/s": 168584.0, + "submit_p50-ms": 0.000561, + "submit_p95-ms": 0.001704, + "B/op": 45825840.0, + "allocs/op": 75182.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_4tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200387649.0, + "avg_cpu_cores": 0.02538, + "components/block": 64.0, + "cpu-ms/block": 5.086, + "feed_lag_p50-ms": 0.5414, + "feed_lag_p95-ms": 0.9647, + "mean_width": 4.0, + "ready_p50-ms": 0.5928, + "ready_p95-ms": 1.033, + "residual_p50-ms": 0.5171, + "residual_p95-ms": 0.5489, + "signatures/block": 256.0, + "signatures/s": 1278.0, + "submit_p50-ms": 0.001523, + "submit_p95-ms": 0.005641, + "B/op": 439648.0, + "allocs/op": 1230.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "sparse_4tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_4tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200883060.0, + "avg_cpu_cores": 0.03008, + "components/block": 64.0, + "cpu-ms/block": 6.043, + "feed_lag_p50-ms": 0.5974, + "feed_lag_p95-ms": 0.9731, + "mean_width": 4.0, + "ready_p50-ms": 0.6814, + "ready_p95-ms": 1.066, + "residual_p50-ms": 1.116, + "residual_p95-ms": 1.146, + "signatures/block": 256.0, + "signatures/s": 1274.0, + "submit_p50-ms": 0.002054, + "submit_p95-ms": 0.007835, + "B/op": 439349.0, + "allocs/op": 1228.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "sparse_4tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_4tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200468704.0, + "avg_cpu_cores": 0.02652, + "components/block": 64.0, + "cpu-ms/block": 5.317, + "feed_lag_p50-ms": 0.5614, + "feed_lag_p95-ms": 0.9687, + "mean_width": 4.0, + "ready_p50-ms": 0.6253, + "ready_p95-ms": 1.041, + "residual_p50-ms": 0.3181, + "residual_p95-ms": 0.7522, + "signatures/block": 256.0, + "signatures/s": 1277.0, + "submit_p50-ms": 0.002074, + "submit_p95-ms": 0.00491, + "B/op": 439341.0, + "allocs/op": 1227.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "sparse_4tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_7tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200580146.0, + "avg_cpu_cores": 0.02269, + "components/block": 37.0, + "cpu-ms/block": 4.551, + "feed_lag_p50-ms": 0.523, + "feed_lag_p95-ms": 1.004, + "mean_width": 6.919, + "ready_p50-ms": 0.6231, + "ready_p95-ms": 1.099, + "residual_p50-ms": 0.448, + "residual_p95-ms": 1.093, + "signatures/block": 256.0, + "signatures/s": 1276.0, + "submit_p50-ms": 0.001423, + "submit_p95-ms": 0.00499, + "B/op": 395837.0, + "allocs/op": 930.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "sparse_7tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_7tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200704543.0, + "avg_cpu_cores": 0.02296, + "components/block": 37.0, + "cpu-ms/block": 4.607, + "feed_lag_p50-ms": 0.5328, + "feed_lag_p95-ms": 1.022, + "mean_width": 6.919, + "ready_p50-ms": 0.6489, + "ready_p95-ms": 1.107, + "residual_p50-ms": 0.648, + "residual_p95-ms": 1.079, + "signatures/block": 256.0, + "signatures/s": 1276.0, + "submit_p50-ms": 0.001783, + "submit_p95-ms": 0.008186, + "B/op": 395837.0, + "allocs/op": 930.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "sparse_7tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_7tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200601736.0, + "avg_cpu_cores": 0.02604, + "components/block": 37.0, + "cpu-ms/block": 5.224, + "feed_lag_p50-ms": 0.5685, + "feed_lag_p95-ms": 1.009, + "mean_width": 6.919, + "ready_p50-ms": 0.6868, + "ready_p95-ms": 1.128, + "residual_p50-ms": 0.6345, + "residual_p95-ms": 0.912, + "signatures/block": 256.0, + "signatures/s": 1276.0, + "submit_p50-ms": 0.001794, + "submit_p95-ms": 0.01362, + "B/op": 395912.0, + "allocs/op": 931.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "sparse_7tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_8tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200649189.0, + "avg_cpu_cores": 0.02026, + "components/block": 32.0, + "cpu-ms/block": 4.065, + "feed_lag_p50-ms": 0.587, + "feed_lag_p95-ms": 1.023, + "mean_width": 8.0, + "ready_p50-ms": 0.6574, + "ready_p95-ms": 1.106, + "residual_p50-ms": 0.5239, + "residual_p95-ms": 0.9372, + "signatures/block": 256.0, + "signatures/s": 1276.0, + "submit_p50-ms": 0.002274, + "submit_p95-ms": 0.02225, + "B/op": 387637.0, + "allocs/op": 876.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "sparse_8tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_8tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200762942.0, + "avg_cpu_cores": 0.0144, + "components/block": 32.0, + "cpu-ms/block": 2.89, + "feed_lag_p50-ms": 0.5812, + "feed_lag_p95-ms": 1.006, + "mean_width": 8.0, + "ready_p50-ms": 0.657, + "ready_p95-ms": 1.083, + "residual_p50-ms": 0.6634, + "residual_p95-ms": 1.04, + "signatures/block": 256.0, + "signatures/s": 1275.0, + "submit_p50-ms": 0.001613, + "submit_p95-ms": 0.01741, + "B/op": 387629.0, + "allocs/op": 875.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "sparse_8tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + }, + { + "name": "BenchmarkTransactionVerificationFlow/generated_1232B/workers_4/target_8/sparse_8tx_200ms_overlap-8", + "iterations": 3, + "ns/op": 200762972.0, + "avg_cpu_cores": 0.01549, + "components/block": 32.0, + "cpu-ms/block": 3.109, + "feed_lag_p50-ms": 0.6425, + "feed_lag_p95-ms": 1.017, + "mean_width": 8.0, + "ready_p50-ms": 0.6983, + "ready_p95-ms": 1.092, + "residual_p50-ms": 0.6307, + "residual_p95-ms": 1.064, + "signatures/block": 256.0, + "signatures/s": 1275.0, + "submit_p50-ms": 0.001583, + "submit_p95-ms": 0.017, + "B/op": 387629.0, + "allocs/op": 875.0, + "source": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "sparse_8tx_200ms_overlap", + "log": "generated-1232-pool-flow.log" + } + ], + "summary": [ + { + "family": "captured", + "workers": 2, + "target": 4, + "scenario": "catchup", + "samples": 9, + "sources": [ + "captured_2622581", + "captured_2622653", + "captured_2624657" + ], + "median": { + "ns/op": 155918266.0, + "cpu-ms/block": 317.8, + "mean_width": 4.0, + "ready_p50-ms": 156.2, + "ready_p95-ms": 162.0, + "submit_p95-ms": 0.007063, + "feed_lag_p95-ms": 0.000491, + "residual_p50-ms": 156.2, + "residual_p95-ms": 162.0, + "signatures/s": 216524.0 + } + }, + { + "family": "captured", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_after_complete", + "samples": 9, + "sources": [ + "captured_2622581", + "captured_2622653", + "captured_2624657" + ], + "median": { + "ns/op": 349811570.0, + "cpu-ms/block": 306.6, + "mean_width": 4.0, + "ready_p50-ms": 249.2, + "ready_p95-ms": 340.4, + "submit_p95-ms": 0.01914, + "feed_lag_p95-ms": 191.2, + "residual_p50-ms": 150.1, + "residual_p95-ms": 153.0, + "signatures/s": 96509.0 + } + }, + { + "family": "captured", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_overlap", + "samples": 9, + "sources": [ + "captured_2622581", + "captured_2622653", + "captured_2624657" + ], + "median": { + "ns/op": 201052815.0, + "cpu-ms/block": 301.7, + "mean_width": 3.956, + "ready_p50-ms": 1.588, + "ready_p95-ms": 2.484, + "submit_p95-ms": 0.002805, + "feed_lag_p95-ms": 0.8607, + "residual_p50-ms": 0.9514, + "residual_p95-ms": 1.38, + "signatures/s": 167916.0 + } + }, + { + "family": "captured", + "workers": 2, + "target": 8, + "scenario": "catchup", + "samples": 9, + "sources": [ + "captured_2622581", + "captured_2622653", + "captured_2624657" + ], + "median": { + "ns/op": 77785688.0, + "cpu-ms/block": 158.7, + "mean_width": 8.0, + "ready_p50-ms": 76.4, + "ready_p95-ms": 81.28, + "submit_p95-ms": 0.006552, + "feed_lag_p95-ms": 0.000531, + "residual_p50-ms": 76.4, + "residual_p95-ms": 81.28, + "signatures/s": 434013.0 + } + }, + { + "family": "captured", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_after_complete", + "samples": 9, + "sources": [ + "captured_2622581", + "captured_2622653", + "captured_2624657" + ], + "median": { + "ns/op": 276093363.0, + "cpu-ms/block": 154.0, + "mean_width": 8.0, + "ready_p50-ms": 176.0, + "ready_p95-ms": 267.2, + "submit_p95-ms": 0.01683, + "feed_lag_p95-ms": 191.3, + "residual_p50-ms": 75.77, + "residual_p95-ms": 77.62, + "signatures/s": 122277.0 + } + }, + { + "family": "captured", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_overlap", + "samples": 9, + "sources": [ + "captured_2622581", + "captured_2622653", + "captured_2624657" + ], + "median": { + "ns/op": 201053633.0, + "cpu-ms/block": 162.9, + "mean_width": 7.912, + "ready_p50-ms": 1.16, + "ready_p95-ms": 1.674, + "submit_p95-ms": 0.003086, + "feed_lag_p95-ms": 0.973, + "residual_p50-ms": 1.053, + "residual_p95-ms": 1.338, + "signatures/s": 167915.0 + } + }, + { + "family": "captured", + "workers": 4, + "target": 4, + "scenario": "catchup", + "samples": 9, + "sources": [ + "captured_2622581", + "captured_2622653", + "captured_2624657" + ], + "median": { + "ns/op": 78168545.0, + "cpu-ms/block": 308.9, + "mean_width": 4.0, + "ready_p50-ms": 76.63, + "ready_p95-ms": 80.96, + "submit_p95-ms": 0.006863, + "feed_lag_p95-ms": 0.000611, + "residual_p50-ms": 76.63, + "residual_p95-ms": 80.96, + "signatures/s": 431887.0 + } + }, + { + "family": "captured", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_after_complete", + "samples": 9, + "sources": [ + "captured_2622581", + "captured_2622653", + "captured_2624657" + ], + "median": { + "ns/op": 277358928.0, + "cpu-ms/block": 307.9, + "mean_width": 4.0, + "ready_p50-ms": 176.8, + "ready_p95-ms": 268.0, + "submit_p95-ms": 0.01613, + "feed_lag_p95-ms": 191.3, + "residual_p50-ms": 76.69, + "residual_p95-ms": 79.21, + "signatures/s": 121720.0 + } + }, + { + "family": "captured", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_overlap", + "samples": 9, + "sources": [ + "captured_2622581", + "captured_2622653", + "captured_2624657" + ], + "median": { + "ns/op": 200821431.0, + "cpu-ms/block": 302.0, + "mean_width": 3.956, + "ready_p50-ms": 1.117, + "ready_p95-ms": 1.659, + "submit_p95-ms": 0.003016, + "feed_lag_p95-ms": 0.9812, + "residual_p50-ms": 0.9866, + "residual_p95-ms": 1.164, + "signatures/s": 168110.0 + } + }, + { + "family": "captured", + "workers": 4, + "target": 8, + "scenario": "catchup", + "samples": 9, + "sources": [ + "captured_2622581", + "captured_2622653", + "captured_2624657" + ], + "median": { + "ns/op": 39479657.0, + "cpu-ms/block": 158.5, + "mean_width": 8.0, + "ready_p50-ms": 39.31, + "ready_p95-ms": 40.18, + "submit_p95-ms": 0.00515, + "feed_lag_p95-ms": 0.000481, + "residual_p50-ms": 39.31, + "residual_p95-ms": 40.18, + "signatures/s": 855124.0 + } + }, + { + "family": "captured", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_after_complete", + "samples": 9, + "sources": [ + "captured_2622581", + "captured_2622653", + "captured_2624657" + ], + "median": { + "ns/op": 241004536.0, + "cpu-ms/block": 160.8, + "mean_width": 8.0, + "ready_p50-ms": 141.0, + "ready_p95-ms": 232.2, + "submit_p95-ms": 0.01687, + "feed_lag_p95-ms": 191.3, + "residual_p50-ms": 41.37, + "residual_p95-ms": 43.41, + "signatures/s": 140080.0 + } + }, + { + "family": "captured", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_overlap", + "samples": 9, + "sources": [ + "captured_2622581", + "captured_2622653", + "captured_2624657" + ], + "median": { + "ns/op": 200864502.0, + "cpu-ms/block": 173.4, + "mean_width": 7.912, + "ready_p50-ms": 0.9103, + "ready_p95-ms": 1.39, + "submit_p95-ms": 0.004097, + "feed_lag_p95-ms": 1.002, + "residual_p50-ms": 0.9549, + "residual_p95-ms": 1.132, + "signatures/s": 168074.0 + } + }, + { + "family": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "catchup", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 165232107.0, + "cpu-ms/block": 342.6, + "mean_width": 4.0, + "ready_p50-ms": 163.8, + "ready_p95-ms": 171.9, + "submit_p95-ms": 0.005961, + "feed_lag_p95-ms": 0.000471, + "residual_p50-ms": 163.8, + "residual_p95-ms": 171.9, + "signatures/s": 204319.0 + } + }, + { + "family": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "sparse_4tx_200ms_overlap", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 200548807.0, + "cpu-ms/block": 4.324, + "mean_width": 4.0, + "ready_p50-ms": 0.5792, + "ready_p95-ms": 1.006, + "submit_p95-ms": 0.003516, + "feed_lag_p95-ms": 0.9542, + "residual_p50-ms": 0.4003, + "residual_p95-ms": 0.9766, + "signatures/s": 1276.0 + } + }, + { + "family": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "sparse_7tx_200ms_overlap", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 200734923.0, + "cpu-ms/block": 4.48, + "mean_width": 3.507, + "ready_p50-ms": 0.6193, + "ready_p95-ms": 1.06, + "submit_p95-ms": 0.003787, + "feed_lag_p95-ms": 1.003, + "residual_p50-ms": 0.8195, + "residual_p95-ms": 1.028, + "signatures/s": 1275.0 + } + }, + { + "family": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "sparse_8tx_200ms_overlap", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 200821061.0, + "cpu-ms/block": 4.551, + "mean_width": 4.0, + "ready_p50-ms": 0.6833, + "ready_p95-ms": 1.099, + "submit_p95-ms": 0.01049, + "feed_lag_p95-ms": 1.025, + "residual_p50-ms": 0.8705, + "residual_p95-ms": 0.9203, + "signatures/s": 1275.0 + } + }, + { + "family": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_after_complete", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 359479815.0, + "cpu-ms/block": 329.7, + "mean_width": 4.0, + "ready_p50-ms": 259.5, + "ready_p95-ms": 349.6, + "submit_p95-ms": 0.01513, + "feed_lag_p95-ms": 190.7, + "residual_p50-ms": 159.4, + "residual_p95-ms": 160.9, + "signatures/s": 93913.0 + } + }, + { + "family": "generated_1232B", + "workers": 2, + "target": 4, + "scenario": "tip_200ms_overlap", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 200405779.0, + "cpu-ms/block": 371.8, + "mean_width": 3.77, + "ready_p50-ms": 0.9154, + "ready_p95-ms": 3.697, + "submit_p95-ms": 0.5208, + "feed_lag_p95-ms": 2.251, + "residual_p50-ms": 0.3923, + "residual_p95-ms": 0.5034, + "signatures/s": 168458.0 + } + }, + { + "family": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "catchup", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 86113936.0, + "cpu-ms/block": 180.0, + "mean_width": 8.0, + "ready_p50-ms": 84.68, + "ready_p95-ms": 89.35, + "submit_p95-ms": 0.00537, + "feed_lag_p95-ms": 0.000732, + "residual_p50-ms": 84.68, + "residual_p95-ms": 89.35, + "signatures/s": 392039.0 + } + }, + { + "family": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "sparse_4tx_200ms_overlap", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 200470397.0, + "cpu-ms/block": 4.159, + "mean_width": 4.0, + "ready_p50-ms": 0.5937, + "ready_p95-ms": 1.037, + "submit_p95-ms": 0.003106, + "feed_lag_p95-ms": 0.9768, + "residual_p50-ms": 0.3612, + "residual_p95-ms": 0.8751, + "signatures/s": 1277.0 + } + }, + { + "family": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "sparse_7tx_200ms_overlap", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 200704225.0, + "cpu-ms/block": 4.138, + "mean_width": 6.919, + "ready_p50-ms": 0.6508, + "ready_p95-ms": 1.095, + "submit_p95-ms": 0.003417, + "feed_lag_p95-ms": 0.9991, + "residual_p50-ms": 0.6189, + "residual_p95-ms": 1.101, + "signatures/s": 1276.0 + } + }, + { + "family": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "sparse_8tx_200ms_overlap", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 200621059.0, + "cpu-ms/block": 2.652, + "mean_width": 8.0, + "ready_p50-ms": 0.6781, + "ready_p95-ms": 1.085, + "submit_p95-ms": 0.006863, + "feed_lag_p95-ms": 1.01, + "residual_p50-ms": 0.6671, + "residual_p95-ms": 0.8341, + "signatures/s": 1276.0 + } + }, + { + "family": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_after_complete", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 285857000.0, + "cpu-ms/block": 179.6, + "mean_width": 8.0, + "ready_p50-ms": 185.9, + "ready_p95-ms": 276.0, + "submit_p95-ms": 0.01781, + "feed_lag_p95-ms": 190.5, + "residual_p50-ms": 85.29, + "residual_p95-ms": 87.23, + "signatures/s": 118101.0 + } + }, + { + "family": "generated_1232B", + "workers": 2, + "target": 8, + "scenario": "tip_200ms_overlap", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 200393747.0, + "cpu-ms/block": 192.4, + "mean_width": 7.001, + "ready_p50-ms": 0.5021, + "ready_p95-ms": 1.098, + "submit_p95-ms": 0.002294, + "feed_lag_p95-ms": 0.6496, + "residual_p50-ms": 0.3419, + "residual_p95-ms": 0.6362, + "signatures/s": 168468.0 + } + }, + { + "family": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "catchup", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 93784047.0, + "cpu-ms/block": 368.9, + "mean_width": 4.0, + "ready_p50-ms": 97.21, + "ready_p95-ms": 97.49, + "submit_p95-ms": 0.00538, + "feed_lag_p95-ms": 0.000581, + "residual_p50-ms": 97.21, + "residual_p95-ms": 97.49, + "signatures/s": 359976.0 + } + }, + { + "family": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "sparse_4tx_200ms_overlap", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 200708870.0, + "cpu-ms/block": 4.931, + "mean_width": 4.0, + "ready_p50-ms": 0.6206, + "ready_p95-ms": 1.037, + "submit_p95-ms": 0.004359, + "feed_lag_p95-ms": 0.9819, + "residual_p50-ms": 0.5738, + "residual_p95-ms": 0.8759, + "signatures/s": 1275.0 + } + }, + { + "family": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "sparse_7tx_200ms_overlap", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 200411787.0, + "cpu-ms/block": 5.011, + "mean_width": 3.507, + "ready_p50-ms": 0.5981, + "ready_p95-ms": 1.064, + "submit_p95-ms": 0.008125, + "feed_lag_p95-ms": 0.995, + "residual_p50-ms": 0.2112, + "residual_p95-ms": 0.7328, + "signatures/s": 1277.0 + } + }, + { + "family": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "sparse_8tx_200ms_overlap", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 200734011.0, + "cpu-ms/block": 3.797, + "mean_width": 4.0, + "ready_p50-ms": 0.6915, + "ready_p95-ms": 1.093, + "submit_p95-ms": 0.003516, + "feed_lag_p95-ms": 1.034, + "residual_p50-ms": 0.6833, + "residual_p95-ms": 0.8221, + "signatures/s": 1275.0 + } + }, + { + "family": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_after_complete", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 284770040.0, + "cpu-ms/block": 338.7, + "mean_width": 4.0, + "ready_p50-ms": 184.7, + "ready_p95-ms": 274.8, + "submit_p95-ms": 0.01669, + "feed_lag_p95-ms": 190.5, + "residual_p50-ms": 83.42, + "residual_p95-ms": 84.9, + "signatures/s": 118552.0 + } + }, + { + "family": "generated_1232B", + "workers": 4, + "target": 4, + "scenario": "tip_200ms_overlap", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 200391623.0, + "cpu-ms/block": 360.4, + "mean_width": 3.77, + "ready_p50-ms": 0.5168, + "ready_p95-ms": 1.161, + "submit_p95-ms": 0.002485, + "feed_lag_p95-ms": 0.6699, + "residual_p50-ms": 0.3539, + "residual_p95-ms": 0.5996, + "signatures/s": 168470.0 + } + }, + { + "family": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "catchup", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 56218950.0, + "cpu-ms/block": 223.0, + "mean_width": 8.0, + "ready_p50-ms": 55.44, + "ready_p95-ms": 58.07, + "submit_p95-ms": 0.01248, + "feed_lag_p95-ms": 0.000551, + "residual_p50-ms": 55.44, + "residual_p95-ms": 58.07, + "signatures/s": 600509.0 + } + }, + { + "family": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "sparse_4tx_200ms_overlap", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 200468704.0, + "cpu-ms/block": 5.317, + "mean_width": 4.0, + "ready_p50-ms": 0.6253, + "ready_p95-ms": 1.041, + "submit_p95-ms": 0.005641, + "feed_lag_p95-ms": 0.9687, + "residual_p50-ms": 0.5171, + "residual_p95-ms": 0.7522, + "signatures/s": 1277.0 + } + }, + { + "family": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "sparse_7tx_200ms_overlap", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 200601736.0, + "cpu-ms/block": 4.607, + "mean_width": 6.919, + "ready_p50-ms": 0.6489, + "ready_p95-ms": 1.107, + "submit_p95-ms": 0.008186, + "feed_lag_p95-ms": 1.009, + "residual_p50-ms": 0.6345, + "residual_p95-ms": 1.079, + "signatures/s": 1276.0 + } + }, + { + "family": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "sparse_8tx_200ms_overlap", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 200762942.0, + "cpu-ms/block": 3.109, + "mean_width": 8.0, + "ready_p50-ms": 0.6574, + "ready_p95-ms": 1.092, + "submit_p95-ms": 0.01741, + "feed_lag_p95-ms": 1.017, + "residual_p50-ms": 0.6307, + "residual_p95-ms": 1.04, + "signatures/s": 1275.0 + } + }, + { + "family": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_after_complete", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 246211332.0, + "cpu-ms/block": 185.7, + "mean_width": 8.0, + "ready_p50-ms": 146.2, + "ready_p95-ms": 236.3, + "submit_p95-ms": 0.01546, + "feed_lag_p95-ms": 190.5, + "residual_p50-ms": 46.77, + "residual_p95-ms": 47.71, + "signatures/s": 137118.0 + } + }, + { + "family": "generated_1232B", + "workers": 4, + "target": 8, + "scenario": "tip_200ms_overlap", + "samples": 3, + "sources": [ + "generated_1232B" + ], + "median": { + "ns/op": 200414118.0, + "cpu-ms/block": 192.7, + "mean_width": 7.001, + "ready_p50-ms": 0.5143, + "ready_p95-ms": 1.017, + "submit_p95-ms": 0.001704, + "feed_lag_p95-ms": 0.7849, + "residual_p50-ms": 0.2302, + "residual_p95-ms": 0.831, + "signatures/s": 168451.0 + } + } + ] +} diff --git a/docs/results/sigverify-streaming/2026-09-12-zen5/run_execution_contention.py b/docs/results/sigverify-streaming/2026-09-12-zen5/run_execution_contention.py new file mode 100644 index 00000000..e3e1a6a0 --- /dev/null +++ b/docs/results/sigverify-streaming/2026-09-12-zen5/run_execution_contention.py @@ -0,0 +1,231 @@ +#!/usr/bin/env python3 +"""Compare actual transfer load/execute under separate-process sigverify load. + +This does not benchmark complete block replay, the shared Go scheduler, account +commit, or the dependency planner. Both processes use the same explicitly chosen +eight physical CPU cores. The signature workload uses the production verifier +pool; 200 ms availability is simulated, not a captured network trace. +""" + +import argparse +import json +import os +from pathlib import Path +import random +import shutil +import statistics +import subprocess +import time + + +def cpu_numbers(spec): + result = [] + for part in spec.split(","): + bounds = [int(value) for value in part.split("-")] + if len(bounds) == 1: + result.append(bounds[0]) + elif len(bounds) == 2 and bounds[0] <= bounds[1]: + result.extend(range(bounds[0], bounds[1] + 1)) + else: + raise ValueError(f"invalid CPU list: {spec}") + if len(result) != len(set(result)): + raise ValueError("CPU list contains duplicates") + return result + + +def cpu_topology(cpus): + rows = [] + for cpu in cpus: + root = Path(f"/sys/devices/system/cpu/cpu{cpu}/topology") + rows.append({ + "cpu": cpu, + "package": int((root / "physical_package_id").read_text()), + "core": int((root / "core_id").read_text()), + }) + return rows + + +def parse_benchmarks(path): + results = [] + for line in path.read_text().splitlines(): + fields = line.strip().split() + if len(fields) < 4 or not fields[0].startswith("Benchmark") or not fields[1].isdigit(): + continue + row = {"name": fields[0], "iterations": int(fields[1])} + for index in range(2, len(fields) - 1, 2): + try: + row[fields[index + 1]] = float(fields[index]) + except ValueError: + break + results.append(row) + return results + + +def atomic_json(path, payload): + temporary = path.with_suffix(".tmp") + temporary.write_text(json.dumps(payload, indent=2) + "\n") + temporary.replace(path) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--turbine-bin", required=True, type=Path) + parser.add_argument("--replay-bin", required=True, type=Path) + parser.add_argument("--fixtures", required=True, type=Path) + parser.add_argument("--slot", required=True, type=int) + parser.add_argument("--cpus", required=True, help="Exactly eight physical cores, one logical CPU each, e.g. 0-7") + parser.add_argument("--out", required=True, type=Path) + parser.add_argument("--samples", type=int, default=3) + parser.add_argument("--probe-time", default="500ms", help="Go benchmark benchtime for one execution sample") + parser.add_argument("--catchup-blocks", type=int, default=256) + parser.add_argument("--tip-blocks", type=int, default=30) + parser.add_argument("--warmup-ms", type=int, default=400) + parser.add_argument("--backend", default="r51") + parser.add_argument("--seed", type=int, default=1) + parser.add_argument("--timeout", type=int, default=120) + args = parser.parse_args() + if min(args.samples, args.timeout) < 1 or min(args.catchup_blocks, args.tip_blocks) < 2 or args.warmup_ms < 0: + parser.error("samples/timeout must be positive, block counts >=2, warmup nonnegative") + if not shutil.which("taskset"): + parser.error("this runner requires Linux taskset") + cpus = cpu_numbers(args.cpus) + topology = cpu_topology(cpus) + if len(cpus) != 8 or len({(row["package"], row["core"]) for row in topology}) != 8: + parser.error("select exactly eight distinct physical CPU cores, one logical CPU per core") + if not set(cpus).issubset(os.sched_getaffinity(0)): + parser.error("selected CPUs are outside this process's allowed affinity") + for name in ("turbine_bin", "replay_bin", "fixtures"): + path = getattr(args, name).resolve(strict=True) + setattr(args, name, path) + if not (args.fixtures / f"block-{args.slot}.json").is_file(): + parser.error("selected slot does not exist in fixture directory") + args.out = args.out.resolve() + args.out.mkdir(parents=True, exist_ok=False) + environment = os.environ.copy() + environment["GOMAXPROCS"] = "8" + # Do not inherit rendezvous paths or fixture limits from another experiment. + for name in list(environment): + if name.startswith("MITHRIL_SIGVERIFY_FLOW_"): + del environment[name] + affinity = ["taskset", "--cpu-list", args.cpus] + probe_command = affinity + [ + str(args.replay_bin), "-test.run=^$", + "-test.bench=^BenchmarkLoadAndExecuteTransferResultMode$/^lean$", + f"-test.benchtime={args.probe_time}", "-test.count=1", + f"-test.timeout={args.timeout}s", + ] + results = { + "description": __doc__, + "arguments": {key: str(value) if isinstance(value, Path) else value for key, value in vars(args).items()}, + "topology": topology, + "gomaxprocs_each_process": 8, + "execution_probe_command": probe_command, + "runs": [], + } + manifest = args.out / "comparison.json" + atomic_json(manifest, results) + + def execution_probe(path): + started = time.monotonic() + with path.open("w") as output: + subprocess.run(probe_command, env=environment, stdout=output, stderr=subprocess.STDOUT, + check=True, timeout=args.timeout) + rows = parse_benchmarks(path) + if len(rows) != 1 or "ns/op" not in rows[0]: + raise RuntimeError(f"expected exactly one execution result in {path}") + return {"wall_seconds": time.monotonic() - started, "benchmark": rows[0], "log": str(path)} + + conditions = [(workers, target, mode) for workers in (2, 4) for target in (4, 8) + for mode in ("catchup", "tip_200ms_overlap")] + rng = random.Random(args.seed) + try: + for sample in range(args.samples): + order = conditions.copy() + rng.shuffle(order) + for workers, target, mode in order: + name = f"sample-{sample + 1}-{mode}-workers{workers}-target{target}" + folder = args.out / name + folder.mkdir() + print(f"{name}: baseline execution", flush=True) + baseline = execution_probe(folder / "execution-baseline.log") + ready, start = folder / "verifier.ready", folder / "verifier.start" + load_env = environment | { + "MITHRIL_SIGVERIFY_FLOW_BACKEND": args.backend, + "MITHRIL_SIGVERIFY_FLOW_FIXTURES": str(args.fixtures), + "MITHRIL_SIGVERIFY_FLOW_READY": str(ready), + "MITHRIL_SIGVERIFY_FLOW_START": str(start), + } + blocks = args.catchup_blocks if mode == "catchup" else args.tip_blocks + benchmark = (f"^BenchmarkTransactionVerificationFlow$/^captured_{args.slot}$/" + f"^workers_{workers}$/^target_{target}$/^{mode}$") + load_command = affinity + [str(args.turbine_bin), "-test.run=^$", + f"-test.bench={benchmark}", f"-test.benchtime={blocks}x", + "-test.count=1", f"-test.timeout={args.timeout}s"] + load_log = folder / "sigverify-load.log" + with load_log.open("w") as output: + load = subprocess.Popen(load_command, env=load_env, stdout=output, stderr=subprocess.STDOUT) + try: + deadline = time.monotonic() + 30 + while not ready.exists(): + if load.poll() is not None: + raise RuntimeError(f"signature workload failed before rendezvous; inspect {load_log}") + if time.monotonic() > deadline: + raise TimeoutError("signature workload readiness timed out") + time.sleep(0.01) + start.touch() + time.sleep(args.warmup_ms / 1000) + if load.poll() is not None: + raise RuntimeError("signature load ended during warmup; increase --catchup-blocks/--tip-blocks") + print(f"{name}: concurrent execution", flush=True) + concurrent = execution_probe(folder / "execution-concurrent.log") + # Reject short load windows: otherwise the probe's late + # iterations could quietly measure unloaded execution. + if load.poll() is not None: + raise RuntimeError("signature load ended before execution probe; increase workload block counts") + exit_code = load.wait(timeout=args.timeout) + if exit_code: + raise RuntimeError(f"signature workload exited {exit_code}; inspect {load_log}") + finally: + if load.poll() is None: + load.terminate() # only the child benchmark process + try: + load.wait(timeout=5) + except subprocess.TimeoutExpired: + load.kill() + load.wait() + load_rows = parse_benchmarks(load_log) + if len(load_rows) != 1: + raise RuntimeError(f"expected one signature result in {load_log}") + ratio = concurrent["benchmark"]["ns/op"] / baseline["benchmark"]["ns/op"] + results["runs"].append({ + "sample": sample + 1, "workers": workers, "target": target, "mode": mode, + "baseline": baseline, "concurrent": concurrent, + "execution_slowdown_ratio": ratio, + "sigverify": load_rows[0], "sigverify_command": load_command, + "sigverify_log": str(load_log), + }) + atomic_json(manifest, results) + print(f"{name}: execution ratio {ratio:.3f}x", flush=True) + except Exception as error: + results["error"] = str(error) + atomic_json(manifest, results) + raise + + summary = [] + for workers, target, mode in conditions: + runs = [row for row in results["runs"] if (row["workers"], row["target"], row["mode"]) == (workers, target, mode)] + summary.append({ + "workers": workers, "target": target, "mode": mode, "samples": len(runs), + "median_execution_slowdown_ratio": statistics.median(row["execution_slowdown_ratio"] for row in runs), + "median_execution_baseline_ns": statistics.median(row["baseline"]["benchmark"]["ns/op"] for row in runs), + "median_execution_concurrent_ns": statistics.median(row["concurrent"]["benchmark"]["ns/op"] for row in runs), + "median_sigverify_residual_p95_ms": statistics.median(row["sigverify"]["residual_p95-ms"] for row in runs), + "median_sigverify_cpu_ms_per_block": statistics.median(row["sigverify"]["cpu-ms/block"] for row in runs), + }) + results["summary"] = summary + atomic_json(manifest, results) + print(json.dumps(summary, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/docs/transaction_sigverify_streaming.md b/docs/transaction_sigverify_streaming.md index fc29745b..84d499b3 100644 --- a/docs/transaction_sigverify_streaming.md +++ b/docs/transaction_sigverify_streaming.md @@ -94,3 +94,6 @@ alongside signature work on the same eight physical cores. Its separate processes measure hardware/OS contention, excluding shared Go scheduler/heap effects, full-block dependency planning, commit and live network timing. Pool throughput alone is insufficient evidence of end-to-end replay improvement. + +Measured Zen 5 results, raw logs, and validation details are in the +[September 12 benchmark report](results/sigverify-streaming/2026-09-12-zen5/README.md). From a8aff5a36f06ccf9352a55f6e97e040e1c34c50f Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Sat, 12 Sep 2026 09:20:10 -0500 Subject: [PATCH 004/183] Avoid rebuilding cached shred component buffers at completion --- .../2026-09-12-zen5/README.md | 134 + .../2026-09-12-zen5/binaries.json | 4 + .../2026-09-12-zen5/commands.jsonl | 15 + .../2026-09-12-zen5/local-race.txt | 1 + .../2026-09-12-zen5/local-unit.txt | 3 + .../2026-09-12-zen5/method.json | 8 + .../2026-09-12-zen5/native-race.txt | 1 + .../2026-09-12-zen5/native-unit.txt | 1 + .../2026-09-12-zen5/run_native.py | 31 + .../2026-09-12-zen5/sample-1-baseline.txt | 13 + .../2026-09-12-zen5/sample-1-candidate.txt | 13 + .../2026-09-12-zen5/sample-2-baseline.txt | 13 + .../2026-09-12-zen5/sample-2-candidate.txt | 13 + .../2026-09-12-zen5/sample-3-baseline.txt | 13 + .../2026-09-12-zen5/sample-3-candidate.txt | 13 + .../2026-09-12-zen5/sample-4-baseline.txt | 13 + .../2026-09-12-zen5/sample-4-candidate.txt | 13 + .../2026-09-12-zen5/sample-5-baseline.txt | 13 + .../2026-09-12-zen5/sample-5-candidate.txt | 13 + .../2026-09-12-zen5/sample-6-baseline.txt | 13 + .../2026-09-12-zen5/sample-6-candidate.txt | 13 + .../2026-09-12-zen5/summarize.py | 54 + .../2026-09-12-zen5/summary.json | 3358 +++++++++++++++++ docs/transaction_sigverify_streaming.md | 12 +- pkg/turbine/entries.go | 47 +- pkg/turbine/entries_direct_compare_test.go | 100 + 26 files changed, 3911 insertions(+), 14 deletions(-) create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/README.md create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/binaries.json create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/commands.jsonl create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/local-race.txt create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/local-unit.txt create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/method.json create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/native-race.txt create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/native-unit.txt create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/run_native.py create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-1-baseline.txt create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-1-candidate.txt create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-2-baseline.txt create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-2-candidate.txt create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-3-baseline.txt create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-3-candidate.txt create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-4-baseline.txt create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-4-candidate.txt create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-5-baseline.txt create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-5-candidate.txt create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-6-baseline.txt create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-6-candidate.txt create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/summarize.py create mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/summary.json create mode 100644 pkg/turbine/entries_direct_compare_test.go diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/README.md b/docs/results/sigverify-direct-cache/2026-09-12-zen5/README.md new file mode 100644 index 00000000..e462121c --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/README.md @@ -0,0 +1,134 @@ +# Direct shred-to-cache comparison on Zen 5 + +For 33,760 maximum-size transactions arriving over 200 ms, removing redundant +component-buffer construction reduced the work remaining after the final shred +from **25.71 to 11.44 ms**. Whole measured assembly allocated **307.49 to +114.25 MB per block**, a **62.8% reduction** in allocation volume. + +## Change and comparison + +Baseline is `11939e2fda29c60381370242e4a26308fd09c9f9`, which already includes +the new signature batching pool and shred-arrival overlap. Candidate changes +only production `pkg/turbine/entries.go`: completion compares each original +shred data slice directly against the corresponding cached bytes instead of +concatenating the slices into another temporary component buffer first. A cache +miss allocates one buffer at the known size, avoiding repeated append growth. + +Cache reuse still requires matching generation/range and every byte, including +padding. Preparation must finish before its data are read. Changed bytes or +lengths trigger fresh decoding and signature verification. Marker handling, +discarded UpdateParent prefixes, transaction ownership, and final block identity +checks retain their existing behavior. Worker counts, batch target, and arrival +scheduling are unchanged. + +This comparison isolates this optimization on our streaming branch. It is not +a comparison against `alpenglow-dev`, an older Narya revision, or overlap off. +The original streaming report's approximately 29 ms maximum-size tail was from +an earlier run; the fresh baseline here is 25.71 ms. Use these paired runs to +evaluate this change. + +## Method + +- AMD Ryzen 7 9700X, eight physical cores / sixteen hardware threads; Go 1.26.4, + native Narya `r51` at `c265ee9667131a556cd332c252b79de0860c7640`. +- `GOMAXPROCS=8`, affinity CPUs 0–7 (distinct physical cores), nice 10. Existing + Mithril and Lightbringer continued running. These are shared-host measurements; + the live validator was not replaced or restarted. +- Two signature workers, target eight, two preparation workers. No batching timer. +- Six baseline/candidate pairs with order alternating between pairs; five timed + blocks per condition in each process, for 30 timed blocks per variant/condition. + Tables show medians of the six reported values. The residual column is the + median of six per-run p50s, not a pooled percentile or confidence interval. +- Both fixtures contain 33,760 distinct valid one-signature generated transactions + at exactly 228 or 1,232 wire bytes. The earlier short-transaction report used a + captured fixture; this A/B uses generated fixtures on both sides. +- Tip scenarios schedule complete component bursts over 200 ms; catch-up offers + all shreds immediately. A 60 KiB transaction-byte budget defines benchmark + components, with actual entry overhead, FEC padding, and Merkle shreds. This + budget is a fixture choice, not a protocol requirement or recorded arrival trace. +- The unchanged `BenchmarkEntryPrefetchAssembly` exercises actual assembler + ingestion, component decoding, final Merkle identity checks, transaction + signature verification, and block publication. Fixture construction, packet + parsing, shred authentication, transaction execution, PoH, and commit are excluded. + +## Tip results with overlap enabled + +All arrows are baseline → candidate. MB denotes decimal megabytes. Allocation +volume is total Go `B/op` for the measured assembly, not peak memory or retained +heap. CPU-ms sums process CPU time across cores; it is not single-thread wall time. + +| Wire bytes/tx | Final-shred-to-ready | First-arrival-to-ready | CPU-ms/block | Allocated MB/block | +|---|---:|---:|---:|---:| +| 228 | 5.70 → **2.29 ms** | 207.24 → **203.11 ms** | 184.95 → 176.10 | 68.21 → **33.09** | +| 1,232 | 25.71 → **11.44 ms** | 228.25 → **212.79 ms** | 273.20 → 236.80 | 307.49 → **114.25** | + +The maximum-size residual fell **55.5% (2.25× faster)**; first-arrival-to-ready +fell 6.8% because the same approximately 201 ms arrival period remains. Each of +the six maximum-size pairs improved residual latency, with reductions of +49.7–60.5%. The median CPU reduction was 13.3%, but paired CPU changes ranged +from a 5.1% increase to a 16.4% decrease on the shared host. + +Median shred collection remained about 201 ms in both maximum-size variants. +The final signature join remained about 0.11 ms; this optimization removes +assembly copies and allocation work, not cryptographic work. The remaining +11.44 ms includes final assembly and identity checks and has not been separately +profiled in this candidate. These results are not a whole-validator replay speedup. + +## Catch-up and cache-miss checks + +The miss path also improves because it can allocate an exactly sized buffer. +Overlap off exercises full decoding/verification without a prefetch cache. +With all shreds available immediately, overlap on has limited time to prepare +transactions before completion, so it also exercises mostly missed cache work. + +| Arrival | Wire bytes/tx | Overlap | First-arrival-to-ready | Allocated MB/block | +|---|---:|---|---:|---:| +| Catch-up | 228 | Off | 86.28 → 84.63 ms | 59.26 → 32.25 | +| Catch-up | 228 | On | 87.25 → 82.78 ms | 61.99 → 34.79 | +| Catch-up | 1,232 | Off | 122.59 → 109.94 ms | 260.02 → 111.95 | +| Catch-up | 1,232 | On | 118.47 → 108.86 ms | 265.47 → 114.43 | +| Tip, 200 ms | 228 | Off | 286.10 → 284.51 ms | 59.26 → 32.25 | +| Tip, 200 ms | 1,232 | Off | 319.12 → 306.41 ms | 260.10 → 112.08 | + +No tested condition regressed at the median. Small short-transaction differences +should be treated cautiously given background load. No worker-policy or execution +contention experiment was added for this change. + +## Validation and artifacts + +- Local full Turbine race suite passed; Turbine, replay, and node package tests + and Turbine vet passed. +- Native full Turbine tests and three repetitions of targeted decoder/prefetch + race tests passed. +- Five-second local fuzz run completed 132,207 executions without a failure, + checking equivalence to bytewise comparison of concatenated data across varied + fragmentation, changed bytes, and different lengths. +- New regressions reject reuse of a successful signature verdict after signature + bytes change, and reject cached buffers of changed length. Existing padding, + cancellation, UpdateParent, and captured Agave decoding tests also passed. +- Every measured assembly asserts complete transaction coverage, exactly one + signature verification per retained transaction, expected block identity and + footer metadata, and absence of internal native-verifier fallback. + +`sample-*.txt` contains the native raw measurements with trailing whitespace +trimmed. `summary.json` contains all +parsed metrics, medians, and paired ratios; regenerate it with `python3 +summarize.py`. `method.json` records the baseline commit and candidate source +hashes, and `binaries.json` records both native binary hashes. The runner and +`commands.jsonl` record exact native commands; runner paths describe the isolated +benchmark directory on this host. Native validation logs are included alongside +the samples. + +To reproduce each variant on an AVX-512 IFMA host after checking out its source: + +```sh +go test -c -o /tmp/turbine-direct-cache.test ./pkg/turbine +GOMAXPROCS=8 MITHRIL_SIGVERIFY_FLOW_BACKEND=r51 \ +MITHRIL_SIGVERIFY_FLOW_COUNT=33760 \ +taskset --cpu-list 0-7 /tmp/turbine-direct-cache.test \ + -test.run='^$' -test.benchtime=5x -test.count=1 \ + -test.bench='^BenchmarkEntryPrefetchAssembly$/^generated_.*$/^workers_2$/^target_8$/.*' +``` + +Choose distinct physical core IDs for the target host, and alternate the two +variants six times rather than running all baseline samples first. diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/binaries.json b/docs/results/sigverify-direct-cache/2026-09-12-zen5/binaries.json new file mode 100644 index 00000000..174a7aea --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/binaries.json @@ -0,0 +1,4 @@ +{ + "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test": "f36508c1d113ea8048ba8b516f4a62b0c15b54369efa41c6211bd4bd491c2da8", + "/srv/mithril-sigverify-streaming-20260912/direct-cache-20260912/candidate.test": "77de0df513f29ff66cb60632a99e45933b06fdba7b39a9726c3e81175cc5a11c" +} \ No newline at end of file diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/commands.jsonl b/docs/results/sigverify-direct-cache/2026-09-12-zen5/commands.jsonl new file mode 100644 index 00000000..09dfe220 --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/commands.jsonl @@ -0,0 +1,15 @@ +{"name": "native-unit", "args": ["nice", "-n", "10", "/usr/local/go/bin/go", "test", "-overlay=/srv/mithril-sigverify-streaming-20260912/direct-cache-20260912/overlay.json", "-p", "2", "./pkg/turbine"], "seconds": 2.5677993297576904, "exit_code": 0} +{"name": "native-race", "args": ["nice", "-n", "10", "/usr/local/go/bin/go", "test", "-overlay=/srv/mithril-sigverify-streaming-20260912/direct-cache-20260912/overlay.json", "-race", "-p", "2", "./pkg/turbine", "-run", "TestDataShredBatchMatches|TestEntryDecode|TestEntryPrefetch", "-count=3"], "seconds": 4.120096921920776, "exit_code": 0} +{"name": "build", "args": ["nice", "-n", "10", "/usr/local/go/bin/go", "test", "-overlay=/srv/mithril-sigverify-streaming-20260912/direct-cache-20260912/overlay.json", "-c", "-p", "2", "-o", "/srv/mithril-sigverify-streaming-20260912/direct-cache-20260912/candidate.test", "./pkg/turbine"], "seconds": 1.5161521434783936, "exit_code": 0} +{"name": "sample-1-baseline", "args": ["nice", "-n", "10", "taskset", "-c", "0-7", "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", "-test.run=^$", "-test.bench=^BenchmarkEntryPrefetchAssembly$/^generated_.*$/^workers_2$/^target_8$/.*", "-test.benchtime=5x", "-test.count=1", "-test.timeout=120s"], "seconds": 12.984313249588013, "exit_code": 0} +{"name": "sample-1-candidate", "args": ["nice", "-n", "10", "taskset", "-c", "0-7", "/srv/mithril-sigverify-streaming-20260912/direct-cache-20260912/candidate.test", "-test.run=^$", "-test.bench=^BenchmarkEntryPrefetchAssembly$/^generated_.*$/^workers_2$/^target_8$/.*", "-test.benchtime=5x", "-test.count=1", "-test.timeout=120s"], "seconds": 12.433180570602417, "exit_code": 0} +{"name": "sample-2-candidate", "args": ["nice", "-n", "10", "taskset", "-c", "0-7", "/srv/mithril-sigverify-streaming-20260912/direct-cache-20260912/candidate.test", "-test.run=^$", "-test.bench=^BenchmarkEntryPrefetchAssembly$/^generated_.*$/^workers_2$/^target_8$/.*", "-test.benchtime=5x", "-test.count=1", "-test.timeout=120s"], "seconds": 12.583751678466797, "exit_code": 0} +{"name": "sample-2-baseline", "args": ["nice", "-n", "10", "taskset", "-c", "0-7", "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", "-test.run=^$", "-test.bench=^BenchmarkEntryPrefetchAssembly$/^generated_.*$/^workers_2$/^target_8$/.*", "-test.benchtime=5x", "-test.count=1", "-test.timeout=120s"], "seconds": 12.884093761444092, "exit_code": 0} +{"name": "sample-3-baseline", "args": ["nice", "-n", "10", "taskset", "-c", "0-7", "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", "-test.run=^$", "-test.bench=^BenchmarkEntryPrefetchAssembly$/^generated_.*$/^workers_2$/^target_8$/.*", "-test.benchtime=5x", "-test.count=1", "-test.timeout=120s"], "seconds": 12.88422703742981, "exit_code": 0} +{"name": "sample-3-candidate", "args": ["nice", "-n", "10", "taskset", "-c", "0-7", "/srv/mithril-sigverify-streaming-20260912/direct-cache-20260912/candidate.test", "-test.run=^$", "-test.bench=^BenchmarkEntryPrefetchAssembly$/^generated_.*$/^workers_2$/^target_8$/.*", "-test.benchtime=5x", "-test.count=1", "-test.timeout=120s"], "seconds": 12.63422966003418, "exit_code": 0} +{"name": "sample-4-candidate", "args": ["nice", "-n", "10", "taskset", "-c", "0-7", "/srv/mithril-sigverify-streaming-20260912/direct-cache-20260912/candidate.test", "-test.run=^$", "-test.bench=^BenchmarkEntryPrefetchAssembly$/^generated_.*$/^workers_2$/^target_8$/.*", "-test.benchtime=5x", "-test.count=1", "-test.timeout=120s"], "seconds": 12.63463544845581, "exit_code": 0} +{"name": "sample-4-baseline", "args": ["nice", "-n", "10", "taskset", "-c", "0-7", "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", "-test.run=^$", "-test.bench=^BenchmarkEntryPrefetchAssembly$/^generated_.*$/^workers_2$/^target_8$/.*", "-test.benchtime=5x", "-test.count=1", "-test.timeout=120s"], "seconds": 12.984484434127808, "exit_code": 0} +{"name": "sample-5-baseline", "args": ["nice", "-n", "10", "taskset", "-c", "0-7", "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", "-test.run=^$", "-test.bench=^BenchmarkEntryPrefetchAssembly$/^generated_.*$/^workers_2$/^target_8$/.*", "-test.benchtime=5x", "-test.count=1", "-test.timeout=120s"], "seconds": 13.034557819366455, "exit_code": 0} +{"name": "sample-5-candidate", "args": ["nice", "-n", "10", "taskset", "-c", "0-7", "/srv/mithril-sigverify-streaming-20260912/direct-cache-20260912/candidate.test", "-test.run=^$", "-test.bench=^BenchmarkEntryPrefetchAssembly$/^generated_.*$/^workers_2$/^target_8$/.*", "-test.benchtime=5x", "-test.count=1", "-test.timeout=120s"], "seconds": 12.936150312423706, "exit_code": 0} +{"name": "sample-6-candidate", "args": ["nice", "-n", "10", "taskset", "-c", "0-7", "/srv/mithril-sigverify-streaming-20260912/direct-cache-20260912/candidate.test", "-test.run=^$", "-test.bench=^BenchmarkEntryPrefetchAssembly$/^generated_.*$/^workers_2$/^target_8$/.*", "-test.benchtime=5x", "-test.count=1", "-test.timeout=120s"], "seconds": 12.533514261245728, "exit_code": 0} +{"name": "sample-6-baseline", "args": ["nice", "-n", "10", "taskset", "-c", "0-7", "/srv/mithril-sigverify-streaming-20260912/bin/turbine-final.test", "-test.run=^$", "-test.bench=^BenchmarkEntryPrefetchAssembly$/^generated_.*$/^workers_2$/^target_8$/.*", "-test.benchtime=5x", "-test.count=1", "-test.timeout=120s"], "seconds": 12.884147882461548, "exit_code": 0} diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/local-race.txt b/docs/results/sigverify-direct-cache/2026-09-12-zen5/local-race.txt new file mode 100644 index 00000000..c19dec5e --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/local-race.txt @@ -0,0 +1 @@ +ok github.com/Overclock-Validator/mithril/pkg/turbine 10.823s diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/local-unit.txt b/docs/results/sigverify-direct-cache/2026-09-12-zen5/local-unit.txt new file mode 100644 index 00000000..19a4c26d --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/local-unit.txt @@ -0,0 +1,3 @@ +ok github.com/Overclock-Validator/mithril/pkg/turbine 1.730s +ok github.com/Overclock-Validator/mithril/pkg/replay 1.489s +ok github.com/Overclock-Validator/mithril/cmd/mithril/node 0.955s diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/method.json b/docs/results/sigverify-direct-cache/2026-09-12-zen5/method.json new file mode 100644 index 00000000..e15e9498 --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/method.json @@ -0,0 +1,8 @@ +{ + "base_commit": "11939e2fda29c60381370242e4a26308fd09c9f9", + "files": { + "entries.go": "d9c8c79bf9b4264ccbcb5028439b67d552947e690603283eaeb8c5525c90668d", + "entries_direct_compare_test.go": "afde5079ef3e99535a69077d01db41b141ebe69d94e9c290b5894d8804a7ef4e" + }, + "description": "Only entries.go production change, direct slice comparison on hits and exact-capacity component allocation on misses. Existing benchmark unchanged." +} \ No newline at end of file diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/native-race.txt b/docs/results/sigverify-direct-cache/2026-09-12-zen5/native-race.txt new file mode 100644 index 00000000..23b12477 --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/native-race.txt @@ -0,0 +1 @@ +ok github.com/Overclock-Validator/mithril/pkg/turbine 1.933s diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/native-unit.txt b/docs/results/sigverify-direct-cache/2026-09-12-zen5/native-unit.txt new file mode 100644 index 00000000..fb5e9d2d --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/native-unit.txt @@ -0,0 +1 @@ +ok github.com/Overclock-Validator/mithril/pkg/turbine 0.971s diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/run_native.py b/docs/results/sigverify-direct-cache/2026-09-12-zen5/run_native.py new file mode 100644 index 00000000..d38acd18 --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/run_native.py @@ -0,0 +1,31 @@ +from pathlib import Path +import hashlib,json,os,subprocess,time +root=Path('/srv/mithril-sigverify-streaming-20260912');out=root/'direct-cache-20260912';go='/usr/local/go/bin/go' +base=root/'bin/turbine-final.test';candidate=out/'candidate.test' +assert hashlib.sha256(base.read_bytes()).hexdigest()=='f36508c1d113ea8048ba8b516f4a62b0c15b54369efa41c6211bd4bd491c2da8' +method=json.loads((out/'method.json').read_text()) +for name,digest in method['files'].items(): assert hashlib.sha256((out/name).read_bytes()).hexdigest()==digest +results=out/'results';results.mkdir(exist_ok=False) +env=os.environ|{'PATH':'/usr/local/go/bin:'+os.environ.get('PATH',''),'GOMAXPROCS':'8','CGO_ENABLED':'1','GOAMD64':'v1','MITHRIL_SIGVERIFY_FLOW_BACKEND':'r51','MITHRIL_SIGVERIFY_FLOW_COUNT':'33760'} +def health(): + return {'service':subprocess.check_output(['systemctl','show','mithril-alpenglow-pr259.service','--property=ActiveState,SubState,MainPID,ExecMainStartTimestamp'],text=True),'load':Path('/proc/loadavg').read_text().strip()} +def run(name,args,timeout=180): + print('START',name,flush=True);start=time.time() + with (results/(name+'.txt')).open('w') as log: + p=subprocess.run(args,cwd=root/'source',env=env,stdout=log,stderr=subprocess.STDOUT,timeout=timeout) + with (results/'commands.jsonl').open('a') as record: record.write(json.dumps({'name':name,'args':args,'seconds':time.time()-start,'exit_code':p.returncode})+'\n') + if p.returncode: print((results/(name+'.txt')).read_text()[-8000:],flush=True);raise RuntimeError(name) + print('PASS',name,flush=True) +(results/'health-before.json').write_text(json.dumps(health(),indent=2)) +overlay='-overlay='+str(out/'overlay.json') +run('native-unit',['nice','-n','10',go,'test',overlay,'-p','2','./pkg/turbine']) +run('native-race',['nice','-n','10',go,'test',overlay,'-race','-p','2','./pkg/turbine','-run','TestDataShredBatchMatches|TestEntryDecode|TestEntryPrefetch','-count=3']) +run('build',['nice','-n','10',go,'test',overlay,'-c','-p','2','-o',str(candidate),'./pkg/turbine']) +(results/'binaries.json').write_text(json.dumps({str(p):hashlib.sha256(p.read_bytes()).hexdigest() for p in [base,candidate]},indent=2)) +bench='^BenchmarkEntryPrefetchAssembly$/^generated_.*$/^workers_2$/^target_8$/.*' +for sample in range(6): + order=[('baseline',base),('candidate',candidate)] if sample%2==0 else [('candidate',candidate),('baseline',base)] + for label,binary in order: + run(f'sample-{sample+1}-{label}',['nice','-n','10','taskset','-c','0-7',str(binary),'-test.run=^$','-test.bench='+bench,'-test.benchtime=5x','-test.count=1','-test.timeout=120s']) +(results/'health-after.json').write_text(json.dumps(health(),indent=2)) +print('COMPLETE',flush=True) diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-1-baseline.txt b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-1-baseline.txt new file mode 100644 index 00000000..3c36d02f --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-1-baseline.txt @@ -0,0 +1,13 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8 5 85293477 ns/op 1.991 avg_cpu_cores 1.118 collection_p50-ms 1.222 collection_p95-ms 4.256 completion_parse_p50-ms 4.496 completion_parse_p95-ms 75.08 completion_sigverify_p50-ms 76.07 completion_sigverify_p95-ms 128.0 components/block 169.8 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 84.59 full_to_ready_p50-ms 86.22 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 59303225 B/op 208748 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8 5 82550451 ns/op 2.066 avg_cpu_cores 1.523 collection_p50-ms 1.637 collection_p95-ms 3.316 completion_parse_p50-ms 3.961 completion_parse_p95-ms 71.99 completion_sigverify_p50-ms 75.24 completion_sigverify_p95-ms 128.0 components/block 170.5 cpu-ms/block 8128 data_shreds/block 161.4 early_verified_tx/block 81.11 full_to_ready_p50-ms 82.92 full_to_ready_p95-ms 7.996 mean_width 0.001032 preparation_wait_p50-ms 0.3401 preparation_wait_p95-ms 33760 tx/block 62210889 B/op 208938 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8 5 284431902 ns/op 0.6029 avg_cpu_cores 200.7 collection_p50-ms 200.8 collection_p95-ms 3.423 completion_parse_p50-ms 4.307 completion_parse_p95-ms 75.24 completion_sigverify_p50-ms 77.36 completion_sigverify_p95-ms 128.0 components/block 171.5 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 83.82 full_to_ready_p50-ms 84.72 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 59440300 B/op 208754 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8 5 207349787 ns/op 0.8917 avg_cpu_cores 200.6 collection_p50-ms 201.2 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.01740 completion_sigverify_p50-ms 0.02466 completion_sigverify_p95-ms 128.0 components/block 184.9 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 5.540 full_to_ready_p50-ms 10.49 full_to_ready_p95-ms 7.912 mean_width 0.02208 preparation_wait_p50-ms 0.02276 preparation_wait_p95-ms 33760 tx/block 68140628 B/op 211686 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8 5 120393310 ns/op 1.967 avg_cpu_cores 6.412 collection_p50-ms 6.950 collection_p95-ms 4.396 completion_parse_p50-ms 5.383 completion_parse_p95-ms 83.47 completion_sigverify_p50-ms 85.24 completion_sigverify_p95-ms 691.0 components/block 236.8 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 111.9 full_to_ready_p50-ms 123.9 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260018664 B/op 235461 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8 5 121769753 ns/op 2.062 avg_cpu_cores 9.028 collection_p50-ms 9.419 collection_p95-ms 4.405 completion_parse_p50-ms 6.850 completion_parse_p95-ms 83.24 completion_sigverify_p50-ms 85.39 completion_sigverify_p95-ms 691.0 components/block 251.1 cpu-ms/block 44160 data_shreds/block 2038 early_verified_tx/block 114.3 full_to_ready_p50-ms 116.6 full_to_ready_p95-ms 7.930 mean_width 0.005170 preparation_wait_p50-ms 0.006164 preparation_wait_p95-ms 33760 tx/block 265754008 B/op 236457 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8 5 322283398 ns/op 0.7984 avg_cpu_cores 201.2 collection_p50-ms 202.9 collection_p95-ms 4.620 completion_parse_p50-ms 5.138 completion_parse_p95-ms 83.39 completion_sigverify_p50-ms 103.0 completion_sigverify_p95-ms 691.0 components/block 257.3 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 118.0 full_to_ready_p50-ms 134.5 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260100848 B/op 235465 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8 5 227419935 ns/op 1.187 avg_cpu_cores 201.0 collection_p50-ms 201.2 collection_p95-ms 0.01162 completion_parse_p50-ms 0.01907 completion_parse_p95-ms 0.3091 completion_sigverify_p50-ms 0.4848 completion_sigverify_p95-ms 691.0 components/block 270.0 cpu-ms/block 44160 data_shreds/block 33721 early_verified_tx/block 25.27 full_to_ready_p50-ms 29.18 full_to_ready_p95-ms 7.001 mean_width 0.1238 preparation_wait_p50-ms 0.1314 preparation_wait_p95-ms 33760 tx/block 307386140 B/op 250045 allocs/op +PASS diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-1-candidate.txt b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-1-candidate.txt new file mode 100644 index 00000000..dc5478d4 --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-1-candidate.txt @@ -0,0 +1,13 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8 5 83134892 ns/op 1.997 avg_cpu_cores 1.178 collection_p50-ms 1.282 collection_p95-ms 3.263 completion_parse_p50-ms 4.674 completion_parse_p95-ms 75.84 completion_sigverify_p50-ms 77.02 completion_sigverify_p95-ms 128.0 components/block 166.0 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 81.77 full_to_ready_p50-ms 84.78 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 32178240 B/op 207227 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8 5 82695024 ns/op 2.045 avg_cpu_cores 1.573 collection_p50-ms 1.693 collection_p95-ms 3.629 completion_parse_p50-ms 4.856 completion_parse_p95-ms 73.77 completion_sigverify_p50-ms 78.48 completion_sigverify_p95-ms 128.0 components/block 169.1 cpu-ms/block 8128 data_shreds/block 53.80 early_verified_tx/block 80.42 full_to_ready_p50-ms 87.90 full_to_ready_p95-ms 7.997 mean_width 0.0007710 preparation_wait_p50-ms 0.03901 preparation_wait_p95-ms 33760 tx/block 34804320 B/op 207381 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8 5 282658756 ns/op 0.5921 avg_cpu_cores 200.8 collection_p50-ms 201.0 collection_p95-ms 3.658 completion_parse_p50-ms 4.300 completion_parse_p95-ms 75.38 completion_sigverify_p50-ms 75.46 completion_sigverify_p95-ms 128.0 components/block 167.4 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 82.09 full_to_ready_p50-ms 83.07 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 32233064 B/op 207230 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8 5 203125335 ns/op 0.8610 avg_cpu_cores 200.8 collection_p50-ms 201.0 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.01565 completion_sigverify_p50-ms 0.01665 completion_sigverify_p95-ms 128.0 components/block 174.9 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 2.212 full_to_ready_p50-ms 2.384 full_to_ready_p95-ms 7.912 mean_width 0.01656 preparation_wait_p50-ms 0.01853 preparation_wait_p95-ms 33760 tx/block 33093758 B/op 210058 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8 5 110251450 ns/op 1.891 avg_cpu_cores 6.539 collection_p50-ms 6.757 collection_p95-ms 3.750 completion_parse_p50-ms 4.958 completion_parse_p95-ms 85.91 completion_sigverify_p50-ms 88.56 completion_sigverify_p95-ms 691.0 components/block 208.5 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 103.8 full_to_ready_p50-ms 104.7 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 111932865 B/op 227176 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8 5 107413848 ns/op 2.009 avg_cpu_cores 9.056 collection_p50-ms 9.607 collection_p95-ms 3.786 completion_parse_p50-ms 4.344 completion_parse_p95-ms 80.71 completion_sigverify_p50-ms 83.94 completion_sigverify_p95-ms 691.0 components/block 215.8 cpu-ms/block 44160 data_shreds/block 2058 early_verified_tx/block 96.75 full_to_ready_p50-ms 104.7 full_to_ready_p95-ms 7.930 mean_width 0.003566 preparation_wait_p50-ms 0.006684 preparation_wait_p95-ms 33760 tx/block 114424409 B/op 228118 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8 5 302887790 ns/op 0.6968 avg_cpu_cores 201.3 collection_p50-ms 201.5 collection_p95-ms 3.559 completion_parse_p50-ms 4.550 completion_parse_p95-ms 84.29 completion_sigverify_p50-ms 85.42 completion_sigverify_p95-ms 691.0 components/block 211.1 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 101.9 full_to_ready_p50-ms 106.5 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 112097940 B/op 227185 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8 5 213778904 ns/op 1.327 avg_cpu_cores 201.0 collection_p50-ms 201.4 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.1053 completion_sigverify_p50-ms 0.1169 completion_sigverify_p95-ms 691.0 components/block 283.7 cpu-ms/block 44160 data_shreds/block 33760 early_verified_tx/block 12.72 full_to_ready_p50-ms 12.87 full_to_ready_p95-ms 7.001 mean_width 0.1121 preparation_wait_p50-ms 0.1170 preparation_wait_p95-ms 33760 tx/block 114137292 B/op 241053 allocs/op +PASS diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-2-baseline.txt b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-2-baseline.txt new file mode 100644 index 00000000..9b8f53eb --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-2-baseline.txt @@ -0,0 +1,13 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8 5 86659017 ns/op 1.995 avg_cpu_cores 1.144 collection_p50-ms 1.292 collection_p95-ms 4.107 completion_parse_p50-ms 4.424 completion_parse_p95-ms 77.20 completion_sigverify_p50-ms 78.30 completion_sigverify_p95-ms 128.0 components/block 172.9 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 85.56 full_to_ready_p50-ms 87.67 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 59220556 B/op 208743 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8 5 86399060 ns/op 2.039 avg_cpu_cores 1.618 collection_p50-ms 1.801 collection_p95-ms 4.302 completion_parse_p50-ms 4.956 completion_parse_p95-ms 75.09 completion_sigverify_p50-ms 77.26 completion_sigverify_p95-ms 128.0 components/block 176.2 cpu-ms/block 8128 data_shreds/block 215.2 early_verified_tx/block 84.87 full_to_ready_p50-ms 87.09 full_to_ready_p95-ms 7.996 mean_width 0.4134 preparation_wait_p50-ms 0.8909 preparation_wait_p95-ms 33760 tx/block 62291787 B/op 208932 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8 5 295572582 ns/op 0.6474 avg_cpu_cores 201.2 collection_p50-ms 201.3 collection_p95-ms 4.790 completion_parse_p50-ms 5.857 completion_parse_p95-ms 84.85 completion_sigverify_p50-ms 94.81 completion_sigverify_p95-ms 128.0 components/block 191.3 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 96.63 full_to_ready_p50-ms 109.6 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 59193052 B/op 208741 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8 5 207101457 ns/op 0.8795 avg_cpu_cores 200.8 collection_p50-ms 201.1 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.01769 completion_sigverify_p50-ms 0.02059 completion_sigverify_p95-ms 128.0 components/block 182.1 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 5.453 full_to_ready_p50-ms 9.838 full_to_ready_p95-ms 7.912 mean_width 0.02266 preparation_wait_p50-ms 0.02356 preparation_wait_p95-ms 33760 tx/block 68303752 B/op 211688 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8 5 120279413 ns/op 1.963 avg_cpu_cores 6.307 collection_p50-ms 6.770 collection_p95-ms 4.339 completion_parse_p50-ms 5.810 completion_parse_p95-ms 83.41 completion_sigverify_p50-ms 83.86 completion_sigverify_p95-ms 691.0 components/block 236.1 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 112.0 full_to_ready_p50-ms 121.7 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260018088 B/op 235459 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8 5 118298008 ns/op 2.033 avg_cpu_cores 8.346 collection_p50-ms 9.341 collection_p95-ms 3.943 completion_parse_p50-ms 4.342 completion_parse_p95-ms 79.88 completion_sigverify_p50-ms 82.24 completion_sigverify_p95-ms 691.0 components/block 240.4 cpu-ms/block 44160 data_shreds/block 1862 early_verified_tx/block 109.8 full_to_ready_p50-ms 113.1 full_to_ready_p95-ms 7.936 mean_width 0.003836 preparation_wait_p50-ms 0.004838 preparation_wait_p95-ms 33760 tx/block 265236585 B/op 236375 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8 5 320159693 ns/op 0.7944 avg_cpu_cores 201.3 collection_p50-ms 201.8 collection_p95-ms 4.424 completion_parse_p50-ms 4.719 completion_parse_p95-ms 88.85 completion_sigverify_p50-ms 95.88 completion_sigverify_p95-ms 691.0 components/block 254.3 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 117.5 full_to_ready_p50-ms 125.4 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260128558 B/op 235467 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8 5 228077236 ns/op 1.181 avg_cpu_cores 201.0 collection_p50-ms 201.4 collection_p95-ms 0 completion_parse_p50-ms 0.01689 completion_parse_p95-ms 0.1095 completion_sigverify_p50-ms 0.3459 completion_sigverify_p95-ms 691.0 components/block 269.4 cpu-ms/block 44160 data_shreds/block 33750 early_verified_tx/block 25.85 full_to_ready_p50-ms 31.67 full_to_ready_p95-ms 7.001 mean_width 0.1293 preparation_wait_p50-ms 0.1316 preparation_wait_p95-ms 33760 tx/block 307341900 B/op 250055 allocs/op +PASS diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-2-candidate.txt b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-2-candidate.txt new file mode 100644 index 00000000..3e93e910 --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-2-candidate.txt @@ -0,0 +1,13 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8 5 86241226 ns/op 1.993 avg_cpu_cores 1.244 collection_p50-ms 1.299 collection_p95-ms 3.632 completion_parse_p50-ms 4.785 completion_parse_p95-ms 77.77 completion_sigverify_p50-ms 81.78 completion_sigverify_p95-ms 128.0 components/block 171.9 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 83.95 full_to_ready_p50-ms 89.64 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 32178248 B/op 207227 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8 5 81680215 ns/op 2.062 avg_cpu_cores 1.645 collection_p50-ms 1.663 collection_p95-ms 3.510 completion_parse_p50-ms 4.122 completion_parse_p95-ms 73.07 completion_sigverify_p50-ms 75.29 completion_sigverify_p95-ms 128.0 components/block 168.5 cpu-ms/block 8128 data_shreds/block 53.80 early_verified_tx/block 79.46 full_to_ready_p50-ms 82.06 full_to_ready_p95-ms 7.996 mean_width 0.0009020 preparation_wait_p50-ms 0.3958 preparation_wait_p95-ms 33760 tx/block 34810161 B/op 207404 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8 5 283720123 ns/op 0.5926 avg_cpu_cores 201.0 collection_p50-ms 201.1 collection_p95-ms 4.150 completion_parse_p50-ms 5.979 completion_parse_p95-ms 75.42 completion_sigverify_p50-ms 76.75 completion_sigverify_p95-ms 128.0 components/block 168.1 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 82.65 full_to_ready_p50-ms 84.17 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 32315624 B/op 207235 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8 5 202974173 ns/op 0.8767 avg_cpu_cores 200.8 collection_p50-ms 200.9 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.01610 completion_sigverify_p50-ms 0.02322 completion_sigverify_p95-ms 128.0 components/block 177.9 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 2.265 full_to_ready_p50-ms 2.340 full_to_ready_p95-ms 7.912 mean_width 0.01836 preparation_wait_p50-ms 0.01868 preparation_wait_p95-ms 33760 tx/block 33013977 B/op 210063 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8 5 108052777 ns/op 1.902 avg_cpu_cores 6.441 collection_p50-ms 6.951 collection_p95-ms 3.540 completion_parse_p50-ms 4.962 completion_parse_p95-ms 84.58 completion_sigverify_p50-ms 85.80 completion_sigverify_p95-ms 691.0 components/block 205.6 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 102.2 full_to_ready_p50-ms 106.2 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 111905424 B/op 227175 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8 5 113945740 ns/op 1.995 avg_cpu_cores 9.282 collection_p50-ms 11.00 collection_p95-ms 3.909 completion_parse_p50-ms 4.912 completion_parse_p95-ms 84.29 completion_sigverify_p50-ms 94.37 completion_sigverify_p95-ms 691.0 components/block 227.4 cpu-ms/block 44160 data_shreds/block 2048 early_verified_tx/block 104.1 full_to_ready_p50-ms 111.8 full_to_ready_p95-ms 7.929 mean_width 0.003519 preparation_wait_p50-ms 0.006271 preparation_wait_p95-ms 33760 tx/block 114311740 B/op 228106 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8 5 304716913 ns/op 0.7074 avg_cpu_cores 201.6 collection_p50-ms 201.7 collection_p95-ms 4.281 completion_parse_p50-ms 4.819 completion_parse_p95-ms 84.11 completion_sigverify_p50-ms 89.27 completion_sigverify_p95-ms 691.0 components/block 215.6 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 102.5 full_to_ready_p50-ms 109.4 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 112180404 B/op 227190 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8 5 212222544 ns/op 1.082 avg_cpu_cores 200.9 collection_p50-ms 201.5 collection_p95-ms 0 completion_parse_p50-ms 0.01717 completion_parse_p95-ms 0.09849 completion_sigverify_p50-ms 0.4180 completion_sigverify_p95-ms 691.0 components/block 229.6 cpu-ms/block 44160 data_shreds/block 33741 early_verified_tx/block 11.01 full_to_ready_p50-ms 11.46 full_to_ready_p95-ms 7.001 mean_width 0.1016 preparation_wait_p50-ms 0.1048 preparation_wait_p95-ms 33760 tx/block 114254763 B/op 241078 allocs/op +PASS diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-3-baseline.txt b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-3-baseline.txt new file mode 100644 index 00000000..d6b81ef7 --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-3-baseline.txt @@ -0,0 +1,13 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8 5 85727666 ns/op 1.994 avg_cpu_cores 1.123 collection_p50-ms 1.319 collection_p95-ms 4.203 completion_parse_p50-ms 4.528 completion_parse_p95-ms 75.36 completion_sigverify_p50-ms 76.36 completion_sigverify_p95-ms 128.0 components/block 171.0 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 85.03 full_to_ready_p50-ms 86.29 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 59248208 B/op 208745 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8 5 93032467 ns/op 2.047 avg_cpu_cores 1.604 collection_p50-ms 1.819 collection_p95-ms 4.104 completion_parse_p50-ms 5.156 completion_parse_p95-ms 80.57 completion_sigverify_p50-ms 87.12 completion_sigverify_p95-ms 128.0 components/block 190.4 cpu-ms/block 8128 data_shreds/block 107.6 early_verified_tx/block 91.48 full_to_ready_p50-ms 95.41 full_to_ready_p95-ms 7.997 mean_width 0.0006920 preparation_wait_p50-ms 0.04334 preparation_wait_p95-ms 33760 tx/block 61931662 B/op 208897 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8 5 285476051 ns/op 0.6068 avg_cpu_cores 200.9 collection_p50-ms 201.0 collection_p95-ms 3.352 completion_parse_p50-ms 4.118 completion_parse_p95-ms 76.14 completion_sigverify_p50-ms 77.78 completion_sigverify_p95-ms 128.0 components/block 173.2 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 84.82 full_to_ready_p50-ms 85.15 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 59303190 B/op 208749 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8 5 207130969 ns/op 0.8933 avg_cpu_cores 200.6 collection_p50-ms 200.7 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.01884 completion_sigverify_p50-ms 0.02053 completion_sigverify_p95-ms 128.0 components/block 185.0 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 5.428 full_to_ready_p50-ms 10.36 full_to_ready_p95-ms 7.912 mean_width 0.02344 preparation_wait_p50-ms 0.02789 preparation_wait_p95-ms 33760 tx/block 68193945 B/op 211684 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8 5 121503561 ns/op 1.942 avg_cpu_cores 6.518 collection_p50-ms 6.678 collection_p95-ms 4.399 completion_parse_p50-ms 4.914 completion_parse_p95-ms 83.32 completion_sigverify_p50-ms 85.03 completion_sigverify_p95-ms 691.0 components/block 236.0 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 111.7 full_to_ready_p50-ms 122.4 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260018412 B/op 235460 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8 5 117837845 ns/op 2.080 avg_cpu_cores 8.353 collection_p50-ms 10.64 collection_p95-ms 4.156 completion_parse_p50-ms 5.325 completion_parse_p95-ms 78.84 completion_sigverify_p50-ms 83.36 completion_sigverify_p95-ms 691.0 components/block 245.1 cpu-ms/block 44160 data_shreds/block 1891 early_verified_tx/block 108.9 full_to_ready_p50-ms 111.3 full_to_ready_p95-ms 7.936 mean_width 0.005110 preparation_wait_p50-ms 0.006629 preparation_wait_p95-ms 33760 tx/block 265386019 B/op 236393 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8 5 318075945 ns/op 0.7698 avg_cpu_cores 201.2 collection_p50-ms 201.7 collection_p95-ms 4.535 completion_parse_p50-ms 6.282 completion_parse_p95-ms 86.26 completion_sigverify_p50-ms 88.65 completion_sigverify_p95-ms 691.0 components/block 244.8 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 116.5 full_to_ready_p50-ms 120.7 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260100819 B/op 235465 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8 5 227891859 ns/op 1.192 avg_cpu_cores 200.9 collection_p50-ms 201.7 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.1033 completion_sigverify_p50-ms 0.1248 completion_sigverify_p95-ms 691.0 components/block 271.8 cpu-ms/block 44160 data_shreds/block 33760 early_verified_tx/block 25.57 full_to_ready_p50-ms 31.02 full_to_ready_p95-ms 7.001 mean_width 0.1267 preparation_wait_p50-ms 0.1306 preparation_wait_p95-ms 33760 tx/block 307494656 B/op 250070 allocs/op +PASS diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-3-candidate.txt b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-3-candidate.txt new file mode 100644 index 00000000..1ca2e352 --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-3-candidate.txt @@ -0,0 +1,13 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8 5 85101485 ns/op 1.996 avg_cpu_cores 1.142 collection_p50-ms 1.251 collection_p95-ms 3.633 completion_parse_p50-ms 4.608 completion_parse_p95-ms 77.59 completion_sigverify_p50-ms 79.04 completion_sigverify_p95-ms 128.0 components/block 169.8 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 84.13 full_to_ready_p50-ms 85.35 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 32233233 B/op 207230 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8 5 83717807 ns/op 2.049 avg_cpu_cores 1.555 collection_p50-ms 1.796 collection_p95-ms 3.655 completion_parse_p50-ms 4.307 completion_parse_p95-ms 75.73 completion_sigverify_p50-ms 77.56 completion_sigverify_p95-ms 128.0 components/block 171.5 cpu-ms/block 8128 data_shreds/block 107.6 early_verified_tx/block 81.90 full_to_ready_p50-ms 84.20 full_to_ready_p95-ms 7.996 mean_width 0.0009510 preparation_wait_p50-ms 0.9772 preparation_wait_p95-ms 33760 tx/block 34781204 B/op 207396 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8 5 283918809 ns/op 0.5965 avg_cpu_cores 200.7 collection_p50-ms 201.0 collection_p95-ms 3.509 completion_parse_p50-ms 4.352 completion_parse_p95-ms 76.49 completion_sigverify_p50-ms 79.83 completion_sigverify_p95-ms 128.0 components/block 169.4 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 83.91 full_to_ready_p50-ms 86.88 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 32260635 B/op 207231 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8 5 203102557 ns/op 0.8531 avg_cpu_cores 200.7 collection_p50-ms 201.0 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.01636 completion_sigverify_p50-ms 0.01724 completion_sigverify_p95-ms 128.0 components/block 173.3 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 2.283 full_to_ready_p50-ms 2.706 full_to_ready_p95-ms 7.912 mean_width 0.01703 preparation_wait_p50-ms 0.01848 preparation_wait_p95-ms 33760 tx/block 33091550 B/op 210049 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8 5 108851790 ns/op 1.903 avg_cpu_cores 5.880 collection_p50-ms 6.600 collection_p95-ms 3.485 completion_parse_p50-ms 4.888 completion_parse_p95-ms 85.29 completion_sigverify_p50-ms 87.68 completion_sigverify_p95-ms 691.0 components/block 207.2 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 102.1 full_to_ready_p50-ms 105.1 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 112042787 B/op 227182 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8 5 105118924 ns/op 1.992 avg_cpu_cores 8.424 collection_p50-ms 9.203 collection_p95-ms 3.571 completion_parse_p50-ms 4.459 completion_parse_p95-ms 79.01 completion_sigverify_p50-ms 82.87 completion_sigverify_p95-ms 691.0 components/block 209.4 cpu-ms/block 44160 data_shreds/block 2009 early_verified_tx/block 95.95 full_to_ready_p50-ms 102.7 full_to_ready_p95-ms 7.932 mean_width 0.002874 preparation_wait_p50-ms 0.004791 preparation_wait_p95-ms 33760 tx/block 114420668 B/op 228093 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8 5 311473242 ns/op 0.7254 avg_cpu_cores 201.3 collection_p50-ms 201.6 collection_p95-ms 4.354 completion_parse_p50-ms 4.596 completion_parse_p95-ms 86.07 completion_sigverify_p50-ms 101.8 completion_sigverify_p95-ms 691.0 components/block 226.0 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 106.9 full_to_ready_p50-ms 121.5 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 112015353 B/op 227181 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8 5 213548260 ns/op 1.136 avg_cpu_cores 201.1 collection_p50-ms 203.1 collection_p95-ms 0 completion_parse_p50-ms 0.01487 completion_parse_p95-ms 0.1838 completion_sigverify_p50-ms 0.5611 completion_sigverify_p95-ms 691.0 components/block 242.6 cpu-ms/block 44160 data_shreds/block 33721 early_verified_tx/block 11.67 full_to_ready_p50-ms 13.52 full_to_ready_p95-ms 7.001 mean_width 0.1105 preparation_wait_p50-ms 0.1124 preparation_wait_p95-ms 33760 tx/block 114250187 B/op 241068 allocs/op +PASS diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-4-baseline.txt b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-4-baseline.txt new file mode 100644 index 00000000..f1c04f78 --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-4-baseline.txt @@ -0,0 +1,13 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8 5 85908997 ns/op 1.990 avg_cpu_cores 1.114 collection_p50-ms 1.748 collection_p95-ms 4.036 completion_parse_p50-ms 4.731 completion_parse_p95-ms 75.53 completion_sigverify_p50-ms 76.38 completion_sigverify_p95-ms 128.0 components/block 171.0 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 85.02 full_to_ready_p50-ms 87.14 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 59303256 B/op 208748 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8 5 83287865 ns/op 2.055 avg_cpu_cores 1.528 collection_p50-ms 1.624 collection_p95-ms 3.147 completion_parse_p50-ms 4.146 completion_parse_p95-ms 73.56 completion_sigverify_p50-ms 75.42 completion_sigverify_p95-ms 128.0 components/block 171.2 cpu-ms/block 8128 data_shreds/block 53.80 early_verified_tx/block 81.77 full_to_ready_p50-ms 82.43 full_to_ready_p95-ms 7.997 mean_width 0.0007500 preparation_wait_p50-ms 0.0007910 preparation_wait_p95-ms 33760 tx/block 62015553 B/op 208909 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8 5 286588469 ns/op 0.6114 avg_cpu_cores 200.8 collection_p50-ms 201.1 collection_p95-ms 3.437 completion_parse_p50-ms 3.868 completion_parse_p95-ms 76.77 completion_sigverify_p50-ms 79.74 completion_sigverify_p95-ms 128.0 components/block 175.2 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 85.44 full_to_ready_p50-ms 88.49 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 59275379 B/op 208745 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8 5 208123357 ns/op 0.9981 avg_cpu_cores 200.8 collection_p50-ms 201.3 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.02067 completion_sigverify_p50-ms 0.02899 completion_sigverify_p95-ms 128.0 components/block 207.7 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 7.752 full_to_ready_p50-ms 10.18 full_to_ready_p95-ms 7.912 mean_width 0.02546 preparation_wait_p50-ms 0.02901 preparation_wait_p95-ms 33760 tx/block 68363801 B/op 211716 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8 5 134090384 ns/op 1.916 avg_cpu_cores 7.863 collection_p50-ms 9.017 collection_p95-ms 5.347 completion_parse_p50-ms 5.887 completion_parse_p95-ms 90.59 completion_sigverify_p50-ms 103.3 completion_sigverify_p95-ms 691.0 components/block 256.9 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 124.8 full_to_ready_p50-ms 146.3 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260045872 B/op 235462 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8 5 118644204 ns/op 2.083 avg_cpu_cores 8.456 collection_p50-ms 8.783 collection_p95-ms 3.887 completion_parse_p50-ms 4.874 completion_parse_p95-ms 80.59 completion_sigverify_p50-ms 82.30 completion_sigverify_p95-ms 691.0 components/block 247.2 cpu-ms/block 44160 data_shreds/block 1931 early_verified_tx/block 109.2 full_to_ready_p50-ms 112.4 full_to_ready_p95-ms 7.935 mean_width 0.004411 preparation_wait_p50-ms 0.004846 preparation_wait_p95-ms 33760 tx/block 265440401 B/op 236406 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8 5 316166377 ns/op 0.7691 avg_cpu_cores 201.3 collection_p50-ms 201.6 collection_p95-ms 4.191 completion_parse_p50-ms 4.500 completion_parse_p95-ms 84.55 completion_sigverify_p50-ms 87.88 completion_sigverify_p95-ms 691.0 components/block 243.2 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 115.2 full_to_ready_p50-ms 119.9 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 259963968 B/op 235459 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8 5 230004734 ns/op 1.196 avg_cpu_cores 201.3 collection_p50-ms 201.8 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.1175 completion_sigverify_p50-ms 0.1314 completion_sigverify_p95-ms 691.0 components/block 275.1 cpu-ms/block 44160 data_shreds/block 33760 early_verified_tx/block 28.30 full_to_ready_p50-ms 32.14 full_to_ready_p95-ms 7.001 mean_width 0.1213 preparation_wait_p50-ms 0.1297 preparation_wait_p95-ms 33760 tx/block 307660395 B/op 250071 allocs/op +PASS diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-4-candidate.txt b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-4-candidate.txt new file mode 100644 index 00000000..929720e8 --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-4-candidate.txt @@ -0,0 +1,13 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8 5 83997761 ns/op 1.990 avg_cpu_cores 1.213 collection_p50-ms 1.275 collection_p95-ms 3.383 completion_parse_p50-ms 4.718 completion_parse_p95-ms 76.12 completion_sigverify_p50-ms 77.08 completion_sigverify_p95-ms 128.0 components/block 167.2 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 82.75 full_to_ready_p50-ms 84.96 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 32260841 B/op 207232 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8 5 82378390 ns/op 2.052 avg_cpu_cores 1.582 collection_p50-ms 1.764 collection_p95-ms 3.427 completion_parse_p50-ms 4.179 completion_parse_p95-ms 73.70 completion_sigverify_p50-ms 77.03 completion_sigverify_p95-ms 128.0 components/block 169.1 cpu-ms/block 8128 data_shreds/block 107.6 early_verified_tx/block 80.55 full_to_ready_p50-ms 83.25 full_to_ready_p95-ms 7.996 mean_width 0.0007110 preparation_wait_p50-ms 0.5494 preparation_wait_p95-ms 33760 tx/block 34778107 B/op 207384 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8 5 285362255 ns/op 0.6030 avg_cpu_cores 201.1 collection_p50-ms 201.1 collection_p95-ms 4.124 completion_parse_p50-ms 4.297 completion_parse_p95-ms 75.54 completion_sigverify_p50-ms 83.57 completion_sigverify_p95-ms 128.0 components/block 172.1 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 83.22 full_to_ready_p50-ms 91.69 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 32287976 B/op 207232 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8 5 203641348 ns/op 1.007 avg_cpu_cores 200.9 collection_p50-ms 201.2 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.01979 completion_sigverify_p50-ms 0.02696 completion_sigverify_p95-ms 128.0 components/block 205.1 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 2.728 full_to_ready_p50-ms 2.801 full_to_ready_p95-ms 7.912 mean_width 0.02069 preparation_wait_p50-ms 0.02411 preparation_wait_p95-ms 33760 tx/block 33091185 B/op 210047 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8 5 109632016 ns/op 1.892 avg_cpu_cores 6.787 collection_p50-ms 7.832 collection_p95-ms 3.642 completion_parse_p50-ms 4.960 completion_parse_p95-ms 85.31 completion_sigverify_p50-ms 88.30 completion_sigverify_p95-ms 691.0 components/block 207.4 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 102.1 full_to_ready_p50-ms 108.2 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 111905504 B/op 227176 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8 5 106324511 ns/op 2.007 avg_cpu_cores 8.568 collection_p50-ms 9.414 collection_p95-ms 3.655 completion_parse_p50-ms 4.119 completion_parse_p95-ms 79.89 completion_sigverify_p50-ms 84.03 completion_sigverify_p95-ms 691.0 components/block 213.4 cpu-ms/block 44160 data_shreds/block 1862 early_verified_tx/block 96.25 full_to_ready_p50-ms 103.4 full_to_ready_p95-ms 7.936 mean_width 0.003455 preparation_wait_p50-ms 0.006185 preparation_wait_p95-ms 33760 tx/block 114547820 B/op 228037 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8 5 311267426 ns/op 0.7263 avg_cpu_cores 201.1 collection_p50-ms 202.1 collection_p95-ms 3.621 completion_parse_p50-ms 5.061 completion_parse_p95-ms 87.90 completion_sigverify_p50-ms 103.1 completion_sigverify_p95-ms 691.0 components/block 226.1 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 105.2 full_to_ready_p50-ms 119.8 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 111932950 B/op 227177 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8 5 212794779 ns/op 1.109 avg_cpu_cores 201.0 collection_p50-ms 202.1 collection_p95-ms 0 completion_parse_p50-ms 0.01383 completion_parse_p95-ms 0.1078 completion_sigverify_p50-ms 0.3044 completion_sigverify_p95-ms 691.0 components/block 236.0 cpu-ms/block 44160 data_shreds/block 33750 early_verified_tx/block 11.18 full_to_ready_p50-ms 12.44 full_to_ready_p95-ms 7.001 mean_width 0.1053 preparation_wait_p50-ms 0.1134 preparation_wait_p95-ms 33760 tx/block 114247308 B/op 241055 allocs/op +PASS diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-5-baseline.txt b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-5-baseline.txt new file mode 100644 index 00000000..51f7d9c5 --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-5-baseline.txt @@ -0,0 +1,13 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8 5 86664771 ns/op 1.983 avg_cpu_cores 1.195 collection_p50-ms 1.430 collection_p95-ms 4.332 completion_parse_p50-ms 5.166 completion_parse_p95-ms 76.40 completion_sigverify_p50-ms 77.61 completion_sigverify_p95-ms 128.0 components/block 171.9 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 86.21 full_to_ready_p50-ms 87.53 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 59275827 B/op 208747 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8 5 100446776 ns/op 2.026 avg_cpu_cores 2.064 collection_p50-ms 2.165 collection_p95-ms 4.494 completion_parse_p50-ms 5.885 completion_parse_p95-ms 89.05 completion_sigverify_p50-ms 89.98 completion_sigverify_p95-ms 128.0 components/block 203.5 cpu-ms/block 8128 data_shreds/block 215.2 early_verified_tx/block 100.3 full_to_ready_p50-ms 104.8 full_to_ready_p95-ms 7.996 mean_width 0.0008210 preparation_wait_p50-ms 0.001052 preparation_wait_p95-ms 33760 tx/block 61973884 B/op 208905 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8 5 286167802 ns/op 0.6098 avg_cpu_cores 200.7 collection_p50-ms 200.8 collection_p95-ms 3.934 completion_parse_p50-ms 4.419 completion_parse_p95-ms 76.59 completion_sigverify_p50-ms 77.91 completion_sigverify_p95-ms 128.0 components/block 174.5 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 85.40 full_to_ready_p50-ms 86.57 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 59193008 B/op 208742 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8 5 207732756 ns/op 0.9023 avg_cpu_cores 200.9 collection_p50-ms 201.1 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.01991 completion_sigverify_p50-ms 0.03155 completion_sigverify_p95-ms 128.0 components/block 187.4 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 7.562 full_to_ready_p50-ms 9.053 full_to_ready_p95-ms 7.912 mean_width 0.02246 preparation_wait_p50-ms 0.02459 preparation_wait_p95-ms 33760 tx/block 68138699 B/op 211680 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8 5 123685493 ns/op 1.960 avg_cpu_cores 6.351 collection_p50-ms 7.320 collection_p95-ms 4.749 completion_parse_p50-ms 4.856 completion_parse_p95-ms 84.69 completion_sigverify_p50-ms 86.93 completion_sigverify_p95-ms 691.0 components/block 242.4 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 118.8 full_to_ready_p50-ms 123.1 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260100822 B/op 235464 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8 5 119201510 ns/op 2.078 avg_cpu_cores 8.512 collection_p50-ms 9.358 collection_p95-ms 4.359 completion_parse_p50-ms 4.711 completion_parse_p95-ms 80.38 completion_sigverify_p50-ms 82.91 completion_sigverify_p95-ms 691.0 components/block 247.7 cpu-ms/block 44160 data_shreds/block 1950 early_verified_tx/block 110.3 full_to_ready_p50-ms 113.1 full_to_ready_p95-ms 7.933 mean_width 0.004432 preparation_wait_p50-ms 0.006141 preparation_wait_p95-ms 33760 tx/block 265605086 B/op 236424 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8 5 326825723 ns/op 0.8088 avg_cpu_cores 201.9 collection_p50-ms 202.2 collection_p95-ms 4.877 completion_parse_p50-ms 5.064 completion_parse_p95-ms 94.15 completion_sigverify_p50-ms 106.9 completion_sigverify_p95-ms 691.0 components/block 264.3 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 127.9 full_to_ready_p50-ms 139.6 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260100937 B/op 235466 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8 5 229345156 ns/op 1.197 avg_cpu_cores 201.0 collection_p50-ms 201.0 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.1071 completion_sigverify_p50-ms 0.1224 completion_sigverify_p95-ms 691.0 components/block 274.6 cpu-ms/block 44160 data_shreds/block 33760 early_verified_tx/block 28.39 full_to_ready_p50-ms 31.10 full_to_ready_p95-ms 7.001 mean_width 0.1263 preparation_wait_p50-ms 0.1313 preparation_wait_p95-ms 33760 tx/block 307580156 B/op 250079 allocs/op +PASS diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-5-candidate.txt b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-5-candidate.txt new file mode 100644 index 00000000..555f7b28 --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-5-candidate.txt @@ -0,0 +1,13 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8 5 86939212 ns/op 2.001 avg_cpu_cores 1.138 collection_p50-ms 1.528 collection_p95-ms 3.315 completion_parse_p50-ms 4.947 completion_parse_p95-ms 80.42 completion_sigverify_p50-ms 81.95 completion_sigverify_p95-ms 128.0 components/block 173.9 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 86.28 full_to_ready_p50-ms 89.75 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 32343236 B/op 207237 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8 5 93051198 ns/op 2.052 avg_cpu_cores 1.908 collection_p50-ms 2.115 collection_p95-ms 3.802 completion_parse_p50-ms 5.595 completion_parse_p95-ms 83.19 completion_sigverify_p50-ms 89.15 completion_sigverify_p95-ms 128.0 components/block 191.0 cpu-ms/block 8128 data_shreds/block 161.4 early_verified_tx/block 89.81 full_to_ready_p50-ms 98.24 full_to_ready_p95-ms 7.995 mean_width 0.1421 preparation_wait_p50-ms 1.063 preparation_wait_p95-ms 33760 tx/block 34757734 B/op 207410 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8 5 285099098 ns/op 0.6058 avg_cpu_cores 200.8 collection_p50-ms 201.0 collection_p95-ms 3.323 completion_parse_p50-ms 4.328 completion_parse_p95-ms 77.77 completion_sigverify_p50-ms 77.90 completion_sigverify_p95-ms 128.0 components/block 172.7 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 84.74 full_to_ready_p50-ms 85.63 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 32205774 B/op 207229 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8 5 203024092 ns/op 0.8731 avg_cpu_cores 200.6 collection_p50-ms 200.9 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.01703 completion_sigverify_p50-ms 0.02449 completion_sigverify_p95-ms 128.0 components/block 177.3 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 2.292 full_to_ready_p50-ms 2.390 full_to_ready_p95-ms 7.912 mean_width 0.01816 preparation_wait_p50-ms 0.01985 preparation_wait_p95-ms 33760 tx/block 33175731 B/op 210061 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8 5 116086892 ns/op 1.896 avg_cpu_cores 7.729 collection_p50-ms 9.382 collection_p95-ms 3.985 completion_parse_p50-ms 6.018 completion_parse_p95-ms 84.53 completion_sigverify_p50-ms 100.6 completion_sigverify_p95-ms 691.0 components/block 220.2 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 109.4 full_to_ready_p50-ms 119.2 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 111960304 B/op 227177 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8 5 115194449 ns/op 1.969 avg_cpu_cores 9.432 collection_p50-ms 10.35 collection_p95-ms 3.882 completion_parse_p50-ms 4.979 completion_parse_p95-ms 85.65 completion_sigverify_p50-ms 94.03 completion_sigverify_p95-ms 691.0 components/block 226.9 cpu-ms/block 44160 data_shreds/block 1735 early_verified_tx/block 104.0 full_to_ready_p50-ms 111.4 full_to_ready_p95-ms 7.941 mean_width 0.004026 preparation_wait_p50-ms 0.005541 preparation_wait_p95-ms 33760 tx/block 114430456 B/op 227975 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8 5 308111487 ns/op 0.7254 avg_cpu_cores 201.5 collection_p50-ms 201.6 collection_p95-ms 4.284 completion_parse_p50-ms 5.167 completion_parse_p95-ms 88.66 completion_sigverify_p50-ms 94.67 completion_sigverify_p95-ms 691.0 components/block 223.5 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 109.1 full_to_ready_p50-ms 113.6 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 112125502 B/op 227188 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8 5 212791787 ns/op 1.116 avg_cpu_cores 200.9 collection_p50-ms 201.0 collection_p95-ms 0.007484 completion_parse_p50-ms 0.01159 completion_parse_p95-ms 0.3225 completion_sigverify_p50-ms 0.3603 completion_sigverify_p95-ms 691.0 components/block 237.6 cpu-ms/block 44160 data_shreds/block 33731 early_verified_tx/block 11.63 full_to_ready_p50-ms 13.06 full_to_ready_p95-ms 7.001 mean_width 0.1056 preparation_wait_p50-ms 0.1122 preparation_wait_p95-ms 33760 tx/block 114082224 B/op 241044 allocs/op +PASS diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-6-baseline.txt b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-6-baseline.txt new file mode 100644 index 00000000..a38e0522 --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-6-baseline.txt @@ -0,0 +1,13 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8 5 87321492 ns/op 1.992 avg_cpu_cores 1.139 collection_p50-ms 1.213 collection_p95-ms 4.206 completion_parse_p50-ms 4.314 completion_parse_p95-ms 76.92 completion_sigverify_p50-ms 79.11 completion_sigverify_p95-ms 128.0 components/block 173.9 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 86.31 full_to_ready_p50-ms 87.54 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 59110704 B/op 208737 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8 5 88098284 ns/op 2.039 avg_cpu_cores 1.612 collection_p50-ms 1.726 collection_p95-ms 3.683 completion_parse_p50-ms 4.031 completion_parse_p95-ms 78.16 completion_sigverify_p50-ms 83.11 completion_sigverify_p95-ms 128.0 components/block 179.7 cpu-ms/block 8128 data_shreds/block 107.6 early_verified_tx/block 87.14 full_to_ready_p50-ms 92.06 full_to_ready_p95-ms 7.997 mean_width 0.0007710 preparation_wait_p50-ms 0.0008420 preparation_wait_p95-ms 33760 tx/block 61902907 B/op 208887 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8 5 286038446 ns/op 0.6079 avg_cpu_cores 200.9 collection_p50-ms 201.1 collection_p95-ms 3.731 completion_parse_p50-ms 4.179 completion_parse_p95-ms 76.35 completion_sigverify_p50-ms 78.24 completion_sigverify_p95-ms 128.0 components/block 173.9 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 85.53 full_to_ready_p50-ms 85.90 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 59248048 B/op 208744 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8 5 206915717 ns/op 0.8863 avg_cpu_cores 200.6 collection_p50-ms 200.9 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.01665 completion_sigverify_p50-ms 0.02066 completion_sigverify_p95-ms 128.0 components/block 183.4 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 5.859 full_to_ready_p50-ms 9.065 full_to_ready_p95-ms 7.912 mean_width 0.02179 preparation_wait_p50-ms 0.02377 preparation_wait_p95-ms 33760 tx/block 68223072 B/op 211693 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8 5 125985246 ns/op 1.958 avg_cpu_cores 6.541 collection_p50-ms 7.319 collection_p95-ms 5.022 completion_parse_p50-ms 5.127 completion_parse_p95-ms 86.20 completion_sigverify_p50-ms 88.08 completion_sigverify_p95-ms 691.0 components/block 246.7 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 118.0 full_to_ready_p50-ms 130.3 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 259990851 B/op 235458 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8 5 118097846 ns/op 2.073 avg_cpu_cores 8.234 collection_p50-ms 9.436 collection_p95-ms 3.897 completion_parse_p50-ms 4.584 completion_parse_p95-ms 80.46 completion_sigverify_p50-ms 84.12 completion_sigverify_p95-ms 691.0 components/block 244.8 cpu-ms/block 44160 data_shreds/block 2009 early_verified_tx/block 110.1 full_to_ready_p50-ms 111.6 full_to_ready_p95-ms 7.932 mean_width 0.003857 preparation_wait_p50-ms 0.005016 preparation_wait_p95-ms 33760 tx/block 265493705 B/op 236438 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8 5 318006733 ns/op 0.7756 avg_cpu_cores 201.6 collection_p50-ms 201.9 collection_p95-ms 5.760 completion_parse_p50-ms 6.369 completion_parse_p95-ms 84.75 completion_sigverify_p50-ms 86.11 completion_sigverify_p95-ms 691.0 components/block 246.7 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 117.0 full_to_ready_p50-ms 120.6 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 260100320 B/op 235463 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8 5 228423719 ns/op 1.210 avg_cpu_cores 201.1 collection_p50-ms 201.6 collection_p95-ms 0 completion_parse_p50-ms 0.02031 completion_parse_p95-ms 0.1011 completion_sigverify_p50-ms 0.5984 completion_sigverify_p95-ms 691.0 components/block 276.4 cpu-ms/block 44160 data_shreds/block 33731 early_verified_tx/block 25.52 full_to_ready_p50-ms 30.97 full_to_ready_p95-ms 7.001 mean_width 0.1290 preparation_wait_p50-ms 0.1313 preparation_wait_p95-ms 33760 tx/block 307480184 B/op 250043 allocs/op +PASS diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-6-candidate.txt b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-6-candidate.txt new file mode 100644 index 00000000..22942a52 --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-6-candidate.txt @@ -0,0 +1,13 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8 5 84167116 ns/op 1.988 avg_cpu_cores 1.144 collection_p50-ms 1.232 collection_p95-ms 3.413 completion_parse_p50-ms 4.888 completion_parse_p95-ms 76.76 completion_sigverify_p50-ms 78.17 completion_sigverify_p95-ms 128.0 components/block 167.3 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 82.76 full_to_ready_p50-ms 84.18 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 32288243 B/op 207233 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8 5 82857969 ns/op 2.043 avg_cpu_cores 1.523 collection_p50-ms 1.630 collection_p95-ms 3.449 completion_parse_p50-ms 5.611 completion_parse_p95-ms 74.33 completion_sigverify_p50-ms 75.86 completion_sigverify_p95-ms 128.0 components/block 169.3 cpu-ms/block 8128 data_shreds/block 215.2 early_verified_tx/block 81.41 full_to_ready_p50-ms 83.26 full_to_ready_p95-ms 7.997 mean_width 0.0009220 preparation_wait_p50-ms 0.07145 preparation_wait_p95-ms 33760 tx/block 34911190 B/op 207376 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8 5 290467977 ns/op 0.6306 avg_cpu_cores 200.7 collection_p50-ms 201.2 collection_p95-ms 3.626 completion_parse_p50-ms 5.792 completion_parse_p95-ms 82.06 completion_sigverify_p50-ms 91.61 completion_sigverify_p95-ms 128.0 components/block 183.2 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 91.79 full_to_ready_p50-ms 98.00 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 32205832 B/op 207229 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8 5 203268498 ns/op 0.8573 avg_cpu_cores 200.9 collection_p50-ms 201.0 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.01763 completion_sigverify_p50-ms 0.02967 completion_sigverify_p95-ms 128.0 components/block 174.3 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 2.370 full_to_ready_p50-ms 2.511 full_to_ready_p95-ms 7.912 mean_width 0.01763 preparation_wait_p50-ms 0.02097 preparation_wait_p95-ms 33760 tx/block 33202425 B/op 210058 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8 5 113739331 ns/op 1.899 avg_cpu_cores 6.908 collection_p50-ms 8.387 collection_p95-ms 3.847 completion_parse_p50-ms 5.097 completion_parse_p95-ms 89.13 completion_sigverify_p50-ms 91.48 completion_sigverify_p95-ms 691.0 components/block 216.0 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 106.6 full_to_ready_p50-ms 111.0 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 112042899 B/op 227183 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8 5 110309323 ns/op 2.000 avg_cpu_cores 9.223 collection_p50-ms 9.799 collection_p95-ms 3.510 completion_parse_p50-ms 4.880 completion_parse_p95-ms 80.54 completion_sigverify_p50-ms 90.01 completion_sigverify_p95-ms 691.0 components/block 220.6 cpu-ms/block 44160 data_shreds/block 2078 early_verified_tx/block 99.70 full_to_ready_p50-ms 109.9 full_to_ready_p95-ms 7.929 mean_width 0.003385 preparation_wait_p50-ms 0.006176 preparation_wait_p95-ms 33760 tx/block 114532560 B/op 228120 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8 5 302321983 ns/op 0.6997 avg_cpu_cores 201.0 collection_p50-ms 201.5 collection_p95-ms 3.910 completion_parse_p50-ms 4.540 completion_parse_p95-ms 83.33 completion_sigverify_p50-ms 85.29 completion_sigverify_p95-ms 691.0 components/block 211.5 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 101.1 full_to_ready_p50-ms 105.9 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 112070532 B/op 227185 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8 5 212242945 ns/op 1.089 avg_cpu_cores 200.8 collection_p50-ms 201.3 collection_p95-ms 0 completion_parse_p50-ms 0.01212 completion_parse_p95-ms 0.09627 completion_sigverify_p50-ms 0.3047 completion_sigverify_p95-ms 691.0 components/block 231.2 cpu-ms/block 44160 data_shreds/block 33750 early_verified_tx/block 11.24 full_to_ready_p50-ms 11.41 full_to_ready_p95-ms 7.001 mean_width 0.1010 preparation_wait_p50-ms 0.1062 preparation_wait_p95-ms 33760 tx/block 114276446 B/op 241076 allocs/op +PASS diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/summarize.py b/docs/results/sigverify-direct-cache/2026-09-12-zen5/summarize.py new file mode 100644 index 00000000..fe0980e0 --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/summarize.py @@ -0,0 +1,54 @@ +"""Summarize alternating native baseline/candidate assembly benchmark runs.""" + +import json +import statistics +from pathlib import Path + + +root = Path(__file__).resolve().parent +rows = [] +for path in sorted(root.glob("sample-*.txt")): + for line in path.read_text().splitlines(): + if not line.startswith("BenchmarkEntryPrefetchAssembly/"): + continue + fields = line.split() + rows.append({ + "sample": int(path.stem.split("-")[1]), + "variant": path.stem.split("-")[2], + "name": fields[0], + "iterations": int(fields[1]), + "metrics": { + fields[i + 1]: float(fields[i]) + for i in range(2, len(fields), 2) + }, + }) + +assert len(rows) == 6 * 2 * 8 +summary = [] +for name in sorted({row["name"] for row in rows}): + variants = { + variant: [row for row in rows if row["name"] == name and row["variant"] == variant] + for variant in ("baseline", "candidate") + } + for samples in variants.values(): + assert len(samples) == 6 + assert sorted(row["sample"] for row in samples) == list(range(1, 7)) + assert all(row["iterations"] == 5 for row in samples) + medians = { + variant: { + metric: statistics.median(row["metrics"][metric] for row in samples) + for metric in samples[0]["metrics"] + } + for variant, samples in variants.items() + } + paired = { + metric: [ + next(row for row in variants["candidate"] if row["sample"] == sample)["metrics"][metric] + / next(row for row in variants["baseline"] if row["sample"] == sample)["metrics"][metric] + for sample in range(1, 7) + ] + for metric in ("ns/op", "cpu-ms/block", "B/op", "full_to_ready_p50-ms") + } + summary.append({"name": name, "medians": medians, "paired_ratios": paired}) + +(root / "summary.json").write_text(json.dumps({"samples": rows, "summary": summary}, indent=2) + "\n") diff --git a/docs/results/sigverify-direct-cache/2026-09-12-zen5/summary.json b/docs/results/sigverify-direct-cache/2026-09-12-zen5/summary.json new file mode 100644 index 00000000..5d9f76d8 --- /dev/null +++ b/docs/results/sigverify-direct-cache/2026-09-12-zen5/summary.json @@ -0,0 +1,3358 @@ +{ + "samples": [ + { + "sample": 1, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 85293477.0, + "avg_cpu_cores": 1.991, + "collection_p50-ms": 1.118, + "collection_p95-ms": 1.222, + "completion_parse_p50-ms": 4.256, + "completion_parse_p95-ms": 4.496, + "completion_sigverify_p50-ms": 75.08, + "completion_sigverify_p95-ms": 76.07, + "components/block": 128.0, + "cpu-ms/block": 169.8, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 84.59, + "full_to_ready_p95-ms": 86.22, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 59303225.0, + "allocs/op": 208748.0 + } + }, + { + "sample": 1, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 82550451.0, + "avg_cpu_cores": 2.066, + "collection_p50-ms": 1.523, + "collection_p95-ms": 1.637, + "completion_parse_p50-ms": 3.316, + "completion_parse_p95-ms": 3.961, + "completion_sigverify_p50-ms": 71.99, + "completion_sigverify_p95-ms": 75.24, + "components/block": 128.0, + "cpu-ms/block": 170.5, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 161.4, + "full_to_ready_p50-ms": 81.11, + "full_to_ready_p95-ms": 82.92, + "mean_width": 7.996, + "preparation_wait_p50-ms": 0.001032, + "preparation_wait_p95-ms": 0.3401, + "tx/block": 33760.0, + "B/op": 62210889.0, + "allocs/op": 208938.0 + } + }, + { + "sample": 1, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 284431902.0, + "avg_cpu_cores": 0.6029, + "collection_p50-ms": 200.7, + "collection_p95-ms": 200.8, + "completion_parse_p50-ms": 3.423, + "completion_parse_p95-ms": 4.307, + "completion_sigverify_p50-ms": 75.24, + "completion_sigverify_p95-ms": 77.36, + "components/block": 128.0, + "cpu-ms/block": 171.5, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 83.82, + "full_to_ready_p95-ms": 84.72, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 59440300.0, + "allocs/op": 208754.0 + } + }, + { + "sample": 1, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 207349787.0, + "avg_cpu_cores": 0.8917, + "collection_p50-ms": 200.6, + "collection_p95-ms": 201.2, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.0174, + "completion_sigverify_p95-ms": 0.02466, + "components/block": 128.0, + "cpu-ms/block": 184.9, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 5.54, + "full_to_ready_p95-ms": 10.49, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.02208, + "preparation_wait_p95-ms": 0.02276, + "tx/block": 33760.0, + "B/op": 68140628.0, + "allocs/op": 211686.0 + } + }, + { + "sample": 1, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 120393310.0, + "avg_cpu_cores": 1.967, + "collection_p50-ms": 6.412, + "collection_p95-ms": 6.95, + "completion_parse_p50-ms": 4.396, + "completion_parse_p95-ms": 5.383, + "completion_sigverify_p50-ms": 83.47, + "completion_sigverify_p95-ms": 85.24, + "components/block": 691.0, + "cpu-ms/block": 236.8, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 111.9, + "full_to_ready_p95-ms": 123.9, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260018664.0, + "allocs/op": 235461.0 + } + }, + { + "sample": 1, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 121769753.0, + "avg_cpu_cores": 2.062, + "collection_p50-ms": 9.028, + "collection_p95-ms": 9.419, + "completion_parse_p50-ms": 4.405, + "completion_parse_p95-ms": 6.85, + "completion_sigverify_p50-ms": 83.24, + "completion_sigverify_p95-ms": 85.39, + "components/block": 691.0, + "cpu-ms/block": 251.1, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 2038.0, + "full_to_ready_p50-ms": 114.3, + "full_to_ready_p95-ms": 116.6, + "mean_width": 7.93, + "preparation_wait_p50-ms": 0.00517, + "preparation_wait_p95-ms": 0.006164, + "tx/block": 33760.0, + "B/op": 265754008.0, + "allocs/op": 236457.0 + } + }, + { + "sample": 1, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 322283398.0, + "avg_cpu_cores": 0.7984, + "collection_p50-ms": 201.2, + "collection_p95-ms": 202.9, + "completion_parse_p50-ms": 4.62, + "completion_parse_p95-ms": 5.138, + "completion_sigverify_p50-ms": 83.39, + "completion_sigverify_p95-ms": 103.0, + "components/block": 691.0, + "cpu-ms/block": 257.3, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 118.0, + "full_to_ready_p95-ms": 134.5, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260100848.0, + "allocs/op": 235465.0 + } + }, + { + "sample": 1, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 227419935.0, + "avg_cpu_cores": 1.187, + "collection_p50-ms": 201.0, + "collection_p95-ms": 201.2, + "completion_parse_p50-ms": 0.01162, + "completion_parse_p95-ms": 0.01907, + "completion_sigverify_p50-ms": 0.3091, + "completion_sigverify_p95-ms": 0.4848, + "components/block": 691.0, + "cpu-ms/block": 270.0, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33721.0, + "full_to_ready_p50-ms": 25.27, + "full_to_ready_p95-ms": 29.18, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1238, + "preparation_wait_p95-ms": 0.1314, + "tx/block": 33760.0, + "B/op": 307386140.0, + "allocs/op": 250045.0 + } + }, + { + "sample": 1, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 83134892.0, + "avg_cpu_cores": 1.997, + "collection_p50-ms": 1.178, + "collection_p95-ms": 1.282, + "completion_parse_p50-ms": 3.263, + "completion_parse_p95-ms": 4.674, + "completion_sigverify_p50-ms": 75.84, + "completion_sigverify_p95-ms": 77.02, + "components/block": 128.0, + "cpu-ms/block": 166.0, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 81.77, + "full_to_ready_p95-ms": 84.78, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 32178240.0, + "allocs/op": 207227.0 + } + }, + { + "sample": 1, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 82695024.0, + "avg_cpu_cores": 2.045, + "collection_p50-ms": 1.573, + "collection_p95-ms": 1.693, + "completion_parse_p50-ms": 3.629, + "completion_parse_p95-ms": 4.856, + "completion_sigverify_p50-ms": 73.77, + "completion_sigverify_p95-ms": 78.48, + "components/block": 128.0, + "cpu-ms/block": 169.1, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 53.8, + "full_to_ready_p50-ms": 80.42, + "full_to_ready_p95-ms": 87.9, + "mean_width": 7.997, + "preparation_wait_p50-ms": 0.000771, + "preparation_wait_p95-ms": 0.03901, + "tx/block": 33760.0, + "B/op": 34804320.0, + "allocs/op": 207381.0 + } + }, + { + "sample": 1, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 282658756.0, + "avg_cpu_cores": 0.5921, + "collection_p50-ms": 200.8, + "collection_p95-ms": 201.0, + "completion_parse_p50-ms": 3.658, + "completion_parse_p95-ms": 4.3, + "completion_sigverify_p50-ms": 75.38, + "completion_sigverify_p95-ms": 75.46, + "components/block": 128.0, + "cpu-ms/block": 167.4, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 82.09, + "full_to_ready_p95-ms": 83.07, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 32233064.0, + "allocs/op": 207230.0 + } + }, + { + "sample": 1, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 203125335.0, + "avg_cpu_cores": 0.861, + "collection_p50-ms": 200.8, + "collection_p95-ms": 201.0, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.01565, + "completion_sigverify_p95-ms": 0.01665, + "components/block": 128.0, + "cpu-ms/block": 174.9, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 2.212, + "full_to_ready_p95-ms": 2.384, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.01656, + "preparation_wait_p95-ms": 0.01853, + "tx/block": 33760.0, + "B/op": 33093758.0, + "allocs/op": 210058.0 + } + }, + { + "sample": 1, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 110251450.0, + "avg_cpu_cores": 1.891, + "collection_p50-ms": 6.539, + "collection_p95-ms": 6.757, + "completion_parse_p50-ms": 3.75, + "completion_parse_p95-ms": 4.958, + "completion_sigverify_p50-ms": 85.91, + "completion_sigverify_p95-ms": 88.56, + "components/block": 691.0, + "cpu-ms/block": 208.5, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 103.8, + "full_to_ready_p95-ms": 104.7, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 111932865.0, + "allocs/op": 227176.0 + } + }, + { + "sample": 1, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 107413848.0, + "avg_cpu_cores": 2.009, + "collection_p50-ms": 9.056, + "collection_p95-ms": 9.607, + "completion_parse_p50-ms": 3.786, + "completion_parse_p95-ms": 4.344, + "completion_sigverify_p50-ms": 80.71, + "completion_sigverify_p95-ms": 83.94, + "components/block": 691.0, + "cpu-ms/block": 215.8, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 2058.0, + "full_to_ready_p50-ms": 96.75, + "full_to_ready_p95-ms": 104.7, + "mean_width": 7.93, + "preparation_wait_p50-ms": 0.003566, + "preparation_wait_p95-ms": 0.006684, + "tx/block": 33760.0, + "B/op": 114424409.0, + "allocs/op": 228118.0 + } + }, + { + "sample": 1, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 302887790.0, + "avg_cpu_cores": 0.6968, + "collection_p50-ms": 201.3, + "collection_p95-ms": 201.5, + "completion_parse_p50-ms": 3.559, + "completion_parse_p95-ms": 4.55, + "completion_sigverify_p50-ms": 84.29, + "completion_sigverify_p95-ms": 85.42, + "components/block": 691.0, + "cpu-ms/block": 211.1, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 101.9, + "full_to_ready_p95-ms": 106.5, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 112097940.0, + "allocs/op": 227185.0 + } + }, + { + "sample": 1, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 213778904.0, + "avg_cpu_cores": 1.327, + "collection_p50-ms": 201.0, + "collection_p95-ms": 201.4, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.1053, + "completion_sigverify_p95-ms": 0.1169, + "components/block": 691.0, + "cpu-ms/block": 283.7, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 12.72, + "full_to_ready_p95-ms": 12.87, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1121, + "preparation_wait_p95-ms": 0.117, + "tx/block": 33760.0, + "B/op": 114137292.0, + "allocs/op": 241053.0 + } + }, + { + "sample": 2, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 86659017.0, + "avg_cpu_cores": 1.995, + "collection_p50-ms": 1.144, + "collection_p95-ms": 1.292, + "completion_parse_p50-ms": 4.107, + "completion_parse_p95-ms": 4.424, + "completion_sigverify_p50-ms": 77.2, + "completion_sigverify_p95-ms": 78.3, + "components/block": 128.0, + "cpu-ms/block": 172.9, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 85.56, + "full_to_ready_p95-ms": 87.67, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 59220556.0, + "allocs/op": 208743.0 + } + }, + { + "sample": 2, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 86399060.0, + "avg_cpu_cores": 2.039, + "collection_p50-ms": 1.618, + "collection_p95-ms": 1.801, + "completion_parse_p50-ms": 4.302, + "completion_parse_p95-ms": 4.956, + "completion_sigverify_p50-ms": 75.09, + "completion_sigverify_p95-ms": 77.26, + "components/block": 128.0, + "cpu-ms/block": 176.2, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 215.2, + "full_to_ready_p50-ms": 84.87, + "full_to_ready_p95-ms": 87.09, + "mean_width": 7.996, + "preparation_wait_p50-ms": 0.4134, + "preparation_wait_p95-ms": 0.8909, + "tx/block": 33760.0, + "B/op": 62291787.0, + "allocs/op": 208932.0 + } + }, + { + "sample": 2, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 295572582.0, + "avg_cpu_cores": 0.6474, + "collection_p50-ms": 201.2, + "collection_p95-ms": 201.3, + "completion_parse_p50-ms": 4.79, + "completion_parse_p95-ms": 5.857, + "completion_sigverify_p50-ms": 84.85, + "completion_sigverify_p95-ms": 94.81, + "components/block": 128.0, + "cpu-ms/block": 191.3, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 96.63, + "full_to_ready_p95-ms": 109.6, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 59193052.0, + "allocs/op": 208741.0 + } + }, + { + "sample": 2, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 207101457.0, + "avg_cpu_cores": 0.8795, + "collection_p50-ms": 200.8, + "collection_p95-ms": 201.1, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.01769, + "completion_sigverify_p95-ms": 0.02059, + "components/block": 128.0, + "cpu-ms/block": 182.1, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 5.453, + "full_to_ready_p95-ms": 9.838, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.02266, + "preparation_wait_p95-ms": 0.02356, + "tx/block": 33760.0, + "B/op": 68303752.0, + "allocs/op": 211688.0 + } + }, + { + "sample": 2, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 120279413.0, + "avg_cpu_cores": 1.963, + "collection_p50-ms": 6.307, + "collection_p95-ms": 6.77, + "completion_parse_p50-ms": 4.339, + "completion_parse_p95-ms": 5.81, + "completion_sigverify_p50-ms": 83.41, + "completion_sigverify_p95-ms": 83.86, + "components/block": 691.0, + "cpu-ms/block": 236.1, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 112.0, + "full_to_ready_p95-ms": 121.7, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260018088.0, + "allocs/op": 235459.0 + } + }, + { + "sample": 2, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 118298008.0, + "avg_cpu_cores": 2.033, + "collection_p50-ms": 8.346, + "collection_p95-ms": 9.341, + "completion_parse_p50-ms": 3.943, + "completion_parse_p95-ms": 4.342, + "completion_sigverify_p50-ms": 79.88, + "completion_sigverify_p95-ms": 82.24, + "components/block": 691.0, + "cpu-ms/block": 240.4, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 1862.0, + "full_to_ready_p50-ms": 109.8, + "full_to_ready_p95-ms": 113.1, + "mean_width": 7.936, + "preparation_wait_p50-ms": 0.003836, + "preparation_wait_p95-ms": 0.004838, + "tx/block": 33760.0, + "B/op": 265236585.0, + "allocs/op": 236375.0 + } + }, + { + "sample": 2, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 320159693.0, + "avg_cpu_cores": 0.7944, + "collection_p50-ms": 201.3, + "collection_p95-ms": 201.8, + "completion_parse_p50-ms": 4.424, + "completion_parse_p95-ms": 4.719, + "completion_sigverify_p50-ms": 88.85, + "completion_sigverify_p95-ms": 95.88, + "components/block": 691.0, + "cpu-ms/block": 254.3, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 117.5, + "full_to_ready_p95-ms": 125.4, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260128558.0, + "allocs/op": 235467.0 + } + }, + { + "sample": 2, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 228077236.0, + "avg_cpu_cores": 1.181, + "collection_p50-ms": 201.0, + "collection_p95-ms": 201.4, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.01689, + "completion_sigverify_p50-ms": 0.1095, + "completion_sigverify_p95-ms": 0.3459, + "components/block": 691.0, + "cpu-ms/block": 269.4, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33750.0, + "full_to_ready_p50-ms": 25.85, + "full_to_ready_p95-ms": 31.67, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1293, + "preparation_wait_p95-ms": 0.1316, + "tx/block": 33760.0, + "B/op": 307341900.0, + "allocs/op": 250055.0 + } + }, + { + "sample": 2, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 86241226.0, + "avg_cpu_cores": 1.993, + "collection_p50-ms": 1.244, + "collection_p95-ms": 1.299, + "completion_parse_p50-ms": 3.632, + "completion_parse_p95-ms": 4.785, + "completion_sigverify_p50-ms": 77.77, + "completion_sigverify_p95-ms": 81.78, + "components/block": 128.0, + "cpu-ms/block": 171.9, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 83.95, + "full_to_ready_p95-ms": 89.64, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 32178248.0, + "allocs/op": 207227.0 + } + }, + { + "sample": 2, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 81680215.0, + "avg_cpu_cores": 2.062, + "collection_p50-ms": 1.645, + "collection_p95-ms": 1.663, + "completion_parse_p50-ms": 3.51, + "completion_parse_p95-ms": 4.122, + "completion_sigverify_p50-ms": 73.07, + "completion_sigverify_p95-ms": 75.29, + "components/block": 128.0, + "cpu-ms/block": 168.5, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 53.8, + "full_to_ready_p50-ms": 79.46, + "full_to_ready_p95-ms": 82.06, + "mean_width": 7.996, + "preparation_wait_p50-ms": 0.000902, + "preparation_wait_p95-ms": 0.3958, + "tx/block": 33760.0, + "B/op": 34810161.0, + "allocs/op": 207404.0 + } + }, + { + "sample": 2, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 283720123.0, + "avg_cpu_cores": 0.5926, + "collection_p50-ms": 201.0, + "collection_p95-ms": 201.1, + "completion_parse_p50-ms": 4.15, + "completion_parse_p95-ms": 5.979, + "completion_sigverify_p50-ms": 75.42, + "completion_sigverify_p95-ms": 76.75, + "components/block": 128.0, + "cpu-ms/block": 168.1, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 82.65, + "full_to_ready_p95-ms": 84.17, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 32315624.0, + "allocs/op": 207235.0 + } + }, + { + "sample": 2, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 202974173.0, + "avg_cpu_cores": 0.8767, + "collection_p50-ms": 200.8, + "collection_p95-ms": 200.9, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.0161, + "completion_sigverify_p95-ms": 0.02322, + "components/block": 128.0, + "cpu-ms/block": 177.9, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 2.265, + "full_to_ready_p95-ms": 2.34, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.01836, + "preparation_wait_p95-ms": 0.01868, + "tx/block": 33760.0, + "B/op": 33013977.0, + "allocs/op": 210063.0 + } + }, + { + "sample": 2, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 108052777.0, + "avg_cpu_cores": 1.902, + "collection_p50-ms": 6.441, + "collection_p95-ms": 6.951, + "completion_parse_p50-ms": 3.54, + "completion_parse_p95-ms": 4.962, + "completion_sigverify_p50-ms": 84.58, + "completion_sigverify_p95-ms": 85.8, + "components/block": 691.0, + "cpu-ms/block": 205.6, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 102.2, + "full_to_ready_p95-ms": 106.2, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 111905424.0, + "allocs/op": 227175.0 + } + }, + { + "sample": 2, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 113945740.0, + "avg_cpu_cores": 1.995, + "collection_p50-ms": 9.282, + "collection_p95-ms": 11.0, + "completion_parse_p50-ms": 3.909, + "completion_parse_p95-ms": 4.912, + "completion_sigverify_p50-ms": 84.29, + "completion_sigverify_p95-ms": 94.37, + "components/block": 691.0, + "cpu-ms/block": 227.4, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 2048.0, + "full_to_ready_p50-ms": 104.1, + "full_to_ready_p95-ms": 111.8, + "mean_width": 7.929, + "preparation_wait_p50-ms": 0.003519, + "preparation_wait_p95-ms": 0.006271, + "tx/block": 33760.0, + "B/op": 114311740.0, + "allocs/op": 228106.0 + } + }, + { + "sample": 2, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 304716913.0, + "avg_cpu_cores": 0.7074, + "collection_p50-ms": 201.6, + "collection_p95-ms": 201.7, + "completion_parse_p50-ms": 4.281, + "completion_parse_p95-ms": 4.819, + "completion_sigverify_p50-ms": 84.11, + "completion_sigverify_p95-ms": 89.27, + "components/block": 691.0, + "cpu-ms/block": 215.6, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 102.5, + "full_to_ready_p95-ms": 109.4, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 112180404.0, + "allocs/op": 227190.0 + } + }, + { + "sample": 2, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 212222544.0, + "avg_cpu_cores": 1.082, + "collection_p50-ms": 200.9, + "collection_p95-ms": 201.5, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.01717, + "completion_sigverify_p50-ms": 0.09849, + "completion_sigverify_p95-ms": 0.418, + "components/block": 691.0, + "cpu-ms/block": 229.6, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33741.0, + "full_to_ready_p50-ms": 11.01, + "full_to_ready_p95-ms": 11.46, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1016, + "preparation_wait_p95-ms": 0.1048, + "tx/block": 33760.0, + "B/op": 114254763.0, + "allocs/op": 241078.0 + } + }, + { + "sample": 3, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 85727666.0, + "avg_cpu_cores": 1.994, + "collection_p50-ms": 1.123, + "collection_p95-ms": 1.319, + "completion_parse_p50-ms": 4.203, + "completion_parse_p95-ms": 4.528, + "completion_sigverify_p50-ms": 75.36, + "completion_sigverify_p95-ms": 76.36, + "components/block": 128.0, + "cpu-ms/block": 171.0, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 85.03, + "full_to_ready_p95-ms": 86.29, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 59248208.0, + "allocs/op": 208745.0 + } + }, + { + "sample": 3, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 93032467.0, + "avg_cpu_cores": 2.047, + "collection_p50-ms": 1.604, + "collection_p95-ms": 1.819, + "completion_parse_p50-ms": 4.104, + "completion_parse_p95-ms": 5.156, + "completion_sigverify_p50-ms": 80.57, + "completion_sigverify_p95-ms": 87.12, + "components/block": 128.0, + "cpu-ms/block": 190.4, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 107.6, + "full_to_ready_p50-ms": 91.48, + "full_to_ready_p95-ms": 95.41, + "mean_width": 7.997, + "preparation_wait_p50-ms": 0.000692, + "preparation_wait_p95-ms": 0.04334, + "tx/block": 33760.0, + "B/op": 61931662.0, + "allocs/op": 208897.0 + } + }, + { + "sample": 3, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 285476051.0, + "avg_cpu_cores": 0.6068, + "collection_p50-ms": 200.9, + "collection_p95-ms": 201.0, + "completion_parse_p50-ms": 3.352, + "completion_parse_p95-ms": 4.118, + "completion_sigverify_p50-ms": 76.14, + "completion_sigverify_p95-ms": 77.78, + "components/block": 128.0, + "cpu-ms/block": 173.2, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 84.82, + "full_to_ready_p95-ms": 85.15, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 59303190.0, + "allocs/op": 208749.0 + } + }, + { + "sample": 3, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 207130969.0, + "avg_cpu_cores": 0.8933, + "collection_p50-ms": 200.6, + "collection_p95-ms": 200.7, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.01884, + "completion_sigverify_p95-ms": 0.02053, + "components/block": 128.0, + "cpu-ms/block": 185.0, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 5.428, + "full_to_ready_p95-ms": 10.36, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.02344, + "preparation_wait_p95-ms": 0.02789, + "tx/block": 33760.0, + "B/op": 68193945.0, + "allocs/op": 211684.0 + } + }, + { + "sample": 3, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 121503561.0, + "avg_cpu_cores": 1.942, + "collection_p50-ms": 6.518, + "collection_p95-ms": 6.678, + "completion_parse_p50-ms": 4.399, + "completion_parse_p95-ms": 4.914, + "completion_sigverify_p50-ms": 83.32, + "completion_sigverify_p95-ms": 85.03, + "components/block": 691.0, + "cpu-ms/block": 236.0, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 111.7, + "full_to_ready_p95-ms": 122.4, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260018412.0, + "allocs/op": 235460.0 + } + }, + { + "sample": 3, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 117837845.0, + "avg_cpu_cores": 2.08, + "collection_p50-ms": 8.353, + "collection_p95-ms": 10.64, + "completion_parse_p50-ms": 4.156, + "completion_parse_p95-ms": 5.325, + "completion_sigverify_p50-ms": 78.84, + "completion_sigverify_p95-ms": 83.36, + "components/block": 691.0, + "cpu-ms/block": 245.1, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 1891.0, + "full_to_ready_p50-ms": 108.9, + "full_to_ready_p95-ms": 111.3, + "mean_width": 7.936, + "preparation_wait_p50-ms": 0.00511, + "preparation_wait_p95-ms": 0.006629, + "tx/block": 33760.0, + "B/op": 265386019.0, + "allocs/op": 236393.0 + } + }, + { + "sample": 3, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 318075945.0, + "avg_cpu_cores": 0.7698, + "collection_p50-ms": 201.2, + "collection_p95-ms": 201.7, + "completion_parse_p50-ms": 4.535, + "completion_parse_p95-ms": 6.282, + "completion_sigverify_p50-ms": 86.26, + "completion_sigverify_p95-ms": 88.65, + "components/block": 691.0, + "cpu-ms/block": 244.8, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 116.5, + "full_to_ready_p95-ms": 120.7, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260100819.0, + "allocs/op": 235465.0 + } + }, + { + "sample": 3, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 227891859.0, + "avg_cpu_cores": 1.192, + "collection_p50-ms": 200.9, + "collection_p95-ms": 201.7, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.1033, + "completion_sigverify_p95-ms": 0.1248, + "components/block": 691.0, + "cpu-ms/block": 271.8, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 25.57, + "full_to_ready_p95-ms": 31.02, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1267, + "preparation_wait_p95-ms": 0.1306, + "tx/block": 33760.0, + "B/op": 307494656.0, + "allocs/op": 250070.0 + } + }, + { + "sample": 3, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 85101485.0, + "avg_cpu_cores": 1.996, + "collection_p50-ms": 1.142, + "collection_p95-ms": 1.251, + "completion_parse_p50-ms": 3.633, + "completion_parse_p95-ms": 4.608, + "completion_sigverify_p50-ms": 77.59, + "completion_sigverify_p95-ms": 79.04, + "components/block": 128.0, + "cpu-ms/block": 169.8, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 84.13, + "full_to_ready_p95-ms": 85.35, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 32233233.0, + "allocs/op": 207230.0 + } + }, + { + "sample": 3, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 83717807.0, + "avg_cpu_cores": 2.049, + "collection_p50-ms": 1.555, + "collection_p95-ms": 1.796, + "completion_parse_p50-ms": 3.655, + "completion_parse_p95-ms": 4.307, + "completion_sigverify_p50-ms": 75.73, + "completion_sigverify_p95-ms": 77.56, + "components/block": 128.0, + "cpu-ms/block": 171.5, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 107.6, + "full_to_ready_p50-ms": 81.9, + "full_to_ready_p95-ms": 84.2, + "mean_width": 7.996, + "preparation_wait_p50-ms": 0.000951, + "preparation_wait_p95-ms": 0.9772, + "tx/block": 33760.0, + "B/op": 34781204.0, + "allocs/op": 207396.0 + } + }, + { + "sample": 3, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 283918809.0, + "avg_cpu_cores": 0.5965, + "collection_p50-ms": 200.7, + "collection_p95-ms": 201.0, + "completion_parse_p50-ms": 3.509, + "completion_parse_p95-ms": 4.352, + "completion_sigverify_p50-ms": 76.49, + "completion_sigverify_p95-ms": 79.83, + "components/block": 128.0, + "cpu-ms/block": 169.4, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 83.91, + "full_to_ready_p95-ms": 86.88, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 32260635.0, + "allocs/op": 207231.0 + } + }, + { + "sample": 3, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 203102557.0, + "avg_cpu_cores": 0.8531, + "collection_p50-ms": 200.7, + "collection_p95-ms": 201.0, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.01636, + "completion_sigverify_p95-ms": 0.01724, + "components/block": 128.0, + "cpu-ms/block": 173.3, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 2.283, + "full_to_ready_p95-ms": 2.706, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.01703, + "preparation_wait_p95-ms": 0.01848, + "tx/block": 33760.0, + "B/op": 33091550.0, + "allocs/op": 210049.0 + } + }, + { + "sample": 3, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 108851790.0, + "avg_cpu_cores": 1.903, + "collection_p50-ms": 5.88, + "collection_p95-ms": 6.6, + "completion_parse_p50-ms": 3.485, + "completion_parse_p95-ms": 4.888, + "completion_sigverify_p50-ms": 85.29, + "completion_sigverify_p95-ms": 87.68, + "components/block": 691.0, + "cpu-ms/block": 207.2, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 102.1, + "full_to_ready_p95-ms": 105.1, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 112042787.0, + "allocs/op": 227182.0 + } + }, + { + "sample": 3, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 105118924.0, + "avg_cpu_cores": 1.992, + "collection_p50-ms": 8.424, + "collection_p95-ms": 9.203, + "completion_parse_p50-ms": 3.571, + "completion_parse_p95-ms": 4.459, + "completion_sigverify_p50-ms": 79.01, + "completion_sigverify_p95-ms": 82.87, + "components/block": 691.0, + "cpu-ms/block": 209.4, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 2009.0, + "full_to_ready_p50-ms": 95.95, + "full_to_ready_p95-ms": 102.7, + "mean_width": 7.932, + "preparation_wait_p50-ms": 0.002874, + "preparation_wait_p95-ms": 0.004791, + "tx/block": 33760.0, + "B/op": 114420668.0, + "allocs/op": 228093.0 + } + }, + { + "sample": 3, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 311473242.0, + "avg_cpu_cores": 0.7254, + "collection_p50-ms": 201.3, + "collection_p95-ms": 201.6, + "completion_parse_p50-ms": 4.354, + "completion_parse_p95-ms": 4.596, + "completion_sigverify_p50-ms": 86.07, + "completion_sigverify_p95-ms": 101.8, + "components/block": 691.0, + "cpu-ms/block": 226.0, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 106.9, + "full_to_ready_p95-ms": 121.5, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 112015353.0, + "allocs/op": 227181.0 + } + }, + { + "sample": 3, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 213548260.0, + "avg_cpu_cores": 1.136, + "collection_p50-ms": 201.1, + "collection_p95-ms": 203.1, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.01487, + "completion_sigverify_p50-ms": 0.1838, + "completion_sigverify_p95-ms": 0.5611, + "components/block": 691.0, + "cpu-ms/block": 242.6, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33721.0, + "full_to_ready_p50-ms": 11.67, + "full_to_ready_p95-ms": 13.52, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1105, + "preparation_wait_p95-ms": 0.1124, + "tx/block": 33760.0, + "B/op": 114250187.0, + "allocs/op": 241068.0 + } + }, + { + "sample": 4, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 85908997.0, + "avg_cpu_cores": 1.99, + "collection_p50-ms": 1.114, + "collection_p95-ms": 1.748, + "completion_parse_p50-ms": 4.036, + "completion_parse_p95-ms": 4.731, + "completion_sigverify_p50-ms": 75.53, + "completion_sigverify_p95-ms": 76.38, + "components/block": 128.0, + "cpu-ms/block": 171.0, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 85.02, + "full_to_ready_p95-ms": 87.14, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 59303256.0, + "allocs/op": 208748.0 + } + }, + { + "sample": 4, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 83287865.0, + "avg_cpu_cores": 2.055, + "collection_p50-ms": 1.528, + "collection_p95-ms": 1.624, + "completion_parse_p50-ms": 3.147, + "completion_parse_p95-ms": 4.146, + "completion_sigverify_p50-ms": 73.56, + "completion_sigverify_p95-ms": 75.42, + "components/block": 128.0, + "cpu-ms/block": 171.2, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 53.8, + "full_to_ready_p50-ms": 81.77, + "full_to_ready_p95-ms": 82.43, + "mean_width": 7.997, + "preparation_wait_p50-ms": 0.00075, + "preparation_wait_p95-ms": 0.000791, + "tx/block": 33760.0, + "B/op": 62015553.0, + "allocs/op": 208909.0 + } + }, + { + "sample": 4, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 286588469.0, + "avg_cpu_cores": 0.6114, + "collection_p50-ms": 200.8, + "collection_p95-ms": 201.1, + "completion_parse_p50-ms": 3.437, + "completion_parse_p95-ms": 3.868, + "completion_sigverify_p50-ms": 76.77, + "completion_sigverify_p95-ms": 79.74, + "components/block": 128.0, + "cpu-ms/block": 175.2, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 85.44, + "full_to_ready_p95-ms": 88.49, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 59275379.0, + "allocs/op": 208745.0 + } + }, + { + "sample": 4, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 208123357.0, + "avg_cpu_cores": 0.9981, + "collection_p50-ms": 200.8, + "collection_p95-ms": 201.3, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.02067, + "completion_sigverify_p95-ms": 0.02899, + "components/block": 128.0, + "cpu-ms/block": 207.7, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 7.752, + "full_to_ready_p95-ms": 10.18, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.02546, + "preparation_wait_p95-ms": 0.02901, + "tx/block": 33760.0, + "B/op": 68363801.0, + "allocs/op": 211716.0 + } + }, + { + "sample": 4, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 134090384.0, + "avg_cpu_cores": 1.916, + "collection_p50-ms": 7.863, + "collection_p95-ms": 9.017, + "completion_parse_p50-ms": 5.347, + "completion_parse_p95-ms": 5.887, + "completion_sigverify_p50-ms": 90.59, + "completion_sigverify_p95-ms": 103.3, + "components/block": 691.0, + "cpu-ms/block": 256.9, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 124.8, + "full_to_ready_p95-ms": 146.3, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260045872.0, + "allocs/op": 235462.0 + } + }, + { + "sample": 4, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 118644204.0, + "avg_cpu_cores": 2.083, + "collection_p50-ms": 8.456, + "collection_p95-ms": 8.783, + "completion_parse_p50-ms": 3.887, + "completion_parse_p95-ms": 4.874, + "completion_sigverify_p50-ms": 80.59, + "completion_sigverify_p95-ms": 82.3, + "components/block": 691.0, + "cpu-ms/block": 247.2, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 1931.0, + "full_to_ready_p50-ms": 109.2, + "full_to_ready_p95-ms": 112.4, + "mean_width": 7.935, + "preparation_wait_p50-ms": 0.004411, + "preparation_wait_p95-ms": 0.004846, + "tx/block": 33760.0, + "B/op": 265440401.0, + "allocs/op": 236406.0 + } + }, + { + "sample": 4, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 316166377.0, + "avg_cpu_cores": 0.7691, + "collection_p50-ms": 201.3, + "collection_p95-ms": 201.6, + "completion_parse_p50-ms": 4.191, + "completion_parse_p95-ms": 4.5, + "completion_sigverify_p50-ms": 84.55, + "completion_sigverify_p95-ms": 87.88, + "components/block": 691.0, + "cpu-ms/block": 243.2, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 115.2, + "full_to_ready_p95-ms": 119.9, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 259963968.0, + "allocs/op": 235459.0 + } + }, + { + "sample": 4, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 230004734.0, + "avg_cpu_cores": 1.196, + "collection_p50-ms": 201.3, + "collection_p95-ms": 201.8, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.1175, + "completion_sigverify_p95-ms": 0.1314, + "components/block": 691.0, + "cpu-ms/block": 275.1, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 28.3, + "full_to_ready_p95-ms": 32.14, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1213, + "preparation_wait_p95-ms": 0.1297, + "tx/block": 33760.0, + "B/op": 307660395.0, + "allocs/op": 250071.0 + } + }, + { + "sample": 4, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 83997761.0, + "avg_cpu_cores": 1.99, + "collection_p50-ms": 1.213, + "collection_p95-ms": 1.275, + "completion_parse_p50-ms": 3.383, + "completion_parse_p95-ms": 4.718, + "completion_sigverify_p50-ms": 76.12, + "completion_sigverify_p95-ms": 77.08, + "components/block": 128.0, + "cpu-ms/block": 167.2, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 82.75, + "full_to_ready_p95-ms": 84.96, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 32260841.0, + "allocs/op": 207232.0 + } + }, + { + "sample": 4, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 82378390.0, + "avg_cpu_cores": 2.052, + "collection_p50-ms": 1.582, + "collection_p95-ms": 1.764, + "completion_parse_p50-ms": 3.427, + "completion_parse_p95-ms": 4.179, + "completion_sigverify_p50-ms": 73.7, + "completion_sigverify_p95-ms": 77.03, + "components/block": 128.0, + "cpu-ms/block": 169.1, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 107.6, + "full_to_ready_p50-ms": 80.55, + "full_to_ready_p95-ms": 83.25, + "mean_width": 7.996, + "preparation_wait_p50-ms": 0.000711, + "preparation_wait_p95-ms": 0.5494, + "tx/block": 33760.0, + "B/op": 34778107.0, + "allocs/op": 207384.0 + } + }, + { + "sample": 4, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 285362255.0, + "avg_cpu_cores": 0.603, + "collection_p50-ms": 201.1, + "collection_p95-ms": 201.1, + "completion_parse_p50-ms": 4.124, + "completion_parse_p95-ms": 4.297, + "completion_sigverify_p50-ms": 75.54, + "completion_sigverify_p95-ms": 83.57, + "components/block": 128.0, + "cpu-ms/block": 172.1, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 83.22, + "full_to_ready_p95-ms": 91.69, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 32287976.0, + "allocs/op": 207232.0 + } + }, + { + "sample": 4, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 203641348.0, + "avg_cpu_cores": 1.007, + "collection_p50-ms": 200.9, + "collection_p95-ms": 201.2, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.01979, + "completion_sigverify_p95-ms": 0.02696, + "components/block": 128.0, + "cpu-ms/block": 205.1, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 2.728, + "full_to_ready_p95-ms": 2.801, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.02069, + "preparation_wait_p95-ms": 0.02411, + "tx/block": 33760.0, + "B/op": 33091185.0, + "allocs/op": 210047.0 + } + }, + { + "sample": 4, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 109632016.0, + "avg_cpu_cores": 1.892, + "collection_p50-ms": 6.787, + "collection_p95-ms": 7.832, + "completion_parse_p50-ms": 3.642, + "completion_parse_p95-ms": 4.96, + "completion_sigverify_p50-ms": 85.31, + "completion_sigverify_p95-ms": 88.3, + "components/block": 691.0, + "cpu-ms/block": 207.4, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 102.1, + "full_to_ready_p95-ms": 108.2, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 111905504.0, + "allocs/op": 227176.0 + } + }, + { + "sample": 4, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 106324511.0, + "avg_cpu_cores": 2.007, + "collection_p50-ms": 8.568, + "collection_p95-ms": 9.414, + "completion_parse_p50-ms": 3.655, + "completion_parse_p95-ms": 4.119, + "completion_sigverify_p50-ms": 79.89, + "completion_sigverify_p95-ms": 84.03, + "components/block": 691.0, + "cpu-ms/block": 213.4, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 1862.0, + "full_to_ready_p50-ms": 96.25, + "full_to_ready_p95-ms": 103.4, + "mean_width": 7.936, + "preparation_wait_p50-ms": 0.003455, + "preparation_wait_p95-ms": 0.006185, + "tx/block": 33760.0, + "B/op": 114547820.0, + "allocs/op": 228037.0 + } + }, + { + "sample": 4, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 311267426.0, + "avg_cpu_cores": 0.7263, + "collection_p50-ms": 201.1, + "collection_p95-ms": 202.1, + "completion_parse_p50-ms": 3.621, + "completion_parse_p95-ms": 5.061, + "completion_sigverify_p50-ms": 87.9, + "completion_sigverify_p95-ms": 103.1, + "components/block": 691.0, + "cpu-ms/block": 226.1, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 105.2, + "full_to_ready_p95-ms": 119.8, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 111932950.0, + "allocs/op": 227177.0 + } + }, + { + "sample": 4, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 212794779.0, + "avg_cpu_cores": 1.109, + "collection_p50-ms": 201.0, + "collection_p95-ms": 202.1, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.01383, + "completion_sigverify_p50-ms": 0.1078, + "completion_sigverify_p95-ms": 0.3044, + "components/block": 691.0, + "cpu-ms/block": 236.0, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33750.0, + "full_to_ready_p50-ms": 11.18, + "full_to_ready_p95-ms": 12.44, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1053, + "preparation_wait_p95-ms": 0.1134, + "tx/block": 33760.0, + "B/op": 114247308.0, + "allocs/op": 241055.0 + } + }, + { + "sample": 5, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 86664771.0, + "avg_cpu_cores": 1.983, + "collection_p50-ms": 1.195, + "collection_p95-ms": 1.43, + "completion_parse_p50-ms": 4.332, + "completion_parse_p95-ms": 5.166, + "completion_sigverify_p50-ms": 76.4, + "completion_sigverify_p95-ms": 77.61, + "components/block": 128.0, + "cpu-ms/block": 171.9, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 86.21, + "full_to_ready_p95-ms": 87.53, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 59275827.0, + "allocs/op": 208747.0 + } + }, + { + "sample": 5, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 100446776.0, + "avg_cpu_cores": 2.026, + "collection_p50-ms": 2.064, + "collection_p95-ms": 2.165, + "completion_parse_p50-ms": 4.494, + "completion_parse_p95-ms": 5.885, + "completion_sigverify_p50-ms": 89.05, + "completion_sigverify_p95-ms": 89.98, + "components/block": 128.0, + "cpu-ms/block": 203.5, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 215.2, + "full_to_ready_p50-ms": 100.3, + "full_to_ready_p95-ms": 104.8, + "mean_width": 7.996, + "preparation_wait_p50-ms": 0.000821, + "preparation_wait_p95-ms": 0.001052, + "tx/block": 33760.0, + "B/op": 61973884.0, + "allocs/op": 208905.0 + } + }, + { + "sample": 5, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 286167802.0, + "avg_cpu_cores": 0.6098, + "collection_p50-ms": 200.7, + "collection_p95-ms": 200.8, + "completion_parse_p50-ms": 3.934, + "completion_parse_p95-ms": 4.419, + "completion_sigverify_p50-ms": 76.59, + "completion_sigverify_p95-ms": 77.91, + "components/block": 128.0, + "cpu-ms/block": 174.5, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 85.4, + "full_to_ready_p95-ms": 86.57, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 59193008.0, + "allocs/op": 208742.0 + } + }, + { + "sample": 5, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 207732756.0, + "avg_cpu_cores": 0.9023, + "collection_p50-ms": 200.9, + "collection_p95-ms": 201.1, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.01991, + "completion_sigverify_p95-ms": 0.03155, + "components/block": 128.0, + "cpu-ms/block": 187.4, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 7.562, + "full_to_ready_p95-ms": 9.053, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.02246, + "preparation_wait_p95-ms": 0.02459, + "tx/block": 33760.0, + "B/op": 68138699.0, + "allocs/op": 211680.0 + } + }, + { + "sample": 5, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 123685493.0, + "avg_cpu_cores": 1.96, + "collection_p50-ms": 6.351, + "collection_p95-ms": 7.32, + "completion_parse_p50-ms": 4.749, + "completion_parse_p95-ms": 4.856, + "completion_sigverify_p50-ms": 84.69, + "completion_sigverify_p95-ms": 86.93, + "components/block": 691.0, + "cpu-ms/block": 242.4, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 118.8, + "full_to_ready_p95-ms": 123.1, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260100822.0, + "allocs/op": 235464.0 + } + }, + { + "sample": 5, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 119201510.0, + "avg_cpu_cores": 2.078, + "collection_p50-ms": 8.512, + "collection_p95-ms": 9.358, + "completion_parse_p50-ms": 4.359, + "completion_parse_p95-ms": 4.711, + "completion_sigverify_p50-ms": 80.38, + "completion_sigverify_p95-ms": 82.91, + "components/block": 691.0, + "cpu-ms/block": 247.7, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 1950.0, + "full_to_ready_p50-ms": 110.3, + "full_to_ready_p95-ms": 113.1, + "mean_width": 7.933, + "preparation_wait_p50-ms": 0.004432, + "preparation_wait_p95-ms": 0.006141, + "tx/block": 33760.0, + "B/op": 265605086.0, + "allocs/op": 236424.0 + } + }, + { + "sample": 5, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 326825723.0, + "avg_cpu_cores": 0.8088, + "collection_p50-ms": 201.9, + "collection_p95-ms": 202.2, + "completion_parse_p50-ms": 4.877, + "completion_parse_p95-ms": 5.064, + "completion_sigverify_p50-ms": 94.15, + "completion_sigverify_p95-ms": 106.9, + "components/block": 691.0, + "cpu-ms/block": 264.3, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 127.9, + "full_to_ready_p95-ms": 139.6, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260100937.0, + "allocs/op": 235466.0 + } + }, + { + "sample": 5, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 229345156.0, + "avg_cpu_cores": 1.197, + "collection_p50-ms": 201.0, + "collection_p95-ms": 201.0, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.1071, + "completion_sigverify_p95-ms": 0.1224, + "components/block": 691.0, + "cpu-ms/block": 274.6, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 28.39, + "full_to_ready_p95-ms": 31.1, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1263, + "preparation_wait_p95-ms": 0.1313, + "tx/block": 33760.0, + "B/op": 307580156.0, + "allocs/op": 250079.0 + } + }, + { + "sample": 5, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 86939212.0, + "avg_cpu_cores": 2.001, + "collection_p50-ms": 1.138, + "collection_p95-ms": 1.528, + "completion_parse_p50-ms": 3.315, + "completion_parse_p95-ms": 4.947, + "completion_sigverify_p50-ms": 80.42, + "completion_sigverify_p95-ms": 81.95, + "components/block": 128.0, + "cpu-ms/block": 173.9, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 86.28, + "full_to_ready_p95-ms": 89.75, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 32343236.0, + "allocs/op": 207237.0 + } + }, + { + "sample": 5, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 93051198.0, + "avg_cpu_cores": 2.052, + "collection_p50-ms": 1.908, + "collection_p95-ms": 2.115, + "completion_parse_p50-ms": 3.802, + "completion_parse_p95-ms": 5.595, + "completion_sigverify_p50-ms": 83.19, + "completion_sigverify_p95-ms": 89.15, + "components/block": 128.0, + "cpu-ms/block": 191.0, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 161.4, + "full_to_ready_p50-ms": 89.81, + "full_to_ready_p95-ms": 98.24, + "mean_width": 7.995, + "preparation_wait_p50-ms": 0.1421, + "preparation_wait_p95-ms": 1.063, + "tx/block": 33760.0, + "B/op": 34757734.0, + "allocs/op": 207410.0 + } + }, + { + "sample": 5, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 285099098.0, + "avg_cpu_cores": 0.6058, + "collection_p50-ms": 200.8, + "collection_p95-ms": 201.0, + "completion_parse_p50-ms": 3.323, + "completion_parse_p95-ms": 4.328, + "completion_sigverify_p50-ms": 77.77, + "completion_sigverify_p95-ms": 77.9, + "components/block": 128.0, + "cpu-ms/block": 172.7, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 84.74, + "full_to_ready_p95-ms": 85.63, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 32205774.0, + "allocs/op": 207229.0 + } + }, + { + "sample": 5, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 203024092.0, + "avg_cpu_cores": 0.8731, + "collection_p50-ms": 200.6, + "collection_p95-ms": 200.9, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.01703, + "completion_sigverify_p95-ms": 0.02449, + "components/block": 128.0, + "cpu-ms/block": 177.3, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 2.292, + "full_to_ready_p95-ms": 2.39, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.01816, + "preparation_wait_p95-ms": 0.01985, + "tx/block": 33760.0, + "B/op": 33175731.0, + "allocs/op": 210061.0 + } + }, + { + "sample": 5, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 116086892.0, + "avg_cpu_cores": 1.896, + "collection_p50-ms": 7.729, + "collection_p95-ms": 9.382, + "completion_parse_p50-ms": 3.985, + "completion_parse_p95-ms": 6.018, + "completion_sigverify_p50-ms": 84.53, + "completion_sigverify_p95-ms": 100.6, + "components/block": 691.0, + "cpu-ms/block": 220.2, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 109.4, + "full_to_ready_p95-ms": 119.2, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 111960304.0, + "allocs/op": 227177.0 + } + }, + { + "sample": 5, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 115194449.0, + "avg_cpu_cores": 1.969, + "collection_p50-ms": 9.432, + "collection_p95-ms": 10.35, + "completion_parse_p50-ms": 3.882, + "completion_parse_p95-ms": 4.979, + "completion_sigverify_p50-ms": 85.65, + "completion_sigverify_p95-ms": 94.03, + "components/block": 691.0, + "cpu-ms/block": 226.9, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 1735.0, + "full_to_ready_p50-ms": 104.0, + "full_to_ready_p95-ms": 111.4, + "mean_width": 7.941, + "preparation_wait_p50-ms": 0.004026, + "preparation_wait_p95-ms": 0.005541, + "tx/block": 33760.0, + "B/op": 114430456.0, + "allocs/op": 227975.0 + } + }, + { + "sample": 5, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 308111487.0, + "avg_cpu_cores": 0.7254, + "collection_p50-ms": 201.5, + "collection_p95-ms": 201.6, + "completion_parse_p50-ms": 4.284, + "completion_parse_p95-ms": 5.167, + "completion_sigverify_p50-ms": 88.66, + "completion_sigverify_p95-ms": 94.67, + "components/block": 691.0, + "cpu-ms/block": 223.5, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 109.1, + "full_to_ready_p95-ms": 113.6, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 112125502.0, + "allocs/op": 227188.0 + } + }, + { + "sample": 5, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 212791787.0, + "avg_cpu_cores": 1.116, + "collection_p50-ms": 200.9, + "collection_p95-ms": 201.0, + "completion_parse_p50-ms": 0.007484, + "completion_parse_p95-ms": 0.01159, + "completion_sigverify_p50-ms": 0.3225, + "completion_sigverify_p95-ms": 0.3603, + "components/block": 691.0, + "cpu-ms/block": 237.6, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33731.0, + "full_to_ready_p50-ms": 11.63, + "full_to_ready_p95-ms": 13.06, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1056, + "preparation_wait_p95-ms": 0.1122, + "tx/block": 33760.0, + "B/op": 114082224.0, + "allocs/op": 241044.0 + } + }, + { + "sample": 6, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 87321492.0, + "avg_cpu_cores": 1.992, + "collection_p50-ms": 1.139, + "collection_p95-ms": 1.213, + "completion_parse_p50-ms": 4.206, + "completion_parse_p95-ms": 4.314, + "completion_sigverify_p50-ms": 76.92, + "completion_sigverify_p95-ms": 79.11, + "components/block": 128.0, + "cpu-ms/block": 173.9, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 86.31, + "full_to_ready_p95-ms": 87.54, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 59110704.0, + "allocs/op": 208737.0 + } + }, + { + "sample": 6, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 88098284.0, + "avg_cpu_cores": 2.039, + "collection_p50-ms": 1.612, + "collection_p95-ms": 1.726, + "completion_parse_p50-ms": 3.683, + "completion_parse_p95-ms": 4.031, + "completion_sigverify_p50-ms": 78.16, + "completion_sigverify_p95-ms": 83.11, + "components/block": 128.0, + "cpu-ms/block": 179.7, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 107.6, + "full_to_ready_p50-ms": 87.14, + "full_to_ready_p95-ms": 92.06, + "mean_width": 7.997, + "preparation_wait_p50-ms": 0.000771, + "preparation_wait_p95-ms": 0.000842, + "tx/block": 33760.0, + "B/op": 61902907.0, + "allocs/op": 208887.0 + } + }, + { + "sample": 6, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 286038446.0, + "avg_cpu_cores": 0.6079, + "collection_p50-ms": 200.9, + "collection_p95-ms": 201.1, + "completion_parse_p50-ms": 3.731, + "completion_parse_p95-ms": 4.179, + "completion_sigverify_p50-ms": 76.35, + "completion_sigverify_p95-ms": 78.24, + "components/block": 128.0, + "cpu-ms/block": 173.9, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 85.53, + "full_to_ready_p95-ms": 85.9, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 59248048.0, + "allocs/op": 208744.0 + } + }, + { + "sample": 6, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 206915717.0, + "avg_cpu_cores": 0.8863, + "collection_p50-ms": 200.6, + "collection_p95-ms": 200.9, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.01665, + "completion_sigverify_p95-ms": 0.02066, + "components/block": 128.0, + "cpu-ms/block": 183.4, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 5.859, + "full_to_ready_p95-ms": 9.065, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.02179, + "preparation_wait_p95-ms": 0.02377, + "tx/block": 33760.0, + "B/op": 68223072.0, + "allocs/op": 211693.0 + } + }, + { + "sample": 6, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 125985246.0, + "avg_cpu_cores": 1.958, + "collection_p50-ms": 6.541, + "collection_p95-ms": 7.319, + "completion_parse_p50-ms": 5.022, + "completion_parse_p95-ms": 5.127, + "completion_sigverify_p50-ms": 86.2, + "completion_sigverify_p95-ms": 88.08, + "components/block": 691.0, + "cpu-ms/block": 246.7, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 118.0, + "full_to_ready_p95-ms": 130.3, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 259990851.0, + "allocs/op": 235458.0 + } + }, + { + "sample": 6, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 118097846.0, + "avg_cpu_cores": 2.073, + "collection_p50-ms": 8.234, + "collection_p95-ms": 9.436, + "completion_parse_p50-ms": 3.897, + "completion_parse_p95-ms": 4.584, + "completion_sigverify_p50-ms": 80.46, + "completion_sigverify_p95-ms": 84.12, + "components/block": 691.0, + "cpu-ms/block": 244.8, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 2009.0, + "full_to_ready_p50-ms": 110.1, + "full_to_ready_p95-ms": 111.6, + "mean_width": 7.932, + "preparation_wait_p50-ms": 0.003857, + "preparation_wait_p95-ms": 0.005016, + "tx/block": 33760.0, + "B/op": 265493705.0, + "allocs/op": 236438.0 + } + }, + { + "sample": 6, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 318006733.0, + "avg_cpu_cores": 0.7756, + "collection_p50-ms": 201.6, + "collection_p95-ms": 201.9, + "completion_parse_p50-ms": 5.76, + "completion_parse_p95-ms": 6.369, + "completion_sigverify_p50-ms": 84.75, + "completion_sigverify_p95-ms": 86.11, + "components/block": 691.0, + "cpu-ms/block": 246.7, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 117.0, + "full_to_ready_p95-ms": 120.6, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260100320.0, + "allocs/op": 235463.0 + } + }, + { + "sample": 6, + "variant": "baseline", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 228423719.0, + "avg_cpu_cores": 1.21, + "collection_p50-ms": 201.1, + "collection_p95-ms": 201.6, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.02031, + "completion_sigverify_p50-ms": 0.1011, + "completion_sigverify_p95-ms": 0.5984, + "components/block": 691.0, + "cpu-ms/block": 276.4, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33731.0, + "full_to_ready_p50-ms": 25.52, + "full_to_ready_p95-ms": 30.97, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.129, + "preparation_wait_p95-ms": 0.1313, + "tx/block": 33760.0, + "B/op": 307480184.0, + "allocs/op": 250043.0 + } + }, + { + "sample": 6, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 84167116.0, + "avg_cpu_cores": 1.988, + "collection_p50-ms": 1.144, + "collection_p95-ms": 1.232, + "completion_parse_p50-ms": 3.413, + "completion_parse_p95-ms": 4.888, + "completion_sigverify_p50-ms": 76.76, + "completion_sigverify_p95-ms": 78.17, + "components/block": 128.0, + "cpu-ms/block": 167.3, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 82.76, + "full_to_ready_p95-ms": 84.18, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 32288243.0, + "allocs/op": 207233.0 + } + }, + { + "sample": 6, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 82857969.0, + "avg_cpu_cores": 2.043, + "collection_p50-ms": 1.523, + "collection_p95-ms": 1.63, + "completion_parse_p50-ms": 3.449, + "completion_parse_p95-ms": 5.611, + "completion_sigverify_p50-ms": 74.33, + "completion_sigverify_p95-ms": 75.86, + "components/block": 128.0, + "cpu-ms/block": 169.3, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 215.2, + "full_to_ready_p50-ms": 81.41, + "full_to_ready_p95-ms": 83.26, + "mean_width": 7.997, + "preparation_wait_p50-ms": 0.000922, + "preparation_wait_p95-ms": 0.07145, + "tx/block": 33760.0, + "B/op": 34911190.0, + "allocs/op": 207376.0 + } + }, + { + "sample": 6, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 290467977.0, + "avg_cpu_cores": 0.6306, + "collection_p50-ms": 200.7, + "collection_p95-ms": 201.2, + "completion_parse_p50-ms": 3.626, + "completion_parse_p95-ms": 5.792, + "completion_sigverify_p50-ms": 82.06, + "completion_sigverify_p95-ms": 91.61, + "components/block": 128.0, + "cpu-ms/block": 183.2, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 91.79, + "full_to_ready_p95-ms": 98.0, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 32205832.0, + "allocs/op": 207229.0 + } + }, + { + "sample": 6, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 203268498.0, + "avg_cpu_cores": 0.8573, + "collection_p50-ms": 200.9, + "collection_p95-ms": 201.0, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.01763, + "completion_sigverify_p95-ms": 0.02967, + "components/block": 128.0, + "cpu-ms/block": 174.3, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 2.37, + "full_to_ready_p95-ms": 2.511, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.01763, + "preparation_wait_p95-ms": 0.02097, + "tx/block": 33760.0, + "B/op": 33202425.0, + "allocs/op": 210058.0 + } + }, + { + "sample": 6, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 113739331.0, + "avg_cpu_cores": 1.899, + "collection_p50-ms": 6.908, + "collection_p95-ms": 8.387, + "completion_parse_p50-ms": 3.847, + "completion_parse_p95-ms": 5.097, + "completion_sigverify_p50-ms": 89.13, + "completion_sigverify_p95-ms": 91.48, + "components/block": 691.0, + "cpu-ms/block": 216.0, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 106.6, + "full_to_ready_p95-ms": 111.0, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 112042899.0, + "allocs/op": 227183.0 + } + }, + { + "sample": 6, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 110309323.0, + "avg_cpu_cores": 2.0, + "collection_p50-ms": 9.223, + "collection_p95-ms": 9.799, + "completion_parse_p50-ms": 3.51, + "completion_parse_p95-ms": 4.88, + "completion_sigverify_p50-ms": 80.54, + "completion_sigverify_p95-ms": 90.01, + "components/block": 691.0, + "cpu-ms/block": 220.6, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 2078.0, + "full_to_ready_p50-ms": 99.7, + "full_to_ready_p95-ms": 109.9, + "mean_width": 7.929, + "preparation_wait_p50-ms": 0.003385, + "preparation_wait_p95-ms": 0.006176, + "tx/block": 33760.0, + "B/op": 114532560.0, + "allocs/op": 228120.0 + } + }, + { + "sample": 6, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8", + "iterations": 5, + "metrics": { + "ns/op": 302321983.0, + "avg_cpu_cores": 0.6997, + "collection_p50-ms": 201.0, + "collection_p95-ms": 201.5, + "completion_parse_p50-ms": 3.91, + "completion_parse_p95-ms": 4.54, + "completion_sigverify_p50-ms": 83.33, + "completion_sigverify_p95-ms": 85.29, + "components/block": 691.0, + "cpu-ms/block": 211.5, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 101.1, + "full_to_ready_p95-ms": 105.9, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 112070532.0, + "allocs/op": 227185.0 + } + }, + { + "sample": 6, + "variant": "candidate", + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8", + "iterations": 5, + "metrics": { + "ns/op": 212242945.0, + "avg_cpu_cores": 1.089, + "collection_p50-ms": 200.8, + "collection_p95-ms": 201.3, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.01212, + "completion_sigverify_p50-ms": 0.09627, + "completion_sigverify_p95-ms": 0.3047, + "components/block": 691.0, + "cpu-ms/block": 231.2, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33750.0, + "full_to_ready_p50-ms": 11.24, + "full_to_ready_p95-ms": 11.41, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.101, + "preparation_wait_p95-ms": 0.1062, + "tx/block": 33760.0, + "B/op": 114276446.0, + "allocs/op": 241076.0 + } + } + ], + "summary": [ + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8", + "medians": { + "baseline": { + "ns/op": 122594527.0, + "avg_cpu_cores": 1.959, + "collection_p50-ms": 6.465, + "collection_p95-ms": 7.1345, + "completion_parse_p50-ms": 4.574, + "completion_parse_p95-ms": 5.255, + "completion_sigverify_p50-ms": 84.08, + "completion_sigverify_p95-ms": 86.08500000000001, + "components/block": 691.0, + "cpu-ms/block": 239.60000000000002, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 115.0, + "full_to_ready_p95-ms": 123.5, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260018538.0, + "allocs/op": 235460.5 + }, + "candidate": { + "ns/op": 109941733.0, + "avg_cpu_cores": 1.8975, + "collection_p50-ms": 6.663, + "collection_p95-ms": 7.3915, + "completion_parse_p50-ms": 3.6959999999999997, + "completion_parse_p95-ms": 4.961, + "completion_sigverify_p50-ms": 85.30000000000001, + "completion_sigverify_p95-ms": 88.43, + "components/block": 691.0, + "cpu-ms/block": 207.95, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 103.0, + "full_to_ready_p95-ms": 107.2, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 111946584.5, + "allocs/op": 227176.5 + } + }, + "paired_ratios": { + "ns/op": [ + 0.9157606016480484, + 0.8983480572855805, + 0.8958732493445192, + 0.8175978972511556, + 0.9385651395673379, + 0.902798816616987 + ], + "cpu-ms/block": [ + 0.8804898648648648, + 0.8708174502329521, + 0.8779661016949152, + 0.8073180225768782, + 0.9084158415841583, + 0.8755573571139036 + ], + "B/op": [ + 0.4304801173811123, + 0.43037553602809353, + 0.43090328157222957, + 0.43032986118695243, + 0.43044963541099457, + 0.43094939136916016 + ], + "full_to_ready_p50-ms": [ + 0.9276139410187667, + 0.9125, + 0.9140555058191584, + 0.8181089743589743, + 0.920875420875421, + 0.9033898305084745 + ] + } + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8", + "medians": { + "baseline": { + "ns/op": 118471106.0, + "avg_cpu_cores": 2.0755, + "collection_p50-ms": 8.404499999999999, + "collection_p95-ms": 9.3885, + "completion_parse_p50-ms": 4.0495, + "completion_parse_p95-ms": 4.7925, + "completion_sigverify_p50-ms": 80.41999999999999, + "completion_sigverify_p95-ms": 83.13499999999999, + "components/block": 691.0, + "cpu-ms/block": 246.14999999999998, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 1940.5, + "full_to_ready_p50-ms": 109.94999999999999, + "full_to_ready_p95-ms": 112.75, + "mean_width": 7.933999999999999, + "preparation_wait_p50-ms": 0.0044215, + "preparation_wait_p95-ms": 0.0055785, + "tx/block": 33760.0, + "B/op": 265467053.0, + "allocs/op": 236415.0 + }, + "candidate": { + "ns/op": 108861585.5, + "avg_cpu_cores": 1.9975, + "collection_p50-ms": 9.1395, + "collection_p95-ms": 9.703, + "completion_parse_p50-ms": 3.7205, + "completion_parse_p95-ms": 4.669499999999999, + "completion_sigverify_p50-ms": 80.625, + "completion_sigverify_p95-ms": 87.02000000000001, + "components/block": 691.0, + "cpu-ms/block": 218.2, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 2028.5, + "full_to_ready_p50-ms": 98.225, + "full_to_ready_p95-ms": 107.30000000000001, + "mean_width": 7.931, + "preparation_wait_p50-ms": 0.003487, + "preparation_wait_p95-ms": 0.0061805, + "tx/block": 33760.0, + "B/op": 114427432.5, + "allocs/op": 228099.5 + } + }, + "paired_ratios": { + "ns/op": [ + 0.8821061499566317, + 0.9632092875139537, + 0.8920642090832533, + 0.8961627067766412, + 0.9663841422814191, + 0.934050253549925 + ], + "cpu-ms/block": [ + 0.8594185583432896, + 0.9459234608985025, + 0.8543451652386781, + 0.8632686084142396, + 0.9160274525635851, + 0.9011437908496731 + ], + "B/op": [ + 0.4305651299904384, + 0.43098028878633016, + 0.4311480628525499, + 0.43153875434357863, + 0.4308293102489762, + 0.431394635138336 + ], + "full_to_ready_p50-ms": [ + 0.8464566929133859, + 0.948087431693989, + 0.8810835629017447, + 0.8814102564102564, + 0.942883046237534, + 0.9055404178019982 + ] + } + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8", + "medians": { + "baseline": { + "ns/op": 319117819.0, + "avg_cpu_cores": 0.7849999999999999, + "collection_p50-ms": 201.3, + "collection_p95-ms": 201.85000000000002, + "completion_parse_p50-ms": 4.577500000000001, + "completion_parse_p95-ms": 5.101, + "completion_sigverify_p50-ms": 85.505, + "completion_sigverify_p95-ms": 92.265, + "components/block": 691.0, + "cpu-ms/block": 250.5, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 117.25, + "full_to_ready_p95-ms": 123.05000000000001, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 260100833.5, + "allocs/op": 235465.0 + }, + "candidate": { + "ns/op": 306414200.0, + "avg_cpu_cores": 0.7164, + "collection_p50-ms": 201.3, + "collection_p95-ms": 201.6, + "completion_parse_p50-ms": 4.0954999999999995, + "completion_parse_p95-ms": 4.7075, + "completion_sigverify_p50-ms": 85.18, + "completion_sigverify_p95-ms": 91.97, + "components/block": 691.0, + "cpu-ms/block": 219.55, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 103.85, + "full_to_ready_p95-ms": 111.5, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 112084236.0, + "allocs/op": 227185.0 + } + }, + "paired_ratios": { + "ns/op": [ + 0.9398181596682805, + 0.9517653835331482, + 0.979241740522063, + 0.9845051486926455, + 0.9427394030426424, + 0.9506779310864465 + ], + "cpu-ms/block": [ + 0.820443062572872, + 0.8478175383405426, + 0.9232026143790849, + 0.9296875, + 0.8456299659477866, + 0.8573165788406972 + ], + "B/op": [ + 0.4309787563629935, + 0.43124985915617925, + 0.4306612852303245, + 0.4305710166725875, + 0.4310845754469543, + 0.43087425651763905 + ], + "full_to_ready_p50-ms": [ + 0.8635593220338984, + 0.8723404255319149, + 0.9175965665236052, + 0.9131944444444444, + 0.8530101641907739, + 0.864102564102564 + ] + } + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8", + "medians": { + "baseline": { + "ns/op": 228250477.5, + "avg_cpu_cores": 1.194, + "collection_p50-ms": 201.0, + "collection_p95-ms": 201.5, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.008445, + "completion_sigverify_p50-ms": 0.10830000000000001, + "completion_sigverify_p95-ms": 0.23864999999999997, + "components/block": 691.0, + "cpu-ms/block": 273.20000000000005, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33755.0, + "full_to_ready_p50-ms": 25.71, + "full_to_ready_p95-ms": 31.060000000000002, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.1265, + "preparation_wait_p95-ms": 0.1313, + "tx/block": 33760.0, + "B/op": 307487420.0, + "allocs/op": 250062.5 + }, + "candidate": { + "ns/op": 212793283.0, + "avg_cpu_cores": 1.1125, + "collection_p50-ms": 200.95, + "collection_p95-ms": 201.45, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.012975, + "completion_sigverify_p50-ms": 0.10655, + "completion_sigverify_p95-ms": 0.3325, + "components/block": 691.0, + "cpu-ms/block": 236.8, + "data_shreds/block": 44160.0, + "early_verified_tx/block": 33745.5, + "full_to_ready_p50-ms": 11.435, + "full_to_ready_p95-ms": 12.655, + "mean_width": 7.001, + "preparation_wait_p50-ms": 0.10545, + "preparation_wait_p95-ms": 0.1123, + "tx/block": 33760.0, + "B/op": 114248747.5, + "allocs/op": 241061.5 + } + }, + "paired_ratios": { + "ns/op": [ + 0.9400183145773918, + 0.9304854255599625, + 0.9370596252848155, + 0.9251756487759943, + 0.9278233327936518, + 0.9291633370175537 + ], + "cpu-ms/block": [ + 1.0507407407407408, + 0.852264291017075, + 0.8925680647534951, + 0.8578698655034532, + 0.8652585579024034, + 0.8364688856729378 + ], + "B/op": [ + 0.371315674805637, + 0.371751339469171, + 0.3715517807242803, + 0.37134226522721586, + 0.37090241933553086, + 0.3716546689720987 + ], + "full_to_ready_p50-ms": [ + 0.5033636723387416, + 0.42591876208897483, + 0.456394211967149, + 0.39505300353356887, + 0.4096512856639662, + 0.44043887147335425 + ] + } + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8", + "medians": { + "baseline": { + "ns/op": 86284007.0, + "avg_cpu_cores": 1.9915, + "collection_p50-ms": 1.131, + "collection_p95-ms": 1.3054999999999999, + "completion_parse_p50-ms": 4.2045, + "completion_parse_p95-ms": 4.5120000000000005, + "completion_sigverify_p50-ms": 75.965, + "completion_sigverify_p95-ms": 76.995, + "components/block": 128.0, + "cpu-ms/block": 171.45, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 85.295, + "full_to_ready_p95-ms": 87.33500000000001, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 59262017.5, + "allocs/op": 208746.0 + }, + "candidate": { + "ns/op": 84634300.5, + "avg_cpu_cores": 1.9945, + "collection_p50-ms": 1.161, + "collection_p95-ms": 1.2785, + "completion_parse_p50-ms": 3.3979999999999997, + "completion_parse_p95-ms": 4.7515, + "completion_sigverify_p50-ms": 77.17500000000001, + "completion_sigverify_p95-ms": 78.605, + "components/block": 128.0, + "cpu-ms/block": 168.55, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 83.355, + "full_to_ready_p95-ms": 85.155, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 32247037.0, + "allocs/op": 207231.0 + } + }, + "paired_ratios": { + "ns/op": [ + 0.9746922616368424, + 0.9951789090799403, + 0.9926956952263228, + 0.9777527841466942, + 1.0031666961884662, + 0.9638762929062183 + ], + "cpu-ms/block": [ + 0.9776207302709069, + 0.9942163100057837, + 0.992982456140351, + 0.9777777777777777, + 1.011634671320535, + 0.9620471535365153 + ], + "B/op": [ + 0.5426052293108848, + 0.543362814763171, + 0.544037264384435, + 0.5439978034258355, + 0.5456395572515589, + 0.5462334368408132 + ], + "full_to_ready_p50-ms": [ + 0.9666627260905544, + 0.9811827956989247, + 0.9894155004116194, + 0.9733003999059046, + 1.0008119707690524, + 0.9588691924458348 + ] + } + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8", + "medians": { + "baseline": { + "ns/op": 87248672.0, + "avg_cpu_cores": 2.043, + "collection_p50-ms": 1.608, + "collection_p95-ms": 1.7635, + "completion_parse_p50-ms": 3.8935, + "completion_parse_p95-ms": 4.551, + "completion_sigverify_p50-ms": 76.625, + "completion_sigverify_p95-ms": 80.185, + "components/block": 128.0, + "cpu-ms/block": 177.95, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 134.5, + "full_to_ready_p50-ms": 86.005, + "full_to_ready_p95-ms": 89.575, + "mean_width": 7.9965, + "preparation_wait_p50-ms": 0.000796, + "preparation_wait_p95-ms": 0.022195999999999997, + "tx/block": 33760.0, + "B/op": 61994718.5, + "allocs/op": 208907.0 + }, + "candidate": { + "ns/op": 82776496.5, + "avg_cpu_cores": 2.0505, + "collection_p50-ms": 1.5775000000000001, + "collection_p95-ms": 1.7285, + "completion_parse_p50-ms": 3.5694999999999997, + "completion_parse_p95-ms": 4.5815, + "completion_sigverify_p50-ms": 74.05, + "completion_sigverify_p95-ms": 77.295, + "components/block": 128.0, + "cpu-ms/block": 169.2, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 107.6, + "full_to_ready_p50-ms": 80.97999999999999, + "full_to_ready_p95-ms": 83.73, + "mean_width": 7.996, + "preparation_wait_p50-ms": 0.000912, + "preparation_wait_p95-ms": 0.4726, + "tx/block": 33760.0, + "B/op": 34792762.0, + "allocs/op": 207390.0 + } + }, + "paired_ratios": { + "ns/op": [ + 1.0017513290145441, + 0.9453831442147634, + 0.8998773191728862, + 0.9890803420162109, + 0.9263731670193178, + 0.9405173998621812 + ], + "cpu-ms/block": [ + 0.9917888563049853, + 0.9562996594778661, + 0.9007352941176471, + 0.9877336448598131, + 0.9385749385749386, + 0.9421257651641626 + ], + "B/op": [ + 0.5594570429623663, + 0.5588242475689451, + 0.5616061781129013, + 0.5607965311540477, + 0.5608448552296642, + 0.5639668909248479 + ], + "full_to_ready_p50-ms": [ + 0.9914930341511528, + 0.9362554495110167, + 0.895277656318321, + 0.9850801027271615, + 0.8954137587238286, + 0.9342437456965802 + ] + } + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8", + "medians": { + "baseline": { + "ns/op": 286103124.0, + "avg_cpu_cores": 0.60885, + "collection_p50-ms": 200.85000000000002, + "collection_p95-ms": 201.05, + "completion_parse_p50-ms": 3.5839999999999996, + "completion_parse_p95-ms": 4.243, + "completion_sigverify_p50-ms": 76.47, + "completion_sigverify_p95-ms": 78.07499999999999, + "components/block": 128.0, + "cpu-ms/block": 174.2, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 85.42, + "full_to_ready_p95-ms": 86.235, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 59261713.5, + "allocs/op": 208744.5 + }, + "candidate": { + "ns/op": 284508953.5, + "avg_cpu_cores": 0.59975, + "collection_p50-ms": 200.8, + "collection_p95-ms": 201.05, + "completion_parse_p50-ms": 3.642, + "completion_parse_p95-ms": 4.34, + "completion_sigverify_p50-ms": 76.015, + "completion_sigverify_p95-ms": 78.86500000000001, + "components/block": 128.0, + "cpu-ms/block": 170.75, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 0.0, + "full_to_ready_p50-ms": 83.565, + "full_to_ready_p95-ms": 86.255, + "mean_width": 8.0, + "preparation_wait_p50-ms": 0.0, + "preparation_wait_p95-ms": 0.0, + "tx/block": 33760.0, + "B/op": 32246849.5, + "allocs/op": 207230.5 + } + }, + "paired_ratios": { + "ns/op": [ + 0.9937660087088263, + 0.9599000052041363, + 0.9945451045909277, + 0.9957213421590944, + 0.9962654638553642, + 1.0154857889278281 + ], + "cpu-ms/block": [ + 0.9760932944606414, + 0.8787245164662832, + 0.9780600461893766, + 0.9823059360730594, + 0.9896848137535816, + 1.0534790109258194 + ], + "B/op": [ + 0.5422762671117071, + 0.5459361007437157, + 0.5439949351797095, + 0.5447114222584726, + 0.5440807130463787, + 0.5435762541915306 + ], + "full_to_ready_p50-ms": [ + 0.9793605344786448, + 0.8553244334057747, + 0.9892713982551286, + 0.9740168539325843, + 0.9922716627634659, + 1.0731906933239799 + ] + } + }, + { + "name": "BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8", + "medians": { + "baseline": { + "ns/op": 207240378.0, + "avg_cpu_cores": 0.8925000000000001, + "collection_p50-ms": 200.7, + "collection_p95-ms": 201.1, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.018265, + "completion_sigverify_p95-ms": 0.02266, + "components/block": 128.0, + "cpu-ms/block": 184.95, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 5.6995000000000005, + "full_to_ready_p95-ms": 10.009, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.02256, + "preparation_wait_p95-ms": 0.02418, + "tx/block": 33760.0, + "B/op": 68208508.5, + "allocs/op": 211687.0 + }, + "candidate": { + "ns/op": 203113946.0, + "avg_cpu_cores": 0.86705, + "collection_p50-ms": 200.8, + "collection_p95-ms": 201.0, + "completion_parse_p50-ms": 0.0, + "completion_parse_p95-ms": 0.0, + "completion_sigverify_p50-ms": 0.016695, + "completion_sigverify_p95-ms": 0.023855, + "components/block": 128.0, + "cpu-ms/block": 176.10000000000002, + "data_shreds/block": 8128.0, + "early_verified_tx/block": 33760.0, + "full_to_ready_p50-ms": 2.2874999999999996, + "full_to_ready_p95-ms": 2.4505, + "mean_width": 7.912, + "preparation_wait_p50-ms": 0.017895, + "preparation_wait_p95-ms": 0.019264999999999997, + "tx/block": 33760.0, + "B/op": 33092654.0, + "allocs/op": 210058.0 + } + }, + "paired_ratios": { + "ns/op": [ + 0.979626446397073, + 0.9800711976642443, + 0.9805513776165456, + 0.9784646516152438, + 0.9773330692247688, + 0.9823734076227761 + ], + "cpu-ms/block": [ + 0.9459167117360735, + 0.9769357495881384, + 0.9367567567567568, + 0.987481945113144, + 0.9461045891141943, + 0.9503816793893131 + ], + "B/op": [ + 0.48566852069517175, + 0.48334060770190196, + 0.4852564256254716, + 0.4840454233959285, + 0.48688530140559333, + 0.48667443471323013 + ], + "full_to_ready_p50-ms": [ + 0.3992779783393502, + 0.4153676875114616, + 0.4205969049373618, + 0.3519091847265222, + 0.3030944194657498, + 0.40450588837685614 + ] + } + } + ] +} diff --git a/docs/transaction_sigverify_streaming.md b/docs/transaction_sigverify_streaming.md index 84d499b3..edd3629b 100644 --- a/docs/transaction_sigverify_streaming.md +++ b/docs/transaction_sigverify_streaming.md @@ -17,10 +17,12 @@ and repair catch-up without a mode transition or a 200 ms batching delay. 3. Signature groups contain available transactions up to the configured lane target. Transactions with multiple signatures remain indivisible. A rolling per-request window refills when any group finishes, without a wave barrier. -4. Once the full slot is assembled, completion rechecks exact batch bytes, - processes all Alpenglow markers and FEC roots, and constructs the final ordered - block. It submits any transactions not already covered and joins signature - work for the retained batches before marking the block verified. +4. Once the full slot is assembled, completion compares shred slices directly + against the cached component bytes, including padding. Cache hits avoid a + second component buffer; misses allocate a fresh buffer at its exact size. + Completion processes all Alpenglow markers and FEC roots and constructs the + final ordered block. It submits any transactions not already covered and joins + signature work for the retained batches before marking the block verified. 5. The existing replay pipeline receives the verified block. This change does not execute transactions before full-slot admission, alter execution batching, or move parent-dependent validation ahead of its required state. @@ -97,3 +99,5 @@ throughput alone is insufficient evidence of end-to-end replay improvement. Measured Zen 5 results, raw logs, and validation details are in the [September 12 benchmark report](results/sigverify-streaming/2026-09-12-zen5/README.md). +The subsequent [direct cache-comparison report](results/sigverify-direct-cache/2026-09-12-zen5/README.md) +isolates the removal of redundant component-buffer construction at completion. diff --git a/pkg/turbine/entries.go b/pkg/turbine/entries.go index 333eb23a..b4657ce1 100644 --- a/pkg/turbine/entries.go +++ b/pkg/turbine/entries.go @@ -135,21 +135,23 @@ func decodeEntriesAndAlpenglowMarkersFromDataShreds(shreds []*Shred, timings *en var entryBatches []*prefetchedShredBatch var parentInfo *AlpenglowParentInfo var blockFooter *BlockFooter - var batchBytes []byte var batchStart uint32 + var batchStartPos, batchSize int var haveBatch bool - for _, shred := range shreds { + for shredPos, shred := range shreds { if shred == nil || shred.Type != ShredTypeData { continue } if !haveBatch { batchStart = shred.Index + batchStartPos = shredPos haveBatch = true } - batchBytes = append(batchBytes, shred.Data...) + batchSize += len(shred.Data) if !shred.DataComplete() { continue } + batchShreds := shreds[batchStartPos : shredPos+1] var batch *prefetchedShredBatch if timings != nil { if cached := timings.prefetched[batchStart]; cached != nil && cached.start == batchStart && cached.end == shred.Index { @@ -172,12 +174,22 @@ func decodeEntriesAndAlpenglowMarkersFromDataShreds(shreds []*Shred, timings *en } // Bounds alone cannot prove identity after repair or replacement. // Read decoded fields only after the preparation channel closes. - if bytes.Equal(batchBytes, cached.raw) { + // Compare the original slices directly: a cache hit needs no + // second component buffer or copies of already decoded bytes. + if len(cached.raw) == batchSize && dataShredBatchMatches(batchShreds, cached.raw) { batch = cached } } } if batch == nil { + // A miss owns a fresh, exactly sized backing array. Transactions + // retain instruction-data slices into it after this call returns. + batchBytes := make([]byte, 0, batchSize) + for _, part := range batchShreds { + if part != nil && part.Type == ShredTypeData { + batchBytes = append(batchBytes, part.Data...) + } + } batch = decodeClosedShredBatch(batchBytes, batchStart, shred.Index) if timings != nil { timings.transactionParse += batch.parseDuration @@ -200,18 +212,16 @@ func decodeEntriesAndAlpenglowMarkersFromDataShreds(shreds []*Shred, timings *en if batch.footer != nil { blockFooter = batch.footer } - batchBytes = nil + batchSize = 0 haveBatch = false continue } entryBatches = append(entryBatches, batch) - // Decoded transactions retain slices into the batch buffer for instruction data. - // Keep the backing array alive instead of reusing and overwriting it. - batchBytes = nil + batchSize = 0 haveBatch = false } - if len(batchBytes) != 0 { - return nil, nil, nil, fmt.Errorf("slot ended with %d undecoded entry bytes", len(batchBytes)) + if batchSize != 0 { + return nil, nil, nil, fmt.Errorf("slot ended with %d undecoded entry bytes", batchSize) } var entries []Entry for _, batch := range entryBatches { @@ -231,6 +241,23 @@ func decodeEntriesAndAlpenglowMarkersFromDataShreds(shreds []*Shred, timings *en return entries, parentInfo, blockFooter, nil } +// dataShredBatchMatches is equivalent to comparing raw with the concatenated +// data bytes, including all padding. Neither equal prefixes nor changed lengths +// can reuse a cached signature verdict. It does not retain or allocate buffers. +func dataShredBatchMatches(shreds []*Shred, raw []byte) bool { + offset := 0 + for _, shred := range shreds { + if shred == nil || shred.Type != ShredTypeData { + continue + } + if len(shred.Data) > len(raw)-offset || !bytes.Equal(shred.Data, raw[offset:offset+len(shred.Data)]) { + return false + } + offset += len(shred.Data) + } + return offset == len(raw) +} + // decodeClosedShredBatch owns raw through the returned decoded transactions. // It decodes the same padded component envelope for early and full assembly; // marker merging and UpdateParent selection still require the full slot. diff --git a/pkg/turbine/entries_direct_compare_test.go b/pkg/turbine/entries_direct_compare_test.go new file mode 100644 index 00000000..4fb55637 --- /dev/null +++ b/pkg/turbine/entries_direct_compare_test.go @@ -0,0 +1,100 @@ +package turbine + +import ( + "bytes" + "context" + "testing" + + "github.com/gagliardetto/solana-go" + "github.com/stretchr/testify/require" +) + +func TestDataShredBatchMatchesChecksLengthsAndEverySlice(t *testing.T) { + raw := []byte("0123456789abcdefghijklmnopqrstuvwxyz") + shreds := []*Shred{ + {Type: ShredTypeData, Data: raw[:10]}, + nil, + {Type: ShredTypeCode, Data: []byte("coding bytes are not component data")}, + {Type: ShredTypeData}, + {Type: ShredTypeData, Data: raw[10:20]}, + {Type: ShredTypeData, Data: raw[20:]}, + } + require.True(t, dataShredBatchMatches(shreds, bytes.Clone(raw))) + for i := range raw { + changed := bytes.Clone(raw) + changed[i] ^= 1 + require.False(t, dataShredBatchMatches(shreds, changed), "changed byte %d", i) + } + for i := 0; i < len(raw); i++ { + require.False(t, dataShredBatchMatches(shreds, raw[:i]), "truncated at %d", i) + } + require.False(t, dataShredBatchMatches(shreds, append(bytes.Clone(raw), 0))) + require.True(t, dataShredBatchMatches(nil, nil)) + require.False(t, dataShredBatchMatches(nil, raw)) +} + +func TestEntryDecodeDirectComparisonCannotReuseChangedSignatureVerdict(t *testing.T) { + v := newTransactionVerifier(2, 16, nil) + defer v.closeAndWait() + txs := verifierSignedTransactions(t, 1) + raw := prefetchTestPayload(t, txs) + cache := decodedPrefetchForTest(paddedComponentShreds(t, raw, 0, 0xa5)) + cached := cache[0] + var err error + cached.verification, err = v.submitTransactions(context.Background(), entryBatchTransactions(cached.entries)) + require.NoError(t, err) + _, err = cached.verification.wait() + require.NoError(t, err) + + bad := *txs[0] + bad.Signatures = append([]solana.Signature(nil), bad.Signatures...) + bad.Signatures[0][0] ^= 1 + changed := prefetchTestPayload(t, []*solana.Transaction{&bad}) + require.Len(t, changed, len(raw)) + timings := entryDecodeTimings{prefetched: cache} + entries, _, _, err := decodeEntriesAndAlpenglowMarkersFromDataShreds(paddedComponentShreds(t, changed, 0, 0xa5), &timings) + require.NoError(t, err) + require.Len(t, timings.retained, 1) + require.NotSame(t, cached, timings.retained[0]) + require.Nil(t, timings.retained[0].verification) + blk := BlockFromEntries(100, 99, entries) + require.Equal(t, bad.Signatures[0], blk.Transactions[0].Signatures[0]) + require.ErrorContains(t, verifyDecodedEntryBatches(context.Background(), blk, timings.retained, v), "failed signature verification") + require.False(t, blk.TransactionSignaturesVerified()) +} + +func TestEntryDecodeDirectComparisonRejectsChangedCachedLength(t *testing.T) { + raw := prefetchTestPayload(t, verifierSignedTransactions(t, 1)) + for _, delta := range []int{-1, 1} { + shreds := paddedComponentShreds(t, raw, 0, 0xa5) + cache := decodedPrefetchForTest(shreds) + cached := cache[0] + if delta < 0 { + cached.raw = cached.raw[:len(cached.raw)-1] + } else { + cached.raw = append(cached.raw, 0) + } + timings := entryDecodeTimings{prefetched: cache} + entries, _, _, err := decodeEntriesAndAlpenglowMarkersFromDataShreds(shreds, &timings) + require.NoError(t, err) + require.Len(t, entries, 1) + require.NotSame(t, cached, timings.retained[0]) + } +} + +func FuzzDataShredBatchMatchesConcatenatedBytes(f *testing.F) { + f.Add([]byte("a component spanning several shreds"), []byte("a component spanning several shreds"), uint8(3)) + f.Add([]byte("truncated"), []byte("truncate"), uint8(1)) + f.Add([]byte{}, []byte{}, uint8(0)) + f.Fuzz(func(t *testing.T, data, candidate []byte, split uint8) { + if len(data) > 64*1024 || len(candidate) > 64*1024 { + t.Skip() + } + shreds := []*Shred{nil, {Type: ShredTypeCode, Data: []byte{1, 2, 3}}} + width := int(split) + 1 + for start := 0; start < len(data); start += width { + shreds = append(shreds, &Shred{Type: ShredTypeData, Data: data[start:min(start+width, len(data))]}) + } + require.Equal(t, bytes.Equal(data, candidate), dataShredBatchMatches(shreds, candidate)) + }) +} From 9265ee9db9b793080a95a8f9fbc6ed2c63d8318d Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Sat, 12 Sep 2026 22:33:00 -0500 Subject: [PATCH 005/183] Reduce completion ordering and root work; bundle ready verification groups --- .../2026-09-12-zen5/README.md | 195 +++ .../baseline-root-adapter.go.txt | 7 + .../2026-09-12-zen5/raw-results.tar.gz | Bin 0 -> 53842 bytes .../2026-09-12-zen5/summarize.py | 59 + .../2026-09-12-zen5/summary.json | 1430 +++++++++++++++++ docs/transaction_sigverify_streaming.md | 23 +- pkg/turbine/assembler.go | 81 +- pkg/turbine/completion_order_root_test.go | 228 +++ pkg/turbine/entries.go | 5 + pkg/turbine/entry_prefetch_benchmark_test.go | 22 +- pkg/turbine/fec_root_cache.go | 56 + pkg/turbine/receiver.go | 7 +- pkg/turbine/sigcache.go | 17 +- pkg/turbine/transaction_job_groups_test.go | 118 ++ pkg/turbine/transaction_verifier.go | 71 +- pkg/turbine/transaction_verifier_test.go | 42 +- 16 files changed, 2285 insertions(+), 76 deletions(-) create mode 100644 docs/results/completion-followup/2026-09-12-zen5/README.md create mode 100644 docs/results/completion-followup/2026-09-12-zen5/baseline-root-adapter.go.txt create mode 100644 docs/results/completion-followup/2026-09-12-zen5/raw-results.tar.gz create mode 100644 docs/results/completion-followup/2026-09-12-zen5/summarize.py create mode 100644 docs/results/completion-followup/2026-09-12-zen5/summary.json create mode 100644 pkg/turbine/completion_order_root_test.go create mode 100644 pkg/turbine/fec_root_cache.go create mode 100644 pkg/turbine/transaction_job_groups_test.go diff --git a/docs/results/completion-followup/2026-09-12-zen5/README.md b/docs/results/completion-followup/2026-09-12-zen5/README.md new file mode 100644 index 00000000..1fb87113 --- /dev/null +++ b/docs/results/completion-followup/2026-09-12-zen5/README.md @@ -0,0 +1,195 @@ +# Shred ordering, authenticated roots, and larger verification jobs + +For 33,760 maximum-size transactions arriving over 200 ms, the final-shred-to-ready +tail fell from **11.24 to 6.44 ms**, a **42.7% reduction**. Catch-up assembly with +overlap enabled improved from **105.36 to 99.75 ms**. These measurements compare +against `e063695f5b22a68990007c99c7dc7b64eef5568e`, which already contains streaming +verification and direct shred-to-cache byte comparison. This is not an +`alpenglow-dev` or whole-validator replay comparison. + +## Changes + +- Complete contiguous slots walk shred indexes directly. The decoder accepts + that order without sorting again; sparse or extra-tail input retains a sorted + fallback that includes every shred. +- The receiver passes the root it authenticated into assembly. Each FEC state + retains at most one selected source snapshot. Completion reuses that root only + if the source, parsed root inputs, and every payload byte still match. It keeps + the previous lowest-data-index / lowest-coding-position selection and error + behavior. Root selection avoids sorting, and relative data index zero avoids + a map scan. Repair, reset, and missing-hint paths retain root computation. +- Large ready signature requests dispatch four vector groups per job, normally + 32 one-signature transactions. Narya still processes eight-wide groups. With + two workers and target eight, requests below 128 ready transactions retain one + group per job. There is no timer or wait for more transactions. A request owns + at most two outstanding jobs under the tested configuration. Cancellation + joins admitted work and can stop between vector groups in a larger job. + +## Method and scope + +- Ryzen 7 9700X, eight physical cores / sixteen hardware threads; Go 1.26.4, + Narya `r51` at `c265ee9667131a556cd332c252b79de0860c7640`. +- `GOMAXPROCS=8`, affinity CPUs 0–7 (distinct physical cores), nice 10. Mithril + and Lightbringer continued running; the validator binary and PID were unchanged. +- Both generated fixtures contain 33,760 distinct valid one-signature + transactions, exactly 228 or 1,232 wire bytes each. Complete component bursts + span 200 ms at the synthetic tip. Catch-up offers all shreds immediately. + Components use a 60 KiB transaction-byte budget, a benchmark choice rather + than a protocol requirement, with real entry overhead and FEC padding. +- The final comparison has six alternating baseline/candidate pairs, each with + five timed blocks per condition. Tables show medians of the six reported + values. Residual columns are medians of per-run p50s, not pooled percentiles. +- The assembly benchmark now supplies already-authenticated roots as the receiver + does. Both binaries use the same benchmark source; a test-only baseline adapter + ignores the roots and calls the old admission method. Root snapshot creation + is inside the timed candidate path. Authentication and fixture construction + remain outside timing on both sides. +- Timed work includes assembly, entry decoding, Merkle/block identity checks, + transaction signature verification, and publication. Packet parsing, shred + authentication, network loss/recovery, disk I/O, transaction execution, PoH, + and commit are excluded. This is not a recorded arrival trace. + +## Final assembly results + +Both sides below have overlap enabled and use two signature workers. CPU-ms +sums process CPU across cores, rather than single-thread wall time. MB means +decimal megabytes of total Go allocation volume (`B/op`), not peak heap. + +| Wire bytes/tx | Final-shred-to-ready | First-arrival-to-ready | CPU-ms/block | Allocated MB/block | +|---|---:|---:|---:|---:| +| 228 | 2.35 → **1.40 ms** | 203.13 → **202.30 ms** | 175.25 → 170.25 | 33.09 → 33.44 | +| 1,232 | 11.24 → **6.44 ms** | 212.58 → **207.64 ms** | 235.40 → 233.55 | 114.14 → 115.56 | + +Every maximum-size pair improved residual latency, by 40.8–44.3%. The whole +arrival-to-ready reduction is 2.3%, since the approximately 201 ms collection +period remains. Root snapshots add about 1.4 MB of allocation volume per large +block net of the removed ordering allocations; this change primarily reduces +the completion tail, rather than total tip CPU work. + +| Catch-up wire bytes/tx | Overlap | Total assembly baseline → final | +|---|---|---:| +| 228 | Off | 83.98 → **80.58 ms** | +| 228 | On | 81.77 → **79.35 ms** | +| 1,232 | Off | 108.87 → **102.78 ms** | +| 1,232 | On | 105.36 → **99.75 ms** | + +These catch-up cases supply authenticated roots, as fresh verified ingress can. +Spool hydration has no retained root hints. A separate three-pair, five-block +comparison exercised that fallback using the same final production code: + +| Catch-up wire bytes/tx | Overlap | No-hint baseline → final | +|---|---|---:| +| 228 | Off | 83.71 → **82.23 ms** | +| 228 | On | 81.80 → **80.67 ms** | +| 1,232 | Off | 108.08 → **104.34 ms** | +| 1,232 | On | 105.57 → **101.32 ms** | + +This models root-hint availability, not actual spool read performance. + +## Choosing the dispatch size + +Four rotated screening rounds compared ordering alone and nominal job sizes of +8, 32, and 64 signatures. Each condition had five timed blocks per round. These +intermediate variants predate the final direct FEC index-zero lookup; their +assembly times must not be substituted for the final comparison above. +The job-size table holds the new dispatcher code constant to isolate policy; +the final assembly comparison instead uses the prior production implementation. + +| Signature-only catch-up | 8 per job | 32 per job | 64 per job | +|---|---:|---:|---:| +| 228-byte transactions, wall time | 77.53 ms | **75.04 ms** | 73.78 ms | +| 1,232-byte transactions, wall time | 86.66 ms | **83.57 ms** | 83.20 ms | +| 228-byte transactions, CPU-ms | 157.60 | **151.35** | 148.30 | +| 1,232-byte transactions, CPU-ms | 181.60 | **174.45** | 173.55 | + +32-signature jobs save about 3–4% catch-up wall time in this pool test. Sparse +four-transaction arrivals still dispatch immediately; their observed p95 +availability-to-verdict remained approximately 1 ms, dominated by synthetic +feed scheduling. The 64 policy is somewhat faster in catch-up, but offers little +additional benefit for maximum-size transactions and doubles the work one job +can put ahead of another request. We selected 32 as the smaller useful policy; +the measurements do not establish that 64 is harmful. + +The real lean transfer load/execute probe also ran before and during signature +load on the same eight cores. It used captured block 2622581's 33,760 228-byte +transactions, two workers, and target eight: + +| Nominal signatures/job | Catch-up execution slowdown | Tip execution slowdown | +|---|---:|---:| +| 8 | +6.71% | +2.28% | +| **32** | **+6.64%** | **+3.35%** | +| 64 | +5.56% | +3.96% | + +These are medians of three paired slowdown ratios, not ratios of aggregate +times. For 32-signature jobs, tip pairs ranged from +2.38% to +4.40%; for eight, +from +0.81% to +4.16%. There is no clear large contention penalty from the wider +jobs in this test, but the small differences should not be overinterpreted. +The two workloads run in separate processes, excluding shared Go scheduler/heap +effects, dependency planning, commit, and full replay. + +The initial contention round overlapped an artifact download/compression and +was excluded in full. An additional complete round replaced it. All original +logs are retained; the table uses rounds 2, 3, and 4 consistently for every policy. + +## Remaining completion work + +A separate 30-block diagnostic profile of the final maximum-size candidate +averaged 6.42 ms after full assembly: + +| Completion stage | Mean ms/block | +|---|---:| +| Entry decoding and cache-byte validation | 4.30 | +| Construct ordered shred slice | 0.82 | +| Collect/check FEC roots | 0.67 | +| Construct block and footer metadata | 0.46 | + +The final signature join's median was 0.106 ms. The stage values are distinct +coarse timers; bookkeeping and the join account for the remainder. The earlier +current-baseline profile measured approximately 3.1 ms in the two ordering +steps and 3.5 ms in root collection. Exact byte validation now dominates the +remaining work. + +## Validation and reproduction + +Native Turbine, replay, and node tests, the full native Turbine race suite, and +native vet passed. The full local Turbine race suite and vet passed on the final +source. Local txverify/sigverify/node tests passed. The local replay suite hit +its existing `promotion_test.go:349` zero-duration assertion, also reproduced +in isolated repetition, then passed on full rerun. That test and production +replay code are unchanged from the baseline; no timing assertion was relaxed. + +New regressions cover sparse/extra-tail ordering, public unsorted decode parity, +every root-snapshot payload byte and parsed input, replacement/reset/duplicate +admission, recovered-data/coding precedence, multisignature groups, failure +index attribution, bounded yielding, and cancellation ownership. The final +root-selector fuzz run passed 64,721 executions against the original sorted +algorithm, including unsupported types; an earlier screening run passed 128,732. +Every timed assembly asserts transaction coverage, exactly one verification per +retained signature, expected block identity/footer metadata, and no internal +native-verifier fallback. + +`raw-results.tar.gz` contains the raw screening, final, fallback, contention, +profile, and validation logs. `summary.json` is regenerated from it by +`python3 summarize.py`. Source/binary hashes and exact commands are included. +The three screening patches in the archive's `sources/` directory recreate +their intermediate source from `e063695f`; +for the 32/64 screening variants, change `defaultTransactionJobGroups` from one +to four/eight in the roots patch result. + +For the final candidate, build this checkout. For the baseline, check out +`e063695f`, copy the candidate's `entry_prefetch_benchmark_test.go` into it, and +copy `baseline-root-adapter.go.txt` to +`pkg/turbine/benchmark_root_adapter_test.go`. Then build and alternate binaries: + +```sh +go test -c -o /tmp/turbine-completion.test ./pkg/turbine +GOMAXPROCS=8 MITHRIL_SIGVERIFY_FLOW_BACKEND=r51 \ +MITHRIL_SIGVERIFY_FLOW_COUNT=33760 \ +taskset --cpu-list 0-7 /tmp/turbine-completion.test \ + -test.run='^$' -test.benchtime=5x -test.count=1 \ + -test.bench='^BenchmarkEntryPrefetchAssembly$/^generated_.*$/^workers_2$/^target_8$/.*' +``` + +Select the target machine's distinct physical core IDs. The archived runners +record this server's paths and settings. The live validator was not deployed +or restarted by these experiments. diff --git a/docs/results/completion-followup/2026-09-12-zen5/baseline-root-adapter.go.txt b/docs/results/completion-followup/2026-09-12-zen5/baseline-root-adapter.go.txt new file mode 100644 index 00000000..9d645b92 --- /dev/null +++ b/docs/results/completion-followup/2026-09-12-zen5/baseline-root-adapter.go.txt @@ -0,0 +1,7 @@ +package turbine + +import "github.com/gagliardetto/solana-go" + +func (a *SlotAssembler) addShredFromWithRoot(s *Shred, repair bool, root *solana.Hash) (*slotCompletionWork, error) { + return a.addShredFrom(s, repair) +} diff --git a/docs/results/completion-followup/2026-09-12-zen5/raw-results.tar.gz b/docs/results/completion-followup/2026-09-12-zen5/raw-results.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..ee85538024754f5cd7c7079d06641a6a17454e9a GIT binary patch literal 53842 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 Om45 512 { + t.Skip() + } + state := &fecState{data: make(map[uint32]*Shred), coding: make(map[uint16]*Shred)} + for i, choice := range choices { + s := &Shred{Variant: merkleDataVariant, Type: ShredType(choice % 3), Payload: bytes.Repeat([]byte{choice}, dataPayloadSize)} + switch choice % 5 { + case 0: + s = nil + case 1: + s.Recovered = true + case 2: + s.Variant = legacyDataVariant + case 3: + s.Payload = s.Payload[:20] + } + if i%2 == 0 { + state.data[uint32(choice)] = s + } else { + state.coding[uint16(choice)] = s + } + } + want, wantOK, wantErr := referenceFECRoot(state) + got, gotOK, gotErr := state.merkleRoot() + require.Equal(t, want, got) + require.Equal(t, wantOK, gotOK) + if wantErr == nil { + require.NoError(t, gotErr) + } else { + require.EqualError(t, gotErr, wantErr.Error()) + } + }) +} + +func TestFECRootCacheKeepsDeterministicDataPrecedence(t *testing.T) { + packets := append(localnetMerkleShreds(t, "d"), localnetMerkleShreds(t, "c")...) + f := &fecState{data: make(map[uint32]*Shred), coding: make(map[uint16]*Shred)} + var shreds []*Shred + for _, packet := range packets { + s, err := ParseShred(packet) + require.NoError(t, err) + if s.FECSetIndex != 0 { + continue + } + shreds = append(shreds, s) + } + require.NotEmpty(t, shreds) + sort.Slice(shreds, func(i, j int) bool { + if shreds[i].Type != shreds[j].Type { + return shreds[i].Type == ShredTypeCode + } + return shreds[i].Index > shreds[j].Index + }) + for _, s := range shreds { + root, err := s.MerkleRoot() + require.NoError(t, err) + if s.Type == ShredTypeData { + f.data[s.Index-s.FECSetIndex] = s + } else { + f.coding[s.Position] = s + } + f.rememberAuthenticatedRoot(s, root) + want, wantOK, wantErr := referenceFECRoot(f) + got, gotOK, gotErr := f.merkleRoot() + require.Equal(t, wantErr, gotErr) + require.Equal(t, wantOK, gotOK) + require.Equal(t, want, got) + } + for _, s := range f.data { + s.Recovered = true + } + want, wantOK, wantErr := referenceFECRoot(f) + got, gotOK, gotErr := f.merkleRoot() + require.Equal(t, wantErr, gotErr) + require.Equal(t, wantOK, gotOK) + require.Equal(t, want, got) +} diff --git a/pkg/turbine/entries.go b/pkg/turbine/entries.go index b4657ce1..f4f505b2 100644 --- a/pkg/turbine/entries.go +++ b/pkg/turbine/entries.go @@ -131,7 +131,12 @@ func decodeEntriesAndAlpenglowMarkersFromDataShreds(shreds []*Shred, timings *en sort.Slice(shreds, func(i, j int) bool { return shreds[i].Index < shreds[j].Index }) + return decodeEntriesFromOrderedDataShreds(shreds, timings) +} +// decodeEntriesFromOrderedDataShreds requires increasing shred indexes. The +// assembler supplies that order directly; public decoding still sorts input. +func decodeEntriesFromOrderedDataShreds(shreds []*Shred, timings *entryDecodeTimings) ([]Entry, *AlpenglowParentInfo, *BlockFooter, error) { var entryBatches []*prefetchedShredBatch var parentInfo *AlpenglowParentInfo var blockFooter *BlockFooter diff --git a/pkg/turbine/entry_prefetch_benchmark_test.go b/pkg/turbine/entry_prefetch_benchmark_test.go index 4a0f14e7..b8279928 100644 --- a/pkg/turbine/entry_prefetch_benchmark_test.go +++ b/pkg/turbine/entry_prefetch_benchmark_test.go @@ -60,11 +60,12 @@ func BenchmarkEntryPrefetchAssembly(b *testing.B) { } type assemblyFlowFixture struct { - components [][]*Shred - blockID solana.Hash - parentID solana.Hash - bankhash solana.Hash - shreds int + components [][]*Shred + authenticatedRoots [][]solana.Hash + blockID solana.Hash + parentID solana.Hash + bankhash solana.Hash + shreds int } func makeAssemblyFlowFixture(tb testing.TB, source *block.Block) assemblyFlowFixture { @@ -90,6 +91,7 @@ func makeAssemblyFlowFixture(tb testing.TB, source *block.Block) assemblyFlowFix chained, nextData, nextCode = generated.chainedMerkleRoot, dataEnd, codeEnd roots = append(roots, generated.fecSetRoots...) var data []*Shred + var authenticatedRoots []solana.Hash for _, packet := range generated.packets { shred, err := ParseShred(packet) if err != nil { @@ -101,9 +103,15 @@ func makeAssemblyFlowFixture(tb testing.TB, source *block.Block) assemblyFlowFix if err := shred.VerifySignature(public); err != nil { tb.Fatal(err) } + root, err := shred.MerkleRoot() + if err != nil { + tb.Fatal(err) + } + authenticatedRoots = append(authenticatedRoots, root) data = append(data, shred) } fixture.components = append(fixture.components, data) + fixture.authenticatedRoots = append(fixture.authenticatedRoots, authenticatedRoots) fixture.shreds += len(data) } appendComponent(NewBlockHeader(99, fixture.parentID), false) @@ -154,8 +162,8 @@ func runAssemblyFlowBenchmark(b *testing.B, source *block.Block, fixture assembl if span > 0 { time.Sleep(time.Until(started.Add(flowArrivalOffset(componentIndex, len(fixture.components), span)))) } - for _, shred := range component { - candidate, err := a.addShredFrom(shred, false) + for shredIndex, shred := range component { + candidate, err := a.addShredFromWithRoot(shred, false, &fixture.authenticatedRoots[componentIndex][shredIndex]) if err != nil { b.Fatal(err) } diff --git a/pkg/turbine/fec_root_cache.go b/pkg/turbine/fec_root_cache.go new file mode 100644 index 00000000..cb4395b0 --- /dev/null +++ b/pkg/turbine/fec_root_cache.go @@ -0,0 +1,56 @@ +package turbine + +import ( + "bytes" + + "github.com/gagliardetto/solana-go" +) + +// One snapshot per FEC generation binds an authenticated root to its source. +// It is written only during assembly, before the state is frozen. Completion +// never trusts pointer identity alone or changes the deterministic root choice. +type authenticatedFECRoot struct { + source *Shred + input shredRootInput + payload []byte + root solana.Hash +} + +// These are every parsed field read by MerkleRoot. The exact payload comparison +// covers headers, data, proof, and trailers, even for noncanonical test input. +type shredRootInput struct { + variant byte + kind ShredType + index, fecSetIndex uint32 + dataCount, position uint16 +} + +func rootInput(s *Shred) shredRootInput { + return shredRootInput{s.Variant, s.Type, s.Index, s.FECSetIndex, s.NumDataShreds, s.Position} +} + +func hasMerkleRootProof(s *Shred) bool { + return s != nil && isMerkleVariant(s.Variant) && (s.Type == ShredTypeData || s.Type == ShredTypeCode) +} + +func (c *authenticatedFECRoot) matches(s *Shred) bool { + return s == c.source && rootInput(s) == c.input && bytes.Equal(s.Payload, c.payload) +} + +func (f *fecState) rememberAuthenticatedRoot(s *Shred, root solana.Hash) { + if s.Recovered || !isMerkleVariant(s.Variant) { + return + } + if cached := f.rootCache; cached != nil { + // Data proofs precede coding proofs, and the lowest index wins. An + // unauthenticated earlier arrival can still force fallback at completion. + old := cached.input + if old.kind == ShredTypeData && (s.Type != ShredTypeData || s.Index >= old.index) { + return + } + if old.kind == ShredTypeCode && s.Type == ShredTypeCode && s.Position >= old.position { + return + } + } + f.rootCache = &authenticatedFECRoot{source: s, input: rootInput(s), payload: bytes.Clone(s.Payload), root: root} +} diff --git a/pkg/turbine/receiver.go b/pkg/turbine/receiver.go index 69b67190..f5588bf6 100644 --- a/pkg/turbine/receiver.go +++ b/pkg/turbine/receiver.go @@ -703,6 +703,7 @@ func (r *UDPReceiver) processPacket(ctx context.Context, conn *net.UDPConn, pack r.codingShreds.Add(1) } var leader solana.PublicKey + var authenticatedRoot *solana.Hash if r.leaderForSlot != nil { var ok bool leader, ok = r.leaderForSlot(shred.Slot) @@ -714,7 +715,8 @@ func (r *UDPReceiver) processPacket(ctx context.Context, conn *net.UDPConn, pack } return true } - if err := r.sigCache.verifyShred(shred, leader); err != nil { + root, err := r.sigCache.verifyShredRoot(shred, leader) + if err != nil { r.signatureErrors.Add(1) select { case r.errs <- err: @@ -722,6 +724,7 @@ func (r *UDPReceiver) processPacket(ctx context.Context, conn *net.UDPConn, pack } return true } + authenticatedRoot = &root } matchedRepair := false if onRepairSocket && r.repairClient != nil { @@ -773,7 +776,7 @@ func (r *UDPReceiver) processPacket(ctx context.Context, conn *net.UDPConn, pack return true } } - work, err := r.assembler.addShredFrom(shred, matchedRepair) + work, err := r.assembler.addShredFromWithRoot(shred, matchedRepair, authenticatedRoot) r.slotResetMu.RUnlock() if err != nil { if errors.Is(err, ErrDuplicateShred) { diff --git a/pkg/turbine/sigcache.go b/pkg/turbine/sigcache.go index 7f3b1313..75b040b3 100644 --- a/pkg/turbine/sigcache.go +++ b/pkg/turbine/sigcache.go @@ -43,9 +43,16 @@ const shredSigCacheGenCap = 4096 // verifyShred authenticates a shred exactly like Shred.VerifySignature, with // the per-root ed25519 result cached. func (c *shredSigCache) verifyShred(s *Shred, leader solana.PublicKey) error { + _, err := c.verifyShredRoot(s, leader) + return err +} + +// verifyShredRoot also returns the root authenticated for these exact bytes. +// Callers must keep the shred immutable through assembler admission. +func (c *shredSigCache) verifyShredRoot(s *Shred, leader solana.PublicKey) (solana.Hash, error) { root, err := s.MerkleRoot() if err != nil { - return err + return solana.Hash{}, err } key := shredSigCacheKey{leader: leader, root: root, sig: s.Signature} @@ -53,25 +60,25 @@ func (c *shredSigCache) verifyShred(s *Shred, leader solana.PublicKey) error { if _, ok := c.cur[key]; ok { c.mu.Unlock() c.hits.Add(1) - return nil + return root, nil } if _, ok := c.prev[key]; ok { // Promote: a set straddling a rotation keeps its entry hot. c.addLocked(key) c.mu.Unlock() c.hits.Add(1) - return nil + return root, nil } c.mu.Unlock() c.verifies.Add(1) if !narya.VerifyStrict(leader[:], root[:], s.Signature[:]) { - return fmt.Errorf("%w: slot %d shred %d", ErrInvalidSignature, s.Slot, s.Index) + return solana.Hash{}, fmt.Errorf("%w: slot %d shred %d", ErrInvalidSignature, s.Slot, s.Index) } c.mu.Lock() c.addLocked(key) c.mu.Unlock() - return nil + return root, nil } func (c *shredSigCache) addLocked(key shredSigCacheKey) { diff --git a/pkg/turbine/transaction_job_groups_test.go b/pkg/turbine/transaction_job_groups_test.go new file mode 100644 index 00000000..ab2edb55 --- /dev/null +++ b/pkg/turbine/transaction_job_groups_test.go @@ -0,0 +1,118 @@ +package turbine + +import ( + "context" + "fmt" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/gagliardetto/solana-go" + "github.com/stretchr/testify/require" +) + +func TestWideVerificationJobsPreserveSignatureFailureIndex(t *testing.T) { + txs := verifierSignedTransactions(t, 320) + txs[33].Signatures[0][0] ^= 1 + txs[98].Signatures[0][0] ^= 1 + for _, groups := range []int{1, 4, 8} { + v := newTransactionVerifierWithJobGroups(2, 32, 8, groups, nil) + r, err := v.submitTransactions(context.Background(), txs) + require.NoError(t, err) + index, err := r.wait() + require.Error(t, err) + require.Equal(t, 33, index) + v.closeAndWait() + } +} + +func TestWideVerificationJobsYieldToReadySmallRequest(t *testing.T) { + for _, groups := range []int{4, 8} { + t.Run(fmt.Sprint(groups), func(t *testing.T) { + large, small := verifierTestBlock(800), verifierTestBlock(4) + started, release := make(chan struct{}), make(chan struct{}) + var releaseOnce sync.Once + var calls, beforeSmall atomic.Int32 + v := newTransactionVerifierWithJobGroups(1, 16, 8, groups, func(tx *solana.Transaction) error { + for _, s := range small.Transactions { + if tx == s { + beforeSmall.Store(calls.Load()) + return nil + } + } + calls.Add(1) + if tx == large.Transactions[0] { + close(started) + <-release + } + return nil + }) + defer v.closeAndWait() + defer releaseOnce.Do(func() { close(release) }) + big, err := v.submitTransactions(context.Background(), large.Transactions) + require.NoError(t, err) + waitSignal(t, started, "large job") + little, err := v.submitTransactions(context.Background(), small.Transactions) + require.NoError(t, err) + require.Eventually(t, func() bool { return len(v.jobs) == 1 }, 3*time.Second, time.Millisecond) + releaseOnce.Do(func() { close(release) }) + _, err = little.wait() + require.NoError(t, err) + require.Equal(t, int32(groups*8), beforeSmall.Load(), "one large job, not an entire catch-up request, precedes small work") + _, err = big.wait() + require.NoError(t, err) + require.Equal(t, int32(800), calls.Load()) + }) + } +} + +func TestWideVerificationJobsCancelBetweenVectorsAndJoin(t *testing.T) { + for _, groups := range []int{4, 8} { + t.Run(fmt.Sprint(groups), func(t *testing.T) { + started, release := make(chan struct{}), make(chan struct{}) + var releaseOnce sync.Once + var calls atomic.Int32 + v := newTransactionVerifierWithJobGroups(1, 16, 8, groups, func(*solana.Transaction) error { + if calls.Add(1) == 1 { + close(started) + <-release + } + return nil + }) + defer v.closeAndWait() + defer releaseOnce.Do(func() { close(release) }) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + r, err := v.submitTransactions(ctx, verifierTestBlock(800).Transactions) + require.NoError(t, err) + waitSignal(t, started, "first vector") + cancel() + select { + case <-r.done: + t.Fatal("released transactions still read by a worker") + default: + } + releaseOnce.Do(func() { close(release) }) + _, err = r.wait() + require.ErrorIs(t, err, context.Canceled) + require.Equal(t, int32(8), calls.Load(), "canceled large job finishes its admitted vector only") + }) + } +} + +func TestWideVerificationJobsDoNotWaitForFourTransactionBatch(t *testing.T) { + for _, groups := range []int{4, 8} { + v := newTransactionVerifierWithJobGroups(2, 32, 8, groups, func(*solana.Transaction) error { return nil }) + r, err := v.submitTransactions(context.Background(), verifierTestBlock(4).Transactions) + require.NoError(t, err) + select { + case <-r.done: + case <-time.After(3 * time.Second): + t.Fatal("partial work waited for another submission") + } + _, err = r.wait() + require.NoError(t, err) + v.closeAndWait() + } +} diff --git a/pkg/turbine/transaction_verifier.go b/pkg/turbine/transaction_verifier.go index f8a1d27d..6dfb5507 100644 --- a/pkg/turbine/transaction_verifier.go +++ b/pkg/turbine/transaction_verifier.go @@ -17,9 +17,14 @@ var ( errTransactionVerifierClosed = fmt.Errorf("transaction verifier closed") ) +// Four vector groups amortize dispatch for large ready requests while bounding +// the work that can precede another component on a worker. +const defaultTransactionJobGroups = 4 + // A job is formed before admission, from transactions which are already // available. Workers never wait for more transactions to fill a vector group. type transactionVerifyJob struct { + ctx context.Context txs []*solana.Transaction errs []error start int @@ -65,7 +70,8 @@ type transactionVerifier struct { verify func(*solana.Transaction) error workers int batchTarget int - // Each accepted request owns at most workers outstanding groups. The + jobGroups int + // Each accepted request owns at most workers outstanding jobs. The // admission semaphore also bounds asynchronous request goroutines; callers // apply backpressure before handing off another decoded component. requests chan struct{} @@ -81,19 +87,28 @@ func newTransactionVerifier(workers, queueDepth int, verify func(*solana.Transac return newTransactionVerifierWithBatchTarget(workers, queueDepth, sigverify.BatchTarget, verify) } -// queueDepth is a transaction budget, rounded up to whole groups. batchTarget +// queueDepth is a transaction budget, rounded up to whole jobs. batchTarget // counts signature lanes: multi-signature transactions stay indivisible and // may exceed the target. Four/eight targets can be compared without changing // the admission or cancellation policy. func newTransactionVerifierWithBatchTarget(workers, queueDepth, batchTarget int, verify func(*solana.Transaction) error) *transactionVerifier { + return newTransactionVerifierWithJobGroups(workers, queueDepth, batchTarget, defaultTransactionJobGroups, verify) +} + +// Job groups amortize dispatch over already available vector groups. They do +// not change vector width or wait for future transactions to arrive. +func newTransactionVerifierWithJobGroups(workers, queueDepth, batchTarget, jobGroups int, verify func(*solana.Transaction) error) *transactionVerifier { workers = max(1, workers) batchTarget = max(1, min(batchTarget, sigverify.BatchTarget)) - queueGroups := max(1, (queueDepth+batchTarget-1)/batchTarget) + jobGroups = max(1, min(jobGroups, 8)) + jobCapacity := batchTarget * jobGroups + queueGroups := max(1, (queueDepth+jobCapacity-1)/jobCapacity) v := &transactionVerifier{ jobs: make(chan *transactionVerifyJob, queueGroups), verify: verify, workers: workers, batchTarget: batchTarget, + jobGroups: jobGroups, requests: make(chan struct{}, 2*workers), stopped: make(chan struct{}), } @@ -114,17 +129,30 @@ func newTransactionVerifierWithBatchTarget(workers, queueDepth, batchTarget int, // request's bounded completion channel always has room for every pending job. func (v *transactionVerifier) verifyGroup(job *transactionVerifyJob, batch *txverify.BatchVerifier) { defer func() { job.done <- job }() - if v.verify != nil { - for i, tx := range job.txs { - if tx == nil { - job.errs[i] = errNilTransaction - } else { - job.errs[i] = verifyTransactionSafely(v.verify, tx) + for start := 0; start < len(job.txs); { + // An admitted job always finishes its first vector group, preserving + // ownership/join semantics. Cancellation can skip additional groups. + if err := job.ctx.Err(); start > 0 && err != nil { + for i := start; i < len(job.errs); i++ { + job.errs[i] = err } + return } - return + end := transactionVerifyGroupEnd(job.txs, start, v.batchTarget) + if v.verify != nil { + for i := start; i < end; i++ { + tx := job.txs[i] + if tx == nil { + job.errs[i] = errNilTransaction + } else { + job.errs[i] = verifyTransactionSafely(v.verify, tx) + } + } + } else { + verifyBatchSafely(batch, job.txs[start:end], job.errs[start:end]) + } + start = end } - verifyBatchSafely(batch, job.txs, job.errs) } // submitTransactions admits one immutable decoded component or complete block. @@ -168,20 +196,28 @@ func (v *transactionVerifier) submitTransactions(ctx context.Context, txs []*sol } // verifyTransactions keeps a rolling window instead of waiting for an entire -// worker wave. A slow group cannot idle workers whose earlier groups finished. -// One caller can queue at most workers groups, so a large catch-up block cannot +// worker wave. A slow job cannot idle workers whose earlier jobs finished. +// One caller can queue at most workers jobs, so a large catch-up block cannot // put all its transactions ahead of a newly available component. func (v *transactionVerifier) verifyTransactions(ctx context.Context, txs []*solana.Transaction) (int, error) { if len(txs) == 0 { return -1, ctx.Err() } window := min(v.workers, len(txs)) + jobGroups := v.jobGroups + // Keep short components responsive and enough independent jobs to supply + // every worker. This is a ready-work threshold, never a batching timer. + if len(txs) < 2*v.workers*v.batchTarget*jobGroups { + jobGroups = 1 + } + jobCapacity := v.batchTarget * jobGroups completed := make(chan *transactionVerifyJob, window) groups := make([]transactionVerifyJob, window) - errs := make([]error, window*v.batchTarget) + errs := make([]error, window*jobCapacity) free := make([]*transactionVerifyJob, window) for i := range groups { - groups[i].errs = errs[i*v.batchTarget : (i+1)*v.batchTarget] + groups[i].ctx = ctx + groups[i].errs = errs[i*jobCapacity : (i+1)*jobCapacity] groups[i].done = completed free[i] = &groups[i] } @@ -203,7 +239,10 @@ func (v *transactionVerifier) verifyTransactions(ctx context.Context, txs []*sol if !stopped && pending == nil && nextIndex < len(txs) && len(free) > 0 { pending = free[len(free)-1] free = free[:len(free)-1] - end := transactionVerifyGroupEnd(txs, nextIndex, v.batchTarget) + end := nextIndex + for group := 0; group < jobGroups && end < len(txs); group++ { + end = transactionVerifyGroupEnd(txs, end, v.batchTarget) + } pending.start = nextIndex pending.txs = txs[nextIndex:end] pending.errs = pending.errs[:end-nextIndex] diff --git a/pkg/turbine/transaction_verifier_test.go b/pkg/turbine/transaction_verifier_test.go index 602fa704..dbb73e85 100644 --- a/pkg/turbine/transaction_verifier_test.go +++ b/pkg/turbine/transaction_verifier_test.go @@ -245,7 +245,7 @@ func TestTransactionVerifierLargeRequestDoesNotQueuePastSmallRequest(t *testing. releaseOnce.Do(func() { close(release) }) _, err = smallRequest.wait() require.NoError(t, err) - require.Equal(t, int32(8), callsBeforeSmall.Load(), "large request may only stay one group ahead") + require.Equal(t, int32(v.batchTarget*v.jobGroups), callsBeforeSmall.Load(), "large request may only stay one job ahead") _, err = largeRequest.wait() require.NoError(t, err) require.Equal(t, int32(800), largeCalls.Load()) @@ -425,23 +425,29 @@ func TestTransactionVerifierKeepsMultisignatureTransactionsIntactAcrossTargets(t txs[i] = tx } for _, target := range []int{4, 8} { - t.Run(fmt.Sprintf("target=%d", target), func(t *testing.T) { - v := newTransactionVerifierWithBatchTarget(2, 16, target, nil) - defer v.closeAndWait() - r, err := v.submitTransactions(context.Background(), txs) - require.NoError(t, err) - _, err = r.wait() - require.NoError(t, err) + for _, groups := range []int{1, 4, 8} { + t.Run(fmt.Sprintf("target=%d/groups=%d", target, groups), func(t *testing.T) { + v := newTransactionVerifierWithJobGroups(2, 16, target, groups, nil) + defer v.closeAndWait() + var large []*solana.Transaction + for range 40 { + large = append(large, txs...) + } + r, err := v.submitTransactions(context.Background(), large) + require.NoError(t, err) + _, err = r.wait() + require.NoError(t, err) - // Corrupt a non-first signer after an oversized (nine-signature) - // transaction. Results must still map to the original tx index. - txs[6].Signatures[1][11] ^= 0x20 - r, err = v.submitTransactions(context.Background(), txs) - require.NoError(t, err) - index, err := r.wait() - require.ErrorContains(t, err, "invalid signature") - require.Equal(t, 6, index) - txs[6].Signatures[1][11] ^= 0x20 - }) + // Corrupt a non-first signer after an oversized (nine-signature) + // transaction. Results must still map to the original tx index. + txs[6].Signatures[1][11] ^= 0x20 + r, err = v.submitTransactions(context.Background(), large) + require.NoError(t, err) + index, err := r.wait() + require.ErrorContains(t, err, "invalid signature") + require.Equal(t, 6, index) + txs[6].Signatures[1][11] ^= 0x20 + }) + } } } From f18453523502d7700a948f1c9eb31ddc22d284bf Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Sun, 13 Sep 2026 02:07:16 -0500 Subject: [PATCH 006/183] Make streaming tests independent of FEC acceleration --- pkg/turbine/entry_prefetch_benchmark_test.go | 10 ++-- pkg/turbine/generate.go | 10 ++-- .../generated_component_boundary_test.go | 47 +++++++++++++++++++ 3 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 pkg/turbine/generated_component_boundary_test.go diff --git a/pkg/turbine/entry_prefetch_benchmark_test.go b/pkg/turbine/entry_prefetch_benchmark_test.go index b8279928..9b494b73 100644 --- a/pkg/turbine/entry_prefetch_benchmark_test.go +++ b/pkg/turbine/entry_prefetch_benchmark_test.go @@ -84,15 +84,14 @@ func makeAssemblyFlowFixture(tb testing.TB, source *block.Block) assemblyFlowFix if err != nil { tb.Fatal(err) } - generated, dataEnd, codeEnd, err := generator.makeShredsFromData(leader, raw, last, chained, nextData, nextCode) + packets, finalRoot, dataEnd, codeEnd, err := generator.MakeShredsFromData(leader, raw, last, chained, nextData, nextCode) if err != nil { tb.Fatal(err) } - chained, nextData, nextCode = generated.chainedMerkleRoot, dataEnd, codeEnd - roots = append(roots, generated.fecSetRoots...) + chained, nextData, nextCode = finalRoot, dataEnd, codeEnd var data []*Shred var authenticatedRoots []solana.Hash - for _, packet := range generated.packets { + for _, packet := range packets { shred, err := ParseShred(packet) if err != nil { tb.Fatal(err) @@ -107,6 +106,9 @@ func makeAssemblyFlowFixture(tb testing.TB, source *block.Block) assemblyFlowFix if err != nil { tb.Fatal(err) } + if shred.Index == shred.FECSetIndex { + roots = append(roots, root) + } authenticatedRoots = append(authenticatedRoots, root) data = append(data, shred) } diff --git a/pkg/turbine/generate.go b/pkg/turbine/generate.go index 14626e21..b4c58548 100644 --- a/pkg/turbine/generate.go +++ b/pkg/turbine/generate.go @@ -96,10 +96,11 @@ func (g *ShredGenerator) MakeShredsFromData( codeIndex := nextCodeIndex chainedRoot := chainedMerkleRoot + // DATA_COMPLETE ends the serialized component, which may span FEC sets. for len(unsignedData) >= unsignedBatch { batch := unsignedData[:unsignedBatch] unsignedData = unsignedData[unsignedBatch:] - batchPackets, root, err := g.makeFECBatch(leader, batch, unsignedCap, proofSize, false, parentOffset, flags, false, chainedRoot, dataIndex, codeIndex) + batchPackets, root, err := g.makeFECBatch(leader, batch, unsignedCap, proofSize, false, parentOffset, flags, len(unsignedData) == 0 && len(signedData) == 0, false, chainedRoot, dataIndex, codeIndex) if err != nil { return nil, solana.Hash{}, dataIndex, codeIndex, err } @@ -110,7 +111,7 @@ func (g *ShredGenerator) MakeShredsFromData( } if len(unsignedData) > 0 || (len(packets) == 0 && !isLastInSlot) { - batchPackets, root, err := g.makeFECBatch(leader, unsignedData, unsignedCap, proofSize, false, parentOffset, flags, false, chainedRoot, dataIndex, codeIndex) + batchPackets, root, err := g.makeFECBatch(leader, unsignedData, unsignedCap, proofSize, false, parentOffset, flags, len(signedData) == 0, false, chainedRoot, dataIndex, codeIndex) if err != nil { return nil, solana.Hash{}, dataIndex, codeIndex, err } @@ -121,7 +122,7 @@ func (g *ShredGenerator) MakeShredsFromData( } if len(signedData) > 0 || (len(packets) == 0 && isLastInSlot) { - batchPackets, root, err := g.makeFECBatch(leader, signedData, signedCap, proofSize, true, parentOffset, flags, isLastInSlot, chainedRoot, dataIndex, codeIndex) + batchPackets, root, err := g.makeFECBatch(leader, signedData, signedCap, proofSize, true, parentOffset, flags, true, isLastInSlot, chainedRoot, dataIndex, codeIndex) if err != nil { return nil, solana.Hash{}, dataIndex, codeIndex, err } @@ -142,6 +143,7 @@ func (g *ShredGenerator) makeFECBatch( resigned bool, parentOffset uint16, flags byte, + dataComplete bool, isLastInSlot bool, chainedMerkleRoot solana.Hash, dataIndex uint32, @@ -196,7 +198,7 @@ func (g *ShredGenerator) makeFECBatch( dataPackets[i][dataFlagsOffset] |= shredFlagLastShredInSlot break } - } else if len(dataPackets) > 0 { + } else if dataComplete && len(dataPackets) > 0 { dataPackets[len(dataPackets)-1][dataFlagsOffset] |= shredFlagDataComplete } diff --git a/pkg/turbine/generated_component_boundary_test.go b/pkg/turbine/generated_component_boundary_test.go new file mode 100644 index 00000000..87184308 --- /dev/null +++ b/pkg/turbine/generated_component_boundary_test.go @@ -0,0 +1,47 @@ +package turbine + +import ( + "bytes" + "fmt" + "testing" + + "github.com/gagliardetto/solana-go" + "github.com/stretchr/testify/require" +) + +// Exercise exact FEC boundaries and the smaller resigned final-set capacity. +// The receiver must see one DATA_COMPLETE per serialized component, regardless +// of how many FEC sets carry it, with proofs authenticating the final flags. +func TestGeneratedComponentHasOneCompletionBoundary(t *testing.T) { + unsigned := dataShredsPerFECBlock * dataCapacity(proofEntriesFor32x32, false) + signed := dataShredsPerFECBlock * dataCapacity(proofEntriesFor32x32, true) + for _, last := range []bool{false, true} { + for _, size := range []int{0, 1, signed, signed + 1, unsigned, unsigned + 1, 2 * unsigned, 2*unsigned + signed} { + t.Run(fmt.Sprintf("last=%t/bytes=%d", last, size), func(t *testing.T) { + leader := testShredLeader(t) + gen := ShredGenerator{Slot: 100, ParentSlot: 99, Version: 7} + payload := bytes.Repeat([]byte{0x5a}, size) + packets, _, nextData, _, err := gen.MakeShredsFromData(leader, payload, last, solana.Hash{}, 0, 0) + require.NoError(t, err) + var decoded []byte + var completed int + for _, packet := range packets { + shred, err := ParseShred(packet) + require.NoError(t, err) + require.NoError(t, shred.VerifySignature(leader.PublicKey())) + if shred.Type != ShredTypeData { + continue + } + decoded = append(decoded, shred.Data...) + if shred.DataComplete() { + completed++ + require.Equal(t, nextData-1, shred.Index) + } + require.Equal(t, last && shred.Index == nextData-1, shred.LastInSlot()) + } + require.Equal(t, 1, completed) + require.True(t, bytes.Equal(payload, decoded)) + }) + } + } +} From 0063cfb02d86d016a07c78c68b485d665e2a9a96 Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Sun, 13 Sep 2026 02:07:16 -0500 Subject: [PATCH 007/183] Allocate each prepared component transaction view once --- pkg/turbine/entry_batch_transactions_test.go | 37 ++++++++++++++++++++ pkg/turbine/entry_prefetch.go | 8 ++++- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 pkg/turbine/entry_batch_transactions_test.go diff --git a/pkg/turbine/entry_batch_transactions_test.go b/pkg/turbine/entry_batch_transactions_test.go new file mode 100644 index 00000000..28329ab0 --- /dev/null +++ b/pkg/turbine/entry_batch_transactions_test.go @@ -0,0 +1,37 @@ +package turbine + +import ( + "fmt" + "testing" + + "github.com/gagliardetto/solana-go" + "github.com/stretchr/testify/require" +) + +func TestEntryBatchTransactionsPreservesEntryOwnershipAndOrder(t *testing.T) { + entries := []Entry{{}, {Txns: make([]solana.Transaction, 3)}, {}, {Txns: make([]solana.Transaction, 2)}} + txs := entryBatchTransactions(entries) + require.Len(t, txs, 5) + for i := 0; i < 3; i++ { + require.Same(t, &entries[1].Txns[i], txs[i]) + } + for i := 0; i < 2; i++ { + require.Same(t, &entries[3].Txns[i], txs[3+i]) + } + require.Empty(t, entryBatchTransactions(nil)) + require.Empty(t, entryBatchTransactions([]Entry{{}, {}})) +} + +var entryBatchBenchmarkSink []*solana.Transaction + +func BenchmarkEntryBatchTransactions(b *testing.B) { + for _, count := range []int{4, 49, 269, 33760} { + b.Run(fmt.Sprintf("tx_%d", count), func(b *testing.B) { + entries := []Entry{{Txns: make([]solana.Transaction, count/2)}, {}, {Txns: make([]solana.Transaction, count-count/2)}} + b.ReportAllocs() + for b.Loop() { + entryBatchBenchmarkSink = entryBatchTransactions(entries) + } + }) + } +} diff --git a/pkg/turbine/entry_prefetch.go b/pkg/turbine/entry_prefetch.go index 5816b1e8..05171918 100644 --- a/pkg/turbine/entry_prefetch.go +++ b/pkg/turbine/entry_prefetch.go @@ -187,7 +187,13 @@ func (p *entryPrefetchPool) run() { } func entryBatchTransactions(entries []Entry) []*solana.Transaction { - var txs []*solana.Transaction + count := 0 + for i := range entries { + count += len(entries[i].Txns) + } + // Entries are already decoded: size this pointer view once instead of + // repeatedly reallocating and copying it while preparing each component. + txs := make([]*solana.Transaction, 0, count) for i := range entries { for j := range entries[i].Txns { txs = append(txs, &entries[i].Txns[j]) From 7c5bcc3d5b6c705b68580defa1a872b1ac26d2cb Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Sun, 13 Sep 2026 02:07:16 -0500 Subject: [PATCH 008/183] Document standalone streaming validation and live trial scope --- .../streaming-pr-review/2026-09-13/README.md | 99 +++++++++++++++++++ .../2026-09-13/binaries-sha256.txt | 2 + .../2026-09-13/local-race.txt | 7 ++ .../2026-09-13/local-root-fuzz.txt | 7 ++ .../2026-09-13/native-assembly.txt | 13 +++ .../2026-09-13/native-build.txt | 0 .../2026-09-13/native-race.txt | 7 ++ .../2026-09-13/native-vet.txt | 0 .../2026-09-13/pointer-after.txt | 18 ++++ .../2026-09-13/pointer-before.txt | 18 ++++ .../2026-09-13/run-native.sh | 19 ++++ .../2026-09-13/service-after.txt | 2 + .../2026-09-13/service-before.txt | 2 + .../2026-09-13/source-sha256.txt | 1 + docs/transaction_sigverify_streaming.md | 4 + 15 files changed, 199 insertions(+) create mode 100644 docs/results/streaming-pr-review/2026-09-13/README.md create mode 100644 docs/results/streaming-pr-review/2026-09-13/binaries-sha256.txt create mode 100644 docs/results/streaming-pr-review/2026-09-13/local-race.txt create mode 100644 docs/results/streaming-pr-review/2026-09-13/local-root-fuzz.txt create mode 100644 docs/results/streaming-pr-review/2026-09-13/native-assembly.txt create mode 100644 docs/results/streaming-pr-review/2026-09-13/native-build.txt create mode 100644 docs/results/streaming-pr-review/2026-09-13/native-race.txt create mode 100644 docs/results/streaming-pr-review/2026-09-13/native-vet.txt create mode 100644 docs/results/streaming-pr-review/2026-09-13/pointer-after.txt create mode 100644 docs/results/streaming-pr-review/2026-09-13/pointer-before.txt create mode 100644 docs/results/streaming-pr-review/2026-09-13/run-native.sh create mode 100644 docs/results/streaming-pr-review/2026-09-13/service-after.txt create mode 100644 docs/results/streaming-pr-review/2026-09-13/service-before.txt create mode 100644 docs/results/streaming-pr-review/2026-09-13/source-sha256.txt diff --git a/docs/results/streaming-pr-review/2026-09-13/README.md b/docs/results/streaming-pr-review/2026-09-13/README.md new file mode 100644 index 00000000..2ed33fb7 --- /dev/null +++ b/docs/results/streaming-pr-review/2026-09-13/README.md @@ -0,0 +1,99 @@ +# Standalone streaming verification PR review + +This branch extracts the receiver, transaction pool, Narya update and completion +work from trial commit `15ad18458dea3b7ff89ea21ef3bae7df04b323de` onto +`alpenglow-dev` at `33dde405`. The dependency planner is already merged in that +base. It does not include the FEC acceleration, producer batching, or subsequent +leader-packing experiments from the combined trial. + +The only shared prerequisite with FEC PR #259 is the small generator correctness +fix that places DATA_COMPLETE at the end of the serialized component, rather +than at every intermediate FEC boundary. Boundary tests cover exact unsigned +and resigned capacities, multiple sets, signature proofs, and round-trip bytes. +The assembly fixture uses the public generation API and derives roots from +packet proofs; fixture generation remains outside timing. The root cache keeps +alpenglow-dev's existing private shredSigCache type. + +## Final allocation improvement + +Early preparation knows the decoded transaction count. Allocate its pointer view +once, preserving order and pointers into the original entry storage. This avoids +repeated slice growth without copying transaction objects or changing ownership. + +Apple M4 Pro, Go 1.26.4, three 200 ms microbenchmark samples per case: + +| Transactions/component | Before bytes / allocations | After bytes / allocations | +|---|---:|---:| +| 4 | 56 / 3 | 32 / 1 | +| 49 | 1,016 / 7 | 416 / 1 | +| 269 | 4,472 / 9 | 2,304 / 1 | +| 33,760 | approximately 1,301,624 / 23 | 270,336 / 1 | + +These measure pointer-view construction alone. The 33,760 case is a helper +stress case, not a typical prefetched component. Concurrent local validation +makes the timing samples unsuitable for an end-to-end speedup claim; allocation +counts are the result of interest. Raw output is in pointer-before.txt and +pointer-after.txt. The before version is the committed trial's append-growth +implementation; this is not an alpenglow-dev comparison. + +## Earlier performance evidence and live validation + +The [streaming report](../../sigverify-streaming/2026-09-12-zen5/README.md), +[direct byte comparison report](../../sigverify-direct-cache/2026-09-12-zen5/README.md), +and [completion follow-up](../../completion-followup/2026-09-12-zen5/README.md) +retain their original raw evidence, source hashes, and baseline definitions. +Those runs used the combined trial branch. They are not a fresh comparison +against this standalone branch's current alpenglow-dev base. + +A five-minute live Alpenglow sample on September 13, 04:03:06–04:08:06 UTC, used +combined trial `15ad1845` before the later leader-packing changes. On the Ryzen 7 +9700X with GOMAXPROCS=8, two signature workers and target eight: + +- 1,241 replayed blocks, 5,700,024 transactions; 118 blocks had at least 20,000 + transactions, with median and maximum transaction count 33,760. +- Those large blocks had median full replay 78.11 ms, p95 98.67 ms; median + final-shred-to-ready 7.53 ms, p95 34.74 ms. The two stages are distinct. +- 3,449,937 of 3,844,618 large-block transactions (89.7%) were signature-verified + before full assembly. +- RPC-tip checks stayed current; last-vote lag was 1–3 slots, median two. No + logged runtime errors, bankhash mismatches, or internal verifier fallbacks + were observed in the sample. + +This was an observational trial, not a paired whole-validator speed comparison. +The live binary also contained the FEC/producer work excluded from this PR. + +## Fresh standalone Zen 5 check + +The source archive identified by source-sha256.txt contains the final production +code and tests. Documentation-only additions followed that archive. Run details +are in run-native.sh; native-assembly.txt contains all measurements. Eight +physical cores (CPUs 0–7), GOMAXPROCS=8, Go 1.26.4, native Narya r51, nice 10; +the existing validator remained active with the same PID throughout. + +For 33,760 distinct generated one-signature transactions, two workers, target +eight, three timed blocks per condition: + +| Wire bytes/tx | Tip final-shred-to-ready, overlap off → on | Tip total arrival-to-ready, off → on | Catch-up total, off → on | +|---|---:|---:|---:| +| 228 | 85.72 → 1.831 ms | 286.93 → 202.94 ms | 85.31 → 86.39 ms | +| 1,232 | 99.89 → 6.504 ms | 302.61 → 207.77 ms | 111.97 → 117.38 ms | + +Residual values are within-run medians; total times are Go benchmark means. +This small run validates the extracted implementation and illustrates overlap; +it is not a stable speedup estimate. Both sides use this PR's new batching, +Narya and completion code. It is explicitly **not old alpenglow-dev versus PR**. +Catch-up offers all shreds immediately and showed modest extra overlap overhead +in this run. The default favors latency at the tip, with no mode-switch timer. + +The tip workload distributes complete component bursts over 200 ms, using a +60 KiB transaction-byte component budget plus actual entry overhead/FEC padding. +Collection took 200.9–201.4 ms. These are synthetic arrivals, not a network trace. +Timed work includes assembly, decoding, Merkle/block identity, signatures and +publication; it excludes packet parsing, shred authentication, loss/recovery, +transaction execution, PoH, disk I/O and commit. Assertions checked exact +signature coverage, block metadata, and zero internal native fallbacks. + +Native and local race suites passed for Turbine, replay, sigverify, txverify, +block, statsd and node; vet and complete Mithril builds passed on both machines. +Raw race logs are included. Root-selection fuzzing compared the new selector +against the original sorted algorithm; local-root-fuzz.txt records the result. diff --git a/docs/results/streaming-pr-review/2026-09-13/binaries-sha256.txt b/docs/results/streaming-pr-review/2026-09-13/binaries-sha256.txt new file mode 100644 index 00000000..0bc09ac1 --- /dev/null +++ b/docs/results/streaming-pr-review/2026-09-13/binaries-sha256.txt @@ -0,0 +1,2 @@ +74a73afaccbad6587342c7c3e010a95bce33398882d7333324e432938eaebefe review-results/mithril +a613bc9efc39128dc0a051a80cccd9f32223834bcbd2bf40b4f7e8e5983c1f8e review-results/turbine.test diff --git a/docs/results/streaming-pr-review/2026-09-13/local-race.txt b/docs/results/streaming-pr-review/2026-09-13/local-race.txt new file mode 100644 index 00000000..e2c01328 --- /dev/null +++ b/docs/results/streaming-pr-review/2026-09-13/local-race.txt @@ -0,0 +1,7 @@ +ok github.com/Overclock-Validator/mithril/pkg/turbine 10.156s +ok github.com/Overclock-Validator/mithril/pkg/replay 4.316s +ok github.com/Overclock-Validator/mithril/pkg/sigverify 23.094s +ok github.com/Overclock-Validator/mithril/pkg/txverify 1.495s +ok github.com/Overclock-Validator/mithril/pkg/block 2.056s +ok github.com/Overclock-Validator/mithril/pkg/statsd 2.038s +ok github.com/Overclock-Validator/mithril/cmd/mithril/node 2.900s diff --git a/docs/results/streaming-pr-review/2026-09-13/local-root-fuzz.txt b/docs/results/streaming-pr-review/2026-09-13/local-root-fuzz.txt new file mode 100644 index 00000000..8acccc98 --- /dev/null +++ b/docs/results/streaming-pr-review/2026-09-13/local-root-fuzz.txt @@ -0,0 +1,7 @@ +fuzz: elapsed: 0s, gathering baseline coverage: 0/79 completed +fuzz: elapsed: 0s, gathering baseline coverage: 79/79 completed, now fuzzing with 4 workers +fuzz: elapsed: 3s, execs: 4734 (1577/sec), new interesting: 1 (total: 80) +fuzz: elapsed: 6s, execs: 4734 (0/sec), new interesting: 1 (total: 80) +fuzz: elapsed: 6s, execs: 4734 (0/sec), new interesting: 1 (total: 80) +PASS +ok github.com/Overclock-Validator/mithril/pkg/turbine 6.468s diff --git a/docs/results/streaming-pr-review/2026-09-13/native-assembly.txt b/docs/results/streaming-pr-review/2026-09-13/native-assembly.txt new file mode 100644 index 00000000..08ec62c6 --- /dev/null +++ b/docs/results/streaming-pr-review/2026-09-13/native-assembly.txt @@ -0,0 +1,13 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_off-8 3 85306561 ns/op 1.964 avg_cpu_cores 1.419 collection_p50-ms 1.453 collection_p95-ms 4.705 completion_parse_p50-ms 5.428 completion_parse_p95-ms 75.24 completion_sigverify_p50-ms 81.81 completion_sigverify_p95-ms 128.0 components/block 167.6 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 82.44 full_to_ready_p50-ms 88.44 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 32456858 B/op 207227 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/catchup/overlap_on-8 3 86393257 ns/op 2.035 avg_cpu_cores 2.079 collection_p50-ms 2.115 collection_p95-ms 4.682 completion_parse_p50-ms 5.162 completion_parse_p95-ms 77.92 completion_sigverify_p50-ms 78.55 completion_sigverify_p95-ms 128.0 components/block 175.8 cpu-ms/block 8128 data_shreds/block 358.7 early_verified_tx/block 84.92 full_to_ready_p50-ms 85.60 full_to_ready_p95-ms 7.996 mean_width 0.0007720 preparation_wait_p50-ms 0.007895 preparation_wait_p95-ms 33760 tx/block 34990840 B/op 207362 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_off-8 3 286934835 ns/op 0.6117 avg_cpu_cores 200.9 collection_p50-ms 201.0 collection_p95-ms 3.815 completion_parse_p50-ms 4.460 completion_parse_p95-ms 80.32 completion_sigverify_p50-ms 82.17 completion_sigverify_p95-ms 128.0 components/block 175.5 cpu-ms/block 8128 data_shreds/block 0 early_verified_tx/block 85.72 full_to_ready_p50-ms 87.87 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 32411189 B/op 207227 allocs/op +BenchmarkEntryPrefetchAssembly/generated_228B/workers_2/target_8/tip_200ms/overlap_on-8 3 202937835 ns/op 0.8674 avg_cpu_cores 200.9 collection_p50-ms 201.1 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.02486 completion_sigverify_p50-ms 0.04140 completion_sigverify_p95-ms 128.0 components/block 176.0 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 1.831 full_to_ready_p50-ms 2.388 full_to_ready_p95-ms 7.912 mean_width 0.02706 preparation_wait_p50-ms 0.03109 preparation_wait_p95-ms 33760 tx/block 33110861 B/op 209062 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_off-8 3 111966851 ns/op 1.906 avg_cpu_cores 7.957 collection_p50-ms 8.498 collection_p95-ms 4.311 completion_parse_p50-ms 5.824 completion_parse_p95-ms 87.03 completion_sigverify_p50-ms 89.17 completion_sigverify_p95-ms 691.0 components/block 213.4 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 102.9 full_to_ready_p50-ms 106.7 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 113167597 B/op 227179 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/catchup/overlap_on-8 3 117376486 ns/op 2.023 avg_cpu_cores 11.83 collection_p50-ms 12.91 collection_p95-ms 4.231 completion_parse_p50-ms 5.194 completion_parse_p95-ms 89.59 completion_sigverify_p50-ms 89.71 completion_sigverify_p95-ms 691.0 components/block 237.4 cpu-ms/block 44160 data_shreds/block 2777 early_verified_tx/block 103.6 full_to_ready_p50-ms 108.8 full_to_ready_p95-ms 7.906 mean_width 0.009261 preparation_wait_p50-ms 0.01254 preparation_wait_p95-ms 33760 tx/block 115776725 B/op 228075 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_off-8 3 302607710 ns/op 0.6960 avg_cpu_cores 201.4 collection_p50-ms 201.5 collection_p95-ms 4.279 completion_parse_p50-ms 6.031 completion_parse_p95-ms 84.70 completion_sigverify_p50-ms 89.83 completion_sigverify_p95-ms 691.0 components/block 210.6 cpu-ms/block 44160 data_shreds/block 0 early_verified_tx/block 99.89 full_to_ready_p50-ms 106.4 full_to_ready_p95-ms 8.000 mean_width 0 preparation_wait_p50-ms 0 preparation_wait_p95-ms 33760 tx/block 113304938 B/op 227184 allocs/op +BenchmarkEntryPrefetchAssembly/generated_1232B/workers_2/target_8/tip_200ms/overlap_on-8 3 207771037 ns/op 1.175 avg_cpu_cores 200.9 collection_p50-ms 201.2 collection_p95-ms 0.01120 completion_parse_p50-ms 0.01515 completion_parse_p95-ms 0.3232 completion_sigverify_p50-ms 0.3461 completion_sigverify_p95-ms 691.0 components/block 244.1 cpu-ms/block 44160 data_shreds/block 33728 early_verified_tx/block 6.504 full_to_ready_p50-ms 6.869 full_to_ready_p95-ms 7.001 mean_width 0.1116 preparation_wait_p50-ms 0.1148 preparation_wait_p95-ms 33760 tx/block 115064322 B/op 236934 allocs/op +PASS diff --git a/docs/results/streaming-pr-review/2026-09-13/native-build.txt b/docs/results/streaming-pr-review/2026-09-13/native-build.txt new file mode 100644 index 00000000..e69de29b diff --git a/docs/results/streaming-pr-review/2026-09-13/native-race.txt b/docs/results/streaming-pr-review/2026-09-13/native-race.txt new file mode 100644 index 00000000..c1383a85 --- /dev/null +++ b/docs/results/streaming-pr-review/2026-09-13/native-race.txt @@ -0,0 +1,7 @@ +ok github.com/Overclock-Validator/mithril/pkg/turbine 6.090s +ok github.com/Overclock-Validator/mithril/pkg/replay 2.053s +ok github.com/Overclock-Validator/mithril/pkg/sigverify 19.684s +ok github.com/Overclock-Validator/mithril/pkg/txverify 1.014s +ok github.com/Overclock-Validator/mithril/pkg/block 1.139s +ok github.com/Overclock-Validator/mithril/pkg/statsd 1.016s +ok github.com/Overclock-Validator/mithril/cmd/mithril/node 1.149s diff --git a/docs/results/streaming-pr-review/2026-09-13/native-vet.txt b/docs/results/streaming-pr-review/2026-09-13/native-vet.txt new file mode 100644 index 00000000..e69de29b diff --git a/docs/results/streaming-pr-review/2026-09-13/pointer-after.txt b/docs/results/streaming-pr-review/2026-09-13/pointer-after.txt new file mode 100644 index 00000000..58ad062d --- /dev/null +++ b/docs/results/streaming-pr-review/2026-09-13/pointer-after.txt @@ -0,0 +1,18 @@ +goos: darwin +goarch: arm64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: Apple M4 Pro +BenchmarkEntryBatchTransactions/tx_4-12 8466316 31.27 ns/op 32 B/op 1 allocs/op +BenchmarkEntryBatchTransactions/tx_4-12 10608848 22.30 ns/op 32 B/op 1 allocs/op +BenchmarkEntryBatchTransactions/tx_4-12 12435661 27.76 ns/op 32 B/op 1 allocs/op +BenchmarkEntryBatchTransactions/tx_49-12 1330062 164.0 ns/op 416 B/op 1 allocs/op +BenchmarkEntryBatchTransactions/tx_49-12 1898496 118.3 ns/op 416 B/op 1 allocs/op +BenchmarkEntryBatchTransactions/tx_49-12 1431538 229.4 ns/op 416 B/op 1 allocs/op +BenchmarkEntryBatchTransactions/tx_269-12 375474 781.9 ns/op 2304 B/op 1 allocs/op +BenchmarkEntryBatchTransactions/tx_269-12 463562 532.6 ns/op 2304 B/op 1 allocs/op +BenchmarkEntryBatchTransactions/tx_269-12 549596 454.2 ns/op 2304 B/op 1 allocs/op +BenchmarkEntryBatchTransactions/tx_33760-12 5101 42209 ns/op 270336 B/op 1 allocs/op +BenchmarkEntryBatchTransactions/tx_33760-12 5328 44019 ns/op 270336 B/op 1 allocs/op +BenchmarkEntryBatchTransactions/tx_33760-12 4857 46700 ns/op 270336 B/op 1 allocs/op +PASS +ok github.com/Overclock-Validator/mithril/pkg/turbine 3.425s diff --git a/docs/results/streaming-pr-review/2026-09-13/pointer-before.txt b/docs/results/streaming-pr-review/2026-09-13/pointer-before.txt new file mode 100644 index 00000000..74a4218d --- /dev/null +++ b/docs/results/streaming-pr-review/2026-09-13/pointer-before.txt @@ -0,0 +1,18 @@ +goos: darwin +goarch: arm64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: Apple M4 Pro +BenchmarkEntryBatchTransactions/tx_4-12 5438229 44.07 ns/op 56 B/op 3 allocs/op +BenchmarkEntryBatchTransactions/tx_4-12 5468454 44.47 ns/op 56 B/op 3 allocs/op +BenchmarkEntryBatchTransactions/tx_4-12 5464107 43.92 ns/op 56 B/op 3 allocs/op +BenchmarkEntryBatchTransactions/tx_49-12 938340 278.3 ns/op 1016 B/op 7 allocs/op +BenchmarkEntryBatchTransactions/tx_49-12 866556 282.0 ns/op 1016 B/op 7 allocs/op +BenchmarkEntryBatchTransactions/tx_49-12 867691 277.3 ns/op 1016 B/op 7 allocs/op +BenchmarkEntryBatchTransactions/tx_269-12 243710 969.2 ns/op 4472 B/op 9 allocs/op +BenchmarkEntryBatchTransactions/tx_269-12 239790 974.8 ns/op 4472 B/op 9 allocs/op +BenchmarkEntryBatchTransactions/tx_269-12 251006 977.0 ns/op 4472 B/op 9 allocs/op +BenchmarkEntryBatchTransactions/tx_33760-12 1576 145701 ns/op 1301628 B/op 23 allocs/op +BenchmarkEntryBatchTransactions/tx_33760-12 1692 145071 ns/op 1301624 B/op 23 allocs/op +BenchmarkEntryBatchTransactions/tx_33760-12 1538 148765 ns/op 1301624 B/op 23 allocs/op +PASS +ok github.com/Overclock-Validator/mithril/pkg/turbine 3.467s diff --git a/docs/results/streaming-pr-review/2026-09-13/run-native.sh b/docs/results/streaming-pr-review/2026-09-13/run-native.sh new file mode 100644 index 00000000..003c6f06 --- /dev/null +++ b/docs/results/streaming-pr-review/2026-09-13/run-native.sh @@ -0,0 +1,19 @@ +set -eu +review_dir=/srv/mithril-streaming-pr-review-20260913 +mkdir "$review_dir" +tar -xzf /tmp/mithril-streaming-pr-review-20260913.tar.gz -C "$review_dir" +cd "$review_dir" +export PATH=/usr/local/go/bin:$PATH +export GOMAXPROCS=8 +mkdir review-results +sha256sum /tmp/mithril-streaming-pr-review-20260913.tar.gz > review-results/source-sha256.txt +systemctl show mithril-alpenglow-pr259.service -p MainPID -p ActiveState > review-results/service-before.txt +nice -n 10 go test -race ./pkg/turbine ./pkg/replay ./pkg/sigverify ./pkg/txverify ./pkg/block ./pkg/statsd ./cmd/mithril/node > review-results/native-race.txt 2>&1 +nice -n 10 go vet ./pkg/turbine ./pkg/replay ./pkg/sigverify ./pkg/txverify ./pkg/block ./pkg/statsd ./cmd/mithril/node > review-results/native-vet.txt 2>&1 +nice -n 10 go build -o review-results/mithril ./cmd/mithril > review-results/native-build.txt 2>&1 +nice -n 10 go test -c -o review-results/turbine.test ./pkg/turbine +MITHRIL_SIGVERIFY_FLOW_BACKEND=r51 nice -n 10 taskset -c 0-7 review-results/turbine.test -test.run='^$' -test.bench='^BenchmarkEntryPrefetchAssembly$/^generated_.*$/^workers_2$/^target_8$/.*' -test.benchtime=3x -test.count=1 > review-results/native-assembly.txt 2>&1 +systemctl show mithril-alpenglow-pr259.service -p MainPID -p ActiveState > review-results/service-after.txt +sha256sum review-results/mithril review-results/turbine.test > review-results/binaries-sha256.txt +cat review-results/native-race.txt +cat review-results/native-assembly.txt diff --git a/docs/results/streaming-pr-review/2026-09-13/service-after.txt b/docs/results/streaming-pr-review/2026-09-13/service-after.txt new file mode 100644 index 00000000..bece5e70 --- /dev/null +++ b/docs/results/streaming-pr-review/2026-09-13/service-after.txt @@ -0,0 +1,2 @@ +ActiveState=active +MainPID=3846480 diff --git a/docs/results/streaming-pr-review/2026-09-13/service-before.txt b/docs/results/streaming-pr-review/2026-09-13/service-before.txt new file mode 100644 index 00000000..bece5e70 --- /dev/null +++ b/docs/results/streaming-pr-review/2026-09-13/service-before.txt @@ -0,0 +1,2 @@ +ActiveState=active +MainPID=3846480 diff --git a/docs/results/streaming-pr-review/2026-09-13/source-sha256.txt b/docs/results/streaming-pr-review/2026-09-13/source-sha256.txt new file mode 100644 index 00000000..91ac36a0 --- /dev/null +++ b/docs/results/streaming-pr-review/2026-09-13/source-sha256.txt @@ -0,0 +1 @@ +439fbf1b4313cb5aa9c98adb40d9e790346dace262441f5477e0486040e030c9 /tmp/mithril-streaming-pr-review-20260913.tar.gz diff --git a/docs/transaction_sigverify_streaming.md b/docs/transaction_sigverify_streaming.md index 8b555088..3baee788 100644 --- a/docs/transaction_sigverify_streaming.md +++ b/docs/transaction_sigverify_streaming.md @@ -116,3 +116,7 @@ The subsequent [direct cache-comparison report](results/sigverify-direct-cache/2 isolates the removal of redundant component-buffer construction at completion. The [completion follow-up report](results/completion-followup/2026-09-12-zen5/README.md) measures direct ordering, authenticated-root reuse, and the four-vector job policy. + +The [standalone PR review](results/streaming-pr-review/2026-09-13/README.md) +records extraction onto current `alpenglow-dev`, the small shared component-boundary +prerequisite, final allocation improvement, and the scope of the live trial. From d0cf70b602570a7a427ca0e95de5c59a50f1f9dc Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Mon, 14 Sep 2026 15:47:00 -0500 Subject: [PATCH 009/183] Avoid redundant shred retention sweeps at an unchanged frontier --- pkg/turbine/assembler.go | 85 +++++++++++------ pkg/turbine/retention_sweep_test.go | 137 ++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+), 27 deletions(-) create mode 100644 pkg/turbine/retention_sweep_test.go diff --git a/pkg/turbine/assembler.go b/pkg/turbine/assembler.go index cd9dd8cc..dc8c69db 100644 --- a/pkg/turbine/assembler.go +++ b/pkg/turbine/assembler.go @@ -43,20 +43,26 @@ const ( ) type SlotAssembler struct { - mu sync.Mutex - slots map[uint64]*slotState - completedSlots map[uint64]struct{} - knownBlockIDs map[uint64]solana.Hash - rejectedBlockIDs map[uint64]map[solana.Hash]struct{} - protectedKnownIDs map[uint64]struct{} - protectedBlockIDs map[uint64]struct{} - priorityRepairSlots map[uint64]struct{} - priorityRepairOrder []uint64 - encoders map[fecLayout]reedsolomon.Encoder - partialShredObs map[uint64]PartialShredObservation // shreds seen for slots that never became full (retained for skip observability) - retentionFloor uint64 // when non-zero, slots >= floor are never "too old" (repair catchup holds a window far behind the live edge) - edgeScanLag uint64 // how far behind the shred edge the freshness-repair scan reaches (0 = repairScanSlotWindow) - maxObservedSlot uint64 + mu sync.Mutex + slots map[uint64]*slotState + completedSlots map[uint64]struct{} + knownBlockIDs map[uint64]solana.Hash + rejectedBlockIDs map[uint64]map[solana.Hash]struct{} + protectedKnownIDs map[uint64]struct{} + protectedBlockIDs map[uint64]struct{} + priorityRepairSlots map[uint64]struct{} + priorityRepairOrder []uint64 + encoders map[fecLayout]reedsolomon.Encoder + partialShredObs map[uint64]PartialShredObservation // shreds seen for slots that never became full (retained for skip observability) + retentionFloor uint64 // when non-zero, slots >= floor are never "too old" (repair catchup holds a window far behind the live edge) + edgeScanLag uint64 // how far behind the shred edge the freshness-repair scan reaches (0 = repairScanSlotWindow) + maxObservedSlot uint64 + // Age sweeps depend on the edge, repair floor, and mutations that can add + // old metadata or release a completing generation's protected identities. + retentionSwept bool + retentionDirty bool + retentionSweepEdge uint64 + retentionSweepFloor uint64 highestFullSlot uint64 // monotonic: highest slot reconstructed from shreds ("full", Agave SlotMeta/is_full sense) recoveredDataShreds uint64 usefulRepairShreds uint64 // distinct data shreds delivered BY repair (the throughput signal) @@ -189,6 +195,7 @@ func (a *SlotAssembler) recordPartialObsLocked(state *slotState) { if state == nil || len(state.shreds) == 0 { return } + a.retentionDirty = true a.partialShredObs[state.slot] = PartialShredObservation{ DataShreds: len(state.shreds), RepairedShreds: state.repairedShreds, @@ -365,6 +372,7 @@ func (a *SlotAssembler) abortCompletion(work *slotCompletionWork) { } a.mu.Lock() if a.slots[work.state.slot] == work.state && work.state.completing { + a.retentionDirty = true work.state.completing = false } a.mu.Unlock() @@ -456,6 +464,8 @@ func (a *SlotAssembler) finalizeCompletion(work *slotCompletionWork, processed p a.mu.Unlock() return nil, nil } + // Every terminal outcome releases this generation's retention protection. + a.retentionDirty = true if processed.canceled { state.completing = false a.mu.Unlock() @@ -553,6 +563,9 @@ func (a *SlotAssembler) SetKnownAlpenglowBlockID(slot uint64, blockID solana.Has if _, rejected := a.rejectedBlockIDs[slot][blockID]; rejected { return } + if _, exists := a.knownBlockIDs[slot]; !exists { + a.retentionDirty = true + } a.knownBlockIDs[slot] = blockID } @@ -573,6 +586,7 @@ func (a *SlotAssembler) RejectAlpenglowBlockID(slot uint64, blockID solana.Hash) if ids == nil { ids = make(map[solana.Hash]struct{}) a.rejectedBlockIDs[slot] = ids + a.retentionDirty = true } ids[blockID] = struct{}{} if a.knownBlockIDs[slot] == blockID { @@ -584,6 +598,7 @@ func (a *SlotAssembler) ResetSlot(slot uint64) { a.mu.Lock() defer a.mu.Unlock() + a.retentionDirty = true a.recordPartialObsLocked(a.slots[slot]) a.releasePrefetchLocked(a.slots[slot]) delete(a.slots, slot) @@ -679,6 +694,32 @@ func (a *SlotAssembler) slotTooOldLocked(slot uint64) bool { } func (a *SlotAssembler) pruneOldSlotsLocked() { + if !a.retentionSwept || a.retentionDirty || a.retentionSweepEdge != a.maxObservedSlot || a.retentionSweepFloor != a.retentionFloor { + a.sweepRetentionMapsLocked() + a.retentionSwept = true + a.retentionDirty = false + a.retentionSweepEdge = a.maxObservedSlot + a.retentionSweepFloor = a.retentionFloor + } + // New incomplete generations can exceed the cap without advancing the + // edge (especially during catch-up). Never cache the capacity check. + + if len(a.slots) == 0 { + return + } + for len(a.slots) > maxRetainedIncompleteSlotCap { + victim, ok := a.capEvictionCandidateLocked() + if !ok { + return + } + a.recordPartialObsLocked(a.slots[victim]) + a.releasePrefetchLocked(a.slots[victim]) + delete(a.slots, victim) + a.evictedSlots++ + } +} + +func (a *SlotAssembler) sweepRetentionMapsLocked() { if len(a.slots) > 0 && a.maxObservedSlot > maxRetainedIncompleteSlotLag { minSlot := a.maxObservedSlot - maxRetainedIncompleteSlotLag if a.retentionFloor > 0 && a.retentionFloor < minSlot { @@ -731,19 +772,6 @@ func (a *SlotAssembler) pruneOldSlotsLocked() { } a.prunePriorityRepairSlotsLocked() - if len(a.slots) == 0 { - return - } - for len(a.slots) > maxRetainedIncompleteSlotCap { - victim, ok := a.capEvictionCandidateLocked() - if !ok { - return - } - a.recordPartialObsLocked(a.slots[victim]) - a.releasePrefetchLocked(a.slots[victim]) - delete(a.slots, victim) - a.evictedSlots++ - } } // capEvictionCandidateLocked chooses state furthest ahead of replay, rather @@ -1064,6 +1092,9 @@ func (a *SlotAssembler) trackBlockIDLocked(blk *block.Block) { if known, ok := a.knownBlockIDs[blk.Slot]; ok && known != (solana.Hash{}) && known != blockID { return } + if _, exists := a.knownBlockIDs[blk.Slot]; !exists { + a.retentionDirty = true + } a.knownBlockIDs[blk.Slot] = blockID } diff --git a/pkg/turbine/retention_sweep_test.go b/pkg/turbine/retention_sweep_test.go new file mode 100644 index 00000000..84064046 --- /dev/null +++ b/pkg/turbine/retention_sweep_test.go @@ -0,0 +1,137 @@ +package turbine + +import ( + "errors" + "testing" + + "github.com/Overclock-Validator/mithril/pkg/block" + "github.com/gagliardetto/solana-go" + "github.com/stretchr/testify/require" +) + +func sweepForTest(a *SlotAssembler) { + a.mu.Lock() + a.pruneOldSlotsLocked() + a.mu.Unlock() +} + +func TestRetentionSweepFloorMovesWithoutNewShreds(t *testing.T) { + a := NewSlotAssembler() + a.maxObservedSlot = 10000 + a.SetRetentionFloor(1000) + a.slots[1000] = &slotState{slot: 1000} + a.slots[1001] = &slotState{slot: 1001} + a.completedSlots[1001] = struct{}{} + a.SetKnownAlpenglowBlockID(1001, solana.Hash{1}) + a.PrioritizeRepairSlot(1000) + sweepForTest(a) + require.Contains(t, a.slots, uint64(1000)) + a.SetRetentionFloor(1001) + sweepForTest(a) + require.NotContains(t, a.slots, uint64(1000)) + require.NotContains(t, a.priorityRepairSlots, uint64(1000)) + require.Contains(t, a.slots, uint64(1001)) + a.SetRetentionFloor(0) + sweepForTest(a) + require.Empty(t, a.slots) + require.Empty(t, a.completedSlots) + require.Empty(t, a.knownBlockIDs) + + // Lowering the floor must permit new old repair state again. + a.SetRetentionFloor(1000) + a.slotState(1000, 1) + sweepForTest(a) + require.Contains(t, a.slots, uint64(1000)) +} + +func TestRetentionSweepReleasesCompletingProtectionAtFixedEdge(t *testing.T) { + for _, outcome := range []string{"abort", "cancel", "error", "complete", "reset"} { + t.Run(outcome, func(t *testing.T) { + a := NewSlotAssembler() + a.maxObservedSlot = 10000 + s := &slotState{slot: 1000, parentSlot: 999, completing: true, shreds: map[uint32]*Shred{0: {}}} + a.slots[s.slot] = s + a.SetKnownAlpenglowBlockID(999, solana.Hash{1}) + a.SetKnownAlpenglowBlockID(1000, solana.Hash{2}) + a.RejectAlpenglowBlockID(1000, solana.Hash{3}) + sweepForTest(a) + require.Contains(t, a.slots, uint64(1000)) + require.Contains(t, a.knownBlockIDs, uint64(999)) + require.Contains(t, a.rejectedBlockIDs, uint64(1000)) + work := &slotCompletionWork{state: s} + switch outcome { + case "abort": + a.abortCompletion(work) + case "cancel": + _, err := a.finalizeCompletion(work, processedSlotCompletion{canceled: true}) + require.NoError(t, err) + case "error": + _, err := a.finalizeCompletion(work, processedSlotCompletion{err: errors.New("decode failure")}) + require.Error(t, err) + case "complete": + _, err := a.finalizeCompletion(work, processedSlotCompletion{block: &block.Block{Slot: 1000}}) + require.NoError(t, err) + case "reset": + a.ResetSlot(1000) + } + sweepForTest(a) + require.Empty(t, a.slots) + require.Empty(t, a.completedSlots) + require.Empty(t, a.knownBlockIDs) + require.Empty(t, a.rejectedBlockIDs) + require.Empty(t, a.partialShredObs) + }) + } +} + +func TestRetentionSweepOldHintsAddedAtFixedEdge(t *testing.T) { + a := NewSlotAssembler() + a.maxObservedSlot = 10000 + sweepForTest(a) + a.SetKnownAlpenglowBlockID(1000, solana.Hash{1}) + a.RejectAlpenglowBlockID(1001, solana.Hash{2}) + sweepForTest(a) + require.Empty(t, a.knownBlockIDs) + require.Empty(t, a.rejectedBlockIDs) + a.mu.Lock() + a.trackBlockIDLocked(&block.Block{Slot: 1002, HasAlpenglowBlockID: true, AlpenglowBlockID: solana.Hash{3}}) + a.mu.Unlock() + sweepForTest(a) + require.Empty(t, a.knownBlockIDs) +} + +func TestRetentionSweepCapacityAtFixedEdge(t *testing.T) { + a := NewSlotAssembler() + a.maxObservedSlot = 10000 + a.SetRetentionFloor(1000) + a.PrioritizeRepairSlot(1001) + sweepForTest(a) + for i := 0; i < maxRetainedIncompleteSlotCap+2; i++ { + a.slotState(1000+uint64(i), 1) + } + sweepForTest(a) + require.Len(t, a.slots, maxRetainedIncompleteSlotCap) + require.Contains(t, a.slots, uint64(1000)) + require.Contains(t, a.slots, uint64(1001)) + require.NotContains(t, a.slots, uint64(1000+maxRetainedIncompleteSlotCap+1)) +} + +func BenchmarkRetentionRepeatedCompletedShred(b *testing.B) { + a := NewSlotAssembler() + a.maxObservedSlot = 10000 + for slot := uint64(9488); slot <= 10000; slot++ { + a.completedSlots[slot] = struct{}{} + a.knownBlockIDs[slot] = solana.Hash{1} + a.rejectedBlockIDs[slot] = map[solana.Hash]struct{}{{2}: {}} + a.partialShredObs[slot] = PartialShredObservation{DataShreds: 1} + } + sh := &Shred{Slot: 10000, Type: ShredTypeData} + // The public ingestion path still acquires the lock and performs its + // ordinary completed-slot rejection on every packet. + _, _ = a.AddShred(sh) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = a.AddShred(sh) + } +} From 331ce3fa7faa657b8437a665f41ee1f5396132d4 Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Mon, 14 Sep 2026 15:59:33 -0500 Subject: [PATCH 010/183] Document retention benchmark and post-deployment FAST measurements --- docs/shred_retention_performance.md | 61 +++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 docs/shred_retention_performance.md diff --git a/docs/shred_retention_performance.md b/docs/shred_retention_performance.md new file mode 100644 index 00000000..7c54dc01 --- /dev/null +++ b/docs/shred_retention_performance.md @@ -0,0 +1,61 @@ +# Shred retention sweep scheduling + +`SlotAssembler` previously scanned its incomplete/completed slots, block-ID hints, +rejected IDs, partial observations, and priority repair state on every incoming +shred, including duplicates and completed-slot packets. The new schedule skips +age sweeps when neither the observed edge nor the retention floor nor relevant +retained state has changed. The original sweep algorithm and age limits remain. + +Mutations invalidate the cached sweep after adding old identity hints or partial +observations, resetting a generation, or terminating completion. Completion +success, error, cancellation and abort all release protected parent-ID state. +Repair-floor advancement, reduction and clearing are checked on the next packet. +The hard incomplete-slot capacity check remains unconditional on every packet, +including catch-up insertion at an unchanged edge. Eviction preference and +protection for completing generations and the repair head are unchanged. + +Regression coverage includes changing the repair floor without advancing the +edge, every terminal completion outcome, newly added old identity hints, and +capacity overflow at a fixed edge. Existing completion, cancellation, generation, +FEC and repair tests also run as part of the full Turbine suite. + +## Isolated benchmark + +`BenchmarkRetentionRepeatedCompletedShred` drives the public `AddShred` path +with a completed-slot packet and 513 retained entries in each of four metadata +maps. It measures the repeated scan/rejection case, not full packet decoding, +authentication, FEC, replay, or a whole-validator speedup. Five 500 ms runs: + +| Host | Baseline median | Candidate median | Allocation | +| --- | ---: | ---: | ---: | +| Apple M4 Pro | 11,617 ns/packet | 7.718 ns/packet | 0 on both | +| Ryzen 7 9700X, GOMAXPROCS=2 | 11,443 ns/packet | 12.99 ns/packet | 0 on both | + +Baseline and candidate use the same fixture; Go's source overlay selects the old +assembler for baseline runs without changing other source. This fixture shows the +avoided work, not a prediction for a validator's actual map population. + +Validation passed locally and natively: race suites for Turbine, replay, +consensus and node; Turbine vet; complete validator build. The live integration +applies this patch over the exact deployed FEC/peer-isolation/status-expiry source. + +## Initial live trial + +Deployed on the Ryzen 7 9700X at 20:47:35 UTC on September 14. A bounded +30-second post-deployment CPU profile recorded no retention-sweep samples, +compared with 7.66% of sampled CPU in the preceding profile. These are different +live workloads; absence of samples does not mean zero cost. + +After excluding startup and extra profiling, local FAST inclusion was +1,381/1,408 (98.08%) across about 7.4 minutes, compared with 3,646/3,792 (96.15%) +in the prior 20-minute sample. For >=10,000-transaction targets it was 168/190 +(88.42%) versus 375/509 (73.67%). These are selected observed FAST certificates, +not all blocks or reward opportunities. Different leaders/workloads, network +variation and restart connection refresh prevent assigning the entire change to +this optimization. All 27 remaining omissions had locally observed notarize +votes; local serialization does not establish remote delivery. + +Voting remained current, with all 87 desired peers connected and no transport +queue drops/send errors/timeouts or safety/history/fold faults in the reviewed +run. Continuous load produced all 28 blocks in seven completed own-leader +windows. The validator and automatic load/monitor services were left running. From 314c48c9e55f7fbbf052ed1ef983050f7691a123 Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Mon, 14 Sep 2026 16:21:58 -0500 Subject: [PATCH 011/183] Prepare transaction message identities during shred arrival --- docs/streaming_message_identities.md | 83 ++++++++++++++ pkg/block/verified_message_identity.go | 37 +++++++ pkg/block/verified_message_identity_test.go | 42 +++++++ pkg/turbine/entry_prefetch.go | 33 +++++- pkg/turbine/entry_prefetch_benchmark_test.go | 37 ++++++- .../streaming_message_identity_test.go | 104 ++++++++++++++++++ pkg/turbine/transaction_verifier.go | 46 ++++++-- pkg/txstatus/message_identity.go | 9 +- pkg/txverify/message_identity.go | 25 +++++ pkg/txverify/message_identity_test.go | 70 ++++++++++++ pkg/txverify/txverify.go | 32 ++++++ 11 files changed, 505 insertions(+), 13 deletions(-) create mode 100644 docs/streaming_message_identities.md create mode 100644 pkg/block/verified_message_identity.go create mode 100644 pkg/block/verified_message_identity_test.go create mode 100644 pkg/turbine/streaming_message_identity_test.go create mode 100644 pkg/txverify/message_identity.go create mode 100644 pkg/txverify/message_identity_test.go diff --git a/docs/streaming_message_identities.md b/docs/streaming_message_identities.md new file mode 100644 index 00000000..7d7d074e --- /dev/null +++ b/docs/streaming_message_identities.md @@ -0,0 +1,83 @@ +# Prepare transaction message identities during shred arrival + +The live Zen 5 admission trace found ~12.45 ms of message serialization, +hashing and identity-cache preparation after assembly on large blocks, followed +by ~1.66 ms of same-block duplicate-plan work. Most blocks reached this stage +while replay was already waiting. + +Turbine now asks signature-verification workers to retain a message identity +derived from the exact canonical bytes they already serialize for verification. +The existing two workers process available groups without waiting for more +transactions. TPU callers of the ordinary verifier do not compute these extra +identities. + +Each opaque result binds a successful signature verdict to the transaction +pointer, message version and recent blockhash. Completion joins requests and +imports only identities covering the final ordered transaction slice. Canceled +requests are reverified; discarded UpdateParent prefixes are excluded. Results +are caller-owned and cannot refer to reusable verifier scratch. The block cache +owns its imported storage and remains nonserialized. The existing requirement +that signed message contents remain immutable still applies; arbitrary in-place +message edits require invalidation, as before. + +Same-block duplicate rejection and mutable ancestor/status checks remain in +place. This change does not cache the duplicate-check plan or alter epoch +processing, vote persistence, worker counts, scheduling deadlines, or packing. + +## Zen 5 comparison + +Baseline: the currently deployed shred-retention source, including its existing +FEC and peer-isolation integrations. Candidate: that same source plus streaming +identities. Both binaries use the identical new benchmark harness. + +`BenchmarkEntryMessageIdentityArrival` feeds real generated data shreds through +the assembler, entry prefetch and signature-verification pipeline, then includes +the admission-time identity lookup. Each block has 33,760 single-signature +transactions, either 228 or 1,232 bytes on the wire. The tip model schedules +component arrivals across 200 ms; catchup offers every shred immediately. +Fixture construction, packet parsing and shred-signature authentication are +outside the timer. There is no network loss, transaction execution, PoH/reward +processing or final whole-block duplicate map in this benchmark. + +AMD Ryzen 7 9700X, Narya `r51` AVX-512 backend, two signature workers, target eight +signature lanes, GOMAXPROCS=16. Five iterations per scenario per run, two runs +per variant in baseline/candidate/candidate/baseline order. Values below are the +median of the two run medians, not a percentile computed over all ten samples. +The live validator and load services continued running, so host contention can +affect the results. + +| Arrival model | Transaction size | Last shred → identities available, baseline | Candidate | +| --- | ---: | ---: | ---: | +| Over 200 ms | 228 bytes | 13.62 ms | 2.66 ms | +| Over 200 ms | 1,232 bytes | 73.72 ms | 7.81 ms | +| Catchup | 228 bytes | 92.90 ms | 88.40 ms | +| Catchup | 1,232 bytes | 154.75 ms | 118.20 ms | + +The table includes completion work; it does not merely move that work out of +the admission timer. Admission's identity lookup alone falls from ~12.1 to +0.24 ms for 228-byte tip transactions and ~66.9 to 0.26 ms for maximum-size tip +transactions. The block-wide duplicate check remains additional work. + +CPU time per tip block was 189.75→197.20 ms for the small fixture (~4% higher) +and 316.40→304.80 ms for the maximum-size fixture (~4% lower). The intended gain +is less work after arrival, not a blanket claim of lower CPU. Maximum-size +fixtures allocate roughly 37 MB fewer bytes per block by avoiding a second +message serialization; retaining opaque identities also has a memory cost. + +The initial runs without an explicit backend used the library's unconfigured +default and are excluded from these deployment-relevant results. + +## Validation and current limits + +Local affected-package tests, race tests for txverify/block/turbine/replay, Go +vet, and a full validator build passed. Tests cover legacy/v0/v1 canonical +identities, failed signatures, scratch reuse, pointer/order/blockhash mismatch, +storage ownership, JSON round-trips, early preparation and mixed canceled-batch +fallback. Existing turbine tests cover invalid and discarded prefixes and +completion cancellation. + +The benchmarked candidate passed native Zen 5 race tests. A subsequent explicit +per-batch length guard and two additional ownership/fallback tests passed the +final local race suite. Automatic approval review blocked uploading those final +source/test updates; final-revision native verification is still pending. No +new binary has been deployed and no live FAST improvement is claimed. diff --git a/pkg/block/verified_message_identity.go b/pkg/block/verified_message_identity.go new file mode 100644 index 00000000..9eff1d26 --- /dev/null +++ b/pkg/block/verified_message_identity.go @@ -0,0 +1,37 @@ +package block + +import ( + "fmt" + + "github.com/Overclock-Validator/mithril/pkg/txstatus" + "github.com/Overclock-Validator/mithril/pkg/txverify" + "github.com/gagliardetto/solana-go" +) + +// CacheVerifiedTransactionMessageIdentities publishes identities from joined +// signature-verification requests. Every result must cover the exact ordered +// transaction slice. Failed/partial requests and obsolete prefetch generations +// cannot seed the cache. It does not replace block-wide duplicate/status checks. +func (b *Block) CacheVerifiedTransactionMessageIdentities(identities []txverify.VerifiedMessageIdentity) error { + if b == nil || len(identities) != len(b.Transactions) { + return fmt.Errorf("verified message identities do not cover block transactions") + } + prepared := &PreparedTransactionMessageIdentities{ + transactions: append([]*solana.Transaction(nil), b.Transactions...), + versions: make([]solana.MessageVersion, len(identities)), + identities: make([]txstatus.TransactionMessageIdentity, len(identities)), + } + for i, tx := range b.Transactions { + identity, ok := identities[i].ForTransaction(tx) + if !ok { + return fmt.Errorf("verified message identity does not match transaction %d", i) + } + prepared.versions[i] = tx.Message.GetVersion() + prepared.identities[i] = identity + } + state := b.transactionState() + state.mu.Lock() + defer state.mu.Unlock() + state.messageIdentities = prepared + return nil +} diff --git a/pkg/block/verified_message_identity_test.go b/pkg/block/verified_message_identity_test.go new file mode 100644 index 00000000..c82d5a4d --- /dev/null +++ b/pkg/block/verified_message_identity_test.go @@ -0,0 +1,42 @@ +package block + +import ( + "crypto/ed25519" + "encoding/json" + "testing" + + "github.com/Overclock-Validator/mithril/pkg/txverify" + "github.com/gagliardetto/solana-go" + "github.com/stretchr/testify/require" +) + +func TestVerifiedIdentityCacheOwnsStorageAndDoesNotSerializeTrust(t *testing.T) { + tx := identityTestTransaction(1) + key := ed25519.NewKeyFromSeed(make([]byte, 32)) + tx.Message.AccountKeys[0] = solana.PublicKeyFromBytes(key.Public().(ed25519.PublicKey)) + msg, err := tx.Message.MarshalBinary() + require.NoError(t, err) + tx.Signatures[0] = solana.SignatureFromBytes(ed25519.Sign(key, msg)) + blk := &Block{Transactions: []*solana.Transaction{tx}} + ids := make([]txverify.VerifiedMessageIdentity, 1) + errs := make([]error, 1) + var verifier txverify.BatchVerifier + verifier.VerifyWithMessageIdentities(blk.Transactions, errs, ids) + require.NoError(t, errs[0]) + require.NoError(t, blk.CacheVerifiedTransactionMessageIdentities(ids)) + cached := blk.transactionDerivedState.messageIdentities + require.NotNil(t, cached, "adoption must populate the cache before the first admission lookup") + clear(ids) + got, err := blk.PrepareTransactionMessageIdentities() + require.NoError(t, err) + require.Same(t, cached, got) + copyBlock := *blk + got, err = copyBlock.PrepareTransactionMessageIdentities() + require.NoError(t, err) + require.Same(t, cached, got) + wire, err := json.Marshal(blk) + require.NoError(t, err) + var decoded Block + require.NoError(t, json.Unmarshal(wire, &decoded)) + require.Nil(t, decoded.transactionDerivedState) +} diff --git a/pkg/turbine/entry_prefetch.go b/pkg/turbine/entry_prefetch.go index 05171918..8159dfe7 100644 --- a/pkg/turbine/entry_prefetch.go +++ b/pkg/turbine/entry_prefetch.go @@ -3,10 +3,12 @@ package turbine import ( "context" "errors" + "fmt" "sync" "time" "github.com/Overclock-Validator/mithril/pkg/block" + "github.com/Overclock-Validator/mithril/pkg/txverify" "github.com/gagliardetto/solana-go" ) @@ -255,6 +257,7 @@ func verifyDecodedEntryBatches(ctx context.Context, blk *block.Block, batches [] type pending struct { future *transactionVerification offset int + count int } var early []pending var missing []*solana.Transaction @@ -276,7 +279,7 @@ func verifyDecodedEntryBatches(ctx context.Context, blk *block.Block, batches [] } } if reusable { - early = append(early, pending{b.verification, offset}) + early = append(early, pending{b.verification, offset, count}) } else { missing = append(missing, blk.Transactions[offset:offset+count]...) for i := 0; i < count; i++ { @@ -316,7 +319,33 @@ func verifyDecodedEntryBatches(ctx context.Context, blk *block.Block, batches [] if firstErr != nil && firstIndex < len(blk.Transactions) { return formatTransactionVerificationError(blk, firstIndex, firstErr) } - return firstErr + if firstErr != nil { + return firstErr + } + // Custom verification hooks do not produce trusted message identities. + // Preserve their existing lazy preparation path (primarily test fixtures). + if verifier.verify != nil { + return nil + } + if offset != len(blk.Transactions) { + return fmt.Errorf("entry identity coverage mismatch") + } + identities := make([]txverify.VerifiedMessageIdentity, len(blk.Transactions)) + for _, p := range early { + if len(p.future.identities) != p.count || p.offset+len(p.future.identities) > len(identities) { + return fmt.Errorf("entry identity range mismatch") + } + copy(identities[p.offset:], p.future.identities) + } + if fallback != nil { + if len(fallback.identities) != len(indices) { + return fmt.Errorf("fallback identity coverage mismatch") + } + for i, index := range indices { + identities[index] = fallback.identities[i] + } + } + return blk.CacheVerifiedTransactionMessageIdentities(identities) } func earlyEntryTimings(t *entryDecodeTimings, fullAt time.Time, timings *block.TurbineIngressTimings) { diff --git a/pkg/turbine/entry_prefetch_benchmark_test.go b/pkg/turbine/entry_prefetch_benchmark_test.go index 9b494b73..ee3443bf 100644 --- a/pkg/turbine/entry_prefetch_benchmark_test.go +++ b/pkg/turbine/entry_prefetch_benchmark_test.go @@ -46,7 +46,7 @@ func BenchmarkEntryPrefetchAssembly(b *testing.B) { name = "overlap_on" } b.Run(name, func(b *testing.B) { - runAssemblyFlowBenchmark(b, source.blk, fixture, workers, target, arrival.span, overlap) + runAssemblyFlowBenchmark(b, source.blk, fixture, workers, target, arrival.span, overlap, false) }) } }) @@ -133,7 +133,7 @@ func makeAssemblyFlowFixture(tb testing.TB, source *block.Block) assemblyFlowFix return fixture } -func runAssemblyFlowBenchmark(b *testing.B, source *block.Block, fixture assemblyFlowFixture, workers, target int, span time.Duration, overlap bool) { +func runAssemblyFlowBenchmark(b *testing.B, source *block.Block, fixture assemblyFlowFixture, workers, target int, span time.Duration, overlap, prepareIdentities bool) { v := newTransactionVerifierWithBatchTarget(workers, 2*workers*target, target, nil) defer v.closeAndWait() if err := v.verifyBlock(source); err != nil { @@ -147,7 +147,7 @@ func runAssemblyFlowBenchmark(b *testing.B, source *block.Block, fixture assembl prefetch := newEntryPrefetchPool(context.Background(), a, v) defer prefetch.closeAndWait() } - var ready, parse, preparation, joins, arrivals []time.Duration + var ready, parse, preparation, joins, arrivals, identityPreparation, fullToIdentities []time.Duration var early uint64 var cpu float64 before := sigverify.Stats() @@ -182,6 +182,12 @@ func runAssemblyFlowBenchmark(b *testing.B, source *block.Block, fixture assembl } processed := a.processCompletion(context.Background(), work) completed, err := a.finalizeCompletion(work, processed) + if prepareIdentities && err == nil && completed != nil { + start := time.Now() + _, err = completed.PrepareTransactionMessageIdentities() + identityPreparation = append(identityPreparation, time.Since(start)) + fullToIdentities = append(fullToIdentities, time.Since(work.state.fullAt)) + } b.StopTimer() cpu += flowCPUSeconds(b) - cpuStarted if err != nil || completed == nil { @@ -214,6 +220,10 @@ func runAssemblyFlowBenchmark(b *testing.B, source *block.Block, fixture assembl flowReportPercentiles(b, preparation, "preparation_wait") flowReportPercentiles(b, joins, "completion_sigverify") flowReportPercentiles(b, arrivals, "collection") + if prepareIdentities { + flowReportPercentiles(b, identityPreparation, "identity_admission") + flowReportPercentiles(b, fullToIdentities, "full_to_identities") + } if after.InternalFaultFallbacks != before.InternalFaultFallbacks { b.Fatal("signature verifier used an internal fault fallback") } @@ -225,3 +235,24 @@ func runAssemblyFlowBenchmark(b *testing.B, source *block.Block, fixture assembl b.Fatalf("verified %d signatures; want %d, exactly once per retained transaction", got, want) } } + +// BenchmarkEntryMessageIdentityArrival includes the first admission-time message +// identity lookup after assembly. Compare unchanged baseline and candidate with +// identical fixtures; full_to_identities includes any moved completion work. +// This does not include replay's whole-block duplicate map or transaction loop. +func BenchmarkEntryMessageIdentityArrival(b *testing.B) { + flowConfigureBackend(b) + for _, source := range flowBenchmarkFixtures(b) { + b.Run(source.name, func(b *testing.B) { + fixture := makeAssemblyFlowFixture(b, source.blk) + for _, arrival := range []struct { + name string + span time.Duration + }{{"catchup", 0}, {"tip_200ms", 200 * time.Millisecond}} { + b.Run(arrival.name, func(b *testing.B) { + runAssemblyFlowBenchmark(b, source.blk, fixture, 2, 8, arrival.span, true, true) + }) + } + }) + } +} diff --git a/pkg/turbine/streaming_message_identity_test.go b/pkg/turbine/streaming_message_identity_test.go new file mode 100644 index 00000000..4fce6deb --- /dev/null +++ b/pkg/turbine/streaming_message_identity_test.go @@ -0,0 +1,104 @@ +package turbine + +import ( + "context" + "testing" + + "github.com/Overclock-Validator/mithril/pkg/block" + "github.com/Overclock-Validator/mithril/pkg/txstatus" + "github.com/gagliardetto/solana-go" + "github.com/stretchr/testify/require" +) + +func TestMessageIdentitiesPreparedBeforeFinalShred(t *testing.T) { + v := newTransactionVerifier(2, 16, nil) + defer v.closeAndWait() + a := NewSlotAssembler() + p := newEntryPrefetchPool(context.Background(), a, v) + defer p.closeAndWait() + batches := prefetchTestShreds(t, 100, + prefetchTestPayload(t, verifierSignedTransactions(t, 3)), + prefetchTestPayload(t, verifierSignedTransactions(t, 4))) + require.Nil(t, feedPrefetchShreds(t, a, batches[0])) + cached := waitPrefetchedBatch(t, a, 100, 0) + _, err := cached.verification.wait() + require.NoError(t, err) + require.Len(t, cached.verification.identities, 3) + for i := range cached.entries[0].Txns { + tx := &cached.entries[0].Txns[i] + got, ok := cached.verification.identities[i].ForTransaction(tx) + require.True(t, ok) + want, err := txstatus.IdentityForTransaction(tx) + require.NoError(t, err) + require.Equal(t, want, got) + } + blk := feedPrefetchShreds(t, a, batches[1]) + require.NotNil(t, blk) + prepared, err := blk.PrepareTransactionMessageIdentities() + require.NoError(t, err) + for i, tx := range blk.Transactions { + want, err := txstatus.IdentityForTransaction(tx) + require.NoError(t, err) + require.Equal(t, want, prepared.Identity(i)) + } +} + +func TestVerifiedIdentityCacheRejectsMismatchedAndPartialCoverage(t *testing.T) { + v := newTransactionVerifier(2, 16, nil) + defer v.closeAndWait() + txs := verifierSignedTransactions(t, 3) + request, err := v.submitTransactions(context.Background(), txs) + require.NoError(t, err) + _, err = request.wait() + require.NoError(t, err) + blk := &block.Block{Transactions: txs} + require.NoError(t, blk.CacheVerifiedTransactionMessageIdentities(request.identities)) + prepared, err := blk.PrepareTransactionMessageIdentities() + require.NoError(t, err) + require.Error(t, blk.CacheVerifiedTransactionMessageIdentities(request.identities[:2])) + copyTx := *txs[0] + for _, changed := range [][]*solana.Transaction{{txs[1], txs[0], txs[2]}, {©Tx, txs[1], txs[2]}} { + other := &block.Block{Transactions: changed} + require.Error(t, other.CacheVerifiedTransactionMessageIdentities(request.identities)) + } + again, err := blk.PrepareTransactionMessageIdentities() + require.NoError(t, err) + require.Same(t, prepared, again, "failed cache adoption must not replace a valid cache") + txs[0].Message.RecentBlockhash[0] ^= 1 + require.Error(t, blk.CacheVerifiedTransactionMessageIdentities(request.identities)) +} + +func TestMessageIdentityFallbackPreservesRetainedTransactionOrder(t *testing.T) { + v := newTransactionVerifier(2, 16, nil) + defer v.closeAndWait() + a := NewSlotAssembler() + p := newEntryPrefetchPool(context.Background(), a, v) + defer p.closeAndWait() + batches := prefetchTestShreds(t, 100, + prefetchTestPayload(t, verifierSignedTransactions(t, 3)), + prefetchTestPayload(t, verifierSignedTransactions(t, 4)), + prefetchTestPayload(t, verifierSignedTransactions(t, 5))) + for i := 0; i < 2; i++ { + require.Nil(t, feedPrefetchShreds(t, a, batches[i])) + cached := waitPrefetchedBatch(t, a, 100, batches[i][0].Index) + _, err := cached.verification.wait() + require.NoError(t, err) + if i == 1 { + // Force a canceled, joined result in the middle of the retained + // sequence. Completion must reverify and scatter its identities. + done := make(chan struct{}) + close(done) + cached.verification = &transactionVerification{done: done, err: context.Canceled, index: -1, cancel: func() {}} + } + } + blk := feedPrefetchShreds(t, a, batches[2]) + require.NotNil(t, blk) + require.Len(t, blk.Transactions, 12) + prepared, err := blk.PrepareTransactionMessageIdentities() + require.NoError(t, err) + for i, tx := range blk.Transactions { + want, err := txstatus.IdentityForTransaction(tx) + require.NoError(t, err) + require.Equal(t, want, prepared.Identity(i)) + } +} diff --git a/pkg/turbine/transaction_verifier.go b/pkg/turbine/transaction_verifier.go index 6dfb5507..bf176a20 100644 --- a/pkg/turbine/transaction_verifier.go +++ b/pkg/turbine/transaction_verifier.go @@ -24,11 +24,12 @@ const defaultTransactionJobGroups = 4 // A job is formed before admission, from transactions which are already // available. Workers never wait for more transactions to fill a vector group. type transactionVerifyJob struct { - ctx context.Context - txs []*solana.Transaction - errs []error - start int - done chan<- *transactionVerifyJob + ctx context.Context + txs []*solana.Transaction + identities []txverify.VerifiedMessageIdentity + errs []error + start int + done chan<- *transactionVerifyJob } // transactionVerification owns an asynchronous request until done closes. @@ -39,6 +40,7 @@ type transactionVerification struct { index int err error finishedAt time.Time + identities []txverify.VerifiedMessageIdentity } func (r *transactionVerification) wait() (int, error) { @@ -149,7 +151,11 @@ func (v *transactionVerifier) verifyGroup(job *transactionVerifyJob, batch *txve } } } else { - verifyBatchSafely(batch, job.txs[start:end], job.errs[start:end]) + if job.identities != nil { + verifyBatchWithIdentitiesSafely(batch, job.txs[start:end], job.errs[start:end], job.identities[start:end]) + } else { + verifyBatchSafely(batch, job.txs[start:end], job.errs[start:end]) + } } start = end } @@ -184,11 +190,14 @@ func (v *transactionVerifier) submitTransactions(ctx context.Context, txs []*sol v.mu.Unlock() ctx, cancel := context.WithCancel(ctx) r := &transactionVerification{done: make(chan struct{}), cancel: cancel, index: -1} + if v.verify == nil { + r.identities = make([]txverify.VerifiedMessageIdentity, len(txs)) + } go func() { defer v.request.Done() defer func() { <-v.requests }() defer cancel() - r.index, r.err = v.verifyTransactions(ctx, txs) + r.index, r.err = v.verifyTransactionsWithIdentities(ctx, txs, r.identities) r.finishedAt = time.Now() close(r.done) }() @@ -200,6 +209,10 @@ func (v *transactionVerifier) submitTransactions(ctx context.Context, txs []*sol // One caller can queue at most workers jobs, so a large catch-up block cannot // put all its transactions ahead of a newly available component. func (v *transactionVerifier) verifyTransactions(ctx context.Context, txs []*solana.Transaction) (int, error) { + return v.verifyTransactionsWithIdentities(ctx, txs, nil) +} + +func (v *transactionVerifier) verifyTransactionsWithIdentities(ctx context.Context, txs []*solana.Transaction, identities []txverify.VerifiedMessageIdentity) (int, error) { if len(txs) == 0 { return -1, ctx.Err() } @@ -245,6 +258,9 @@ func (v *transactionVerifier) verifyTransactions(ctx context.Context, txs []*sol } pending.start = nextIndex pending.txs = txs[nextIndex:end] + if identities != nil { + pending.identities = identities[nextIndex:end] + } pending.errs = pending.errs[:end-nextIndex] clear(pending.errs) } @@ -266,6 +282,7 @@ func (v *transactionVerifier) verifyTransactions(ctx context.Context, txs []*sol } } job.txs = nil + job.identities = nil clear(job.errs) free = append(free, job) case <-ctxDone: @@ -314,6 +331,18 @@ func verifyBatchSafely(batch *txverify.BatchVerifier, txs []*solana.Transaction, batch.Verify(txs, errs) } +func verifyBatchWithIdentitiesSafely(batch *txverify.BatchVerifier, txs []*solana.Transaction, errs []error, identities []txverify.VerifiedMessageIdentity) { + defer func() { + if recovered := recover(); recovered != nil { + clear(identities) + for i := range errs { + errs[i] = fmt.Errorf("signature verifier panic: %v", recovered) + } + } + }() + batch.VerifyWithMessageIdentities(txs, errs, identities) +} + func (v *transactionVerifier) closeAndWait() { if v == nil { return @@ -360,6 +389,9 @@ func (v *transactionVerifier) verifyBlockContext(ctx context.Context, blk *block if err != nil && index >= 0 { return formatTransactionVerificationError(blk, index, err) } + if err == nil && request.identities != nil { + return blk.CacheVerifiedTransactionMessageIdentities(request.identities) + } return err } diff --git a/pkg/txstatus/message_identity.go b/pkg/txstatus/message_identity.go index 4d41f545..4541a2a1 100644 --- a/pkg/txstatus/message_identity.go +++ b/pkg/txstatus/message_identity.go @@ -27,11 +27,18 @@ func TransactionMessageHash(tx *solana.Transaction) ([32]byte, error) { return messageHash, fmt.Errorf("serialize transaction message: %w", err) } + return HashCanonicalMessage(message), nil +} + +// HashCanonicalMessage hashes the exact canonical bytes used for transaction +// signature verification, including any message-version prefix. +func HashCanonicalMessage(message []byte) [32]byte { + var messageHash [32]byte hasher := blake3.New() _, _ = hasher.Write([]byte(transactionMessageHashDomain)) _, _ = hasher.Write(message) hasher.Sum(messageHash[:0]) - return messageHash, nil + return messageHash } // IdentityForTransaction captures both components needed for a status-cache diff --git a/pkg/txverify/message_identity.go b/pkg/txverify/message_identity.go new file mode 100644 index 00000000..4ba83bfc --- /dev/null +++ b/pkg/txverify/message_identity.go @@ -0,0 +1,25 @@ +package txverify + +import ( + "github.com/Overclock-Validator/mithril/pkg/txstatus" + "github.com/gagliardetto/solana-go" +) + +// VerifiedMessageIdentity is an immutable result of signature verification. +// Its zero value is unusable. Signed message contents must remain immutable; +// as with Block's existing cache, arbitrary in-place edits require invalidation. +type VerifiedMessageIdentity struct { + transaction *solana.Transaction + version solana.MessageVersion + identity txstatus.TransactionMessageIdentity + verified bool +} + +// ForTransaction checks the binding without reserializing. Address-table +// resolution is allowed because it does not change the canonical message. +func (v VerifiedMessageIdentity) ForTransaction(tx *solana.Transaction) (txstatus.TransactionMessageIdentity, bool) { + if !v.verified || tx == nil || tx != v.transaction || tx.Message.GetVersion() != v.version || tx.Message.RecentBlockhash != v.identity.RecentBlockhash { + return txstatus.TransactionMessageIdentity{}, false + } + return v.identity, true +} diff --git a/pkg/txverify/message_identity_test.go b/pkg/txverify/message_identity_test.go new file mode 100644 index 00000000..29d26549 --- /dev/null +++ b/pkg/txverify/message_identity_test.go @@ -0,0 +1,70 @@ +package txverify + +import ( + "crypto/ed25519" + "encoding/hex" + "testing" + + "github.com/Overclock-Validator/mithril/pkg/txstatus" + "github.com/gagliardetto/solana-go" + "github.com/stretchr/testify/require" +) + +func identitySignedTransaction(t *testing.T, version solana.MessageVersion) *solana.Transaction { + t.Helper() + key := ed25519.NewKeyFromSeed(make([]byte, 32)) + tx := &solana.Transaction{Message: solana.Message{ + Header: solana.MessageHeader{NumRequiredSignatures: 1, NumReadonlyUnsignedAccounts: 1}, + AccountKeys: []solana.PublicKey{solana.PublicKeyFromBytes(key.Public().(ed25519.PublicKey)), {2}}, + RecentBlockhash: solana.Hash{3}, + Instructions: []solana.CompiledInstruction{{ProgramIDIndex: 1, Accounts: []uint16{0}, Data: []byte{4}}}, + }} + _, err := tx.Message.SetVersion(version) + require.NoError(t, err) + msg, err := MessageBytes(tx) + require.NoError(t, err) + tx.Signatures = []solana.Signature{solana.SignatureFromBytes(ed25519.Sign(key, msg))} + return tx +} + +func TestVerifiedMessageIdentityCanonicalVersionsAndFailures(t *testing.T) { + wire, err := hex.DecodeString(rustV1FeeHeapTransaction) + require.NoError(t, err) + v1, err := solana.TransactionFromBytes(wire) + require.NoError(t, err) + txs := []*solana.Transaction{identitySignedTransaction(t, solana.MessageVersionLegacy), identitySignedTransaction(t, solana.MessageVersionV0), v1} + bad := identitySignedTransaction(t, solana.MessageVersionLegacy) + bad.Signatures[0][0] ^= 1 + txs = append(txs, bad, nil) + errs := make([]error, len(txs)) + ids := make([]VerifiedMessageIdentity, len(txs)) + var verifier BatchVerifier + verifier.VerifyWithMessageIdentities(txs, errs, ids) + for i := range txs { + id, ok := ids[i].ForTransaction(txs[i]) + if i >= 3 { + require.Error(t, errs[i]) + require.False(t, ok) + continue + } + require.NoError(t, errs[i]) + require.True(t, ok) + want, err := txstatus.IdentityForTransaction(txs[i]) + require.NoError(t, err) + require.Equal(t, want, id) + } + // Scratch reuse cannot invalidate a prior successful request, and reusing + // an output lane for failure must not leave a usable old identity behind. + saved := ids[0] + verifier.VerifyWithMessageIdentities([]*solana.Transaction{bad}, errs[:1], ids[:1]) + _, ok := saved.ForTransaction(txs[0]) + require.True(t, ok) + _, ok = ids[0].ForTransaction(txs[0]) + require.False(t, ok) + copyTx := *txs[0] + _, ok = saved.ForTransaction(©Tx) + require.False(t, ok) + txs[0].Message.RecentBlockhash[0] ^= 1 + _, ok = saved.ForTransaction(txs[0]) + require.False(t, ok) +} diff --git a/pkg/txverify/txverify.go b/pkg/txverify/txverify.go index 7221399c..af58b9cb 100644 --- a/pkg/txverify/txverify.go +++ b/pkg/txverify/txverify.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/Overclock-Validator/mithril/pkg/sigverify" + "github.com/Overclock-Validator/mithril/pkg/txstatus" "github.com/gagliardetto/solana-go" ) @@ -222,6 +223,21 @@ type BatchVerifier struct { // Every transaction gets an independent verdict: one bad transaction does not // mask the others, so a caller can report precisely which one failed. func (v *BatchVerifier) Verify(txs []*solana.Transaction, errs []error) { + v.verify(txs, errs, nil) +} + +// VerifyWithMessageIdentities additionally retains identities derived from the +// same canonical bytes used by signature verification. Only successful verdicts +// produce usable identities. The output is caller-owned, not verifier scratch. +func (v *BatchVerifier) VerifyWithMessageIdentities(txs []*solana.Transaction, errs []error, identities []VerifiedMessageIdentity) { + if len(identities) != len(txs) { + panic("txverify: identities and txs length mismatch") + } + clear(identities) + v.verify(txs, errs, identities) +} + +func (v *BatchVerifier) verify(txs []*solana.Transaction, errs []error, identities []VerifiedMessageIdentity) { if len(errs) != len(txs) { panic("txverify: errs and txs length mismatch") } @@ -239,6 +255,16 @@ func (v *BatchVerifier) Verify(txs []*solana.Transaction, errs []error) { v.signers = append(v.signers, nil) continue } + if identities != nil { + identities[i] = VerifiedMessageIdentity{ + transaction: tx, + version: tx.Message.GetVersion(), + identity: txstatus.TransactionMessageIdentity{ + MessageHash: txstatus.HashCanonicalMessage(msg), + RecentBlockhash: tx.Message.RecentBlockhash, + }, + } + } for j := range tx.Signatures { v.batch.Add((*[32]byte)(&signers[j]), msg, tx.Signatures[j][:]) } @@ -247,6 +273,9 @@ func (v *BatchVerifier) Verify(txs []*solana.Transaction, errs []error) { } if v.batch.Verify() { + for i := range identities { + identities[i].verified = errs[i] == nil + } return } @@ -257,6 +286,9 @@ func (v *BatchVerifier) Verify(txs []*solana.Transaction, errs []error) { errs[i] = fmt.Errorf("invalid signature by %s", v.signers[i][j]) } } + if identities != nil { + identities[i].verified = errs[i] == nil + } lane += count } } From addabeadf862f9723b1814d7349afcacf71c2873 Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Mon, 14 Sep 2026 16:38:48 -0500 Subject: [PATCH 012/183] Record native deployment and initial live identity timing results --- docs/streaming_message_identities.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/docs/streaming_message_identities.md b/docs/streaming_message_identities.md index 7d7d074e..94b293f0 100644 --- a/docs/streaming_message_identities.md +++ b/docs/streaming_message_identities.md @@ -76,8 +76,19 @@ storage ownership, JSON round-trips, early preparation and mixed canceled-batch fallback. Existing turbine tests cover invalid and discarded prefixes and completion cancellation. -The benchmarked candidate passed native Zen 5 race tests. A subsequent explicit -per-batch length guard and two additional ownership/fallback tests passed the -final local race suite. Automatic approval review blocked uploading those final -source/test updates; final-revision native verification is still pending. No -new binary has been deployed and no live FAST improvement is claimed. +The final revision passed native Zen 5 race tests covering txstatus, txverify, +block, turbine, replay, consensus and node startup, plus vet and a full build. +It was deployed at 21:25:24 UTC on September 14 with clean reserved-history +shutdown and all prior live integrations preserved. Continuous leader load +resumed at 21:26:04 UTC after three advancing healthy vote checks. Live FAST +comparison excludes the first two minutes after load resumes; benchmark gains +alone do not establish a FAST improvement. + +The first completed live comparison covers 1,336 post-warmup FAST proofs over +7.3 minutes. Large-block median full-assembly-to-admission fell from 18.15 to +7.04 ms (admission alone 14.25→1.82 ms). FAST inclusion changed from 98.08% to +98.35% overall and 88.42% to 90.50% on large blocks. These small score changes +are observational; the baseline and candidate windows span an epoch change. +Several remaining misses coincide with unusually slow replay during local +load sends, while others have late signature completions or shred collection. +No claim of eliminating FAST misses or proving a score improvement is made. From 2e0824bcd25cbee6dc7585eb9643f570f803be13 Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Mon, 14 Sep 2026 20:39:25 -0500 Subject: [PATCH 013/183] Discover independent complete batches and preserve bounded prefetch reset ownership --- .gitattributes | 7 + docs/out-of-order-entry-prefetch.md | 35 +++ docs/transaction_sigverify_streaming.md | 13 +- go.sum | 2 - pkg/turbine/assembler.go | 36 ++-- pkg/turbine/entries.go | 8 + pkg/turbine/entry_batch_index.go | 162 ++++++++++++++ pkg/turbine/entry_batch_index_test.go | 106 ++++++++++ pkg/turbine/entry_pipeline_trace.go | 212 +++++++++++++++++++ pkg/turbine/entry_pipeline_trace_test.go | 68 ++++++ pkg/turbine/entry_prefetch.go | 67 +++--- pkg/turbine/entry_prefetch_benchmark_test.go | 30 +++ pkg/turbine/entry_prefetch_test.go | 165 +++++++++++++++ pkg/turbine/transaction_verifier.go | 50 ++++- 14 files changed, 911 insertions(+), 50 deletions(-) create mode 100644 .gitattributes create mode 100644 docs/out-of-order-entry-prefetch.md create mode 100644 pkg/turbine/entry_batch_index.go create mode 100644 pkg/turbine/entry_batch_index_test.go create mode 100644 pkg/turbine/entry_pipeline_trace.go create mode 100644 pkg/turbine/entry_pipeline_trace_test.go diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..d64360d9 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# Keep raw benchmark evidence available without overwhelming the review. +# Retain raw Go CPU padding and test-framework space/tab indentation. +docs/results/**/*.json linguist-generated=true +docs/results/**/*.jsonl linguist-generated=true +docs/results/**/*.txt linguist-generated=true whitespace=-blank-at-eol +docs/results/**/*.log linguist-generated=true -whitespace +docs/results/**/*.tar.gz linguist-generated=true diff --git a/docs/out-of-order-entry-prefetch.md b/docs/out-of-order-entry-prefetch.md new file mode 100644 index 00000000..b435405b --- /dev/null +++ b/docs/out-of-order-entry-prefetch.md @@ -0,0 +1,35 @@ +# Prepare complete entry batches despite earlier shred gaps + +Live tracing found five large external blocks whose final assembly-to-ready time was 20–39 ms. Most fallback verification work was already available more than 20 ms before full assembly. For one 33,760-transaction block, 6,506 transactions in later complete batches waited 44–116 ms for discovery behind an earlier missing shred. + +The old discovery cursor stopped at the first missing data index. The new bounded bitmap index discovers each complete DATA_COMPLETE range independently. Receiving a data shred or recovering one through FEC can release its containing batch and, when it supplies a boundary, the next batch. A batch still needs every data shred and its preceding boundary, unless it begins at index zero. Results are queued in discovery order and final assembly restores wire order using the existing exact range and byte-identity checks. + +The index uses about 24 KiB per retained slot and is allocated only with streaming preparation enabled. Successor/predecessor queries have bounded cost even with reverse or adversarial arrival order. Existing worker counts, verifier batching, retained-byte limits, cancellation, generation ownership, final block checks and signature validation remain unchanged. + +Regression coverage includes a delayed earlier shred, delayed preceding boundary, FEC-recovered boundary, disabled preparation, randomized arrival against a reference oracle, duplicate discovery, index word/group/slot boundaries, and the existing final-validation and cancellation tests. Native Turbine/replay race tests and Turbine vet passed. + +## Controlled Zen 5 benchmark + +AMD Ryzen 7 9700X, Go 1.26.4, Narya r51, GOMAXPROCS=8, two transaction verification workers, target batch size eight. 33,760 generated signed transactions arrive as complete component bursts across 200 ms. One data shred in a component three quarters through the block is withheld until after the footer. Both versions run with identical fixtures in baseline/candidate/candidate/baseline order, three iterations per case in each run, while the validator remains running. Ranges below are the two run medians, not a confidence interval. + +| Wire transaction size | Prior assembly → ready | New assembly → ready | +| --- | ---: | ---: | +| 228 bytes, delayed shred | 21.43–22.77 ms | 2.82–2.83 ms | +| 1,232 bytes, delayed shred | 35.46–36.34 ms | 7.04–8.08 ms | +| 228 bytes, ordered | 2.50–2.56 ms | 2.40–2.52 ms | +| 1,232 bytes, ordered | 6.91–7.67 ms | 6.87–7.89 ms | + +The delayed-shred case now verifies roughly 33.5–33.7k transactions before assembly, compared with 25.3–25.6k previously. The benchmark asserts every retained signature is verified exactly once and block metadata remains correct. It includes assembly, decoding, final validation and transaction verification; it excludes network I/O, replay execution and actual FAST-certificate inclusion. This modeled case is not an end-to-end validator speedup or a prediction of overall FAST percentage. + +Reproduce with `MITHRIL_SIGVERIFY_FLOW_BACKEND=r51 GOMAXPROCS=8 go test ./pkg/turbine -run '^$' -bench '^BenchmarkEntryPrefetchGapArrival$' -benchtime=3x` on each implementation, copying the same benchmark file to the baseline. + +## Initial live measurement + +The fixed post-warmup window, 2026-09-15 01:27:00–01:30:00 UTC, contains 27 sampled large blocks: 25 external and two own-leader observations, which are excluded from these latency statistics. Every retained transaction had known batch availability, timing order and transaction accounting passed validation, and no trace reports were dropped. + +Across the 25 external blocks, maximum complete-availability-to-discovery delay was 0.018715 ms (18.7 microseconds). Assembly-to-ready was 4.709 ms median and 14.710 ms maximum; none exceeded 20 ms. The earlier diagnostic window had five external blocks above20ms among30, including the38.99ms example. These are small observational samples with different blocks/leaders, not matched causal estimates or a guarantee that all long tails are gone. The direct discovery timings and controlled delayed-shred benchmark support the mechanism specifically. + +The first completed current-build FAST capture, filtered to source slots first observed after01:27UTC and deduplicated by full proof key, included us in461/466FAST certificates (98.93%); large blocks were79/82 (96.34%). This is a local footer sample, not the rolling Puffin score or Titan reward inclusion. It does not establish a lasting overall FAST improvement. All751clean replay observations had notarize events; no reservation exhaustion was observed. A separate30second probe sanity check also had112/112replay/notarize, no rejection/exhaustion and no parse/truncation errors. + +At01:30:27UTC voting was current within3slots, allfourservices active,88/88peer connections, zero broadcast drops, peer-send errors, queue drops/discards/timeouts or connection errors. Three completed own-leader load windows produced12blocks with zero sender errors, up to48,622transactions/block. Counts by window:3798364=[22447,48622,44343,43730];3799208=[17139,48622,36041,40611];3799488=[22814,46680,41221,42949]. The existing continuous loader and all monitoring remain running. + diff --git a/docs/transaction_sigverify_streaming.md b/docs/transaction_sigverify_streaming.md index 3baee788..02619d45 100644 --- a/docs/transaction_sigverify_streaming.md +++ b/docs/transaction_sigverify_streaming.md @@ -1,7 +1,7 @@ # Transaction signature verification during shred arrival Turbine verifies transaction signatures as complete entry batches arrive. The -default shared transaction pool has two workers and targets eight signature +default shared transaction pool has `min(2, GOMAXPROCS)` workers and targets eight signature lanes. A ready batch containing four transactions runs immediately; there is no timer or minimum occupancy requirement. The same policy handles live reception and repair catch-up without a mode transition or a 200 ms batching delay. @@ -120,3 +120,14 @@ measures direct ordering, authenticated-root reuse, and the four-vector job poli The [standalone PR review](results/streaming-pr-review/2026-09-13/README.md) records extraction onto current `alpenglow-dev`, the small shared component-boundary prerequisite, final allocation improvement, and the scope of the live trial. + +## Worker default compatibility + +The automatic transaction-verifier default changes from `(GOMAXPROCS + 1) / 2` workers to +`min(2, GOMAXPROCS)`, including when shred overlap is disabled. This favors spare +CPU capacity for execution and other verification at the tip. It is not a claim +of maximum catch-up throughput on every core count or backend. Set +`--sigverify-workers N` or `[sigverify] workers = N` explicitly when tuning a +larger machine; disabling overlap alone does not restore the previous worker +count. Existing two/four-worker contention measurements are in the September 12 +report above. No 32-core comparison was performed. diff --git a/go.sum b/go.sum index b5997c28..086dc43c 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,6 @@ github.com/Overclock-Validator/crypto v0.0.0-20250307094320-aaf52fac5261 h1:Y715 github.com/Overclock-Validator/crypto v0.0.0-20250307094320-aaf52fac5261/go.mod h1:ZhRHOaVg8I1gg0VK4wmqOQPnlgPgKFT9McZ+TCW/hBA= github.com/Overclock-Validator/gnark-crypto v0.0.0-20250309203346-2a67ed08a105 h1:mP6FWHZ8ddcmbE8UTrVVI2Mi2c24aqX/8p12Vn6zokQ= github.com/Overclock-Validator/gnark-crypto v0.0.0-20250309203346-2a67ed08a105/go.mod h1:Poczuq3dbt+CwyTKgOjGaEwJOMP7YxQobF7QhgNcguk= -github.com/Overclock-Validator/narya-ed25519 v0.0.0-20260726222623-da0d045dae9d h1:ipaL+9MHKeI8QIfWneId0VLa+STLRM1e6MnvZhQyhPU= -github.com/Overclock-Validator/narya-ed25519 v0.0.0-20260726222623-da0d045dae9d/go.mod h1:B7/xqV/5NtGJa8OlZAa9TRMHgeIE+VEJNiPzMP4FrIg= github.com/Overclock-Validator/narya-ed25519 v0.0.0-20260730051143-c265ee966713 h1:nRAD+snanlR/sX4W5rkrxr6+sYBZ3Hl2xZQ6HCpM0Hc= github.com/Overclock-Validator/narya-ed25519 v0.0.0-20260730051143-c265ee966713/go.mod h1:B7/xqV/5NtGJa8OlZAa9TRMHgeIE+VEJNiPzMP4FrIg= github.com/Overclock-Validator/solana-snapshot-finder-go v0.0.0-20260223201452-d8363b514fc0 h1:elgavEQb8l7Zn3gS3Y+2/98PlUylOWdlM3V1VumQ7mA= diff --git a/pkg/turbine/assembler.go b/pkg/turbine/assembler.go index dc8c69db..3d97bf14 100644 --- a/pkg/turbine/assembler.go +++ b/pkg/turbine/assembler.go @@ -98,14 +98,15 @@ type PartialShredObservation struct { } type slotState struct { - slot uint64 - parentSlot uint64 - shreds map[uint32]*Shred - fecSets map[uint32]*fecState - lastIndex uint32 - haveLast bool - shredVer uint16 - firstParent bool + pipelineTrace *entryPipelineTrace + slot uint64 + parentSlot uint64 + shreds map[uint32]*Shred + fecSets map[uint32]*fecState + lastIndex uint32 + haveLast bool + shredVer uint16 + firstParent bool // Observability: when the slot's first shred was accepted, and how many of // its shreds arrived via repair rather than turbine. @@ -113,10 +114,10 @@ type slotState struct { fullAt time.Time repairedShreds int // completing makes the immutable full state a single-owner generation token. - completing bool - batchScan, batchStart uint32 - completeBatches []shredBatchRange - prefetch *slotEntryPrefetch + completing bool + batchIndex *entryBatchIndex + completeBatches []shredBatchRange + prefetch *slotEntryPrefetch // Assembly failures for this slot (mixed variants/signatures, FEC layout // conflicts, ...). A slot frozen below completion while repair responses // flow is usually poisoned state — the latest error names the poison. @@ -305,6 +306,8 @@ func (a *SlotAssembler) addShredFromWithRoot(shred *Shred, fromRepair bool, root state.noteError(err) return nil, err } + state.traceAcceptedShred(shred) + a.notePrefetchShredLocked(state, shred) if state.firstShredAt.IsZero() { state.firstShredAt = time.Now() } @@ -326,6 +329,8 @@ func (a *SlotAssembler) addShredFromWithRoot(shred *Shred, fromRepair bool, root return nil, err } if err == nil { + state.traceAcceptedShred(recoveredShred) + a.notePrefetchShredLocked(state, recoveredShred) a.recoveredDataShreds++ } } @@ -342,6 +347,9 @@ func (a *SlotAssembler) claimCompletionLocked(state *slotState, reportNonCanonic return nil } now := time.Now() + if state.pipelineTrace != nil { + state.pipelineTrace.sealed = true + } observeCollection := state.fullAt.IsZero() if observeCollection { state.fullAt = now @@ -388,6 +396,7 @@ func (a *SlotAssembler) processCompletion(ctx context.Context, work *slotComplet if ctx.Err() != nil { return processedSlotCompletion{canceled: true} } + ctx = withEntryPipelineTrace(ctx, work.state.pipelineTrace) startedAt := time.Now() timings := block.TurbineIngressTimings{CompletionQueueDelay: startedAt.Sub(work.queuedAt)} _ = statsd.Duration(statsd.TurbineBlockCompletionQueueDelay, timings.CompletionQueueDelay, nil) @@ -429,7 +438,7 @@ func (a *SlotAssembler) processCompletion(ctx context.Context, work *slotComplet sigverifyStartedAt := time.Now() if work.state.prefetch != nil && len(decodeTimings.retained) > 0 { - processed.err = verifyDecodedEntryBatches(ctx, blk, decodeTimings.retained, work.state.prefetch.pool.verifier) + processed.err = verifyDecodedEntryBatchesWithTimings(ctx, blk, decodeTimings.retained, work.state.prefetch.pool.verifier, &decodeTimings) } else { processed.err = work.verifyTransactions(ctx, blk) } @@ -450,6 +459,7 @@ func (a *SlotAssembler) processCompletion(ctx context.Context, work *slotComplet _ = statsd.Duration(statsd.TurbineEarlyTransactionParse, processed.timings.EarlyTransactionParse, nil) _ = statsd.Duration(statsd.TurbineEarlyTransactionSigverify, processed.timings.EarlyTransactionSigverify, nil) _ = statsd.Count(statsd.TurbineEarlyVerifiedTransactions, int64(processed.timings.EarlyVerifiedTransactions), nil) + queueEntryPipelineReport(work.state, blk, &decodeTimings, startedAt, processed.completionReadyAt) } return processed } diff --git a/pkg/turbine/entries.go b/pkg/turbine/entries.go index f4f505b2..e9372204 100644 --- a/pkg/turbine/entries.go +++ b/pkg/turbine/entries.go @@ -47,6 +47,7 @@ type entryDecodeTimings struct { retained []*prefetchedShredBatch all []*prefetchedShredBatch prefetchWait time.Duration + traceFallback *transactionVerification } func (e *Entry) UnmarshalWithDecoder(decoder *bin.Decoder) error { @@ -189,6 +190,10 @@ func decodeEntriesFromOrderedDataShreds(shreds []*Shred, timings *entryDecodeTim if batch == nil { // A miss owns a fresh, exactly sized backing array. Transactions // retain instruction-data slices into it after this call returns. + var traceStart int64 + if timings != nil && entryTraceContext(timings.ctx) { + traceStart = entryTraceNow() + } batchBytes := make([]byte, 0, batchSize) for _, part := range batchShreds { if part != nil && part.Type == ShredTypeData { @@ -196,6 +201,9 @@ func decodeEntriesFromOrderedDataShreds(shreds []*Shred, timings *entryDecodeTim } } batch = decodeClosedShredBatch(batchBytes, batchStart, shred.Index) + if traceStart != 0 { + batch.traceDecodeStart, batch.traceDecodeEnd = traceStart, entryTraceNow() + } if timings != nil { timings.transactionParse += batch.parseDuration } diff --git a/pkg/turbine/entry_batch_index.go b/pkg/turbine/entry_batch_index.go new file mode 100644 index 00000000..3bf3f264 --- /dev/null +++ b/pkg/turbine/entry_batch_index.go @@ -0,0 +1,162 @@ +package turbine + +import "math/bits" + +// Three levels cover all 65,536 permitted data-shred indexes. Successor and +// predecessor queries touch a bounded number of words, even in adversarial order. +// The index is bounded (~24 KiB per retained slot) and allocated only when +// streaming preparation is enabled. It never rescans a slot's retained map. +const batchIndexWords = maxDataShredsPerSlot / 64 + +type shredIndexBits struct { + words [batchIndexWords]uint64 + groups [batchIndexWords / 64]uint64 + top uint64 +} + +func (b *shredIndexBits) set(i uint32) { + w, g := i/64, i/4096 + b.words[w] |= uint64(1) << (i % 64) + b.groups[g] |= uint64(1) << (w % 64) + b.top |= uint64(1) << g +} +func (b *shredIndexBits) clear(i uint32) { + w, g := i/64, i/4096 + b.words[w] &^= uint64(1) << (i % 64) + if b.words[w] == 0 { + b.groups[g] &^= uint64(1) << (w % 64) + if b.groups[g] == 0 { + b.top &^= uint64(1) << g + } + } +} +func (b *shredIndexBits) next(i uint32) (uint32, bool) { + if i >= maxDataShredsPerSlot { + return 0, false + } + w, g := i/64, i/4096 + if x := b.words[w] & (^uint64(0) << (i % 64)); x != 0 { + return w*64 + uint32(bits.TrailingZeros64(x)), true + } + x := b.groups[g] & (^uint64(0) << (w%64 + 1)) + if x == 0 { + top := b.top & (^uint64(0) << (g + 1)) + if top == 0 { + return 0, false + } + g = uint32(bits.TrailingZeros64(top)) + x = b.groups[g] + } + w = g*64 + uint32(bits.TrailingZeros64(x)) + return w*64 + uint32(bits.TrailingZeros64(b.words[w])), true +} +func (b *shredIndexBits) previous(i uint32) (uint32, bool) { + if i >= maxDataShredsPerSlot { + i = maxDataShredsPerSlot - 1 + } + w, g := i/64, i/4096 + if x := b.words[w] & (^uint64(0) >> (63 - i%64)); x != 0 { + return w*64 + uint32(63-bits.LeadingZeros64(x)), true + } + x := b.groups[g] & ((uint64(1) << (w % 64)) - 1) + if x == 0 { + top := b.top & ((uint64(1) << g) - 1) + if top == 0 { + return 0, false + } + g = uint32(63 - bits.LeadingZeros64(top)) + x = b.groups[g] + } + w = g*64 + uint32(63-bits.LeadingZeros64(x)) + return w*64 + uint32(63-bits.LeadingZeros64(b.words[w])), true +} + +type entryBatchIndex struct { + missing shredIndexBits + ends shredIndexBits + emitted [batchIndexWords]uint64 +} + +func newEntryBatchIndex() *entryBatchIndex { + b := new(entryBatchIndex) + for i := range b.missing.words { + b.missing.words[i] = ^uint64(0) + } + for i := range b.missing.groups { + b.missing.groups[i] = ^uint64(0) + } + b.missing.top = (uint64(1) << len(b.missing.groups)) - 1 + return b +} + +// One insertion can complete its containing batch, and, if it provides a new +// DATA_COMPLETE boundary, the immediately following batch. All other batches +// are unchanged. A range is emitted once, only when every data index is present. +// The preceding boundary is mandatory unless the range starts at index zero. +func (b *entryBatchIndex) add(i uint32, dataComplete bool) (ready [2]shredBatchRange, n int) { + if i >= maxDataShredsPerSlot { + return ready, 0 + } + b.missing.clear(i) + if dataComplete { + b.ends.set(i) + } + if end, ok := b.ends.next(i); ok { + if r, ok := b.complete(end); ok { + ready[n] = r + n++ + } + } + if dataComplete { + if end, ok := b.ends.next(i + 1); ok { + if r, ok := b.complete(end); ok { + ready[n] = r + n++ + } + } + } + return +} +func (b *entryBatchIndex) complete(end uint32) (shredBatchRange, bool) { + if b.emitted[end/64]&(uint64(1)<<(end%64)) != 0 { + return shredBatchRange{}, false + } + start := uint32(0) + if end > 0 { + if prev, ok := b.ends.previous(end - 1); ok { + start = prev + 1 + } + } + if missing, ok := b.missing.next(start); ok && missing <= end { + return shredBatchRange{}, false + } + b.emitted[end/64] |= uint64(1) << (end % 64) + return shredBatchRange{start, end}, true +} + +func (s *slotState) discoverEntryBatch(sh *Shred) { + ready, n := s.batchIndex.add(sh.Index, sh.DataComplete()) + for _, r := range ready[:n] { + s.completeBatches = append(s.completeBatches, r) + if s.pipelineTrace != nil && !s.pipelineTrace.sealed { + s.pipelineTrace.discovered[r.start] = entryTraceNow() + } + } +} + +// Seed once if preparation is installed on an assembler with existing data. +// Normal ingress creates the index with the first accepted data shred. +func (a *SlotAssembler) notePrefetchShredLocked(s *slotState, sh *Shred) { + p := a.entryPrefetch + if p == nil || p.closed || p.ctx.Err() != nil || sh.Type != ShredTypeData { + return + } + if s.batchIndex == nil { + s.batchIndex = newEntryBatchIndex() + for _, existing := range s.shreds { + s.discoverEntryBatch(existing) + } + } else { + s.discoverEntryBatch(sh) + } +} diff --git a/pkg/turbine/entry_batch_index_test.go b/pkg/turbine/entry_batch_index_test.go new file mode 100644 index 00000000..5f812be8 --- /dev/null +++ b/pkg/turbine/entry_batch_index_test.go @@ -0,0 +1,106 @@ +package turbine + +import ( + "github.com/stretchr/testify/require" + "math/rand" + "testing" +) + +func TestShredIndexBitsBoundaries(t *testing.T) { + var b shredIndexBits + indexes := []uint32{0, 1, 63, 64, 65, 4095, 4096, 4097, 65534, 65535} + for _, i := range indexes { + b.set(i) + } + for i := uint32(0); i <= 65536; i++ { + var wantNext, wantPrev uint32 + var hasNext, hasPrev bool + for _, j := range indexes { + if j >= i && !hasNext { + wantNext, hasNext = j, true + } + if j <= i { + wantPrev, hasPrev = j, true + } + } + got, ok := b.next(i) + require.Equal(t, hasNext, ok) + if ok { + require.Equal(t, wantNext, got) + } + got, ok = b.previous(i) + require.Equal(t, hasPrev, ok) + if ok { + require.Equal(t, wantPrev, got) + } + } + for _, i := range indexes { + b.clear(i) + } + _, ok := b.next(0) + require.False(t, ok) + _, ok = b.previous(65535) + require.False(t, ok) + require.Zero(t, b.top) +} + +func TestEntryBatchIndexRandomArrivalMatchesOracle(t *testing.T) { + rng := rand.New(rand.NewSource(42)) + for trial := 0; trial < 100; trial++ { + const size = 257 + var ends, present [size]bool + for i := range ends { + ends[i] = rng.Intn(8) == 0 + } + ends[size-1] = true + index := newEntryBatchIndex() + emitted := map[shredBatchRange]bool{} + for _, i := range rng.Perm(size) { + present[i] = true + got, n := index.add(uint32(i), ends[i]) + want := map[shredBatchRange]bool{} + start, complete := 0, true + for j := 0; j < size; j++ { + complete = complete && present[j] + if ends[j] && present[j] { + r := shredBatchRange{uint32(start), uint32(j)} + if complete && !emitted[r] { + want[r] = true + } + start, complete = j+1, true + } + } + require.Len(t, want, n, "trial %d index %d", trial, i) + for _, r := range got[:n] { + require.True(t, want[r]) + require.False(t, emitted[r]) + emitted[r] = true + } + _, n = index.add(uint32(i), ends[i]) + require.Zero(t, n, "duplicate emitted") + } + } +} + +func BenchmarkEntryBatchIndex(b *testing.B) { + for _, reverse := range []bool{false, true} { + name := "ordered" + if reverse { + name = "reverse" + } + b.Run(name, func(b *testing.B) { + b.ReportAllocs() + for n := 0; n < b.N; n++ { + idx := newEntryBatchIndex() + for k := uint32(0); k < 65536; k++ { + i := k + if reverse { + i = 65535 - k + } + idx.add(i, i%64 == 63) + } + } + b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(b.N)/65536, "ns/shred") + }) + } +} diff --git a/pkg/turbine/entry_pipeline_trace.go b/pkg/turbine/entry_pipeline_trace.go new file mode 100644 index 00000000..c2c83b45 --- /dev/null +++ b/pkg/turbine/entry_pipeline_trace.go @@ -0,0 +1,212 @@ +package turbine + +// Temporary, opt-in pipeline diagnostics. No transaction bytes or keys are logged. +// Timestamps are monotonic nanoseconds relative to origin_unix_ns. Worker elapsed +// time includes descheduling; summed job durations are NOT wall-clock critical paths. +import ( + "context" + "encoding/json" + "fmt" + "os" + "strconv" + "sync/atomic" + "time" + + "github.com/Overclock-Validator/mithril/pkg/block" +) + +var entryTraceOrigin = time.Now() +var entryTraceDropped atomic.Uint64 +var entryTraceConfig = configureEntryTrace() + +type entryTraceSettings struct { + modulo uint64 + until time.Time + reports chan entryPipelineReport +} + +func configureEntryTrace() entryTraceSettings { + n, err := strconv.ParseUint(os.Getenv("MITHRIL_ENTRY_TRACE_MOD"), 10, 32) + if err != nil || n == 0 { + return entryTraceSettings{} + } + seconds, err := strconv.Atoi(os.Getenv("MITHRIL_ENTRY_TRACE_SECONDS")) + if err != nil || seconds < 1 || seconds > 1800 { + seconds = 600 + } + path := os.Getenv("MITHRIL_ENTRY_TRACE_FILE") + if path == "" { + return entryTraceSettings{} + } + f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600) + if err != nil { + fmt.Fprintf(os.Stderr, "entry pipeline trace disabled: %v\n", err) + return entryTraceSettings{} + } + ch := make(chan entryPipelineReport, 8) + go func() { + defer f.Close() + enc := json.NewEncoder(f) + for r := range ch { + r.Dropped = entryTraceDropped.Load() + r.finish() + if err := enc.Encode(r); err != nil { + entryTraceDropped.Add(1) + } + } + }() + return entryTraceSettings{n, time.Now().Add(time.Duration(seconds) * time.Second), ch} +} + +func entryTraceNow() int64 { return time.Since(entryTraceOrigin).Nanoseconds() } +func entryTraceTime(t time.Time) int64 { return t.Sub(entryTraceOrigin).Nanoseconds() } + +type entryTraceContextKey struct{} + +func withEntryPipelineTrace(ctx context.Context, t *entryPipelineTrace) context.Context { + if t == nil { + return ctx + } + return context.WithValue(ctx, entryTraceContextKey{}, true) +} +func entryTraceContext(ctx context.Context) bool { + return ctx != nil && ctx.Value(entryTraceContextKey{}) == true +} + +type entryPipelineTrace struct { + arrivals map[uint32]int64 + discovered map[uint32]int64 + sealed bool // frozen at first completion claim, including retry/error paths +} + +// Called only after successful admission, under the assembler lock. Includes +// FEC-reconstructed data. This is local availability, not a NIC timestamp. +func (s *slotState) traceAcceptedShred(sh *Shred) { + if sh.Type != ShredTypeData { + return + } + if s.pipelineTrace == nil { + c := entryTraceConfig + if c.modulo == 0 || s.slot%c.modulo != 0 || time.Now().After(c.until) { + return + } + s.pipelineTrace = &entryPipelineTrace{arrivals: make(map[uint32]int64), discovered: make(map[uint32]int64)} + } + if !s.pipelineTrace.sealed { + s.pipelineTrace.arrivals[sh.Index] = entryTraceNow() + } +} + +type entryVerificationTrace struct { + Transactions int `json:"transactions"` + Submit int64 `json:"submit_ns"` + Admitted int64 `json:"admitted_ns"` + FirstWorker int64 `json:"first_worker_ns"` + LastWorker int64 `json:"last_worker_ns"` + Finished int64 `json:"finished_ns"` + Jobs int `json:"jobs"` + JobWaitSum int64 `json:"job_offer_to_start_sum_ns"` + JobWaitMax int64 `json:"job_offer_to_start_max_ns"` + WorkerSum int64 `json:"worker_elapsed_sum_ns"` + WorkerMax int64 `json:"worker_elapsed_max_ns"` +} + +func (t *entryVerificationTrace) observe(j *transactionVerifyJob) { + if t.FirstWorker == 0 || j.workerStart < t.FirstWorker { + t.FirstWorker = j.workerStart + } + t.LastWorker = max(t.LastWorker, j.workerEnd) + t.Jobs++ + wait, work := j.workerStart-j.offeredAt, j.workerEnd-j.workerStart + t.JobWaitSum += wait + t.JobWaitMax = max(t.JobWaitMax, wait) + t.WorkerSum += work + t.WorkerMax = max(t.WorkerMax, work) +} + +type entryBatchTraceReport struct { + Start uint32 `json:"start"` + End uint32 `json:"end"` + Transactions int `json:"transactions"` + Retained bool `json:"retained"` + Prefetched bool `json:"prefetched"` + AvailabilityKnown bool `json:"availability_known"` + Available int64 `json:"available_ns"` + Discovered int64 `json:"discovered_ns"` + DecodeStart int64 `json:"decode_start_ns"` + DecodeEnd int64 `json:"decode_end_ns"` + Verification *entryVerificationTrace `json:"verification,omitempty"` +} + +type entryPipelineReport struct { + Origin int64 `json:"origin_unix_ns"` + Slot uint64 `json:"slot"` + Transactions int `json:"transactions"` + Full int64 `json:"full_ns"` + CompletionStart int64 `json:"completion_start_ns"` + Ready int64 `json:"ready_ns"` + Dropped uint64 `json:"dropped_reports"` + Batches []entryBatchTraceReport `json:"batches"` + Fallback *entryVerificationTrace `json:"fallback,omitempty"` + source *entryPipelineTrace + all, retained []*prefetchedShredBatch + fallback *transactionVerification +} + +func completedEntryVerification(r *transactionVerification) *entryVerificationTrace { + if r == nil { + return nil + } + select { + case <-r.done: + return r.trace + default: + return nil + } +} + +// All source maps are sealed, and decode has joined all preparation readers. +// Reading request metrics additionally requires the verification done barrier. +func (r *entryPipelineReport) finish() { + retained := make(map[*prefetchedShredBatch]bool, len(r.retained)) + for _, b := range r.retained { + retained[b] = true + } + for _, b := range r.all { + row := entryBatchTraceReport{Start: b.start, End: b.end, Retained: retained[b], Prefetched: b.ready != nil, + DecodeStart: b.traceDecodeStart, DecodeEnd: b.traceDecodeEnd, Discovered: r.source.discovered[b.start], + AvailabilityKnown: true, Verification: completedEntryVerification(b.verification)} + for _, e := range b.entries { + row.Transactions += len(e.Txns) + } + // Require the preceding DATA_COMPLETE boundary as well as every shred in + // this batch. An end marker alone cannot establish an independent start. + start := b.start + if start > 0 { + start-- + } + for i := start; i <= b.end; i++ { + at, ok := r.source.arrivals[i] + if !ok { + row.AvailabilityKnown = false + } + row.Available = max(row.Available, at) + } + r.Batches = append(r.Batches, row) + } + r.Fallback = completedEntryVerification(r.fallback) +} + +func queueEntryPipelineReport(s *slotState, b *block.Block, d *entryDecodeTimings, start, ready time.Time) { + if s.pipelineTrace == nil || len(b.Transactions) < 10000 || entryTraceConfig.reports == nil { + return + } + r := entryPipelineReport{Origin: entryTraceOrigin.UnixNano(), Slot: s.slot, Transactions: len(b.Transactions), + Full: entryTraceTime(s.fullAt), CompletionStart: entryTraceTime(start), Ready: entryTraceTime(ready), + source: s.pipelineTrace, all: d.all, retained: d.retained, fallback: d.traceFallback} + select { + case entryTraceConfig.reports <- r: + default: + entryTraceDropped.Add(1) + } +} diff --git a/pkg/turbine/entry_pipeline_trace_test.go b/pkg/turbine/entry_pipeline_trace_test.go new file mode 100644 index 00000000..6aa49360 --- /dev/null +++ b/pkg/turbine/entry_pipeline_trace_test.go @@ -0,0 +1,68 @@ +package turbine + +import ( + "context" + "testing" + + "github.com/gagliardetto/solana-go" + "github.com/stretchr/testify/require" +) + +func TestEntryPipelineTraceRequiresCompleteBatchAndBoundary(t *testing.T) { + source := &entryPipelineTrace{arrivals: map[uint32]int64{0: 10, 1: 100, 2: 20, 3: 30, 4: 40}, discovered: map[uint32]int64{0: 110, 3: 120}, sealed: true} + first := &prefetchedShredBatch{start: 0, end: 2} + later := &prefetchedShredBatch{start: 3, end: 4} + r := entryPipelineReport{source: source, all: []*prefetchedShredBatch{first, later}, retained: []*prefetchedShredBatch{later}} + r.finish() + require.Equal(t, int64(100), r.Batches[0].Available) + require.Equal(t, int64(40), r.Batches[1].Available) + require.Equal(t, int64(80), r.Batches[1].Discovered-r.Batches[1].Available, "a gap in the earlier batch delays discovery, not availability of the later one") + require.False(t, r.Batches[0].Retained) + require.True(t, r.Batches[1].Retained) + delete(source.arrivals, 2) + r.Batches = nil + r.finish() + require.False(t, r.Batches[1].AvailabilityKnown, "the preceding boundary must also have been observed") +} + +func TestEntryVerificationTraceJoinsWorkerTimings(t *testing.T) { + entered, release := make(chan struct{}), make(chan struct{}) + v := newTransactionVerifier(1, 8, func(*solana.Transaction) error { + select { + case <-entered: + default: + close(entered) + } + <-release + return nil + }) + defer v.closeAndWait() + ctx := withEntryPipelineTrace(context.Background(), &entryPipelineTrace{}) + r, err := v.submitTransactions(ctx, []*solana.Transaction{{}}) + require.NoError(t, err) + <-entered + require.Nil(t, completedEntryVerification(r), "unfinished mutable metrics must not be read") + close(release) + _, err = r.wait() + require.NoError(t, err) + m := completedEntryVerification(r) + require.NotNil(t, m) + require.Equal(t, 1, m.Jobs) + require.LessOrEqual(t, m.Submit, m.Admitted) + require.LessOrEqual(t, m.Admitted, m.FirstWorker) + require.Less(t, m.FirstWorker, m.LastWorker) + require.LessOrEqual(t, m.LastWorker, m.Finished) + require.Positive(t, m.WorkerSum) + require.GreaterOrEqual(t, m.JobWaitSum, int64(0)) + plain, err := v.submitTransactions(context.Background(), []*solana.Transaction{{}}) + require.NoError(t, err) + _, err = plain.wait() + require.NoError(t, err) + require.Nil(t, plain.trace, "ordinary verification does not collect job timestamps") +} + +func TestEntryPipelineTraceSealedGeneration(t *testing.T) { + s := &slotState{pipelineTrace: &entryPipelineTrace{arrivals: map[uint32]int64{1: 42}, discovered: map[uint32]int64{}, sealed: true}} + s.traceAcceptedShred(&Shred{Type: ShredTypeData, Index: 2}) + require.Len(t, s.pipelineTrace.arrivals, 1, "completion/retry cannot mutate a report's frozen arrival map") +} diff --git a/pkg/turbine/entry_prefetch.go b/pkg/turbine/entry_prefetch.go index 8159dfe7..c8b39ea8 100644 --- a/pkg/turbine/entry_prefetch.go +++ b/pkg/turbine/entry_prefetch.go @@ -26,18 +26,20 @@ type shredBatchRange struct{ start, end uint32 } // Fields are immutable after ready closes; signature readers own its decoded // transactions until verification.done closes. type prefetchedShredBatch struct { - start, end uint32 - raw []byte - entries []Entry - parent *AlpenglowParentInfo - footer *BlockFooter - marker bool - parseDuration time.Duration - err error - ready chan struct{} - verification *transactionVerification - submittedAt time.Time - submitErr error + start, end uint32 + raw []byte + entries []Entry + parent *AlpenglowParentInfo + footer *BlockFooter + marker bool + traceDecodeStart int64 + traceDecodeEnd int64 + parseDuration time.Duration + err error + ready chan struct{} + verification *transactionVerification + submittedAt time.Time + submitErr error } type slotEntryPrefetch struct { @@ -47,11 +49,12 @@ type slotEntryPrefetch struct { batches map[uint32]*prefetchedShredBatch next int queued, released bool + queueDone chan struct{} // closed after the queued/running token retires bytes int } // All scheduling and accounting use assembler.mu. The packet reader only -// advances a contiguous frontier and attempts a nonblocking, coalesced enqueue. +// indexes complete data ranges and attempts a nonblocking, coalesced enqueue. // Decoding and bounded verifier admission run on separate background workers. type entryPrefetchPool struct { a *SlotAssembler @@ -83,21 +86,14 @@ func (a *SlotAssembler) prefetchEntriesLocked(s *slotState) { if p == nil || p.closed || p.ctx.Err() != nil { return } - // Each index is visited once, even when one batch spans many FEC sets or - // arrives out of order. A gap never yields a speculative partial decode. - for s.batchScan < maxDataShredsPerSlot { - sh := s.shreds[s.batchScan] - if sh == nil { - break - } - if sh.DataComplete() { - s.completeBatches = append(s.completeBatches, shredBatchRange{s.batchStart, s.batchScan}) - s.batchStart = s.batchScan + 1 + if s.batchIndex == nil && len(s.shreds) != 0 { + s.batchIndex = newEntryBatchIndex() + for _, sh := range s.shreds { + s.discoverEntryBatch(sh) } - s.batchScan++ } if s.prefetch == nil && len(s.completeBatches) > 0 && p.slots < entryPrefetchSlots { - ctx, cancel := context.WithCancel(p.ctx) + ctx, cancel := context.WithCancel(withEntryPipelineTrace(p.ctx, s.pipelineTrace)) s.prefetch = &slotEntryPrefetch{pool: p, ctx: ctx, cancel: cancel, batches: make(map[uint32]*prefetchedShredBatch)} p.slots++ } @@ -112,6 +108,7 @@ func (p *entryPrefetchPool) enqueueLocked(s *slotState) { select { case p.jobs <- s: f.queued = true + f.queueDone = make(chan struct{}) default: } } @@ -123,6 +120,7 @@ func (p *entryPrefetchPool) run() { f := s.prefetch if p.closed || f.released || f.ctx.Err() != nil || p.a.slots[s.slot] != s || s.completing { f.queued = false + close(f.queueDone) p.a.mu.Unlock() continue } @@ -159,11 +157,15 @@ func (p *entryPrefetchPool) run() { } if batch == nil { f.queued = false + close(f.queueDone) p.a.mu.Unlock() continue } p.a.mu.Unlock() + if s.pipelineTrace != nil { + batch.traceDecodeStart = entryTraceNow() + } raw := make([]byte, 0, rawSize) for _, sh := range shreds { raw = append(raw, sh.Data...) @@ -173,6 +175,9 @@ func (p *entryPrefetchPool) run() { batch.raw, batch.entries = decoded.raw, decoded.entries batch.parent, batch.footer, batch.marker = decoded.parent, decoded.footer, decoded.marker batch.parseDuration, batch.err = decoded.parseDuration, decoded.err + if s.pipelineTrace != nil { + batch.traceDecodeEnd = entryTraceNow() + } if batch.err == nil && !batch.marker && f.ctx.Err() == nil { txs := entryBatchTransactions(batch.entries) if len(txs) > 0 { @@ -183,6 +188,7 @@ func (p *entryPrefetchPool) run() { close(ready) p.a.mu.Lock() f.queued = false + close(f.queueDone) p.enqueueLocked(s) p.a.mu.Unlock() } @@ -214,6 +220,7 @@ func (a *SlotAssembler) releasePrefetchLocked(s *slotState) { f.released = true f.cancel() p := f.pool + queueDone := f.queueDone p.cleanup.Add(1) go func() { defer p.cleanup.Done() @@ -223,6 +230,9 @@ func (a *SlotAssembler) releasePrefetchLocked(s *slotState) { b.verification.wait() } } + if queueDone != nil { + <-queueDone + } p.a.mu.Lock() p.slots-- p.bytes -= f.bytes @@ -254,6 +264,10 @@ func (p *entryPrefetchPool) closeAndWait() { // invalid optimistic prefix. Unprefetched transactions form one immediately // available request, overlapping any early requests still running. func verifyDecodedEntryBatches(ctx context.Context, blk *block.Block, batches []*prefetchedShredBatch, verifier *transactionVerifier) error { + return verifyDecodedEntryBatchesWithTimings(ctx, blk, batches, verifier, nil) +} + +func verifyDecodedEntryBatchesWithTimings(ctx context.Context, blk *block.Block, batches []*prefetchedShredBatch, verifier *transactionVerifier, timings *entryDecodeTimings) error { type pending struct { future *transactionVerification offset int @@ -292,6 +306,9 @@ func verifyDecodedEntryBatches(ctx context.Context, blk *block.Block, batches [] var err error if len(missing) > 0 { fallback, err = verifier.submitTransactions(ctx, missing) + if timings != nil { + timings.traceFallback = fallback + } } firstIndex := len(blk.Transactions) firstErr := err diff --git a/pkg/turbine/entry_prefetch_benchmark_test.go b/pkg/turbine/entry_prefetch_benchmark_test.go index ee3443bf..be1ef6dc 100644 --- a/pkg/turbine/entry_prefetch_benchmark_test.go +++ b/pkg/turbine/entry_prefetch_benchmark_test.go @@ -66,6 +66,7 @@ type assemblyFlowFixture struct { parentID solana.Hash bankhash solana.Hash shreds int + holdGap bool } func makeAssemblyFlowFixture(tb testing.TB, source *block.Block) assemblyFlowFixture { @@ -165,6 +166,9 @@ func runAssemblyFlowBenchmark(b *testing.B, source *block.Block, fixture assembl time.Sleep(time.Until(started.Add(flowArrivalOffset(componentIndex, len(fixture.components), span)))) } for shredIndex, shred := range component { + if fixture.holdGap && componentIndex == len(fixture.components)*3/4 && shredIndex == 1 { + continue + } candidate, err := a.addShredFromWithRoot(shred, false, &fixture.authenticatedRoots[componentIndex][shredIndex]) if err != nil { b.Fatal(err) @@ -177,6 +181,14 @@ func runAssemblyFlowBenchmark(b *testing.B, source *block.Block, fixture assembl } } } + if fixture.holdGap { + ci := len(fixture.components) * 3 / 4 + candidate, err := a.addShredFromWithRoot(fixture.components[ci][1], false, &fixture.authenticatedRoots[ci][1]) + if err != nil || candidate == nil || work != nil { + b.Fatalf("held gap completion failed: %v", err) + } + work = candidate + } if work == nil { b.Fatal("all generated data shreds did not complete the slot") } @@ -256,3 +268,21 @@ func BenchmarkEntryMessageIdentityArrival(b *testing.B) { }) } } + +// Holds one data shred in a batch three quarters through the block until the +// footer has arrived. Other complete batches continue arriving over 200 ms. +// This isolates discovery behind a gap; it is not a measured network replay. +func BenchmarkEntryPrefetchGapArrival(b *testing.B) { + flowConfigureBackend(b) + for _, source := range flowBenchmarkFixtures(b) { + b.Run(source.name, func(b *testing.B) { + fixture := makeAssemblyFlowFixture(b, source.blk) + for _, gap := range []bool{false, true} { + b.Run(fmt.Sprintf("gap_%t", gap), func(b *testing.B) { + fixture.holdGap = gap + runAssemblyFlowBenchmark(b, source.blk, fixture, 2, 8, 200*time.Millisecond, true, true) + }) + } + }) + } +} diff --git a/pkg/turbine/entry_prefetch_test.go b/pkg/turbine/entry_prefetch_test.go index e22f514c..42caaa7e 100644 --- a/pkg/turbine/entry_prefetch_test.go +++ b/pkg/turbine/entry_prefetch_test.go @@ -3,6 +3,7 @@ package turbine import ( "context" "errors" + "fmt" "sync" "sync/atomic" "testing" @@ -358,3 +359,167 @@ func TestEntryPrefetchCanceledCompletionCanRetrySameGeneration(t *testing.T) { require.NotNil(t, blk) require.True(t, blk.TransactionSignaturesVerified()) } + +// A complete later batch must verify while an earlier batch still has a gap. +// Its preceding DATA_COMPLETE shred remains necessary to establish its start. +func TestEntryPrefetchBypassesEarlierGap(t *testing.T) { + for _, lateBoundary := range []bool{false, true} { + t.Run(fmt.Sprint("lateBoundary=", lateBoundary), func(t *testing.T) { + var calls atomic.Int32 + v := newTransactionVerifier(2, 8, func(tx *solana.Transaction) error { calls.Add(1); return txverify.VerifyTransaction(tx) }) + defer v.closeAndWait() + a := NewSlotAssembler() + p := newEntryPrefetchPool(context.Background(), a, v) + defer p.closeAndWait() + const slot = 909 + txs := verifierSignedTransactions(t, 60) + batches := prefetchTestShreds(t, slot, prefetchTestPayload(t, txs[:30]), prefetchTestPayload(t, txs[30:]), buildAlpenglowEndingTick(t)) + require.Greater(t, len(batches[0]), 2) + end := len(batches[0]) - 1 + for i, sh := range batches[0] { + if i == 1 || (lateBoundary && i == end) { + continue + } + require.Nil(t, feedPrefetchShreds(t, a, []*Shred{sh})) + } + require.Nil(t, feedPrefetchShreds(t, a, batches[1])) + if lateBoundary { + a.mu.Lock() + empty := len(a.slots[slot].completeBatches) == 0 + a.mu.Unlock() + require.True(t, empty, "unknown preceding boundary must prevent speculation") + require.Nil(t, feedPrefetchShreds(t, a, batches[0][end:])) + } + later := waitPrefetchedBatch(t, a, slot, batches[1][0].Index) + _, err := later.verification.wait() + require.NoError(t, err) + require.Equal(t, int32(30), calls.Load()) + require.Nil(t, feedPrefetchShreds(t, a, batches[0][1:2])) + earlier := waitPrefetchedBatch(t, a, slot, 0) + _, err = earlier.verification.wait() + require.NoError(t, err) + blk := feedPrefetchShreds(t, a, batches[2]) + require.NotNil(t, blk) + require.True(t, blk.TransactionSignaturesVerified()) + require.Len(t, blk.Transactions, 60) + require.Equal(t, int32(60), calls.Load(), "every signature verified exactly once") + for i, tx := range txs { + require.Equal(t, tx.Signatures[0], blk.Transactions[i].Signatures[0]) + } + }) + } +} + +func TestEntryPrefetchDiscoversRecoveredBoundary(t *testing.T) { + v := newTransactionVerifier(2, 8, nil) + defer v.closeAndWait() + a := NewSlotAssembler() + p := newEntryPrefetchPool(context.Background(), a, v) + defer p.closeAndWait() + const slot = 910 + txs := verifierSignedTransactions(t, 60) + gen := ShredGenerator{Slot: slot, ParentSlot: slot - 1, Version: 1} + raw := prefetchTestPayload(t, txs[:30]) + packets, root, nextData, nextCode, err := gen.MakeShredsFromData(testShredLeader(t), raw, false, solana.Hash{}, 0, 0) + require.NoError(t, err) + var code []*Shred + for _, packet := range packets { + sh, err := ParseShred(packet) + require.NoError(t, err) + if sh.Type == ShredTypeCode { + code = append(code, sh) + continue + } + if !sh.DataComplete() { + require.Nil(t, feedPrefetchShreds(t, a, []*Shred{sh})) + } + } + packets, _, _, _, err = gen.MakeShredsFromData(testShredLeader(t), prefetchTestPayload(t, txs[30:]), false, root, nextData, nextCode) + require.NoError(t, err) + for _, packet := range packets { + sh, err := ParseShred(packet) + require.NoError(t, err) + if sh.Type == ShredTypeData { + require.Nil(t, feedPrefetchShreds(t, a, []*Shred{sh})) + } + } + a.mu.Lock() + empty := len(a.slots[slot].completeBatches) == 0 + a.mu.Unlock() + require.True(t, empty) + require.NotEmpty(t, code) + for _, sh := range code { + require.Nil(t, feedPrefetchShreds(t, a, []*Shred{sh})) + } + later := waitPrefetchedBatch(t, a, slot, nextData) + _, err = later.verification.wait() + require.NoError(t, err) + first := waitPrefetchedBatch(t, a, slot, 0) + _, err = first.verification.wait() + require.NoError(t, err) +} + +func TestEntryPrefetchIndexDisabledAndLateInstall(t *testing.T) { + a := NewSlotAssembler() + batches := prefetchTestShreds(t, 911, prefetchTestPayload(t, verifierSignedTransactions(t, 3)), buildAlpenglowEndingTick(t)) + require.Nil(t, feedPrefetchShreds(t, a, batches[0])) + a.mu.Lock() + absent := a.slots[911].batchIndex == nil + a.mu.Unlock() + require.True(t, absent) + v := newTransactionVerifier(2, 8, nil) + defer v.closeAndWait() + p := newEntryPrefetchPool(context.Background(), a, v) + defer p.closeAndWait() + // Seeding also works on a coding-only admission with no new data recovery. + a.mu.Lock() + a.prefetchEntriesLocked(a.slots[911]) + a.mu.Unlock() + cached := waitPrefetchedBatch(t, a, 911, 0) + _, err := cached.verification.wait() + require.NoError(t, err) +} + +func TestEntryPrefetchResetRetainsQueuedReservations(t *testing.T) { + a := NewSlotAssembler() + ctx, cancel := context.WithCancel(context.Background()) + // Hold workers until after reset so all tokens remain in the channel. + p := &entryPrefetchPool{a: a, ctx: ctx, cancel: cancel, jobs: make(chan *slotState, entryPrefetchSlots)} + a.entryPrefetch = p + startWorker := sync.OnceFunc(func() { + p.workers.Add(1) + go p.run() + }) + defer func() { + startWorker() + p.closeAndWait() + }() + for i := 0; i < entryPrefetchSlots; i++ { + s := &slotState{slot: uint64(i), completeBatches: []shredBatchRange{{0, 0}}} + a.mu.Lock() + a.slots[s.slot] = s + a.prefetchEntriesLocked(s) + a.releasePrefetchLocked(s) + a.mu.Unlock() + } + require.Equal(t, entryPrefetchSlots, len(p.jobs)) + // Cleanup must not admit another generation while stale queue tokens live. + require.Never(t, func() bool { + a.mu.Lock() + defer a.mu.Unlock() + return p.slots != entryPrefetchSlots + }, 50*time.Millisecond, time.Millisecond) + fresh := &slotState{slot: 100, completeBatches: []shredBatchRange{{0, 0}}} + a.mu.Lock() + a.prefetchEntriesLocked(fresh) + reserved := fresh.prefetch != nil + a.mu.Unlock() + // Start the worker before assertions so test failures cannot strand cleanup. + startWorker() + require.False(t, reserved) + p.cleanup.Wait() + a.mu.Lock() + slots := p.slots + a.mu.Unlock() + require.Zero(t, slots) +} diff --git a/pkg/turbine/transaction_verifier.go b/pkg/turbine/transaction_verifier.go index bf176a20..3332eb80 100644 --- a/pkg/turbine/transaction_verifier.go +++ b/pkg/turbine/transaction_verifier.go @@ -24,17 +24,20 @@ const defaultTransactionJobGroups = 4 // A job is formed before admission, from transactions which are already // available. Workers never wait for more transactions to fill a vector group. type transactionVerifyJob struct { - ctx context.Context - txs []*solana.Transaction - identities []txverify.VerifiedMessageIdentity - errs []error - start int - done chan<- *transactionVerifyJob + trace bool + offeredAt, workerStart, workerEnd int64 + ctx context.Context + txs []*solana.Transaction + identities []txverify.VerifiedMessageIdentity + errs []error + start int + done chan<- *transactionVerifyJob } // transactionVerification owns an asynchronous request until done closes. // Transactions submitted to it must remain immutable until wait returns. type transactionVerification struct { + trace *entryVerificationTrace done chan struct{} cancel context.CancelFunc index int @@ -130,7 +133,15 @@ func newTransactionVerifierWithJobGroups(workers, queueDepth, batchTarget, jobGr // verifyGroup releases its job even if signature verification panics. The // request's bounded completion channel always has room for every pending job. func (v *transactionVerifier) verifyGroup(job *transactionVerifyJob, batch *txverify.BatchVerifier) { - defer func() { job.done <- job }() + if job.trace { + job.workerStart = entryTraceNow() + } + defer func() { + if job.trace { + job.workerEnd = entryTraceNow() + } + job.done <- job + }() for start := 0; start < len(job.txs); { // An admitted job always finishes its first vector group, preserving // ownership/join semantics. Cancellation can skip additional groups. @@ -172,6 +183,10 @@ func (v *transactionVerifier) submitTransactions(ctx context.Context, txs []*sol if err := ctx.Err(); err != nil { return nil, err } + var trace *entryVerificationTrace + if entryTraceContext(ctx) { + trace = &entryVerificationTrace{Submit: entryTraceNow(), Transactions: len(txs)} + } select { case v.requests <- struct{}{}: case <-ctx.Done(): @@ -189,7 +204,10 @@ func (v *transactionVerifier) submitTransactions(ctx context.Context, txs []*sol v.request.Add(1) v.mu.Unlock() ctx, cancel := context.WithCancel(ctx) - r := &transactionVerification{done: make(chan struct{}), cancel: cancel, index: -1} + if trace != nil { + trace.Admitted = entryTraceNow() + } + r := &transactionVerification{done: make(chan struct{}), cancel: cancel, index: -1, trace: trace} if v.verify == nil { r.identities = make([]txverify.VerifiedMessageIdentity, len(txs)) } @@ -197,7 +215,10 @@ func (v *transactionVerifier) submitTransactions(ctx context.Context, txs []*sol defer v.request.Done() defer func() { <-v.requests }() defer cancel() - r.index, r.err = v.verifyTransactionsWithIdentities(ctx, txs, r.identities) + r.index, r.err = v.verifyTransactionsWithTiming(ctx, txs, r.identities, trace) + if trace != nil { + trace.Finished = entryTraceNow() + } r.finishedAt = time.Now() close(r.done) }() @@ -213,6 +234,10 @@ func (v *transactionVerifier) verifyTransactions(ctx context.Context, txs []*sol } func (v *transactionVerifier) verifyTransactionsWithIdentities(ctx context.Context, txs []*solana.Transaction, identities []txverify.VerifiedMessageIdentity) (int, error) { + return v.verifyTransactionsWithTiming(ctx, txs, identities, nil) +} + +func (v *transactionVerifier) verifyTransactionsWithTiming(ctx context.Context, txs []*solana.Transaction, identities []txverify.VerifiedMessageIdentity, trace *entryVerificationTrace) (int, error) { if len(txs) == 0 { return -1, ctx.Err() } @@ -229,6 +254,7 @@ func (v *transactionVerifier) verifyTransactionsWithIdentities(ctx context.Conte errs := make([]error, window*jobCapacity) free := make([]*transactionVerifyJob, window) for i := range groups { + groups[i].trace = trace != nil groups[i].ctx = ctx groups[i].errs = errs[i*jobCapacity : (i+1)*jobCapacity] groups[i].done = completed @@ -256,6 +282,9 @@ func (v *transactionVerifier) verifyTransactionsWithIdentities(ctx context.Conte for group := 0; group < jobGroups && end < len(txs); group++ { end = transactionVerifyGroupEnd(txs, end, v.batchTarget) } + if trace != nil { + pending.offeredAt = entryTraceNow() + } pending.start = nextIndex pending.txs = txs[nextIndex:end] if identities != nil { @@ -274,6 +303,9 @@ func (v *transactionVerifier) verifyTransactionsWithIdentities(ctx context.Conte active++ pending = nil case job := <-completed: + if trace != nil { + trace.observe(job) + } active-- for i, err := range job.errs { if err != nil && (failureIndex < 0 || job.start+i < failureIndex) { From 7593722c2d1f9dbf514d631f9697e6d16bcb2644 Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Mon, 14 Sep 2026 20:45:28 -0500 Subject: [PATCH 014/183] Document isolated PR validation and retain relevant benchmark evidence --- .../out-of-order-prefetch/2026-09-15/README.md | 1 + .../2026-09-15/baseline-bench.log | 18 ++++++++++++++++++ .../2026-09-15/baseline-regression.log | 16 ++++++++++++++++ .../2026-09-15/benchmark-window.json | 1 + .../2026-09-15/candidate-bench.log | 18 ++++++++++++++++++ .../2026-09-15/index-bench.log | 7 +++++++ .../pr-split-2026-09-15/streaming/README.md | 7 +++++++ .../streaming/streaming-build.log | 0 .../streaming/streaming-tests.log | 6 ++++++ .../streaming/streaming-vet.log | 0 10 files changed, 74 insertions(+) create mode 100644 docs/results/out-of-order-prefetch/2026-09-15/README.md create mode 100644 docs/results/out-of-order-prefetch/2026-09-15/baseline-bench.log create mode 100644 docs/results/out-of-order-prefetch/2026-09-15/baseline-regression.log create mode 100644 docs/results/out-of-order-prefetch/2026-09-15/benchmark-window.json create mode 100644 docs/results/out-of-order-prefetch/2026-09-15/candidate-bench.log create mode 100644 docs/results/out-of-order-prefetch/2026-09-15/index-bench.log create mode 100644 docs/results/pr-split-2026-09-15/streaming/README.md create mode 100644 docs/results/pr-split-2026-09-15/streaming/streaming-build.log create mode 100644 docs/results/pr-split-2026-09-15/streaming/streaming-tests.log create mode 100644 docs/results/pr-split-2026-09-15/streaming/streaming-vet.log diff --git a/docs/results/out-of-order-prefetch/2026-09-15/README.md b/docs/results/out-of-order-prefetch/2026-09-15/README.md new file mode 100644 index 00000000..9472cdf3 --- /dev/null +++ b/docs/results/out-of-order-prefetch/2026-09-15/README.md @@ -0,0 +1 @@ +Native Zen5 evidence for docs/out-of-order-entry-prefetch.md. Baseline is the preceding streaming implementation, not alpenglow-dev. Identical generated33760-transaction fixtures, two verification workers, target8, GOMAXPROCS8, Narya r51, 200ms arrivals; baseline/candidate/candidate/baseline, three iterations per case per run. The delayed shred is in a batch three quarters through the block and released after the footer. The old regression is expected to fail; the new full Turbine/replay race suites passed. diff --git a/docs/results/out-of-order-prefetch/2026-09-15/baseline-bench.log b/docs/results/out-of-order-prefetch/2026-09-15/baseline-bench.log new file mode 100644 index 00000000..fcd07264 --- /dev/null +++ b/docs/results/out-of-order-prefetch/2026-09-15/baseline-bench.log @@ -0,0 +1,18 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchGapArrival/generated_228B/gap_false-8 3 203419380 ns/op 0.8933 avg_cpu_cores 200.9 collection_p50-ms 201.0 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 0.9940 completion_sigverify_p50-ms 1.374 completion_sigverify_p95-ms 128.0 components/block 181.7 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 2.883 full_to_identities_p50-ms 3.076 full_to_identities_p95-ms 2.560 full_to_ready_p50-ms 2.768 full_to_ready_p95-ms 0.2605 identity_admission_p50-ms 0.2795 identity_admission_p95-ms 7.912 mean_width 0.01855 preparation_wait_p50-ms 0.02018 preparation_wait_p95-ms 33760 tx/block 42116514 B/op 208938 allocs/op +BenchmarkEntryPrefetchGapArrival/generated_228B/gap_true-8 3 222455444 ns/op 0.7987 avg_cpu_cores 200.5 collection_p50-ms 201.0 collection_p95-ms 0.7364 completion_parse_p50-ms 0.9805 completion_parse_p95-ms 19.21 completion_sigverify_p50-ms 19.98 completion_sigverify_p95-ms 128.0 components/block 177.7 cpu-ms/block 8128 data_shreds/block 25555 early_verified_tx/block 21.66 full_to_identities_p50-ms 22.51 full_to_identities_p95-ms 21.43 full_to_ready_p50-ms 22.22 full_to_ready_p95-ms 0.2099 identity_admission_p50-ms 0.2381 identity_admission_p95-ms 7.932 mean_width 0.01560 preparation_wait_p50-ms 0.01561 preparation_wait_p95-ms 33760 tx/block 42224880 B/op 208484 allocs/op +BenchmarkEntryPrefetchGapArrival/generated_1232B/gap_false-8 3 208711001 ns/op 1.415 avg_cpu_cores 200.8 collection_p50-ms 201.7 collection_p95-ms 0 completion_parse_p50-ms 0.02004 completion_parse_p95-ms 0.8660 completion_sigverify_p50-ms 2.104 completion_sigverify_p95-ms 691.0 components/block 295.3 cpu-ms/block 44160 data_shreds/block 33711 early_verified_tx/block 7.178 full_to_identities_p50-ms 8.592 full_to_identities_p95-ms 6.909 full_to_ready_p50-ms 8.139 full_to_ready_p95-ms 0.2246 identity_admission_p50-ms 0.2708 identity_admission_p95-ms 7.002 mean_width 0.1018 preparation_wait_p50-ms 0.1058 preparation_wait_p95-ms 33760 tx/block 124307720 B/op 236270 allocs/op +BenchmarkEntryPrefetchGapArrival/generated_1232B/gap_true-8 3 239200703 ns/op 1.216 avg_cpu_cores 201.6 collection_p50-ms 202.3 collection_p95-ms 0.8561 completion_parse_p50-ms 1.145 completion_parse_p95-ms 28.34 completion_sigverify_p50-ms 30.65 completion_sigverify_p95-ms 691.0 components/block 290.9 cpu-ms/block 44160 data_shreds/block 25333 early_verified_tx/block 36.07 full_to_identities_p50-ms 40.96 full_to_identities_p95-ms 35.46 full_to_ready_p50-ms 40.48 full_to_ready_p95-ms 0.2848 identity_admission_p50-ms 0.4285 identity_admission_p95-ms 7.224 mean_width 0.08450 preparation_wait_p50-ms 0.08918 preparation_wait_p95-ms 33760 tx/block 124373101 B/op 233691 allocs/op +PASS +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchGapArrival/generated_228B/gap_false-8 3 203568075 ns/op 0.8848 avg_cpu_cores 200.8 collection_p50-ms 201.0 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 1.075 completion_sigverify_p50-ms 1.529 completion_sigverify_p95-ms 128.0 components/block 180.1 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 2.854 full_to_identities_p50-ms 3.315 full_to_identities_p95-ms 2.497 full_to_ready_p50-ms 3.061 full_to_ready_p95-ms 0.2661 identity_admission_p50-ms 0.3131 identity_admission_p95-ms 7.912 mean_width 0.01889 preparation_wait_p50-ms 0.02164 preparation_wait_p95-ms 33760 tx/block 42163530 B/op 208945 allocs/op +BenchmarkEntryPrefetchGapArrival/generated_228B/gap_true-8 3 225299379 ns/op 0.8924 avg_cpu_cores 200.7 collection_p50-ms 200.8 collection_p95-ms 0.8216 completion_parse_p50-ms 1.087 completion_parse_p95-ms 19.79 completion_sigverify_p50-ms 26.55 completion_sigverify_p95-ms 128.0 components/block 201.1 cpu-ms/block 8128 data_shreds/block 25555 early_verified_tx/block 23.01 full_to_identities_p50-ms 29.40 full_to_identities_p95-ms 22.77 full_to_ready_p50-ms 29.00 full_to_ready_p95-ms 0.1953 identity_admission_p50-ms 0.3365 identity_admission_p95-ms 7.932 mean_width 0.01832 preparation_wait_p50-ms 0.01964 preparation_wait_p95-ms 33760 tx/block 42175618 B/op 208465 allocs/op +BenchmarkEntryPrefetchGapArrival/generated_1232B/gap_false-8 3 208929240 ns/op 1.451 avg_cpu_cores 200.8 collection_p50-ms 200.9 collection_p95-ms 0.01374 completion_parse_p50-ms 0.03586 completion_parse_p95-ms 1.310 completion_sigverify_p50-ms 1.921 completion_sigverify_p95-ms 691.0 components/block 303.2 cpu-ms/block 44160 data_shreds/block 33695 early_verified_tx/block 8.115 full_to_identities_p50-ms 8.617 full_to_identities_p95-ms 7.671 full_to_ready_p50-ms 8.154 full_to_ready_p95-ms 0.2751 identity_admission_p50-ms 0.2978 identity_admission_p95-ms 7.001 mean_width 0.1099 preparation_wait_p50-ms 0.1156 preparation_wait_p95-ms 33760 tx/block 124208197 B/op 236242 allocs/op +BenchmarkEntryPrefetchGapArrival/generated_1232B/gap_true-8 3 238923610 ns/op 1.217 avg_cpu_cores 202.1 collection_p50-ms 202.1 collection_p95-ms 0.8885 completion_parse_p50-ms 1.180 completion_parse_p95-ms 29.01 completion_sigverify_p50-ms 29.63 completion_sigverify_p95-ms 691.0 components/block 290.8 cpu-ms/block 44160 data_shreds/block 25333 early_verified_tx/block 36.76 full_to_identities_p50-ms 38.95 full_to_identities_p95-ms 36.34 full_to_ready_p50-ms 38.47 full_to_ready_p95-ms 0.2954 identity_admission_p50-ms 0.2956 identity_admission_p95-ms 7.224 mean_width 0.08041 preparation_wait_p50-ms 0.08621 preparation_wait_p95-ms 33760 tx/block 124193456 B/op 233703 allocs/op +PASS diff --git a/docs/results/out-of-order-prefetch/2026-09-15/baseline-regression.log b/docs/results/out-of-order-prefetch/2026-09-15/baseline-regression.log new file mode 100644 index 00000000..c314b359 --- /dev/null +++ b/docs/results/out-of-order-prefetch/2026-09-15/baseline-regression.log @@ -0,0 +1,16 @@ +--- FAIL: TestEntryPrefetchBypassesEarlierGap (6.01s) + --- FAIL: TestEntryPrefetchBypassesEarlierGap/lateBoundary=false (3.00s) + gap_regression_test.go:39: + Error Trace: /srv/mithril-out-of-order-prefetch-20260915/benchmark-baseline/pkg/turbine/entry_prefetch_test.go:66 + /srv/mithril-out-of-order-prefetch-20260915/benchmark-baseline/pkg/turbine/gap_regression_test.go:39 + Error: Condition never satisfied + Test: TestEntryPrefetchBypassesEarlierGap/lateBoundary=false + --- FAIL: TestEntryPrefetchBypassesEarlierGap/lateBoundary=true (3.00s) + gap_regression_test.go:39: + Error Trace: /srv/mithril-out-of-order-prefetch-20260915/benchmark-baseline/pkg/turbine/entry_prefetch_test.go:66 + /srv/mithril-out-of-order-prefetch-20260915/benchmark-baseline/pkg/turbine/gap_regression_test.go:39 + Error: Condition never satisfied + Test: TestEntryPrefetchBypassesEarlierGap/lateBoundary=true +FAIL +FAIL github.com/Overclock-Validator/mithril/pkg/turbine 6.032s +FAIL diff --git a/docs/results/out-of-order-prefetch/2026-09-15/benchmark-window.json b/docs/results/out-of-order-prefetch/2026-09-15/benchmark-window.json new file mode 100644 index 00000000..456a772d --- /dev/null +++ b/docs/results/out-of-order-prefetch/2026-09-15/benchmark-window.json @@ -0,0 +1 @@ +{"start": "2026-09-15T01:23:33.704018+00:00", "end": "2026-09-15T01:24:04.072112+00:00"} \ No newline at end of file diff --git a/docs/results/out-of-order-prefetch/2026-09-15/candidate-bench.log b/docs/results/out-of-order-prefetch/2026-09-15/candidate-bench.log new file mode 100644 index 00000000..2b574a3d --- /dev/null +++ b/docs/results/out-of-order-prefetch/2026-09-15/candidate-bench.log @@ -0,0 +1,18 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchGapArrival/generated_228B/gap_false-8 3 203625072 ns/op 0.9958 avg_cpu_cores 201.0 collection_p50-ms 201.1 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 1.063 completion_sigverify_p50-ms 1.159 completion_sigverify_p95-ms 128.0 components/block 202.8 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 2.710 full_to_identities_p50-ms 2.947 full_to_identities_p95-ms 2.519 full_to_ready_p50-ms 2.619 full_to_ready_p95-ms 0.1543 identity_admission_p50-ms 0.2779 identity_admission_p95-ms 7.912 mean_width 0.02061 preparation_wait_p50-ms 0.02297 preparation_wait_p95-ms 33760 tx/block 42057354 B/op 208959 allocs/op +BenchmarkEntryPrefetchGapArrival/generated_228B/gap_true-8 3 203765428 ns/op 0.8952 avg_cpu_cores 200.7 collection_p50-ms 200.9 collection_p95-ms 0.02773 completion_parse_p50-ms 0.02990 completion_parse_p95-ms 1.474 completion_sigverify_p50-ms 1.541 completion_sigverify_p95-ms 128.0 components/block 182.4 cpu-ms/block 8128 data_shreds/block 33491 early_verified_tx/block 3.158 full_to_identities_p50-ms 3.264 full_to_identities_p95-ms 2.830 full_to_ready_p50-ms 2.941 full_to_ready_p95-ms 0.2819 identity_admission_p50-ms 0.2881 identity_admission_p95-ms 7.912 mean_width 0.01931 preparation_wait_p50-ms 0.02116 preparation_wait_p95-ms 33760 tx/block 41870840 B/op 208905 allocs/op +BenchmarkEntryPrefetchGapArrival/generated_1232B/gap_false-8 3 208751838 ns/op 1.397 avg_cpu_cores 201.2 collection_p50-ms 201.5 collection_p95-ms 0 completion_parse_p50-ms 0.008235 completion_parse_p95-ms 0.9218 completion_sigverify_p50-ms 1.698 completion_sigverify_p95-ms 691.0 components/block 291.7 cpu-ms/block 44160 data_shreds/block 33744 early_verified_tx/block 7.301 full_to_identities_p50-ms 8.281 full_to_identities_p95-ms 6.868 full_to_ready_p50-ms 7.893 full_to_ready_p95-ms 0.2754 identity_admission_p50-ms 0.2821 identity_admission_p95-ms 7.001 mean_width 0.1045 preparation_wait_p50-ms 0.1074 preparation_wait_p95-ms 33760 tx/block 124374250 B/op 236276 allocs/op +BenchmarkEntryPrefetchGapArrival/generated_1232B/gap_true-8 3 209871843 ns/op 1.442 avg_cpu_cores 201.0 collection_p50-ms 201.2 collection_p95-ms 0.01179 completion_parse_p50-ms 0.03625 completion_parse_p95-ms 1.889 completion_sigverify_p50-ms 2.005 completion_sigverify_p95-ms 691.0 components/block 302.6 cpu-ms/block 44160 data_shreds/block 33662 early_verified_tx/block 8.442 full_to_identities_p50-ms 9.757 full_to_identities_p95-ms 8.081 full_to_ready_p50-ms 9.206 full_to_ready_p95-ms 0.3298 identity_admission_p50-ms 0.3725 identity_admission_p95-ms 7.002 mean_width 0.1180 preparation_wait_p50-ms 0.1203 preparation_wait_p95-ms 33760 tx/block 124131978 B/op 236199 allocs/op +PASS +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryPrefetchGapArrival/generated_228B/gap_false-8 3 203319966 ns/op 0.8970 avg_cpu_cores 200.8 collection_p50-ms 201.2 collection_p95-ms 0 completion_parse_p50-ms 0 completion_parse_p95-ms 1.036 completion_sigverify_p50-ms 1.079 completion_sigverify_p95-ms 128.0 components/block 182.4 cpu-ms/block 8128 data_shreds/block 33760 early_verified_tx/block 2.646 full_to_identities_p50-ms 2.726 full_to_identities_p95-ms 2.401 full_to_ready_p50-ms 2.524 full_to_ready_p95-ms 0.2021 identity_admission_p50-ms 0.2745 identity_admission_p95-ms 7.912 mean_width 0.01811 preparation_wait_p50-ms 0.02068 preparation_wait_p95-ms 33760 tx/block 41962456 B/op 208936 allocs/op +BenchmarkEntryPrefetchGapArrival/generated_228B/gap_true-8 3 203727557 ns/op 0.8970 avg_cpu_cores 200.7 collection_p50-ms 200.9 collection_p95-ms 0.03751 completion_parse_p50-ms 0.03875 completion_parse_p95-ms 1.457 completion_sigverify_p50-ms 1.465 completion_sigverify_p95-ms 128.0 components/block 182.7 cpu-ms/block 8128 data_shreds/block 33491 early_verified_tx/block 3.096 full_to_identities_p50-ms 3.145 full_to_identities_p95-ms 2.820 full_to_ready_p50-ms 2.918 full_to_ready_p95-ms 0.1335 identity_admission_p50-ms 0.2832 identity_admission_p95-ms 7.912 mean_width 0.01969 preparation_wait_p50-ms 0.02175 preparation_wait_p95-ms 33760 tx/block 42057861 B/op 208933 allocs/op +BenchmarkEntryPrefetchGapArrival/generated_1232B/gap_false-8 3 209401141 ns/op 1.445 avg_cpu_cores 201.1 collection_p50-ms 202.0 collection_p95-ms 0.01781 completion_parse_p50-ms 0.01969 completion_parse_p95-ms 1.327 completion_sigverify_p50-ms 1.796 completion_sigverify_p95-ms 691.0 components/block 302.6 cpu-ms/block 44160 data_shreds/block 33679 early_verified_tx/block 8.305 full_to_identities_p50-ms 8.707 full_to_identities_p95-ms 7.891 full_to_ready_p50-ms 8.216 full_to_ready_p95-ms 0.2680 identity_admission_p50-ms 0.2807 identity_admission_p95-ms 7.001 mean_width 0.1102 preparation_wait_p50-ms 0.1178 preparation_wait_p95-ms 33760 tx/block 124370002 B/op 236242 allocs/op +BenchmarkEntryPrefetchGapArrival/generated_1232B/gap_true-8 3 208867308 ns/op 1.394 avg_cpu_cores 201.0 collection_p50-ms 201.6 collection_p95-ms 0.006092 completion_parse_p50-ms 0.01323 completion_parse_p95-ms 1.120 completion_sigverify_p50-ms 1.672 completion_sigverify_p95-ms 691.0 components/block 291.1 cpu-ms/block 44160 data_shreds/block 33711 early_verified_tx/block 7.502 full_to_identities_p50-ms 8.357 full_to_identities_p95-ms 7.037 full_to_ready_p50-ms 7.895 full_to_ready_p95-ms 0.2785 identity_admission_p50-ms 0.2925 identity_admission_p95-ms 7.001 mean_width 0.1067 preparation_wait_p50-ms 0.1109 preparation_wait_p95-ms 33760 tx/block 124318808 B/op 236225 allocs/op +PASS diff --git a/docs/results/out-of-order-prefetch/2026-09-15/index-bench.log b/docs/results/out-of-order-prefetch/2026-09-15/index-bench.log new file mode 100644 index 00000000..f2a26550 --- /dev/null +++ b/docs/results/out-of-order-prefetch/2026-09-15/index-bench.log @@ -0,0 +1,7 @@ +goos: linux +goarch: amd64 +pkg: github.com/Overclock-Validator/mithril/pkg/turbine +cpu: AMD Ryzen 7 9700X 8-Core Processor +BenchmarkEntryBatchIndex/ordered-8 5683 212759 ns/op 3.246 ns/shred 0 B/op 0 allocs/op +BenchmarkEntryBatchIndex/reverse-8 3334 368259 ns/op 5.619 ns/shred 0 B/op 0 allocs/op +PASS diff --git a/docs/results/pr-split-2026-09-15/streaming/README.md b/docs/results/pr-split-2026-09-15/streaming/README.md new file mode 100644 index 00000000..1432d858 --- /dev/null +++ b/docs/results/pr-split-2026-09-15/streaming/README.md @@ -0,0 +1,7 @@ +# Review branch validation, September 15 + +This PR is split from #279 plus the later working-tree improvements. The tested code commit before this documentation commit was `a41b108d797f55045ef13479fbd6fcf362a1ce52`. Tests ran locally on Apple M4 Pro, Go1.26.4, GOMAXPROCS3 and package parallelism2. Logs beside this file are the fresh split-branch checks, not native measurements. Existing Zen5 benchmark documents retain their original baselines and scope. No validator restart or deployment occurred during this reorganization. + +Four independent branches start at current alpenglow-dev33dde405. Voting is based on the certificate-processing PR; leader packing is based on the streaming-preparation PR. Runtime changes and status-cache changes are independent. Shared CLI/configuration additions need an ordinary three-file merge reconciliation when combining leader packing and voting. A separate audit checkout reconciled these additions and matched the preserved full implementation exactly across Go sources, module files, TOML configuration and CI. + +The branch-specific race suites and vet passed. The combined audit has a separately documented pre-existing intermittent peer reconnect timeout; this is not reported as an entirely green combined race run. diff --git a/docs/results/pr-split-2026-09-15/streaming/streaming-build.log b/docs/results/pr-split-2026-09-15/streaming/streaming-build.log new file mode 100644 index 00000000..e69de29b diff --git a/docs/results/pr-split-2026-09-15/streaming/streaming-tests.log b/docs/results/pr-split-2026-09-15/streaming/streaming-tests.log new file mode 100644 index 00000000..1f7e405b --- /dev/null +++ b/docs/results/pr-split-2026-09-15/streaming/streaming-tests.log @@ -0,0 +1,6 @@ +ok github.com/Overclock-Validator/mithril/pkg/turbine 9.651s +ok github.com/Overclock-Validator/mithril/pkg/block 1.780s +ok github.com/Overclock-Validator/mithril/pkg/txverify 1.192s +ok github.com/Overclock-Validator/mithril/pkg/txstatus 1.174s +ok github.com/Overclock-Validator/mithril/pkg/sigverify 22.929s +ok github.com/Overclock-Validator/mithril/pkg/replay 4.239s diff --git a/docs/results/pr-split-2026-09-15/streaming/streaming-vet.log b/docs/results/pr-split-2026-09-15/streaming/streaming-vet.log new file mode 100644 index 00000000..e69de29b From ef927bd136738ac5dd90f5f288c5c209c4115a10 Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Mon, 14 Sep 2026 20:46:13 -0500 Subject: [PATCH 015/183] Normalize benchmark document formatting --- docs/out-of-order-entry-prefetch.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/out-of-order-entry-prefetch.md b/docs/out-of-order-entry-prefetch.md index b435405b..c24e2dbd 100644 --- a/docs/out-of-order-entry-prefetch.md +++ b/docs/out-of-order-entry-prefetch.md @@ -32,4 +32,3 @@ Across the 25 external blocks, maximum complete-availability-to-discovery delay The first completed current-build FAST capture, filtered to source slots first observed after01:27UTC and deduplicated by full proof key, included us in461/466FAST certificates (98.93%); large blocks were79/82 (96.34%). This is a local footer sample, not the rolling Puffin score or Titan reward inclusion. It does not establish a lasting overall FAST improvement. All751clean replay observations had notarize events; no reservation exhaustion was observed. A separate30second probe sanity check also had112/112replay/notarize, no rejection/exhaustion and no parse/truncation errors. At01:30:27UTC voting was current within3slots, allfourservices active,88/88peer connections, zero broadcast drops, peer-send errors, queue drops/discards/timeouts or connection errors. Three completed own-leader load windows produced12blocks with zero sender errors, up to48,622transactions/block. Counts by window:3798364=[22447,48622,44343,43730];3799208=[17139,48622,36041,40611];3799488=[22814,46680,41221,42949]. The existing continuous loader and all monitoring remain running. - From 7934bacb8397b6df15367b1b661a4c1038db4b6c Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Mon, 14 Sep 2026 22:23:52 -0500 Subject: [PATCH 016/183] Recover safely from inconsistent entry identities and own streaming config --- cmd/mithril/configcmd/configcmd.go | 7 +- cmd/mithril/configcmd/configcmd_test.go | 24 ++ .../results/review-fixes/2026-09-15/README.md | 15 ++ .../2026-09-15/native-blackhole-race.log | 242 ++++++++++++++++++ .../2026-09-15/native-build-final.log | 6 + .../review-fixes/2026-09-15/native-build.log | 0 .../2026-09-15/native-config-final.log | 9 + .../review-fixes/2026-09-15/native-race.log | 10 + .../review-fixes/2026-09-15/native-run.log | 10 + .../2026-09-15/native-summary.json | 14 + .../review-fixes/2026-09-15/native-vet.log | 0 .../2026-09-15/native-window.json | 4 + .../2026-09-15/post-test-health.json | 1 + .../2026-09-15/streaming-before.log | 37 +++ .../2026-09-15/streaming-build.log | 0 .../2026-09-15/streaming-config-final.log | 1 + .../2026-09-15/streaming-race.log | 7 + .../2026-09-15/streaming-targeted.log | 2 + .../review-fixes/2026-09-15/streaming-vet.log | 0 .../2026-09-15/tested-source.json | 16 ++ .../review-fixes/2026-09-15/voting-before.log | 18 ++ .../2026-09-15/voting-blackhole-race.log | 1 + .../review-fixes/2026-09-15/voting-build.log | 0 .../review-fixes/2026-09-15/voting-race.log | 4 + .../2026-09-15/voting-targeted.log | 1 + .../review-fixes/2026-09-15/voting-vet.log | 0 docs/streaming_message_identities.md | 26 ++ pkg/turbine/entry_identity_recovery_test.go | 131 ++++++++++ pkg/turbine/entry_prefetch.go | 47 +++- 29 files changed, 625 insertions(+), 8 deletions(-) create mode 100644 cmd/mithril/configcmd/configcmd_test.go create mode 100644 docs/results/review-fixes/2026-09-15/README.md create mode 100644 docs/results/review-fixes/2026-09-15/native-blackhole-race.log create mode 100644 docs/results/review-fixes/2026-09-15/native-build-final.log create mode 100644 docs/results/review-fixes/2026-09-15/native-build.log create mode 100644 docs/results/review-fixes/2026-09-15/native-config-final.log create mode 100644 docs/results/review-fixes/2026-09-15/native-race.log create mode 100644 docs/results/review-fixes/2026-09-15/native-run.log create mode 100644 docs/results/review-fixes/2026-09-15/native-summary.json create mode 100644 docs/results/review-fixes/2026-09-15/native-vet.log create mode 100644 docs/results/review-fixes/2026-09-15/native-window.json create mode 100644 docs/results/review-fixes/2026-09-15/post-test-health.json create mode 100644 docs/results/review-fixes/2026-09-15/streaming-before.log create mode 100644 docs/results/review-fixes/2026-09-15/streaming-build.log create mode 100644 docs/results/review-fixes/2026-09-15/streaming-config-final.log create mode 100644 docs/results/review-fixes/2026-09-15/streaming-race.log create mode 100644 docs/results/review-fixes/2026-09-15/streaming-targeted.log create mode 100644 docs/results/review-fixes/2026-09-15/streaming-vet.log create mode 100644 docs/results/review-fixes/2026-09-15/tested-source.json create mode 100644 docs/results/review-fixes/2026-09-15/voting-before.log create mode 100644 docs/results/review-fixes/2026-09-15/voting-blackhole-race.log create mode 100644 docs/results/review-fixes/2026-09-15/voting-build.log create mode 100644 docs/results/review-fixes/2026-09-15/voting-race.log create mode 100644 docs/results/review-fixes/2026-09-15/voting-targeted.log create mode 100644 docs/results/review-fixes/2026-09-15/voting-vet.log create mode 100644 pkg/turbine/entry_identity_recovery_test.go diff --git a/cmd/mithril/configcmd/configcmd.go b/cmd/mithril/configcmd/configcmd.go index 903ff68c..3236b9fc 100644 --- a/cmd/mithril/configcmd/configcmd.go +++ b/cmd/mithril/configcmd/configcmd.go @@ -261,7 +261,12 @@ max_rps = 8 # Verifier's own RPC budget (never shares the block-fe # ── Replay tuning ──────────────────────────────────────────────────────── [tuning] txpar = 24 # Validator auto-defaults to 2x CPU cores only when unset; explicit 0 = sequential -sigverify_backend = "auto" # auto|r51|generic|stdlib; stdlib uses Go's crypto/ed25519 impl after strict checks. + +[sigverify] +backend = "auto" # auto|r51|generic|stdlib +workers = 0 # 0 = min(2, GOMAXPROCS); explicit value overrides the shared transaction pool +batch_target = 8 # 4 or 8 signature lanes; available work runs immediately +disable_shred_overlap = false # Diagnostic fallback: verify after complete block assembly # ── Mithril's RPC server ───────────────────────────────────────────────── [rpc] diff --git a/cmd/mithril/configcmd/configcmd_test.go b/cmd/mithril/configcmd/configcmd_test.go new file mode 100644 index 00000000..2d62bb8b --- /dev/null +++ b/cmd/mithril/configcmd/configcmd_test.go @@ -0,0 +1,24 @@ +package configcmd + +import ( + "strings" + "testing" + + "github.com/spf13/viper" + "github.com/stretchr/testify/require" +) + +func TestStarterConfigSignatureVerification(t *testing.T) { + for _, validator := range []bool{false, true} { + v := viper.New() + v.SetConfigType("toml") + require.NoError(t, v.ReadConfig(strings.NewReader(generateStarterConfig(validator)))) + require.Equal(t, "auto", v.GetString("sigverify.backend")) + require.True(t, v.IsSet("sigverify.workers")) + require.Zero(t, v.GetInt("sigverify.workers")) + require.Equal(t, 8, v.GetInt("sigverify.batch_target")) + require.True(t, v.IsSet("sigverify.disable_shred_overlap")) + require.False(t, v.GetBool("sigverify.disable_shred_overlap")) + require.False(t, v.IsSet("tuning.sigverify_backend")) + } +} diff --git a/docs/results/review-fixes/2026-09-15/README.md b/docs/results/review-fixes/2026-09-15/README.md new file mode 100644 index 00000000..953ef105 --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/README.md @@ -0,0 +1,15 @@ +# Review follow-up validation, September 15 + +Fixes the stalled-peer deadline, remote-close reconnect paths, config-template ownership and entry-identity recovery from the external review. The two-worker Turbine default remains unchanged. + +The sender deadline now covers queue wait plus the active QUIC enqueue, with an age check at dequeue as well. Every sender exit requests a bounded/deduplicated reconnect, subject to desired-peer, shutdown and replacement checks. Peer queues remain bounded FIFO with existing best-effort failure/discard behavior; no voting decision, persistence or certificate rule changed. + +Streaming handles missing/oversized ranges and partial/mismatched identities by joining old readers and fully re-verifying final transactions. Valid blocks recover from optimization faults; invalid signatures, failed recovery, closed verifiers and cancellation remain errors. The template and test live with the config reader in streaming. VM pooling remains owned by the runtime branch: the standalone streaming template does not enable it implicitly. + +Before-fix logs demonstrate missing reconnect requests in both idle/dequeue paths, missing queue-age expiry, stale enqueueing and valid-block rejection on inconsistent identity metadata. After-fix targeted race tests pass. Full local standalone voting and streaming race suites, vet and builds pass. Final template narrowing also has separate config-test evidence. + +The native combined checkout includes all six branches, the later transaction-status publication work and these fixes. Zen 5 Ryzen 7 9700X, Go 1.26.4, GOMAXPROCS=2, package parallelism=2; isolated staging process with CPU quota 200%, Nice=15, memory cap 6 GB. Full native race suites passed for Alpenglow, consensus, Turbine, block, txverify, txstatus, sigverify, replay, configcmd and node. Native vet and validator build passed. After narrowing the template, config/default/node race tests and the final native build passed again. + +The real QUIC blackhole regression passed ten race runs on M4 Pro and ten on Zen 5. Each run covers reconnect, shutdown, peer departure and address replacement. Native watchdog retirement was 1.038–1.098 seconds after the fault; healthy marker latency across 40 subcases was 0.180 ms median, 8.361 ms maximum. These are loopback regression measurements under race detection, not live network delivery or FAST results. The existing 250 ms healthy-marker assertion was retained. Retirement allowance is measured from the fault with explicit scheduler slack. Deterministic reconnect tests disable reconciliation entirely, so a later tick cannot hide the bug. + +Source hashes, test failures before changes, passing logs and native timing summary are retained here. Native test/build transcripts have native prefixes. The staging executable was not deployed. The enrolled validator remained PID 568418, voting at lag one with all four server services active at the final health check. diff --git a/docs/results/review-fixes/2026-09-15/native-blackhole-race.log b/docs/results/review-fixes/2026-09-15/native-blackhole-race.log new file mode 100644 index 00000000..76de07e9 --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/native-blackhole-race.log @@ -0,0 +1,242 @@ +=== RUN TestVotorBroadcasterIsolatesBlockedPeer +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/reconnect +(+ 0s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 0s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 391.583µs while other peer's SendDatagram is blocked + peer_sender_test.go:216: Blackholed peer retired after 1.092794036s +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/close +(+ 1s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 1s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 323.005µs while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/depart +(+ 1s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 1s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 549.921µs while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/move +(+ 1s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 1s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 3.679084ms while other peer's SendDatagram is blocked +(+ 1s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +--- PASS: TestVotorBroadcasterIsolatesBlockedPeer (1.37s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/reconnect (1.32s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/close (0.01s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/depart (0.01s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/move (0.02s) +=== RUN TestVotorBroadcasterIsolatesBlockedPeer +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/reconnect +(+ 1s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 1s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 124.033µs while other peer's SendDatagram is blocked + peer_sender_test.go:216: Blackholed peer retired after 1.096725481s +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/close +(+ 2s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 2s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 3.817733ms while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/depart +(+ 2s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 2s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 190.036µs while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/move +(+ 2s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 2s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 88.305µs while other peer's SendDatagram is blocked +(+ 2s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +--- PASS: TestVotorBroadcasterIsolatesBlockedPeer (1.16s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/reconnect (1.11s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/close (0.01s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/depart (0.01s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/move (0.02s) +=== RUN TestVotorBroadcasterIsolatesBlockedPeer +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/reconnect +(+ 2s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 2s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 4.433337ms while other peer's SendDatagram is blocked + peer_sender_test.go:216: Blackholed peer retired after 1.097000497s +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/close +(+ 3s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 3s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 69.74µs while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/depart +(+ 3s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 3s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 4.71775ms while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/move +(+ 3s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 3s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 150.843µs while other peer's SendDatagram is blocked +(+ 3s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +--- PASS: TestVotorBroadcasterIsolatesBlockedPeer (1.36s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/reconnect (1.31s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/close (0.01s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/depart (0.01s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/move (0.02s) +=== RUN TestVotorBroadcasterIsolatesBlockedPeer +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/reconnect +(+ 3s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 3s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 219.862µs while other peer's SendDatagram is blocked + peer_sender_test.go:216: Blackholed peer retired after 1.097559214s +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/close +(+ 5s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 5s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 152.987µs while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/depart +(+ 5s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 5s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 8.361257ms while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/move +(+ 5s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 5s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 146.214µs while other peer's SendDatagram is blocked +(+ 5s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +--- PASS: TestVotorBroadcasterIsolatesBlockedPeer (1.39s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/reconnect (1.32s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/close (0.03s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/depart (0.02s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/move (0.03s) +=== RUN TestVotorBroadcasterIsolatesBlockedPeer +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/reconnect +(+ 5s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 5s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 4.565925ms while other peer's SendDatagram is blocked + peer_sender_test.go:216: Blackholed peer retired after 1.037632347s +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/close +(+ 6s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 6s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 125.615µs while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/depart +(+ 6s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 6s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 118.261µs while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/move +(+ 6s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 6s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 209.753µs while other peer's SendDatagram is blocked +(+ 6s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +--- PASS: TestVotorBroadcasterIsolatesBlockedPeer (1.31s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/reconnect (1.26s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/close (0.01s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/depart (0.01s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/move (0.02s) +=== RUN TestVotorBroadcasterIsolatesBlockedPeer +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/reconnect +(+ 6s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 6s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 95.769µs while other peer's SendDatagram is blocked + peer_sender_test.go:216: Blackholed peer retired after 1.097403342s +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/close +(+ 7s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 7s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 81.482µs while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/depart +(+ 7s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 7s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 85.37µs while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/move +(+ 7s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 7s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 113.492µs while other peer's SendDatagram is blocked +(+ 7s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +--- PASS: TestVotorBroadcasterIsolatesBlockedPeer (1.36s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/reconnect (1.32s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/close (0.01s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/depart (0.01s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/move (0.02s) +=== RUN TestVotorBroadcasterIsolatesBlockedPeer +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/reconnect +(+ 7s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 7s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 169.097µs while other peer's SendDatagram is blocked + peer_sender_test.go:216: Blackholed peer retired after 1.098292458s +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/close +(+ 9s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 9s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 4.337057ms while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/depart +(+ 9s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 9s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 153.357µs while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/move +(+ 9s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 9s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 4.582918ms while other peer's SendDatagram is blocked +(+ 9s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +--- PASS: TestVotorBroadcasterIsolatesBlockedPeer (1.36s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/reconnect (1.32s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/close (0.01s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/depart (0.01s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/move (0.02s) +=== RUN TestVotorBroadcasterIsolatesBlockedPeer +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/reconnect +(+ 9s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 9s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 160.09µs while other peer's SendDatagram is blocked + peer_sender_test.go:216: Blackholed peer retired after 1.097958692s +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/close +(+ 10s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 10s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 89.748µs while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/depart +(+ 10s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 10s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 278.562µs while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/move +(+ 10s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 10s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 4.742486ms while other peer's SendDatagram is blocked +(+ 10s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +--- PASS: TestVotorBroadcasterIsolatesBlockedPeer (1.36s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/reconnect (1.32s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/close (0.01s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/depart (0.01s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/move (0.02s) +=== RUN TestVotorBroadcasterIsolatesBlockedPeer +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/reconnect +(+ 10s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 10s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 109.656µs while other peer's SendDatagram is blocked + peer_sender_test.go:216: Blackholed peer retired after 1.098472025s +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/close +(+ 11s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 11s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 647.754µs while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/depart +(+ 12s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 12s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 4.269089ms while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/move +(+ 12s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 12s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 3.536917ms while other peer's SendDatagram is blocked +(+ 12s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +--- PASS: TestVotorBroadcasterIsolatesBlockedPeer (1.36s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/reconnect (1.32s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/close (0.01s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/depart (0.01s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/move (0.02s) +=== RUN TestVotorBroadcasterIsolatesBlockedPeer +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/reconnect +(+ 12s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 12s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 111.178µs while other peer's SendDatagram is blocked + peer_sender_test.go:216: Blackholed peer retired after 1.098050635s +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/close +(+ 13s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 13s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 82.054µs while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/depart +(+ 13s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 13s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 1.004662ms while other peer's SendDatagram is blocked +=== RUN TestVotorBroadcasterIsolatesBlockedPeer/move +(+ 13s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +(+ 13s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) + peer_sender_test.go:135: Healthy marker received in 103.303µs while other peer's SendDatagram is blocked +(+ 13s) ALPENGLOW Votor receiver decoded first message (votes=1 certificates=0 latest_vote_slot=999999 latest_certificate_slot=0) +--- PASS: TestVotorBroadcasterIsolatesBlockedPeer (1.36s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/reconnect (1.32s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/close (0.01s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/depart (0.02s) + --- PASS: TestVotorBroadcasterIsolatesBlockedPeer/move (0.02s) +PASS +ok github.com/Overclock-Validator/mithril/pkg/alpenglow 14.403s diff --git a/docs/results/review-fixes/2026-09-15/native-build-final.log b/docs/results/review-fixes/2026-09-15/native-build-final.log new file mode 100644 index 00000000..710ce41d --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/native-build-final.log @@ -0,0 +1,6 @@ +Running as unit: mithril-review-build-final-20260915.service; invocation ID: f2a0b767b9084c4791e7f8566c5bd48f + Finished with result: success +Main processes terminated with: code=exited, status=0/SUCCESS + Service runtime: 2.115s + CPU time consumed: 2.484s + Memory peak: 529.2M (swap: 0B) diff --git a/docs/results/review-fixes/2026-09-15/native-build.log b/docs/results/review-fixes/2026-09-15/native-build.log new file mode 100644 index 00000000..e69de29b diff --git a/docs/results/review-fixes/2026-09-15/native-config-final.log b/docs/results/review-fixes/2026-09-15/native-config-final.log new file mode 100644 index 00000000..2cfbfeb2 --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/native-config-final.log @@ -0,0 +1,9 @@ +Running as unit: mithril-review-config-final-20260915.service +ok github.com/Overclock-Validator/mithril/pkg/config 1.006s +ok github.com/Overclock-Validator/mithril/cmd/mithril/configcmd 1.007s +ok github.com/Overclock-Validator/mithril/cmd/mithril/node 1.140s + Finished with result: success +Main processes terminated with: code=exited, status=0/SUCCESS + Service runtime: 3.313s + CPU time consumed: 1.955s + Memory peak: 375.3M (swap: 0B) diff --git a/docs/results/review-fixes/2026-09-15/native-race.log b/docs/results/review-fixes/2026-09-15/native-race.log new file mode 100644 index 00000000..ab1b51f7 --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/native-race.log @@ -0,0 +1,10 @@ +ok github.com/Overclock-Validator/mithril/pkg/alpenglow 6.472s +ok github.com/Overclock-Validator/mithril/pkg/consensus 2.971s +ok github.com/Overclock-Validator/mithril/pkg/turbine 6.195s +ok github.com/Overclock-Validator/mithril/pkg/block 1.201s +ok github.com/Overclock-Validator/mithril/pkg/txverify 1.012s +ok github.com/Overclock-Validator/mithril/pkg/txstatus 1.007s +ok github.com/Overclock-Validator/mithril/pkg/sigverify 20.401s +ok github.com/Overclock-Validator/mithril/pkg/replay 2.292s +ok github.com/Overclock-Validator/mithril/cmd/mithril/configcmd 1.008s +ok github.com/Overclock-Validator/mithril/cmd/mithril/node 1.141s diff --git a/docs/results/review-fixes/2026-09-15/native-run.log b/docs/results/review-fixes/2026-09-15/native-run.log new file mode 100644 index 00000000..9027ea27 --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/native-run.log @@ -0,0 +1,10 @@ +Running as unit: mithril-review-fixes-check-20260915.service; invocation ID: 51c80c67f31744f9bbf9b056bbecd2db +race 0 +blackhole-race 0 +vet 0 +build 0 + Finished with result: success +Main processes terminated with: code=exited, status=0/SUCCESS + Service runtime: 1min 4.346s + CPU time consumed: 1min 12.623s + Memory peak: 1019.1M (swap: 0B) diff --git a/docs/results/review-fixes/2026-09-15/native-summary.json b/docs/results/review-fixes/2026-09-15/native-summary.json new file mode 100644 index 00000000..1703b2e9 --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/native-summary.json @@ -0,0 +1,14 @@ +{ + "retirement_seconds": { + "samples": 10, + "min": 1.037632347, + "median": 1.097481278, + "max": 1.098472025 + }, + "healthy_marker_ms": { + "samples": 40, + "min": 0.06974, + "median": 0.17956650000000002, + "max": 8.361257 + } +} diff --git a/docs/results/review-fixes/2026-09-15/native-vet.log b/docs/results/review-fixes/2026-09-15/native-vet.log new file mode 100644 index 00000000..e69de29b diff --git a/docs/results/review-fixes/2026-09-15/native-window.json b/docs/results/review-fixes/2026-09-15/native-window.json new file mode 100644 index 00000000..4ee434b6 --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/native-window.json @@ -0,0 +1,4 @@ +{ + "start": "2026-09-15T03:16:20.248616+00:00", + "end": "2026-09-15T03:17:24.360675+00:00" +} \ No newline at end of file diff --git a/docs/results/review-fixes/2026-09-15/post-test-health.json b/docs/results/review-fixes/2026-09-15/post-test-health.json new file mode 100644 index 00000000..83828ce2 --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/post-test-health.json @@ -0,0 +1 @@ +{"health": {"utc": "2026-09-15T03:18:12.622352+00:00", "pid": 568418, "rpc_slot": 3830073, "local_slot": 3830073, "last_vote": 3830072, "vote_lag": 1}, "services": ["active", "active", "active", "active"]} diff --git a/docs/results/review-fixes/2026-09-15/streaming-before.log b/docs/results/review-fixes/2026-09-15/streaming-before.log new file mode 100644 index 00000000..56ef8574 --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/streaming-before.log @@ -0,0 +1,37 @@ +--- FAIL: TestEntryIdentityRecoveryVerifiesFinalTransactions (0.00s) + --- FAIL: TestEntryIdentityRecoveryVerifiesFinalTransactions/partial_identities/valid (0.00s) + entry_identity_recovery_test.go:57: + Error Trace: /Users/nikolashayes/Desktop/programming/Codex/mithril-pr-split-20260915/streaming-preparation/pkg/turbine/entry_identity_recovery_test.go:57 + Error: Received unexpected error: + entry identity range mismatch + Test: TestEntryIdentityRecoveryVerifiesFinalTransactions/partial_identities/valid + --- FAIL: TestEntryIdentityRecoveryVerifiesFinalTransactions/partial_identities/invalid (0.00s) + entry_identity_recovery_test.go:54: + Error Trace: /Users/nikolashayes/Desktop/programming/Codex/mithril-pr-split-20260915/streaming-preparation/pkg/turbine/entry_identity_recovery_test.go:54 + Error: Error "entry identity range mismatch" does not contain "failed signature verification" + Test: TestEntryIdentityRecoveryVerifiesFinalTransactions/partial_identities/invalid + --- FAIL: TestEntryIdentityRecoveryVerifiesFinalTransactions/wrong_pointer/valid (0.00s) + entry_identity_recovery_test.go:57: + Error Trace: /Users/nikolashayes/Desktop/programming/Codex/mithril-pr-split-20260915/streaming-preparation/pkg/turbine/entry_identity_recovery_test.go:57 + Error: Received unexpected error: + verified message identity does not match transaction 0 + Test: TestEntryIdentityRecoveryVerifiesFinalTransactions/wrong_pointer/valid + --- FAIL: TestEntryIdentityRecoveryVerifiesFinalTransactions/wrong_pointer/invalid (0.00s) + entry_identity_recovery_test.go:54: + Error Trace: /Users/nikolashayes/Desktop/programming/Codex/mithril-pr-split-20260915/streaming-preparation/pkg/turbine/entry_identity_recovery_test.go:54 + Error: Error "verified message identity does not match transaction 0" does not contain "failed signature verification" + Test: TestEntryIdentityRecoveryVerifiesFinalTransactions/wrong_pointer/invalid + --- FAIL: TestEntryIdentityRecoveryVerifiesFinalTransactions/missing_range/valid (0.00s) + entry_identity_recovery_test.go:57: + Error Trace: /Users/nikolashayes/Desktop/programming/Codex/mithril-pr-split-20260915/streaming-preparation/pkg/turbine/entry_identity_recovery_test.go:57 + Error: Received unexpected error: + entry identity coverage mismatch + Test: TestEntryIdentityRecoveryVerifiesFinalTransactions/missing_range/valid + --- FAIL: TestEntryIdentityRecoveryVerifiesFinalTransactions/missing_range/invalid (0.00s) + entry_identity_recovery_test.go:54: + Error Trace: /Users/nikolashayes/Desktop/programming/Codex/mithril-pr-split-20260915/streaming-preparation/pkg/turbine/entry_identity_recovery_test.go:54 + Error: Error "entry identity coverage mismatch" does not contain "failed signature verification" + Test: TestEntryIdentityRecoveryVerifiesFinalTransactions/missing_range/invalid +FAIL +FAIL github.com/Overclock-Validator/mithril/pkg/turbine 0.319s +FAIL diff --git a/docs/results/review-fixes/2026-09-15/streaming-build.log b/docs/results/review-fixes/2026-09-15/streaming-build.log new file mode 100644 index 00000000..e69de29b diff --git a/docs/results/review-fixes/2026-09-15/streaming-config-final.log b/docs/results/review-fixes/2026-09-15/streaming-config-final.log new file mode 100644 index 00000000..01ef45b2 --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/streaming-config-final.log @@ -0,0 +1 @@ +ok github.com/Overclock-Validator/mithril/cmd/mithril/configcmd 1.174s diff --git a/docs/results/review-fixes/2026-09-15/streaming-race.log b/docs/results/review-fixes/2026-09-15/streaming-race.log new file mode 100644 index 00000000..86a69184 --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/streaming-race.log @@ -0,0 +1,7 @@ +ok github.com/Overclock-Validator/mithril/pkg/turbine 10.467s +ok github.com/Overclock-Validator/mithril/pkg/block 1.529s +ok github.com/Overclock-Validator/mithril/pkg/txverify 1.200s +ok github.com/Overclock-Validator/mithril/pkg/txstatus 1.183s +ok github.com/Overclock-Validator/mithril/pkg/sigverify 23.338s +ok github.com/Overclock-Validator/mithril/pkg/replay 4.516s +ok github.com/Overclock-Validator/mithril/cmd/mithril/configcmd 1.171s diff --git a/docs/results/review-fixes/2026-09-15/streaming-targeted.log b/docs/results/review-fixes/2026-09-15/streaming-targeted.log new file mode 100644 index 00000000..099da547 --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/streaming-targeted.log @@ -0,0 +1,2 @@ +ok github.com/Overclock-Validator/mithril/pkg/turbine 1.773s +ok github.com/Overclock-Validator/mithril/cmd/mithril/configcmd 1.190s diff --git a/docs/results/review-fixes/2026-09-15/streaming-vet.log b/docs/results/review-fixes/2026-09-15/streaming-vet.log new file mode 100644 index 00000000..e69de29b diff --git a/docs/results/review-fixes/2026-09-15/tested-source.json b/docs/results/review-fixes/2026-09-15/tested-source.json new file mode 100644 index 00000000..f9a730fa --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/tested-source.json @@ -0,0 +1,16 @@ +{ + "combined_base": "97c6562f", + "status_publication": "6d819275", + "streaming_before_fix": "75e76646", + "voting_before_fix": "0e0afb06", + "changed_go": { + "pkg/turbine/entry_prefetch.go": "6c158d62826fd6e263eeb1182643a777b035ee67deb4275538a674cf595d2ab1", + "pkg/turbine/entry_identity_recovery_test.go": "f3f3dcf1fd4b299b2cdce55d58295cf1f0f33344fcd6e2493a6615d12022408b", + "cmd/mithril/configcmd/configcmd.go": "a41c8a29265099f625f8342517ac8c64f30d28067a83cc4db796d339e76dc1cd", + "cmd/mithril/configcmd/configcmd_test.go": "70b19e81e02e3144a5f91f6f6d38defd2af3c9ce4d37794b420eec8a33d27418", + "pkg/alpenglow/peer_sender.go": "78589eb1879ba5a5f7e96126d5ba62415b68fa39fcb86884b618020ea91f5ca0", + "pkg/alpenglow/peer_sender_test.go": "f0c9e112205e92fc7f5bb4b874fff115615e8ecdd9f3ae03405b88047a47851b", + "pkg/alpenglow/peer_sender_recovery_test.go": "555c06411d147720c6c0bcd1481111e6209a98f20c3515b5168f9b4a3da7dd75" + }, + "note": "Native combined tests include all six split branches plus status publication and these fixes. Final template-only narrowing was checked separately with config/node race tests and a final build. Standalone voting retains its base template; the native combined template comes from streaming." +} diff --git a/docs/results/review-fixes/2026-09-15/voting-before.log b/docs/results/review-fixes/2026-09-15/voting-before.log new file mode 100644 index 00000000..928ff50f --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/voting-before.log @@ -0,0 +1,18 @@ +--- FAIL: TestVotorPeerReconnectOnRemoteCloseWithoutReconcile (0.01s) + --- FAIL: TestVotorPeerReconnectOnRemoteCloseWithoutReconcile/idle (0.00s) + peer_sender_recovery_test.go:81: sender exited without requesting reconnect + --- FAIL: TestVotorPeerReconnectOnRemoteCloseWithoutReconcile/dequeue (0.00s) + peer_sender_recovery_test.go:81: sender exited without requesting reconnect +--- FAIL: TestVotorPeerDeadlineIncludesQueueAge (0.00s) + --- FAIL: TestVotorPeerDeadlineIncludesQueueAge/progress_does_not_reset_age (0.00s) + peer_sender_recovery_test.go:111: + Error Trace: /Users/nikolashayes/Desktop/programming/Codex/mithril-pr-split-20260915/vote-delivery-persistence/pkg/alpenglow/peer_sender_recovery_test.go:111 + Error: Not equal: + expected: true + actual : false + Test: TestVotorPeerDeadlineIncludesQueueAge/progress_does_not_reset_age +--- FAIL: TestVotorPeerRejectsAgedQueueBeforeQUICEnqueue (1.00s) + peer_sender_recovery_test.go:129: aged queue did not retire its connection +FAIL +FAIL github.com/Overclock-Validator/mithril/pkg/alpenglow 1.194s +FAIL diff --git a/docs/results/review-fixes/2026-09-15/voting-blackhole-race.log b/docs/results/review-fixes/2026-09-15/voting-blackhole-race.log new file mode 100644 index 00000000..61e8979f --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/voting-blackhole-race.log @@ -0,0 +1 @@ +ok github.com/Overclock-Validator/mithril/pkg/alpenglow 13.360s diff --git a/docs/results/review-fixes/2026-09-15/voting-build.log b/docs/results/review-fixes/2026-09-15/voting-build.log new file mode 100644 index 00000000..e69de29b diff --git a/docs/results/review-fixes/2026-09-15/voting-race.log b/docs/results/review-fixes/2026-09-15/voting-race.log new file mode 100644 index 00000000..1bbd7ac9 --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/voting-race.log @@ -0,0 +1,4 @@ +ok github.com/Overclock-Validator/mithril/pkg/alpenglow 10.108s +ok github.com/Overclock-Validator/mithril/pkg/consensus 10.208s +ok github.com/Overclock-Validator/mithril/cmd/mithril/configcmd 1.169s +ok github.com/Overclock-Validator/mithril/cmd/mithril/node 1.923s diff --git a/docs/results/review-fixes/2026-09-15/voting-targeted.log b/docs/results/review-fixes/2026-09-15/voting-targeted.log new file mode 100644 index 00000000..b70979c5 --- /dev/null +++ b/docs/results/review-fixes/2026-09-15/voting-targeted.log @@ -0,0 +1 @@ +ok github.com/Overclock-Validator/mithril/pkg/alpenglow 1.375s diff --git a/docs/results/review-fixes/2026-09-15/voting-vet.log b/docs/results/review-fixes/2026-09-15/voting-vet.log new file mode 100644 index 00000000..e69de29b diff --git a/docs/streaming_message_identities.md b/docs/streaming_message_identities.md index 94b293f0..a168744c 100644 --- a/docs/streaming_message_identities.md +++ b/docs/streaming_message_identities.md @@ -92,3 +92,29 @@ are observational; the baseline and candidate windows span an epoch change. Several remaining misses coincide with unusually slow replay during local load sends, while others have late signature completions or shred collection. No claim of eliminating FAST misses or proving a score improvement is made. + + +## Recovery from inconsistent prefetch metadata + +Missing/oversized retained ranges, partial identities and identity-binding +mismatches now log a warning and fall back to full signature verification of the +final block. Bounds are checked before slicing the final transaction array. Old +readers are joined first, including on cancellation. Valid final transactions +can therefore recover from an optimization bookkeeping fault; a successful +cached verdict for different bytes cannot authorize the final transaction. +Normal cached signature failures remain errors, as do failed re-verification, +cancellation and a closed verifier. No signatures or duplicate checks are skipped. + +Regression tests cover valid and invalid final blocks for each metadata fault, +cache identities matching the final transaction order, canceled-reader ownership +and verifier failure. The ordinary path retains exact-range/byte checks and +verified identity reuse. Full re-verification is exceptional and costs additional +work; this change is a correctness/availability fix, not a throughput claim. + +The `[sigverify]` starter configuration and its test moved here from the voting +branch, because this branch reads those keys and supports the legacy backend key. +The unrelated explicit `tuning.use_pool` template setting is omitted: enabling +pooling by default and fixing retained vote ownership belong to the runtime +branch. In the combined build, its configuration defaults still enable pooling. +The default remains two Turbine verification workers (bounded by GOMAXPROCS). +Many-core catch-up tuning remains a separate measurement question. diff --git a/pkg/turbine/entry_identity_recovery_test.go b/pkg/turbine/entry_identity_recovery_test.go new file mode 100644 index 00000000..aab96f79 --- /dev/null +++ b/pkg/turbine/entry_identity_recovery_test.go @@ -0,0 +1,131 @@ +package turbine + +import ( + "context" + "sync" + "testing" + "time" + + "github.com/Overclock-Validator/mithril/pkg/block" + "github.com/Overclock-Validator/mithril/pkg/txstatus" + "github.com/gagliardetto/solana-go" + "github.com/stretchr/testify/require" +) + +func TestEntryIdentityRecoveryVerifiesFinalTransactions(t *testing.T) { + for _, fault := range []string{"partial_identities", "wrong_pointer", "missing_range", "oversized_range", "nil_batch"} { + for _, invalidFinal := range []bool{false, true} { + name := fault + "/valid" + if invalidFinal { + name = fault + "/invalid" + } + t.Run(name, func(t *testing.T) { + v := newTransactionVerifier(2, 16, nil) + defer v.closeAndWait() + txs := verifierSignedTransactions(t, 3) + entries := []Entry{{Txns: []solana.Transaction{*txs[0], *txs[1], *txs[2]}}} + blk := &block.Block{Slot: 812, Transactions: entryBatchTransactions(entries)} + request, err := v.submitTransactions(context.Background(), blk.Transactions) + require.NoError(t, err) + _, err = request.wait() + require.NoError(t, err) + batches := []*prefetchedShredBatch{{entries: entries, verification: request}} + switch fault { + case "partial_identities": + request.identities = request.identities[:2] + case "wrong_pointer": + copyTx := *blk.Transactions[0] + blk.Transactions[0] = ©Tx + case "missing_range": + batches = nil + case "oversized_range": + batches[0].entries = append(batches[0].entries, Entry{Txns: []solana.Transaction{*txs[0]}}) + case "nil_batch": + batches = []*prefetchedShredBatch{nil} + } + if invalidFinal { + // The old request verified a different, valid transaction. + // A successful old verdict must not bless these final bytes. + copyTx := *blk.Transactions[0] + copyTx.Signatures = append([]solana.Signature(nil), copyTx.Signatures...) + copyTx.Signatures[0][0] ^= 1 + blk.Transactions[0] = ©Tx + } + err = verifyDecodedEntryBatches(context.Background(), blk, batches, v) + if invalidFinal { + require.ErrorContains(t, err, "failed signature verification") + return + } + require.NoError(t, err) + prepared, err := blk.PrepareTransactionMessageIdentities() + require.NoError(t, err) + for i, tx := range blk.Transactions { + want, err := txstatus.IdentityForTransaction(tx) + require.NoError(t, err) + require.Equal(t, want, prepared.Identity(i)) + } + }) + } + } +} + +func TestEntryIdentityRecoveryPreservesCancellationAndVerifierFailure(t *testing.T) { + blk := &block.Block{Slot: 813, Transactions: verifierSignedTransactions(t, 2)} + v := newTransactionVerifier(2, 16, nil) + ctx, cancel := context.WithCancel(context.Background()) + cancel() + require.ErrorIs(t, verifyDecodedEntryBatches(ctx, blk, nil, v), context.Canceled) + v.closeAndWait() + require.ErrorIs(t, verifyDecodedEntryBatches(context.Background(), blk, nil, v), errTransactionVerifierClosed) +} + +func TestEntryIdentityRecoveryJoinsCanceledReaders(t *testing.T) { + started := make(chan struct{}, 1) + release := make(chan struct{}) + v := newTransactionVerifier(1, 8, func(*solana.Transaction) error { + select { + case started <- struct{}{}: + default: + } + <-release + return nil + }) + defer v.closeAndWait() + var releaseOnce sync.Once + unblock := func() { releaseOnce.Do(func() { close(release) }) } + defer unblock() + txs := verifierSignedTransactions(t, 2) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + request, err := v.submitTransactions(ctx, txs) + require.NoError(t, err) + select { + case <-started: + case <-time.After(time.Second): + t.Fatal("reader never started") + } + result := make(chan error, 1) + // This deliberately inconsistent range sends us through recovery while + // the old verifier still owns the block's transaction buffers. + go func() { + result <- verifyDecodedEntryBatches(ctx, &block.Block{Transactions: txs}, []*prefetchedShredBatch{{verification: request}}, v) + }() + cancel() + select { + case err := <-result: + t.Fatalf("returned before old reader released its buffers: %v", err) + case <-time.After(20 * time.Millisecond): + } + unblock() + select { + case err := <-result: + require.ErrorIs(t, err, context.Canceled) + case <-time.After(time.Second): + t.Fatal("recovery did not join canceled readers") + } + select { + case <-request.done: + default: + t.Fatal("request ownership was not released") + } +} diff --git a/pkg/turbine/entry_prefetch.go b/pkg/turbine/entry_prefetch.go index c8b39ea8..68abb540 100644 --- a/pkg/turbine/entry_prefetch.go +++ b/pkg/turbine/entry_prefetch.go @@ -3,11 +3,11 @@ package turbine import ( "context" "errors" - "fmt" "sync" "time" "github.com/Overclock-Validator/mithril/pkg/block" + "github.com/Overclock-Validator/mithril/pkg/mlog" "github.com/Overclock-Validator/mithril/pkg/txverify" "github.com/gagliardetto/solana-go" ) @@ -268,6 +268,12 @@ func verifyDecodedEntryBatches(ctx context.Context, blk *block.Block, batches [] } func verifyDecodedEntryBatchesWithTimings(ctx context.Context, blk *block.Block, batches []*prefetchedShredBatch, verifier *transactionVerifier, timings *entryDecodeTimings) error { + if ctx == nil { + ctx = context.Background() + } + if blk == nil { + return errors.New("verify decoded entries: nil block") + } type pending struct { future *transactionVerification offset int @@ -278,10 +284,16 @@ func verifyDecodedEntryBatchesWithTimings(ctx context.Context, blk *block.Block, var indices []int offset := 0 for _, b := range batches { + if b == nil { + return recoverEntryVerification(ctx, blk, batches, verifier, errors.New("nil retained entry batch")) + } count := 0 for _, e := range b.entries { count += len(e.Txns) } + if count > len(blk.Transactions)-offset { + return recoverEntryVerification(ctx, blk, batches, verifier, errors.New("entry transaction range exceeds final block")) + } reusable := b.verification != nil if reusable { select { @@ -302,6 +314,9 @@ func verifyDecodedEntryBatchesWithTimings(ctx context.Context, blk *block.Block, } offset += count } + if offset != len(blk.Transactions) { + return recoverEntryVerification(ctx, blk, batches, verifier, errors.New("entry identity coverage mismatch")) + } var fallback *transactionVerification var err error if len(missing) > 0 { @@ -344,25 +359,43 @@ func verifyDecodedEntryBatchesWithTimings(ctx context.Context, blk *block.Block, if verifier.verify != nil { return nil } - if offset != len(blk.Transactions) { - return fmt.Errorf("entry identity coverage mismatch") - } identities := make([]txverify.VerifiedMessageIdentity, len(blk.Transactions)) for _, p := range early { if len(p.future.identities) != p.count || p.offset+len(p.future.identities) > len(identities) { - return fmt.Errorf("entry identity range mismatch") + return recoverEntryVerification(ctx, blk, batches, verifier, errors.New("entry identity range mismatch")) } copy(identities[p.offset:], p.future.identities) } if fallback != nil { if len(fallback.identities) != len(indices) { - return fmt.Errorf("fallback identity coverage mismatch") + return recoverEntryVerification(ctx, blk, batches, verifier, errors.New("fallback identity coverage mismatch")) } for i, index := range indices { identities[index] = fallback.identities[i] } } - return blk.CacheVerifiedTransactionMessageIdentities(identities) + if err := blk.CacheVerifiedTransactionMessageIdentities(identities); err != nil { + return recoverEntryVerification(ctx, blk, batches, verifier, err) + } + return nil +} + +// Prefetch metadata is an optimization, never a substitute for verifying the +// final block. Join old readers, then verify every final transaction afresh. +// This also repairs pointer/coverage mismatches without treating a successful +// verdict for another transaction as proof for this one. Normal signature +// failures above are still rejected directly. Failed recovery stays an error. +func recoverEntryVerification(ctx context.Context, blk *block.Block, batches []*prefetchedShredBatch, verifier *transactionVerifier, reason error) error { + for _, batch := range batches { + if batch != nil && batch.verification != nil { + _, _ = batch.verification.waitContext(ctx) + } + } + if err := ctx.Err(); err != nil { + return err + } + mlog.Log.Warnf("slot %d: discarded inconsistent entry verification metadata; re-verifying final transactions: %v", blk.Slot, reason) + return verifier.verifyBlockContext(ctx, blk) } func earlyEntryTimings(t *entryDecodeTimings, fullAt time.Time, timings *block.TurbineIngressTimings) { From 406317bc78d97998348f3b78ef2780b076759baa Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Mon, 14 Sep 2026 23:39:25 -0500 Subject: [PATCH 017/183] Reuse relay peer scratch and packet storage with explicit ownership --- docs/turbine-relay-buffers.md | 60 ++++ pkg/turbine/cluster_nodes.go | 12 +- pkg/turbine/retransmit.go | 91 +++++- .../retransmit_allocation_bench_test.go | 89 ++++++ pkg/turbine/retransmit_allocation_test.go | 267 ++++++++++++++++++ 5 files changed, 504 insertions(+), 15 deletions(-) create mode 100644 docs/turbine-relay-buffers.md create mode 100644 pkg/turbine/retransmit_allocation_bench_test.go create mode 100644 pkg/turbine/retransmit_allocation_test.go diff --git a/docs/turbine-relay-buffers.md b/docs/turbine-relay-buffers.md new file mode 100644 index 00000000..e34c4f77 --- /dev/null +++ b/docs/turbine-relay-buffers.md @@ -0,0 +1,60 @@ +# Turbine relay buffer ownership + +Each retransmit worker reuses a private peer-result slice. Weighted shuffle, +tree placement, address filtering and fanout are unchanged. The exported +`RetransmitPeers` API still returns independently allocated result storage. +Workers clear their entire scratch slice after each send so it cannot retain +addresses from an old cluster snapshot. + +`SubmitFrom` copies a packet into exclusively owned storage before returning +to its caller. Canonical packets use a fixed-size, GC-reclaimable `sync.Pool`; +oversized inputs retain the independent allocation path. Queue admission +transfers ownership to the worker. The worker returns storage only after all +synchronous sends and retries finish, including error and no-peer paths. +Queue rejection returns storage immediately. Shutdown closes admission under +a short lock, joins workers, then drains remaining copies. The channel stays +open for concurrent submitters, which cannot enqueue after admission closes. + +`packetBatchSender.Send` borrows both packet bytes and peer addresses only +until return, even on partial sends or errors. Implementations that retain +either must copy them. A pooled packet must never escape this lifetime. +The admission lock is not held during authentication, routing or socket I/O. + +## Measurement + +`BenchmarkRetransmitPipeline` measures deduplication, packet copying, queue +handoff, weighted routing and dispatch to a mock sender. Run with: + +```sh +GOMAXPROCS=2 go test ./pkg/turbine -run '^$' \ + -bench '^BenchmarkRetransmitPipeline$' -benchmem -benchtime=20000x -count=3 +``` + +On a Ryzen 7 9700X (Zen 5), Go 1.26.4, one producer and one relay worker, +the incremental comparison against the relay implementation at +`c40ac9e8ca8aa09a9f2a8759a231199b0f90346e` was: + +| Gossip contacts | Before ns/shred | After ns/shred | Before B/shred | After B/shred | Allocations before → after | +|---|---:|---:|---:|---:|---:| +| 90 | 3,906 | 3,761 | 3,784 | ~729 | 8 → 6 | +| 512 | 23,789 | 22,056 | 3,784 | ~729 | 8 → 6 | + +Times are medians of six samples per version, in baseline/candidate/candidate/ +baseline order, three samples per round. Both versions use the same benchmark +and combined validator source; only the two relay production files change. +Each iteration submits a distinct 1,203-byte data shred with cached topology; +the benchmark checks that none are dropped and waits for workers to finish. +The fixture includes staked and zero-stake peers. Contact count does not mean +that every shred has that many recipients: tree position determines forwarding. + +Allocation fell about 81%. The 4–7% median timing improvement is modest and +noisy on the shared validator host; one candidate sample was slower than every +baseline sample in its case. These are amortized in-memory pipeline times, +not network delivery latency or live FAST-score gains. Socket syscalls, parent +authentication and retransmitter signing are excluded from this fixture. + +Routing tests compare against a full weighted permutation, including both +shuffle modes and missing/unroutable contacts. Ownership tests exercise caller +buffer reuse, queue pressure, send retries, concurrent routing and shutdown. +The full Turbine race suite passed locally and natively; native vet and the +combined validator build passed. The benchmark candidate was not deployed. diff --git a/pkg/turbine/cluster_nodes.go b/pkg/turbine/cluster_nodes.go index 8446a396..ff6e0bdc 100644 --- a/pkg/turbine/cluster_nodes.go +++ b/pkg/turbine/cluster_nodes.go @@ -89,6 +89,13 @@ func newClusterNodes(cfg ClusterNodesConfig, broadcast bool) *ClusterNodes { // shuffle because it already owns the shred. Tree placement and fanout match // Agave ClusterNodes::get_retransmit_addrs. func (c *ClusterNodes) RetransmitPeers(leader solana.PublicKey, shred ShredID, fanout int) (uint8, []*net.UDPAddr, error) { + return c.retransmitPeersInto(leader, shred, fanout, nil) +} + +// retransmitPeersInto uses caller-owned result storage. The caller must finish +// using the returned slice before reusing dst; addresses still belong to this +// immutable cluster snapshot. Public callers retain the allocating API above. +func (c *ClusterNodes) retransmitPeersInto(leader solana.PublicKey, shred ShredID, fanout int, dst []*net.UDPAddr) (uint8, []*net.UDPAddr, error) { if c == nil || fanout <= 0 { return maxTurbineHops - 1, nil, nil } @@ -123,7 +130,10 @@ func (c *ClusterNodes) RetransmitPeers(leader solana.PublicKey, shred ShredID, f step = 1 } position := anchor*fanout + offset + 1 - peers := make([]*net.UDPAddr, 0, fanout) + peers := dst[:0] + if dst == nil { + peers = make([]*net.UDPAddr, 0, fanout) + } shufflePosition := selfPos for range fanout { var index int diff --git a/pkg/turbine/retransmit.go b/pkg/turbine/retransmit.go index d8584e6c..dfb0a04a 100644 --- a/pkg/turbine/retransmit.go +++ b/pkg/turbine/retransmit.go @@ -60,10 +60,17 @@ type RetransmitConfig struct { type retransmitWork struct { packet []byte - shred ShredID - leader solana.PublicKey + // storage is exclusively owned by this work until send (including retries) + // completes. Nil denotes the unpooled oversized compatibility path. + storage *retransmitPacket + shred ShredID + leader solana.PublicKey } +// Canonical shreds fit in one Solana packet. Keep the pool fixed-size rather +// than retaining arbitrary caller-provided capacities. +type retransmitPacket [packetDataSize]byte + type cachedRetransmitNodes struct { asof time.Time nodes *ClusterNodes @@ -91,6 +98,8 @@ type retransmitParentSigCache struct { } type packetBatchSender interface { + // Send borrows packet and peers only until it returns, including on errors + // or partial sends. Implementations must copy anything they retain. Send(packet []byte, peers []*net.UDPAddr) (int, error) Close() error } @@ -120,8 +129,13 @@ type Retransmitter struct { // immediately visible alongside short-send counters. sendBufferBytes int - queue chan retransmitWork - senders []packetBatchSender + queue chan retransmitWork + senders []packetBatchSender + packetPool sync.Pool + // Only guards queue admission versus shutdown; never held during crypto, + // peer selection or socket writes. A stopped queue cannot retain late work. + submitMu sync.RWMutex + stopped bool cacheMu sync.Mutex cache map[uint64]cachedRetransmitNodes @@ -283,20 +297,53 @@ func (r *Retransmitter) Run(ctx context.Context) { sender := sender go func() { defer workers.Done() + var peers [dataPlaneFanout]*net.UDPAddr for { select { case <-ctx.Done(): return case work := <-r.queue: - r.send(work, sender) + r.send(work, sender, peers[:0]) } } }() } <-ctx.Done() + r.submitMu.Lock() + r.stopped = true + r.submitMu.Unlock() workers.Wait() - for _, sender := range r.senders { - _ = sender.Close() + // Admission is closed and senders have returned their leases. Drain the + // remaining queue without closing a channel still visible to submitters. + for { + select { + case work := <-r.queue: + r.releasePacket(work.storage) + default: + for _, sender := range r.senders { + _ = sender.Close() + } + return + } + } +} + +func (r *Retransmitter) copyPacket(packet []byte) ([]byte, *retransmitPacket) { + if len(packet) > len(retransmitPacket{}) { + return append([]byte(nil), packet...), nil + } + storage, _ := r.packetPool.Get().(*retransmitPacket) + if storage == nil { + storage = new(retransmitPacket) + } + out := storage[:len(packet)] + copy(out, packet) + return out, storage +} + +func (r *Retransmitter) releasePacket(storage *retransmitPacket) { + if storage != nil { + r.packetPool.Put(storage) } } @@ -340,25 +387,37 @@ func (r *Retransmitter) SubmitFrom(packet []byte, shred *Shred, leader solana.Pu if packetSize == 0 || packetSize > len(packet) { return fmt.Errorf("turbine retransmit: invalid canonical packet size %d/%d", packetSize, len(packet)) } - out := append([]byte(nil), packet[:packetSize]...) + // Validate the signing range before borrowing storage, so all error exits + // either precede ownership or release it through send/the queue-drop path. + offset := 0 if root != nil { - offset, err := shred.retransmitterSignatureOffset() + offset, err = shred.retransmitterSignatureOffset() if err != nil { return fmt.Errorf("turbine retransmit: locate retransmitter signature: %w", err) } - if offset+ed25519.SignatureSize > len(out) { - return fmt.Errorf("turbine retransmit: retransmitter signature slice %d:%d exceeds packet size %d", offset, offset+ed25519.SignatureSize, len(out)) + if offset+ed25519.SignatureSize > packetSize { + return fmt.Errorf("turbine retransmit: retransmitter signature slice %d:%d exceeds packet size %d", offset, offset+ed25519.SignatureSize, packetSize) } + } + out, storage := r.copyPacket(packet[:packetSize]) + if root != nil { signature := ed25519.Sign(r.cfg.Identity, root[:]) copy(out[offset:offset+ed25519.SignatureSize], signature) r.resignedShreds.Add(1) } r.submitted.Add(1) + r.submitMu.RLock() + defer r.submitMu.RUnlock() + if r.stopped { + r.releasePacket(storage) + return nil + } select { - case r.queue <- retransmitWork{packet: out, shred: id, leader: leader}: + case r.queue <- retransmitWork{packet: out, storage: storage, shred: id, leader: leader}: default: r.queueDrops.Add(1) + r.releasePacket(storage) } return nil } @@ -417,9 +476,13 @@ func (r *Retransmitter) verifyParentSignature(shred *Shred, leader solana.Public return &root, nil } -func (r *Retransmitter) send(work retransmitWork, sender packetBatchSender) { +func (r *Retransmitter) send(work retransmitWork, sender packetBatchSender, scratch []*net.UDPAddr) { + defer r.releasePacket(work.storage) + // Clear even the unused tail after selection: worker scratch must not pin + // old snapshot addresses after a topology refresh or a no-peer/error path. + defer clear(scratch[:cap(scratch)]) nodes := r.clusterNodesForSlot(work.shred.Slot) - distance, peers, err := nodes.RetransmitPeers(work.leader, work.shred, dataPlaneFanout) + distance, peers, err := nodes.retransmitPeersInto(work.leader, work.shred, dataPlaneFanout, scratch) if errors.Is(err, ErrRetransmitLoopback) { r.loopbacks.Add(1) return diff --git a/pkg/turbine/retransmit_allocation_bench_test.go b/pkg/turbine/retransmit_allocation_bench_test.go new file mode 100644 index 00000000..3f376652 --- /dev/null +++ b/pkg/turbine/retransmit_allocation_bench_test.go @@ -0,0 +1,89 @@ +package turbine + +import ( + "context" + "crypto/ed25519" + "encoding/binary" + "fmt" + "net" + "runtime" + "testing" + "time" + + "github.com/Overclock-Validator/mithril/pkg/gossip" + "github.com/gagliardetto/solana-go" +) + +type discardRelaySender struct{} + +func (*discardRelaySender) Send(_ []byte, peers []*net.UDPAddr) (int, error) { return len(peers), nil } +func (*discardRelaySender) Close() error { return nil } + +// Includes Submit's dedupe/copy, channel handoff, routing and sender dispatch. +// The sender performs no syscalls; this isolates relay CPU/allocations rather +// than claiming a network-throughput improvement. Authentication before Submit +// and resigned-shred crypto are covered by functional tests, not this fixture. +func BenchmarkRetransmitPipeline(b *testing.B) { + for _, count := range []int{90, 512} { + b.Run(fmt.Sprint(count), func(b *testing.B) { + nodes, leader, key := relayAllocationNodes(count, true) + r, err := newRetransmitterWithSenders(RetransmitConfig{Identity: key, Peers: &mutableTVUPeers{}, Stakes: func(uint64) map[solana.PublicKey]uint64 { return nil }, QueueDepth: 256}, []packetBatchSender{&discardRelaySender{}}) + if err != nil { + b.Fatal(err) + } + r.cache[10] = cachedRetransmitNodes{asof: time.Now().Add(time.Hour), nodes: nodes} + ctx, cancel := context.WithCancel(context.Background()) + done := make(chan struct{}) + go func() { r.Run(ctx); close(done) }() + packet := make([]byte, dataPayloadSize) + shred := &Shred{Slot: 10, Type: ShredTypeData, Payload: packet} + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + // Exactly one producer; leave capacity before submitting so every + // iteration measures actual forwarding rather than dropped work. + for len(r.queue) == cap(r.queue) { + runtime.Gosched() + } + binary.LittleEndian.PutUint64(packet[:8], uint64(i)) + shred.Index = uint32(i) + if err := r.Submit(packet, shred, leader, false); err != nil { + b.Fatal(err) + } + } + for { + var n uint64 + for i := range r.rootDistance { + n += r.rootDistance[i].Load() + } + if n >= uint64(b.N) { + break + } + runtime.Gosched() + } + cancel() + <-done + b.StopTimer() + if r.queueDrops.Load() != 0 { + b.Fatal("unexpected queue drop") + } + }) + } +} + +func relayAllocationNodes(count int, chacha8 bool) (*ClusterNodes, solana.PublicKey, ed25519.PrivateKey) { + key := ed25519.NewKeyFromSeed(make([]byte, ed25519.SeedSize)) + var self solana.PublicKey + copy(self[:], key.Public().(ed25519.PublicKey)) + leader := solana.PublicKey{255} + peers := make([]gossip.TVUPeer, 0, count) + stakes := map[solana.PublicKey]uint64{self: 100, leader: 50} + for i := 0; i < count; i++ { + var pub solana.PublicKey + binary.LittleEndian.PutUint64(pub[:], uint64(i+1)) + addr := &net.UDPAddr{IP: net.IPv4(127, 1, byte(i/250), byte(i%250+1)), Port: 8001} + peers = append(peers, gossip.TVUPeer{Pubkey: gossip.Pubkey(pub), TVUAddr: addr}) + stakes[pub] = uint64(i % 101) + } + return NewRetransmitClusterNodes(ClusterNodesConfig{Self: self, TVUPeers: peers, Stakes: stakes, UseChaCha8: chacha8}), leader, key +} diff --git a/pkg/turbine/retransmit_allocation_test.go b/pkg/turbine/retransmit_allocation_test.go new file mode 100644 index 00000000..3cced312 --- /dev/null +++ b/pkg/turbine/retransmit_allocation_test.go @@ -0,0 +1,267 @@ +package turbine + +import ( + "bytes" + "context" + "net" + "sync" + "syscall" + "testing" + "time" + + "github.com/gagliardetto/solana-go" + "github.com/stretchr/testify/require" +) + +// Derive expected children from the full weighted permutation, independently +// of the streaming child-selection loop and its caller-owned output storage. +func expectedRelayPeers(nodes *ClusterNodes, leader solana.PublicKey, id ShredID, fanout int) (uint8, []*net.UDPAddr) { + order := nodes.retransmitShuffle(leader, id) + self := -1 + for i, index := range order { + if nodes.nodes[index].pubkey == nodes.selfPubkey { + self = i + break + } + } + if self < 0 { + return maxTurbineHops - 1, nil + } + offset := 0 + if self > 0 { + offset = (self - 1) % fanout + } + step := fanout + if self == 0 { + step = 1 + } + var peers []*net.UDPAddr + for position, n := (self-offset)*fanout+offset+1, 0; position < len(order) && n < fanout; position, n = position+step, n+1 { + node := nodes.nodes[order[position]] + if node.hasContact { + if addr, ok := broadcastTVUUDP(node.tvuAddr); ok { + peers = append(peers, addr) + } + } + } + return turbineRootDistance(self, fanout), peers +} + +func TestRetransmitScratchMatchesPermutation(t *testing.T) { + for _, chacha8 := range []bool{false, true} { + for _, count := range []int{0, 31, 90, 512} { + nodes, leader, _ := relayAllocationNodes(count, chacha8) + // Exercise absent contacts and unroutable peers without changing stake order. + for i := range nodes.nodes { + if i%13 == 0 { + nodes.nodes[i].hasContact = false + } + if i%17 == 0 { + nodes.nodes[i].tvuAddr = &net.UDPAddr{IP: net.ParseIP("::1"), Port: 8001} + } + } + for _, fanout := range []int{1, 3, 200} { + var scratch [dataPlaneFanout]*net.UDPAddr + for index := uint32(0); index < 40; index++ { + id := ShredID{Slot: uint64(10 + index/4), Index: index, Type: ShredType(index % 2)} + wantDistance, want := expectedRelayPeers(nodes, leader, id, fanout) + distance, got, err := nodes.retransmitPeersInto(leader, id, fanout, scratch[:0]) + require.NoError(t, err) + require.Equal(t, wantDistance, distance) + require.Equal(t, len(want), len(got)) + for i := range want { + require.Same(t, want[i], got[i]) + } + _, owned, err := nodes.RetransmitPeers(leader, id, fanout) + require.NoError(t, err) + copyOfOwned := append([]*net.UDPAddr(nil), owned...) + clear(scratch[:]) + require.Equal(t, copyOfOwned, append([]*net.UDPAddr(nil), owned...)) + } + } + } + } +} + +func TestRetransmitScratchConcurrent(t *testing.T) { + nodes, leader, _ := relayAllocationNodes(300, true) + var wg sync.WaitGroup + for range 8 { + wg.Go(func() { + var scratch [dataPlaneFanout]*net.UDPAddr + for index := uint32(0); index < 50; index++ { + id := ShredID{Slot: 10, Index: index, Type: ShredTypeData} + wd, wp := expectedRelayPeers(nodes, leader, id, 3) + d, p, err := nodes.retransmitPeersInto(leader, id, 3, scratch[:0]) + if err != nil || d != wd || len(p) != len(wp) { + t.Error("concurrent routing mismatch") + return + } + for i := range p { + if p[i] != wp[i] { + t.Error("concurrent peer mismatch") + return + } + } + } + }) + } + wg.Wait() +} + +func TestRetransmitPacketPoolOwnership(t *testing.T) { + r := &Retransmitter{} + input := bytes.Repeat([]byte{7}, packetDataSize) + a, ownerA := r.copyPacket(input) + b, ownerB := r.copyPacket(input) + require.NotSame(t, ownerA, ownerB) + clear(input) + require.Equal(t, byte(7), a[0]) + require.Equal(t, byte(7), b[0]) + r.releasePacket(ownerA) + for range 50 { + p, owner := r.copyPacket(bytes.Repeat([]byte{9}, 1203)) + clear(p) + r.releasePacket(owner) + } + require.Equal(t, bytes.Repeat([]byte{7}, packetDataSize), b) + r.releasePacket(ownerB) + oversized := bytes.Repeat([]byte{4}, packetDataSize+1) + p, owner := r.copyPacket(oversized) + require.Nil(t, owner) + clear(oversized) + require.Equal(t, byte(4), p[0]) +} + +func TestRetransmitQueuedPacketOwnsInput(t *testing.T) { + nodes, leader, key := relayAllocationNodes(90, true) + r, err := newRetransmitterWithSenders(RetransmitConfig{Identity: key, Peers: &mutableTVUPeers{}, Stakes: func(uint64) map[solana.PublicKey]uint64 { return nil }, QueueDepth: 1}, []packetBatchSender{newCaptureBatchSender()}) + require.NoError(t, err) + r.cache[10] = cachedRetransmitNodes{asof: time.Now(), nodes: nodes} + packet := bytes.Repeat([]byte{3}, dataPayloadSize) + packet[0] = 1 + shred := &Shred{Slot: 10, Index: 1, Type: ShredTypeData, Payload: packet} + require.NoError(t, r.Submit(packet, shred, leader, false)) + want := append([]byte(nil), packet...) + for i := 2; i < 20; i++ { + packet[0] = byte(i) + shred.Index = uint32(i) + require.NoError(t, r.Submit(packet, shred, leader, false)) + } + require.Equal(t, uint64(18), r.queueDrops.Load()) + clear(packet) + work := <-r.queue + require.Equal(t, want, work.packet) + // Cancellation leaves no owned copies queued after workers finish. + r.queue <- work + ctx, cancel := context.WithCancel(context.Background()) + cancel() + r.Run(ctx) + require.Empty(t, r.queue) + packet[0] = 99 + shred.Index = 99 + require.NoError(t, r.Submit(packet, shred, leader, false)) + require.Empty(t, r.queue, "late submit retained storage after workers stopped") +} + +type borrowedRelaySender struct { + t *testing.T + want []byte + entered chan struct{} + resume chan struct{} + calls int +} + +func (s *borrowedRelaySender) Send(packet []byte, peers []*net.UDPAddr) (int, error) { + s.calls++ + if s.calls == 1 { + close(s.entered) + <-s.resume + } + require.Equal(s.t, s.want, packet) + if s.calls == 1 { + return 0, syscall.EAGAIN + } + return len(peers), nil +} +func (*borrowedRelaySender) Close() error { return nil } + +func TestRetransmitPoolLeaseSurvivesSendRetries(t *testing.T) { + nodes, leader, key := relayAllocationNodes(31, true) + id := ShredID{Slot: 10, Type: ShredTypeData} + // Select a shred for which this validator is the root and has children. + for ; id.Index < 10000; id.Index++ { + d, p, err := nodes.RetransmitPeers(leader, id, 200) + require.NoError(t, err) + if d == 0 && len(p) > 1 { + break + } + } + require.Less(t, id.Index, uint32(10000)) + want := bytes.Repeat([]byte{7}, dataPayloadSize) + sender := &borrowedRelaySender{t: t, want: want, entered: make(chan struct{}), resume: make(chan struct{})} + r, err := newRetransmitterWithSenders(RetransmitConfig{Identity: key, Peers: &mutableTVUPeers{}, Stakes: func(uint64) map[solana.PublicKey]uint64 { return nil }}, []packetBatchSender{sender}) + require.NoError(t, err) + r.cache[10] = cachedRetransmitNodes{asof: time.Now(), nodes: nodes} + packet, owner := r.copyPacket(want) + var scratch [dataPlaneFanout]*net.UDPAddr + done := make(chan struct{}) + go func() { + defer close(done) + r.send(retransmitWork{packet: packet, storage: owner, shred: id, leader: leader}, sender, scratch[:0]) + }() + select { + case <-sender.entered: + case <-time.After(5 * time.Second): + t.Fatal("send did not start") + } + for range 100 { + p, owned := r.copyPacket(want) + clear(p) + r.releasePacket(owned) + } + close(sender.resume) + select { + case <-done: + case <-time.After(5 * time.Second): + t.Fatal("send did not finish") + } + require.Equal(t, 2, sender.calls) + for _, addr := range scratch { + require.Nil(t, addr, "scratch pinned prior snapshot") + } +} + +func TestRetransmitConcurrentSubmitAndStop(t *testing.T) { + nodes, leader, key := relayAllocationNodes(90, true) + r, err := newRetransmitterWithSenders(RetransmitConfig{Identity: key, Peers: &mutableTVUPeers{}, Stakes: func(uint64) map[solana.PublicKey]uint64 { return nil }, QueueDepth: 8}, []packetBatchSender{&discardRelaySender{}, &discardRelaySender{}}) + require.NoError(t, err) + r.cache[10] = cachedRetransmitNodes{asof: time.Now(), nodes: nodes} + ctx, cancel := context.WithCancel(context.Background()) + done := make(chan struct{}) + go func() { r.Run(ctx); close(done) }() + var wg sync.WaitGroup + for worker := 0; worker < 8; worker++ { + wg.Go(func() { + packet := make([]byte, dataPayloadSize) + for i := 0; i < 100; i++ { + packet[0], packet[1] = byte(worker), byte(i) + shred := &Shred{Slot: 10, Index: uint32(worker*100 + i), Type: ShredTypeData, Payload: packet} + if err := r.Submit(packet, shred, leader, false); err != nil { + t.Error(err) + } + if i == 50 { + cancel() + } + } + }) + } + wg.Wait() + cancel() + select { + case <-done: + case <-time.After(5 * time.Second): + t.Fatal("shutdown blocked") + } + require.Empty(t, r.queue) +} From d5c44ec22ea303aa4069c39123d90694eaf86d39 Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Tue, 15 Sep 2026 10:14:17 -0500 Subject: [PATCH 018/183] turbine: reserve verifier admission for completion --- docs/transaction_sigverify_streaming.md | 26 +++ pkg/turbine/entry_prefetch.go | 2 +- pkg/turbine/entry_prefetch_test.go | 7 +- pkg/turbine/transaction_verifier.go | 45 ++--- pkg/turbine/transaction_verifier_admission.go | 76 ++++++++ ...ction_verifier_admission_benchmark_test.go | 118 ++++++++++++ .../transaction_verifier_admission_test.go | 172 ++++++++++++++++++ 7 files changed, 421 insertions(+), 25 deletions(-) create mode 100644 pkg/turbine/transaction_verifier_admission.go create mode 100644 pkg/turbine/transaction_verifier_admission_benchmark_test.go create mode 100644 pkg/turbine/transaction_verifier_admission_test.go diff --git a/docs/transaction_sigverify_streaming.md b/docs/transaction_sigverify_streaming.md index 02619d45..ebb94590 100644 --- a/docs/transaction_sigverify_streaming.md +++ b/docs/transaction_sigverify_streaming.md @@ -131,3 +131,29 @@ of maximum catch-up throughput on every core count or backend. Set larger machine; disabling overlap alone does not restore the previous worker count. Existing two/four-worker contention measurements are in the September 12 report above. No 32-core comparison was performed. + +## Reserved admission for completion + +Decoded prefetch components now use a separate admission class. The existing total request limit remains `2 * workers`; at most `2 * workers - 1` requests may prefetch. Thus the default two-worker pool keeps four total permits, with at most three occupied by prefetch. Waiting completion/full-block recovery requests win the next free permit over prefetch. Their admission, cancellation and close registration share the verifier mutex; notification channels are allocated only when callers must wait. + +No worker or job queue is added, and verification, vector width, job grouping and per-request rolling windows are unchanged. Accepted jobs finish normally and are joined before transaction memory can be reused. No signature checks are skipped. Prefetch may wait while completion callers remain queued and resumes when that backlog drains. This is completion-class priority, not exact replay-head priority: future-slot completions also qualify, and already admitted prefetch work is not promoted or preempted. Checkpoint, persistence and voting-recovery contracts are unchanged. + +### Saturation benchmark + +`BenchmarkVerifierCompletionReservation` verifies four already-ready prefetch components (256 or 4,096 signed 228-byte transactions each) plus a 32-transaction completion request. All requests are joined; total-work timing includes all four components. Two verifier workers, eight signature lanes, four vector groups, GOMAXPROCS=8, Narya r51, Ryzen 9700X / Go1.26.4. Three runs of 100 iterations each, Nice19 and a 200% CPU quota on the shared validator host. Test intervals are excluded from live FAST comparisons. + +The before comparison uses the previously deployed source (status-validation combined build, SHA256 `2c81fc403e8a6eca73b87ede51890041347e1af0e3c63df005fcfeb26448e872`) with only the benchmark added via a Go test overlay. The candidate also measures the shared-class control to distinguish policy from incidental overhead. These are incremental admission results, not the whole PR versus alpenglow-dev. + +For four 4,096-transaction components, medians of the three per-run statistics were: + +| Measurement | Previous deployment | Reserved admission | +|---|---:|---:| +| Completion admission p50 | 37.19 ms | 0.000742 ms | +| Completion admission p99 | 45.78 ms | 0.004599 ms | +| Completion finished p99 | 47.31 ms | 1.488 ms | +| All work finished p50 | 39.43 ms | 39.11 ms | +| All work finished p99 | 49.09 ms | 50.65 ms | + +Completion-finished p99 ranged 46.43–54.52 ms before and 1.477–1.719 ms after. Admission p99 ranged 44.27–53.76 ms before and 0.003206–0.06401 ms after. Every iteration reached its intended request occupancy. For 256-transaction components, completion-finished p99 medians were 3.215→1.165 ms. Shared-host scheduling introduces variation; reserving admission does not remove queued-job or CPU delays, and these 100-sample tails are not a live p99/FAST claim. Total-work throughput was roughly unchanged; no total-work tail improvement is claimed. + +Full local/native turbine and blockstream race suites, targeted native node recovery race tests, local/native vet and combined build passed. Tests cover the reserved permit, the unchanged total bound, waiting completion priority, prefetch resumption, cancellation cleanup, close/admission races and joining owned transactions. The reset test retains both generations' memory reservations while a one-worker verifier delays the new prefetch until its canceled old reader joins. Server-only raw evidence and exact combined source: `/srv/mithril-verifier-reservation-20260915`. diff --git a/pkg/turbine/entry_prefetch.go b/pkg/turbine/entry_prefetch.go index 68abb540..2b082e52 100644 --- a/pkg/turbine/entry_prefetch.go +++ b/pkg/turbine/entry_prefetch.go @@ -182,7 +182,7 @@ func (p *entryPrefetchPool) run() { txs := entryBatchTransactions(batch.entries) if len(txs) > 0 { batch.submittedAt = time.Now() - batch.verification, batch.submitErr = p.verifier.submitTransactions(f.ctx, txs) + batch.verification, batch.submitErr = p.verifier.submitPrefetchTransactions(f.ctx, txs) } } close(ready) diff --git a/pkg/turbine/entry_prefetch_test.go b/pkg/turbine/entry_prefetch_test.go index 42caaa7e..679ee18b 100644 --- a/pkg/turbine/entry_prefetch_test.go +++ b/pkg/turbine/entry_prefetch_test.go @@ -175,14 +175,17 @@ func TestEntryPrefetchResetKeepsOldReservationsUntilReadersJoin(t *testing.T) { require.Positive(t, p.bytes) a.mu.Unlock() require.Nil(t, feedPrefetchShreds(t, a, fresh[0])) - newBatch := waitPrefetchedBatch(t, a, slot, 0) - require.NotSame(t, oldBatch, newBatch) a.mu.Lock() require.Equal(t, 2, p.slots) a.mu.Unlock() + // With one verifier worker only one request may prefetch. The fresh + // generation keeps its pool reservation while admission waits for the old + // reader to join; it must not release or reuse the old generation's bytes. releaseOnce.Do(func() { close(release) }) _, err := oldBatch.verification.wait() require.ErrorIs(t, err, context.Canceled) + newBatch := waitPrefetchedBatch(t, a, slot, 0) + require.NotSame(t, oldBatch, newBatch) _, err = newBatch.verification.wait() require.NoError(t, err) blk := feedPrefetchShreds(t, a, fresh[1]) diff --git a/pkg/turbine/transaction_verifier.go b/pkg/turbine/transaction_verifier.go index 3332eb80..050e126b 100644 --- a/pkg/turbine/transaction_verifier.go +++ b/pkg/turbine/transaction_verifier.go @@ -80,12 +80,16 @@ type transactionVerifier struct { // admission semaphore also bounds asynchronous request goroutines; callers // apply backpressure before handing off another decoded component. requests chan struct{} - request sync.WaitGroup - mu sync.Mutex - closed bool - stopped chan struct{} - close sync.Once - worker sync.WaitGroup + // Protected by mu. Reserve one request permit for completion/recovery. + prefetchRequests int + completionWaiters int + admissionChanged chan struct{} + request sync.WaitGroup + mu sync.Mutex + closed bool + stopped chan struct{} + close sync.Once + worker sync.WaitGroup } func newTransactionVerifier(workers, queueDepth int, verify func(*solana.Transaction) error) *transactionVerifier { @@ -177,6 +181,16 @@ func (v *transactionVerifier) verifyGroup(job *transactionVerifyJob, batch *txve // never the UDP reader or while holding the assembler mutex. Cancellation of // ctx stops further groups but still joins every admitted group. func (v *transactionVerifier) submitTransactions(ctx context.Context, txs []*solana.Transaction) (*transactionVerification, error) { + return v.submitRequest(ctx, txs, false) +} + +// submitPrefetchTransactions applies backpressure before allocating a request: +// prefetch may use at most 2*workers-1 of the existing 2*workers permits. +func (v *transactionVerifier) submitPrefetchTransactions(ctx context.Context, txs []*solana.Transaction) (*transactionVerification, error) { + return v.submitRequest(ctx, txs, true) +} + +func (v *transactionVerifier) submitRequest(ctx context.Context, txs []*solana.Transaction, prefetch bool) (*transactionVerification, error) { if ctx == nil { ctx = context.Background() } @@ -187,22 +201,9 @@ func (v *transactionVerifier) submitTransactions(ctx context.Context, txs []*sol if entryTraceContext(ctx) { trace = &entryVerificationTrace{Submit: entryTraceNow(), Transactions: len(txs)} } - select { - case v.requests <- struct{}{}: - case <-ctx.Done(): - return nil, ctx.Err() - case <-v.stopped: - return nil, errTransactionVerifierClosed - } - - v.mu.Lock() - if v.closed { - v.mu.Unlock() - <-v.requests - return nil, errTransactionVerifierClosed + if err := v.acquireRequest(ctx, prefetch); err != nil { + return nil, err } - v.request.Add(1) - v.mu.Unlock() ctx, cancel := context.WithCancel(ctx) if trace != nil { trace.Admitted = entryTraceNow() @@ -213,7 +214,7 @@ func (v *transactionVerifier) submitTransactions(ctx context.Context, txs []*sol } go func() { defer v.request.Done() - defer func() { <-v.requests }() + defer v.releaseRequest(prefetch) defer cancel() r.index, r.err = v.verifyTransactionsWithTiming(ctx, txs, r.identities, trace) if trace != nil { diff --git a/pkg/turbine/transaction_verifier_admission.go b/pkg/turbine/transaction_verifier_admission.go new file mode 100644 index 00000000..c0a20ed2 --- /dev/null +++ b/pkg/turbine/transaction_verifier_admission.go @@ -0,0 +1,76 @@ +package turbine + +import "context" + +// acquireRequest keeps the total request/job bounds unchanged while reserving +// one permit for completion or full-block recovery. Waiting completions win the +// next available permit over prefetch; completions are otherwise equal priority. +// This is not replay-head scheduling: unfinished prefetch already admitted for +// the head keeps its existing rolling job window, and future-slot completions +// also use the reservation. No worker is reserved and no admitted job is evicted. +// +// Prefetch can wait while completions remain queued. It is speculative work and +// resumes when the completion backlog drains. Cancellation/close wake waiters +// without admitting a request; accepted requests retain the full join contract. +func (v *transactionVerifier) acquireRequest(ctx context.Context, prefetch bool) error { + v.mu.Lock() + waitingCompletion := false + defer func() { + if waitingCompletion { + v.completionWaiters-- + v.wakeAdmissionLocked() + } + v.mu.Unlock() + }() + for { + if v.closed { + return errTransactionVerifierClosed + } + if err := ctx.Err(); err != nil { + return err + } + if len(v.requests) < cap(v.requests) && + (!prefetch || (v.prefetchRequests < cap(v.requests)-1 && v.completionWaiters == 0)) { + v.requests <- struct{}{} + if prefetch { + v.prefetchRequests++ + } + // Add under the same lock as close, so closeAndWait cannot finish + // while an accepted request has yet to start its goroutine. + v.request.Add(1) + return nil + } + if !prefetch && !waitingCompletion { + v.completionWaiters++ + waitingCompletion = true + } + if v.admissionChanged == nil { + v.admissionChanged = make(chan struct{}) + } + changed := v.admissionChanged + v.mu.Unlock() + select { + case <-changed: + case <-ctx.Done(): + case <-v.stopped: + } + v.mu.Lock() + } +} + +func (v *transactionVerifier) releaseRequest(prefetch bool) { + v.mu.Lock() + <-v.requests + if prefetch { + v.prefetchRequests-- + } + v.wakeAdmissionLocked() + v.mu.Unlock() +} + +func (v *transactionVerifier) wakeAdmissionLocked() { + if v.admissionChanged != nil { + close(v.admissionChanged) + v.admissionChanged = nil + } +} diff --git a/pkg/turbine/transaction_verifier_admission_benchmark_test.go b/pkg/turbine/transaction_verifier_admission_benchmark_test.go new file mode 100644 index 00000000..9971224f --- /dev/null +++ b/pkg/turbine/transaction_verifier_admission_benchmark_test.go @@ -0,0 +1,118 @@ +package turbine + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/gagliardetto/solana-go" +) + +// Compare the request-class policy with the same workers, rolling job window, +// Narya backend and total work. Shared submits prefetch as ordinary completion +// requests to reproduce the old four-permit occupancy; reserved labels it as +// prefetch. This is a saturation microbenchmark, not observed live p99 or true +// replay-head scheduling. All signatures are verified and every request joined. +func BenchmarkVerifierCompletionReservation(b *testing.B) { + flowConfigureBackend(b) + txs := make([]*solana.Transaction, 4096) + for i := range txs { + txs[i] = flowGeneratedTransaction(b, 228, uint64(i)) + } + for _, size := range []int{256, 4096} { + for _, reserved := range []bool{false, true} { + b.Run(fmt.Sprintf("prefetch_%d/reserved_%t", size, reserved), func(b *testing.B) { + v := newTransactionVerifierWithBatchTarget(2, 32, 8, nil) + defer v.closeAndWait() + submit := v.submitTransactions + if reserved { + submit = v.submitPrefetchTransactions + } + var admission, finish, total []time.Duration + occupied := 0 + ctx := context.WithValue(context.Background(), entryTraceContextKey{}, true) + warm, err := v.submitTransactions(context.Background(), txs[:256]) + if err != nil { + b.Fatal(err) + } + if _, err = warm.wait(); err != nil { + b.Fatal(err) + } + b.ResetTimer() + for range b.N { + start := time.Now() + prior := make([]*transactionVerification, 0, 4) + for range 3 { + r, err := submit(context.Background(), txs[:size]) + if err != nil { + b.Fatal(err) + } + prior = append(prior, r) + } + type result struct { + r *transactionVerification + err error + } + fourth := make(chan result, 1) + attempting := make(chan struct{}) + go func() { + close(attempting) + r, err := submit(context.Background(), txs[:size]) + fourth <- result{r, err} + }() + <-attempting + if !reserved { + last := <-fourth + if last.err != nil { + b.Fatal(last.err) + } + prior = append(prior, last.r) + } + expectedActive := cap(v.requests) + if reserved { + expectedActive-- + } + if len(v.requests) == expectedActive { + occupied++ + } + r, err := v.submitTransactions(ctx, txs[:32]) + if err != nil { + b.Fatal(err) + } + if _, err = r.wait(); err != nil { + b.Fatal(err) + } + admission = append(admission, time.Duration(r.trace.Admitted-r.trace.Submit)) + finish = append(finish, time.Duration(r.trace.Finished-r.trace.Submit)) + if reserved { + last := <-fourth + if last.err != nil { + b.Fatal(last.err) + } + prior = append(prior, last.r) + } + for _, r := range prior { + if _, err = r.wait(); err != nil { + b.Fatal(err) + } + } + total = append(total, time.Since(start)) + } + b.StopTimer() + b.ReportMetric(float64(occupied)/float64(b.N), "occupied_fraction") + for _, metric := range []struct { + name string + values []time.Duration + }{ + {"completion_admit", admission}, {"completion_done", finish}, {"all_work", total}, + } { + flowReportPercentiles(b, metric.values, metric.name) + index := max(0, (len(metric.values)*99+99)/100-1) + b.ReportMetric(float64(metric.values[index])/float64(time.Millisecond), metric.name+"_p99-ms") + b.ReportMetric(float64(metric.values[len(metric.values)-1])/float64(time.Millisecond), metric.name+"_max-ms") + } + }) + } + } +} diff --git a/pkg/turbine/transaction_verifier_admission_test.go b/pkg/turbine/transaction_verifier_admission_test.go new file mode 100644 index 00000000..eef2c960 --- /dev/null +++ b/pkg/turbine/transaction_verifier_admission_test.go @@ -0,0 +1,172 @@ +package turbine + +import ( + "context" + "sync" + "testing" + "time" + + "github.com/gagliardetto/solana-go" + "github.com/stretchr/testify/require" +) + +func TestPrefetchLeavesCompletionPermitAndCancellationJoins(t *testing.T) { + release := make(chan struct{}) + v := newTransactionVerifier(2, 32, func(*solana.Transaction) error { <-release; return nil }) + defer v.closeAndWait() + defer close(release) + for range 3 { + _, err := v.submitPrefetchTransactions(context.Background(), verifierTestBlock(64).Transactions) + require.NoError(t, err) + } + require.Equal(t, 3, len(v.requests)) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + blocked := make(chan error, 1) + go func() { _, err := v.submitPrefetchTransactions(ctx, verifierTestBlock(1).Transactions); blocked <- err }() + accepted := make(chan *transactionVerification, 1) + go func() { + r, err := v.submitTransactions(context.Background(), verifierTestBlock(1).Transactions) + if err != nil { + t.Error(err) + } + accepted <- r + }() + select { + case r := <-accepted: + require.NotNil(t, r) + case <-time.After(3 * time.Second): + t.Fatal("prefetch occupied the reserved completion permit") + } + require.Equal(t, cap(v.requests), len(v.requests), "total bound must not increase") + cancel() + select { + case err := <-blocked: + require.ErrorIs(t, err, context.Canceled) + case <-time.After(3 * time.Second): + t.Fatal("canceled prefetch admission did not return") + } + // The admitted jobs are still reading transactions until release closes. + require.Equal(t, 4, len(v.requests)) +} + +// Exercise permit arbitration without depending on cryptographic job duration. +// Holding permits models admitted requests; each release also joins its request. +func TestCompletionWinsAdmissionAndPrefetchResumes(t *testing.T) { + v := newTransactionVerifier(1, 8, nil) + ctx, cancel := context.WithCancel(context.Background()) + var cleanup sync.WaitGroup + defer v.closeAndWait() + defer cleanup.Wait() + defer cancel() + release := func(prefetch bool) { v.releaseRequest(prefetch); v.request.Done() } + for range 2 { + require.NoError(t, v.acquireRequest(ctx, false)) + } + firstReleased := false + defer func() { + if !firstReleased { + release(false) + } + release(false) + }() + completionAdmitted := make(chan struct{}) + completionRelease := make(chan struct{}) + var once sync.Once + defer once.Do(func() { close(completionRelease) }) + cleanup.Go(func() { + if err := v.acquireRequest(ctx, false); err != nil { + return + } + close(completionAdmitted) + select { + case <-completionRelease: + case <-ctx.Done(): + } + release(false) + }) + require.Eventually(t, func() bool { v.mu.Lock(); defer v.mu.Unlock(); return v.completionWaiters == 1 }, 3*time.Second, time.Millisecond) + prefetchAdmitted := make(chan struct{}) + cleanup.Go(func() { + if err := v.acquireRequest(ctx, true); err != nil { + return + } + close(prefetchAdmitted) + release(true) + }) + release(false) + firstReleased = true + waitSignal(t, completionAdmitted, "priority completion admission") + select { + case <-prefetchAdmitted: + t.Fatal("prefetch bypassed waiting completion") + default: + } + once.Do(func() { close(completionRelease) }) + waitSignal(t, prefetchAdmitted, "prefetch resumed after completion") +} + +func TestCanceledCompletionDoesNotBlockPrefetch(t *testing.T) { + v := newTransactionVerifier(1, 8, nil) + defer v.closeAndWait() + for range 2 { + require.NoError(t, v.acquireRequest(context.Background(), false)) + } + defer func() { + for range 2 { + v.releaseRequest(false) + v.request.Done() + } + }() + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + done := make(chan error, 1) + go func() { done <- v.acquireRequest(ctx, false) }() + require.Eventually(t, func() bool { v.mu.Lock(); defer v.mu.Unlock(); return v.completionWaiters == 1 }, 3*time.Second, time.Millisecond) + cancel() + select { + case err := <-done: + require.ErrorIs(t, err, context.Canceled) + case <-time.After(3 * time.Second): + t.Fatal("completion cancellation stranded admission") + } + v.mu.Lock() + require.Zero(t, v.completionWaiters) + v.mu.Unlock() +} + +func TestCloseWakesBothAdmissionClassesAndJoinsAcceptedWork(t *testing.T) { + release := make(chan struct{}) + v := newTransactionVerifier(1, 8, func(*solana.Transaction) error { <-release; return nil }) + var once sync.Once + defer v.closeAndWait() + defer once.Do(func() { close(release) }) + _, err := v.submitPrefetchTransactions(context.Background(), verifierTestBlock(1).Transactions) + require.NoError(t, err) + _, err = v.submitTransactions(context.Background(), verifierTestBlock(1).Transactions) + require.NoError(t, err) + results := make(chan error, 2) + for _, prefetch := range []bool{true, false} { + go func() { + _, err := v.submitRequest(context.Background(), verifierTestBlock(1).Transactions, prefetch) + results <- err + }() + } + closed := make(chan struct{}) + go func() { v.closeAndWait(); close(closed) }() + for range 2 { + select { + case err := <-results: + require.ErrorIs(t, err, errTransactionVerifierClosed) + case <-time.After(3 * time.Second): + t.Fatal("close stranded admission") + } + } + select { + case <-closed: + t.Fatal("close returned while jobs still own transactions") + default: + } + once.Do(func() { close(release) }) + waitSignal(t, closed, "close joined accepted work") +} From be807ff74d391470548147aabb551054b43630c5 Mon Sep 17 00:00:00 2001 From: 7layermagik <7layermagik@users.noreply.github.com> Date: Tue, 15 Sep 2026 19:32:17 -0500 Subject: [PATCH 019/183] review: clarify ownership and archive investigation artifacts --- .gitattributes | 7 - docs/out-of-order-entry-prefetch.md | 12 +- .../2026-09-12-zen5/README.md | 195 - .../baseline-root-adapter.go.txt | 7 - .../2026-09-12-zen5/raw-results.tar.gz | Bin 53842 -> 0 bytes .../2026-09-12-zen5/summarize.py | 59 - .../2026-09-12-zen5/summary.json | 1430 ----- .../2026-09-15/README.md | 1 - .../2026-09-15/baseline-bench.log | 18 - .../2026-09-15/baseline-regression.log | 16 - .../2026-09-15/benchmark-window.json | 1 - .../2026-09-15/candidate-bench.log | 18 - .../2026-09-15/index-bench.log | 7 - .../pr-split-2026-09-15/streaming/README.md | 7 - .../streaming/streaming-build.log | 0 .../streaming/streaming-tests.log | 6 - .../streaming/streaming-vet.log | 0 .../results/review-fixes/2026-09-15/README.md | 15 - .../2026-09-15/native-blackhole-race.log | 242 - .../2026-09-15/native-build-final.log | 6 - .../review-fixes/2026-09-15/native-build.log | 0 .../2026-09-15/native-config-final.log | 9 - .../review-fixes/2026-09-15/native-race.log | 10 - .../review-fixes/2026-09-15/native-run.log | 10 - .../2026-09-15/native-summary.json | 14 - .../review-fixes/2026-09-15/native-vet.log | 0 .../2026-09-15/native-window.json | 4 - .../2026-09-15/post-test-health.json | 1 - .../2026-09-15/streaming-before.log | 37 - .../2026-09-15/streaming-build.log | 0 .../2026-09-15/streaming-config-final.log | 1 - .../2026-09-15/streaming-race.log | 7 - .../2026-09-15/streaming-targeted.log | 2 - .../review-fixes/2026-09-15/streaming-vet.log | 0 .../2026-09-15/tested-source.json | 16 - .../review-fixes/2026-09-15/voting-before.log | 18 - .../2026-09-15/voting-blackhole-race.log | 1 - .../review-fixes/2026-09-15/voting-build.log | 0 .../review-fixes/2026-09-15/voting-race.log | 4 - .../2026-09-15/voting-targeted.log | 1 - .../review-fixes/2026-09-15/voting-vet.log | 0 .../2026-09-12-zen5/README.md | 134 - .../2026-09-12-zen5/binaries.json | 4 - .../2026-09-12-zen5/commands.jsonl | 15 - .../2026-09-12-zen5/local-race.txt | 1 - .../2026-09-12-zen5/local-unit.txt | 3 - .../2026-09-12-zen5/method.json | 8 - .../2026-09-12-zen5/native-race.txt | 1 - .../2026-09-12-zen5/native-unit.txt | 1 - .../2026-09-12-zen5/run_native.py | 31 - .../2026-09-12-zen5/sample-1-baseline.txt | 13 - .../2026-09-12-zen5/sample-1-candidate.txt | 13 - .../2026-09-12-zen5/sample-2-baseline.txt | 13 - .../2026-09-12-zen5/sample-2-candidate.txt | 13 - .../2026-09-12-zen5/sample-3-baseline.txt | 13 - .../2026-09-12-zen5/sample-3-candidate.txt | 13 - .../2026-09-12-zen5/sample-4-baseline.txt | 13 - .../2026-09-12-zen5/sample-4-candidate.txt | 13 - .../2026-09-12-zen5/sample-5-baseline.txt | 13 - .../2026-09-12-zen5/sample-5-candidate.txt | 13 - .../2026-09-12-zen5/sample-6-baseline.txt | 13 - .../2026-09-12-zen5/sample-6-candidate.txt | 13 - .../2026-09-12-zen5/summarize.py | 54 - .../2026-09-12-zen5/summary.json | 3358 ---------- .../2026-09-12-zen5/BENCHMARKS.md | 113 - .../2026-09-12-zen5/README.md | 152 - .../2026-09-12-zen5/assembly-1232.log | 29 - .../2026-09-12-zen5/assembly-captured.log | 29 - .../2026-09-12-zen5/assembly-comparison.json | 1602 ----- .../2026-09-12-zen5/binary-sha256.txt | 3 - .../2026-09-12-zen5/captured-pool-flow.log | 113 - .../2026-09-12-zen5/execution-comparison.json | 1653 ----- .../2026-09-12-zen5/execution-contention.log | 162 - .../2026-09-12-zen5/execution-raw.log | 576 -- .../2026-09-12-zen5/final-commands.jsonl | 6 - .../2026-09-12-zen5/final-source-update.json | 30 - .../generated-1232-pool-flow.log | 77 - .../2026-09-12-zen5/health-after-final.txt | 4 - .../2026-09-12-zen5/local-replay.log | 1 - .../2026-09-12-zen5/local-turbine-race.log | 1 - .../2026-09-12-zen5/local-unit.log | 7 - .../2026-09-12-zen5/native-final-race.log | 1 - .../2026-09-12-zen5/native-final-unit.log | 6 - .../2026-09-12-zen5/pool-comparison.json | 5503 ----------------- .../run_execution_contention.py | 231 - .../streaming-pr-review/2026-09-13/README.md | 99 - .../2026-09-13/binaries-sha256.txt | 2 - .../2026-09-13/local-race.txt | 7 - .../2026-09-13/local-root-fuzz.txt | 7 - .../2026-09-13/native-assembly.txt | 13 - .../2026-09-13/native-build.txt | 0 .../2026-09-13/native-race.txt | 7 - .../2026-09-13/native-vet.txt | 0 .../2026-09-13/pointer-after.txt | 18 - .../2026-09-13/pointer-before.txt | 18 - .../2026-09-13/run-native.sh | 19 - .../2026-09-13/service-after.txt | 2 - .../2026-09-13/service-before.txt | 2 - .../2026-09-13/source-sha256.txt | 1 - docs/shred_retention_performance.md | 23 +- docs/streaming-preparation-evidence.md | 14 + docs/streaming_message_identities.md | 20 +- docs/transaction_sigverify_streaming.md | 8 +- docs/turbine-relay-buffers.md | 2 +- 104 files changed, 28 insertions(+), 16481 deletions(-) delete mode 100644 .gitattributes delete mode 100644 docs/results/completion-followup/2026-09-12-zen5/README.md delete mode 100644 docs/results/completion-followup/2026-09-12-zen5/baseline-root-adapter.go.txt delete mode 100644 docs/results/completion-followup/2026-09-12-zen5/raw-results.tar.gz delete mode 100644 docs/results/completion-followup/2026-09-12-zen5/summarize.py delete mode 100644 docs/results/completion-followup/2026-09-12-zen5/summary.json delete mode 100644 docs/results/out-of-order-prefetch/2026-09-15/README.md delete mode 100644 docs/results/out-of-order-prefetch/2026-09-15/baseline-bench.log delete mode 100644 docs/results/out-of-order-prefetch/2026-09-15/baseline-regression.log delete mode 100644 docs/results/out-of-order-prefetch/2026-09-15/benchmark-window.json delete mode 100644 docs/results/out-of-order-prefetch/2026-09-15/candidate-bench.log delete mode 100644 docs/results/out-of-order-prefetch/2026-09-15/index-bench.log delete mode 100644 docs/results/pr-split-2026-09-15/streaming/README.md delete mode 100644 docs/results/pr-split-2026-09-15/streaming/streaming-build.log delete mode 100644 docs/results/pr-split-2026-09-15/streaming/streaming-tests.log delete mode 100644 docs/results/pr-split-2026-09-15/streaming/streaming-vet.log delete mode 100644 docs/results/review-fixes/2026-09-15/README.md delete mode 100644 docs/results/review-fixes/2026-09-15/native-blackhole-race.log delete mode 100644 docs/results/review-fixes/2026-09-15/native-build-final.log delete mode 100644 docs/results/review-fixes/2026-09-15/native-build.log delete mode 100644 docs/results/review-fixes/2026-09-15/native-config-final.log delete mode 100644 docs/results/review-fixes/2026-09-15/native-race.log delete mode 100644 docs/results/review-fixes/2026-09-15/native-run.log delete mode 100644 docs/results/review-fixes/2026-09-15/native-summary.json delete mode 100644 docs/results/review-fixes/2026-09-15/native-vet.log delete mode 100644 docs/results/review-fixes/2026-09-15/native-window.json delete mode 100644 docs/results/review-fixes/2026-09-15/post-test-health.json delete mode 100644 docs/results/review-fixes/2026-09-15/streaming-before.log delete mode 100644 docs/results/review-fixes/2026-09-15/streaming-build.log delete mode 100644 docs/results/review-fixes/2026-09-15/streaming-config-final.log delete mode 100644 docs/results/review-fixes/2026-09-15/streaming-race.log delete mode 100644 docs/results/review-fixes/2026-09-15/streaming-targeted.log delete mode 100644 docs/results/review-fixes/2026-09-15/streaming-vet.log delete mode 100644 docs/results/review-fixes/2026-09-15/tested-source.json delete mode 100644 docs/results/review-fixes/2026-09-15/voting-before.log delete mode 100644 docs/results/review-fixes/2026-09-15/voting-blackhole-race.log delete mode 100644 docs/results/review-fixes/2026-09-15/voting-build.log delete mode 100644 docs/results/review-fixes/2026-09-15/voting-race.log delete mode 100644 docs/results/review-fixes/2026-09-15/voting-targeted.log delete mode 100644 docs/results/review-fixes/2026-09-15/voting-vet.log delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/README.md delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/binaries.json delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/commands.jsonl delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/local-race.txt delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/local-unit.txt delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/method.json delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/native-race.txt delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/native-unit.txt delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/run_native.py delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-1-baseline.txt delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-1-candidate.txt delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-2-baseline.txt delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-2-candidate.txt delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-3-baseline.txt delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-3-candidate.txt delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-4-baseline.txt delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-4-candidate.txt delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-5-baseline.txt delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-5-candidate.txt delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-6-baseline.txt delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/sample-6-candidate.txt delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/summarize.py delete mode 100644 docs/results/sigverify-direct-cache/2026-09-12-zen5/summary.json delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/BENCHMARKS.md delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/README.md delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/assembly-1232.log delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/assembly-captured.log delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/assembly-comparison.json delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/binary-sha256.txt delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/captured-pool-flow.log delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/execution-comparison.json delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/execution-contention.log delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/execution-raw.log delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/final-commands.jsonl delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/final-source-update.json delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/generated-1232-pool-flow.log delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/health-after-final.txt delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/local-replay.log delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/local-turbine-race.log delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/local-unit.log delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/native-final-race.log delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/native-final-unit.log delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/pool-comparison.json delete mode 100644 docs/results/sigverify-streaming/2026-09-12-zen5/run_execution_contention.py delete mode 100644 docs/results/streaming-pr-review/2026-09-13/README.md delete mode 100644 docs/results/streaming-pr-review/2026-09-13/binaries-sha256.txt delete mode 100644 docs/results/streaming-pr-review/2026-09-13/local-race.txt delete mode 100644 docs/results/streaming-pr-review/2026-09-13/local-root-fuzz.txt delete mode 100644 docs/results/streaming-pr-review/2026-09-13/native-assembly.txt delete mode 100644 docs/results/streaming-pr-review/2026-09-13/native-build.txt delete mode 100644 docs/results/streaming-pr-review/2026-09-13/native-race.txt delete mode 100644 docs/results/streaming-pr-review/2026-09-13/native-vet.txt delete mode 100644 docs/results/streaming-pr-review/2026-09-13/pointer-after.txt delete mode 100644 docs/results/streaming-pr-review/2026-09-13/pointer-before.txt delete mode 100644 docs/results/streaming-pr-review/2026-09-13/run-native.sh delete mode 100644 docs/results/streaming-pr-review/2026-09-13/service-after.txt delete mode 100644 docs/results/streaming-pr-review/2026-09-13/service-before.txt delete mode 100644 docs/results/streaming-pr-review/2026-09-13/source-sha256.txt create mode 100644 docs/streaming-preparation-evidence.md diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index d64360d9..00000000 --- a/.gitattributes +++ /dev/null @@ -1,7 +0,0 @@ -# Keep raw benchmark evidence available without overwhelming the review. -# Retain raw Go CPU padding and test-framework space/tab indentation. -docs/results/**/*.json linguist-generated=true -docs/results/**/*.jsonl linguist-generated=true -docs/results/**/*.txt linguist-generated=true whitespace=-blank-at-eol -docs/results/**/*.log linguist-generated=true -whitespace -docs/results/**/*.tar.gz linguist-generated=true diff --git a/docs/out-of-order-entry-prefetch.md b/docs/out-of-order-entry-prefetch.md index c24e2dbd..9645b6d3 100644 --- a/docs/out-of-order-entry-prefetch.md +++ b/docs/out-of-order-entry-prefetch.md @@ -23,12 +23,6 @@ The delayed-shred case now verifies roughly 33.5–33.7k transactions before ass Reproduce with `MITHRIL_SIGVERIFY_FLOW_BACKEND=r51 GOMAXPROCS=8 go test ./pkg/turbine -run '^$' -bench '^BenchmarkEntryPrefetchGapArrival$' -benchtime=3x` on each implementation, copying the same benchmark file to the baseline. -## Initial live measurement - -The fixed post-warmup window, 2026-09-15 01:27:00–01:30:00 UTC, contains 27 sampled large blocks: 25 external and two own-leader observations, which are excluded from these latency statistics. Every retained transaction had known batch availability, timing order and transaction accounting passed validation, and no trace reports were dropped. - -Across the 25 external blocks, maximum complete-availability-to-discovery delay was 0.018715 ms (18.7 microseconds). Assembly-to-ready was 4.709 ms median and 14.710 ms maximum; none exceeded 20 ms. The earlier diagnostic window had five external blocks above20ms among30, including the38.99ms example. These are small observational samples with different blocks/leaders, not matched causal estimates or a guarantee that all long tails are gone. The direct discovery timings and controlled delayed-shred benchmark support the mechanism specifically. - -The first completed current-build FAST capture, filtered to source slots first observed after01:27UTC and deduplicated by full proof key, included us in461/466FAST certificates (98.93%); large blocks were79/82 (96.34%). This is a local footer sample, not the rolling Puffin score or Titan reward inclusion. It does not establish a lasting overall FAST improvement. All751clean replay observations had notarize events; no reservation exhaustion was observed. A separate30second probe sanity check also had112/112replay/notarize, no rejection/exhaustion and no parse/truncation errors. - -At01:30:27UTC voting was current within3slots, allfourservices active,88/88peer connections, zero broadcast drops, peer-send errors, queue drops/discards/timeouts or connection errors. Three completed own-leader load windows produced12blocks with zero sender errors, up to48,622transactions/block. Counts by window:3798364=[22447,48622,44343,43730];3799208=[17139,48622,36041,40611];3799488=[22814,46680,41221,42949]. The existing continuous loader and all monitoring remain running. +Historical live trials and their limitations are in the +[archived evidence](streaming-preparation-evidence.md). Component results do not establish +a sustained FAST-inclusion improvement. diff --git a/docs/results/completion-followup/2026-09-12-zen5/README.md b/docs/results/completion-followup/2026-09-12-zen5/README.md deleted file mode 100644 index 1fb87113..00000000 --- a/docs/results/completion-followup/2026-09-12-zen5/README.md +++ /dev/null @@ -1,195 +0,0 @@ -# Shred ordering, authenticated roots, and larger verification jobs - -For 33,760 maximum-size transactions arriving over 200 ms, the final-shred-to-ready -tail fell from **11.24 to 6.44 ms**, a **42.7% reduction**. Catch-up assembly with -overlap enabled improved from **105.36 to 99.75 ms**. These measurements compare -against `e063695f5b22a68990007c99c7dc7b64eef5568e`, which already contains streaming -verification and direct shred-to-cache byte comparison. This is not an -`alpenglow-dev` or whole-validator replay comparison. - -## Changes - -- Complete contiguous slots walk shred indexes directly. The decoder accepts - that order without sorting again; sparse or extra-tail input retains a sorted - fallback that includes every shred. -- The receiver passes the root it authenticated into assembly. Each FEC state - retains at most one selected source snapshot. Completion reuses that root only - if the source, parsed root inputs, and every payload byte still match. It keeps - the previous lowest-data-index / lowest-coding-position selection and error - behavior. Root selection avoids sorting, and relative data index zero avoids - a map scan. Repair, reset, and missing-hint paths retain root computation. -- Large ready signature requests dispatch four vector groups per job, normally - 32 one-signature transactions. Narya still processes eight-wide groups. With - two workers and target eight, requests below 128 ready transactions retain one - group per job. There is no timer or wait for more transactions. A request owns - at most two outstanding jobs under the tested configuration. Cancellation - joins admitted work and can stop between vector groups in a larger job. - -## Method and scope - -- Ryzen 7 9700X, eight physical cores / sixteen hardware threads; Go 1.26.4, - Narya `r51` at `c265ee9667131a556cd332c252b79de0860c7640`. -- `GOMAXPROCS=8`, affinity CPUs 0–7 (distinct physical cores), nice 10. Mithril - and Lightbringer continued running; the validator binary and PID were unchanged. -- Both generated fixtures contain 33,760 distinct valid one-signature - transactions, exactly 228 or 1,232 wire bytes each. Complete component bursts - span 200 ms at the synthetic tip. Catch-up offers all shreds immediately. - Components use a 60 KiB transaction-byte budget, a benchmark choice rather - than a protocol requirement, with real entry overhead and FEC padding. -- The final comparison has six alternating baseline/candidate pairs, each with - five timed blocks per condition. Tables show medians of the six reported - values. Residual columns are medians of per-run p50s, not pooled percentiles. -- The assembly benchmark now supplies already-authenticated roots as the receiver - does. Both binaries use the same benchmark source; a test-only baseline adapter - ignores the roots and calls the old admission method. Root snapshot creation - is inside the timed candidate path. Authentication and fixture construction - remain outside timing on both sides. -- Timed work includes assembly, entry decoding, Merkle/block identity checks, - transaction signature verification, and publication. Packet parsing, shred - authentication, network loss/recovery, disk I/O, transaction execution, PoH, - and commit are excluded. This is not a recorded arrival trace. - -## Final assembly results - -Both sides below have overlap enabled and use two signature workers. CPU-ms -sums process CPU across cores, rather than single-thread wall time. MB means -decimal megabytes of total Go allocation volume (`B/op`), not peak heap. - -| Wire bytes/tx | Final-shred-to-ready | First-arrival-to-ready | CPU-ms/block | Allocated MB/block | -|---|---:|---:|---:|---:| -| 228 | 2.35 → **1.40 ms** | 203.13 → **202.30 ms** | 175.25 → 170.25 | 33.09 → 33.44 | -| 1,232 | 11.24 → **6.44 ms** | 212.58 → **207.64 ms** | 235.40 → 233.55 | 114.14 → 115.56 | - -Every maximum-size pair improved residual latency, by 40.8–44.3%. The whole -arrival-to-ready reduction is 2.3%, since the approximately 201 ms collection -period remains. Root snapshots add about 1.4 MB of allocation volume per large -block net of the removed ordering allocations; this change primarily reduces -the completion tail, rather than total tip CPU work. - -| Catch-up wire bytes/tx | Overlap | Total assembly baseline → final | -|---|---|---:| -| 228 | Off | 83.98 → **80.58 ms** | -| 228 | On | 81.77 → **79.35 ms** | -| 1,232 | Off | 108.87 → **102.78 ms** | -| 1,232 | On | 105.36 → **99.75 ms** | - -These catch-up cases supply authenticated roots, as fresh verified ingress can. -Spool hydration has no retained root hints. A separate three-pair, five-block -comparison exercised that fallback using the same final production code: - -| Catch-up wire bytes/tx | Overlap | No-hint baseline → final | -|---|---|---:| -| 228 | Off | 83.71 → **82.23 ms** | -| 228 | On | 81.80 → **80.67 ms** | -| 1,232 | Off | 108.08 → **104.34 ms** | -| 1,232 | On | 105.57 → **101.32 ms** | - -This models root-hint availability, not actual spool read performance. - -## Choosing the dispatch size - -Four rotated screening rounds compared ordering alone and nominal job sizes of -8, 32, and 64 signatures. Each condition had five timed blocks per round. These -intermediate variants predate the final direct FEC index-zero lookup; their -assembly times must not be substituted for the final comparison above. -The job-size table holds the new dispatcher code constant to isolate policy; -the final assembly comparison instead uses the prior production implementation. - -| Signature-only catch-up | 8 per job | 32 per job | 64 per job | -|---|---:|---:|---:| -| 228-byte transactions, wall time | 77.53 ms | **75.04 ms** | 73.78 ms | -| 1,232-byte transactions, wall time | 86.66 ms | **83.57 ms** | 83.20 ms | -| 228-byte transactions, CPU-ms | 157.60 | **151.35** | 148.30 | -| 1,232-byte transactions, CPU-ms | 181.60 | **174.45** | 173.55 | - -32-signature jobs save about 3–4% catch-up wall time in this pool test. Sparse -four-transaction arrivals still dispatch immediately; their observed p95 -availability-to-verdict remained approximately 1 ms, dominated by synthetic -feed scheduling. The 64 policy is somewhat faster in catch-up, but offers little -additional benefit for maximum-size transactions and doubles the work one job -can put ahead of another request. We selected 32 as the smaller useful policy; -the measurements do not establish that 64 is harmful. - -The real lean transfer load/execute probe also ran before and during signature -load on the same eight cores. It used captured block 2622581's 33,760 228-byte -transactions, two workers, and target eight: - -| Nominal signatures/job | Catch-up execution slowdown | Tip execution slowdown | -|---|---:|---:| -| 8 | +6.71% | +2.28% | -| **32** | **+6.64%** | **+3.35%** | -| 64 | +5.56% | +3.96% | - -These are medians of three paired slowdown ratios, not ratios of aggregate -times. For 32-signature jobs, tip pairs ranged from +2.38% to +4.40%; for eight, -from +0.81% to +4.16%. There is no clear large contention penalty from the wider -jobs in this test, but the small differences should not be overinterpreted. -The two workloads run in separate processes, excluding shared Go scheduler/heap -effects, dependency planning, commit, and full replay. - -The initial contention round overlapped an artifact download/compression and -was excluded in full. An additional complete round replaced it. All original -logs are retained; the table uses rounds 2, 3, and 4 consistently for every policy. - -## Remaining completion work - -A separate 30-block diagnostic profile of the final maximum-size candidate -averaged 6.42 ms after full assembly: - -| Completion stage | Mean ms/block | -|---|---:| -| Entry decoding and cache-byte validation | 4.30 | -| Construct ordered shred slice | 0.82 | -| Collect/check FEC roots | 0.67 | -| Construct block and footer metadata | 0.46 | - -The final signature join's median was 0.106 ms. The stage values are distinct -coarse timers; bookkeeping and the join account for the remainder. The earlier -current-baseline profile measured approximately 3.1 ms in the two ordering -steps and 3.5 ms in root collection. Exact byte validation now dominates the -remaining work. - -## Validation and reproduction - -Native Turbine, replay, and node tests, the full native Turbine race suite, and -native vet passed. The full local Turbine race suite and vet passed on the final -source. Local txverify/sigverify/node tests passed. The local replay suite hit -its existing `promotion_test.go:349` zero-duration assertion, also reproduced -in isolated repetition, then passed on full rerun. That test and production -replay code are unchanged from the baseline; no timing assertion was relaxed. - -New regressions cover sparse/extra-tail ordering, public unsorted decode parity, -every root-snapshot payload byte and parsed input, replacement/reset/duplicate -admission, recovered-data/coding precedence, multisignature groups, failure -index attribution, bounded yielding, and cancellation ownership. The final -root-selector fuzz run passed 64,721 executions against the original sorted -algorithm, including unsupported types; an earlier screening run passed 128,732. -Every timed assembly asserts transaction coverage, exactly one verification per -retained signature, expected block identity/footer metadata, and no internal -native-verifier fallback. - -`raw-results.tar.gz` contains the raw screening, final, fallback, contention, -profile, and validation logs. `summary.json` is regenerated from it by -`python3 summarize.py`. Source/binary hashes and exact commands are included. -The three screening patches in the archive's `sources/` directory recreate -their intermediate source from `e063695f`; -for the 32/64 screening variants, change `defaultTransactionJobGroups` from one -to four/eight in the roots patch result. - -For the final candidate, build this checkout. For the baseline, check out -`e063695f`, copy the candidate's `entry_prefetch_benchmark_test.go` into it, and -copy `baseline-root-adapter.go.txt` to -`pkg/turbine/benchmark_root_adapter_test.go`. Then build and alternate binaries: - -```sh -go test -c -o /tmp/turbine-completion.test ./pkg/turbine -GOMAXPROCS=8 MITHRIL_SIGVERIFY_FLOW_BACKEND=r51 \ -MITHRIL_SIGVERIFY_FLOW_COUNT=33760 \ -taskset --cpu-list 0-7 /tmp/turbine-completion.test \ - -test.run='^$' -test.benchtime=5x -test.count=1 \ - -test.bench='^BenchmarkEntryPrefetchAssembly$/^generated_.*$/^workers_2$/^target_8$/.*' -``` - -Select the target machine's distinct physical core IDs. The archived runners -record this server's paths and settings. The live validator was not deployed -or restarted by these experiments. diff --git a/docs/results/completion-followup/2026-09-12-zen5/baseline-root-adapter.go.txt b/docs/results/completion-followup/2026-09-12-zen5/baseline-root-adapter.go.txt deleted file mode 100644 index 9d645b92..00000000 --- a/docs/results/completion-followup/2026-09-12-zen5/baseline-root-adapter.go.txt +++ /dev/null @@ -1,7 +0,0 @@ -package turbine - -import "github.com/gagliardetto/solana-go" - -func (a *SlotAssembler) addShredFromWithRoot(s *Shred, repair bool, root *solana.Hash) (*slotCompletionWork, error) { - return a.addShredFrom(s, repair) -} diff --git a/docs/results/completion-followup/2026-09-12-zen5/raw-results.tar.gz b/docs/results/completion-followup/2026-09-12-zen5/raw-results.tar.gz deleted file mode 100644 index ee85538024754f5cd7c7079d06641a6a17454e9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53842 zcmYJZcRW`A|37|QW;WUDvR7udF+~3 z*b{-8vWzGGcb)I}(U(7#xmkGa)o;g|Yr@yL4YPeXD*wr4&B%R5eft_5F!i-5=;DAZ zz{~IKQ{cs_|5(WBL5wXMpxM`Q`~%COmCnSeYl7j~rL}OHBSyvr#-ZK4y@mFb5O}Zo zR2CKbrRmw}0=MnoBs9EJ+SGrsH3vMs&UXBk|NQ|ArAV>Rpo4`IWe|%p9KA%7@zMO>dKBLMLiwO*EX*%(cOQLG{ik@N%M()sh4z(XQXX$n~ zT)c~sL#^0i2L^_Wn)AEF$ZvZ8dxo%Ntf%_g^m{fmARzE==g&i zO|KkeU;3?RIo4vPMZ*B8A1r^6f4-ulxR&Lb#clpY%CTe?r}_L&-KESaVw3u|m(%Ri zdsltrC0<|W$4-CR-Hv*KBgf6w*qgDBU;1>^`&S#6bWxVkO!G-*o0RZVa5v>=qiQ?_ z|1EF+Hl}=IG8nxlk!Ik%A;Huaq#+pN&lKZKk|BavF*wxNJ8oqOh*p`n!q>fYckvHe?#(=nSwZ9t_J~T4aKg#+EO-0|BK8)LH zeIXPeOiAcY?4x`&xbaK&nxeV{{!>}SH#7%)9(0zc=dmovKgU=6Fo`swa(~%-b?QZLYO!Qc zjdX`XwXbk9j@v>Jne?(DaiAe|LL_I7yw0V`LJ{+UOl$wKhbf65mulr(%4*;5lhI_Z z<;2(7t+dzT#aV*-HmobdKWFkgW^$#Ky%4(+R^B9ox13kc+YS)1(e5*ryB4 z(26$Z!`vS?TXG`=arw%UF?3tS$;^SeT!r&*g-v{o=v@=b3exbsxv(*;Yg$k46y%KF zkwnMNbHJ$+ZD_$f?xO{iG~0lr^e$$WP;M6)m+KP!ClA$v{yLJ~%rzv%Gg-Wg9N1Qt z-a}Ru?qc4QyBKNGc{%p$ekf*-yga(==jMc1E{Zg7uL*p3S?!tdsVT+Z+4z)lhr9kz zR+Z@yVZFbEUZ$ZbV&)25B&&}RpAc$2j5CE@n_PorcDn^LEvZhga_RrIz}z~wpEr^| zh(PiC5O@zBdU5RvFb1V%&KnH}(49I^hs+zr7q%jMh{JLTPOo-yYR`RT^JK!>wJDye z=ik;Ve|VvxNO$mp{%6c^mOs-f)3wpaz($V`=JSi^<}^m+*j{?lxWC~jFTP!3g|yAm z(lmZ1Qs*rbZHirD)>iWMtXDqIZsl&pwjN#-Eo$fdkTfTskyd8F+G!OSp5}U_uB*vL6yZyd{fUH&X75s$<0U5)Y4Ce!+7qnP&-%tu?!^ zhucVSPZf&_ln65CHOTl>$DnOwqg19OD)hGao090YR#f9`FFgU0ft{<^j!jC03VbRQ z2#!QgSsASrp|nJ<9*Pmx&m$kTqt3$Grvyv6z~BZGRv-pL2Jm!wmNMylT>8b}n$Mi4 z28*bZr%#a__i-Pa%8A>UCGuq92%|mZU8N<|L+nEutUxT61rlgI4zSO?su^NG7*@e9 z?(_PLD}aA>1SN@aD7Q8#J4$B~QI_RCYPDbYjtWqV&@^=aB*l~DYANZf1Q*7I6P#z> ztNb+GXRn11bSPxA8s%wKwy(TcT_pH6!sebRsUQ{$Tqaq>8Dh1QmOxr#Rw-{vb&9lb z1D|K*(bHA~^X%)A1Q4NaqZ8##$oTD;NCzB9j&pW&ATY~4etjPG7xK}N6(NLP=XE;g zP6X%%TFMJ`d{fG~hadLhndkX1b40cx6iG({0dZ{eb#+KKW3L4noZSXE?QFY_1Y1yXm+q;Q1|^n!_n`4 zvu)}zOQn*@wV&VQI#e?~lYLC(yc%ReO|AMQ=hQ9zmW5I_F=t*v+H+>2owAbRHlX@` zn@CNtcDn2O>v9?1*xa0}9&QbUM$X|4Nb*Cd)m3qZ!>E& zrckP)BTw-qtXJA;=BYgV@|EV3Vg+>E_S-URBI}C&bnXYXAPpZU z!$mE~#Pq929H$X(;V2f9SM7=fXu;j<@~bcAsai>njmQtyeMT=aMEL`&=r!N;W%*sL zA2O!A#w=H0K?eI7%2S8%dkFNfx2N&ut5Ch`$AjGbg2tG5 zS+di1vMMy`X#~Z}^qmsPQbKsyf#bLpX-S3^dafY1Rv=X0d_sp-^ zj@1%clVR-$+BgO!myIZIU1#TVFyBGHjLQ+>ylrG>(DLNo%~Fe9{gl1;H41dlO>N`1 zx%J7M%85jD!46bV-JZ5F`HcbY*Iav_!w6({ky+}9CrWU8{K5;6y@zo+oTFXMVt>|$ z<&=Sq)Fl(FVAQ+HxW=-;!#R_~bFeFN^{u><{mxHxYJE9D&iMVtF7A`hH!N%G4(BAI znA+aG)LfUAo^offBx~3lMU$=WgWCs`eQS0)9XeQyIRTYYaQ*Q+CHW70qo3TPQW_5D zjJXpv!$ho!nPQ-R(W6Yu}ocNDVl`HP)GwqiGv= zZVC~^>dR~wyPA{Xar4BDmV#ULFVYrXoO|5XdILxX3xRV2mkMou9Mri)%_)dw#GDQF zG;-hGnY`O3h9IyL#eGhr3fP`0CY5~wF?+J(nLN>U)|?Z&o8ljt)gX}Yt5-zICztc> zN|uOa_beU5;#j5#QSTM!);jNIh^C_Bs{>4oj(pSwp z?@+Q-C(kJC|1{B|xi5Fvr&K;DnH2sf*DtZPV40;>()@*hvq-q=oxi+T^#1L;x;4sJ zfqPhV-g^+uUOTK`J%0ea^4>O@dNx@w4?3iB>n)(1Obs%z$Qy$|;LZ8rTpkq2LlL&$ zJvd=+eBJU2B&>|N{Y+5Bt9mR~wdQ0H}mYGqNUc{_Ygond2i`#mAi%9mGt zT^v^;7uz=zF!2L4{iZGY+N<6=uZT>giaAW%+C>c7H$CngPgxUi;<1*)U5>XDs6vmx z6_(5I&{iR1E+dBQGxf7#MG@3LR)Ohout$2m!h<05k&+6>m!^HAR+(O5zeOH<@m(Na zbiA?0;F1i}qgoi?)aMVyJrlq?DxgFCO|#BCGh+0X^cCQ>i{@~x^t;M=DDo{jEMnbA zU->Y`tJWwhpI}x7kM>m7cRpwj({wR;raK28x}Of=0b6g`&MGTwru zqSIS_&b~1L@cg9@bk2&AY)ueNFO)e$1)H3EbWV>wpaQSzb}=0@@R>xWgC-D7sXd&t zOj-Fp%F!AH!F*qMd@CU&6jeo@=VBE!A_h5@ zONL4Fwki`DzZ>R1j4cbKe0+GNTK>zu*LLmi@e4`@)80L<()fM-{6`$iN(ZgX->B>M z)&}^7Y3D=|{FahXyZ|0_bK3O-zKZ0)b4QbZ$-x{%#wiok-2TId)$j3D(uawmm(lA& z+61jPA;HQHNS9VrXHJ&BMFP?=zBbp0x3#o8C=3%9U!yCT!2xvnWqF!l|-8Cm{;JiZ|_U^XciMS4XVsAtQRCM1dmRl`*HP$IB zFEy%TeWVxRw#j^p*yyU=6dco|0|}GvI;_RNZ-OJNZe3WOQW=Ys{#+2g%gx4-rB{J% zxySc-nKmqe@>OhhQ4W6^_swQ9we>RMH z3yNQ+_-hfps$d|#0u|+S)_+)to334PCO1?EqPN18`K^?7=EvE? z=&zN|n~KF(LL1*Bg-6pr8R^gQ?V` zgwD($IfIWSP)3`-)4VZWr8D_VGGVEM+lKWaUegEke$z&DsNg7DnnT;3g)c@EJH@^cD~Q92oEj;0pilpA`fKiDs8uBocePR{ z4(If@uKL7Z{_YoIFjXoQP!)&Ur7RNK?N5zN&E5rk$BaLa)RFx1hh1b}_tXf%J)%6| z{XxS=`q2XFQWl)?_87 zodf2lr9ZCvF~X|%DPW=Z7Q@6KR&>=uPdUA$iWtU|!?yc$)UDg^4o!%E;rLmmh5ukh zq=LKOY2)@XQa|olw76#T!T2^>sHQH z_6rsGPzd~Anb-l|^)Yn$Fgn@II_OlozEZ;n%7Cp1_FGV@vv<3Ztv%av-2Q5i7?ZrGso~1wwf2LJNNb{8k5$w8vl8qslB>>2%|8=sE)BqM8a_&*q z2Chua1Cq~5!m*GKtQ+E z)K#x@8+Fv6J3fpgRX!9TVvd88S3VOz9Y)GnT*1-2h-*l~Mku|2^E~l!BSdFf=GN;} zh23}6I?9FVR^N0GWJ`!Qd;W@7cS%9pD^*n$3@1*{V;wY6XT-hZ+)2NRblLCvwI(EK zm5cg{Woz#?0C`5k{qRb!M3)JnMUPIqD&_%W-a#vK{(^QKvG5M+{@&;6Oy%?op17xc zH3i%igs?`x!rSv7XkKzg&H#dwm>VjL+8>!N>Hc!P3z^TSUy#6*<=Lq3V5{gZu@MC} zj=_JGolkGfaz05@Sf!Qg^y=brr9}PsoHTSH!D+Z`f>x)MBh(%fVHzfwY-J-|ZV&4T z$5T~`M>raiQYRYz%x>yr$JEct?+hG#7X`?m|Jm9H)-Wn~9jHIVeU^f2$l>j?N0k5VL;LS(6$I&TL&wBciguBGKX2~mew6>X z0`TwEGhFOqbfvXi)|*{T!=pm@h5qgXu7m1nlWd;MF?$#1olLc>xIKA2^73Y`LOm-% z#IE)hQZMq0`ded4w*{0tKiAQfbVjbtve%&zIEQsp8S>V;_$`Ms)OF5>BR@u?3NkZ~ zb2a^PjQY;Cp6e)G*}?={YjfqWEux%GC4Zi;HSQw!mQb2&PZCvjFv5f3;6cW-gp$)N z=@nQO{UaqcF3nsmm(4Y+>hQsQ!pyMuP65fltyv#f=UO-_K0WEh@Fd-$v4~a16wAC( z;U7+aq2^c5V|s|5u&cjyx}_Y|lRoEoM9nK9eN?6N1Ig+PYserEVlKu4f1YW@^889X zFp`wE>OCXoVI&^nSfw(`=zla_Q$_ak&Ld)fG38ECEWaJc8qz{gXDxC+LlfJp^Xox3 zGoOGf*);`_$16ndOtq(#zCrT2qd8A`4VgFJ9;)WOC3KZP3;$wd&$EQ;qL+|DM*r8o zI(ed6=+x`7gKw!_tFBYObhgjn_0R1vbIbo3iCdROqR#?KjrcSv`|Ll9h#4F6!Xoek z%xdglpE#9wb|U@~`6xXhVHGobN;M>D^`d&}iGn{<*5$}3o3^L!6ns|GS$B#$BhaF} z1eI4Yg%&9?yO?x9m1;E2Jg{W3wF1oLhMp@J>;tcjW(!rCUwh=;>&=9G7!EN;xg{^^ zWMS%U`>eEy=VAL>f@F6?=r~u3vFMKAaCS#S$xuJt^v~f2mLdk-{+UDy#nLZ3Vd9eq z=bsn|1?ivIB&FxS#w|DV<26Vmym~FV0ZiTVEUBrB3NK{{{Zo@L6Y)2;WLs&v6isA! zk{>njbhC{T+R1a~?6upelWPg)Nmz6g;}Z}af7`;c<-b`l9@W0=Y)lx~vsWzJv+uC( z|I3_EUKxq!wa1;JY)8@-kF|O)MpQCeCZobB;~lOd!a>~=OdoSsBSQ<3>Gd4WD(L4e zE(Xr*3YQ^4^leVxRae2H;#cjOk#znqehv4@&MIv$hj1=pWkfbmO$4x>a|(``Pk%cIi1h(prN$6VGgLF$XV$?AK;=N?B_^j!n3tQvX+tY})V4*Yf0T^8dUC`^-S z1;h@U!9mf##-(a~$?*k=*%Ws%+)|8MZK$%I^imr_`L5UVm0M3l8_iT)Ez!%0O6?m>D_Hcl2uee+(ROl3s`Kde$1)ERgLj(E z2=>M9BiWx8igkbq;SB=i=9y0KQ2kKtZj1r^PS3-D-+QwbGBYN`XRk3c~uw=Zd3g@PH7iw&X=s)G`Veb1?;7b5+T9n2cz$XzSCR94^z6Hv+S2K9N%&# zMNltg@cHpC6GhQC%5(gC(jsBJMJ8&8kc#&{gG%4^HiTfC5=1RR3=vX6z8?sw6-C2> zoMPWY$;+m5{-R;D9|)k^UdI2HMy*of38`hFyy{^S0oMY(5ZT*VA@1|JZ`a!K)}S!Q z=dSS{)q(@OIfq3lzN%qiC;t7Kk45PljQcj)J;gd}?@@D>(T^qj=tSswY?c@E1yXZr ze%$;kVko5AWyExFmy(h|Q2Iu@_cevEpfpm1<2)}k5BNwbX!c)1W zG>v#y$17MVEt+Wg>l4{XPRSTs_)X0}!x<%wv2hc4d7kzRDp9(~W3TfD2I!6wmBJyO ziYqr%dv{Q|GVMwpG=-i znHO?QPq&(*II4fC#w>b6ETiZ`d!uz#^b1FkbJL>TlVRle>tSTtthnCCbJqFm*>S-( zoC7POx$P{on;s+wyc?g)Q|iabH+@YGktq%3B5A3e4p11Q1 zW9U{#)?Os!qn=M`pvjZe(ea~ERJes#1O^2yq+UtzRWmiThP?`n;#{k-R&Mk8iwS?%b;s6^p@P5%1I44h?yZ?o#jd4MBR+x* zCQYs^_teq)2@N}3=T{xM_(N!{jRcjc1?6S$>rqi{t|DHwh*)!)_Ynw|TKtqHp`%G! zLTCyw3MLx-?4*u7R>^ajdk?cVH+%`6`WoWX6etFe>G%NI_CG(LckYi!2o`ha_7BA4 zGvKLip>a`zjblt^VG(&w6Oj!EnGJ_hb>ZQFMyZKI0L4C?eSf1PG*ewk(S`LAxlx z$R}jx2OQ1?O#NK*eE4cL);aq*kUv8;evXcA?pPApV8YLPKrTiuc#m)~b@ zs{uR`byC%H3C`8t+PGovN0~#v;+2?^8Q*0r$Q-^JjqX=~n588-V+CHnGceVE78fLX zMPBV5*LG_dDf>zX-#qzlBeP21QXP2?6Se=lDPJfhR?AMs+3;ap%38ObN?6N{C8i$S zUGppW*T<_Z|8zsucEp_VmQNwl*=kokF=Ea`S2BeYqaS)>?o^CUk{(x{{9rhE_SEtZ z?W4xX-#*adYfjEyRaVL?-HkG}s;-_}DfMh&pGH`?n}jKKHoYP5(dqiZ-!)Sf8w6Jx zm~N_BjQd0O#Hk!H*IbDN?jc{anG;d#oss`Fhr&DRM8crEY3IE2+(zl9Padd9z89#z z+nQQJ_|5p{h|-^X_2!vfB?xP!OU|Ns?e_6#?Sd|Yic1vtaLrSMR*%{+IRPiW|7J@g zg^bJ|n@*l?PPJo^-7Ek}!}rzal| zR=(pl8h0`3FjZF#_|LB;0t?Ci_Quyh>Vp9LM8QkR-WJVj?<>iF$J#-&)LC-@>?)P7 z^uMGZ`PH>3z$Zed-{NmUYhLtlvK1{&Epf7dqQ`yip^!Fp=&zkv+rE;UF7xFK^@}g} zVY8BG3^1M??Hs_%8KpT*GOJa4?ILoDpT@frj;d!kEi@iqKW{5^4fM>r@>*1diisdWMsz|Vz}dV3zA<~e`1pH z-YH6B975C9wjgb7nMUy8Pl2tNq66x%E}pl^9mP&lh>g@^rDX|&HB&Sb*6aBp7hX|S zjb;yXiobM?h=#=#tg2Why{pLS)lC@nvZo$W?tF$kT`DggSRIjx{PYGSMUb$oX2;Uxo*bQB>l%34)QCXxq-F8Jui z=jW0hlbGY<&9eIKWoBwSo%Gdw7liy@^am%9YW;pC;uuAjs#pJ9GSMF_)DF4h-@gKn z&~=K~V=kyViVx?0$XW3EzO5xZik8U@NU4`S5jf=3*!ltl=R;FU>gJKvZLa@(z(Tx> zrV`%JFR0gb@E(V?quMH0Rq@JYmgKV8%opSKm>zCjk3chNMay_iTNK?q!PGUN(#j*P z^-jFdzUE+{C?6a*2;OxXZIU>rwmJ8}`&LgYIk*59UgfR%x`Ps>NneBu1xiHj^teCk zQ?nC2LE@3j3KWabpCF~m$XX<2WXsHh`G~*B8fGIr&-@13922ez(rS-Z77k?k`NluC zol=9t?XaaJA?Lf8JjGwImdy6`nRxaEU4*Bku<-Gf7Wyk+Rk2!$+@NTFi{|Drs&#ub z`YbV%r#gQ!+>_%1%#zfTMd30jYw_h^{h4hKJ;~kHZQc%42z~~mnof5FQda*(O(MfJemWklgs;QSfmJmgFBtMgGmgF% zb_PG!n_?Ah(>+bVC*Ll?3Dfy+!zcS1!fE@b5IFdF|K>65r;nF5yr{nY5MCH^gg zPTEt!GdYT7OY6vLSw%`jU!8JGE+KVi9Vh1}!TcmVI=?SitAuF=o4`yqtAzMJA+xm8 zKJT34L|>Qw>?3l%R=MQ5vJosOg&`s+s_zt~;^Hi6Abf*bQup5gh5Jc(d6-57?Qj5G2Qod=zw4|S^UEYH6s=brW zUU}{*bsjfi11*BL!#RXJZ+lzz)pL;w>FrdLiR1aN|t1dwfvU zWi3f$CQ64NaQt<+;!Tu%63i;%EL!>4&FhAc)fL0Et@Ce<+#icTGz~8}RfdfyfNP`0 zP2JLQ;fuWQLX83Ahl($MmXpDEDceP2A&!KbU`-j@t7+!`O`!=M>mBo;N zd(>HIgMO4N6NpRRq~j!i=_IV`yMPM6IjSZZSRCc-rEf6|mp*(HkOvV9)SKt}I80?- zyL^y1PGnJDETk|0ogX4uHhP(0Sx8>utrj$>a7Tn7?=8W6*BEc|v?MQ8RL=-E6n?q5 zHGmUPwE0DvrsQ4nj?3&*(|QtfWf34sC*xYTe*EJ1n))vGUCV zMRxM&G}x*c%qyLHq-CCa1X!+9y_^5}oLLcQP|(HUM0`A&VS4?Q=z7=x5eU|Akyu%nthI?C-&I zsm)WPvrOeybi7C#GYCvf0tdf4J5S6qsIoqLJdwLxA>G4m`7&4T%FLR7QTzRFIU@Pv z(#x-u)-b);v>5%NqU5ag$d;S_hVHiR7=4tR&K&p>+&x5TvT~y&Yk)|>X7lI33SV(K zt8TzS5D#nPqGQm}`H@?!cSv#1q-GeioXO#IK#e57!R{&hQ;FW~{;y)zxbkaFUt0|t zgyxo4H)&UniV3^6`tv4(af;S7Pwe5<3^}@^=#PiA+-s9QM~7Lo>HmZ?%yeYs0(^Wz z;%GdWDg#pIuj6_3h`$u~sGO>-jFh9kKj&VFzvuS#do-PWASyR>vS+2KZN;rIz27ai zx6*{%_e_zYpXvMeKh}>zM>d3S2jLVyk7jU9z3!Y$eq!H{Mq%S2oAs~xVrZ=apuPuQ zoOiAnzv(^i_X9}mw=~wZ3($A~j?ahOak6LU3ArBu%Ou))V=`_M6Ont?e9abEyqh!q zh>ARbhx#VxoNpjXW zko8F+Y)d%oQh&?^D)c^G@SaoX(c(foZgt;=@+%`DE7g_Vl}Uxkgsi5|9{=FOJ=~-? zytfYztoTUhC~>N}!wo+=^M(F?C*JU{xCL{^niyC?MIP~Nx=2#8<%NQs$!^kGV|Js)}Dbc3~Fk|RZzrx2-zk=JMx)vXk zt^|&+V7GL`(R_^3Pd~b!{du7(pZW4j9@-}G;N#l!TZmW@+VK`Yrp3k)%leV)@loN| zIPv5aKlV1N1m-Tj61@H5?6WixYslllC|tp0^xG7MvQ(xn+bo|OUmx7~k!fnlNpkkb z>;Bt=zb+$g_H@sqRLo~5%Pjg98f8&uCWf!8-Z?Q{PyCX%_6tiVE_iFa=vGfU;>G2? zUC#!Edi+hx;cTy;Hj1N-N`V|qd{xxl!R7gV>(_k5HW@`W4`lG1NR1r@me$>To9)R(X%M2_}zE?fgDlU{5#h76!}#90w>Le4;p_4<(4_v zk#umIz5;WBPJ=7GZ3#Ju8Ei&Boxqc}wdu9N#ed6r>gBE@jKZw2x4 zyY!mtNWs-B2Csy)cf#0n7%*f9SH*vDJ>n!XOnhvtJh>u3bz9dkr!Rc^md)S+)3UU9 z=?ed~TVY{0i5Fb=z%$tw4^6^c)=?Vt%EN$D`2aL)0!&}UzY~K%yJs9iERv-^@7p{a zwo6K*exy7zE^Y*-G3toOge-&53J-DgrYYF~Rrt4)v7cXw2OY_vP+JQF zTS*xnF}bH_<;3xC&#W81{V)rtxtO_L7+rf&C(vxK-1&ELVd-ZRo{kg2>E)U}%H&`s zC3W@T&B25eHZ{!fU$1a)Pr*aI=W8)cf)PjS{H0uV7A;erE=Ccrcr=siXk~ljuN@ix zAZMke`=`G}m07`Ff23vLWl0m!+Aw`?A2kx5YOCk9&Ptih#%z8iTZOADqK8Z0@m$7R zq-qeUpx&u|B@fpl^powFDU?8i6yH_A+pJeH$$na%?PlkV4-7XOH&_!nI2h7)>|-UE zl)2_UsxP!>wt1dL4)U(8{5cikXkEFr`7+NtqillvU2KjSk6_Oj$(NqH#8ZqsoBL7{ zhDmwpT&nVW-ggj!DdDKsQaFBzW3lv61$j|&3MDJCpzYw{=&qQsee-u4nvKv@G(t zwAR8k`~G{;EQwjOllO)y?6y4&m4ZE^=whU(QpT?v(WMIsm?=0!I|yh*8k2EItdzF$ zaKAh4#9t}s5$Q*?nkqCMM+l@acYH4_Uydo$G9%zn{t|CwbF|L=HprLoJ)4aLlZrE) z8(x};@-==An<`7JXWgj~&um0tf{$age1I=S-;~)om?lt}!GUlfE|Gfyd;rQ67-hE$ zA1T0UZ_Ks5wxva)?zl6UxR0HqH)Dw}FLcD`z-WkN9iVP{Idbs{c~vB*V4E!gRb0?H zT3_|)mY}ZNF=)iyHMoguULEx@0mzG-G}I9omnTZ_`db9ssuhFoR#W2-w{P){=s3|u zo->6ct}tFDu~P?GV=8uW9!@jh!Hd+GMNZ5%UYeq@xe8 z#=P$-A&Cucd}!nmL8r+%J2@nRSNu&_xI!M{9FQ{$oqI+EUH5}paBvHTicfo>QKs7! z9}=F3RR7+3Jvm$%<@NyD-H3A_hFtEkL+;(bUgN1$3S7Pf&23i?&&TDIkjQHVhapHM zU=!lJM+9ZR#}6x#eGGA`#%LvRDqVWIW0tGEPw%~vg+6UUVOy6zap|}eWUSM01A?r4 zpk%3}mC?$lkct*L6z%5RD`$gS@7oAngdpG3^|pmkfyrHSc4+Fbu>XC{ma!IUUsQ4u z${PhUQfKI8{WxNnihB(PvtVc(FrJwi=9eZGNYjHkj@Pf@W*aTnvSoooFtMPb+;7Xm z5{nL@n9gouBUbtwN}D)*eudVDGe~WGQ(JO&|<@~dRLXAJni@+ zz)!P~cgEO7aSqZ%YN;#lrnuRWt26^p1Zraw5 zVV%csJ7wM@ZO*cWqG9AAXc&Y67i{zpOkVZ^D{Px7v!ZYU8tXf4&e5(XAo}Vanl;Q@ zX7Z_0ESTBl-dPh!>;$j5?=T8g{Q_4l=HTXBS{R8huvu1AJHME^i>~-EuN#gmKW#SX z1g;Gc3DQbXZ0n|#r=+29k%X!rLgk1?o~_d3TAW2CuMshj6D;+%W!IEv*BD`mrDgF; zTdY;oO}SSuXcs_{!Rs25K)b|piV`|bgxU-VDqaF90aLw@Q!wtM=N4kE@Hy`$qD8`$ zpoN`$cS6KpiCPtdk&!^09(KIq2}>&~%2=R*q8>3aa;YLOZTo-owB|kpD(@tZe;`d+ zGLdz+pb3h99_mvO52>^uBH7oFN_&=DSo;r|A9Wg{2P7Ls({-F?TF@{j#9IqdR>I=6>t4&1TCQshaBryw@ARE+|PieXR^Zy+% z3UdO6aNs!({XIV~L%VSnMrVPK(t!XOa{`ujVbr}7ATSTA-X)q{p!JS$=@;!v3$BnOSsutIg*@kPqYZSr*><`+@RCrE`7@!<(XaK8vwYVH9Rj8zLh z0J7{sBB*FKPWRtA7_XCwB0Y0?<}RvfCAA*Sq#e~|gue|+A5t6uS8Nrb`ImCt3vs;n z+h~NMJ2(jZuFfvBmj2-j{IPg-!wOKz`r+qQ!^q7qGPlF{>p}Wux`FzN$4O}Oj@??` z3y1nS3Ce!LC+<+%Yr52LN1(y^!Xs+Y{@ZpldllXTnN^nC5dg{W0Sy4iI0yBEuDs6N)i6mqlr8gU6?Av*ay45F6azO$~yoSR3 zCNd*%;z|{`p|zD3{-;lF#QbU)8e);JQ@-gXg2&k@9Fb-Ez6SX0ve81)##5|T{g;Ox z`f~QE`$}$fNgXf|3V`wqp&lH#gMcV8RuKImM!oLY%sx*^9=N;k%lRV7sRA1YQL9Si zCSq-$z;}aQyS;u~?P)L_%dXTY{nIN+{w;3EnhWwIJdLgT-oWq0j0oG&(4IS#6du%q z0!G1@;ssdn1mFe0TmXe5FnxG=xy`1c`(_GIZQp)>ng3saK8}@3V3-6kmOxzcZaAIO zLM|S}bI?l;c~cQ<>NGsWdq5K9#tL=xAym{`4Gc;tAz?&V#C2V#&gx$+BayUU4?%|( z$z|lofdkaE`}aX}HKfvkN8^=0aq8$8$`adTq<(IT_K?+9*4o9 ze|mOoC4aU8lZDqG@NODrhX}u^DQGTQfML)E0mhEpGzmb2zh1ebD`D2kcJW zR?GP&%I2wiGIaMVkA|xs7{`Zs(iD9&V9dR381GKdkSOJts~b^Wg_g@F4!gx2^v;M~ z$|;Jla;U;7ztNASxxUK^RovR>7lpIk1{g1Z8N2{%FuD=O(DSOy!RR+%0Y;d(z(_Z4 zOd5-MTF-~6-5c!;Py4TWap1CgS3rc0L1)O8v)K$lWjn4O+XmR`xL#rYOar6o63l&# zE-=1v#~9XA^yBbn)c`}0I{!lbC!q48eL-u2V_%*#W`k9e!ZSG!fy|fn;h%4QuCm^*t#8IgnU}Ul2SGCO5 z?uo95Y8i$Y9BAOTIyj4S*Z`z-@5vyOQn1z9Soa!;#~$p!XiGl=m0sSXmymghC{&b* zctHJ59E$8cL>spAgh_mbRFb~nweJINC07FDmpN=~6*MaAufXJ+gtD=GP-Ayx?mG>% ze@LT3K33;;fRpyZgL?U2LQIePWcW^9=oeUaYJda7qU!1|UMyff0aT}etE~~BPQbw- zh&Hc1rqcBiJlKtkx-;ni6UNkj(}^>UOOvk!AKSCiE+?_E_C}h4?jW=A`*UD@Szb*c zrIi3fRq;IY_%Aq+hS6z{fQKJwj&u!&ZDUv)1Zmw$IhS}DSB9A)v3`=C?oCHdB za_f`yEOMuCd!q{tw>r4JOS-^*Xmz-zZ;q!;;D-pa_;$Gz@(GCdiP9Nq!AWEXC6jm$ zVq1T&f*4XfPV*d)r07SO$8CMFE_R()iRFE&7GHKfLdB05>Iwo$A;)Nv<024q*9?+a z&%ZxW50Yfh)`c$u+HokkG&k4FRqN31Yy0TBpLJjMZ(qOfOw2ivB=$$xnC&m*vS-X> zQhBrw0&{R^#jXFEpYRC8XO?MSj(mej@bMV*B&t1Pfs=0VqlqPysTM%PzuigDQFYo( zAMi*%^)`)0By_9@ z?TDMuewYG?ZIM7{9j{DNUVwrD#bS_grxcnGAcg2Z z8_jHi$2M47bxeSx%IL;vv#w_2Jr=sKcV3r|zZaS`(fkr!o|P1yal6vVg=sQYtP8C9 z9sfTRojwNPrZkzErl7gC=x`S-jpNYsb^ygP3y3SvfdRD%L+hOz4nC z*AVjTVSv{EEl=@Tw@enuu5PsbT>s;afE*}uw#s6`qPxll&;#}L-kvlX?*}W!4pYk& zKc}aAR=EBe}xBV`vLdc2yPI(?Gz+9yHgrvOC&?p>`|JSJ4;Xd9B$B z5I6!t6EmNQ{y(bTIxed2iyj^jkZx%mx*HTwWDx0)mhNr=15g;cySqaaX{3~q?iN7- zX%Oil9AKF9&h!1f@p=CmX1I6e?z7k4=bU}_S{JQd6Nm(DWxt5$03g461QT6#wdj)*h-wq0%3Qpfx$*%@55= zVGwnd6X9`ePVlj-lwyZ<*9)`GlD?J+B$}dfRfdk|<0u2jW;4hJ!(Q zh+f?l>>HK|?6wM1tqBG0X>*_@bh*;NEw#EI`Da<(;JOxNN71LujBtr4; zUGprm)9SxqaZIueEpomEoFBY;;nA`M)*$N!4WqvrRU(Ot?6Sb#TetY>?WX{K5|<~{ ziY=FJ4;*0Yo!ceXRupeqoBm}dU|@rDvo~m1Uo=S*t2#bh&61HF&=dU4?GFjRN-gTL2zpjL8A;6y_G znBC|rTrgpDQskc8X2P+?9x!~Pv$kS88j8h$Hsh#$Y0rH_9&5Aut(vZ>1uu#eoXf1&LxO*(VA%E`|KM}7{?ti9qo<)6UURz(Z}@1>lz}n0rN0(IrQ3^{!0(|`LTi%Is#-f z{~bNx+?*wOh}yDBN4)$8^@5|9MG%RIQBmWa zA6sDnxpma_>|F<95}?J8hv7gLdAT)ucvSRmgTm{#M^HKpezU*Ri5}${;W(7r);96; z3s9=Jc#pge)dhW zj({FT@cxH%RDN3Kgj#!G+_0vOxsl@kPGq<3xRW8FG=E3NsrskJ&v%NdRHItzi5isH zpT$Iy>xApeHT-;qKjGrC+nnykqh)M8bdh{S!#?j=YCc!gc~oq zajw4FGURJf)5U=fsMzVa^O?jl>`m`c*FNDk0{-hb;MJS!(XO}Qq1W7(SM~p(u$$b` za2E__`5IZxW0OL>JUOy0tTN#c=2yxNZ~B_e@a5Lg;pgsCR9GuwZ~1y~b$I3Gq@ep4 z6){@mc~}dRL!*+x=gX5luM2nYvl_3re-t>i+;N-l+)fKv`_c~Vx{i=>?O53po1?FA z)a6?5_VRhu0rSoAbtfzX1Yz!DRZ>=#FzHq{&nkJVug?NMANdW}9ZCIz24PO1wIumx zi|DUX2+YCY$3X;oZ!2#Rek}sd_TZS)?GE%~_ywjHv9mBlO!kd?YJn$qI=^awZof|MXPTdO9Z&rq!FhIf* z6h!V`p2Bv1ud{-U%PZLEAYyYA)7$Tvbh+#`Vz9T4K+jUppXhn^%$?7X>9uthpIuaHZ zCNMib3d&m?S;DbOKV4f}M+PjmXK61jEz=j;j=-oM#=+luzd5~B3FNI??NkY!8($oy zz-rxiVCH)V-@vbP0$$ymEN>LSua})>I3CL)SHQ(6oE&lNdFpwJs5`U-=w*8Htl<4oCRkd^{`?hM8kFHZm3@g97poS}~mnxZm4-qjJ1$L-PY&_d-|05XdE>o^rIoMOUP)NRAF>uB>xO>?2odiq&)F@%%bTs2A}Tvi-k1?^a#|Gy=A5<^n#|1%{m+Z%NDwzYE%fk?~6XL;U>>Bkn|R%y%}N z6DM||r1JK(=P}CAx?+sDH2ilV4u}y&7&KZPv-bv$U2Th#PAT6ct$hPzM3WdVEb?8iyuRKZ<@HF< zveKP=sw+aQv|j4hWLy5!-yj&rp%Put`SO1_q_?4dRelMe zUH_x|W+B&_MebNWA2;;R;YL?+@Z**AxXkCk?q8RerVdRo*PmB#he!tD5nc3O8?%dh zv2W{nEx%v|dS*W!WLZ8I*7~wH`&k`{`ldw`YLql*ILTpWB>TKI>B}YR;^5<_NR_(! zXtsA(nTvdm2c z9lJ|g%((WPTf6r7v-#^$(%xoD9`ae!1~Rt!z`3EwZ!#|Vnz01D`08>y2s{aXXY&Wy zUe}L$(LYpUi380_V?bMvFftvZu9v2 zxiJs>$!n;_OGpj`wZcpu>M*_xn0ZNsnMr9Fr;UG2ecyEI|5XwSR-3z$T(e_B(#R^_ zC;v;~VZZxFprXV=o%xmPZ^6eTn>bT$S)wYL6J(kkwfEoT@}yVzrlfu(|2;l)!+t)x z`ld5O(%O4E?uVVHvozz^-i_%;tPaqCsMSxEyWabL?!0#V2+*c8A;x-O`*4MG>JRbh zQ)+0$+Xk9{BTgejcz1dK812Z~6SA++9-iX?6MLNU7%)_Vk@$brK0?bmqYQ&4^ay%s zPR(I+Jlo~fhFhJc&mX8{Xcx5eY&WgKQm?+2B^C*|{>6DyXz;RKy+S`%fSBhg`k_(0 zn#WzV3eCq1q8Xb>^#?5D>Uv4r?`9vUUvKgs(6p+=n=%k}VYRT3Ec!nCcfU!NGTQD& z<(|}x%lMP~Ke>%53-fU63YylZA=(&PE8Sf0$kq%h$jN$D`f9akUG=uYPF=h%Pn z;W=2sjWuqO8$xrN6kpkTUgFw3R#W-*`lW_Rx+eu)1BaE6$C8q45YsKSQR7!3-L^T| zQOXA?H5zN_%5jU7>KCt?d2?Uhf$$=vLQ={pAnV;Pgj>u%Wk>4#J`NE2wECAc!h)G+ zxRcRY_BN*JamBzoEL9+4dm!f3%tE>PLQYvK0TV&+SgL?7MLgR_xAVx9-ihzB+%ty9 zP)%J{a9ntk=1duR0{uYG+CaCkloCr(G56EDQiJu^|=`m;um`mPyH$i*?#JPy!MVA)|e|1n3fWI=g4y~*7a zf`fxr6%9MvXH$Pnrr(7r#oogtg|?13Wk&(KxPuHRc`pU?(d;^)yfZL)Xz6bpgJowq zW?!5BFkS=iO>Y4)ccImeW9a!Rti6TIGBbQajN3?%_nQJ5%KH=q$m-`!{#XUP`o{-C z1f!q!jEO0^NIui7khW11gtyBD4?Si`uGnSJaZXwMPP5d`=Y!ws%gS;2IiJIDutKz$ z<=3y$&ucMH&RHuimbB&==1U>?z2#UrhfwJh+%w4;`rhDhG=mO#cMh+-jTkW{(|ta9 zP9ItV+B6ZBu+YQ`2p93A*=z-z*gb1`NW6WZ>%&aY#W`9%tmSKzd;PJz|~gXE==k_RN=`EyetK3p$kDe4XC>oMcl~(fhqQ>3*H3kV z2TEZwY_8R(Z}{Zb7E2(HyWv09K=M5#w(+c? z*|A{eTeo+AS;x9T17AGRylwlP@DKf2Q)#Ax^nI!}UJbIJ`a$NPBIi-A)=r69AO0n*`p)E!CNLKUhU8`J|5AMlCP$Jms$tgb)jKz# zmKxVWq5}#!`)r_|^v%aL!a~>^hBP;u>A`8vi&VJiIL%x=<#F0uW{*_3WFhTkRO%t` z^K_O30UTH~JKGtlW&G0!G>vvB+RknW)}EDn3q=%%1H;d+;=WV~yNi$JJkz4}Es~%^ zv5i8%s9<8;QsB11LtlS+-9b`t*W7|7(eyH14o;<&3spOn4|Q=`NJjhLLsAGTW2S#R zZ!cuJyv^X_`g@U|LLdc>EGdk&w5B*K>zzu%ohvEI6jVI+=HzU+eKoxq5fr`61~h|% zf^9oDRmbmtP%MxxhO$Hkz1R6*KBXNi`P`g0%7=gWP~cjHqoxm&;w;!+Bpn`Pn>xH- z6j@_)HpHY(&(i$46tZqcCCGSpduaA^va%D=V!4)1nzn%UP7>iG%?Aw-w+1+GD5ddDO@o$WpI1&(t5t&5Tq!pf%f#CC+1)-Q_DQ)dKDeC193P~wGI$<2_|j(>9$ zm@-8}WlsO=J#IRI6PAdg1OC4Ia15{C0yK7Z)k{NLpcl(IVG{u=jx%;@aVK!nJPhoK z_88!KAxj2|*u~@nN#b<*F|ZkV2}5Ra6GFLIyk>e^+Nc zQc(I!6HLP#8O%fwUR~k-C)Z!JeF4VjUved_k^3V8Z#7mcPx2>hw|Sa0t{38An=9g|U4{Guuy66^qXAH<}z(}ruVyPu2$uZWm^+kcK?RB*h!k;ef>hJq4th`N@MqMdyh_)sa_NvR- z3{f!C#q!YnVN>@97sCw7S!ZVPo|s7%@kpGvi#>FJ$H;^nqy2GHb?JgxaCP#S=}s2e zYbfC9Z$K9@aN;d*08aDKo7-G>Vp{GUN4;pYeIBMsQByd?&6#zb^fraquW)D^tN)-g zd$W^HXGx+h(Vu;B`Vu?;a_Ep!UZY^5GU+Y^CsK4TN?@GZbnvqFzLm;i7@ja)vP&91 zZIV4s3_W1xpt$jI2YFVn$bFTk+b(ic9%Hd65Gvi^HlT)}Ac4Rl^b_*}mYV zvzV%#f^X|X6xs^A$>oIl=p zdTbC~_YnC%)FB$=6N`mN`5A69uudHw8re4i&gl+gAizlIh^)CVk3 zfBfsx!9s-+#N?3?si~N8Lp}h6xItW+f>tJKe>n~5> z`7_Z$BtOLt>7Q8Fh3H_Zq1gj8!MyY*%{zc&jNoRHdy5U=zp15Ef2rm?@@rk z00k=v0hDH=8xogoQ^HoO=<^_#nn_drp0?r&-zS2WZ>h76O$C=k*0sh>Dc ziw~>aq%5g%yauCuj7pldV^?XKSWl;}Jcch_c~RvBJ-;^>D=BDxkCVr6N1Zfj3qr;H zi|v`Ss<#kD@l0;+nRjra=#{%FiBc6Nufs2Q_>=pPEX8eJ;elEA9+=MRPyLbEn2ibN zhD{gCxLb;xF>e)q63zq^w#cD)Vy|T6Bc&-4+gWZ$f6u)qpPzUN;U{U7qbQ~w@C_z@ z>XLOU+|3_Cq+BLPu2XMAp8S0cx>v7MIlqa_6phMp#QAjT|CQ@ysD0*}*8HdX;sQM` z-oeRQ)?TgV^GFE4?MM{6Nqg?Sbr$+KXlMt%j;nRfm>f!FsEP6Y^heS{M`{Tc80RF9 zFIKR}c-~ZKQe^yFN@bK(b@~3=PU|akOwwyeY5MEwBJ}gf3m>q7_LHP zBe6{1Rl#Tqe0F7RlLWfqPqD=3=BT9f7M5LKO`?(>tQO~ulslH#n^VW2M=@QL|4ZSAckZB(ZFP&! z-=B;ynRcu>SNi0HPoGP~=a=5tbNYet z*#6)eMYkz0gDy_^nD2-${?HUA6EaE_zJmuRTUP8o0vOvW;oG^df7Q(sV z+q?o9`o;bt6{`Tn5JmwZ7XJa^P39kXe2djM4y0*@VI|!p$AE6~L%^dmYQm1PZwd{_ z=lb>~Zi{bhL$DjW_-GR|*(BEpnuiGeu>p!ssn0CF$>8Sk9RK>VUzDj~_P56+MUpY@Ucd15 z?fFK)W}x;se#7U7NGZvoJ%F@-*!|QSPyeq(I!c9kICK;0?v76v*0!MoeOcSVpTq-< zJrNf}uoGrI_@i&|=SUC}h5o7wn!k-161|R+{?T1TYubOi zgEBzjY(GN-*$5Av=*Fx?xc84*`nywcpOw4+x>vyE(~20x3MnnX4pcan!jq72NVZ_;9yj6RCQt2DxqAzP9V;;-V~a|KA+(QbqW zcw!ubu`70F!nQ+Nr@8G$Du+{JXH;pdPH&xV9;wkX$1bc{CpWSEnd=BsC5?n@8hS8> z0fOz&{Idb3HcbP_Zx#PZgNFqNolB|8Qk+C(;snRGYmXw>cx0v8L1C|Zhjpc{{&cumn<`;ms4=2b@PrJ23FDyY(5x0-TZj^b4q_l<^0E`Y#fUQ z3oP0D8t7<%glC#Yga^Rs$f9%h!LP{an-98ZBdJ8U_&c7Qd(QCY$ltD$4S8b1i8uw9dcHJoZ`Ciq2x zx%eZ)fZPAseSrz%2KUI0=)(N9o)g$Rnc)b!q11?!;YGc^!W=6QRek;)lyI*H$dM$M zs_RfaS|Y91iU2wZyjo;H*V%9jUeCXYZMPJr#`HQ*OKWv!mPro^kN`GGsb~7XYo*6o zwQXh5Dqe!@2oNm!cCQz{$+86xH;=_vtq52V=0Qj4<}zdK6j;6NaZ2$|iE|p$ zd?SIg{gTM~7915RD4!dArm1Lp36*?=j@qkH z8=QG}@j15lRJ7vkc! zm~)jz+aJ(pJLHg=7efl^QjDJHs}jQk6Vt5MJ~jcaWeV4`&c)sn1mc^0SVGzW%< z!GQCYROv*2mpn3rvMDeHV80>|u7@y;UVg#{Sb!mvl zJGBsxj{>s;&Yn3BMm$X*$!eaBjiTfJxWNo_OcewWm!QQ_;QWa=4<2nv97!lfFn=4lL^??KVvbn^fONcgi*2g8MtVWR1P+sBKU-TkcjCo zw$Dp-#>Ci_#KY(lWF8oP&ZOaKkjG1|cG6|V<*gGJ)YPJjhTy(~N#L+x%QGrWr~Z=< zjBY(WSo+(@Tz!NzRwovR)zC`Z9=rESVc zL{`hy{~m8}mDpDYhhNS;xXs;!tPzr2oLt&Gg?F`z+;D8AS|KTCzZz!gSQSXjg0q+G ziQ8-|;B7taRPu^3c|U_=GcesulX2xZ8XT4DRPyQ=Gk5uto54M}tJIgr@Ky3iOuzxG zen<1!FL)bk#f{V5qU+#8Ie(SH4kkVpLGS7j%i<}U zB_aICe927DZx0>_P-Gr|c;mN89$)%&pY7}IP_gyfq)>-hVZQV90_0iwc56r8%sbCOWRqU*E=L@7-d>{p|6r z!wPzMeWT3*g1<&P;gjF;LkJY}zl}5q*3`Nf{BmGP!f<@JW8?Ks;$e{u;==D&2-C$% z;bj&c$Ks`s|H9PAk_Q0@)1`TvYrI;NWf{qfTLO;Fg$h2kVl*S)3v6C2UgM&j$`&Qv z;=4Q&<{zE4ck7P5I{Zap4to9(Y_zJp^@%w`4rKR}Z|&yXet(Zc5U=+mf3>tgvji8D*?lGs(%#$IV*FKa z%4x5wwh(-;U;1|h%U)_Xs$CX|TaJJV@Glk#j45)P*}YO7H-U`|xa@Y!7cWNKXn2}?>S9%r=IW08I<}6#$TpftpsP*7q+6MO5{^$ zwh+6Ov7@-@IpIjYpIqX|IJ?Tm(>VPCv!yN_`L4cZ^Sfic@uazBX7gk*-nWD{)K1K5neT2ShrNB4=*{pcQJSisq=j)6e7ObY3Y3NNs!hK1hQDVzR61*J#D;*uhyUu$bBUP5m#UrhP(U(C&`L=&1a0;*kT}#Q_ zf`%=73FVI?fOy@?vqCa$9ubThbP}Z_jZv5bFI<111%FbY?$Bzx3*x0Qr`~8<1_{r8 ze<{t;RLm)8cCn!#!qy;Gr?t72!*{(~>R>vTsz8T|RiHDl98z#KxlSO4E7Gji43df~ zrF*KPdee0@9ZX%Hh(Bs!Rgiw9qbHv6CN~a$^*!$N{)^9wYu`id8FS;$d@_GlG2*?m zAeo)ZQe~eGsh47ECoNq^ku_GW9@MT@B_@bwhqY&B*&-UKuw@ zjedRE)ga`76PW#0S@jdkG==pyYBwdzqA&0dgjkpp zhmQBVJ*T|xcWZ@BAD_`WtjeIv7+QGao8dLuhs0y>_M2BCgEbq22ZW1Sid= zthD<9i$#fVBFGj1L*ZwTaSqkE^m0HJ4d*V)vI%=~x&`ye+k{cJac&b`Lw_fuqw1&Pi<{FO1fOEc{E^VnQ6NB4;Mix7B3YeJ zrgXX zsJZ38h|v_|m6pt+$R94^sWv`7x9P?o{V4pL_b@z8fm?n!E;d*}WDqZ!UKD2?`<~A? zu}QVTzbYHz9eInFKi7iVzT96)o>Mw0L+ZW*QC~j$YB^d(iW*1>ffI3{!3RF^Vzk+n zL~}K0oX{|DOSF}xj#`STAHIc{qOK9CwKCr?^F9Ny%cP;Djv3Vz{_7(7)b;S2B=-@F zlWd%hE81$nWjo$+9^Ne&r8ZESjUF^)yDkzI1l3#45`E~Z9BUer7Q7SfHS}pd4d!-@ zeTpwx@qMpXE|u{Y8JvQ_eov{3!`rRdwqpU!{ZQX`@>CNag+KYT5!FLR-35c&-s7oe zrtHoSta^;#s=8ghHi6)ma_W9I7)db9`myVv(X!4+C!g4~1uOB{gt3v}H|dpNlY=VV zD;y;snYoH#+_{PzUOfw@GV@oF!q&K);!iOepBS<0CFk$7r@4@fVOd%Vi2c<7az&^C zWL#RQUwYj~LLaEzR{L-x!eOVpdX&ip_zJQ>1?9c%_mF#z_haG)08vLi3Sl@0!YfAW zfSOkZIx2xEhkGAxtA7DwBT5dXy__sB&v})5%W5-zcC32j)KQod=<4xeDDEVJvX?R! zu&xob2;L3>g!&~1jt=e#C7!lQy-IrutuTvG@25Zm6JG)eOU8yth2IchEc z_Iw?WS`zNyX{C|ThS068vwek^zOEA6A|g@uN9xS*Hn#B#opopNaa*c~ctr+diGmjx z0(Qu76klZ9jgWmf`N9^Q;OPYUNPg>=W`if<;LW24!#vk-9o4l)>lLI(hn*Qg-lq{eI+jse~NYv(~Nmf$A6d68=$-grfrsPaDks-EG@# znVh(t2q)K;x*Ip-3U<*|zO?zS6ceo(7+Ff0+dCdmWoL78o3m*S?ass%>3_Ms8g&Tx zVf*7jw-!jG>T7cb_sC~xdQ%DTMF(hA1roc ziuk+jzUb}xLBoK*P+2JRlogLep{*z94x0)OpIrf=h6#r)i(C5lVJ+=?Q*JIltq&-d z9DC)lhsm3{12WW|YOIERo~^Qe4I2Lh%gYMRfR190a<0kINzgjCKb+41r z$#`GcMlSHp_ZIIzT5|iXc~Ad|%fUVwxW;)y4MvUQ#F(NpyBm39Ud7%ghS2zBZmM7P zUK#dL|BPX^hTy5Wh+FdFY06T~I$4S1n!&&j0kFdbgWG#M(5660e4rPHQ);qcaX2wS}O`)`#FrMV)g&AkXcA|;c)dj zwbVi9{;AB*SdU|KJgsH*0B-55>a+NhPUT5FdLo1Sl}-wEQH40UhVkOF4LWZU3)NN$ zUywi6$NQK^CE4x9nN-a7$(M);LG;8fhgPdzGuBaXN;aufEx<08yJdQ5OII=y$;YHs z=B#KP@q$}v7U0HKs)v4-45f1wl#(By&EzLLmxwuHVhrPxNWT!)L%vED<7#J*b=F6i zPrcG>I7ZnECaRWMh+28t4{6Rgpr4zNZ;jCP`DtxU3F-ToZ?KHuC%o@#a?Vm8vkCQK z%asxR>JcdS_FZea1mmZJzy&8s1JAYY60+v6F_D#Mq~{ zVxr6#dv;v4`5YT1hhDh#ERNf@oiYXfW?RVh z5JycWC4ON3rQ99_Jf&~UN2Wu7{4mS92UAg9*b&MCCEB*vqr@#SgkPUHlei%%+VWwK-kUTUNtPU-;RIF}3i z9HTC=@q5kG0rfyzwVA_6Ax-uP>~f4Qvi#Y<>LTkWMx6QH)$$*v;$7{0Dc?M4a;6r; zF`bwbOl9`>;-tC|9B1dZCFO|Yr^6rC5sc04@sCw{(s(D1CQz`_c+;=PAVay6L0vkv zd|J5MrQab0Q_db^K|#Xn0n!k)SnOuUJw^4(3#R4qnL5 zy^F9U6u8-;uW)YtZoti#%a$O*z>Xp5>HUUGVMnL6L}JNFob1eFbI@a&gp z(d0K?3{(Upo#~WLALw{oaGeIFPq80A^Rdg{rT!lKKDr`)(`>}=Lj|cKEJ0nv#D&j{ zU2QQx?kk^F<~^FqLl(A;+{#hM{7?P;_gIT=5z(0H@Es}ZFl4G~^Co8<)(@#A(0dyT z78}yWx!loOAK6c?cXx5`2y0Fj4cJH)O-K=5ug#{X=63EOk(uEauZ}>?zg@^WjFtMq z?-_6D{mk&;*O@okS-cF~yB&S!+1<^w`L}p#xCV@u6IdPjX?xqBjGaY38T097vyojS zb##5QJs_GU8=CRQuA9M8kT^VCH=VgxQ?Y|Fo)dW1Vt5ccK^z zw%*R4I&3N_;=hcPo+KuyG59c%%qIA%a-u$-M&MQCnP+*5t$LLs<>uL8MT(w!#YfTz z)7y6??Bz8)SPATz{pl4&ZF(YgJ)b9<|H{y6SMd$>d!2vivP$mepr4ro&L%|09A{In}3!FV-aLP;+0L zLt)FYVDN8b!>Bx`e^*!XPRBS&mw2mx26IQeZy+g+5ZxTTYh!-Rsr0g2A@zvFc|^tX zM+5rbDS}W8LH`oM$|JoL@8&NaWQVls3!Ked3JHLr#`$C6TFq>^{n1AY?L4~Mpjl#e|~v1 zIvV>34K&w$sZ2Q&`TOe1Y8=M_iS|b}meH!2RzuV)3l3p|931RyQk32Hud}np&VLrS zXCS^)vu9BWuQ#!s&Z;z=o$1C7?Z-!dz@{K3wz2PSzpp;GEM2WMTpi)0EcLz(!MqmX zT)3vvTV|&E`fGL6+U0zOtS&0`d_^mT(&Pu+YH+7!@tlHX;rm+Fr>5FPuY9QVp`m{L zr{DcQLwpG!k866pzy1Pb69K)e17BMY9XfZ(J8r1H96epEhg{Jmr`_7Y#Hmc|?IFG< za@-Z7y6V+^OA(?hQx}SRyxc_t+{Z`l6t#nP!tYRYkp$)O-%hN^xd>fj&A(k{MJ`JA zEc{8UhY#=7=&s}Oy4!@7>Lmr-!Q9mOrXiit}0Yl z9o47c#@kx0y%S!bMkMpC?(-Kd^zS}_+@1%|6!@S0mNN9n4_8GmzpvB^Z~YYJ6w^AN z2&(#)l(@PtFJV1|A}8=+aAzI3PZv{x!F0h(#9S{hPhCYHYwHpLE;M}vT;JIZ4}@kS zS4LLhPt-)UF}IZc^*}Ga@ERf=WZF6>aF7U`g(x!I$<9kB49oS|WiM&TpP(bu;%m>r zEfLFcR14!y_~x!VWvV%=*v~Ee>tF>*n9W>U&bqaZxTmMTC@*yu8$~Yig$c5_ znoNp|f*@mU09icjWwL%Uw+`=q;0AhY`T!R&N(QsBipV121GqpKxc>{NqeRvayl5Iq zh{~}@weT9e{TRV`ZB-5Uwh&yufasR#U&(8z*>_BptMn`;O1JPP>2Lo&oYQeLPkh5$ zwilz4O4oIEd#4!?2__FU0`F805XL=w0sCO>Kz#wzT|a2q013YUFW>)0su`#;4#V@) z(JM@=@U063HAVv^LI}7^1(1NY0_^-Vac7rZbqTl+=fF7?mm83s?>tW$uVy z&IPO*ReAxFT*M4IE`nw~-dRl57W)NEQK|Aq+kO#PCsb`dA$WwF`eF$ar6Jp8imuCa z!kG181~o8sn;>=sPONd~C*TymMBM2Hq1yCkH2xvqA<~%^x z0EpDESGR?z_zBw9^OKuVu&(zvNvF9ZjliaW8K`Vwugj9AX&?SU+36?fsd8KZJ^zh_ zSYq3Mhp>qsz>O;wfV2a)66?VLM8?sr(Kkt%Co5P#$YPxKLBGi`_;e4mlZHnh48*}x zA`r1wL^8&4UBr6;K86A;%FM5!sn|`W`CmA8XWDWBb1BuVI)KMow}3#R<{5!e51a_#-@w`{H&8Ik0U*qXk)i=c+wlK`hI%}lcp(YE z!*jo|07$?v+QkuAF;nGT_iJc@4InAX^#Elg3qVr&;UnOLb%;(p_F6Sv+0?IBB2R$h zDLfPN9|mgn)bTrJIOE5)}@Pv8e;#zn}`M*O$YD?QqIaKs0A;Y!l4Rq%Iw1Y)vvS@Ta+EH zCR^4)0`}Wa;aFRzui*K^;$R1hyMq54ckjWIZ;eWrq7G~vl7c+!{{N~-4`YUfxD6ZU zw#x;q@%;@2qm5`UCJMO$2u%(G zRx73dr3vurMZudcVWX&{R3I<}Y`9(e0GrBdoQgnE4!_pLuLG0{_?y z_{h?uDz|`rz%;r@{38ZBQ46x7De?y~w`U9PV#PbQLHd)`Rrg!07Vj}dVgio%5b9hH z2rb_wtU|O7Dg|kzPO75=Ub4XHe?Fc@K|c(fz&mO{7eC6%4Kw+_koyaUUl;(T(iu#v zIch}*Guep2>fZk6+dHvq&FG?+C+H%dr{@6WeqHoo+~<Uk7B^ao#{+gRB_v45lkx!7Z`IL;)z_~!HILgWiZS}tlTnmH; zu+`slm_{TR@B6PRh>fI}6SyjgKB)~>jdptd1TOdpBQlRsIm2SmHS;EEK0TiiREh7y z*TQ_U4OgjmfJ#MX&I$bCIA$>ZS>6Al+3Nvt+67ifIQ|xlV2~>n7?=PXvSY**y6AuN znkXiT_rV0v`vsog27B>X!3zYo8rgCQYe<$B0#)nprctmAEXeuDTuT;+|AKLT0xuPN z_F2r}rNRlE)`1(+kIid=?4A* z{DmFX;K>Q#Qk3fgHb^!BEdxn<4oGvr;w-!TCkTJ;aD&j=0OQ;LkArV0G(K@$CS_u* z+=BnV=)Hu?Y^B_2XC5Q4V_$YtR|AZ&2&e^7(e~I#3Z-uWDT3F~@kGF3uX|lI_8#zH zLn$5W-|tv+EB`8G-e_-c0(%$iQ}9yQZGb-4Ju9LAnTw5}OGN4AO2)R`CDtHpZkW#n zP5_`!CH# zi2nsPsV+ccN!Sz2{yYbi!xJE8775p*B&5DT%s^l6qTqE$_b0v%^moau{;$y1l5{*d zJ~%W0!h5%${Q=qX4(NZTa#pP@PMy1#2|=As&$=%{nr^1YddZT%Y&_e+YJ2{HKZ@9p_sH-#liO2|N8v!67LeC3^KI zrOIM3>gfWDWx&mi@8p4u<;Si21YH}ibDz2S`S0SnbHD7gxUU~|Z|`35?neP+c_5 z@3<$ivQx5d2Nu6&yEbF?!?YQlmi>UfCI{DnNYmxy&R#(0_!hAO>TKT41~4|)eR=B1 zYl(C$d$dnV?u{&US-RWf5Q_F_^R}I*gdi5ZuBQJ6E)!ECUw@mqOn*{E95%O_!3FI9-U*jWDiX#`iZV#=<)m?DDYlkV)6qus6>R zP>yFzwk&<#wNyI{0xXa1?Su1;tZ*cxd~>ihHTJyi5Wb4EJu0We;*67sRPi6ysr?dr z@~Li2JEvnFCU{iibM$H0Yi?!Ua>b-`)Iv@dbz%#(nM|T9ah?P*C*(|1yy-`hqf`F{ z<`py^I@c}H4Y7C^RTXmUNR>Tqw%p_;U)Tc&h*)xknrNg36>IN5D&D-hv~RL*?i$mC z*W!VX)Mmy15<{oqEhx!p24e&F;7)C6joyvIbPxe*x}5 z5x|+tS#TY9>wl!q+Qw zEl933we>4<$rV;NAy-P)R6e=F8W$i~iAKdK7Vs-7gJNk`(>#-6O?NO!u_pUigkn)a zlqf*4NJ1}|O0f{bX%veQF`GAA z!IX?O(Z@nE76))FK(VOErC5rj%UB@AiA;(m{{<9_l9FQGlw#cq8y6MnHZFGO#4SNE zhJ37?8|rwyEI<3c*k#$~M79A(Xum2R@L$4zQTR8OwsHMWUc&#X;eSp^aQ^&H6pJ$dQz`$gHvf|~ zF{jmkQF5{RFRI2e@;~A1`Y%$^Me{$=jQTHXcK#>8m09_p2-S<_f6|%tUvN(S7d@T- zDKHKv@;|W>kFN*+r`CaAgZ+=-691R{Uorci3DOzYe<|g^mBarU?0+Tvm+)T@{%v4e zB>!Pr!vAXEf35aEQR;t6`EP0VzfmM-iv16(1?_((ZZos~i_W$G5xr3T7aMJvF7w$i z%XE=%^i;aQH+pbBc`t~_%(DLxnr;6>3{TttY#3(3{#WMv-5mbkjQvlR_`l@;iphT_ z*J~vI@v{EI8sUF+_P-MTOZYEn|1UcVUH?VP#q56+v6=QiCD=^+pUL)}W&dMZEM)(qIMe<|v+aMFPTT*2 zjNWDamrdY*b#wFIBKm(^@_!}&SJ?kkNEFF`n3eqBis64w^WP%y&rA3(;lC*Sn>@^s z{HI9?|0{w2h0T8p+5g~A3IC=1x2*WTF!6Yb{g1N+?SCfCcxL<`Lb>)owOIV0$qzmw z{?8-^pAr8TJ~bo$FMM#$_&=LNJj?#ak<7IJ36>WBXA*~(_P^VK|8H#mTY&$gvW)*O z`M<*QAI9VOKV0U2Ss(ltlLQyA|CRY4O874f|E8K;1pj6JrW}5$qoHqXj^$!!~KU$*kC4GARZmSL0zV5Z)sPEfl-5aN^okz{LDE?=F?vwZ* zs5UF{|5`pzVDk^0X4^gMbp1iQVe<}eJs7qxo6gUV;7)@RS9z#~O|9HI@K=qN)Qr@d zsxDNsC7Z2!Ln*p-eBFbN?D;wMdv3$qI&NQiCYd)8dr0pA1S5KY!~p>Bo8yOD_W{R$ z@*FsP13=*iChu>n+Zg(Xy?{bIjLzWJ(RufCyL0ArfC2O!w_!61n+tGcP54husTU8b z4yiHmgVSv}#vo8*^2GyZ&>gs!TaWtPUe9YfD(qpWF}!mAze9%tf}}4V?1s6ATbJ%2 z`1c3+ z*mR3(g4pr2wBt?QSYW)JAN|Yj;Ar3uyxm&2-}HdI9-YHKez+)@1_KcMgHe}a^+QDN z!W#>|DX;(oulc6k8Bp@8ckO>T>(=~px98P<9KuCqGeKk6Q#%1OkevVxCIB~d{Kf(k zXnGAe4dFV2%yIv+=XK72&v@ZluEOlXBX{5?mcucF0;OWo&W4fbjKpui{Jnn1y#$%4 zb?G$*m+gU9JNoRxDeP|rt9@Y zuT8e`a2ALJv%n&lh4{fqxv{`3f|Tfw>=HN48ecy!ig_$Dq{O(PbNGZ|0b^CP$}@!WBdDfttb*dazr&bYaft*~8Kr#^JDf@_Bdxyuf=; z_VKdh=r_Xu*A3&h6sCU;{qNLwOjzmvy^;M7YpM9PkAAmvxt{&!n9+&-r<|1jA8Yx1 zjp{#H(BG~)+iw5NRO|T=*3b!R=L9u#obCOg-`@wC2+ZwScOS?f{4v*qay8I4P`h0p zE~!Y)#Q6++x5v{C*RcQg%)cZU-_CL+gHK4wW}sS}5!gO~D?adE06@0PA`?m?O(zs&pbbO{i9k%qj$HpiPreW$vQ++wR|}8$5$t-5~cEp z-|zqT%v zt?eAIdfSuh57LaFQX1A%!55)9&DwxTMfnZ4Af`8++!Bja_Gait{{b740TalSXW&|M zf&~>?5T)~g!ZQeL&-kSI3vS6}+aDaxryTq@0}X7DB8n191tVOl=?yA{>^mg?CFshM z6ajhi9~_}c`yb_{{C5}ae{gN%}?=?bmv4 zf6z92^IKqF99#NeypyO$VjsjbF!PNkh*hvyc=_g-$x%5PzX$biVq8qK<4%t!#_L9~ zeM`2eF>}O=SToy;z}DvMv^$0q+D#u_%JJyjjxO~2OsSKz(dlb%Z5q)DIyIJs=y_N& z!?g!zP>K^Uk|9^ZFs%?&XY*$15QatONs~ zT7^+?YTWS(VrsWWsnvKDOpZ*Jw%+rd#JHhqa!wSFR|DDASaeQ>JRMRdAeXf$xf94* z2bR7!5vg$NZP@P@ZqG0PyS1M?&34~w3?5&4S2^dLf+qCAD_1S+VB9rz%RQms~$^HkRxNWSy?SWCDdB`Z*c#GEwafQ;_Y)?b$ zhHN%uT`DH+f zM6|eM@OYyM7mUL7mOTCCxEt)^ft?lD-UMzbzjvQ8Tf+90^;5h;XAJ-!V?eX~mivSg#*w(fYQ z<42Le?L6%|p;Z&4&CccZPat_ZeXrN`+d$B-9S~aqdv=Uu`e{VwoyNJ_IfEtH-ukvw z_>bFH*9HF=Q!xqugp~Q;*9ZTvP3T_38$)t&EwbMo_8VTD-Q1r<1FKO)RxB}w5V{dIiE5NewtJV*Q<4*WM74L5Ohdbu|_bao=Ud7DTZ2~s@GT1TggE1?E z>z?O?OX)RDq{7&g@4$SAje+yEQn1~BIx)MA?^u)^L|h!V&1?IW*vNeo^>N_XKUK%; z_YcfJRc8=1Js5rYR;fCL8&~5KIB=Tr!N0{v59waj33l%1PODpWTF|}MxBWW@ht7Pe zyB$BNSlro-rnhTep;EE8j{vv_rgy7-c-j37yWxZnn#)tYY&q@Ls3Yh996Fu$rSo-k zA!zJ`y&bhX=2%3->;lCLb|H1t6|6xx_wk!&&pviSlJ78{G`s^WU2Ny-mltMYllBZ) zexu@riMLvwHP5}WZ*>%03>w*uux_O(3j(M2W_?c{?r0JH*Ci;Wo~_hbApWunHsVF}yek$cIKN2t;M4 zV)VlELJ#zD4)0xsZay49Zzom%1N=ES885*&qGrdp4*|r&NIUJS^Ur9-^)j(;_Kq`S zxtz@P8lOJrUJ~>s=M=1)J)yJqJ#Q|_l?qxOhBM09*BE3Z=NX?+FvaPvM`$B~1Y$_T zz{R~R%#kJg&B7xYjZn%ce`rihA|#+%X--ue@tKv!-Y4E`$k*o z%-Wi-+m=XdA2b67s~YNN1AJ~S$EnA*r5>k2xC-2h5tD68Ow7fAs)YR*To?6XY0UN* z%5Cd0#o4ytb80gonOkEpt8TYoB~I-+Z69Q=(>K_e=8TCGTayJ^! z?&^#7Q#FngtNEP* zvk(c#Cgx)2L*=Xs2o9dz`&_C1Xb!xcUvJmKM$d?tcI1 zrPdr?_57W$l~7?@IrtjL!1pR?>cPsr-a&MK9_=1HI5F98->QbwGXChhqq)Xxg&9)~ zY)h4c*fQDIK7~Gd!+}|^wpp#d_h}C#Bj1DX&mP}@RDtFB+%zY>TQ$7~%TzP?qX($7 zVy6WQ&^riK61BkhZ6{pqfCkmCVWW0-cWdX~muCA6Hf?8eAHG#9G2=|-pt3C6OeL{q zcSZjf1v)J+3OL99LkOGH|Isr4&ze5BE&p3;0NVaU_*rJ+xBYS0*>vtVQz(F7q9}!a zCUd`;oM<{d^&9kD)4+gT8jmF7h?vY?Mi4f+-(t5X%Pl!${CjHATw4A!MkG&ZI90j{ zBdp`?BAsVSr;K4Tqiv#Jp>alXJ3?_yrX;t6-UV`u_vvXM*iL7@V~kMCQ=G;ax0D=t zw5DN8Y{M82meP>JHi@8NoKKvQb`SA*Q^N{QH^i`eENC|7@lyIT2{XcWmQhU|k_i&d zZp>DuzAjVY)GV_)(S%aTh~v5a%j;9SUu`)2gD=w)=gP5j9&}GrvjAdJqj<8(RC+;# zaB6x%bJpOM1GA9j_D(;$smc2=rYNP|RN}zs9WZ7{NXhUhvmcNFM0lCmZz}m-8Yyqf;H;7Tudw-T_a|f4Gmq|9=8#7!Kb>_C zD`^p&l`XIH>9A|GoS)kLZs&i$R$kpdeg;hZRO^Gvy>Yu5@C-XaQ;>#1nt1x#i~E1P zdi~qOBY0N9#TP#xKYRW2^V6fBpT2$k`sXKqo<4d0+q=^T_aFZH_~j#L)aQ71vxmRE zd3g+tEXu2V3(Srn99ogv#H3cEaD0V~39{F3cVI?G$M;_!SE{yI>vHIy2U5>Zb?>a* zIke)n`NtRzKEr}LR@Sk--m4gXy|Qa^zImOU%IC_is-`9|(58c@X>w zB*&!CXx^xDV3(m{rdm0$6Rw1jrqNlB4On>=d&-g$doFw+6@3wuG9mRKolfm2d#GC$l?_r<nG!vB-X9B4N>l4YKC)Wdusc8TVn_G0NV!kNdU@A;( zXi?Q4!ip8r{b8cA3R_5S-hH~Tg@Wg@b$^uWLb^XxlVsE~Tlt4-8Vg)d`-e2)1=N2g z-vH4C^ndU|8lyY~AQD{T0vbS66Li$u3>Bb2xhg=DenH4=9iUA`D07v7vucdkW5)|= z0TI?n&!q;W6l1{%iL`(i8Q2_a0oRKfOzlCTQ&5A1vpy3wh%D4FX*pOOYT)yr22GcN z8f1DA)B>o15nd2AP^}8028u*s)PSWZh8kE=)G&hjEYu)JZ=Hu47-LI74HWBK)L=@q z-UKx$Tnsf3%ILhPL2v<^A4d&nW2gaRPIy|uC_(vb)F89D2C^R1z_~1r8nkB1;TqVY zsDa6%T!TPGxdv98YoMecYQU->YLGG?H7Fzsat(;A2{kYP?VF$mnaT{L9yv5GYG9fR znLrJ65!A4tLqQxhV4}Iij8FR$VBqg&V1~fjo`D(o&HV`klcbP80VcR8dN6q&m*Gz! zYIH$=0y#SVdHw{772+FMEdtM6+`#mR7s>G_81Xc~3f_ZnXN zQ#4!N&`MI&qP)rANV_IUUBiQQ&{Vg$N3WE!XeT~N_d%Oo#8t0j9%Rnx~Z9`8$_czhvU&y z3NctvIJTpaV$6-D%E1=J22u^=x$rb`>##PiM2#j#O-@`-cnyIYEf^gUuZ~^pA>CwN zQv!^65*SuNT1utu(8q55)C3Us{P;+cHw7%Z2P=cPTX$u>xi3?O{PVO zy_QK&h+A5!7H+n515R|-SxCH5Q`QwM3T3nozyXv~bAV?Bfaht%;kR&=f>Q~Hh42Qj zBmksMC0Nsgm!w{p7p!z8x^47-Hl4(|A6%XB>r5rFlQ z{;!SxPb4RQVt7E4h^9HTn7}bw&YzqJYdh{`x8pfO-}7xgDTDT$^LA%oDrq@a(D)LX z1nF(uPj36tHQBTRHLVR2Gex!f-oR~lyr$z02j_sZ+l?R%4ID_G5x0M9dtOjdvZa^PQJJjwqPB6tb^Yvun~1-Qi)@AKPDFU*+-%`PvUj%$kv1`)60>^{~wwp_MCz?rMbP+JpL{ZQ6>Z$=(L25w)Sn6@V<7rzKH{783J8%QCsMV0D=`lDT zk^+wlEVd9#*Be}O?h*kAx4{|5LIYnfTkw{sDYWagl-{;OeGA#p(NVZ9E4d_Xc8WYp zMa$HkZg`y670eC91pkW|E7{wqJG%a5bVl+2Gs!@W&s!^slw?`H#jX2_~ zfBrUk9J_7%dY{ zp4jrluHwWZ1aFJ$a7JhycqN!zgAotbRbk<2DuDh^ArLyshLb|jStCu&l9Uv!hr+HZwyUaq} zih^BcBCm@S?Mg#5hkkfD#*m!YN*~jgmsOlA0*n9=jOuem3mSY4UTL!amVY>&S6+#X zvIJ0B0;p&Spz)cUDgzWdqmxyD#z%Hs1SmSYW$B*VTDqqw3IXI8@P!FKf;}?6{3#-@Izdu&Ig~(<)Jeu@N}r90FgMi)#;} z(F&AQ`?fW5);Tn6K@V6PU|^h4F3|80ZO77xp1Eh2Z5QbKV9?z+jx`;3@2tDMWh=Pu zxXzD;f4V>7jCUQk83=hs;CKh!7=pgzL$h-$N*T1(?%VRIK`mM5$Dq^NGdPC3&d!g1 zf**SajF4sZyU_R7sLZ!pi;uJ8k2>Dn`nCn{wH2htH43cJ379CkyJgUb6?Y6D7Bo*3 zr!{jnQvo?(;O#mS@@oa?WAdT>{ZOQ|;+E6%`f&HkCmauK@ye-2YR+`NfhWT&#6{vA7 z>Yi}ZgiSS9EF{G07dn-HxcjA9`Oy+q4!(Z-wlx-sf|JzlL~9&b3?{7*<1Q?{jBbZE ziGa88Ee!^&o?)R#nmeMhlF5O`dil{K36*?gELqrkF)AtQOxiAj^YdZ+x+j4^Yfe<_ zz`21AKd7F03k)QqSDRre85J;f7OG$xw23_&nkoKa@*n&?4Nsu~>7_aVV6l6}F9Kn2))2rUi4a^R-dK06;cfI1An zXY*FowziIfOgv))m@zk*YN>cHHW}#?4NsXFEk+d4p1qZILNUi z`MS0Rv)sy)R09FEYbceWa#wL-)v|rwmaSSg7FmneEej>l{K{oUOdOM#@j3?AXV|;F z&L{IkRGrMSgA*0W0wQ{^KRU4tyf zhmMAe*A30l<7tI{4L>>19k64=R_ih}QIGk}(X35>_SSf%tz-m3LnRn-?`!b)9{#px z(DhgN=iA;_^YFJy^iZg z2@;W|tOU0Hiy@8v>~3E_zW?aY%7F!XYY>{*GT08=(!T5NxAEc{-HSQFf*CAp&jR46 z=!7~RP!xx-=z)ch(u91}ipi<=907wJa_RG-tC)!V){5SN!1x4cC}64vh@B?J_ml`i zxWcom=vD5S7r$45ky=xT?Q5_`-@X(@ZV@m5(uf_qh~3#UC(ItzsA&<@7r>XrV9;v} zoxQTpB#_|f3>U+MyNNLd{p;kQfh6lTLm;%4y{j$|G4myHF~jH4;Ubj34yya55MeoyaOktIOZhZusf^Y$;tlT(Tj|_Jr4FRQFAlp zWBc(hJ+HS@LwLH4g{#`2J8YaAlpAl(rd!Yd!WFZlMi~rzZm2u9$gncqIZ%L5&y|5O z$Bia%=5nUk99qrKtSN?U(P#jZU~?xa|&x~nC<20f%5b}d@BBfabD(sDfK`99R1H;2vDUSsMG_MdZ1Dd zw1d~J2V$ijsMG_MdZ1DdRO*3BJy59!y0dy9R_cLDJ3==z{bE)1?ka+mpo0q`H zS8N?JX!h{wZ>Nu6-hc4?v3b-y`1H5?FCGa7zdqqgkV?ad$re=syK9qZBxN*vD~5x9 zvYgDJWnj!dh7MWoG{D6>fn#LAH0(}utG&Ys3EhlZwecu+w*vpnN_8Zu$Jo=Ea(cuW zD3qK`CB)&rB@368(R|$TeBl3pSS0C0p!2csUNJMQ9N2kQf|y148GHY|AR+@0ecL2c zG1ReF3$z2~*SCmD7{()Z;~-e*)OCw7H6QjA;Hra@#3rP$S0Qhjph1(Hw`Ep5h`g^< zQ{=O$N;&gBa^|VudENv1u+jHo)Oq>SoUp#)CxZB_ukw?^|E(bRTLJ!0AWSFgKT28Ff4YtFzs9_lZdO|%GkDfL zOecX`F*ebh-Hq~yIb7XxnaC6#G2*ufLwA~A4F8rqV>Zud_?3|13anFMN{opV87CoY zW0UCxL0qP}T_U5$@pmlu7xpw66BXCheh5>)okXE+p+0ajhAiG+kfCp8G}+-{@NFyN zVNm`j)}3KW~R=%BQ807IL7-Xx!Te1!1`)`Hm;f@Ot#-KXTfk} zA=`A49KUbE*$R#yw4FVVSz~{L0Ziy}wtn$qGF4$OC%*Bb+A}~B%zt#;6Nwg=E27L2Ohk@g5 zfk+ZN#vzK!KFF!4B!L{~k&crO<{$m}&j%)yJeV!TMlJ{NJ#;!a?RLJe1nV-97inH2 zZ}!_Qvau8u+}Ws6Zy3&E_I^Q|noXEi*&Q8-Q3JRIuWfg~+qGoSwllqVdv+nZCSin` z2toF;d)DeUhW??=xpp{aL5nU+@i_vO`~=%!xQoHiH@o9s`+!s$12fSeF-&E|G`pju z7}mi+*TRR*l+C&C0mZ#Oyl?X?+O!?jqhUSx^1^L*Uj6*2YTSU#cbjt17_VU5t6nM9 zm!E9;Kgio)QZ=kK|2v{n@;?!*tp9c^&+cQg7KX{TmBS_1P8;eQpm{|dlAM}kbkKc~2a|2w7sTd`Yx zsM#BN){hi@qw6zteP>;p7BE$JnCfl6kS@@fQU*HH+CXPQ9q1I)2RaKW1Rbm6awb%Q zMLm737R-y%X^-@SBZtSGaM5$Mgkuk!q~~L#Fm$FhhVwduPiqaQrddFD81o{|QzANX zEuxd5Mznd^ay5ye=UZHvIN`W7Yq`@Di>XfAvo(w}oTK8MMES=iHHI0Q!l=564N#fR zK((8ev1__nGKE&8#B|15%o&-sGW3!YX}|LHlg6Vl)KJ=$9IGILTvJtNZVkl51S)gr zASNHp)k2IxprEGA=G`l@ZWCkY=+j2(tDsa&A`@4bZ_s4ZUZys!*X>>=yUcbvFXla`KSQU_lM$L2Y5Bs;kFe@6 zh(AKk@s*y43JH{cqqR;```sWeApJ0ADvd@nxsgI}@}1-P6pckLUhp&V6NvChxYR#T zSnT;8JQzKBGP%Cy&~1Kg%`9%TuK)O;=kgPMKDn3erbUDSziZ7?fhN=N8Eeu1ASoyF z|4CZvf7bHpUO3KovGm-(0YPb)z^T2r!O7_MBO_>xx%f`kFlT;=4E}NO-x~h?_j=(U zBRr}9VSp1#_+N|u2e$jb@qkhFO=uGWk@n0ToClepqY&PPVP@Sk4;t(X>V&Equemkv z3xvDcWv=M-~b06$U6h* z>cGLo*%@>P?&X0a`R-(2V%(Qtl0aXWP=#i8CdQrVsm}CNXKU}sNbg&VqjH92iONg- zZ}GozrCJ*1FM|IumlRFv|0OQ@zgx}!ks3kD-`crnq+jIkI#DeTn~dPV2yzv+FxhhAZ%+j@BSfj zhMg-|hI4pobS0STOIwKN!aGD89`nwg!~Dgfv8AGG*qm~_fBeD2YhI{wymGvG$6Exj z@SK2!7X&Pv1z3wtJpSBtTVPd!624}*TlK!izz(d*mD_2zjFH>xb%8Zf4CExUzZafw zToy)5b^NaN5^Tolf??wYRtDJh}h# z^8@D?#(2{)HZrey42;#0&F=ZYuyjFHVBgeSg!MRrGu&xD3fQe*y=&juK{bT@kspHL z>x`FRShMbcGJW7g7Pjx~F?WuQed6G|<(C_cMgQ!l&ShdI2jP!xv^`3()Prp|ZrS6O zW^E4QKNef4*scY8()T{QCZl1qZHj5vM_F3~t=fU*h7U0|Ne~A?Qo%#)xYlL-uw^`> zLRS1VdfscEhJ7ANIl61{QSAD^7%U&Ze*N2P=x*fBHj+}pwbsty%OR8UtoP?F7yI5{Lz9xqWP|eUZ5Jkfd2O>p zL95u6VJEs~pt#*Qy?}!Szk*E;e_VFE7sH;VC8jk{l@H{p&y{-Re|*$?@b{CZnQ7etq%wm!r)t^@HF4;1|aa|CYZWy?TB2=d0GU`Z4|d%SHW{zaF^5 z7sn5tcj)y6ebM~%{ye$Vb3HldQeS!0`&0ftd?mY-K6xu&>CUTP+THt}_wdWG>mB#& z;{CfL{_Eh~{dd=IpZ11F-hJ#zzx#&0fA;>^d-2yY|m-pW9`0+)v&mR2#`0C>L!PBd^EmzRqK(a1x zi&yRU7q5PK@v8qjIp%Nwyx^}p7k_*?a*rM!J%4lEbsuhat?$2U4&T3e`{Lqd=f%_K z@Be=N=1j&b9v2efRn36+3(M*Q4VO!H@L)`+leK-0!`6*LwNaU+n1q zgY)O_e?Rj7e)jyn|Ln_)_a8rLpYq4=hQD9Ee&71*SKfH|{I8b}>n|@Z{0B!L?~|h! z51X4^YWnM6?e~8_B5mP)A)l}AzkhN3@GbvUuuoSn>wjOl{LeSTzXyNUsrUmYmwK)z z=Ui&S`i(Ec^Isk`{5KD}=huInzd6DK`L=ugsQW_w{;umk?R)(t|?6X`OW8Ff|K#xjxB%Q+?~6J=x{C8#bka8 zcoB@bAFRdV{(p8+_F9*)=u5H#=lTDESTyPXLvdOEcP*b%kF!oa&P~u1s!>7agzm-R zADDz;XHD>r=e1uSh0mQDf_LgR-QK|KkLc;v|NM`$hpNcA zhpW>0pa0pq*K->e?wRL=&u`t^x)(;0Z^y9AnR|BGcKc0lFzD`sgyVMHy|eDNY26xj z8qSXE{CEW1eHi)Y^>-b&**rQ2I{O4@`a9_9HB4v6hi2wt)l`ae+kNA(b6K?k<<5^m zzcr)k-*t9=G}6MuD8}57=&Iux4q(^$x^?fnux^xFix0Hpk9ywSy7$c*z1+m|7*v_R7jT$qHJqOx+3@c1!oZCnfrq`5ykUH{OepBo4c~O>2SqzN z16aG*n4?c@?0et2!@;>p0b(5Znr7pIxy5_E7oT8Moh8vAHqrD3u?eR)h)q1IIsz{c zEUrCxSH>Vey}&zzx-$rTuWQE-s!o74ogeL-YY)u7yQv%V)$XQ7RpH#zA&fZReb+d* zZgIx3`^(^wJ8*+<4{aGICyGU_h3#H={fkS_EL_zAlI%V<^@2>OID9eP*#Jd&FsvD3 ze^z7Nw7drJqIThHwc4(EHu(9-=nmR9y3vb{Y90nn+u>pfS zKD<7(4wl^ln`!&X#L3zrcYc|$J|T47JG6BZgHatj<)H6}qdD!o^gdgddFHuIufL;dYvamG+`DHc4dy0103C zUf8p}8qO+Xh;is@UARrtAaPpY2|_@TOY>~Lp(LU_SQrsrjy4E=Ke4fuQ>M z5qu#{$k>mg@oIi!h*`BaNn`QG+CG08_aDO6Ez>Vc}4&yHBI3`7JPCRx& zJrLlzUOA29K#>xMw5id&FX?V$dIz5)GQb6q3;PJGoCF1if{Y=fqVK}qlmrJIVkG^% z=<|mOQ11z01Oh@Un~kpQxAfdRd1BV2fFADmAayF0pb4KkqYtVur(|a!>>j6P5r>Da z+H(jL!4*KTyvIGqlaE1c;6)J_UY@u&&d}f9ut)8abEoh~s~5uGfB8jKBOVO6e)Niy zLuy44)Dkk+t#hOr(HPF?jdP=#7ApCPzDm#O*Ils4HeuZbJF!k(^@cHVnJtbV*(yRD zjXuS7g$=}+O}x3MBI6t+uQO={j)V#-75;lj;tqG_-%g=TFp7YQ5?k8^Vima-I_b0N#9rPjS`- z&cea=@m$70Po#y__vUuA#P>vUQ7K<5zg!m;8Nm5`Zm#npYv(&S`gdYk>4a)X;*FlO zCH@URc`J4B6GS#$YPS7nZ8DoT#k5T822tci=x=F!61GujK1HZt=`}MMi{^R1EGE8- zKQo)Cps&FuR64G*2Gis-&v>*%0Kd9JK>v#X{KQU7o1&+rLci1Kf7FTzv-2wb%U&g% z)pf7`NFVb4+#B%rq<_>^6f*^39ry5sXdRWsMBG7Z9D~5JCco>4DSZl2Y3G4lnRC;2 zfBa>a>VTu+NHraC=B~&i<(HXxJF^TeFpFx@0a+4(m+|7Pdk?EIUZf3x#%{%80%H~oLnQJ9~}1^BT4Zy(3KH~oJ{ zyWRQk|1SQ&!$bCR&_62v;ol;8#rg*<4XOgS{HtD8hf{*73i7>HwZn4i6q&H};&yGz zzJ7IzT^p-1#AIv6TrX)@cPeCu`|O1o?(e6AJ?Fnz;?!=@D*5n_e5Fp3%8U$b4b&|b z>yKiG@d?hX;p;fy7P9z4R{3q4+YT|iz`-h1(|r7B#` zTd7Ef{vlYZztt?=;GrHYTlbOq*7lYejmP#9uARb^m*{mgH*);6W^1p<_?&&Zp2vcg z+A+v-D)NO&nzg|@@l^99Vug_ENY!Q~Qed#&U5V(-0ZtCF@o10IFOi@p+_0uh zQbo433&N^hzHEwPM|0bvDej0W$eVo&d-cl3D)uPTI_k2=Ls1PP9z)WIP8=R}(TOfP z(M2aVq7z^5|38RM9PSRg=tLKt_@w9r6VB1#Fx@*K$~oG9mhKIjf?;a5A>Cws7Ll`r z)-J}bi2De~ZF@*|{!hF^@Eu5Rnz8#p3~0~oq?Y*)>hEQ7KRAJ?1~|)_Vr}t*4fn_V zJ^fAFw(srTa#@kW0P{9Aua?W73OLmR>q@-U?|Nm?^F670c6nuaf0VSPh+-@W8O%t& z-AnPPaP^`-_vKR?99}XjiA|&eEHB3MHM{6>_9JU5GBT)xemL&->q>P!hZJ@(L5c~m zq9nbLHOfoE%QQ1T+PNL`i6s~-kx{-_FHB*XwmaS3X}r+doH7L z;?K28b+AerOsh`Lspi)Nc9#MC_PCAI#vQFC6Z{nb`Q-)}nAYnVY> znUxBnC@90Py%AACghpObKYXyiT?P-{Xif`6YMdcCL1a-eNSdl$!qO*kHI{LT z!+{1U3Pek=F=!C*WU_DzHb3ir5T^Kz)^AY368Q!v>ym(of|?s**D1B6j#ifajhNI8 zM-mB>)7;J{e3p~BxG{n6vi>S@2ID#cO_C*DDR$U%P?;IC5#@BLxIQF4xmx1(13aQG z3%NkEENHWo1xGTp1TjGX!$W3;FTrlvjUv_BAym_}jby(N&0K;Fb6hQ)vg?h_39 z6bHqo#(Rj?Y-7j%^`#q<&)7|xV~v8H^(VKL^FP3cjWOY0$64Yy5`KQSj(nb|_+CeK zSM&Fe+oRTr@s_3^r&?2CbTAIbnbH~AsL|vSc_t)Bk9b>Wul~L!jzU8bIw0jIQ6vLiwmolMY$!OUe)+|GvEkMUE}h7b{*~rAze#iqd<)sqCMRpmPQc>X z29sK)W<;~tr6@KYyzFG=y(|>Wx)DCMqa_)8q|%ANqs|Mp>2P69h{55Kk`VUKIIuP6 zv8!Jo*Zq!((UXknoz}_II8T6GTTEVUxoSH9{sqI}88{!8$DZg<_jSYiF?FN8 zv_Ep>>N@h9s;w*h7cCI!K~LJK`c`Q5*l=ixka1k2+0-$pW2M(qFy=t7i4dB+bl08- zk7duV?#o1ppF%Vq?Q%d1|2UgssZKZ9xUB6AoB{^Le$HId5&QS7CI89Zs84r80jNdv zCGxP$1jg%fiL`;5;0KKIgG+(gl7=a&UNqlRmni-e?e1uRsNBxc;2>ystm!(20gsfZ zzx`PMUuISQj@K=dv*pC9s9Y2leKzfYorbpG4kK2T6pqs6hQh-D#PpEM2?FMw>sDKi zM>y3mBM6mw-Up;(nf`FdYdQ3>$$O{2(_&hHW|y2V#BT}vooI#z_zzS)S-`T8>K{us z+`xG=`8ea07)7zFTVF>&rRA3_j$IolEQQ)z;0O8$ShB5B6Zv z(*FmCE`%EqUTq$npT)H<+hU%7u)_12W^c+jN=ihS_!ud&oZM*aWO#5e_}XPBDMNRW zzp)BJ4@Pc_MuCQau;g_Kj~<)$g4_(;jh6|L%X;aTfO$E zwP|=F>Rt%b7W{~jcwhLy#e&V&2YcgP96u`GqXFH@K#z@M+d*2TNGc$?m-&gibcDmb zba(&}gnyVl(C~g{md|THUN6t6zw;B+@D3Yii**)lLaLaN{p1*CKaOQbvyoxAgs^5e zq%U1H`r!~Q-<)=g9b{RJCtfmVGmPMAJ{$<5VhfIavW6_cOol~`zXgw+^ayhD8OPoL z!!?qtVI#poGyI|$EpJ9{m#>!jn1dy>I%mh{vOxStv@rBLsS(9=vC3E`O?zK{buFj) zny)5G|6fhMWES_P;ByfpPExUK_BKNDKw#=~^$=m_TZiJ7WvHXCU&r|-%Gs|=)F4=F z@K%`4GR}}bS;d)~0Q5AZ)T~Gp*s6v9M;SOj>ssEU#ogCZk~G-WdE}#1v}@mn_Kw}~ ztsSHl*H9nl06DmP1&Ez|NoWJ1?QjmTnb_%wAJ zN=Ra!IxIX_lqAqN^{7G~(0C@7wig&A+1VW zyECVqdPT|;HF<~eWg7liHE?o66Nt_9@rsOVcY<|xD*qBXS05`5OE|SQLV+N=!c%6& z2ob_($iV?-bq7$;4xc$aNRP?p!jZ!kpehonwcha@!VOy&&|Th+mhbFJBPj3vD!4X; zyjLS&lv9o2ak773!}Ke!3%*uzQPK|wyIikm$a01>qf5ho49Bk<@xsOEa>i>3!Fo}y z*|~+AV@L)ToWZHxyekRJim0|a@rjoL?edZ|5!j8ydaDXsL+N9t11P6c+EXPbmq@5^ z5amjXTjAlelR7lRJ}ulC6s7VJ zVcF`KRG9fH??>z?-ZHfIH}DDMS9z5~r5P2H&9|U>`*Ccocn?SNbVTVxOf-<2S82hYgmlbkfmEx1SlngBpBou?nEXvpo>|rypX_AZ z6D1zuQrE<{y3Qv=dS%2@r|V4;A+lpXkaa5U=fOo_T%Tj10<%PJ@W#|IRF!hoWmK*$x|deVYQR)fJ`+(F)wX$`vBL_H*^uCRr&lG_C;CfvU zdEf{H52AS<*N6oAqn|e33mB6W8(` zfaIUyQM$JqzK7!e{;LxCr@~3Uc><`ylJYUX9^F(V(kkeI3%Mgu!WMc}15Lu)(O0bm z?My?SE6C(N+%vN1;m4S80~D+#@f^F9eMJ@AIqq$PBME@-SRE$2;Yw}pnvuvEnyFbu zX}SOamB?q%(ZgDD9#)KfRcATA5TL)l%jdDu#OZU!;;N3;H)I^q8$XVwc7D@yBgA-; zkc1cI*J(bTG-F)otBj}Aja~jghlysPiq=MR+&$61pL0A{Ur0{8$Ngo&a%=^~3i#9I zo+509G@_7;8?$1>mN@kn@=ySgHb#Uw%P(nf=AvN1!XT!78jD7Dy?@9r@qtyYAB-t? zj~t6MatxJJSg7{B#LWUB?k7(+^AC7k^%JG#>V*Cd^JTnH6&WEKBi>lhC}E-DfF}|M z*bQoBN`6&LdVUGGXX5)=gIBiG;(ddr{%S)NO4Uwiyi(hsQm%WHOu3b()3$d$jZg(n zKv@msW2AbLpg8QVx`?E9S6M9V z+(%&53^DsCd4;wV{aKM}!j`x#*cpfT5Lhi{07(V~hSL{s1eP#ky?2u|Bz#W^?VDAp zKI-Auv(($1^Q>6W5>CtM@cF`j2j(U~ggD&x6WgxQ^mdrpZB3qu+02XAko&dwYm(n= zh0p5TS5ObhW{qlm9BK9D_!YISGv-bu5_g{qlm9G5n Om45