Skip to content

Add deeply-nested-multi benchmark. #1205

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

Merged
merged 1 commit into from
Mar 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions collector/benchmarks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ compiler in interesting ways.
behavior](https://github.com/rust-lang/rust/issues/75992) in the past.
- **deeply-nested-closures**: A small program that caused [exponential
behavior](https://github.com/rust-lang/rust/issues/72408) in the past.
- **deeply-nested-multi**: A small program containing multiple examples
([one](https://github.com/rust-lang/rust/issues/38528),
[two](https://github.com/rust-lang/rust/issues/72408),
[three](https://github.com/rust-lang/rust/issues/75992))
of code that caused exponential behavior in the past.
- **deep-vector**: A test containing a single large vector of zeroes, which
caused [poor performance](https://github.com/rust-lang/rust/issues/20936) in
the past.
Expand Down
7 changes: 7 additions & 0 deletions collector/benchmarks/deeply-nested-multi/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions collector/benchmarks/deeply-nested-multi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "deeply-nested-multi"
version = "0.1.0"
authors = [
"Tatsuyuki Ishi <[email protected]>",
"Bastian Kauschke <[email protected]>",
"Valerii Lashmanov <[email protected]>",
]
edition = "2021"

[dependencies]

[workspace]
3 changes: 3 additions & 0 deletions collector/benchmarks/deeply-nested-multi/perf-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"category": "secondary"
}
145 changes: 145 additions & 0 deletions collector/benchmarks/deeply-nested-multi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// There used to be three distinct stress tests named `deeply-nested`,
// `deeply-nested-closures`, and `deeply-nested-async`. They were combined into
// this single stress test because having three separate stress tests cluttered
// up the results. A single stress test should be enough to identify any
// regressions.

//---------------------------------------------------------------------------
// deeply-nested-closures
//---------------------------------------------------------------------------

#![type_length_limit="469762040"]

//---------------------------------------------------------------------------
// deeply-nested
//---------------------------------------------------------------------------
// A test case from rust-lang/rust#38528.
// The original blowup had both exponential compute and memory complexity.
// The nesting should be kept at 16 level to avoid crashing the test machine.

pub fn foo1() -> Box<dyn Iterator<Item = ()>> {
use std::iter::empty;

Box::new(empty()
.chain(empty())
.chain(empty())
.chain(empty())
.chain(empty())
.chain(empty())
.chain(empty())
.chain(empty())
.chain(empty())
.chain(empty())
.chain(empty()) // 10th .chain(empty())
.chain(empty())
.chain(empty())
.chain(empty())
.chain(empty())
.chain(empty())
.chain(empty()) // 16th .chain(empty())
)
}

//---------------------------------------------------------------------------
// deeply-nested-closures
//---------------------------------------------------------------------------
// A test case from rust-lang/rust#72408.
// Nesting closures produce exponentially sized type tree with a lot of duplicates.

fn dup(f: impl Fn(i32) -> i32) -> impl Fn(i32) -> i32 {
move |a| f(a * 2)
}

pub fn foo2() {
let f = |a| a;

let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);

let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);

let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);

let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);

let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);

println!("Type size was at least {}", f(1));
}

//---------------------------------------------------------------------------
// deeply-nested-async
//---------------------------------------------------------------------------
// A regression test for #75992.
// Nested async blocks produce an exponentially sized type tree with a lot of duplicates.
//
// Created by @kellerkindt in https://github.com/rust-lang/rust/issues/75992#issuecomment-682595159.

pub async fn h0(v: &String, x: &u64) { println!("{} {}", v, x) }
pub async fn h1(v: &String, x: &u64) { h0(v, x).await }
pub async fn h2(v: &String, x: &u64) { h1(v, x).await }
pub async fn h3(v: &String, x: &u64) { h2(v, x).await }
pub async fn h4(v: &String, x: &u64) { h3(v, x).await }
pub async fn h5(v: &String, x: &u64) { h4(v, x).await }
pub async fn h6(v: &String, x: &u64) { h5(v, x).await }
pub async fn h7(v: &String, x: &u64) { h6(v, x).await }
pub async fn h8(v: &String, x: &u64) { h7(v, x).await }
pub async fn h9(v: &String, x: &u64) { h8(v, x).await }

pub async fn h10(v: &String, x: &u64) { h9(v, x).await }
pub async fn h11(v: &String, x: &u64) { h10(v, x).await }
pub async fn h12(v: &String, x: &u64) { h11(v, x).await }
pub async fn h13(v: &String, x: &u64) { h12(v, x).await }
pub async fn h14(v: &String, x: &u64) { h13(v, x).await }
pub async fn h15(v: &String, x: &u64) { h14(v, x).await }
pub async fn h16(v: &String, x: &u64) { h15(v, x).await }
pub async fn h17(v: &String, x: &u64) { h16(v, x).await }
pub async fn h18(v: &String, x: &u64) { h17(v, x).await }
pub async fn h19(v: &String, x: &u64) { h18(v, x).await }


macro_rules! async_recursive {
(13, $inner:expr) => { async { async_recursive!(12, $inner) }.await };
(12, $inner:expr) => { async { async_recursive!(11, $inner) }.await };
(11, $inner:expr) => { async { async_recursive!(10, $inner) }.await };
(10, $inner:expr) => { async { async_recursive!(9, $inner) }.await };

(9, $inner:expr) => { async { async_recursive!(8, $inner) }.await };
(8, $inner:expr) => { async { async_recursive!(7, $inner) }.await };
(7, $inner:expr) => { async { async_recursive!(6, $inner) }.await };
(6, $inner:expr) => { async { async_recursive!(5, $inner) }.await };
(5, $inner:expr) => { async { async_recursive!(4, $inner) }.await };
(4, $inner:expr) => { async { async_recursive!(3, $inner) }.await };
(3, $inner:expr) => { async { async_recursive!(2, $inner) }.await };
(2, $inner:expr) => { async { async_recursive!(1, $inner) }.await };
(1, $inner:expr) => { async { async_recursive!(0, $inner) }.await };
(0, $inner:expr) => { async { h19(&String::from("owo"), &0).await; $inner }.await };
}

async fn f() {
async_recursive!(13, println!("hello"));
}

pub fn foo3() {
let _ = f();
}

4 changes: 2 additions & 2 deletions docs/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ The following is a glossary of domain specific terminology. Although benchmarks

## Benchmarks

* **stress test benchmark**: a benchmark that is specifically designed to stress a certain part of the compiler. For example, [deeply-nested-async](https://github.com/rust-lang/rustc-perf/tree/master/collector/benchmarks/deeply-nested-async) is meant to stress parts of the compiler used in async code.
* **stress test benchmark**: a benchmark that is specifically designed to stress a certain part of the compiler. For example, [projection-caching](https://github.com/rust-lang/rustc-perf/tree/master/collector/benchmarks/projection-caching) stresses the compiler's projection caching mechanisms.
* **real world benchmark**: a benchmark based on a real world crate. These are typically copied as-is from crates.io. For example, [serde](https://github.com/rust-lang/rustc-perf/tree/master/collector/benchmarks/serde) is a popular crate and the benchmark has not been altered from a release of serde on crates.io.

## Artifacts
Expand Down Expand Up @@ -44,4 +44,4 @@ The following is a glossary of domain specific terminology. Although benchmarks
## Other

* **bootstrap**: the process of building the compiler from a previous version of the compiler
* **compiler query**: a query used inside the [compiler query system](https://rustc-dev-guide.rust-lang.org/overview.html#queries).
* **compiler query**: a query used inside the [compiler query system](https://rustc-dev-guide.rust-lang.org/overview.html#queries).