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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
//! gander-core — platform data collection and process model.
//!
//! This crate must not depend on any UI crate. That keeps the parsers testable
//! against fixtures on any host, and makes a `--json` batch mode (and future
//! non-TUI front ends) nearly free.
//!
//! Two backends exist:
//! * [`linux`] — reads `/proc` and `/sys`. Parametrised by a root path, so the
//! entire read path is testable from fixtures on any unix.
//! * [`darwin`] — uses `libproc`, `sysctl` and Mach host statistics.
//!
//! Both produce the same [`row::Row`] / [`system::SystemSnapshot`] types, so the
//! UI and configuration layers are platform-independent.
//!
//! See `docs/DESIGN.md` and `docs/PORTABILITY.md`.
/// The `/proc` backend. Compiles on any unix because the IO layer is
/// parameterised by a root path; only Linux has a live `/proc` to point it at.
/// The macOS backend: `libproc` + `sysctl` + Mach.
/// The FreeBSD backend: `sysctl` + `libkvm` + `devstat`.
/// Process identifier.
pub type Pid = u32;
/// A unified sampler interface so the front end does not name a backend.
///
/// `docs/DESIGN.md` §5: selection happens at compile time, so this trait exists
/// for genericity in tests and for documentation, not for runtime dispatch in
/// the hot loop.
/// What the front end is currently showing, and therefore what the sampler has to
/// pay for.
///
/// # Why this is one struct rather than three setters
///
/// The per-process reads named here are not free:
///
/// * `threads` — an extra `stat` read per thread (~1700 per tick on a desktop).
/// * `smaps` — a kernel walk over every VMA of every process (tens of ms).
/// * `gpu` — a `readdir` of `fdinfo` plus a read per open DRM fd, per process.
///
/// Each one used to be its own `set_*` method on the trait. That worked until the
/// third, at which point a front end had to remember to call every setter on every
/// change, and a forgotten one meant either a wasted scan or a column of dashes.
/// Passing the whole decision as one value makes both failures impossible: there
/// is one call, it carries everything, and a new gated read can only be added by
/// extending this struct — which breaks every call site until it is answered.
/// Whether a live backend exists for this build.
///
/// Three backends: Linux reads `/proc`, macOS uses `libproc` and Mach, FreeBSD
/// uses `sysctl` and `libkvm`. Everything else compiles but has no sampler, and
/// the front ends refuse to start rather than showing an empty table.
pub const PLATFORM_SUPPORTED: bool = cfg!;
/// The sampler for the current target.
pub type Sampler = Sampler;
pub type Sampler = Sampler;
pub type Sampler = Sampler;
/// Re-export of the platform selected at compile time.
pub use LinuxPlatform as CurrentPlatform;
pub use DarwinPlatform as CurrentPlatform;
pub use FreeBsdPlatform as CurrentPlatform;
/// Platform capabilities that vary per OS, resolved at compile time.
///
/// Front ends use this to hide panes and columns that cannot work here, rather
/// than discovering it at runtime. See `docs/PORTABILITY.md`.
///
/// **A constant here must be read by something.** This module had ten and four of
/// them were referenced by nothing but their own doc comments — among them
/// `PROC_IO`, which claimed per-process I/O counters were available while no such
/// column existed. A capability nothing consults is worse than no capability: it
/// reads like an implemented feature and answers a question nobody asked. They
/// were removed rather than kept "for later"; adding one back is two lines, and
/// the second line is the call site.
///
/// Where the answer is needed by only one module, ask that module instead of
/// growing this list — `affinity::supported()` returns whether a mask can actually
/// be read and written, which is a stricter question than "does the panel open".