nextest_runner/usdt.rs
1// Copyright (c) The nextest Contributors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! [USDT](usdt) probes for nextest.
5//!
6//! This module acts as documentation for USDT (Userland Statically Defined
7//! Tracing) probes defined by nextest.
8//!
9//! USDT probes are supported:
10//!
11//! * On x86_64: Linux, via [bpftrace](https://bpftrace.org/)
12//! * On aarch64: macOS, via [DTrace](https://dtrace.org/)
13//! * On x86_64 and aarch64: illumos and other Solaris derivatives, and FreeBSD, via [DTrace](https://dtrace.org/)
14//!
15//! The probes and their contents are not part of nextest's stability guarantees.
16//!
17//! For more information and examples, see the [nextest documentation](https://nexte.st/docs/integrations/usdt).
18
19use nextest_metadata::RustBinaryId;
20use quick_junit::ReportUuid;
21use serde::Serialize;
22
23/// Register USDT probes on supported platforms.
24#[cfg(any(
25 all(
26 target_arch = "x86_64",
27 any(target_os = "linux", target_os = "freebsd", target_os = "illumos")
28 ),
29 all(
30 target_arch = "aarch64",
31 any(target_os = "macos", target_os = "freebsd", target_os = "illumos")
32 )
33))]
34pub fn register_probes() -> Result<(), usdt::Error> {
35 usdt::register_probes()
36}
37
38/// No-op for unsupported platforms.
39#[cfg(not(any(
40 all(
41 target_arch = "x86_64",
42 any(target_os = "linux", target_os = "freebsd", target_os = "illumos")
43 ),
44 all(
45 target_arch = "aarch64",
46 any(target_os = "macos", target_os = "freebsd", target_os = "illumos")
47 )
48)))]
49pub fn register_probes() -> Result<(), std::convert::Infallible> {
50 Ok(())
51}
52
53#[cfg(any(
54 all(
55 target_arch = "x86_64",
56 any(target_os = "linux", target_os = "freebsd", target_os = "illumos")
57 ),
58 all(
59 target_arch = "aarch64",
60 any(target_os = "macos", target_os = "freebsd", target_os = "illumos")
61 )
62))]
63#[usdt::provider(provider = "nextest")]
64pub mod usdt_probes {
65 use crate::usdt::*;
66
67 pub fn test__attempt__start(
68 attempt: &UsdtTestAttemptStart,
69 attempt_id: &str,
70 binary_id: &str,
71 test_name: &str,
72 pid: u32,
73 ) {
74 }
75 pub fn test__attempt__done(
76 attempt: &UsdtTestAttemptDone,
77 attempt_id: &str,
78 binary_id: &str,
79 test_name: &str,
80 result: &str,
81 duration_nanos: u64,
82 ) {
83 }
84 pub fn test__attempt__slow(
85 slow: &UsdtTestAttemptSlow,
86 attempt_id: &str,
87 binary_id: &str,
88 test_name: &str,
89 elapsed_nanos: u64,
90 ) {
91 }
92 pub fn setup__script__start(
93 script: &UsdtSetupScriptStart,
94 id: &str,
95 script_id: &str,
96 pid: u32,
97 ) {
98 }
99 pub fn setup__script__slow(
100 script: &UsdtSetupScriptSlow,
101 id: &str,
102 script_id: &str,
103 elapsed_nanos: u64,
104 ) {
105 }
106 pub fn setup__script__done(
107 script: &UsdtSetupScriptDone,
108 id: &str,
109 script_id: &str,
110 result: &str,
111 duration_nanos: u64,
112 ) {
113 }
114 pub fn run__start(run: &UsdtRunStart, run_id: ReportUuid) {}
115 pub fn run__done(run: &UsdtRunDone, run_id: ReportUuid) {}
116 pub fn stress__sub__run__start(
117 sub_run: &UsdtStressSubRunStart,
118 stress_sub_run_id: &str,
119 stress_current: u32,
120 ) {
121 }
122 pub fn stress__sub__run__done(
123 sub_run: &UsdtStressSubRunDone,
124 stress_sub_run_id: &str,
125 stress_current: u32,
126 ) {
127 }
128}
129
130/// Fires a USDT probe on supported platforms.
131#[cfg(any(
132 all(
133 target_arch = "x86_64",
134 any(target_os = "linux", target_os = "freebsd", target_os = "illumos")
135 ),
136 all(
137 target_arch = "aarch64",
138 any(target_os = "macos", target_os = "freebsd", target_os = "illumos")
139 )
140))]
141#[macro_export]
142macro_rules! fire_usdt {
143 (UsdtTestAttemptStart { $($tt:tt)* }) => {{
144 $crate::usdt::usdt_probes::test__attempt__start!(|| {
145 let probe = $crate::usdt::UsdtTestAttemptStart { $($tt)* };
146 let attempt_id = probe.attempt_id.clone();
147 let binary_id = probe.binary_id.to_string();
148 let test_name = probe.test_name.clone();
149 let pid = probe.pid;
150 (probe, attempt_id, binary_id, test_name, pid)
151 })
152 }};
153 (UsdtTestAttemptDone { $($tt:tt)* }) => {{
154 $crate::usdt::usdt_probes::test__attempt__done!(|| {
155 let probe = $crate::usdt::UsdtTestAttemptDone { $($tt)* };
156 let attempt_id = probe.attempt_id.clone();
157 let binary_id = probe.binary_id.to_string();
158 let test_name = probe.test_name.clone();
159 let result = probe.result;
160 let duration_nanos = probe.duration_nanos;
161 (
162 probe,
163 attempt_id,
164 binary_id,
165 test_name,
166 result,
167 duration_nanos,
168 )
169 })
170 }};
171 (UsdtTestAttemptSlow { $($tt:tt)* }) => {{
172 $crate::usdt::usdt_probes::test__attempt__slow!(|| {
173 let probe = $crate::usdt::UsdtTestAttemptSlow { $($tt)* };
174 let attempt_id = probe.attempt_id.clone();
175 let binary_id = probe.binary_id.to_string();
176 let test_name = probe.test_name.clone();
177 let elapsed_nanos = probe.elapsed_nanos;
178 (probe, attempt_id, binary_id, test_name, elapsed_nanos)
179 })
180 }};
181 (UsdtSetupScriptStart { $($tt:tt)* }) => {{
182 $crate::usdt::usdt_probes::setup__script__start!(|| {
183 let probe = $crate::usdt::UsdtSetupScriptStart { $($tt)* };
184 let id = probe.id.clone();
185 let script_id = probe.script_id.clone();
186 let pid = probe.pid;
187 (probe, id, script_id, pid)
188 })
189 }};
190 (UsdtSetupScriptSlow { $($tt:tt)* }) => {{
191 $crate::usdt::usdt_probes::setup__script__slow!(|| {
192 let probe = $crate::usdt::UsdtSetupScriptSlow { $($tt)* };
193 let id = probe.id.clone();
194 let script_id = probe.script_id.clone();
195 let elapsed_nanos = probe.elapsed_nanos;
196 (probe, id, script_id, elapsed_nanos)
197 })
198 }};
199 (UsdtSetupScriptDone { $($tt:tt)* }) => {{
200 $crate::usdt::usdt_probes::setup__script__done!(|| {
201 let probe = $crate::usdt::UsdtSetupScriptDone { $($tt)* };
202 let id = probe.id.clone();
203 let script_id = probe.script_id.clone();
204 let result = probe.result;
205 let duration_nanos = probe.duration_nanos;
206 (probe, id, script_id, result, duration_nanos)
207 })
208 }};
209 (UsdtRunStart { $($tt:tt)* }) => {{
210 $crate::usdt::usdt_probes::run__start!(|| {
211 let probe = $crate::usdt::UsdtRunStart { $($tt)* };
212 let run_id = probe.run_id;
213 (probe, run_id)
214 })
215 }};
216 (UsdtRunDone { $($tt:tt)* }) => {{
217 $crate::usdt::usdt_probes::run__done!(|| {
218 let probe = $crate::usdt::UsdtRunDone { $($tt)* };
219 let run_id = probe.run_id;
220 (probe, run_id)
221 })
222 }};
223 (UsdtStressSubRunStart { $($tt:tt)* }) => {{
224 $crate::usdt::usdt_probes::stress__sub__run__start!(|| {
225 let probe = $crate::usdt::UsdtStressSubRunStart { $($tt)* };
226 let stress_sub_run_id = probe.stress_sub_run_id.clone();
227 let stress_current = probe.stress_current;
228 (probe, stress_sub_run_id, stress_current)
229 })
230 }};
231 (UsdtStressSubRunDone { $($tt:tt)* }) => {{
232 $crate::usdt::usdt_probes::stress__sub__run__done!(|| {
233 let probe = $crate::usdt::UsdtStressSubRunDone { $($tt)* };
234 let stress_sub_run_id = probe.stress_sub_run_id.clone();
235 let stress_current = probe.stress_current;
236 (probe, stress_sub_run_id, stress_current)
237 })
238 }};
239}
240
241/// No-op version of fire_usdt for unsupported platforms.
242#[cfg(not(any(
243 all(
244 target_arch = "x86_64",
245 any(target_os = "linux", target_os = "freebsd", target_os = "illumos")
246 ),
247 all(
248 target_arch = "aarch64",
249 any(target_os = "macos", target_os = "freebsd", target_os = "illumos")
250 )
251)))]
252#[macro_export]
253macro_rules! fire_usdt {
254 ($($tt:tt)*) => {
255 let _ = $crate::usdt::$($tt)*;
256 };
257}
258
259/// Data associated with the `test-attempt-start` probe.
260///
261/// This data is JSON-encoded as `arg0`.
262#[derive(Clone, Debug, Serialize)]
263pub struct UsdtTestAttemptStart {
264 /// A unique identifier for this test attempt, comprised of the run ID, the
265 /// binary ID, the test name, the attempt number, and the stress index.
266 ///
267 /// Also available as `arg1`.
268 pub attempt_id: String,
269
270 /// The nextest run ID, unique for each run.
271 pub run_id: ReportUuid,
272
273 /// The binary ID.
274 ///
275 /// Also available as `arg2`.
276 pub binary_id: RustBinaryId,
277
278 /// The name of the test.
279 ///
280 /// Also available as `arg3`.
281 pub test_name: String,
282
283 /// The process ID of the test.
284 ///
285 /// Also available as `arg4`.
286 pub pid: u32,
287
288 /// The program to run.
289 pub program: String,
290
291 /// The arguments to pass to the program.
292 pub args: Vec<String>,
293
294 /// The attempt number, starting at 1 and <= `total_attempts`.
295 pub attempt: u32,
296
297 /// The total number of attempts.
298 pub total_attempts: u32,
299
300 /// The 0-indexed stress run index, if running stress tests.
301 pub stress_current: Option<u32>,
302
303 /// The total number of stress runs, if available.
304 pub stress_total: Option<u32>,
305}
306
307/// Data associated with the `test-attempt-done` probe.
308///
309/// This data is JSON-encoded as `arg0`.
310#[derive(Clone, Debug, Serialize)]
311pub struct UsdtTestAttemptDone {
312 /// A unique identifier for this test attempt, comprised of the run ID, the
313 /// binary ID, the test name, the attempt number, and the stress index.
314 ///
315 /// Also available as `arg1`.
316 pub attempt_id: String,
317
318 /// The nextest run ID, unique for each run.
319 pub run_id: ReportUuid,
320
321 /// The binary ID.
322 ///
323 /// Also available as `arg2`.
324 pub binary_id: RustBinaryId,
325
326 /// The name of the test.
327 ///
328 /// Also available as `arg3`.
329 pub test_name: String,
330
331 /// The attempt number, starting at 1 and <= `total_attempts`.
332 pub attempt: u32,
333
334 /// The total number of attempts.
335 pub total_attempts: u32,
336
337 /// The test result as a string (e.g., "pass", "fail", "timeout", "exec-fail").
338 ///
339 /// Also available as `arg4`.
340 pub result: &'static str,
341
342 /// The exit code of the test process, if available.
343 pub exit_code: Option<i32>,
344
345 /// The duration of the test in nanoseconds.
346 ///
347 /// Also available as `arg5`.
348 pub duration_nanos: u64,
349
350 /// Whether file descriptors were leaked.
351 pub leaked: bool,
352
353 /// Time taken for the standard output and standard error file descriptors
354 /// to close, in nanoseconds. None if they didn't close (timed out).
355 pub time_to_close_fds_nanos: Option<u64>,
356
357 /// The 0-indexed stress run index, if running stress tests.
358 pub stress_current: Option<u32>,
359
360 /// The total number of stress runs, if available.
361 pub stress_total: Option<u32>,
362
363 /// The length of stdout in bytes, if captured.
364 pub stdout_len: Option<u64>,
365
366 /// The length of stderr in bytes, if captured.
367 pub stderr_len: Option<u64>,
368}
369
370/// Data associated with the `test-attempt-slow` probe.
371///
372/// This data is JSON-encoded as `arg0`.
373#[derive(Clone, Debug, Serialize)]
374pub struct UsdtTestAttemptSlow {
375 /// A unique identifier for this test attempt, comprised of the run ID, the
376 /// binary ID, the test name, the attempt number, and the stress index.
377 ///
378 /// Also available as `arg1`.
379 pub attempt_id: String,
380
381 /// The nextest run ID, unique for each run.
382 pub run_id: ReportUuid,
383
384 /// The binary ID. Also available as `arg2`.
385 pub binary_id: RustBinaryId,
386
387 /// The name of the test. Also available as `arg3`.
388 pub test_name: String,
389
390 /// The attempt number, starting at 1 and <= `total_attempts`.
391 pub attempt: u32,
392
393 /// The total number of attempts.
394 pub total_attempts: u32,
395
396 /// The time elapsed since the test started, in nanoseconds.
397 ///
398 /// Also available as `arg4`.
399 pub elapsed_nanos: u64,
400
401 /// Whether the test is about to be terminated due to timeout.
402 pub will_terminate: bool,
403
404 /// The 0-indexed stress run index, if running stress tests.
405 pub stress_current: Option<u32>,
406
407 /// The total number of stress runs, if available.
408 pub stress_total: Option<u32>,
409}
410
411/// Data associated with the `setup-script-start` probe.
412///
413/// This data is JSON-encoded as `arg0`.
414#[derive(Clone, Debug, Serialize)]
415pub struct UsdtSetupScriptStart {
416 /// A unique identifier for this script run, comprised of the run ID, the
417 /// script ID, and the stress index if relevant.
418 ///
419 /// Also available as `arg1`.
420 pub id: String,
421
422 /// The nextest run ID, unique for each run.
423 pub run_id: ReportUuid,
424
425 /// The script ID.
426 ///
427 /// Also available as `arg2`.
428 pub script_id: String,
429
430 /// The process ID of the script.
431 ///
432 /// Also available as `arg3`.
433 pub pid: u32,
434
435 /// The program to run.
436 pub program: String,
437
438 /// The arguments to pass to the program.
439 pub args: Vec<String>,
440
441 /// The 0-indexed stress run index, if running stress tests.
442 pub stress_current: Option<u32>,
443
444 /// The total number of stress runs, if available.
445 pub stress_total: Option<u32>,
446}
447
448/// Data associated with the `setup-script-slow` probe.
449///
450/// This data is JSON-encoded as `arg0`.
451#[derive(Clone, Debug, Serialize)]
452pub struct UsdtSetupScriptSlow {
453 /// A unique identifier for this script run, comprised of the run ID, the
454 /// script ID, and the stress index if relevant.
455 ///
456 /// Also available as `arg1`.
457 pub id: String,
458
459 /// The nextest run ID, unique for each run.
460 pub run_id: ReportUuid,
461
462 /// The script ID.
463 ///
464 /// Also available as `arg2`.
465 pub script_id: String,
466
467 /// The program to run.
468 pub program: String,
469
470 /// The arguments to pass to the program.
471 pub args: Vec<String>,
472
473 /// The time elapsed since the script started, in nanoseconds.
474 ///
475 /// Also available as `arg3`.
476 pub elapsed_nanos: u64,
477
478 /// Whether the script is about to be terminated due to timeout.
479 pub will_terminate: bool,
480
481 /// The 0-indexed stress run index, if running stress tests.
482 pub stress_current: Option<u32>,
483
484 /// The total number of stress runs, if available.
485 pub stress_total: Option<u32>,
486}
487
488/// Data associated with the `setup-script-done` probe.
489///
490/// This data is JSON-encoded as `arg0`.
491#[derive(Clone, Debug, Serialize)]
492pub struct UsdtSetupScriptDone {
493 /// A unique identifier for this script run, comprised of the run ID, the
494 /// script ID, and the stress index if relevant.
495 ///
496 /// Also available as `arg1`.
497 pub id: String,
498
499 /// The nextest run ID, unique for each run.
500 pub run_id: ReportUuid,
501
502 /// The script ID.
503 ///
504 /// Also available as `arg2`.
505 pub script_id: String,
506
507 /// The program to run.
508 pub program: String,
509
510 /// The arguments to pass to the program.
511 pub args: Vec<String>,
512
513 /// The script result as a string (e.g., "pass", "fail", "timeout",
514 /// "exec-fail").
515 ///
516 /// Also available as `arg3`.
517 pub result: &'static str,
518
519 /// The exit code of the script process, if available.
520 pub exit_code: Option<i32>,
521
522 /// The duration of the script execution in nanoseconds.
523 ///
524 /// Also available as `arg4`.
525 pub duration_nanos: u64,
526
527 /// The 0-indexed stress run index, if running stress tests.
528 pub stress_current: Option<u32>,
529
530 /// The total number of stress runs, if available.
531 pub stress_total: Option<u32>,
532
533 /// The length of stdout in bytes, if captured.
534 pub stdout_len: Option<u64>,
535
536 /// The length of stderr in bytes, if captured.
537 pub stderr_len: Option<u64>,
538}
539
540/// Data associated with the `run-start` probe.
541///
542/// This data is JSON-encoded as `arg0`.
543#[derive(Clone, Debug, Serialize)]
544pub struct UsdtRunStart {
545 /// The nextest run ID, unique for each run.
546 ///
547 /// Also available as `arg1`.
548 pub run_id: ReportUuid,
549
550 /// The profile name (e.g., "default", "ci").
551 pub profile_name: String,
552
553 /// Total number of tests in the test list.
554 pub total_tests: usize,
555
556 /// Number of tests after filtering.
557 pub filter_count: usize,
558
559 /// Number of test threads.
560 pub test_threads: usize,
561
562 /// If this is a count-based stress run with a finite number of runs, the
563 /// number of stress runs.
564 pub stress_count: Option<u32>,
565
566 /// True if this is a count-based stress run with an infinite number of
567 /// runs.
568 pub stress_infinite: bool,
569
570 /// If this is a duration-based stress run, how long we're going to run for.
571 pub stress_duration_nanos: Option<u64>,
572}
573
574/// Data associated with the `run-done` probe.
575///
576/// This data is JSON-encoded as `arg0`.
577#[derive(Clone, Debug, Serialize)]
578pub struct UsdtRunDone {
579 /// The nextest run ID, unique for each run.
580 ///
581 /// Also available as `arg1`.
582 pub run_id: ReportUuid,
583
584 /// The profile name (e.g., "default", "ci").
585 pub profile_name: String,
586
587 /// Total number of tests that were run.
588 ///
589 /// For stress runs, this consists of the last run's total test count.
590 pub total_tests: usize,
591
592 /// Number of tests that passed.
593 ///
594 /// For stress runs, this consists of the last run's passed test count.
595 pub passed: usize,
596
597 /// Number of tests that failed.
598 ///
599 /// For stress runs, this consists of the last run's failed test count.
600 pub failed: usize,
601
602 /// Number of tests that were skipped.
603 ///
604 /// For stress runs, this consists of the last run's skipped test count.
605 pub skipped: usize,
606
607 /// Total active duration of the run in nanoseconds, not including paused
608 /// time.
609 ///
610 /// For stress runs, this adds up the duration across all sub-runs.
611 pub duration_nanos: u64,
612
613 /// The number of nanoseconds the run was paused.
614 ///
615 /// For stress runs, this adds up the paused duration across all sub-runs.
616 pub paused_nanos: u64,
617
618 /// The number of stress runs completed, if this is a stress run.
619 pub stress_completed: Option<u32>,
620
621 /// The number of stress runs that succeeded, if this is a stress run.
622 pub stress_success: Option<u32>,
623
624 /// The number of stress runs that failed, if this is a stress run.
625 pub stress_failed: Option<u32>,
626}
627
628/// Data associated with the `stress-sub-run-start` probe.
629///
630/// This data is JSON-encoded as `arg0`.
631#[derive(Clone, Debug, Serialize)]
632pub struct UsdtStressSubRunStart {
633 /// A unique identifier for this stress sub-run, of the form
634 /// `{run_id}:@stress-{stress_current}`.
635 ///
636 /// Also available as `arg1`.
637 pub stress_sub_run_id: String,
638
639 /// The nextest run ID, unique for each run.
640 pub run_id: ReportUuid,
641
642 /// The profile name (e.g., "default", "ci").
643 pub profile_name: String,
644
645 /// The 0-indexed current stress run number.
646 ///
647 /// Also available as `arg2`.
648 pub stress_current: u32,
649
650 /// The total number of stress runs, if available (None for infinite or
651 /// duration-based runs).
652 pub stress_total: Option<u32>,
653
654 /// The total elapsed time since the overall stress run started, in
655 /// nanoseconds.
656 pub elapsed_nanos: u64,
657}
658
659/// Data associated with the `stress-sub-run-done` probe.
660///
661/// This data is JSON-encoded as `arg0`.
662#[derive(Clone, Debug, Serialize)]
663pub struct UsdtStressSubRunDone {
664 /// A unique identifier for this stress sub-run, of the form
665 /// `{run_id}:@stress-{stress_current}`.
666 ///
667 /// Also available as `arg1`.
668 pub stress_sub_run_id: String,
669
670 /// The nextest run ID, unique for each run.
671 pub run_id: ReportUuid,
672
673 /// The profile name (e.g., "default", "ci").
674 pub profile_name: String,
675
676 /// The 0-indexed current stress run number.
677 ///
678 /// Also available as `arg2`.
679 pub stress_current: u32,
680
681 /// The total number of stress runs, if available (None for infinite or
682 /// duration-based runs).
683 pub stress_total: Option<u32>,
684
685 /// The total elapsed time since the overall stress run started, in
686 /// nanoseconds.
687 pub elapsed_nanos: u64,
688
689 /// The duration of this sub-run in nanoseconds.
690 pub sub_run_duration_nanos: u64,
691
692 /// Total number of tests that were run in this sub-run.
693 pub total_tests: usize,
694
695 /// Number of tests that passed in this sub-run.
696 pub passed: usize,
697
698 /// Number of tests that failed in this sub-run.
699 pub failed: usize,
700
701 /// Number of tests that were skipped in this sub-run.
702 pub skipped: usize,
703}