add end-to-end IO benchmarks and fix pprof-identified hotspots
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>
This commit is contained in:
@@ -109,13 +109,38 @@ func bsPerformCommand(bs api.BackingStore, cmd *api.SCSICommand) (err error, key
|
||||
// TODO
|
||||
break
|
||||
case api.READ_6, api.READ_10, api.READ_12, api.READ_16:
|
||||
rbuf, err = bs.Read(int64(offset), tl)
|
||||
if err != nil && err != io.EOF {
|
||||
key = MEDIUM_ERROR
|
||||
asc = ASC_READ_ERROR
|
||||
break
|
||||
// Read directly into InSDBBuffer to avoid extra allocation + copy
|
||||
if int64(cmd.InSDBBuffer.Length) >= tl {
|
||||
if reader, ok := bs.(interface {
|
||||
ReadAt(buf []byte, offset int64) (int, error)
|
||||
}); ok {
|
||||
length, err = reader.ReadAt(cmd.InSDBBuffer.Buffer[:tl], int64(offset))
|
||||
if err != nil && err != io.EOF {
|
||||
key = MEDIUM_ERROR
|
||||
asc = ASC_READ_ERROR
|
||||
break
|
||||
}
|
||||
err = nil
|
||||
} else {
|
||||
rbuf, err = bs.Read(int64(offset), tl)
|
||||
if err != nil && err != io.EOF {
|
||||
key = MEDIUM_ERROR
|
||||
asc = ASC_READ_ERROR
|
||||
break
|
||||
}
|
||||
length = len(rbuf)
|
||||
copy(cmd.InSDBBuffer.Buffer, rbuf)
|
||||
}
|
||||
} else {
|
||||
rbuf, err = bs.Read(int64(offset), tl)
|
||||
if err != nil && err != io.EOF {
|
||||
key = MEDIUM_ERROR
|
||||
asc = ASC_READ_ERROR
|
||||
break
|
||||
}
|
||||
length = len(rbuf)
|
||||
copy(cmd.InSDBBuffer.Buffer, rbuf)
|
||||
}
|
||||
length = len(rbuf)
|
||||
|
||||
if (opcode != api.READ_6) && (scb[1]&0x10 != 0) {
|
||||
bs.DataAdvise(int64(offset), int64(length), util.POSIX_FADV_NOREUSE)
|
||||
@@ -126,7 +151,6 @@ func bsPerformCommand(bs api.BackingStore, cmd *api.SCSICommand) (err error, key
|
||||
asc = ASC_INVALID_FIELD_IN_CDB
|
||||
goto sense
|
||||
}
|
||||
copy(cmd.InSDBBuffer.Buffer, rbuf)
|
||||
// Zero-fill any remaining bytes if read was short
|
||||
if length < int(tl) {
|
||||
for i := length; i < int(tl) && i < len(cmd.InSDBBuffer.Buffer); i++ {
|
||||
@@ -158,7 +182,9 @@ write:
|
||||
asc = ASC_WRITE_ERROR
|
||||
goto sense
|
||||
}
|
||||
log.Debugf("write data at 0x%x for length %d", offset, len(wbuf))
|
||||
if log.GetLevel() >= log.DebugLevel {
|
||||
log.Debugf("write data at 0x%x for length %d", offset, len(wbuf))
|
||||
}
|
||||
var pg *api.ModePage
|
||||
for _, p := range lu.ModePages {
|
||||
if p.PageCode == 0x08 && p.SubPageCode == 0 {
|
||||
|
||||
Reference in New Issue
Block a user