diff options
Diffstat (limited to 'internal/statsengine')
| -rw-r--r-- | internal/statsengine/engine.go | 71 | ||||
| -rw-r--r-- | internal/statsengine/engine_reset_test.go | 4 | ||||
| -rw-r--r-- | internal/statsengine/engine_test.go | 57 | ||||
| -rw-r--r-- | internal/statsengine/snapshot.go | 18 |
4 files changed, 93 insertions, 57 deletions
diff --git a/internal/statsengine/engine.go b/internal/statsengine/engine.go index 7d85e96..85017fd 100644 --- a/internal/statsengine/engine.go +++ b/internal/statsengine/engine.go @@ -47,13 +47,14 @@ type Engine struct { startedAt time.Time topN int - totalSyscalls uint64 - totalErrors uint64 - totalBytes uint64 - totalReadBytes uint64 - totalWriteBytes uint64 - totalLatency uint64 - totalGap uint64 + totalSyscalls uint64 + totalErrors uint64 + totalBytes uint64 + totalAddressSpaceBytes uint64 + totalReadBytes uint64 + totalWriteBytes uint64 + totalLatency uint64 + totalGap uint64 syscalls *syscallAccumulator families *familyAccumulator @@ -70,13 +71,14 @@ type snapshotInputs struct { now time.Time startedAt time.Time - totalSyscalls uint64 - totalErrors uint64 - totalBytes uint64 - totalReadBytes uint64 - totalWriteBytes uint64 - totalLatency uint64 - totalGap uint64 + totalSyscalls uint64 + totalErrors uint64 + totalBytes uint64 + totalAddressSpaceBytes uint64 + totalReadBytes uint64 + totalWriteBytes uint64 + totalLatency uint64 + totalGap uint64 latencySeries []float64 gapSeries []float64 @@ -130,6 +132,7 @@ func (e *Engine) Reset() { e.totalSyscalls = 0 e.totalErrors = 0 e.totalBytes = 0 + e.totalAddressSpaceBytes = 0 e.totalReadBytes = 0 e.totalWriteBytes = 0 e.totalLatency = 0 @@ -157,6 +160,7 @@ func (e *Engine) Ingest(pair *event.Pair) { now := e.now() e.totalSyscalls++ e.totalBytes += pair.Bytes + e.totalAddressSpaceBytes += pair.AddressSpaceBytes e.totalLatency += pair.Duration e.totalGap += pair.DurationToPrev @@ -209,24 +213,25 @@ func (e *Engine) captureSnapshotInputs() snapshotInputs { defer e.mu.Unlock() return snapshotInputs{ - now: e.now(), - startedAt: e.startedAt, - totalSyscalls: e.totalSyscalls, - totalErrors: e.totalErrors, - totalBytes: e.totalBytes, - totalReadBytes: e.totalReadBytes, - totalWriteBytes: e.totalWriteBytes, - totalLatency: e.totalLatency, - totalGap: e.totalGap, - latencySeries: e.latencySeries.Values(), - gapSeries: e.gapSeries.Values(), - throughputSeries: e.throughputSeries.Values(), - syscalls: e.syscalls.snapshotInputs(), - families: e.families.snapshotInputs(), - files: e.files.snapshotInputs(), - processes: e.processes.snapshotInputs(), - latencyHist: e.latencyHist.snapshotInputs(), - gapHist: e.gapHist.snapshotInputs(), + now: e.now(), + startedAt: e.startedAt, + totalSyscalls: e.totalSyscalls, + totalErrors: e.totalErrors, + totalBytes: e.totalBytes, + totalAddressSpaceBytes: e.totalAddressSpaceBytes, + totalReadBytes: e.totalReadBytes, + totalWriteBytes: e.totalWriteBytes, + totalLatency: e.totalLatency, + totalGap: e.totalGap, + latencySeries: e.latencySeries.Values(), + gapSeries: e.gapSeries.Values(), + throughputSeries: e.throughputSeries.Values(), + syscalls: e.syscalls.snapshotInputs(), + families: e.families.snapshotInputs(), + files: e.files.snapshotInputs(), + processes: e.processes.snapshotInputs(), + latencyHist: e.latencyHist.snapshotInputs(), + gapHist: e.gapHist.snapshotInputs(), } } @@ -287,8 +292,10 @@ func populateSnapshotFields(snap *Snapshot, in snapshotInputs, elapsed time.Dura snap.TotalSyscalls = in.totalSyscalls snap.TotalErrors = in.totalErrors snap.TotalBytes = in.totalBytes + snap.TotalAddressSpaceBytes = in.totalAddressSpaceBytes snap.SyscallRatePerSec = safeRate(in.totalSyscalls, rateDiv) snap.ErrorRatePerSec = safeRate(in.totalErrors, rateDiv) + snap.AddressSpaceBytesPerSec = safeRate(in.totalAddressSpaceBytes, rateDiv) snap.ReadBytesPerSec = safeRate(in.totalReadBytes, rateDiv) snap.WriteBytesPerSec = safeRate(in.totalWriteBytes, rateDiv) snap.LatencyMeanNs = safeMean(in.totalLatency, in.totalSyscalls) diff --git a/internal/statsengine/engine_reset_test.go b/internal/statsengine/engine_reset_test.go index c09c059..5e8388a 100644 --- a/internal/statsengine/engine_reset_test.go +++ b/internal/statsengine/engine_reset_test.go @@ -9,7 +9,7 @@ import ( func TestEngineResetClearsAccumulatedStats(t *testing.T) { e := NewEngine(8) - e.Ingest(newEnginePair(types.SYS_ENTER_READ, 7, types.READ_CLASSIFIED, "test", 1, "/tmp/a", 7, 1000, 50)) + e.Ingest(newEnginePair(types.SYS_ENTER_READ, 7, types.READ_CLASSIFIED, "test", 1, "/tmp/a", 7, 512, 1000, 50)) before, err := e.Snapshot() if err != nil { t.Fatalf("unexpected snapshot error: %v", err) @@ -23,7 +23,7 @@ func TestEngineResetClearsAccumulatedStats(t *testing.T) { if err != nil { t.Fatalf("unexpected snapshot error after reset: %v", err) } - if after.TotalSyscalls != 0 || after.TotalBytes != 0 || after.TotalErrors != 0 { + if after.TotalSyscalls != 0 || after.TotalBytes != 0 || after.TotalAddressSpaceBytes != 0 || after.TotalErrors != 0 { t.Fatalf("expected totals cleared after reset, got %+v", after) } if after.Elapsed > 2*time.Second { diff --git a/internal/statsengine/engine_test.go b/internal/statsengine/engine_test.go index 9543405..0500d20 100644 --- a/internal/statsengine/engine_test.go +++ b/internal/statsengine/engine_test.go @@ -26,11 +26,11 @@ func TestEngineIngestAndSnapshotIntegration(t *testing.T) { clock := &fakeClock{now: time.Unix(1000, 0)} engine := newEngineWithClock(2, clock.Now) - engine.Ingest(newEnginePair(types.SYS_ENTER_READ, 100, types.READ_CLASSIFIED, "proc-a", 1, "/tmp/a", 100, 10, 3)) + engine.Ingest(newEnginePair(types.SYS_ENTER_READ, 100, types.READ_CLASSIFIED, "proc-a", 1, "/tmp/a", 100, 0, 10, 3)) clock.Advance(500 * time.Millisecond) - engine.Ingest(newEnginePair(types.SYS_ENTER_WRITE, -1, types.WRITE_CLASSIFIED, "proc-a", 1, "/tmp/a", 50, 20, 5)) + engine.Ingest(newEnginePair(types.SYS_ENTER_WRITE, -1, types.WRITE_CLASSIFIED, "proc-a", 1, "/tmp/a", 50, 0, 20, 5)) clock.Advance(500 * time.Millisecond) - engine.Ingest(newEnginePair(types.SYS_ENTER_COPY_FILE_RANGE, 80, types.TRANSFER_CLASSIFIED, "proc-b", 2, "/tmp/b", 20, 40, 8)) + engine.Ingest(newEnginePair(types.SYS_ENTER_COPY_FILE_RANGE, 80, types.TRANSFER_CLASSIFIED, "proc-b", 2, "/tmp/b", 20, 0, 40, 8)) clock.Advance(1 * time.Second) snap, err := engine.Snapshot() @@ -44,6 +44,9 @@ func TestEngineIngestAndSnapshotIntegration(t *testing.T) { if snap.TotalSyscalls != 3 || snap.TotalErrors != 1 || snap.TotalBytes != 170 { t.Fatalf("unexpected totals: syscalls=%d errors=%d bytes=%d", snap.TotalSyscalls, snap.TotalErrors, snap.TotalBytes) } + if snap.TotalAddressSpaceBytes != 0 { + t.Fatalf("unexpected address-space total: %d", snap.TotalAddressSpaceBytes) + } if snap.LatencyMeanNs != (10+20+40)/3.0 { t.Fatalf("unexpected latency mean: %v", snap.LatencyMeanNs) } @@ -89,10 +92,10 @@ func TestEngineAggregatesSyscallFamilies(t *testing.T) { clock := &fakeClock{now: time.Unix(3000, 0)} engine := newEngineWithClock(10, clock.Now) - engine.Ingest(newEnginePair(types.SYS_ENTER_EPOLL_WAIT, 0, types.UNCLASSIFIED, "poller", 1, "", 0, 100, 1)) - engine.Ingest(newEnginePair(types.SYS_ENTER_POLL, -1, types.UNCLASSIFIED, "poller", 1, "", 0, 300, 2)) - engine.Ingest(newEnginePair(types.SYS_ENTER_GETPID, 0, types.UNCLASSIFIED, "proc", 2, "", 0, 50, 3)) - engine.Ingest(newEnginePair(types.SYS_ENTER_READ, 4, types.READ_CLASSIFIED, "reader", 3, "/tmp/a", 4, 25, 4)) + engine.Ingest(newEnginePair(types.SYS_ENTER_EPOLL_WAIT, 0, types.UNCLASSIFIED, "poller", 1, "", 0, 0, 100, 1)) + engine.Ingest(newEnginePair(types.SYS_ENTER_POLL, -1, types.UNCLASSIFIED, "poller", 1, "", 0, 0, 300, 2)) + engine.Ingest(newEnginePair(types.SYS_ENTER_GETPID, 0, types.UNCLASSIFIED, "proc", 2, "", 0, 0, 50, 3)) + engine.Ingest(newEnginePair(types.SYS_ENTER_READ, 4, types.READ_CLASSIFIED, "reader", 3, "/tmp/a", 4, 0, 25, 4)) clock.Advance(time.Second) snap, err := engine.Snapshot() @@ -148,6 +151,29 @@ func TestEngineSnapshotWithNoEvents(t *testing.T) { } } +func TestEngineTracksAddressSpaceBytesSeparately(t *testing.T) { + clock := &fakeClock{now: time.Unix(4000, 0)} + engine := newEngineWithClock(10, clock.Now) + + engine.Ingest(newEnginePair(types.SYS_ENTER_MUNMAP, 0, types.UNCLASSIFIED, "proc", 1, "", 0, 4096, 10, 1)) + engine.Ingest(newEnginePair(types.SYS_ENTER_MREMAP, 0, types.UNCLASSIFIED, "proc", 1, "", 0, 8192, 20, 2)) + clock.Advance(2 * time.Second) + + snap, err := engine.Snapshot() + if err != nil { + t.Fatalf("Snapshot() error = %v", err) + } + if snap.TotalBytes != 0 { + t.Fatalf("TotalBytes = %d, want 0 for non-IO memory operations", snap.TotalBytes) + } + if snap.TotalAddressSpaceBytes != 12288 { + t.Fatalf("TotalAddressSpaceBytes = %d, want 12288", snap.TotalAddressSpaceBytes) + } + if math.Abs(snap.AddressSpaceBytesPerSec-6144.0) > 1e-9 { + t.Fatalf("AddressSpaceBytesPerSec = %v, want 6144", snap.AddressSpaceBytesPerSec) + } +} + func TestEngineTrendDetection(t *testing.T) { if got := detectTrend(make([]float64, trendWindowSlots*2)); got.Direction != TrendStable { t.Fatalf("expected stable for flat data, got %+v", got) @@ -175,14 +201,15 @@ func TestEngineTrendDetection(t *testing.T) { } } -func newEnginePair(traceID types.TraceId, ret int64, retType uint32, comm string, pid uint32, path string, bytes uint64, duration uint64, gap uint64) *event.Pair { +func newEnginePair(traceID types.TraceId, ret int64, retType uint32, comm string, pid uint32, path string, bytes uint64, addressSpaceBytes uint64, duration uint64, gap uint64) *event.Pair { return &event.Pair{ - EnterEv: &types.RetEvent{TraceId: traceID, Pid: pid}, - ExitEv: &types.RetEvent{TraceId: traceID, Pid: pid, Ret: ret, RetType: retType}, - Comm: comm, - Duration: duration, - DurationToPrev: gap, - Bytes: bytes, - File: file.NewFd(3, path, -1), + EnterEv: &types.RetEvent{TraceId: traceID, Pid: pid}, + ExitEv: &types.RetEvent{TraceId: traceID, Pid: pid, Ret: ret, RetType: retType}, + Comm: comm, + Duration: duration, + DurationToPrev: gap, + Bytes: bytes, + AddressSpaceBytes: addressSpaceBytes, + File: file.NewFd(3, path, -1), } } diff --git a/internal/statsengine/snapshot.go b/internal/statsengine/snapshot.go index 859cd2e..bec92fb 100644 --- a/internal/statsengine/snapshot.go +++ b/internal/statsengine/snapshot.go @@ -30,14 +30,16 @@ type Snapshot struct { GeneratedAt time.Time Elapsed time.Duration - TotalSyscalls uint64 - TotalErrors uint64 - TotalBytes uint64 - - SyscallRatePerSec float64 - ErrorRatePerSec float64 - ReadBytesPerSec float64 - WriteBytesPerSec float64 + TotalSyscalls uint64 + TotalErrors uint64 + TotalBytes uint64 + TotalAddressSpaceBytes uint64 + + SyscallRatePerSec float64 + ErrorRatePerSec float64 + AddressSpaceBytesPerSec float64 + ReadBytesPerSec float64 + WriteBytesPerSec float64 LatencyMeanNs float64 GapMeanNs float64 |
