diff options
Diffstat (limited to 'internal/benchutil')
| -rw-r--r-- | internal/benchutil/eventmix.go | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/internal/benchutil/eventmix.go b/internal/benchutil/eventmix.go new file mode 100644 index 0000000..1057c0e --- /dev/null +++ b/internal/benchutil/eventmix.go @@ -0,0 +1,231 @@ +package benchutil + +import ( + "fmt" + "math/rand" + "syscall" + + "ior/internal/types" +) + +const ( + defaultMixSeed int64 = 1 + defaultStreamTime uint64 = 1 + defaultBasePid uint32 = 1000 + defaultBaseTid uint32 = 2000 + defaultBaseFd int32 = 64 +) + +type MixEvent uint8 + +const ( + MixRead MixEvent = iota + 1 + MixWrite + MixOpen + MixClose + MixStat + MixSync + MixFsync + MixAccess + MixMkdir + MixUnlink + MixRename + MixLink + MixFcntl + MixDup3 + MixOpenByHandleAt +) + +type MixEntry struct { + Event MixEvent + Weight int +} + +type EventMix struct { + Entries []MixEntry + Seed int64 +} + +var ReadHeavy = EventMix{ + Entries: []MixEntry{ + {Event: MixRead, Weight: 30}, + {Event: MixWrite, Weight: 30}, + {Event: MixOpen, Weight: 10}, + {Event: MixClose, Weight: 10}, + {Event: MixStat, Weight: 10}, + {Event: MixSync, Weight: 10}, + }, + Seed: defaultMixSeed, +} + +var WriteHeavy = EventMix{ + Entries: []MixEntry{ + {Event: MixWrite, Weight: 40}, + {Event: MixFsync, Weight: 20}, + {Event: MixRead, Weight: 15}, + {Event: MixOpen, Weight: 5}, + {Event: MixClose, Weight: 5}, + {Event: MixStat, Weight: 15}, + }, + Seed: defaultMixSeed, +} + +var MetadataHeavy = EventMix{ + Entries: []MixEntry{ + {Event: MixStat, Weight: 15}, + {Event: MixAccess, Weight: 15}, + {Event: MixOpen, Weight: 12}, + {Event: MixClose, Weight: 13}, + {Event: MixMkdir, Weight: 10}, + {Event: MixUnlink, Weight: 10}, + {Event: MixRename, Weight: 8}, + {Event: MixLink, Weight: 7}, + {Event: MixRead, Weight: 5}, + {Event: MixWrite, Weight: 5}, + }, + Seed: defaultMixSeed, +} + +var DiverseAllTypes = EventMix{ + Entries: []MixEntry{ + {Event: MixOpen, Weight: 1}, + {Event: MixRead, Weight: 1}, + {Event: MixSync, Weight: 1}, + {Event: MixStat, Weight: 1}, + {Event: MixRename, Weight: 1}, + {Event: MixFcntl, Weight: 1}, + {Event: MixDup3, Weight: 1}, + {Event: MixOpenByHandleAt, Weight: 1}, + {Event: MixClose, Weight: 1}, + }, + Seed: defaultMixSeed, +} + +func (m EventMix) GenerateStream(gen EventGenerator, n, numThreads int) [][]byte { + if n <= 0 { + return nil + } + + threadCount := numThreads + if threadCount < 1 { + threadCount = 1 + } + + entries := m.activeEntries() + totalWeight := sumWeights(entries) + rng := rand.New(rand.NewSource(m.seed())) + + stream := make([][]byte, 0, n*2) + nextTime := defaultStreamTime + for i := 0; i < n; i++ { + threadIdx := i % threadCount + pid := defaultBasePid + uint32(threadIdx) + tid := defaultBaseTid + uint32(threadIdx) + fd := fdFor(threadIdx, i) + event := choose(entries, totalWeight, rng) + enter, exit := event.pair(gen, nextTime, pid, tid, fd, i) + stream = append(stream, enter, exit) + nextTime += gen.pairDelta() + 1 + } + + return stream +} + +func choose(entries []MixEntry, totalWeight int, rng *rand.Rand) MixEvent { + if totalWeight <= 0 { + return MixRead + } + + roll := rng.Intn(totalWeight) + for _, entry := range entries { + if entry.Weight <= 0 { + continue + } + if roll < entry.Weight { + return entry.Event + } + roll -= entry.Weight + } + return entries[len(entries)-1].Event +} + +func fdFor(threadIdx, seq int) int32 { + return defaultBaseFd + int32(threadIdx*100+seq%100) +} + +func (m EventMix) activeEntries() []MixEntry { + active := make([]MixEntry, 0, len(m.Entries)) + for _, entry := range m.Entries { + if entry.Weight > 0 { + active = append(active, entry) + } + } + if len(active) == 0 { + return DiverseAllTypes.Entries + } + return active +} + +func (m EventMix) seed() int64 { + if m.Seed == 0 { + return defaultMixSeed + } + return m.Seed +} + +func sumWeights(entries []MixEntry) int { + total := 0 + for _, entry := range entries { + total += entry.Weight + } + return total +} + +func (e MixEvent) pair(gen EventGenerator, time uint64, pid, tid uint32, fd int32, seq int) ([]byte, []byte) { + switch e { + case MixRead: + return gen.FdPair(time, pid, tid, fd, types.SYS_ENTER_READ, types.SYS_EXIT_READ, 128) + case MixWrite: + return gen.FdPair(time, pid, tid, fd, types.SYS_ENTER_WRITE, types.SYS_EXIT_WRITE, 256) + case MixOpen: + return gen.OpenPair(time, pid, tid) + case MixClose: + _, enter := gen.EnterFdEvent(time, pid, tid, fd, types.SYS_ENTER_CLOSE) + _, exit := gen.ExitFdEvent(time+gen.pairDelta(), pid, tid, fd, types.SYS_EXIT_CLOSE) + return enter, exit + case MixStat: + path := fmt.Sprintf("/tmp/ior-stat-%d-%d", tid, seq) + return gen.PathPair(time, pid, tid, path, types.SYS_ENTER_NEWSTAT, types.SYS_EXIT_NEWSTAT, 0) + case MixSync: + return gen.NullPair(time, pid, tid, types.SYS_ENTER_SYNC, types.SYS_EXIT_SYNC) + case MixFsync: + return gen.FdPair(time, pid, tid, fd, types.SYS_ENTER_FSYNC, types.SYS_EXIT_FSYNC, 0) + case MixAccess: + path := fmt.Sprintf("/tmp/ior-access-%d-%d", tid, seq) + return gen.PathPair(time, pid, tid, path, types.SYS_ENTER_ACCESS, types.SYS_EXIT_ACCESS, 0) + case MixMkdir: + path := fmt.Sprintf("/tmp/ior-mkdir-%d-%d", tid, seq) + return gen.PathPair(time, pid, tid, path, types.SYS_ENTER_MKDIR, types.SYS_EXIT_MKDIR, 0) + case MixUnlink: + path := fmt.Sprintf("/tmp/ior-unlink-%d-%d", tid, seq) + return gen.PathPair(time, pid, tid, path, types.SYS_ENTER_UNLINK, types.SYS_EXIT_UNLINK, 0) + case MixRename: + oldname := fmt.Sprintf("/tmp/ior-old-%d-%d", tid, seq) + newname := fmt.Sprintf("/tmp/ior-new-%d-%d", tid, seq) + return gen.NamePair(time, pid, tid, oldname, newname, types.SYS_ENTER_RENAME, types.SYS_EXIT_RENAME, 0) + case MixLink: + oldname := fmt.Sprintf("/tmp/ior-link-old-%d-%d", tid, seq) + newname := fmt.Sprintf("/tmp/ior-link-new-%d-%d", tid, seq) + return gen.NamePair(time, pid, tid, oldname, newname, types.SYS_ENTER_LINK, types.SYS_EXIT_LINK, 0) + case MixFcntl: + return gen.FcntlPair(time, pid, tid, uint32(fd), syscall.F_SETFL, syscall.O_NONBLOCK, types.SYS_EXIT_FCNTL, 0) + case MixDup3: + return gen.Dup3Pair(time, pid, tid, fd, syscall.O_CLOEXEC, types.SYS_EXIT_DUP3, int64(fd+1)) + case MixOpenByHandleAt: + _, enter := gen.EnterOpenByHandleAtEvent(time, pid, tid, syscall.O_RDWR) + _, exit := gen.ExitRetEvent(time+gen.pairDelta(), pid, tid, types.SYS_EXIT_OPEN_BY_HANDLE_AT, int64(fd)) + return enter, exit + default: + return gen.NullPair(time, pid, tid, types.SYS_ENTER_SYNC, types.SYS_EXIT_SYNC) + } +} |
