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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
Build.dependencies({"git", "make", "rustc", "cargo"})
Build.metric(
"nightly version",
string.gsub(Build.check_output({"rustc", "--version"}).stdout, '^%s*(.*)%s*$', '%1')
)
Step.start("crate")
Step.push("build")
Build.run({"cargo", "build"}) -- `run` automatically records stdout and stderr to log files named after the command
Step.advance("test")
Build.run({"cargo", "test"}, {name="test stdlib/fmt"}) -- artifacts are stored under `name` if that's present
Build.run({"cargo", "test", "--no-default-features"}, {name="test nostdlib/nofmt"})
Build.run({"cargo", "test", "--no-default-features", "--features", "fmt"}, {name="test nostdlib/fmt"})
Build.run({"cargo", "test", "--no-default-features", "--features", "std"}, {name="test nostdlib/std"})
Build.run({"cargo", "test", "--no-default-features", "--features", "std,fmt"}, {name="test nostdlib/std+fmt"})
-- the interesting benchmarking happens through disas-bench, but the in-tree capstone bench isn't gone *quite* yet.
Step.start("bench")
Build.run({"cargo", "test", "--no-default-features", "capstone_bench"}, {name="bench smoketest"})
Step.start("ffi")
Step.push("build")
Build.run({"rustup", "component", "add", "rust-src", "--toolchain", "nightly-x86_64-unknown-linux-gnu"})
Build.run({"cargo", "+nightly", "build", "-Z", "build-std", "--release", "--no-default-features", "--target", Build.environment.vars.native_rust_triple}, {cwd="ffi/"})
Step.advance("validate")
sopath = "ffi/target/" .. Build.environment.vars.native_rust_triple .. "/release/libyaxpeax_x86_ffi_long_mode.so"
Build.run({"ls", sopath})
Build.metric(
"libyaxpeax_x86_ffi_long_mode.so size (bytes)",
Build.environment.size(sopath)
)
Build.artifact(sopath)
-- now run some perf numbers...
Step.start("perf")
Build.run({"git", "clone", "https://github.com/iximeow/disas-bench.git", "disas-bench"})
Build.run({"git", "submodule", "update", "--recursive", "--init"}, {cwd="disas-bench"})
Build.run({"git", "remote", "add", "dev", "../../.."}, {cwd="disas-bench/libs/yaxpeax"})
-- there might not be a ref for the current commit, if building locally and this is some untagged HEAD
-- so fetch by sha from ../../.. 'cause it *better* be the current commit.
Build.run({"git", "fetch", "dev", Build.sha}, {cwd="disas-bench/libs/yaxpeax"})
Build.run({"git", "checkout", Build.sha}, {cwd="disas-bench/libs/yaxpeax"})
Step.push("build")
Build.run({"make", "make-bench-yaxpeax"}, {cwd="disas-bench/bench/yaxpeax"})
Build.metric(
"bench-yaxpeax-fmt size (bytes)",
Build.environment.size("disas-bench/bench/yaxpeax/bench-yaxpeax-fmt")
)
Build.metric(
"bench-yaxpeax-no-fmt size (bytes)",
Build.environment.size("disas-bench/bench/yaxpeax/bench-yaxpeax-no-fmt")
)
-- fmt
Step.advance("fmt")
bench_start = Build.now_ms()
Build.run({"./bench-yaxpeax-fmt", "20", "0x400", "0x2460400", "../../input/xul.dll"}, {cwd="disas-bench/bench/yaxpeax"})
bench_end = Build.now_ms()
Build.metric("fmt runtime (ms)", bench_end - bench_start)
-- no-fmt
Step.advance("no-fmt")
bench_start = Build.now_ms()
Build.run({"./bench-yaxpeax-no-fmt", "20", "0x400", "0x2460400", "../../input/xul.dll"}, {cwd="disas-bench/bench/yaxpeax"})
bench_end = Build.now_ms()
Build.metric("no-fmt runtime (ms)", bench_end - bench_start)
-- perf
if Build.environment.has("perf") then
perf_setting = Build.check_output({"cat", "/proc/sys/kernel/perf_event_paranoid"})
-- TODO: roll this up into some perf tools in the lua env. for now, if perf
-- event paranoid is >2 then we'll probably just fail the build trying and
-- failing to run perf.
perf_out = Build.check_output({"perf", "stat", "-x", ";", "-e", "cycles,instructions", "./bench-yaxpeax-no-fmt", "20", "0x400", "0x2460400", "../../input/xul.dll"}, {cwd="disas-bench/bench/yaxpeax"})
measurements = {}
for count, unit, name in perf_out.stderr:gmatch("([^;]*);([^;]*);([^;]*)[^\n]*\n?") do
measurements[name] = tonumber(count)
end
insts, good, bad, ms = perf_out.stdout:match("Disassembled (%d*) instructions %((%d*) valid, (%d*) bad%), (%d*) ms")
measurements["decoded"] = tonumber(insts)
measurements["elapsed_ms"] = tonumber(ms)
local instructions_name = "instructions:u"
local cycles_name = "cycles:u"
if measurements[instructions_name] == nil then
instructions_name = "instructions"
cycles_name = "cycles"
end
ipc = measurements[instructions_name] / measurements[cycles_name]
Build.metric("no-fmt IPC", string.format("%.3f", ipc))
inst_per_decode = measurements[instructions_name] / measurements["decoded"]
Build.metric("no-fmt instructions/decode", string.format("%.1f", inst_per_decode))
ms_per_decode = measurements["elapsed_ms"] / measurements["decoded"]
Build.metric("no-fmt ns/decode", string.format("%.2f", ms_per_decode * 1000000))
perf_out = Build.check_output({"perf", "stat", "-x", ";", "-e", "cycles,instructions", "./bench-yaxpeax-fmt", "20", "0x400", "0x2460400", "../../input/xul.dll"}, {cwd="disas-bench/bench/yaxpeax"})
measurements = {}
for count, unit, name in perf_out.stderr:gmatch("([^;]*);([^;]*);([^;]*)[^\n]*\n?") do
measurements[name] = tonumber(count)
end
insts, good, bad, ms = perf_out.stdout:match("Disassembled (%d*) instructions %((%d*) valid, (%d*) bad%), (%d*) ms")
measurements["decoded"] = tonumber(insts)
measurements["elapsed_ms"] = tonumber(ms)
ipc = measurements[instructions_name] / measurements[cycles_name]
Build.metric("fmt IPC", string.format("%.3f", ipc))
inst_per_decode = measurements[instructions_name] / measurements["decoded"]
Build.metric("fmt instructions/decode+display", string.format("%.1f", inst_per_decode))
ms_per_decode = measurements["elapsed_ms"] / measurements["decoded"]
Build.metric("fmt ns/decode+display", string.format("%.2f", ms_per_decode * 1000000))
end
|