-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbenchmark.py
135 lines (114 loc) · 4.33 KB
/
benchmark.py
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
131
132
133
134
135
import sys
import sysconfig
import platform
import psutil
from argparse import ArgumentParser
from memory_profiler import profile as memory_profile
from time import perf_counter_ns
from typing import Callable
def cpu_profile(fn):
"""Decorator to print cummulative CPU time costs for a function to stdout."""
import cProfile
import io
import pstats
from pstats import SortKey
def inner(*args, **kwargs):
profiler = cProfile.Profile()
profiler.enable()
result = fn(*args, **kwargs)
profiler.disable()
stream = io.StringIO()
ps = pstats.Stats(profiler, stream=stream).sort_stats(SortKey.CUMULATIVE)
ps.print_stats()
print(stream.getvalue())
return result
return inner
class Benchmark:
def __init__(self,
name: str,
serialization_fn: Callable[[], bytes],
deserialization_fn: Callable[[bytes], None],
show_serialized: bool = False):
self._name = name
self._count = 10000
self._serialization_fn = serialization_fn
self._deserialization_fn = deserialization_fn
self._serialized = bytes()
self.show_serialized = show_serialized
def warm_up(self):
self._serialized = self._serialization_fn()
self._deserialization_fn(self._serialized)
assert len(self._serialized) > 0
def serialization(self) -> float:
start = perf_counter_ns()
i = 0
while i < self._count:
self._serialization_fn()
i += 1
elapsed = (perf_counter_ns() - start) / 1000000
return elapsed
def deserialization(self) -> float:
start = perf_counter_ns()
i = 0
while i < self._count:
self._deserialization_fn(self._serialized)
i += 1
elapsed = (perf_counter_ns() - start) / 1000000
return elapsed
@cpu_profile
def serialization_cpu(self):
"""Serialization benchmark with CPU cummulative time cost profiling."""
return self.serialization()
@cpu_profile
def deserialization_cpu(self):
"""Deserialization benchmark with CPU cummulative time cost profiling."""
return self.deserialization()
@memory_profile
def serialization_memory(self):
"""Serialization benchmark with memory profiling."""
return self.serialization()
@memory_profile
def deserialization_memory(self):
"""Deserialization benchmark with memory profiling."""
return self.deserialization()
@classmethod
def get_host_info(cls) -> str:
ghz = psutil.cpu_freq().max / 1000
return "\n".join([
f"CPU: {platform.processor()}, {psutil.cpu_count()} cpu, {ghz:.1f} GHz",
f"OS: {sysconfig.get_platform()}",
f"Python: {platform.python_version()}, {platform.python_implementation()}, {platform.python_revision()}",
])
def run(self):
ap = ArgumentParser(description="")
ap.add_argument("-s", "--skip_serialization", action="store_true",
help="")
ap.add_argument("-d", "--skip_deserialization", action="store_true",
help="")
ap.add_argument("-c", "--cpu_profile", action="store_true",
help="")
ap.add_argument("-m", "--memory_profile", action="store_true",
help="")
args = ap.parse_args()
self.warm_up()
if not args.skip_serialization:
if args.cpu_profile:
elapsed = self.serialization_cpu()
else:
elapsed = self.serialization()
if args.memory_profile:
self.serialization_memory()
print(f"{self._name} serialization [{self._count}]: {elapsed:.2f} ms")
if not args.skip_deserialization:
if args.cpu_profile:
elapsed = self.deserialization_cpu()
else:
elapsed = self.deserialization()
if args.memory_profile:
self.deserialization_memory()
print(f"{self._name} deserialization [{self._count}]: {elapsed:.2f} ms")
if self.show_serialized:
print()
print(f"_serialized [{len(self._serialized)}]: {self._serialized.hex()}")
print()
print(Benchmark.get_host_info())