• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daisytuner / docc / 30250037658

27 Jul 2026 08:28AM UTC coverage: 64.145% (-0.07%) from 64.219%
30250037658

push

github

web-flow
Merge pull request #885 from daisytuner/perf-control

adds perf control util to report steady-state runtime numbers via CI

0 of 78 new or added lines in 2 files covered. (0.0%)

2 existing lines in 1 file now uncovered.

42851 of 66803 relevant lines covered (64.15%)

731.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/python/docc/benchmarks/perf.py
1
"""Runtime control of ``perf stat`` hardware-counter measurement.
2

3
When a benchmark process is launched under ``perf stat --control`` with perf
4
started disabled (``-D -1``), the process can turn counting on and off at
5
runtime. This lets the reported counters cover only a region of interest -- for
6
example the steady-state loop -- instead of the whole process, which is
7
otherwise dominated by interpreter/library import, graph tracing, and one-time
8
compilation/warmup costs.
9

10
The launcher wires up the control channel via environment variables, either as
11
fifo paths (``PERF_CTL_FIFO`` / ``PERF_ACK_FIFO``) or inherited file descriptors
12
(``PERF_CTL_FD`` / ``PERF_ACK_FD``). A matching perf invocation looks like::
13

14
    ctl=/tmp/perf_ctl.fifo; ack=/tmp/perf_ack.fifo
15
    mkfifo "$ctl" "$ack"
16
    PERF_CTL_FIFO=$ctl PERF_ACK_FIFO=$ack \\
17
    perf stat -D -1 --control fifo:$ctl,$ack -e cycles,instructions -- \\
18
        python my_benchmark.py
19

20
Typical usage inside the benchmark::
21

22
    from docc.benchmarks.perf import PerfControl
23

24
    perf = PerfControl.from_env()
25

26
    warmup()                 # cold-start work, not counted
27
    with perf.measure():     # counters enabled only inside this block
28
        for _ in range(n_runs):
29
            step()
30

31
Or manually with start / stop / resume::
32

33
    perf.start()
34
    ...
35
    perf.stop()              # pause
36
    perf.resume()            # continue
37
    ...
38
    perf.stop()
39

40
When no perf control channel is configured (env vars unset) every method is a
41
no-op, so the same code runs unchanged outside of perf.
42
"""
43

NEW
44
from __future__ import annotations
×
45

NEW
46
import os
×
NEW
47
import sys
×
NEW
48
from contextlib import contextmanager
×
NEW
49
from typing import IO, Iterator, Mapping, Optional
×
50

NEW
51
__all__ = ["PerfControl"]
×
52

53

NEW
54
class PerfControl:
×
55
    """Toggle ``perf stat`` counting around a region of interest.
56

57
    Instances are usually created with :meth:`from_env`. When the process was
58
    not launched under ``perf stat --control``, the returned instance is inert
59
    (:attr:`enabled` is ``False``) and every method does nothing.
60
    """
61

NEW
62
    def __init__(
×
63
        self,
64
        ctl_file: Optional[IO[str]] = None,
65
        ack_file: Optional[IO[str]] = None,
66
        *,
67
        verbose: bool = True,
68
    ) -> None:
NEW
69
        self._ctl = ctl_file
×
NEW
70
        self._ack = ack_file
×
NEW
71
        self._active = False
×
NEW
72
        if verbose and self._ctl is not None:
×
NEW
73
            print(
×
74
                "perf control active: measuring only the selected region",
75
                flush=True,
76
            )
77

NEW
78
    @classmethod
×
NEW
79
    def from_env(
×
80
        cls,
81
        env: Optional[Mapping[str, str]] = None,
82
        *,
83
        verbose: bool = True,
84
    ) -> "PerfControl":
85
        """Build a :class:`PerfControl` from the perf control environment.
86

87
        Reads ``PERF_CTL_FD`` / ``PERF_ACK_FD`` (inherited file descriptors) or,
88
        failing that, ``PERF_CTL_FIFO`` / ``PERF_ACK_FIFO`` (named-pipe paths).
89
        Returns an inert instance when neither is set or the channel cannot be
90
        opened, so callers never need to special-case the non-perf run.
91
        """
NEW
92
        env = os.environ if env is None else env
×
NEW
93
        ctl_fd = env.get("PERF_CTL_FD")
×
NEW
94
        ack_fd = env.get("PERF_ACK_FD")
×
NEW
95
        ctl_fifo = env.get("PERF_CTL_FIFO")
×
NEW
96
        ack_fifo = env.get("PERF_ACK_FIFO")
×
97

NEW
98
        ctl_file: Optional[IO[str]] = None
×
NEW
99
        ack_file: Optional[IO[str]] = None
×
NEW
100
        try:
×
NEW
101
            if ctl_fd is not None:
×
NEW
102
                ctl_file = os.fdopen(int(ctl_fd), "w")
×
NEW
103
                if ack_fd is not None:
×
NEW
104
                    ack_file = os.fdopen(int(ack_fd), "r")
×
NEW
105
            elif ctl_fifo is not None:
×
106
                # perf opens the ctl fifo for reading and the ack fifo for
107
                # writing, so these opens do not block once perf is running.
NEW
108
                ctl_file = open(ctl_fifo, "w")
×
NEW
109
                if ack_fifo is not None:
×
NEW
110
                    ack_file = open(ack_fifo, "r")
×
NEW
111
        except OSError as exc:
×
NEW
112
            print(
×
113
                f"perf control unavailable ({exc}); measurement not gated",
114
                file=sys.stderr,
115
            )
NEW
116
            return cls(None, None, verbose=False)
×
117

NEW
118
        return cls(ctl_file, ack_file, verbose=verbose)
×
119

NEW
120
    @property
×
NEW
121
    def enabled(self) -> bool:
×
122
        """Whether a perf control channel is wired up."""
NEW
123
        return self._ctl is not None
×
124

NEW
125
    @property
×
NEW
126
    def active(self) -> bool:
×
127
        """Whether counting is currently enabled."""
NEW
128
        return self._active
×
129

NEW
130
    def _send(self, command: str) -> None:
×
NEW
131
        if self._ctl is None:
×
NEW
132
            return
×
NEW
133
        self._ctl.write(command + "\n")
×
NEW
134
        self._ctl.flush()
×
NEW
135
        if self._ack is not None:
×
136
            # perf replies with "ack\n" once the command has been applied.
NEW
137
            self._ack.readline()
×
138

NEW
139
    def start(self) -> None:
×
140
        """Enable perf counting (begin the measured region)."""
NEW
141
        self._send("enable")
×
NEW
142
        self._active = True
×
143

NEW
144
    def resume(self) -> None:
×
145
        """Resume perf counting after :meth:`stop` (``continue``)."""
NEW
146
        self._send("enable")
×
NEW
147
        self._active = True
×
148

NEW
149
    def stop(self) -> None:
×
150
        """Disable perf counting (pause or end the measured region)."""
NEW
151
        self._send("disable")
×
NEW
152
        self._active = False
×
153

NEW
154
    @contextmanager
×
NEW
155
    def measure(self) -> Iterator["PerfControl"]:
×
156
        """Enable counting on entry and disable it on exit."""
NEW
157
        self.start()
×
NEW
158
        try:
×
NEW
159
            yield self
×
160
        finally:
NEW
161
            self.stop()
×
162

NEW
163
    def close(self) -> None:
×
164
        """Close the control/ack channel file objects."""
NEW
165
        for handle in (self._ctl, self._ack):
×
NEW
166
            if handle is not None:
×
NEW
167
                try:
×
NEW
168
                    handle.close()
×
NEW
169
                except OSError:
×
NEW
170
                    pass
×
NEW
171
        self._ctl = None
×
NEW
172
        self._ack = None
×
173

NEW
174
    def __enter__(self) -> "PerfControl":
×
NEW
175
        return self
×
176

NEW
177
    def __exit__(self, *exc_info: object) -> None:
×
NEW
178
        self.close()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc