diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-03 10:15:04 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-03 10:15:04 +0200 |
| commit | 49885cfc8cba02d378a615c7383ea778afd5aaf9 (patch) | |
| tree | bd2d645ab0a0d19b385bcec8c805a27570657c52 /internal/bench_components_test.go | |
| parent | 778706798fc66b9aa6be739517bb1486b3653e58 (diff) | |
Add component-level benchmark suite
Diffstat (limited to 'internal/bench_components_test.go')
| -rw-r--r-- | internal/bench_components_test.go | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/internal/bench_components_test.go b/internal/bench_components_test.go new file mode 100644 index 0000000..1f9ccb5 --- /dev/null +++ b/internal/bench_components_test.go @@ -0,0 +1,363 @@ +package internal + +import ( + "fmt" + "syscall" + "testing" + + "ior/internal/benchutil" + "ior/internal/event" + "ior/internal/file" + "ior/internal/types" +) + +const ( + componentBenchPID uint32 = 4242 + componentBenchTID uint32 = 4343 +) + +type recyclable interface { + Recycle() +} + +func BenchmarkDeserializeOpenEvent(b *testing.B) { + gen := benchutil.NewEventGenerator() + _, raw := gen.EnterOpenEvent(1, componentBenchPID, componentBenchTID) + benchmarkDeserialize(b, raw, types.NewOpenEvent) +} + +func BenchmarkDeserializeFdEvent(b *testing.B) { + gen := benchutil.NewEventGenerator() + _, raw := gen.EnterFdEvent(1, componentBenchPID, componentBenchTID, 12, types.SYS_ENTER_READ) + benchmarkDeserialize(b, raw, types.NewFdEvent) +} + +func BenchmarkDeserializeNullEvent(b *testing.B) { + gen := benchutil.NewEventGenerator() + _, raw := gen.EnterNullEvent(1, componentBenchPID, componentBenchTID, types.SYS_ENTER_SYNC) + benchmarkDeserialize(b, raw, types.NewNullEvent) +} + +func BenchmarkDeserializeRetEvent(b *testing.B) { + gen := benchutil.NewEventGenerator() + _, raw := gen.ExitRetEvent(1, componentBenchPID, componentBenchTID, types.SYS_EXIT_READ, 64) + benchmarkDeserialize(b, raw, types.NewRetEvent) +} + +func BenchmarkDeserializePathEvent(b *testing.B) { + gen := benchutil.NewEventGenerator() + _, raw := gen.EnterPathEvent(1, componentBenchPID, componentBenchTID, "/tmp/p", types.SYS_ENTER_MKDIR) + benchmarkDeserialize(b, raw, types.NewPathEvent) +} + +func BenchmarkDeserializeNameEvent(b *testing.B) { + gen := benchutil.NewEventGenerator() + _, raw := gen.EnterNameEvent(1, componentBenchPID, componentBenchTID, "/tmp/a", "/tmp/b", types.SYS_ENTER_RENAME) + benchmarkDeserialize(b, raw, types.NewNameEvent) +} + +func BenchmarkDeserializeFcntlEvent(b *testing.B) { + gen := benchutil.NewEventGenerator() + _, raw := gen.EnterFcntlEvent(1, componentBenchPID, componentBenchTID, 33, syscall.F_SETFL, syscall.O_NONBLOCK) + benchmarkDeserialize(b, raw, types.NewFcntlEvent) +} + +func BenchmarkDeserializeDup3Event(b *testing.B) { + gen := benchutil.NewEventGenerator() + _, raw := gen.EnterDup3Event(1, componentBenchPID, componentBenchTID, 8, syscall.O_CLOEXEC) + benchmarkDeserialize(b, raw, types.NewDup3Event) +} + +func BenchmarkRawHandlerLookup(b *testing.B) { + b.ReportAllocs() + + el := newEventLoop(eventLoopConfig{}) + eventTypes := []types.EventType{ + types.ENTER_OPEN_EVENT, + types.EXIT_OPEN_EVENT, + types.ENTER_FD_EVENT, + types.EXIT_FD_EVENT, + types.ENTER_NULL_EVENT, + types.EXIT_NULL_EVENT, + types.EXIT_RET_EVENT, + types.ENTER_NAME_EVENT, + types.ENTER_PATH_EVENT, + types.ENTER_FCNTL_EVENT, + types.ENTER_DUP3_EVENT, + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = el.rawHandlers[eventTypes[i%len(eventTypes)]] + } +} + +func BenchmarkTracepointEntered(b *testing.B) { + b.ReportAllocs() + + gen := benchutil.NewEventGenerator() + _, raw := gen.EnterOpenEvent(1, componentBenchPID, componentBenchTID) + el := newComponentBenchEventLoop(componentBenchTID) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + enterEv := types.NewOpenEvent(raw) + el.tracepointEntered(enterEv) + if ep, ok := el.enterEvs[componentBenchTID]; ok { + delete(el.enterEvs, componentBenchTID) + // tracepointEntered stores only EnterEv; provide a placeholder so Pair.Recycle can return to the pool. + ep.ExitEv = &types.NullEvent{} + ep.Recycle() + } + } +} + +func BenchmarkTracepointExited(b *testing.B) { + b.ReportAllocs() + + gen := benchutil.NewEventGenerator() + _, enterRaw := gen.EnterNullEvent(1, componentBenchPID, componentBenchTID, types.SYS_ENTER_SYNC) + _, exitRaw := gen.ExitNullEvent(2, componentBenchPID, componentBenchTID, types.SYS_EXIT_SYNC) + el := newComponentBenchEventLoop(componentBenchTID) + out := make(chan *event.Pair, 1) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + enterEv := types.NewNullEvent(enterRaw) + el.enterEvs[componentBenchTID] = event.NewPair(enterEv) + exitEv := types.NewNullEvent(exitRaw) + el.tracepointExited(exitEv, out) + (<-out).Recycle() + } +} + +func BenchmarkHandleOpenExit(b *testing.B) { + b.ReportAllocs() + + gen := benchutil.NewEventGenerator() + enterTemplate, _ := gen.EnterOpenEvent(1, componentBenchPID, componentBenchTID) + exitTemplate, _ := gen.ExitOpenEvent(2, componentBenchPID, componentBenchTID) + el := newComponentBenchEventLoop(componentBenchTID) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + enter := enterTemplate + enter.Time = uint64(i*2 + 1) + exit := exitTemplate + exit.Time = uint64(i*2 + 2) + ep := event.NewPair(&enter) + ep.ExitEv = &exit + if !el.handleOpenExit(ep, &enter) { + b.Fatal("handleOpenExit returned false") + } + ep.Recycle() + } +} + +func BenchmarkHandleFdExit(b *testing.B) { + b.ReportAllocs() + + gen := benchutil.NewEventGenerator() + enterTemplate, _ := gen.EnterFdEvent(1, componentBenchPID, componentBenchTID, 99, types.SYS_ENTER_READ) + exitTemplate, _ := gen.ExitRetEvent(2, componentBenchPID, componentBenchTID, types.SYS_EXIT_READ, 128) + el := newComponentBenchEventLoop(componentBenchTID) + el.fdState().set(99, file.NewFd(99, "/tmp/fd", syscall.O_RDONLY)) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + enter := enterTemplate + enter.Time = uint64(i*2 + 1) + exit := exitTemplate + exit.Time = uint64(i*2 + 2) + ep := event.NewPair(&enter) + ep.ExitEv = &exit + if !el.handleFdExit(ep, &enter) { + b.Fatal("handleFdExit returned false") + } + ep.Recycle() + } +} + +func BenchmarkHandlePathExit(b *testing.B) { + b.ReportAllocs() + + gen := benchutil.NewEventGenerator() + enterTemplate, _ := gen.EnterPathEvent(1, componentBenchPID, componentBenchTID, "/tmp/path", types.SYS_ENTER_MKDIR) + exitTemplate, _ := gen.ExitRetEvent(2, componentBenchPID, componentBenchTID, types.SYS_EXIT_MKDIR, 0) + el := newComponentBenchEventLoop(componentBenchTID) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + enter := enterTemplate + enter.Time = uint64(i*2 + 1) + exit := exitTemplate + exit.Time = uint64(i*2 + 2) + ep := event.NewPair(&enter) + ep.ExitEv = &exit + if !el.handlePathExit(ep, &enter) { + b.Fatal("handlePathExit returned false") + } + ep.Recycle() + } +} + +func BenchmarkHandleNameExit(b *testing.B) { + b.ReportAllocs() + + gen := benchutil.NewEventGenerator() + enterTemplate, _ := gen.EnterNameEvent(1, componentBenchPID, componentBenchTID, "/tmp/a", "/tmp/b", types.SYS_ENTER_RENAME) + exitTemplate, _ := gen.ExitRetEvent(2, componentBenchPID, componentBenchTID, types.SYS_EXIT_RENAME, 0) + el := newComponentBenchEventLoop(componentBenchTID) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + enter := enterTemplate + enter.Time = uint64(i*2 + 1) + exit := exitTemplate + exit.Time = uint64(i*2 + 2) + ep := event.NewPair(&enter) + ep.ExitEv = &exit + if !el.handleNameExit(ep, &enter) { + b.Fatal("handleNameExit returned false") + } + ep.Recycle() + } +} + +func BenchmarkHandleNullExit(b *testing.B) { + b.ReportAllocs() + + gen := benchutil.NewEventGenerator() + enterTemplate, _ := gen.EnterNullEvent(1, componentBenchPID, componentBenchTID, types.SYS_ENTER_SYNC) + exitTemplate, _ := gen.ExitNullEvent(2, componentBenchPID, componentBenchTID, types.SYS_EXIT_SYNC) + el := newComponentBenchEventLoop(componentBenchTID) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + enter := enterTemplate + enter.Time = uint64(i*2 + 1) + exit := exitTemplate + exit.Time = uint64(i*2 + 2) + ep := event.NewPair(&enter) + ep.ExitEv = &exit + if !el.handleNullExit(ep, &enter) { + b.Fatal("handleNullExit returned false") + } + ep.Recycle() + } +} + +func BenchmarkHandleFcntlExit(b *testing.B) { + b.ReportAllocs() + + gen := benchutil.NewEventGenerator() + enterTemplate, _ := gen.EnterFcntlEvent(1, componentBenchPID, componentBenchTID, 7, syscall.F_SETFL, syscall.O_NONBLOCK) + exitTemplate, _ := gen.ExitRetEvent(2, componentBenchPID, componentBenchTID, types.SYS_EXIT_FCNTL, 0) + el := newComponentBenchEventLoop(componentBenchTID) + el.fdState().set(7, file.NewFd(7, "/tmp/fcntl", syscall.O_RDONLY)) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + enter := enterTemplate + enter.Time = uint64(i*2 + 1) + exit := exitTemplate + exit.Time = uint64(i*2 + 2) + ep := event.NewPair(&enter) + ep.ExitEv = &exit + if !el.handleFcntlExit(ep, &enter) { + b.Fatal("handleFcntlExit returned false") + } + ep.Recycle() + } +} + +func BenchmarkHandleDup3Exit(b *testing.B) { + b.ReportAllocs() + + gen := benchutil.NewEventGenerator() + enterTemplate, _ := gen.EnterDup3Event(1, componentBenchPID, componentBenchTID, 9, syscall.O_CLOEXEC) + exitTemplate, _ := gen.ExitRetEvent(2, componentBenchPID, componentBenchTID, types.SYS_EXIT_DUP3, 10) + el := newComponentBenchEventLoop(componentBenchTID) + el.fdState().set(9, file.NewFd(9, "/tmp/dup3", syscall.O_RDONLY)) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + enter := enterTemplate + enter.Time = uint64(i*2 + 1) + exit := exitTemplate + exit.Time = uint64(i*2 + 2) + ep := event.NewPair(&enter) + ep.ExitEv = &exit + if !el.handleDup3Exit(ep, &enter) { + b.Fatal("handleDup3Exit returned false") + } + ep.Recycle() + } +} + +func BenchmarkFdTrackerGetSet(b *testing.B) { + b.ReportAllocs() + + tracker := newFDTracker(nil) + fdFile := file.NewFd(11, "/tmp/tracker", syscall.O_RDONLY) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + fd := int32(i % 1024) + tracker.set(fd, fdFile) + _, _ = tracker.get(fd) + } +} + +func BenchmarkCommResolverCachedHit(b *testing.B) { + b.ReportAllocs() + + resolver := newCommResolver(nil) + const tid = componentBenchTID + resolver.setCached(tid, "bench") + + b.ResetTimer() + for i := 0; i < b.N; i++ { + if resolver.comm(tid) == "" { + b.Fatal("unexpected cache miss") + } + } +} + +func BenchmarkEventPoolGetPut(b *testing.B) { + b.ReportAllocs() + + gen := benchutil.NewEventGenerator() + enterTemplate, _ := gen.EnterNullEvent(1, componentBenchPID, componentBenchTID, types.SYS_ENTER_SYNC) + exitTemplate, _ := gen.ExitNullEvent(2, componentBenchPID, componentBenchTID, types.SYS_EXIT_SYNC) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + enter := enterTemplate + enter.Time = uint64(i*2 + 1) + exit := exitTemplate + exit.Time = uint64(i*2 + 2) + ep := event.NewPair(&enter) + ep.ExitEv = &exit + ep.Recycle() + } +} + +func benchmarkDeserialize[T recyclable](b *testing.B, raw []byte, decode func([]byte) T) { + b.Helper() + b.ReportAllocs() + + b.ResetTimer() + for i := 0; i < b.N; i++ { + ev := decode(raw) + ev.Recycle() + } +} + +func newComponentBenchEventLoop(tids ...uint32) *eventLoop { + el := newEventLoop(eventLoopConfig{}) + for _, tid := range tids { + el.setCachedComm(tid, fmt.Sprintf("bench-%d", tid)) + } + return el +} |
