Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/obs/ash/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
48 changes: 48 additions & 0 deletions pkg/obs/ash/bench_test.go
Original file line number Diff line number Diff line change
@@ -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()
}
5 changes: 2 additions & 3 deletions pkg/obs/ash/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading