mirror of
https://github.com/sharkdp/hyperfine.git
synced 2026-11-14 00:17:37 +00:00
Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12fec42098 | ||
|
|
564ccafb03 | ||
|
|
99d24b7a2e | ||
|
|
2899deb8fd | ||
|
|
74615f01fb | ||
|
|
83edd2f8e3 | ||
|
|
2efc633486 | ||
|
|
83f04cdd31 | ||
|
|
f096c266f0 | ||
|
|
e3e86174d9 |
No files matched your search
@@ -22,17 +22,25 @@ jobs:
|
||||
- name: Extract crate information
|
||||
id: crate_metadata
|
||||
run: |
|
||||
cargo metadata --no-deps --format-version 1 | jq -r '"name=" + .packages[0].name' | tee -a $GITHUB_OUTPUT
|
||||
cargo metadata --no-deps --format-version 1 | jq -r '"version=" + .packages[0].version' | tee -a $GITHUB_OUTPUT
|
||||
cargo metadata --no-deps --format-version 1 | jq -r '"maintainer=" + .packages[0].authors[0]' | tee -a $GITHUB_OUTPUT
|
||||
cargo metadata --no-deps --format-version 1 | jq -r '"homepage=" + .packages[0].homepage' | tee -a $GITHUB_OUTPUT
|
||||
cargo metadata --no-deps --format-version 1 | jq -r '"msrv=" + .packages[0].rust_version' | tee -a $GITHUB_OUTPUT
|
||||
cargo metadata --no-deps --format-version 1 | jq -r '
|
||||
.packages[0] |
|
||||
[
|
||||
"name=" + .name,
|
||||
"version=" + .version,
|
||||
"maintainer=" + (.authors[0] // ""),
|
||||
"homepage=" + (.homepage // ""),
|
||||
"msrv=" + (.rust_version // ""),
|
||||
"bin-name=" + ( (.targets[] | select(.kind[0] == "bin") | .name) // .name )
|
||||
] |
|
||||
join("\n")
|
||||
' | tee -a $GITHUB_OUTPUT
|
||||
outputs:
|
||||
name: ${{ steps.crate_metadata.outputs.name }}
|
||||
version: ${{ steps.crate_metadata.outputs.version }}
|
||||
maintainer: ${{ steps.crate_metadata.outputs.maintainer }}
|
||||
homepage: ${{ steps.crate_metadata.outputs.homepage }}
|
||||
msrv: ${{ steps.crate_metadata.outputs.msrv }}
|
||||
bin-name: ${{ steps.crate_metadata.outputs.bin-name }}
|
||||
|
||||
ensure_cargo_fmt:
|
||||
name: Ensure 'cargo fmt' has been run
|
||||
@@ -115,6 +123,7 @@ jobs:
|
||||
- name: Show version information (Rust, cargo, GCC)
|
||||
shell: bash
|
||||
run: |
|
||||
set -x
|
||||
gcc --version || true
|
||||
rustup -V
|
||||
rustup toolchain list
|
||||
@@ -137,7 +146,7 @@ jobs:
|
||||
esac;
|
||||
|
||||
# Setup paths
|
||||
BIN_NAME="${{ needs.crate_metadata.outputs.name }}${EXE_suffix}"
|
||||
BIN_NAME="${{ needs.crate_metadata.outputs.bin-name }}${EXE_suffix}"
|
||||
BIN_PATH="target/${{ matrix.job.target }}/release/${BIN_NAME}"
|
||||
|
||||
# Let subsequent steps know where to find the binary
|
||||
@@ -150,7 +159,7 @@ jobs:
|
||||
run: |
|
||||
# test only library unit tests and binary for arm-type targets
|
||||
unset CARGO_TEST_OPTIONS
|
||||
unset CARGO_TEST_OPTIONS ; case ${{ matrix.job.target }} in arm-* | aarch64-*) CARGO_TEST_OPTIONS="--bin ${{ needs.crate_metadata.outputs.name }}" ;; esac;
|
||||
unset CARGO_TEST_OPTIONS ; case ${{ matrix.job.target }} in arm-* | aarch64-*) CARGO_TEST_OPTIONS="--bin ${{ steps.bin.outputs.BIN_NAME }}" ;; esac;
|
||||
echo "CARGO_TEST_OPTIONS=${CARGO_TEST_OPTIONS}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Run tests
|
||||
|
||||
+13
-5
@@ -1,17 +1,25 @@
|
||||
# unreleased
|
||||
# v1.19.0
|
||||
|
||||
## Features
|
||||
|
||||
|
||||
## Changes
|
||||
|
||||
- Add a new `--reference <cmd>` option to specify a reference command for the relative speed comparison, see #579, #577 and #744 (@sharkdp)
|
||||
- Add `--conclude` argument (analog to `--prepare`), see #565 and #719 (@jackoconnordev)
|
||||
- Allow `--output=…` to appear once for each command, enabling use cases like `hyperfine --output=null my-cmd --output=./file.log my-cmd`, see #529 and #775 (@sharkdp)
|
||||
- The environment variable `$HYPERFINE_ITERATION` will now contain the current iteration number for each benchmarked command, see #775 (@sharkdp)
|
||||
- Add iteration information to failure error message, see #771 and #772 (@sharkdp)
|
||||
- Python scripts:
|
||||
- legend modification parameters and output DPI, see #758 (@Spreadcat)
|
||||
- Nicer whiskers plot, see #727 (@serpent7776)
|
||||
|
||||
## Bugfixes
|
||||
|
||||
- ETA not clearly visible on terminals with a block cursor, see #698 and #699 (@overclockworked64)
|
||||
- Fix zsh completions, see #717 (@xzfc)
|
||||
|
||||
## Other
|
||||
|
||||
|
||||
- Build binaries for aarch64-apple-darwin, see #728 (@Phault)
|
||||
- Various cleanups (@hamirmahal, @one230six)
|
||||
|
||||
# v1.18.0
|
||||
|
||||
|
||||
Generated
+244
-315
File diff suppressed because it is too large.
Load diff
+17
-9
@@ -7,10 +7,10 @@ license = "MIT OR Apache-2.0"
|
||||
name = "hyperfine"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/sharkdp/hyperfine"
|
||||
version = "1.18.0"
|
||||
version = "1.19.0"
|
||||
edition = "2018"
|
||||
build = "build.rs"
|
||||
rust-version = "1.70.0"
|
||||
rust-version = "1.76.0"
|
||||
|
||||
[features]
|
||||
# Use the nightly feature windows_process_extensions_main_thread_handle
|
||||
@@ -20,20 +20,20 @@ windows_process_extensions_main_thread_handle = []
|
||||
colored = "2.1"
|
||||
indicatif = "=0.17.4"
|
||||
statistical = "1.0"
|
||||
csv = "1.1"
|
||||
csv = "1.3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
rust_decimal = "1.35"
|
||||
rust_decimal = "1.36"
|
||||
rand = "0.8"
|
||||
shell-words = "1.0"
|
||||
thiserror = "1.0"
|
||||
thiserror = "2.0"
|
||||
anyhow = "1.0"
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows-sys = { version = "0.48", features = [
|
||||
windows-sys = { version = "0.59", features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_Security",
|
||||
"Win32_System_JobObjects",
|
||||
@@ -45,18 +45,26 @@ windows-sys = { version = "0.48", features = [
|
||||
once_cell = "1.19"
|
||||
|
||||
[target.'cfg(target_os="linux")'.dependencies]
|
||||
nix = { version = "0.27.1", features = ["zerocopy"] }
|
||||
nix = { version = "0.29", features = ["zerocopy"] }
|
||||
|
||||
[dependencies.clap]
|
||||
version = "4"
|
||||
default-features = false
|
||||
features = ["suggestions", "color", "wrap_help", "cargo", "help", "usage", "error-context"]
|
||||
features = [
|
||||
"suggestions",
|
||||
"color",
|
||||
"wrap_help",
|
||||
"cargo",
|
||||
"help",
|
||||
"usage",
|
||||
"error-context",
|
||||
]
|
||||
|
||||
[dev-dependencies]
|
||||
approx = "0.5"
|
||||
assert_cmd = "2.0"
|
||||
predicates = "3.0"
|
||||
tempfile = "3.9"
|
||||
tempfile = "3.14"
|
||||
|
||||
[build-dependencies]
|
||||
clap = "4.4.12"
|
||||
|
||||
@@ -10,21 +10,6 @@ A command-line benchmarking tool.
|
||||
|
||||

|
||||
|
||||
## Sponsors
|
||||
|
||||
A special *thank you* goes to our biggest <a href="doc/sponsors.md">sponsor</a>:
|
||||
|
||||
<a href="https://bencher.dev/hyperfine/?utm_source=github&utm_medium=referral&utm_campaign=hyperfine&utm_content=wordmark">
|
||||
<img src="doc/sponsors/bencher_wordmark.svg" width="200" alt="🐰 Bencher">
|
||||
<br />
|
||||
<strong>Continuous Benchmarking: Catch performance regressions in CI</strong>
|
||||
</a>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
Track the results of your <code>hyperfine</code> benchmarks over time with Bencher. \
|
||||
Detect and prevent performance regressions before they make it to production.
|
||||
|
||||
## Features
|
||||
|
||||
* Statistical analysis across multiple runs.
|
||||
@@ -178,7 +163,7 @@ like `--warmup`, `--prepare <cmd>`, `--setup <cmd>` or `--cleanup <cmd>`:
|
||||
|
||||
## Installation
|
||||
|
||||
[](https://repology.org/project/hyperfine/versions)
|
||||
[](https://repology.org/project/hyperfine/versions)
|
||||
|
||||
### On Ubuntu
|
||||
|
||||
@@ -316,7 +301,7 @@ Hyperfine can be installed from source via [cargo](https://doc.rust-lang.org/car
|
||||
cargo install --locked hyperfine
|
||||
```
|
||||
|
||||
Make sure that you use Rust 1.70 or newer.
|
||||
Make sure that you use Rust 1.76 or newer.
|
||||
|
||||
### From binaries (Linux, macOS, Windows)
|
||||
|
||||
|
||||
@@ -290,6 +290,11 @@ Don't redirect the output at all (same as \&'\-\-show\-output').
|
||||
.IP "<FILE>"
|
||||
Write the output to the given file.
|
||||
.RE
|
||||
.IP
|
||||
This option can be specified once for all commands or multiple times,
|
||||
once for each command. Note: If you want to log the output of each and
|
||||
every iteration, you can use a shell redirection and the $HYPERFINE_ITERATION
|
||||
environment variable: 'my-command > output-${HYPERFINE_ITERATION}.log'
|
||||
.HP
|
||||
\fB\-\-input\fR \fIWHERE\fP
|
||||
.IP
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
## Sponsors
|
||||
|
||||
`hyperfine` development is sponsored by many individuals and companies. Thank you very much!
|
||||
|
||||
Please note, that being sponsored does not affect the individuality of the `hyperfine`
|
||||
project or affect the maintainers' actions in any way.
|
||||
We remain impartial and continue to assess pull requests solely on merit - the
|
||||
features added, bugs solved, and effect on the overall complexity of the code.
|
||||
No issue will have a different priority based on sponsorship status of the
|
||||
reporter.
|
||||
|
||||
If you want to see our biggest sponsors, check the top of [`README.md`](../README.md#sponsors).
|
||||
@@ -1,80 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="bencher_wordmark"
|
||||
version="1.1"
|
||||
viewBox="0 0 600 113"
|
||||
sodipodi:docname="bencher_wordmark.svg"
|
||||
inkscape:version="1.3 (0e150ed, 2023-07-21)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="256"
|
||||
inkscape:cx="0.09765625"
|
||||
inkscape:cy="80.701172"
|
||||
inkscape:window-width="1672"
|
||||
inkscape:window-height="1278"
|
||||
inkscape:window-x="672"
|
||||
inkscape:window-y="25"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="bencher_wordmark" />
|
||||
<rect
|
||||
style="fill:#ffffff;stroke-width:8.58435"
|
||||
id="rect1"
|
||||
width="600"
|
||||
height="113"
|
||||
x="0.00028267503"
|
||||
y="0"
|
||||
inkscape:label="background" />
|
||||
<path
|
||||
id="outline"
|
||||
fill="#000000"
|
||||
fill-opacity="1"
|
||||
d="m 87.04,54.87 c 5.413333,4.24 9.113333,9.476667 11.1,15.71 1.853333,5.786667 2.15333,11.436667 0.9,16.95 -1.366667,6.013333 -4.61,11.023333 -9.73,15.03 -4.386667,3.44 -9.736667,5.77333 -16.05,7 -9.833333,1.91333 -19.61,1.67 -29.33,-0.73 -4.053333,-1 -7.823333,-2.63667 -11.31,-4.91 C 27.826667,100.78667 24.42,96.77 22.4,91.87 20.553333,87.363333 19.95,82.366667 20.59,76.88 21.583333,68.446667 25.623333,61.153333 32.71,55 c 0.602958,-0.526584 0.745946,-1.405539 0.34,-2.09 -4.04,-6.76 -7.213333,-14.043333 -9.52,-21.85 -1.38,-4.673333 -1.906667,-8.61 -1.58,-11.81 0.433333,-4.353333 1.97,-8.166667 4.61,-11.44 3.16,-3.9133333 7.056667,-5.7966667 11.69,-5.65 3.92,0.12 7.6,1.59 11.04,4.41 4.6,3.78 7.336667,7.42904 8.21,13.935707 0.49,3.643333 0.657432,5.952996 0.865387,10.739823 0.150482,3.522425 0.111596,7.280575 0.07402,10.602405 -0.04773,1.205311 -0.01116,2.062877 0.193426,2.394139 0.734393,1.130752 2.423841,1.054593 2.837174,-0.09207 0.153333,-0.433333 0.206667,-1.17 0.16,-2.21 -0.18,-3.6 -0.183333,-7.2 -0.01,-10.8 0.24,-5.093333 0.56,-8.676667 0.96,-10.75 1.48,-7.68 5.723333,-13.29 12.73,-16.83 3.4,-1.7133333 6.866667,-2.0133333 10.4,-0.9 2.98,0.9466667 5.603333,2.8733333 7.87,5.78 3.333333,4.28 4.866667,9.083333 4.6,14.41 -0.186667,3.64 -1.616667,8.863333 -4.29,15.67 -1.973333,5.046667 -4.36,9.94 -7.16,14.68 -0.326572,0.559373 -0.194376,1.271522 0.31,1.67 z m -20.85,-5 C 62.283333,49.383333 58.143333,49.37 53.77,49.83 53.447244,49.8578 53.180693,49.581558 53.22,49.26 54.473333,39.493333 54.316667,29.99 52.75,20.75 52.323333,18.23 51.266667,15.79 49.58,13.43 48.033333,11.256667 46.086667,9.56 43.74,8.34 37.9,5.2933333 33.136667,6.4366667 29.45,11.77 c -1.406667,2.033333 -2.343333,4.356667 -2.81,6.97 -0.5,2.84 -0.443333,5.406667 0.17,7.7 2.666667,9.866667 6.923333,19.276667 12.77,28.23 0.173388,0.265249 0.09631,0.618913 -0.17,0.78 -5.8,3.666667 -9.92,8.423333 -12.36,14.27 -2.48,5.953333 -2.926667,11.89 -1.34,17.81 2.006667,7.5 7.123333,12.72 15.35,15.66 11.58,4.13333 23.636667,4.3 36.17,0.5 7.873333,-2.38667 13.18,-6.823333 15.92,-13.31 2.513333,-5.953333 2.663333,-12.243333 0.45,-18.87 -2.193333,-6.54 -6.52,-11.856667 -12.98,-15.95 -0.308104,-0.194766 -0.398356,-0.600899 -0.2,-0.9 5.073333,-7.793333 8.956667,-15.926667 11.65,-24.4 0.96,-3.04 1.486667,-5.63 1.58,-7.77 0.126667,-3.086667 -0.36,-5.73 -1.46,-7.93 -3.346667,-6.6533333 -7.873333,-9.07 -13.58,-7.25 -3.566667,1.1333333 -6.43,3.433333 -8.59,6.9 -2.013333,3.226667 -3.186667,6.906667 -3.52,11.04 -0.68,8.426667 -0.633333,16.486667 0.14,24.18 0.02818,0.257891 -0.192807,0.473963 -0.45,0.44 z" />
|
||||
<path
|
||||
id="face"
|
||||
d="m 37.625,6.6796875 c -0.314528,0.00599 -0.625523,0.029637 -0.931641,0.068359 -0.306116,0.038724 -0.608544,0.092604 -0.90625,0.1640625 -0.297704,0.071458 -0.591565,0.1594803 -0.880859,0.2636718 -0.289294,0.1041917 -0.574586,0.2244025 -0.855469,0.3613282 -0.280882,0.1369257 -0.555653,0.2912777 -0.828125,0.4609375 -0.27247,0.1696597 -0.542581,0.3542468 -0.80664,0.5566406 -0.264061,0.2023938 -0.523649,0.4211222 -0.779297,0.65625 -0.255649,0.2351278 -0.506669,0.4879974 -0.753907,0.7558594 -0.247236,0.2678625 -0.489689,0.5509675 -0.728515,0.8515625 -0.238826,0.300597 -0.474664,0.617843 -0.705078,0.951172 -0.351663,0.508329 -0.673884,1.035501 -0.966797,1.580078 -0.292914,0.544579 -0.554898,1.106673 -0.789063,1.6875 -0.234163,0.580828 -0.439819,1.179798 -0.615234,1.796875 -0.175415,0.617078 -0.320835,1.252924 -0.4375,1.90625 -0.124998,0.709994 -0.216069,1.402299 -0.271484,2.078125 -0.05542,0.675827 -0.07667,1.334902 -0.0625,1.976563 0.01417,0.64166 0.06469,1.265553 0.148437,1.873047 0.08375,0.607494 0.202137,1.198157 0.355469,1.771484 0.33333,1.233321 0.691202,2.460637 1.074219,3.679688 0.383017,1.21905 0.789952,2.429986 1.222656,3.634765 0.432704,1.20478 0.890655,2.403241 1.373047,3.59375 0.48239,1.190509 0.989406,2.374543 1.521484,3.550781 0.532078,1.17624 1.09011,2.343893 1.671875,3.50586 0.581765,1.161967 1.186908,2.317146 1.818359,3.464844 0.631453,1.147696 1.289564,2.288448 1.970704,3.421875 0.681138,1.133425 1.386361,2.25975 2.117187,3.378906 0.04143,0.06285 0.06999,0.133262 0.08398,0.207031 0.0136,0.07397 0.01226,0.149706 -0.0039,0.222656 -0.01615,0.07267 -0.04671,0.141089 -0.08984,0.201172 -0.04283,0.05992 -0.09729,0.110398 -0.160156,0.148438 -0.724992,0.458328 -1.423209,0.935344 -2.095703,1.427734 -0.672494,0.492391 -1.319459,1.000891 -1.939453,1.527344 -0.619994,0.526453 -1.213756,1.070344 -1.78125,1.630859 -0.567494,0.560515 -1.108051,1.137845 -1.623047,1.732422 -0.514994,0.594577 -1.004301,1.205346 -1.466797,1.833984 -0.462494,0.62864 -0.898598,1.274799 -1.308594,1.9375 -0.409994,0.662703 -0.794847,1.342299 -1.152343,2.039063 -0.357496,0.696764 -0.68719,1.411752 -0.992188,2.142578 -0.309996,0.744159 -0.589481,1.486831 -0.835937,2.230469 -0.246456,0.743638 -0.461616,1.48735 -0.644532,2.230469 -0.182914,0.743117 -0.33375,1.485919 -0.453125,2.228515 -0.119373,0.742598 -0.205886,1.484486 -0.261718,2.226563 -0.05583,0.742075 -0.07997,1.485007 -0.07227,2.226562 0.0077,0.741556 0.04594,1.481623 0.117188,2.222656 0.07125,0.741035 0.175757,1.482143 0.310546,2.222657 0.134791,0.740513 0.301669,1.480711 0.5,2.220703 0.125417,0.468746 0.262398,0.929927 0.41211,1.380859 0.149712,0.450933 0.310366,0.893051 0.484375,1.326172 0.174008,0.433121 0.360288,0.856177 0.558594,1.271484 0.198305,0.415309 0.41021,0.821254 0.632812,1.21875 0.222602,0.397498 0.456226,0.786333 0.703125,1.166016 0.246899,0.379684 0.506148,0.75141 0.777344,1.113281 0.271195,0.361873 0.554118,0.714535 0.849609,1.058594 0.295493,0.344059 0.60404,0.679613 0.923828,1.005859 0.319789,0.326248 0.652009,0.642738 0.996094,0.951172 0.344085,0.308435 0.699978,0.607815 1.068359,0.898438 0.368383,0.290621 0.747947,0.572893 1.140625,0.845703 0.39268,0.272815 0.797869,0.536015 1.214844,0.791015 0.416975,0.255 0.845838,0.5011 1.28711,0.73828 0.44127,0.23719 0.895759,0.46617 1.361328,0.68555 0.465567,0.21937 0.943729,0.4293 1.433593,0.63086 0.489866,0.20156 0.991698,0.39437 1.50586,0.57812 0.723742,0.25834 1.448315,0.50118 2.175781,0.72852 0.727466,0.22734 1.458263,0.44036 2.189453,0.63672 0.731192,0.19635 1.464305,0.37565 2.199219,0.54101 0.734914,0.16537 1.470346,0.3168 2.208984,0.45118 0.73864,0.13436 1.480294,0.25208 2.222657,0.35546 0.742362,0.10339 1.486335,0.19128 2.232421,0.26368 0.746088,0.0724 1.494331,0.13046 2.244141,0.17187 0.74981,0.0414 1.500372,0.0658 2.253906,0.0762 0.753535,0.0104 1.510321,0.007 2.267578,-0.0137 0.757259,-0.0206 1.516362,-0.0578 2.277344,-0.10937 0.760982,-0.0516 1.522403,-0.11862 2.28711,-0.20118 0.764705,-0.0825 1.532351,-0.17943 2.300781,-0.29296 0.76843,-0.11355 1.538393,-0.24415 2.310547,-0.38868 0.772153,-0.14453 1.546388,-0.30299 2.322265,-0.47851 0.775878,-0.17552 1.55243,-0.36771 2.332032,-0.57422 0.779601,-0.20651 1.562377,-0.42852 2.345703,-0.66602 0.492078,-0.14916 0.973286,-0.30552 1.445312,-0.4707 0.472027,-0.16518 0.934744,-0.33833 1.386719,-0.51953 0.451975,-0.1812 0.894249,-0.37115 1.326172,-0.56836 0.431923,-0.19721 0.853754,-0.40202 1.265625,-0.61523 0.411871,-0.21323 0.813259,-0.43482 1.205078,-0.66407 0.391819,-0.22924 0.772764,-0.46569 1.144531,-0.71093 0.371767,-0.245268 0.734223,-0.498497 1.085938,-0.759771 0.351715,-0.261272 0.693727,-0.531305 1.02539,-0.808593 0.331664,-0.27729 0.653233,-0.562165 0.964844,-0.855469 0.311612,-0.293305 0.612737,-0.594978 0.904297,-0.904297 0.29156,-0.309319 0.574195,-0.625837 0.845703,-0.951172 0.271508,-0.325335 0.531748,-0.658649 0.783203,-1 0.251456,-0.34135 0.493206,-0.691462 0.72461,-1.048828 0.231403,-0.357366 0.45271,-0.722322 0.664062,-1.095703 0.211352,-0Line truncated
|
||||
style="fill:#ffffff" />
|
||||
<path
|
||||
id="mouth"
|
||||
fill="#bfb5bf"
|
||||
fill-opacity="1"
|
||||
d="m 65,95.56 q 2.08,0 3.57,-1.6 0.21,-0.24 0.41,-0.35 1.2,-0.71 0.21,0.83 -2.88,4.47 -8.66,1.9 a 1.22,1.23 46.3 0 0 -0.95,-0.02 q -6.21,2.54 -8.93,-2.26 -0.42,-0.74 0.05,-0.71 a 1.04,0.54 59.1 0 1 0.6,0.37 q 3.6,4.14 7.61,-0.87 a 1.32,1.32 0 0 1 2.22,0.26 q 0.46,0.98 1.65,1.76 1.06,0.69 2.22,0.69 z" />
|
||||
<ellipse
|
||||
id="nose"
|
||||
fill="#fc7300"
|
||||
fill-opacity="1"
|
||||
cx="60.445126"
|
||||
cy="88.674728"
|
||||
rx="3.53"
|
||||
ry="1.97"
|
||||
transform="rotate(0.3)" />
|
||||
<path
|
||||
id="ears"
|
||||
fill="#fc7300"
|
||||
fill-opacity="1"
|
||||
d="m 42.15,15.69 c 0.733333,0.553333 1.346667,1.216667 1.84,1.99 1.933333,3.046667 3.033333,6.736667 3.3,11.07 0.366667,6.166667 0.33,12.673333 -0.11,19.52 -0.186667,2.98 -1.19,3.286667 -3.01,0.92 -4.42,-5.753333 -7.956667,-12.92 -10.61,-21.5 -0.84,-2.726667 -0.876667,-5.523333 -0.11,-8.39 0.58,-2.153333 1.433333,-3.646667 2.56,-4.48 1.666667,-1.24 3.713333,-0.95 6.14,0.87 z m 35.7,0 c -0.733333,0.553333 -1.346667,1.216667 -1.84,1.99 -1.933333,3.046667 -3.033333,6.736667 -3.3,11.07 -0.366667,6.166667 -0.33,12.673333 0.11,19.52 0.186667,2.98 1.19,3.286667 3.01,0.92 4.42,-5.753333 7.956667,-12.92 10.61,-21.5 0.84,-2.726667 0.876667,-5.523333 0.11,-8.39 -0.58,-2.153333 -1.433333,-3.646667 -2.56,-4.48 -1.666667,-1.24 -3.713333,-0.95 -6.14,0.87 z" />
|
||||
<path
|
||||
id="cheeks"
|
||||
style="fill:#fdb07e;fill-opacity:1"
|
||||
d="m 42.084458,84.719032 c 0,3.872338 -3.278533,7.011488 -7.322808,7.011488 -4.044275,0 -7.322808,-3.13915 -7.322808,-7.011488 0,-3.872337 3.278533,-7.011487 7.322808,-7.011487 4.044275,0 7.322808,3.13915 7.322808,7.011487 z m 35.831084,0 c 0,3.872338 3.278533,7.011488 7.322808,7.011488 4.044275,0 7.322808,-3.13915 7.322808,-7.011488 0,-3.872337 -3.278533,-7.011487 -7.322808,-7.011487 -4.044275,0 -7.322808,3.13915 -7.322808,7.011487 z" />
|
||||
<path
|
||||
id="eyes"
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
d="m 47.451446,76.183212 c 0,3.131826 -2.549593,5.670672 -5.694675,5.670672 -3.145082,0 -5.694674,-2.538846 -5.694674,-5.670672 0,-3.131825 2.549592,-5.670671 5.694674,-5.670671 3.145082,0 5.694675,2.538846 5.694675,5.670671 z m 25.097108,0 c 0,3.131826 2.549593,5.670672 5.694675,5.670672 3.145082,0 5.694674,-2.538846 5.694674,-5.670672 0,-3.131825 -2.549592,-5.670671 -5.694674,-5.670671 -3.145082,0 -5.694675,2.538846 -5.694675,5.670671 z" />
|
||||
<path
|
||||
id="bencher"
|
||||
style="font-size:112.596px;fill:#000000;stroke-width:9.38295"
|
||||
d="m 417.35352,12 v 85.544924 h 10.33593 V 51.69336 c 2.82223,-2.162487 5.77277,-3.939244 8.85157,-5.332032 3.07879,-1.392787 6.02933,-2.089843 8.85156,-2.089843 2.74892,0 4.98437,0.384598 6.70703,1.154297 1.72266,0.733046 3.04268,1.868806 3.95899,3.408203 0.87965,1.392787 1.48458,3.335768 1.81445,5.828125 0.32987,2.455704 0.49414,5.095741 0.49414,7.917968 v 34.964846 h 10.33594 V 57.685547 c 0,-7.513723 -1.74069,-13.266617 -5.22266,-17.261719 -3.48197,-3.995101 -8.53976,-5.99414 -15.17383,-5.99414 -3.62858,0 -7.16601,0.751161 -10.61133,2.253906 -3.44531,1.502745 -6.78045,3.59196 -10.00586,6.267578 V 12 Z M 144,15.683594 v 81.86133 h 29.0293 c 5.68111,0 10.3543,-0.5128 14.01953,-1.53906 3.70188,-1.026269 7.09113,-2.748921 10.16992,-5.167973 2.60232,-2.015877 4.6735,-4.58182 6.21289,-7.697266 1.5394,-3.115446 2.3086,-6.706984 2.3086,-10.77539 0,-5.681108 -1.5925,-10.372336 -4.78125,-14.074219 -3.18875,-3.738535 -7.55144,-6.176279 -13.08594,-7.3125 v -0.439453 c 3.29871,-1.649354 5.93874,-3.830698 7.91797,-6.542969 1.97922,-2.748923 2.96875,-6.066027 2.96875,-9.951172 0,-3.445317 -0.67902,-6.395858 -2.03516,-8.851562 -1.35613,-2.492357 -3.53748,-4.525514 -6.54297,-6.101563 -2.71227,-1.392788 -5.55264,-2.310172 -8.52148,-2.75 -2.96884,-0.439828 -7.43974,-0.658203 -13.41406,-0.658203 z m 10.88672,9.291016 h 12.97461 c 3.62858,0 6.67125,0.128199 9.12695,0.384765 2.45571,0.219914 4.54492,0.824841 6.26758,1.814453 1.46609,0.843003 2.52776,1.942693 3.1875,3.298828 0.65974,1.356136 0.99024,3.022729 0.99024,5.001954 0,2.3824 -0.36657,4.453579 -1.09961,6.21289 -0.6964,1.722659 -1.90625,3.132853 -3.62891,4.232422 -1.72266,1.099569 -3.59154,1.832696 -5.60742,2.199219 -2.01588,0.329871 -4.72806,0.496094 -8.13672,0.496094 h -14.07422 z m 90.98828,9.455078 c -8.94316,0 -16.16231,2.950541 -21.66015,8.851562 -5.4612,5.901022 -8.19336,13.873284 -8.19336,23.916016 0,10.152689 2.86036,17.996751 8.57812,23.53125 5.71776,5.497848 13.67003,8.246098 23.85938,8.246098 3.9951,0 7.80696,-0.49477 11.43554,-1.48438 3.62858,-0.98961 7.18405,-2.217501 10.66602,-3.683593 V 82.53711 h -0.54883 c -1.79596,1.612701 -4.8206,3.261259 -9.07227,4.947265 -4.21501,1.649354 -8.41148,2.47461 -12.58984,2.47461 -3.1521,0 -6.04853,-0.440657 -8.6875,-1.320313 -2.60231,-0.879655 -4.8558,-2.19772 -6.76172,-3.957031 -1.97922,-1.795963 -3.5376,-4.087472 -4.67383,-6.873047 -1.13622,-2.822228 -1.70312,-6.121297 -1.70312,-9.896484 h 45.24609 v -5.607422 c 0,-8.906511 -2.25348,-15.779083 -6.76172,-20.617188 -4.47158,-4.838104 -10.84939,-7.257812 -19.13281,-7.257812 z m 72.51758,0 c -3.62858,0 -7.16601,0.751161 -10.61133,2.253906 -3.44532,1.502745 -6.78045,3.59196 -10.00586,6.267578 v -6.816406 h -10.33594 v 61.410158 h 10.33594 V 51.69336 c 2.82223,-2.162487 5.77277,-3.939244 8.85156,-5.332032 3.0788,-1.392787 6.02934,-2.089843 8.85157,-2.089843 2.74892,0 4.98437,0.384598 6.70703,1.154297 1.72266,0.733046 3.04268,1.868806 3.95898,3.408203 0.87966,1.392787 1.48459,3.335768 1.81446,5.828125 0.32987,2.455704 0.49414,5.095741 0.49414,7.917968 v 34.964846 h 10.33593 V 57.685547 c 0,-7.513723 -1.74068,-13.266617 -5.22265,-17.261719 -3.48197,-3.995101 -8.53976,-5.99414 -15.17383,-5.99414 z m 195.72266,0 c -8.94317,0 -16.16231,2.950541 -21.66016,8.851562 -5.46119,5.901022 -8.19336,13.873284 -8.19336,23.916016 0,10.152689 2.86037,17.996751 8.57813,23.53125 5.71776,5.497848 13.67003,8.246098 23.85937,8.246098 3.9951,0 7.80697,-0.49477 11.43555,-1.48438 3.62858,-0.98961 7.18404,-2.217501 10.66601,-3.683593 V 82.53711 h -0.54883 c -1.79596,1.612701 -4.82059,3.261259 -9.07226,4.947265 -4.21502,1.649354 -8.41148,2.47461 -12.58984,2.47461 -3.1521,0 -6.04854,-0.440657 -8.6875,-1.320313 -2.60232,-0.879655 -4.8558,-2.19772 -6.76172,-3.957031 -1.97923,-1.795963 -3.53761,-4.087472 -4.67383,-6.873047 -1.13622,-2.822228 -1.70313,-6.121297 -1.70313,-9.896484 h 45.2461 v -5.607422 c 0,-8.906511 -2.25349,-15.779083 -6.76172,-20.617188 -4.47158,-4.838104 -10.84939,-7.257812 -19.13281,-7.257812 z m -129.69336,0.27539 c -9.05312,0 -16.34832,2.858412 -21.88282,8.576172 -5.49784,5.71776 -8.24609,13.597893 -8.24609,23.640625 0,5.387889 0.73313,10.099106 2.19922,14.13086 1.46609,4.031753 3.53727,7.366893 6.21289,10.005859 2.63897,2.638966 5.80984,4.61802 9.51172,5.9375 3.70188,1.28283 7.77015,1.92383 12.20508,1.92383 3.48197,0 6.76105,-0.45869 9.83984,-1.375 3.11545,-0.91631 6.39648,-2.198304 9.8418,-3.847658 v -11.38086 h -0.54883 c -0.7697,0.62309 -1.81528,1.374251 -3.13477,2.253907 -1.31948,0.843003 -2.72967,1.650223 -4.23242,2.419922 -1.72266,0.879655 -3.66564,1.594746 -5.82812,2.144531 -2.16249,0.549784 -4.28777,0.824219 -6.37696,0.824219 -6.01097,0 -10.68417,-1.979051 -14.01953,-5.9375 -3.29871,-3.995102 -4.94922,-9.695844 -4.94922,-17.09961 0,-7.62368 1.68659,-13.396562 5.0586,-17.318359 3.40866,-3.958449 8.04578,-5.9375 13.91015,-5.9375 3.18875,0 6.4498,0.660986 9.78516,1.980469 3.37201,1.319483 6.63501,3.206404 9.78711,5.662109 h 0.54883 V 39.81836 c -2.82223,-1.42944 -5.93704,-Line truncated
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 24 KiB |
+1
-1
@@ -9,7 +9,7 @@ hyperfine 'sleep 0.020' 'sleep 0.021' 'sleep 0.022' --export-json sleep.json
|
||||
|
||||
### Pre-requisites
|
||||
|
||||
To make these scripts work, you will need to install `numpy`, `matplotlib` and `scipy`.
|
||||
To make these scripts work, you will need `numpy`, `matplotlib` and `scipy`.
|
||||
|
||||
If you have a Python package manager that understands [PEP-723](https://peps.python.org/pep-0723/)
|
||||
inline script requirements like [`uv`](https://github.com/astral-sh/uv) or [`pipx`](https://github.com/pypa/pipx),
|
||||
|
||||
@@ -16,12 +16,30 @@ use super::timing_result::TimingResult;
|
||||
use anyhow::{bail, Context, Result};
|
||||
use statistical::mean;
|
||||
|
||||
pub enum BenchmarkIteration {
|
||||
NonBenchmarkRun,
|
||||
Warmup(u64),
|
||||
Benchmark(u64),
|
||||
}
|
||||
|
||||
impl BenchmarkIteration {
|
||||
pub fn to_env_var_value(&self) -> Option<String> {
|
||||
match self {
|
||||
BenchmarkIteration::NonBenchmarkRun => None,
|
||||
BenchmarkIteration::Warmup(i) => Some(format!("warmup-{}", i)),
|
||||
BenchmarkIteration::Benchmark(i) => Some(format!("{}", i)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Executor {
|
||||
/// Run the given command and measure the execution time
|
||||
fn run_command_and_measure(
|
||||
&self,
|
||||
command: &Command<'_>,
|
||||
iteration: BenchmarkIteration,
|
||||
command_failure_action: Option<CmdFailureAction>,
|
||||
output_policy: &CommandOutputPolicy,
|
||||
) -> Result<(TimingResult, ExitStatus)>;
|
||||
|
||||
/// Perform a calibration of this executor. For example,
|
||||
@@ -39,6 +57,7 @@ pub trait Executor {
|
||||
|
||||
fn run_command_and_measure_common(
|
||||
mut command: std::process::Command,
|
||||
iteration: BenchmarkIteration,
|
||||
command_failure_action: CmdFailureAction,
|
||||
command_input_policy: &CommandInputPolicy,
|
||||
command_output_policy: &CommandOutputPolicy,
|
||||
@@ -53,17 +72,29 @@ fn run_command_and_measure_common(
|
||||
randomized_environment_offset::value(),
|
||||
);
|
||||
|
||||
if let Some(value) = iteration.to_env_var_value() {
|
||||
command.env("HYPERFINE_ITERATION", value);
|
||||
}
|
||||
|
||||
let result = execute_and_measure(command)
|
||||
.with_context(|| format!("Failed to run command '{command_name}'"))?;
|
||||
|
||||
if command_failure_action == CmdFailureAction::RaiseError && !result.status.success() {
|
||||
let when = match iteration {
|
||||
BenchmarkIteration::NonBenchmarkRun => "a non-benchmark run".to_string(),
|
||||
BenchmarkIteration::Warmup(0) => "the first warmup run".to_string(),
|
||||
BenchmarkIteration::Warmup(i) => format!("warmup iteration {i}"),
|
||||
BenchmarkIteration::Benchmark(0) => "the first benchmark run".to_string(),
|
||||
BenchmarkIteration::Benchmark(i) => format!("benchmark iteration {i}"),
|
||||
};
|
||||
bail!(
|
||||
"{}. Use the '-i'/'--ignore-failure' option if you want to ignore this. \
|
||||
"{cause} in {when}. Use the '-i'/'--ignore-failure' option if you want to ignore this. \
|
||||
Alternatively, use the '--show-output' option to debug what went wrong.",
|
||||
result.status.code().map_or(
|
||||
cause=result.status.code().map_or(
|
||||
"The process has been terminated by a signal".into(),
|
||||
|c| format!("Command terminated with non-zero exit code: {c}")
|
||||
)
|
||||
|c| format!("Command terminated with non-zero exit code {c}")
|
||||
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -80,17 +111,20 @@ impl<'a> RawExecutor<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Executor for RawExecutor<'a> {
|
||||
impl Executor for RawExecutor<'_> {
|
||||
fn run_command_and_measure(
|
||||
&self,
|
||||
command: &Command<'_>,
|
||||
iteration: BenchmarkIteration,
|
||||
command_failure_action: Option<CmdFailureAction>,
|
||||
output_policy: &CommandOutputPolicy,
|
||||
) -> Result<(TimingResult, ExitStatus)> {
|
||||
let result = run_command_and_measure_common(
|
||||
command.get_command()?,
|
||||
iteration,
|
||||
command_failure_action.unwrap_or(self.options.command_failure_action),
|
||||
&self.options.command_input_policy,
|
||||
&self.options.command_output_policy,
|
||||
output_policy,
|
||||
&command.get_command_line(),
|
||||
)?;
|
||||
|
||||
@@ -129,11 +163,13 @@ impl<'a> ShellExecutor<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Executor for ShellExecutor<'a> {
|
||||
impl Executor for ShellExecutor<'_> {
|
||||
fn run_command_and_measure(
|
||||
&self,
|
||||
command: &Command<'_>,
|
||||
iteration: BenchmarkIteration,
|
||||
command_failure_action: Option<CmdFailureAction>,
|
||||
output_policy: &CommandOutputPolicy,
|
||||
) -> Result<(TimingResult, ExitStatus)> {
|
||||
let on_windows_cmd = cfg!(windows) && *self.shell == Shell::Default("cmd.exe");
|
||||
let mut command_builder = self.shell.command();
|
||||
@@ -149,9 +185,10 @@ impl<'a> Executor for ShellExecutor<'a> {
|
||||
|
||||
let mut result = run_command_and_measure_common(
|
||||
command_builder,
|
||||
iteration,
|
||||
command_failure_action.unwrap_or(self.options.command_failure_action),
|
||||
&self.options.command_input_policy,
|
||||
&self.options.command_output_policy,
|
||||
output_policy,
|
||||
&command.get_command_line(),
|
||||
)?;
|
||||
|
||||
@@ -191,7 +228,12 @@ impl<'a> Executor for ShellExecutor<'a> {
|
||||
|
||||
for _ in 0..COUNT {
|
||||
// Just run the shell without any command
|
||||
let res = self.run_command_and_measure(&Command::new(None, ""), None);
|
||||
let res = self.run_command_and_measure(
|
||||
&Command::new(None, ""),
|
||||
BenchmarkIteration::NonBenchmarkRun,
|
||||
None,
|
||||
&CommandOutputPolicy::Null,
|
||||
);
|
||||
|
||||
match res {
|
||||
Err(_) => {
|
||||
@@ -260,7 +302,9 @@ impl Executor for MockExecutor {
|
||||
fn run_command_and_measure(
|
||||
&self,
|
||||
command: &Command<'_>,
|
||||
_iteration: BenchmarkIteration,
|
||||
_command_failure_action: Option<CmdFailureAction>,
|
||||
_output_policy: &CommandOutputPolicy,
|
||||
) -> Result<(TimingResult, ExitStatus)> {
|
||||
#[cfg(unix)]
|
||||
let status = {
|
||||
|
||||
+54
-17
@@ -6,8 +6,11 @@ pub mod timing_result;
|
||||
|
||||
use std::cmp;
|
||||
|
||||
use crate::benchmark::executor::BenchmarkIteration;
|
||||
use crate::command::Command;
|
||||
use crate::options::{CmdFailureAction, ExecutorKind, Options, OutputStyleOption};
|
||||
use crate::options::{
|
||||
CmdFailureAction, CommandOutputPolicy, ExecutorKind, Options, OutputStyleOption,
|
||||
};
|
||||
use crate::outlier_detection::{modified_zscores, OUTLIER_THRESHOLD};
|
||||
use crate::output::format::{format_duration, format_duration_unit};
|
||||
use crate::output::progress_bar::get_progress_bar;
|
||||
@@ -55,9 +58,15 @@ impl<'a> Benchmark<'a> {
|
||||
&self,
|
||||
command: &Command<'_>,
|
||||
error_output: &'static str,
|
||||
output_policy: &CommandOutputPolicy,
|
||||
) -> Result<TimingResult> {
|
||||
self.executor
|
||||
.run_command_and_measure(command, Some(CmdFailureAction::RaiseError))
|
||||
.run_command_and_measure(
|
||||
command,
|
||||
executor::BenchmarkIteration::NonBenchmarkRun,
|
||||
Some(CmdFailureAction::RaiseError),
|
||||
output_policy,
|
||||
)
|
||||
.map(|r| r.0)
|
||||
.map_err(|_| anyhow!(error_output))
|
||||
}
|
||||
@@ -66,6 +75,7 @@ impl<'a> Benchmark<'a> {
|
||||
fn run_setup_command(
|
||||
&self,
|
||||
parameters: impl IntoIterator<Item = ParameterNameAndValue<'a>>,
|
||||
output_policy: &CommandOutputPolicy,
|
||||
) -> Result<TimingResult> {
|
||||
let command = self
|
||||
.options
|
||||
@@ -77,7 +87,7 @@ impl<'a> Benchmark<'a> {
|
||||
Append ' || true' to the command if you are sure that this can be ignored.";
|
||||
|
||||
Ok(command
|
||||
.map(|cmd| self.run_intermediate_command(&cmd, error_output))
|
||||
.map(|cmd| self.run_intermediate_command(&cmd, error_output, output_policy))
|
||||
.transpose()?
|
||||
.unwrap_or_default())
|
||||
}
|
||||
@@ -86,6 +96,7 @@ impl<'a> Benchmark<'a> {
|
||||
fn run_cleanup_command(
|
||||
&self,
|
||||
parameters: impl IntoIterator<Item = ParameterNameAndValue<'a>>,
|
||||
output_policy: &CommandOutputPolicy,
|
||||
) -> Result<TimingResult> {
|
||||
let command = self
|
||||
.options
|
||||
@@ -97,25 +108,33 @@ impl<'a> Benchmark<'a> {
|
||||
Append ' || true' to the command if you are sure that this can be ignored.";
|
||||
|
||||
Ok(command
|
||||
.map(|cmd| self.run_intermediate_command(&cmd, error_output))
|
||||
.map(|cmd| self.run_intermediate_command(&cmd, error_output, output_policy))
|
||||
.transpose()?
|
||||
.unwrap_or_default())
|
||||
}
|
||||
|
||||
/// Run the command specified by `--prepare`.
|
||||
fn run_preparation_command(&self, command: &Command<'_>) -> Result<TimingResult> {
|
||||
fn run_preparation_command(
|
||||
&self,
|
||||
command: &Command<'_>,
|
||||
output_policy: &CommandOutputPolicy,
|
||||
) -> Result<TimingResult> {
|
||||
let error_output = "The preparation command terminated with a non-zero exit code. \
|
||||
Append ' || true' to the command if you are sure that this can be ignored.";
|
||||
|
||||
self.run_intermediate_command(command, error_output)
|
||||
self.run_intermediate_command(command, error_output, output_policy)
|
||||
}
|
||||
|
||||
/// Run the command specified by `--conclude`.
|
||||
fn run_conclusion_command(&self, command: &Command<'_>) -> Result<TimingResult> {
|
||||
fn run_conclusion_command(
|
||||
&self,
|
||||
command: &Command<'_>,
|
||||
output_policy: &CommandOutputPolicy,
|
||||
) -> Result<TimingResult> {
|
||||
let error_output = "The conclusion command terminated with a non-zero exit code. \
|
||||
Append ' || true' to the command if you are sure that this can be ignored.";
|
||||
|
||||
self.run_intermediate_command(command, error_output)
|
||||
self.run_intermediate_command(command, error_output, output_policy)
|
||||
}
|
||||
|
||||
/// Run the benchmark for a single command
|
||||
@@ -135,6 +154,8 @@ impl<'a> Benchmark<'a> {
|
||||
let mut exit_codes: Vec<Option<i32>> = vec![];
|
||||
let mut all_succeeded = true;
|
||||
|
||||
let output_policy = &self.options.command_output_policies[self.number];
|
||||
|
||||
let preparation_command = self.options.preparation_command.as_ref().map(|values| {
|
||||
let preparation_command = if values.len() == 1 {
|
||||
&values[0]
|
||||
@@ -147,10 +168,11 @@ impl<'a> Benchmark<'a> {
|
||||
self.command.get_parameters().iter().cloned(),
|
||||
)
|
||||
});
|
||||
|
||||
let run_preparation_command = || {
|
||||
preparation_command
|
||||
.as_ref()
|
||||
.map(|cmd| self.run_preparation_command(cmd))
|
||||
.map(|cmd| self.run_preparation_command(cmd, output_policy))
|
||||
.transpose()
|
||||
};
|
||||
|
||||
@@ -169,11 +191,11 @@ impl<'a> Benchmark<'a> {
|
||||
let run_conclusion_command = || {
|
||||
conclusion_command
|
||||
.as_ref()
|
||||
.map(|cmd| self.run_conclusion_command(cmd))
|
||||
.map(|cmd| self.run_conclusion_command(cmd, output_policy))
|
||||
.transpose()
|
||||
};
|
||||
|
||||
self.run_setup_command(self.command.get_parameters().iter().cloned())?;
|
||||
self.run_setup_command(self.command.get_parameters().iter().cloned(), output_policy)?;
|
||||
|
||||
// Warmup phase
|
||||
if self.options.warmup_count > 0 {
|
||||
@@ -187,9 +209,14 @@ impl<'a> Benchmark<'a> {
|
||||
None
|
||||
};
|
||||
|
||||
for _ in 0..self.options.warmup_count {
|
||||
for i in 0..self.options.warmup_count {
|
||||
let _ = run_preparation_command()?;
|
||||
let _ = self.executor.run_command_and_measure(self.command, None)?;
|
||||
let _ = self.executor.run_command_and_measure(
|
||||
self.command,
|
||||
BenchmarkIteration::Warmup(i),
|
||||
None,
|
||||
output_policy,
|
||||
)?;
|
||||
let _ = run_conclusion_command()?;
|
||||
if let Some(bar) = progress_bar.as_ref() {
|
||||
bar.inc(1)
|
||||
@@ -216,7 +243,12 @@ impl<'a> Benchmark<'a> {
|
||||
preparation_result.map_or(0.0, |res| res.time_real + self.executor.time_overhead());
|
||||
|
||||
// Initial timing run
|
||||
let (res, status) = self.executor.run_command_and_measure(self.command, None)?;
|
||||
let (res, status) = self.executor.run_command_and_measure(
|
||||
self.command,
|
||||
BenchmarkIteration::Benchmark(0),
|
||||
None,
|
||||
output_policy,
|
||||
)?;
|
||||
let success = status.success();
|
||||
|
||||
let conclusion_result = run_conclusion_command()?;
|
||||
@@ -260,7 +292,7 @@ impl<'a> Benchmark<'a> {
|
||||
}
|
||||
|
||||
// Gather statistics (perform the actual benchmark)
|
||||
for _ in 0..count_remaining {
|
||||
for i in 0..count_remaining {
|
||||
run_preparation_command()?;
|
||||
|
||||
let msg = {
|
||||
@@ -272,7 +304,12 @@ impl<'a> Benchmark<'a> {
|
||||
bar.set_message(msg.to_owned())
|
||||
}
|
||||
|
||||
let (res, status) = self.executor.run_command_and_measure(self.command, None)?;
|
||||
let (res, status) = self.executor.run_command_and_measure(
|
||||
self.command,
|
||||
BenchmarkIteration::Benchmark(i + 1),
|
||||
None,
|
||||
output_policy,
|
||||
)?;
|
||||
let success = status.success();
|
||||
|
||||
times_real.push(res.time_real);
|
||||
@@ -401,7 +438,7 @@ impl<'a> Benchmark<'a> {
|
||||
println!(" ");
|
||||
}
|
||||
|
||||
self.run_cleanup_command(self.command.get_parameters().iter().cloned())?;
|
||||
self.run_cleanup_command(self.command.get_parameters().iter().cloned(), output_policy)?;
|
||||
|
||||
Ok(BenchmarkResult {
|
||||
command: self.command.get_name(),
|
||||
|
||||
+6
-2
@@ -327,7 +327,7 @@ fn build_command() -> Command {
|
||||
Arg::new("output")
|
||||
.long("output")
|
||||
.conflicts_with("show-output")
|
||||
.action(ArgAction::Set)
|
||||
.action(ArgAction::Append)
|
||||
.value_name("WHERE")
|
||||
.help(
|
||||
"Control where the output of the benchmark is redirected. Note \
|
||||
@@ -343,7 +343,11 @@ fn build_command() -> Command {
|
||||
\n \
|
||||
inherit: Don't redirect the output at all (same as '--show-output').\n\
|
||||
\n \
|
||||
<FILE>: Write the output to the given file.",
|
||||
<FILE>: Write the output to the given file.\n\n\
|
||||
This option can be specified once for all commands or multiple times, once for \
|
||||
each command. Note: If you want to log the output of each and every iteration, \
|
||||
you can use a shell redirection and the '$HYPERFINE_ITERATION' environment variable:\n \
|
||||
hyperfine 'my-command > output-${HYPERFINE_ITERATION}.log'\n\n",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
|
||||
+4
-4
@@ -134,7 +134,7 @@ impl<'a> Command<'a> {
|
||||
pub struct Commands<'a>(Vec<Command<'a>>);
|
||||
|
||||
impl<'a> Commands<'a> {
|
||||
pub fn from_cli_arguments(matches: &'a ArgMatches) -> Result<Commands> {
|
||||
pub fn from_cli_arguments(matches: &'a ArgMatches) -> Result<Commands<'a>> {
|
||||
let command_names = matches.get_many::<String>("command-name");
|
||||
let command_strings = matches
|
||||
.get_many::<String>("command")
|
||||
@@ -251,8 +251,8 @@ impl<'a> Commands<'a> {
|
||||
self.0.iter()
|
||||
}
|
||||
|
||||
pub fn num_commands(&self) -> usize {
|
||||
self.0.len()
|
||||
pub fn num_commands(&self, has_reference_command: bool) -> usize {
|
||||
self.0.len() + if has_reference_command { 1 } else { 0 }
|
||||
}
|
||||
|
||||
/// Finds all the strings that appear multiple times in the input iterator, returning them in
|
||||
@@ -383,7 +383,7 @@ fn test_get_parameterized_command_name() {
|
||||
assert_eq!(cmd.get_name(), "name-quux-baz");
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for Command<'a> {
|
||||
impl fmt::Display for Command<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.get_command_line())
|
||||
}
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ fn run() -> Result<()> {
|
||||
colored::control::set_virtual_terminal(true).unwrap();
|
||||
|
||||
let cli_arguments = get_cli_arguments(env::args_os());
|
||||
let options = Options::from_cli_arguments(&cli_arguments)?;
|
||||
let mut options = Options::from_cli_arguments(&cli_arguments)?;
|
||||
let commands = Commands::from_cli_arguments(&cli_arguments)?;
|
||||
let export_manager = ExportManager::from_cli_arguments(&cli_arguments, options.time_unit)?;
|
||||
|
||||
|
||||
+45
-29
@@ -234,8 +234,8 @@ pub struct Options {
|
||||
/// Where input to the benchmarked command comes from
|
||||
pub command_input_policy: CommandInputPolicy,
|
||||
|
||||
/// What to do with the output of the benchmarked command
|
||||
pub command_output_policy: CommandOutputPolicy,
|
||||
/// What to do with the output of the benchmarked commands
|
||||
pub command_output_policies: Vec<CommandOutputPolicy>,
|
||||
|
||||
/// Which time unit to use when displaying results
|
||||
pub time_unit: Option<Unit>,
|
||||
@@ -257,7 +257,7 @@ impl Default for Options {
|
||||
sort_order_speed_comparison: SortOrder::MeanTime,
|
||||
sort_order_exports: SortOrder::Command,
|
||||
executor_kind: ExecutorKind::default(),
|
||||
command_output_policy: CommandOutputPolicy::Null,
|
||||
command_output_policies: vec![CommandOutputPolicy::Null],
|
||||
time_unit: None,
|
||||
command_input_policy: CommandInputPolicy::Null,
|
||||
}
|
||||
@@ -320,23 +320,28 @@ impl Options {
|
||||
|
||||
options.cleanup_command = matches.get_one::<String>("cleanup").map(String::from);
|
||||
|
||||
options.command_output_policy = if matches.get_flag("show-output") {
|
||||
CommandOutputPolicy::Inherit
|
||||
} else if let Some(output) = matches.get_one::<String>("output").map(|s| s.as_str()) {
|
||||
match output {
|
||||
"null" => CommandOutputPolicy::Null,
|
||||
"pipe" => CommandOutputPolicy::Pipe,
|
||||
"inherit" => CommandOutputPolicy::Inherit,
|
||||
arg => {
|
||||
let path = PathBuf::from(arg);
|
||||
if path.components().count() <= 1 {
|
||||
return Err(OptionsError::UnknownOutputPolicy(arg.to_string()));
|
||||
options.command_output_policies = if matches.get_flag("show-output") {
|
||||
vec![CommandOutputPolicy::Inherit]
|
||||
} else if let Some(output_values) = matches.get_many::<String>("output") {
|
||||
let mut policies = vec![];
|
||||
for value in output_values {
|
||||
let policy = match value.as_str() {
|
||||
"null" => CommandOutputPolicy::Null,
|
||||
"pipe" => CommandOutputPolicy::Pipe,
|
||||
"inherit" => CommandOutputPolicy::Inherit,
|
||||
arg => {
|
||||
let path = PathBuf::from(arg);
|
||||
if path.components().count() <= 1 {
|
||||
return Err(OptionsError::UnknownOutputPolicy(arg.to_string()));
|
||||
}
|
||||
CommandOutputPolicy::File(path)
|
||||
}
|
||||
CommandOutputPolicy::File(path)
|
||||
}
|
||||
};
|
||||
policies.push(policy);
|
||||
}
|
||||
policies
|
||||
} else {
|
||||
CommandOutputPolicy::Null
|
||||
vec![CommandOutputPolicy::Null]
|
||||
};
|
||||
|
||||
options.output_style = match matches.get_one::<String>("style").map(|s| s.as_str()) {
|
||||
@@ -346,7 +351,10 @@ impl Options {
|
||||
Some("color") => OutputStyleOption::Color,
|
||||
Some("none") => OutputStyleOption::Disabled,
|
||||
_ => {
|
||||
if options.command_output_policy == CommandOutputPolicy::Inherit
|
||||
if options
|
||||
.command_output_policies
|
||||
.iter()
|
||||
.any(|policy| *policy == CommandOutputPolicy::Inherit)
|
||||
|| !io::stdout().is_terminal()
|
||||
{
|
||||
OutputStyleOption::Basic
|
||||
@@ -436,26 +444,34 @@ impl Options {
|
||||
Ok(options)
|
||||
}
|
||||
|
||||
pub fn validate_against_command_list(&self, commands: &Commands) -> Result<()> {
|
||||
let num_commands = commands.num_commands()
|
||||
+ if self.reference_command.is_some() {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
pub fn validate_against_command_list(&mut self, commands: &Commands) -> Result<()> {
|
||||
let has_reference_command = self.reference_command.is_some();
|
||||
let num_commands = commands.num_commands(has_reference_command);
|
||||
|
||||
if let Some(preparation_command) = &self.preparation_command {
|
||||
ensure!(
|
||||
preparation_command.len() <= 1 || num_commands == preparation_command.len(),
|
||||
"The '--prepare' option has to be provided just once or N times, where N is the \
|
||||
number of benchmark commands including a potential reference."
|
||||
"The '--prepare' option has to be provided just once or N times, where N={num_commands} is the \
|
||||
number of benchmark commands (including a potential reference)."
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(conclusion_command) = &self.conclusion_command {
|
||||
ensure!(
|
||||
conclusion_command.len() <= 1 || num_commands == conclusion_command.len(),
|
||||
"The '--conclude' option has to be provided just once or N times, where N is the \
|
||||
number of benchmark commands including a potential reference."
|
||||
"The '--conclude' option has to be provided just once or N times, where N={num_commands} is the \
|
||||
number of benchmark commands (including a potential reference)."
|
||||
);
|
||||
}
|
||||
|
||||
if self.command_output_policies.len() == 1 {
|
||||
self.command_output_policies =
|
||||
vec![self.command_output_policies[0].clone(); num_commands];
|
||||
} else {
|
||||
ensure!(
|
||||
self.command_output_policies.len() == num_commands,
|
||||
"The '--output' option has to be provided just once or N times, where N={num_commands} is the \
|
||||
number of benchmark commands (including a potential reference)."
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -11,7 +11,7 @@ use nix::fcntl::{splice, SpliceFFlags};
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::fs::File;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::os::fd::AsFd;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
use windows_sys::Win32::System::Threading::CREATE_SUSPENDED;
|
||||
@@ -53,9 +53,9 @@ fn discard(output: ChildStdout) {
|
||||
{
|
||||
if let Ok(file) = File::create("/dev/null") {
|
||||
while let Ok(bytes) = splice(
|
||||
output.as_raw_fd(),
|
||||
output.as_fd(),
|
||||
None,
|
||||
file.as_raw_fd(),
|
||||
file.as_fd(),
|
||||
None,
|
||||
CHUNK_SIZE,
|
||||
SpliceFFlags::empty(),
|
||||
|
||||
@@ -37,7 +37,7 @@ static NtResumeProcess: Lazy<unsafe extern "system" fn(ProcessHandle: HANDLE) ->
|
||||
Lazy::new(|| {
|
||||
// SAFETY: Getting the module handle for ntdll.dll is safe
|
||||
let ntdll = unsafe { GetModuleHandleW(w!("ntdll.dll")) };
|
||||
assert!(ntdll != 0, "GetModuleHandleW failed");
|
||||
assert!(ntdll != std::ptr::null_mut(), "GetModuleHandleW failed");
|
||||
|
||||
// SAFETY: The ntdll handle is valid
|
||||
let nt_resume_process = unsafe { GetProcAddress(ntdll, s!("NtResumeProcess")) };
|
||||
@@ -56,7 +56,10 @@ impl CPUTimer {
|
||||
|
||||
// SAFETY: Creating a new job object is safe
|
||||
let job_object = unsafe { CreateJobObjectW(ptr::null_mut(), ptr::null_mut()) };
|
||||
assert!(job_object != 0, "CreateJobObjectW failed");
|
||||
assert!(
|
||||
job_object != std::ptr::null_mut(),
|
||||
"CreateJobObjectW failed"
|
||||
);
|
||||
|
||||
// SAFETY: The job object handle is valid
|
||||
let ret = unsafe { AssignProcessToJobObject(job_object, child_handle) };
|
||||
|
||||
Reference in new issue
Block a user