about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-05-10 08:59:08 +0000
committerbors <bors@rust-lang.org>2024-05-10 08:59:08 +0000
commite93f34210120d1fc6a0195d527eee828a36e57b1 (patch)
tree276e29caddbc4b3116b4843f085d90315f9abedf
parentf7b1501ce7e63a53b36f9d6d01b939eef6602d42 (diff)
parent2a7c42f93c2e3e3c07a8cae6453e4c7626e83b51 (diff)
downloadrust-e93f34210120d1fc6a0195d527eee828a36e57b1.tar.gz
rust-e93f34210120d1fc6a0195d527eee828a36e57b1.zip
Auto merge of #124774 - the8472:subnanosecond-benches, r=jhpratt
Display walltime benchmarks with subnanosecond precision

With modern CPUs running at more than one cycle per nanosecond the current precision is insufficient to resolve differences worth several cycles per iteration.

Granted, walltime benchmarks often are noisy but occasionally, especially when no allocations are involved, the difference really is just a few cycles.

example results when benchmarking 1-4 serialized ADD instructions and an empty bench body

```
running 4 tests
test add  ... bench:           0.24 ns/iter (+/- 0.00)
test add2 ... bench:           0.48 ns/iter (+/- 0.01)
test add3 ... bench:           0.72 ns/iter (+/- 0.01)
test add4 ... bench:           0.96 ns/iter (+/- 0.01)
test empty ... bench:           0.24 ns/iter (+/- 0.00)
```
-rw-r--r--library/test/src/bench.rs23
-rw-r--r--library/test/src/formatters/json.rs4
-rw-r--r--src/bootstrap/src/utils/render_tests.rs8
-rw-r--r--tests/run-make/libtest-padding/Makefile2
4 files changed, 20 insertions, 17 deletions
diff --git a/library/test/src/bench.rs b/library/test/src/bench.rs
index 23925e6ea72..9a5dc351f6d 100644
--- a/library/test/src/bench.rs
+++ b/library/test/src/bench.rs
@@ -68,12 +68,12 @@ pub fn fmt_bench_samples(bs: &BenchSamples) -> String {
     use std::fmt::Write;
     let mut output = String::new();
 
-    let median = bs.ns_iter_summ.median as usize;
-    let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
+    let median = bs.ns_iter_summ.median;
+    let deviation = bs.ns_iter_summ.max - bs.ns_iter_summ.min;
 
     write!(
         output,
-        "{:>11} ns/iter (+/- {})",
+        "{:>14} ns/iter (+/- {})",
         fmt_thousands_sep(median, ','),
         fmt_thousands_sep(deviation, ',')
     )
@@ -85,24 +85,27 @@ pub fn fmt_bench_samples(bs: &BenchSamples) -> String {
 }
 
 // Format a number with thousands separators
-fn fmt_thousands_sep(mut n: usize, sep: char) -> String {
+fn fmt_thousands_sep(mut n: f64, sep: char) -> String {
     use std::fmt::Write;
     let mut output = String::new();
     let mut trailing = false;
     for &pow in &[9, 6, 3, 0] {
         let base = 10_usize.pow(pow);
-        if pow == 0 || trailing || n / base != 0 {
-            if !trailing {
-                write!(output, "{}", n / base).unwrap();
-            } else {
-                write!(output, "{:03}", n / base).unwrap();
+        if pow == 0 || trailing || n / base as f64 >= 1.0 {
+            match (pow, trailing) {
+                // modern CPUs can execute multiple instructions per nanosecond
+                // e.g. benching an ADD takes about 0.25ns.
+                (0, true) => write!(output, "{:06.2}", n / base as f64).unwrap(),
+                (0, false) => write!(output, "{:.2}", n / base as f64).unwrap(),
+                (_, true) => write!(output, "{:03}", n as usize / base).unwrap(),
+                _ => write!(output,  "{}", n as usize / base).unwrap()
             }
             if pow != 0 {
                 output.push(sep);
             }
             trailing = true;
         }
-        n %= base;
+        n %= base as f64;
     }
 
     output
diff --git a/library/test/src/formatters/json.rs b/library/test/src/formatters/json.rs
index 47c4e7757e4..6245aae17c4 100644
--- a/library/test/src/formatters/json.rs
+++ b/library/test/src/formatters/json.rs
@@ -167,8 +167,8 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> {
             ),
 
             TestResult::TrBench(ref bs) => {
-                let median = bs.ns_iter_summ.median as usize;
-                let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
+                let median = bs.ns_iter_summ.median;
+                let deviation = bs.ns_iter_summ.max - bs.ns_iter_summ.min;
 
                 let mbps = if bs.mb_s == 0 {
                     String::new()
diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs
index 462b76d03bd..5c9918bce32 100644
--- a/src/bootstrap/src/utils/render_tests.rs
+++ b/src/bootstrap/src/utils/render_tests.rs
@@ -215,8 +215,8 @@ impl<'a> Renderer<'a> {
             for bench in &self.benches {
                 rows.push((
                     &bench.name,
-                    format!("{:.2?}/iter", Duration::from_nanos(bench.median)),
-                    format!("+/- {:.2?}", Duration::from_nanos(bench.deviation)),
+                    format!("{:.2?}/iter", bench.median),
+                    format!("+/- {:.2?}", bench.deviation),
                 ));
             }
 
@@ -394,8 +394,8 @@ enum TestMessage {
 #[derive(serde_derive::Deserialize)]
 struct BenchOutcome {
     name: String,
-    median: u64,
-    deviation: u64,
+    median: f64,
+    deviation: f64,
 }
 
 #[derive(serde_derive::Deserialize)]
diff --git a/tests/run-make/libtest-padding/Makefile b/tests/run-make/libtest-padding/Makefile
index 42bc1192925..c8e2fc01f67 100644
--- a/tests/run-make/libtest-padding/Makefile
+++ b/tests/run-make/libtest-padding/Makefile
@@ -2,7 +2,7 @@
 # needs-unwind because #[bench] and -Cpanic=abort requires -Zpanic-abort-tests
 include ../tools.mk
 
-NORMALIZE=sed 's%[0-9,]\{1,\} ns/iter (+/- [0-9,]\{1,\})%?? ns/iter (+/- ??)%' | sed 's%finished in [0-9\.]\{1,\}%finished in ??%'
+NORMALIZE=sed 's%[0-9,\.]\{1,\} ns/iter (+/- [0-9,\.]\{1,\})%?? ns/iter (+/- ??)%' | sed 's%finished in [0-9\.]\{1,\}%finished in ??%'
 
 all:
 	$(RUSTC) --test tests.rs