Skip to content

Commit 5dc6f3b

Browse files
committed
feat: use instrument hooks
1 parent 9e16050 commit 5dc6f3b

File tree

2 files changed

+44
-23
lines changed

2 files changed

+44
-23
lines changed

src/pytest_codspeed/instruments/valgrind.py

+16-19
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

+28-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
from rich.table import Table
1212
from rich.text import Text
1313

14+
from pytest_codspeed import __semver_version__
1415
from pytest_codspeed.instruments import Instrument
16+
from pytest_codspeed.instruments.hooks import InstrumentHooks
1517

1618
if TYPE_CHECKING:
1719
from typing import Any, Callable
@@ -131,17 +133,26 @@ class Benchmark:
131133

132134

133135
def run_benchmark(
134-
name: str, uri: str, fn: Callable[P, T], args, kwargs, config: BenchmarkConfig
136+
instrument_hooks: InstrumentHooks | None,
137+
name: str,
138+
uri: str,
139+
fn: Callable[P, T],
140+
args,
141+
kwargs,
142+
config: BenchmarkConfig,
135143
) -> tuple[Benchmark, T]:
144+
def __codspeed_root_frame__() -> T:
145+
return fn(*args, **kwargs)
146+
136147
# Compute the actual result of the function
137-
out = fn(*args, **kwargs)
148+
out = __codspeed_root_frame__()
138149

139150
# Warmup
140151
times_per_round_ns: list[float] = []
141152
warmup_start = start = perf_counter_ns()
142153
while True:
143154
start = perf_counter_ns()
144-
fn(*args, **kwargs)
155+
__codspeed_root_frame__()
145156
end = perf_counter_ns()
146157
times_per_round_ns.append(end - start)
147158
if end - warmup_start > config.warmup_time_ns:
@@ -166,16 +177,21 @@ def run_benchmark(
166177
# Benchmark
167178
iter_range = range(iter_per_round)
168179
run_start = perf_counter_ns()
180+
if instrument_hooks:
181+
instrument_hooks.start_benchmark()
169182
for _ in range(rounds):
170183
start = perf_counter_ns()
171184
for _ in iter_range:
172-
fn(*args, **kwargs)
185+
__codspeed_root_frame__()
173186
end = perf_counter_ns()
174187
times_per_round_ns.append(end - start)
175188

176189
if end - run_start > config.max_time_ns:
177190
# TODO: log something
178191
break
192+
if instrument_hooks:
193+
instrument_hooks.stop_benchmark()
194+
instrument_hooks.set_executed_benchmark(uri)
179195
benchmark_end = perf_counter_ns()
180196
total_time = (benchmark_end - run_start) / 1e9
181197

@@ -192,8 +208,15 @@ def run_benchmark(
192208

193209
class WallTimeInstrument(Instrument):
194210
instrument = "walltime"
211+
instrument_hooks: InstrumentHooks | None
195212

196213
def __init__(self, config: CodSpeedConfig) -> None:
214+
try:
215+
self.instrument_hooks = InstrumentHooks()
216+
self.instrument_hooks.set_integration("pytest-codspeed", __semver_version__)
217+
except RuntimeError:
218+
self.instrument_hooks = None
219+
197220
self.config = config
198221
self.benchmarks: list[Benchmark] = []
199222

@@ -209,6 +232,7 @@ def measure(
209232
**kwargs: P.kwargs,
210233
) -> T:
211234
bench, out = run_benchmark(
235+
instrument_hooks=self.instrument_hooks,
212236
name=name,
213237
uri=uri,
214238
fn=fn,

0 commit comments

Comments
 (0)