Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracking issue for #[bench] and benchmarking support #29553

Open
alexcrichton opened this issue Nov 4, 2015 · 17 comments
Open

Tracking issue for #[bench] and benchmarking support #29553

alexcrichton opened this issue Nov 4, 2015 · 17 comments
Labels
B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. Libs-Tracked Libs issues that are tracked on the team's project board. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@alexcrichton
Copy link
Member

alexcrichton commented Nov 4, 2015

This is a tracking issue for the #[bench] attribute and its stability in the compiler. Currently it is not possible to use this from stable Rust as it requires extern crate test which is itself not stable.

Core APIs for benchmarking:

  • #[bench], which means the function should take a &mut Bencher argument and will be run as part of regular tests (and specifically benchmarked with --bench passed to the test binary).
crate test {
    mod bench {
        #[derive(Clone)]
        struct Bencher { ... }

        impl Bencher {
            fn iter<T, F>(&mut self, inner: F)
            where
                F: FnMut() -> T;
        }       
    }
}
@alexcrichton alexcrichton added I-nominated T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. B-unstable Blocker: Implemented in the nightly compiler and unstable. labels Nov 4, 2015
@alexcrichton
Copy link
Member Author

Nominating for discussion in 1.6, and cc https://internals.rust-lang.org/t/bench-status/2122/10, a thread about this.

I've currently extracted libtest and I would personally like to deprecate #[bench] with a little bit of extra support from perhaps Cargo or the compiler. We'd basically be saying "let's have benchmark support develop externally first" before moving it back in to the compiler.

@nagisa
Copy link
Member

nagisa commented Nov 4, 2015

I like bench being as easy to use as it currently is, but would like more functionality.

IMO it would be nice to be able to provide custom providers for --test bineries so you could compile rustc … --test and run binary --bench, binary --quickcheck, binary --criterion etc for whatever testing and benching libraries you’re using.

@alexcrichton
Copy link
Member Author

Yeah my feeling here is that I wouldn't want to stabilize anything in the compiler itself unless it looks like a generic "custom test framework" infrastructure, but that's unfortunately a big undertaking that may take awhile. As a result my personal preference is to deprecate the support in the meantime for technically-the-same-if-not-quite-as-easy-to-use support on crates.io

@alexcrichton
Copy link
Member Author

The libs team decided to punt on this for 1.6

@briansmith
Copy link
Contributor

This looks like it might be a good replacement for the current #[bench] mechanism: https://github.com/japaric/criterion.rs.

I agree with Alex that deprecation is the best resolution.

zackmdavis added a commit to zackmdavis/Mezzanine that referenced this issue Feb 7, 2016
The word upstream is that the unstable builtin benchmark tests are
likely to be deprecated (rust-lang/rust#29553), but I didn't feel like
learning Criterion just for this.

test
inference::triangle::tests::concerning_the_expense_of_computing_entropy
... bench:           0 ns/iter (+/- 0)
test inference::triangle::tests::concerning_the_expense_of_updating
... bench:   1,485,967 ns/iter (+/- 81,055)

I'm not sure how to interpret the zero for computing the entropy; I
assume some sort of clever LLVM optimization has sloughed off the work
to compile time.

But yeah, that 1.5 million nanoseconds to do an update is way too explosive
for a hotspot like `value_of_information`. We're going to need some new
techniques.
@Aatch
Copy link
Contributor

Aatch commented Apr 12, 2016

This just came up on IRC and should be a consideration for anything we do here. Allowing for "unbenchmarked" parts of an iteration. The specific case this came up for was benchmarking an in-place sorting algorithm. Since performance is going to be different for sorted vs. unsorted lists, you need to clone the list each iteration which can throw off the results.

stewart added a commit to stewart/cargo that referenced this issue Dec 29, 2016
The `#[bench]` attribute is [currently unstable][1], and is only usable
on nightly Rust.

However, being able to benchmark code with `cargo bench` is very useful
functionality when writing performance-focused code, and something that
the Cargo documentation currently glosses over.

Some useful information on how to get benchmark tests up and running,
with necessary caveats about stability, would likely be very helpful to
new users.

[1]: rust-lang/rust#29553
@Mark-Simulacrum Mark-Simulacrum added the C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. label Jul 22, 2017
@fschutt
Copy link
Contributor

fschutt commented Sep 15, 2017

I'm sorry, but this is still required in nightly 1.20. If I write:

#[bench]
fn bench_blur_image(b: &mut Bencher) {}

Rust complains that it can't find Bencher. You have to use #![feature(test)] and extern crate test still. Why is this not stabilized or that Bencher could be found automatically? Just asking.

@SimonSapin
Copy link
Contributor

@fschutt That is correct, benchmarking with #[bench] is unstable on only available in Nightly at the moment. This issue is about tracking its stabilization.

@alkis
Copy link
Contributor

alkis commented Oct 23, 2017

What's the current status of this given the recent discussion here? Is there another ongoing discussion somewhere else?

@Manishearth
Copy link
Member

rust-lang/rfcs#2287

@tomaka
Copy link
Contributor

tomaka commented Oct 19, 2018

Latest development seems to be rust-lang/rfcs#2318

@steveklabnik
Copy link
Member

Triage: no major movement recently

@KodrAus KodrAus added the Libs-Tracked Libs issues that are tracked on the team's project board. label Jul 31, 2020
@Mark-Simulacrum Mark-Simulacrum added the I-libs-api-nominated Nominated for discussion during a libs-api team meeting. label Mar 2, 2022
@Mark-Simulacrum
Copy link
Member

This has been discussed numerous times across various RFCs and internals threads over the last ~7 years (and probably before then, too), and the latest 'next step' towards stabilization here seems to be the custom test frameworks RFC (tracked in #50297). That RFC and implementation seem unlikely to be pushed over the finish line -- even for a working, usable nightly implementation -- on any relatively short timescale, so I would like to suggest that we discuss whether the existing bench API could be minimally stabilized essentially as-is (listed in the issue description).

It has a number of extensions that users have asked for historically, some already implemented:

  • Non-time data collection (e.g., memory, throughput -- in bytes/time instead of time/op)
  • Customizable data reporting, aggregation, etc.
  • Customizable number of iterations
  • Customizable "parameter" to vary (e.g., to evaluate scalability of some algorithm)

The majority of these seem relatively feasible to either add to libtest or develop out of tree (e.g., in crates like criterion), but also look to me like extensible design atop the very simple interface we have today which has -- largely -- worked fine for the majority of basic use cases. A relatively fast skim through of the various RFCs to me suggest that the main objection to just stabilizing in place has always been more general designs or concerns about a forever stable piece of the language. Ultimately, it seems to me that a few functions and an attribute (which could have a different meaning or multiple meanings in the future) are not that painful to commit to.

For example, we could, I think, easily imagine that #[bench] here is basically the equivalent of #[ignore]. The main difference is the argument passed to the function, but it seems like the minimal API being stabilized here could be provided by other frameworks, or at least doesn't really hurt them. The surface area is pretty minimal, after all.

The stabilization would mean stable access to the test crate, which I believe today is entirely unstable, so one alternative would be to move Bencher to std::test, re-exporting it in test.

@Kixunil
Copy link
Contributor

Kixunil commented Mar 3, 2022

@Mark-Simulacrum as far as I can see the only part that the language has to support is preventing optimizations - stabilizing black_box. Everything else can be built on top using external crates. Am I missing something?

@SimonSapin
Copy link
Contributor

Like #[test], #[bench] has special powers not available to #[proc_macro_attribute]: all functions in a crate with these attributes are "collected" and then some code is generated at the crate top-level to call them all.

@Mark-Simulacrum
Copy link
Member

black_box is separately tracked by #64102 these days and is not necessary for a baseline stabilization (the closure return value is already passed through a black box, IIRC).

FWIW, I don't personally see bench as distinct from test there -- they both share nearly all of the same infrastructure in the compiler and libtest. If we wanted to make test the only special attribute and require #[test] #[bench] or #[test(bench)] or something on all benchmarks in the stable variant, that would probably be fine (just seems like needless churn to me).

@SimonSapin
Copy link
Contributor

Given that the custom test frameworks experiment has been closed, how does @rust-lang/lang and @rust-lang/libs-api feel about either:

  • Stabilize the #[bench] attribute and a minimal Bencher API as-is (perhaps in a different module than test::bench?)
  • Or deprecate built-in benchmarking entirely.
    • cargo bench would continue to run benches/*.rs to support external tools like criterion.
    • Possible Cargo.toml changes for a future edition: make harness = false the default in [[benches]] sections, make bench = false the default in other "target" sections ([lib], [[bin]], [[example]], and [[test]]).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. Libs-Tracked Libs issues that are tracked on the team's project board. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests