diff options
| author | Paul Buetow <paul@buetow.org> | 2025-04-06 21:59:54 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-04-06 21:59:54 +0300 |
| commit | 95e3477875c0e31e0c6907ab6afe4ce48fb37391 (patch) | |
| tree | a4965cd66b377fbe18d54d66243227d59399fa3e | |
| parent | 6ca3491f421e8506fa3ff832a51b3a7d8a5c7ef6 (diff) | |
more refined iod format
| -rw-r--r-- | internal/flamegraph/counter.go | 3 | ||||
| -rw-r--r-- | internal/flamegraph/iordata.go | 40 | ||||
| -rw-r--r-- | internal/flamegraph/iordata_test.go | 74 |
3 files changed, 95 insertions, 22 deletions
diff --git a/internal/flamegraph/counter.go b/internal/flamegraph/counter.go index 98ac035..bc30df0 100644 --- a/internal/flamegraph/counter.go +++ b/internal/flamegraph/counter.go @@ -4,12 +4,13 @@ type counter struct { count uint64 duration uint64 durationToPrev uint64 - // bytes uint64 TODO implement + bytes uint64 // TODO: implement } func (c counter) add(other counter) counter { c.count += other.count c.duration += other.duration c.durationToPrev += other.durationToPrev + c.bytes += other.bytes return c } diff --git a/internal/flamegraph/iordata.go b/internal/flamegraph/iordata.go index 1cf1f0a..2d4b46b 100644 --- a/internal/flamegraph/iordata.go +++ b/internal/flamegraph/iordata.go @@ -1,17 +1,20 @@ package flamegraph import ( - "encoding/json" "fmt" "ior/internal/event" "ior/internal/flags" "ior/internal/types" + "iter" "os" + "strings" "time" "github.com/DataDog/zstd" ) +const recordSeparator = " ␞ " + type pathType = string type traceIdType = types.TraceId type commType = string @@ -123,6 +126,37 @@ func (iod iorData) commit() error { encoder := zstd.NewWriter(file) defer encoder.Close() - jsonEncoder := json.NewEncoder(encoder) - return jsonEncoder.Encode(iod.paths) + // Write the data to a .txt file one line one entry and with a separator ␞, don't use JSON + return nil +} + +func (iod iorData) lines() iter.Seq[string] { + return func(yield func(string) bool) { + for path, traceIdMap := range iod.paths { + for traceId, commMap := range traceIdMap { + for comm, pidMap := range commMap { + for pid, tidMap := range pidMap { + for tid, flagsMap := range tidMap { + for flags, cnt := range flagsMap { + joinedStr := strings.Join([]string{ + path, + traceId.String(), + comm, + fmt.Sprint(pid), + fmt.Sprint(tid), + flags, + fmt.Sprintf("%d %d %d %d", cnt.count, cnt.duration, cnt.durationToPrev, cnt.bytes), + }, + recordSeparator) + if !yield(joinedStr) { + // Stop iteration if yield returns false + return + } + } + } + } + } + } + } + } } diff --git a/internal/flamegraph/iordata_test.go b/internal/flamegraph/iordata_test.go index f938a49..7496067 100644 --- a/internal/flamegraph/iordata_test.go +++ b/internal/flamegraph/iordata_test.go @@ -1,17 +1,14 @@ package flamegraph import ( + "ior/internal/types" "testing" ) -func TestAdd(t *testring.T) { - -} - func TestAddPath(t *testing.T) { iod := newIorData() path := pathType("testPath") - traceId := traceIdType(1) + traceId := types.SYS_ENTER_OPENAT comm := commType("testComm") pid := pidType(1234) tid := tidType(5678) @@ -36,28 +33,29 @@ func TestAddPath(t *testing.T) { func TestMerge(t *testing.T) { rdwrFlag := flagsType("O_RDWR") roFlag := flagsType("O_RDONLY") + traceId := types.SYS_ENTER_OPENAT // Initialize two iorData instances with sample data iod1 := iorData{paths: pathMap{ - "path1": {1: {"comm1": {100: {1000: {rdwrFlag: counter{ + "path1": {traceId: {"comm1": {100: {1000: {rdwrFlag: counter{ count: 10, duration: 1000, durationToPrev: 100, }}}}}}}} iod2 := iorData{paths: pathMap{ - "path1": {1: {"comm1": {100: {1000: {roFlag: counter{ + "path1": {traceId: {"comm1": {100: {1000: {roFlag: counter{ count: 20, duration: 2000, durationToPrev: 200, }}}}}}}} iod3 := iorData{paths: pathMap{ - "path2": {1: {"comm2": {101: {1000: {roFlag: counter{ + "path2": {traceId: {"comm2": {101: {1000: {roFlag: counter{ count: 20, duration: 2000, durationToPrev: 200, }}}}}}}} iod4 := iorData{paths: pathMap{ - "path2": {1: {"comm2": {101: {1000: {roFlag: counter{ + "path2": {traceId: {"comm2": {101: {1000: {roFlag: counter{ count: 40, duration: 4000, durationToPrev: 400, @@ -69,16 +67,56 @@ func TestMerge(t *testing.T) { merged := iod1.merge(iod2).merge(iod3).merge(iod4) t.Log(merged) - // Check if the merged data contains data from both iod1 and iod2 - if len(merged.paths) != 2 { - t.Errorf("Expected 2 paths, got %d", len(merged.paths)) - } + t.Run("Merged correctly", func(t *testing.T) { + if len(merged.paths) != 2 { + t.Errorf("Expected 2 paths, got %d", len(merged.paths)) + } + if merged.paths["path1"][traceId]["comm1"][100][1000][flagsType("O_RDWR")].count != 10 { + t.Errorf("Expected counter 10, got %d", merged.paths["path1"][1]["comm1"][100][1000][flagsType("O_RDWR")].count) + } + if merged.paths["path2"][traceId]["comm2"][101][1000][roFlag].count != 60 { + t.Errorf("Expected counter 60, got %d", merged.paths["path2"][1]["comm2"][101][1000][roFlag].count) + } + }) - if merged.paths["path1"][1]["comm1"][100][1000][flagsType("O_RDWR")].count != 10 { - t.Errorf("Expected counter 10, got %d", merged.paths["path1"][1]["comm1"][100][1000][flagsType("O_RDWR")].count) - } + t.Run("Iterate over lines", func(t *testing.T) { + expectedLines := []string{ + "path1 ␞ enter_openat ␞ comm1 ␞ 100 ␞ 1000 ␞ O_RDWR ␞ 10 1000 100 0", + "path1 ␞ enter_openat ␞ comm1 ␞ 100 ␞ 1000 ␞ O_RDONLY ␞ 20 2000 200 0", + "path2 ␞ enter_openat ␞ comm2 ␞ 101 ␞ 1000 ␞ O_RDONLY ␞ 60 6000 600 0", + } + var lines []string - if merged.paths["path2"][1]["comm2"][101][1000][roFlag].count != 60 { - t.Errorf("Expected counter 60, got %d", merged.paths["path2"][1]["comm2"][101][1000][roFlag].count) + for line := range merged.lines() { + t.Log(line) + lines = append(lines, line) + } + + if len(lines) != len(expectedLines) { + t.Errorf("Expected %d lines, got %d", len(expectedLines), len(lines)) + } + + if !bothArraysHaveSameElements(lines, expectedLines) { + t.Errorf("Expected lines %v, got %v", expectedLines, lines) + } + }) +} + +func bothArraysHaveSameElements(a, b []string) bool { + if len(a) != len(b) { + return false + } + for _, v1 := range a { + found := false + for _, v2 := range b { + if v1 == v2 { + found = true + break + } + } + if !found { + return false + } } + return true } |
