From ea2b7d93d6c2fe81070a6da6358a5e637e6e31ff Mon Sep 17 00:00:00 2001 From: alyshanjahani-crl Date: Mon, 13 Apr 2026 16:59:51 -0400 Subject: [PATCH] obs/ash: add BenchmarkSetWorkState microbenchmark Add a microbenchmark for the SetWorkState + clearWorkState hot path. This complements the existing end-to-end BenchmarkASH in pkg/bench by isolating the activeWorkStates sync.Map contention that degrades on high-core machines. Varying GOMAXPROCS via -test.cpu shows how per-operation latency scales with core count due to cache coherence traffic on the map's internal mutex. Also updates old / inaccurate information in obs/ash/doc.go Fixes: #164683 Release note: None Co-Authored-By: roachdev-claude --- pkg/obs/ash/BUILD.bazel | 1 + pkg/obs/ash/bench_test.go | 48 +++++++++++++++++++++++++++++++++++++++ pkg/obs/ash/doc.go | 5 ++-- 3 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 pkg/obs/ash/bench_test.go diff --git a/pkg/obs/ash/BUILD.bazel b/pkg/obs/ash/BUILD.bazel index e97e54620a70..61e73c76fefb 100644 --- a/pkg/obs/ash/BUILD.bazel +++ b/pkg/obs/ash/BUILD.bazel @@ -42,6 +42,7 @@ go_test( name = "ash_test", srcs = [ "aggregate_test.go", + "bench_test.go", "buffer_test.go", "report_test.go", "sampler_test.go", diff --git a/pkg/obs/ash/bench_test.go b/pkg/obs/ash/bench_test.go new file mode 100644 index 000000000000..19dda7526b3f --- /dev/null +++ b/pkg/obs/ash/bench_test.go @@ -0,0 +1,48 @@ +// Copyright 2026 The Cockroach Authors. +// +// Use of this software is governed by the CockroachDB Software License +// included in the /LICENSE file. + +package ash + +import ( + "testing" + + "github.com/cockroachdb/cockroach/pkg/roachpb" +) + +// BenchmarkSetWorkState measures the per-operation cost of a +// SetWorkState + clearWorkState cycle — the pair of calls every +// registered goroutine makes on the ASH hot path. +// +// activeWorkStates is a global syncutil.Map. On high-core machines, +// concurrent Stores from different cores cause cache-line +// invalidations on the map's internal mutex and dirty-map pointer, +// degrading throughput as core count grows. This benchmark +// quantifies that degradation by varying GOMAXPROCS via -test.cpu. +// RunParallel spawns one goroutine per core, which is the right +// model: contention scales with cores executing simultaneously, +// not goroutines queued in the scheduler. +// +// See #168289 for the sharded-map proposal to address this. +// +// Example: +// +// ./dev bench pkg/obs/ash -f BenchmarkSetWorkState --test-args='-test.cpu=1,4,16,64' +func BenchmarkSetWorkState(b *testing.B) { + enabled.Store(true) + defer enabled.Store(false) + + tenantID := roachpb.MustMakeTenantID(5) + info := WorkloadInfo{WorkloadID: 12345} + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + clear := SetWorkState(tenantID, info, WorkCPU, "BenchmarkOp") + clear() + } + }) + + // Drain retired states so subsequent benchmarks start clean. + reclaimRetiredWorkStates() +} diff --git a/pkg/obs/ash/doc.go b/pkg/obs/ash/doc.go index 7cad718ecf2e..e92a007804fa 100644 --- a/pkg/obs/ash/doc.go +++ b/pkg/obs/ash/doc.go @@ -248,9 +248,8 @@ // // The on-hot-path cost is limited to SetWorkState and its cleanup // function: a sync.Pool get/put and a sync.Map store/load. Benchmarks -// show ASH adds a near-fixed ~600-700 bytes and ~17-21 allocations per -// operation with no statistically significant impact on latency or -// throughput. +// show ASH is allocation free in the steady state, and has no significant +// impact on latency or throughput. // // Plumbing workload identity also has allocation cost. // context.WithValue allocates, so context-based propagation