Skip to content

Commit bc1f2fc

Browse files
authored
Merge pull request #1205 from nnethercote/merge-deeply-nested
Add `deeply-nested-multi` benchmark.
2 parents 5abe11b + e85b254 commit bc1f2fc

File tree

6 files changed

+175
-2
lines changed

6 files changed

+175
-2
lines changed

collector/benchmarks/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ compiler in interesting ways.
7373
behavior](https://github.com/rust-lang/rust/issues/75992) in the past.
7474
- **deeply-nested-closures**: A small program that caused [exponential
7575
behavior](https://github.com/rust-lang/rust/issues/72408) in the past.
76+
- **deeply-nested-multi**: A small program containing multiple examples
77+
([one](https://github.com/rust-lang/rust/issues/38528),
78+
[two](https://github.com/rust-lang/rust/issues/72408),
79+
[three](https://github.com/rust-lang/rust/issues/75992))
80+
of code that caused exponential behavior in the past.
7681
- **deep-vector**: A test containing a single large vector of zeroes, which
7782
caused [poor performance](https://github.com/rust-lang/rust/issues/20936) in
7883
the past.

collector/benchmarks/deeply-nested-multi/Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "deeply-nested-multi"
3+
version = "0.1.0"
4+
authors = [
5+
"Tatsuyuki Ishi <[email protected]>",
6+
"Bastian Kauschke <[email protected]>",
7+
"Valerii Lashmanov <[email protected]>",
8+
]
9+
edition = "2021"
10+
11+
[dependencies]
12+
13+
[workspace]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"category": "secondary"
3+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// There used to be three distinct stress tests named `deeply-nested`,
2+
// `deeply-nested-closures`, and `deeply-nested-async`. They were combined into
3+
// this single stress test because having three separate stress tests cluttered
4+
// up the results. A single stress test should be enough to identify any
5+
// regressions.
6+
7+
//---------------------------------------------------------------------------
8+
// deeply-nested-closures
9+
//---------------------------------------------------------------------------
10+
11+
#![type_length_limit="469762040"]
12+
13+
//---------------------------------------------------------------------------
14+
// deeply-nested
15+
//---------------------------------------------------------------------------
16+
// A test case from rust-lang/rust#38528.
17+
// The original blowup had both exponential compute and memory complexity.
18+
// The nesting should be kept at 16 level to avoid crashing the test machine.
19+
20+
pub fn foo1() -> Box<dyn Iterator<Item = ()>> {
21+
use std::iter::empty;
22+
23+
Box::new(empty()
24+
.chain(empty())
25+
.chain(empty())
26+
.chain(empty())
27+
.chain(empty())
28+
.chain(empty())
29+
.chain(empty())
30+
.chain(empty())
31+
.chain(empty())
32+
.chain(empty())
33+
.chain(empty()) // 10th .chain(empty())
34+
.chain(empty())
35+
.chain(empty())
36+
.chain(empty())
37+
.chain(empty())
38+
.chain(empty())
39+
.chain(empty()) // 16th .chain(empty())
40+
)
41+
}
42+
43+
//---------------------------------------------------------------------------
44+
// deeply-nested-closures
45+
//---------------------------------------------------------------------------
46+
// A test case from rust-lang/rust#72408.
47+
// Nesting closures produce exponentially sized type tree with a lot of duplicates.
48+
49+
fn dup(f: impl Fn(i32) -> i32) -> impl Fn(i32) -> i32 {
50+
move |a| f(a * 2)
51+
}
52+
53+
pub fn foo2() {
54+
let f = |a| a;
55+
56+
let f = dup(f);
57+
let f = dup(f);
58+
let f = dup(f);
59+
let f = dup(f);
60+
let f = dup(f);
61+
62+
let f = dup(f);
63+
let f = dup(f);
64+
let f = dup(f);
65+
let f = dup(f);
66+
let f = dup(f);
67+
68+
let f = dup(f);
69+
let f = dup(f);
70+
let f = dup(f);
71+
let f = dup(f);
72+
let f = dup(f);
73+
74+
let f = dup(f);
75+
let f = dup(f);
76+
let f = dup(f);
77+
let f = dup(f);
78+
let f = dup(f);
79+
80+
let f = dup(f);
81+
let f = dup(f);
82+
let f = dup(f);
83+
let f = dup(f);
84+
let f = dup(f);
85+
86+
println!("Type size was at least {}", f(1));
87+
}
88+
89+
//---------------------------------------------------------------------------
90+
// deeply-nested-async
91+
//---------------------------------------------------------------------------
92+
// A regression test for #75992.
93+
// Nested async blocks produce an exponentially sized type tree with a lot of duplicates.
94+
//
95+
// Created by @kellerkindt in https://github.com/rust-lang/rust/issues/75992#issuecomment-682595159.
96+
97+
pub async fn h0(v: &String, x: &u64) { println!("{} {}", v, x) }
98+
pub async fn h1(v: &String, x: &u64) { h0(v, x).await }
99+
pub async fn h2(v: &String, x: &u64) { h1(v, x).await }
100+
pub async fn h3(v: &String, x: &u64) { h2(v, x).await }
101+
pub async fn h4(v: &String, x: &u64) { h3(v, x).await }
102+
pub async fn h5(v: &String, x: &u64) { h4(v, x).await }
103+
pub async fn h6(v: &String, x: &u64) { h5(v, x).await }
104+
pub async fn h7(v: &String, x: &u64) { h6(v, x).await }
105+
pub async fn h8(v: &String, x: &u64) { h7(v, x).await }
106+
pub async fn h9(v: &String, x: &u64) { h8(v, x).await }
107+
108+
pub async fn h10(v: &String, x: &u64) { h9(v, x).await }
109+
pub async fn h11(v: &String, x: &u64) { h10(v, x).await }
110+
pub async fn h12(v: &String, x: &u64) { h11(v, x).await }
111+
pub async fn h13(v: &String, x: &u64) { h12(v, x).await }
112+
pub async fn h14(v: &String, x: &u64) { h13(v, x).await }
113+
pub async fn h15(v: &String, x: &u64) { h14(v, x).await }
114+
pub async fn h16(v: &String, x: &u64) { h15(v, x).await }
115+
pub async fn h17(v: &String, x: &u64) { h16(v, x).await }
116+
pub async fn h18(v: &String, x: &u64) { h17(v, x).await }
117+
pub async fn h19(v: &String, x: &u64) { h18(v, x).await }
118+
119+
120+
macro_rules! async_recursive {
121+
(13, $inner:expr) => { async { async_recursive!(12, $inner) }.await };
122+
(12, $inner:expr) => { async { async_recursive!(11, $inner) }.await };
123+
(11, $inner:expr) => { async { async_recursive!(10, $inner) }.await };
124+
(10, $inner:expr) => { async { async_recursive!(9, $inner) }.await };
125+
126+
(9, $inner:expr) => { async { async_recursive!(8, $inner) }.await };
127+
(8, $inner:expr) => { async { async_recursive!(7, $inner) }.await };
128+
(7, $inner:expr) => { async { async_recursive!(6, $inner) }.await };
129+
(6, $inner:expr) => { async { async_recursive!(5, $inner) }.await };
130+
(5, $inner:expr) => { async { async_recursive!(4, $inner) }.await };
131+
(4, $inner:expr) => { async { async_recursive!(3, $inner) }.await };
132+
(3, $inner:expr) => { async { async_recursive!(2, $inner) }.await };
133+
(2, $inner:expr) => { async { async_recursive!(1, $inner) }.await };
134+
(1, $inner:expr) => { async { async_recursive!(0, $inner) }.await };
135+
(0, $inner:expr) => { async { h19(&String::from("owo"), &0).await; $inner }.await };
136+
}
137+
138+
async fn f() {
139+
async_recursive!(13, println!("hello"));
140+
}
141+
142+
pub fn foo3() {
143+
let _ = f();
144+
}
145+

docs/glossary.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ The following is a glossary of domain specific terminology. Although benchmarks
1313

1414
## Benchmarks
1515

16-
* **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.
16+
* **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.
1717
* **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.
1818

1919
## Artifacts
@@ -44,4 +44,4 @@ The following is a glossary of domain specific terminology. Although benchmarks
4444
## Other
4545

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

0 commit comments

Comments
 (0)