Skip to content

Commit 26a11e8

Browse files
committed
feat: use instrument hooks
1 parent f887f93 commit 26a11e8

2 files changed

Lines changed: 50 additions & 23 deletions

File tree

src/pytest_codspeed/instruments/valgrind.py

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,36 @@
11
from __future__ import annotations
22

3-
import os
43
import sys
54
from typing import TYPE_CHECKING
65

76
from pytest_codspeed import __semver_version__
87
from pytest_codspeed.instruments import Instrument
9-
from pytest_codspeed.instruments.valgrind._wrapper import get_lib
8+
from pytest_codspeed.instruments.hooks import InstrumentHooks
109

1110
if TYPE_CHECKING:
1211
from typing import Any, Callable
1312

1413
from pytest import Session
1514

1615
from pytest_codspeed.instruments import P, T
17-
from pytest_codspeed.instruments.valgrind._wrapper import LibType
1816
from pytest_codspeed.plugin import CodSpeedConfig
1917

2018
SUPPORTS_PERF_TRAMPOLINE = sys.version_info >= (3, 12)
2119

2220

2321
class ValgrindInstrument(Instrument):
2422
instrument = "valgrind"
25-
lib: LibType | None
23+
instrument_hooks: InstrumentHooks | None
2624

2725
def __init__(self, config: CodSpeedConfig) -> None:
2826
self.benchmark_count = 0
29-
self.should_measure = os.environ.get("CODSPEED_ENV") is not None
30-
if self.should_measure:
31-
self.lib = get_lib()
32-
self.lib.dump_stats_at(
33-
f"Metadata: pytest-codspeed {__semver_version__}".encode("ascii")
34-
)
35-
if SUPPORTS_PERF_TRAMPOLINE:
36-
sys.activate_stack_trampoline("perf") # type: ignore
37-
else:
38-
self.lib = None
27+
try:
28+
self.instrument_hooks = InstrumentHooks()
29+
self.instrument_hooks.set_integration("pytest-codspeed", __semver_version__)
30+
except RuntimeError:
31+
self.instrument_hooks = None
32+
33+
self.should_measure = self.instrument_hooks is not None
3934

4035
def get_instrument_config_str_and_warns(self) -> tuple[str, list[str]]:
4136
config = (
@@ -61,7 +56,8 @@ def measure(
6156
**kwargs: P.kwargs,
6257
) -> T:
6358
self.benchmark_count += 1
64-
if self.lib is None: # Thus should_measure is False
59+
60+
if not self.instrument_hooks:
6561
return fn(*args, **kwargs)
6662

6763
def __codspeed_root_frame__() -> T:
@@ -71,14 +67,15 @@ def __codspeed_root_frame__() -> T:
7167
# Warmup CPython performance map cache
7268
__codspeed_root_frame__()
7369

74-
self.lib.zero_stats()
75-
self.lib.start_instrumentation()
70+
# Manually call the library function to avoid an extra stack frame. Also
71+
# call the callgrind markers directly to avoid extra overhead.
72+
self.instrument_hooks.lib.callgrind_start_instrumentation()
7673
try:
7774
return __codspeed_root_frame__()
7875
finally:
7976
# Ensure instrumentation is stopped even if the test failed
80-
self.lib.stop_instrumentation()
81-
self.lib.dump_stats_at(uri.encode("ascii"))
77+
self.instrument_hooks.lib.callgrind_stop_instrumentation()
78+
self.instrument_hooks.set_executed_benchmark(uri)
8279

8380
def report(self, session: Session) -> None:
8481
reporter = session.config.pluginmanager.get_plugin("terminalreporter")

src/pytest_codspeed/instruments/walltime.py

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import annotations
22

3+
import os
4+
import warnings
35
from dataclasses import asdict, dataclass
46
from math import ceil
57
from statistics import mean, quantiles, stdev
@@ -11,7 +13,9 @@
1113
from rich.table import Table
1214
from rich.text import Text
1315

16+
from pytest_codspeed import __semver_version__
1417
from pytest_codspeed.instruments import Instrument
18+
from pytest_codspeed.instruments.hooks import InstrumentHooks
1519

1620
if TYPE_CHECKING:
1721
from typing import Any, Callable
@@ -131,17 +135,26 @@ class Benchmark:
131135

132136

133137
def run_benchmark(
134-
name: str, uri: str, fn: Callable[P, T], args, kwargs, config: BenchmarkConfig
138+
instrument_hooks: InstrumentHooks | None,
139+
name: str,
140+
uri: str,
141+
fn: Callable[P, T],
142+
args,
143+
kwargs,
144+
config: BenchmarkConfig,
135145
) -> tuple[Benchmark, T]:
146+
def __codspeed_root_frame__() -> T:
147+
return fn(*args, **kwargs)
148+
136149
# Compute the actual result of the function
137-
out = fn(*args, **kwargs)
150+
out = __codspeed_root_frame__()
138151

139152
# Warmup
140153
times_per_round_ns: list[float] = []
141154
warmup_start = start = perf_counter_ns()
142155
while True:
143156
start = perf_counter_ns()
144-
fn(*args, **kwargs)
157+
__codspeed_root_frame__()
145158
end = perf_counter_ns()
146159
times_per_round_ns.append(end - start)
147160
if end - warmup_start > config.warmup_time_ns:
@@ -166,16 +179,21 @@ def run_benchmark(
166179
# Benchmark
167180
iter_range = range(iter_per_round)
168181
run_start = perf_counter_ns()
182+
if instrument_hooks:
183+
instrument_hooks.start_benchmark()
169184
for _ in range(rounds):
170185
start = perf_counter_ns()
171186
for _ in iter_range:
172-
fn(*args, **kwargs)
187+
__codspeed_root_frame__()
173188
end = perf_counter_ns()
174189
times_per_round_ns.append(end - start)
175190

176191
if end - run_start > config.max_time_ns:
177192
# TODO: log something
178193
break
194+
if instrument_hooks:
195+
instrument_hooks.stop_benchmark()
196+
instrument_hooks.set_executed_benchmark(uri)
179197
benchmark_end = perf_counter_ns()
180198
total_time = (benchmark_end - run_start) / 1e9
181199

@@ -192,8 +210,19 @@ def run_benchmark(
192210

193211
class WallTimeInstrument(Instrument):
194212
instrument = "walltime"
213+
instrument_hooks: InstrumentHooks | None
195214

196215
def __init__(self, config: CodSpeedConfig) -> None:
216+
try:
217+
self.instrument_hooks = InstrumentHooks()
218+
self.instrument_hooks.set_integration("pytest-codspeed", __semver_version__)
219+
except RuntimeError as e:
220+
if os.environ.get("CODSPEED_ENV") is not None:
221+
warnings.warn(
222+
f"Failed to initialize instrument hooks: {e}", RuntimeWarning
223+
)
224+
self.instrument_hooks = None
225+
197226
self.config = config
198227
self.benchmarks: list[Benchmark] = []
199228

@@ -209,6 +238,7 @@ def measure(
209238
**kwargs: P.kwargs,
210239
) -> T:
211240
bench, out = run_benchmark(
241+
instrument_hooks=self.instrument_hooks,
212242
name=name,
213243
uri=uri,
214244
fn=fn,

0 commit comments

Comments
 (0)