forked from zyedidia/perforator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
perforator_test.go
109 lines (97 loc) · 2.37 KB
/
perforator_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package perforator
import (
"os/exec"
"runtime"
"testing"
"acln.ro/perf"
)
// Tests require permissions to run perf from user code (see the perf paranoid
// setting). The test also may depend on particular hardware characteristics.
// If the reported metrics are wildly different from the expected results, this
// probably indicates an error rather than different hardware, but I'm not
// sure.
// Try: `sudo sh -c 'echo 0 >/proc/sys/kernel/perf_event_paranoid'`
const near = 100000
func must(err error, t *testing.T) {
if err != nil {
t.Error(err)
}
}
func abs(a int) int {
if a < 0 {
return -a
}
return a
}
func buildGo(src, out string, dwarf, pie bool) error {
args := []string{"build"}
if !dwarf {
args = append(args, "-ldflags", "-w")
}
if pie {
args = append(args, "-buildmode=pie")
}
args = append(args, "-o", out, src)
cmd := exec.Command("go", args...)
_, err := cmd.Output()
return err
}
func check(target string, regions []string, events []perf.Configurator, expected TotalMetrics, t *testing.T) {
evs := Events{
Base: events,
}
opts := perf.Options{
ExcludeKernel: true,
ExcludeHypervisor: true,
}
total, err := Run(target, []string{}, regions, evs, opts, func() MetricsWriter { return nil })
must(err, t)
for i, v := range total {
nm := expected[i]
if len(nm.Results) != len(v.Results) {
t.Errorf("unexpected result length %d", len(v.Results))
}
for i, result := range v.Results {
if abs(int(result.Value)-int(nm.Results[i].Value)) > near {
t.Errorf("unexpected result for %s: %d", nm.Name, result.Value)
}
}
}
}
// Tests a single region with PIE active (the test target is a Go program, so
// it also tests multithreading support, since the Go runtime automatically
// spawns threads).
func TestSingleRegion(t *testing.T) {
runtime.LockOSThread()
must(buildGo("test/sum.go", "test/sum", true, true), t)
regions := []string{
"main.sum",
}
events := []perf.Configurator{
perf.Instructions,
perf.BranchInstructions,
perf.BranchMisses,
}
expected := TotalMetrics{
NamedMetrics{
Name: "main.sum",
Metrics: Metrics{
Results: []Result{
{
Label: "instructions",
Value: 70000000,
},
{
Label: "branch-instructions",
Value: 10000000,
},
{
Label: "branch-misses",
Value: 10,
},
},
},
},
}
check("test/sum", regions, events, expected, t)
}