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