Skip to content

add end-to-end IO benchmarks and fix pprof-identified hotspots - #128

Merged
carmark merged 1 commit into
masterfrom
perf/benchmark-and-pprof
Mar 14, 2026
Merged

add end-to-end IO benchmarks and fix pprof-identified hotspots#128
carmark merged 1 commit into
masterfrom
perf/benchmark-and-pprof

Conversation

@carmark

@carmark carmark commented Mar 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Designed benchmark programs for read/write IO paths, used pprof CPU+memory profiling to identify hotspots, and fixed them.

Benchmark Suite (io_bench_test.go)

  • BenchmarkEndToEndRead/Write — full SCSI stack: AddCommandQueue -> SBCReadWrite -> FileBackingStore (512B/4KB/64KB/256KB)
  • BenchmarkEndToEndReadParallel/WriteParallel — concurrent 4KB IO
  • BenchmarkFileBackingStoreRead/Write — isolated backing store layer

pprof Findings & Fixes

1. logrus debug logging: 22% CPU (FIXED)
log.Debugf() in hot paths (scsi.go:101, sbc.go:436, backingstore.go:161) was allocating logrus Entry objects even when debug level was disabled. Fixed by guarding with log.GetLevel() >= log.DebugLevel.

2. FileBackingStore.Read allocation: 38% memory (FIXED)
Every read allocated make([]byte, tl) then copied to InSDBBuffer. Added ReadAt(buf, offset) method to FileBackingStore, used via interface assertion in bsPerformCommand to read directly into InSDBBuffer — zero allocation, zero copy.

Results (256KB reads)

Metric Before After Improvement
Throughput 9,943 MB/s 14,098 MB/s +42%
Allocs/op 10 5 -50%
logrus CPU 22% 0% eliminated

Test plan

  • go build ./... passes
  • go vet ./... passes
  • go test ./... all tests pass
  • Local daemon startup verified

Add comprehensive benchmark suite (io_bench_test.go):
- BenchmarkEndToEndRead/Write: full SCSI stack (512B to 256KB)
- BenchmarkEndToEndReadParallel/WriteParallel: concurrent IO
- BenchmarkFileBackingStoreRead/Write: isolated backing store

pprof-guided optimizations:
- Guard hot-path log.Debugf with log.GetLevel() check in scsi.go,
  sbc.go, backingstore.go — eliminates 22% CPU overhead from logrus
  Entry allocation even when debug logging is disabled
- Add FileBackingStore.ReadAt for zero-copy reads directly into
  caller's buffer, bypassing Read()'s per-call make([]byte, tl)
- Use ReadAt via interface assertion in bsPerformCommand to read
  directly into InSDBBuffer, eliminating allocation + copy

Results (256KB reads): +42% throughput, allocs reduced from 10 to 5

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@carmark
carmark merged commit bbd373b into master Mar 14, 2026
1 check passed
@carmark
carmark deleted the perf/benchmark-and-pprof branch March 14, 2026 11:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant