Skip to content

Commit e1d2014

Browse files
authored
Add file to help benchmark, memory measure (#29)
* bench * fix test
1 parent e92c72b commit e1d2014

File tree

9 files changed

+960
-0
lines changed

9 files changed

+960
-0
lines changed

CHANGELOGS.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ Change Logs
44
0.3.0
55
+++++
66

7+
* :pr:`29`: adds helpers to measure the memory peak and run benchmark
8+
on different processes
79
* :pr:`28`: adds command line to print out the configuration for a model id,
810
support image-text-to-text
911
* :pr:`26`: creates a folder ``helpers`` to gather all the functions

_doc/api/helpers/bench_run.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
onnx_diagnostic.helpers.bench_run
3+
=================================
4+
5+
.. automodule:: onnx_diagnostic.helpers.bench_run
6+
:members:
7+
:no-undoc-members:

_doc/api/helpers/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ onnx_diagnostic.helpers
77
:caption: submodules
88

99
args_helper
10+
bench_run
1011
cache_helper
1112
helper
13+
memory_peak
1214
onnx_helper
1315
ort_session
1416
torch_test_helper

_doc/api/helpers/memory_peak.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
onnx_diagnostic.helpers.memory_peak
3+
===================================
4+
5+
.. automodule:: onnx_diagnostic.helpers.memory_peak
6+
:members:
7+
:no-undoc-members:
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import unittest
2+
import torch
3+
from onnx_diagnostic.ext_test_case import ExtTestCase, hide_stdout
4+
from onnx_diagnostic.helpers import max_diff
5+
from onnx_diagnostic.helpers.bench_run import (
6+
BenchmarkError,
7+
_cmd_line,
8+
_extract_metrics,
9+
get_machine,
10+
make_configs,
11+
run_benchmark,
12+
)
13+
from onnx_diagnostic.helpers.cache_helper import make_dynamic_cache
14+
15+
16+
class TestBenchRun(ExtTestCase):
17+
def test_reg(self):
18+
text = ":m,6;"
19+
m = _extract_metrics(text)
20+
self.assertEqual(m, {"m": 6})
21+
22+
def test_cmd(self):
23+
cmd = _cmd_line("l", m=6)
24+
self.assertEqual(cmd[1:], ["-m", "l", "--m", "6"])
25+
26+
def test_machine(self):
27+
ma = get_machine()
28+
self.assertIn("machine", ma)
29+
self.assertIn("processor", ma)
30+
self.assertIn("cpu", ma)
31+
self.assertIn("has_cuda", ma)
32+
self.assertIn("processor_name", ma)
33+
34+
def test_run_script(self):
35+
script_name = "onnx_diagnostic._bench_test"
36+
configs = [dict(m=6)]
37+
try:
38+
res = run_benchmark(script_name, configs)
39+
except BenchmarkError as e:
40+
raise unittest.SkipTest(f"Probably no metric collected due to {e}") # noqa: B904
41+
self.assertEqual(len(res), 1)
42+
expected = {"metric1": 0.5, "metric2": 5, "metric3": "dummy", "m": 6}
43+
got = res[0]
44+
for k, v in expected.items():
45+
self.assertIn(k, got)
46+
self.assertEqual(v, got[k])
47+
48+
def test_make_configs(self):
49+
kwargs = {"single": "1", "multi2": "1,2", "multi3": "A,B,C"}
50+
confs = make_configs(kwargs)
51+
self.assertEqual(
52+
confs,
53+
[
54+
{"single": "1", "multi2": "1", "multi3": "A"},
55+
{"single": "1", "multi2": "1", "multi3": "B"},
56+
{"single": "1", "multi2": "1", "multi3": "C"},
57+
{"single": "1", "multi2": "2", "multi3": "A"},
58+
{"single": "1", "multi2": "2", "multi3": "B"},
59+
{"single": "1", "multi2": "2", "multi3": "C"},
60+
],
61+
)
62+
63+
def test_make_configs_last(self):
64+
kwargs = {"single": "1", "multi2": "1,2", "multi3": "5, 6"}
65+
confs = make_configs(kwargs, last=["multi2"])
66+
self.assertEqual(
67+
confs,
68+
[
69+
{"single": "1", "multi3": "5", "multi2": "1"},
70+
{"single": "1", "multi3": "5", "multi2": "2"},
71+
{"single": "1", "multi3": " 6", "multi2": "1"},
72+
{"single": "1", "multi3": " 6", "multi2": "2"},
73+
],
74+
)
75+
76+
def test_make_configs_filter(self):
77+
def filter_out(kwargs):
78+
if kwargs["multi2"] == "1" and kwargs["multi3"] == "A":
79+
return True
80+
return False
81+
82+
kwargs = {"single": "1", "multi2": "1,2", "multi3": "A,B,C"}
83+
confs = make_configs(kwargs, filter_function=filter_out)
84+
self.assertEqual(confs, [{"single": "1", "multi2": "1", "multi3": "A"}])
85+
86+
def test_make_configs_drop(self):
87+
kwargs = {"single": "1", "multi2": "1,2", "multi3": "A,B,C"}
88+
confs = make_configs(kwargs, drop=["multi3"])
89+
self.assertEqual(
90+
confs,
91+
[{"single": "1", "multi2": "1"}, {"single": "1", "multi2": "2"}],
92+
)
93+
94+
def test_make_configs_replace(self):
95+
kwargs = {"single": "1", "multi2": "1,2", "multi3": "A,B,C"}
96+
confs = make_configs(kwargs, replace={"multi3": "ZZZ"})
97+
self.assertEqual(
98+
confs,
99+
[
100+
{"single": "1", "multi2": "1", "multi3": "ZZZ"},
101+
{"single": "1", "multi2": "2", "multi3": "ZZZ"},
102+
],
103+
)
104+
105+
def test_max_diff(self):
106+
self.assertEqual(
107+
max_diff(torch.Tensor([1, 2]), torch.Tensor([1, 2])),
108+
{"abs": 0.0, "rel": 0.0, "sum": 0.0, "n": 2.0, "dnan": 0.0},
109+
)
110+
self.assertEqual(
111+
max_diff(
112+
(torch.Tensor([1, 2]),),
113+
(torch.Tensor([1, 2])),
114+
),
115+
{"abs": 0.0, "rel": 0.0, "sum": 0.0, "n": 2.0, "dnan": 0.0},
116+
)
117+
self.assertEqual(
118+
max_diff(
119+
(torch.Tensor([1, 2]), (torch.Tensor([1, 2]),)),
120+
(torch.Tensor([1, 2]), (torch.Tensor([1, 2]),)),
121+
),
122+
{"abs": 0.0, "rel": 0.0, "sum": 0.0, "n": 4.0, "dnan": 0.0},
123+
)
124+
self.assertEqual(
125+
max_diff(
126+
{"a": torch.Tensor([1, 2])},
127+
{"a": torch.Tensor([1, 2])},
128+
),
129+
{"abs": 0.0, "rel": 0.0, "sum": 0.0, "n": 2.0, "dnan": 0.0},
130+
)
131+
self.assertEqual(
132+
max_diff(
133+
{"a": torch.Tensor([1, 2])},
134+
[torch.Tensor([1, 2])],
135+
),
136+
{"abs": 0.0, "rel": 0.0, "sum": 0.0, "n": 2.0, "dnan": 0.0},
137+
)
138+
self.assertEqual(
139+
max_diff(
140+
{"a": torch.Tensor([1, float("nan")])},
141+
[torch.Tensor([1, 2])],
142+
),
143+
{
144+
"abs": 9999999998.0,
145+
"dnan": 1.0,
146+
"n": 2.0,
147+
"rel": 0.9999999997999001,
148+
"sum": 9999999998.0,
149+
},
150+
)
151+
152+
@hide_stdout()
153+
def test_max_diff_dynamic_cache(self):
154+
t1 = torch.tensor([0, 1], dtype=torch.float32)
155+
cache = make_dynamic_cache([(torch.ones((2, 2)), (torch.ones((2, 2)) * 2))])
156+
md = max_diff(
157+
(t1, cache),
158+
(t1, cache.key_cache[0], cache.value_cache[0]),
159+
flatten=True,
160+
verbose=10,
161+
)
162+
self.assertEqual(md, {"abs": 0.0, "rel": 0.0, "sum": 0.0, "n": 10.0, "dnan": 0})
163+
164+
165+
if __name__ == "__main__":
166+
unittest.main(verbosity=2)
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import os
2+
import time
3+
import unittest
4+
import numpy as np
5+
import torch
6+
from onnx_diagnostic.ext_test_case import (
7+
ExtTestCase,
8+
skipif_ci_apple,
9+
ignore_warnings,
10+
requires_cuda,
11+
)
12+
from onnx_diagnostic.helpers.memory_peak import get_memory_rss, start_spying_on
13+
14+
15+
class TestMemoryPeak(ExtTestCase):
16+
@skipif_ci_apple("stuck")
17+
def test_memory(self):
18+
mem = get_memory_rss(os.getpid())
19+
self.assertIsInstance(mem, int)
20+
21+
@skipif_ci_apple("stuck")
22+
@ignore_warnings(DeprecationWarning)
23+
def test_spy_cpu(self):
24+
p = start_spying_on(cuda=False)
25+
n_elements = 0
26+
for _i in range(10):
27+
time.sleep(0.005)
28+
value = np.empty(2**23, dtype=np.int64)
29+
time.sleep(0.005)
30+
value += 1
31+
time.sleep(0.005)
32+
n_elements = max(value.shape[0], n_elements)
33+
time.sleep(0.02)
34+
pres = p.stop()
35+
self.assertGreater(n_elements, 0)
36+
self.assertIsInstance(pres, dict)
37+
self.assertLessEqual(pres["cpu"].end, pres["cpu"].max_peak)
38+
self.assertLessEqual(pres["cpu"].begin, pres["cpu"].max_peak)
39+
self.assertGreater(pres["cpu"].begin, 0)
40+
# Zero should not happen...
41+
self.assertGreaterOrEqual(pres["cpu"].delta_peak, 0)
42+
self.assertGreaterOrEqual(pres["cpu"].delta_peak, pres["cpu"].delta_end)
43+
self.assertGreaterOrEqual(pres["cpu"].delta_peak, pres["cpu"].delta_avg)
44+
self.assertGreaterOrEqual(pres["cpu"].delta_end, 0)
45+
self.assertGreaterOrEqual(pres["cpu"].delta_avg, 0)
46+
# Too unstable.
47+
# self.assertGreater(pres["cpu"].delta_peak, n_elements * 8 * 0.5)
48+
self.assertIsInstance(pres["cpu"].to_dict(), dict)
49+
50+
@skipif_ci_apple("stuck")
51+
@requires_cuda()
52+
def test_spy_cuda(self):
53+
p = start_spying_on(cuda=True)
54+
n_elements = 0
55+
for _i in range(10):
56+
time.sleep(0.005)
57+
value = torch.empty(2**23, dtype=torch.int64, device="cuda")
58+
value += 1
59+
n_elements = max(value.shape[0], n_elements)
60+
time.sleep(0.02)
61+
pres = p.stop()
62+
self.assertIsInstance(pres, dict)
63+
self.assertIn("gpus", pres)
64+
gpu = pres["gpus"][0]
65+
self.assertLessEqual(gpu.end, gpu.max_peak)
66+
self.assertLessEqual(gpu.begin, gpu.max_peak)
67+
self.assertGreater(gpu.delta_peak, 0)
68+
self.assertGreaterOrEqual(gpu.delta_peak, gpu.delta_end)
69+
self.assertGreaterOrEqual(gpu.delta_peak, gpu.delta_avg)
70+
self.assertGreater(gpu.delta_end, 0)
71+
self.assertGreater(gpu.delta_avg, 0)
72+
self.assertGreater(gpu.delta_peak, n_elements * 8 * 0.5)
73+
74+
75+
if __name__ == "__main__":
76+
unittest.main(verbosity=2)

0 commit comments

Comments
 (0)