summaryrefslogtreecommitdiff
path: root/internal/statsengine
diff options
context:
space:
mode:
Diffstat (limited to 'internal/statsengine')
-rw-r--r--internal/statsengine/engine.go71
-rw-r--r--internal/statsengine/engine_reset_test.go4
-rw-r--r--internal/statsengine/engine_test.go57
-rw-r--r--internal/statsengine/snapshot.go18
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