diff options
author | Matus Fabian <matfabia@cisco.com> | 2024-07-19 16:04:09 +0200 |
---|---|---|
committer | Florin Coras <florin.coras@gmail.com> | 2024-07-22 17:44:42 +0000 |
commit | e99d266612b53163d460f3ceab96934b1d961ac8 (patch) | |
tree | b0bf01f2802f2a7c282ff268b48bd412edfd3c98 /extras/hs-test/infra/vppinstance.go | |
parent | 7f163b682a57f42bd9b39a7f2d7e4c1c67df8386 (diff) |
hs-test: memory leak testing
add infra for memory leak testing
Type: test
Change-Id: I882e8dbb360597cdb82ad52682725f7d39b2df24
Signed-off-by: Matus Fabian <matfabia@cisco.com>
Diffstat (limited to 'extras/hs-test/infra/vppinstance.go')
-rw-r--r-- | extras/hs-test/infra/vppinstance.go | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/extras/hs-test/infra/vppinstance.go b/extras/hs-test/infra/vppinstance.go index d4f570046c7..dfb236b6725 100644 --- a/extras/hs-test/infra/vppinstance.go +++ b/extras/hs-test/infra/vppinstance.go @@ -2,6 +2,7 @@ package hst import ( "context" + "encoding/json" "fmt" "go.fd.io/govpp/binapi/ethernet_types" "io" @@ -97,6 +98,13 @@ type VppCpuConfig struct { SkipCores int } +type VppMemTrace struct { + Count int `json:"count"` + Size int `json:"bytes"` + Sample string `json:"sample"` + Traceback []string `json:"traceback"` +} + func (vpp *VppInstance) getSuite() *HstSuite { return vpp.Container.Suite } @@ -535,3 +543,83 @@ func (vpp *VppInstance) generateVPPCpuConfig() string { return c.Close().ToString() } + +// EnableMemoryTrace enables memory traces of VPP main-heap +func (vpp *VppInstance) EnableMemoryTrace() { + vpp.getSuite().Log(vpp.Vppctl("memory-trace on main-heap")) +} + +// GetMemoryTrace dumps memory traces for analysis +func (vpp *VppInstance) GetMemoryTrace() ([]VppMemTrace, error) { + var trace []VppMemTrace + vpp.getSuite().Log(vpp.Vppctl("save memory-trace trace.json")) + err := vpp.Container.GetFile("/tmp/trace.json", "/tmp/trace.json") + if err != nil { + return nil, err + } + fileBytes, err := os.ReadFile("/tmp/trace.json") + if err != nil { + return nil, err + } + err = json.Unmarshal(fileBytes, &trace) + if err != nil { + return nil, err + } + return trace, nil +} + +// memTracesSuppressCli filter out CLI related samples +func memTracesSuppressCli(traces []VppMemTrace) []VppMemTrace { + var filtered []VppMemTrace + for i := 0; i < len(traces); i++ { + isCli := false + for j := 0; j < len(traces[i].Traceback); j++ { + if strings.Contains(traces[i].Traceback[j], "unix_cli") { + isCli = true + break + } + } + if !isCli { + filtered = append(filtered, traces[i]) + } + } + return filtered +} + +// MemLeakCheck compares memory traces at different point in time, analyzes if memory leaks happen and produces report +func (vpp *VppInstance) MemLeakCheck(first, second []VppMemTrace) { + totalBytes := 0 + totalCounts := 0 + trace1 := memTracesSuppressCli(first) + trace2 := memTracesSuppressCli(second) + report := "" + for i := 0; i < len(trace2); i++ { + match := false + for j := 0; j < len(trace1); j++ { + if trace1[j].Sample == trace2[i].Sample { + if trace2[i].Size > trace1[j].Size { + deltaBytes := trace2[i].Size - trace1[j].Size + deltaCounts := trace2[i].Count - trace1[j].Count + report += fmt.Sprintf("grow %d byte(s) in %d allocation(s) from:\n", deltaBytes, deltaCounts) + for j := 0; j < len(trace2[i].Traceback); j++ { + report += fmt.Sprintf("\t#%d %s\n", j, trace2[i].Traceback[j]) + } + totalBytes += deltaBytes + totalCounts += deltaCounts + } + match = true + break + } + } + if !match { + report += fmt.Sprintf("\nleak of %d byte(s) in %d allocation(s) from:\n", trace2[i].Size, trace2[i].Count) + for j := 0; j < len(trace2[i].Traceback); j++ { + report += fmt.Sprintf("\t#%d %s\n", j, trace2[i].Traceback[j]) + } + totalBytes += trace2[i].Size + totalCounts += trace2[i].Count + } + } + summary := fmt.Sprintf("\nSUMMARY: %d byte(s) leaked in %d allocation(s)\n", totalBytes, totalCounts) + AddReportEntry(summary, report) +} |