-
-
Notifications
You must be signed in to change notification settings - Fork 14.7k
Add the parallel front-end test suite #143953
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -150,6 +150,9 @@ pub struct TestProps { | |
| // empty before the test starts. Incremental mode tests will reuse the | ||
| // incremental directory between passes in the same test. | ||
| pub incremental: bool, | ||
| // Number of times to run the test, for the parallel front-end test suit. | ||
| // Repeat tests to ensure no ICEs occur. | ||
| pub iteration_count: Option<usize>, | ||
| // If `true`, this test is a known bug. | ||
| // | ||
| // When set, some requirements are relaxed. Currently, this only means no | ||
|
|
@@ -238,6 +241,7 @@ mod directives { | |
| pub const ASSEMBLY_OUTPUT: &'static str = "assembly-output"; | ||
| pub const STDERR_PER_BITWIDTH: &'static str = "stderr-per-bitwidth"; | ||
| pub const INCREMENTAL: &'static str = "incremental"; | ||
| pub const ITERATION_COUNT: &'static str = "iteration-count"; | ||
| pub const KNOWN_BUG: &'static str = "known-bug"; | ||
| pub const TEST_MIR_PASS: &'static str = "test-mir-pass"; | ||
| pub const REMAP_SRC_BASE: &'static str = "remap-src-base"; | ||
|
|
@@ -280,6 +284,7 @@ impl TestProps { | |
| forbid_output: vec![], | ||
| incremental_dir: None, | ||
| incremental: false, | ||
| iteration_count: None, | ||
| known_bug: false, | ||
| pass_mode: None, | ||
| fail_mode: None, | ||
|
|
@@ -540,6 +545,16 @@ impl TestProps { | |
| &mut self.stderr_per_bitwidth, | ||
| ); | ||
| config.set_name_directive(ln, INCREMENTAL, &mut self.incremental); | ||
| config.set_name_value_directive( | ||
| ln, | ||
| ITERATION_COUNT, | ||
| &mut self.iteration_count, | ||
| |s| { | ||
| s.trim() | ||
| .parse() | ||
| .expect("The value of iteration-count must be a positive integer.") | ||
| }, | ||
| ); | ||
|
|
||
| // Unlike the other `name_value_directive`s this needs to be handled manually, | ||
| // because it sets a `bool` flag. | ||
|
|
@@ -892,6 +907,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ | |
| "ignore-x86_64-pc-windows-gnu", | ||
| "ignore-x86_64-unknown-linux-gnu", | ||
| "incremental", | ||
| "iteration-count", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: please document this directive in |
||
| "known-bug", | ||
| "llvm-cov-flags", | ||
| "max-llvm-major-version", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| use crate::runtest::{TestCx, WillExecute}; | ||
|
|
||
| impl TestCx<'_> { | ||
| pub(super) fn run_parallel_test(&self) { | ||
| let pm = self.pass_mode(); | ||
| let emit_metadata = self.should_emit_metadata(pm); | ||
|
|
||
| // Repeated testing due to instability in multithreaded environments. | ||
| let iteration_count = self.props.iteration_count.unwrap_or(50); | ||
| for _ in 0..iteration_count { | ||
| let proc_res = self.compile_test(WillExecute::No, emit_metadata); | ||
| // Ensure there is no ICE during parallel complication. | ||
| self.check_no_compiler_crash(&proc_res, false); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should add a timeout here to prevent CI from getting stuck in a deadlock.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or does the current test set already have it? @jieyouxu
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current compiletest executor is basically libtest's. That is, tests are ran under test threads. There's a test running for too long warning message, but no hard kill-after-timeout, which IIUC is hard to implement with this setup because it'd require some kind of collaborative scheme. For existing tests we've massaged them to not take that long, or disabled them if e.g. the compile time truly that long pointing to an issue tracking it. |
||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| This directory contains the robustness test for prallel front end, which means deadlocks | ||
| and other ice bugs. In other words, we don't care whether the compiler output in these tests, | ||
| but whether they can compile normally without deadlock or other ice bugs. | ||
|
|
||
| So when a test in this directory fails, please pay attention to whether it causes any ice problems. | ||
| If so(it should do), please post your comments in the issue corresponding to each test (or create a new issue | ||
| with the `wg-parallel-rustc` label). Even if it is an existing issue, please add a new comment, | ||
| which will help us determine the reproducibility of the bug. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| // Test for #111528, the ice issue cause waiting on a query that panicked | ||
| // | ||
| //@ compile-flags: -Z threads=16 | ||
|
|
||
| #![crate_type = "rlib"] | ||
| #![allow(warnings)] | ||
|
|
||
| #[export_name = "fail"] | ||
| pub fn a() {} | ||
|
|
||
| #[export_name = "fail"] | ||
| pub fn b() {} | ||
|
|
||
| fn main() {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| //@ compile-flags: -Z threads=2 | ||
| //@ iteration-count: 20 | ||
|
|
||
| const FOO: usize = FOO; | ||
|
|
||
| fn main() {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| // Test for #119785, which causes a deadlock bug | ||
| // | ||
| //@ compile-flags: -Z threads=200 | ||
|
|
||
| #![allow(incomplete_features)] | ||
| #![feature( | ||
| const_trait_impl, | ||
| effects, | ||
| )] | ||
|
|
||
| use std::marker::Destruct; | ||
|
|
||
| const fn cmp(a: &impl ~const PartialEq) -> bool { | ||
| a == a | ||
| } | ||
|
|
||
| const fn wrap(x: impl ~const PartialEq + ~const Destruct) | ||
| -> impl ~const PartialEq + ~const Destruct | ||
| { | ||
| x | ||
| } | ||
|
|
||
| #[const_trait] | ||
| trait Foo { | ||
| fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output; | ||
| } | ||
|
|
||
| impl const Foo for () { | ||
| fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { | ||
| 123 | ||
| } | ||
| } | ||
|
|
||
| const _: () = { | ||
| assert!(cmp(&0xDEADBEEFu32)); | ||
| assert!(cmp(&())); | ||
| assert!(wrap(123) == wrap(123)); | ||
| assert!(wrap(123) != wrap(456)); | ||
| let x = <() as Foo>::huh(); | ||
| assert!(x == x); | ||
| }; | ||
|
|
||
| #[const_trait] | ||
| trait T {} | ||
| struct S; | ||
| impl const T for S {} | ||
|
|
||
| const fn rpit() -> impl ~const T { S } | ||
|
|
||
| const fn apit(_: impl ~const T + ~const Destruct) {} | ||
|
|
||
| const fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) } | ||
|
|
||
| const fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T> + ~From Destruct) {} | ||
|
|
||
| fn main() {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| // Test for #120757, which causes a deadlock bug | ||
| // | ||
| //@ compile-flags: -Z threads=50 | ||
|
|
||
| #![feature(generic_const_exprs)] | ||
|
|
||
| trait TensorDimension { | ||
| const DIM: usize; | ||
| const ISSCALAR: bool = Self::DIM == 0; | ||
| fn is_scalar(&self) -> bool { | ||
| Self::ISSCALAR | ||
| } | ||
| } | ||
|
|
||
| trait TensorSize: TensorDimension { | ||
| fn size(&self) -> [usize; Self::DIM]; | ||
| fn inbounds(&self, index: [usize; Self::DIM]) -> bool { | ||
| index.iter().zip(self.size().iter()).all(|(i, s)| i < s) | ||
| } | ||
| } | ||
|
|
||
| trait Broadcastable: TensorSize + Sized { | ||
| type Element; | ||
| fn bget(&self, index: [usize; Self::DIM]) -> Option<Self::Element>; | ||
| fn lazy_updim<const NEWDIM: usize>( | ||
| &self, | ||
| size: [usize; NEWDIM], | ||
| ) -> LazyUpdim<Self, { Self::DIM }, NEWDIM> { | ||
| assert!( | ||
| NEWDIM >= Self::DIM, | ||
| "Updimmed tensor cannot have fewer indices than the initial one." | ||
| ); // const generic bounds on nightly. ( ) | ||
| LazyUpdim { size, reference: &self } | ||
| } | ||
| fn bmap<T, F: Fn(Self::Element) -> T>(&self, foo: F) -> BMap<T, Self, F, { Self::DIM }> { | ||
| BMap { reference: self, closure: foo } | ||
| } | ||
| } | ||
|
|
||
| struct LazyUpdim<'a, T: Broadcastable, const OLDDIM: usize, const DIM: usize> { | ||
| size: [usize; DIM], | ||
| reference: &'a T, | ||
| } | ||
|
|
||
| impl<'a, T: Broadcastable, const DIM: usize> TensorDimension for LazyUpdim<'a, T, { T::DIM }, DIM> { | ||
| const DIM: usize = DIM; | ||
| } | ||
| impl<'a, T: Broadcastable, const DIM: usize> TensorSize for LazyUpdim<'a, T, { T::DIM }, DIM> { | ||
| fn size(&self) -> [usize; DIM] { | ||
| self.size | ||
| } | ||
| } | ||
| impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a, T, { T::DIM }, DIM> { | ||
| type Element = T::Element; | ||
| fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> { | ||
| assert!(DIM >= T::DIM); | ||
| if !self.inbounds(index) { | ||
| return None; | ||
| } | ||
| let size = self.size(); | ||
| //array_init::array_init(|i| if size[i] > 1 {index[i]} else {0}); | ||
| let newindex: [usize; T::DIM] = Default::default(); | ||
| self.reference.bget(newindex) | ||
| } | ||
| } | ||
|
|
||
| struct BMap<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> { | ||
| reference: &'a T, | ||
| closure: F, | ||
| } | ||
|
|
||
| impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> TensorDimension | ||
| for BMap<'a, R, T, F, DIM> | ||
| { | ||
| const DIM: usize = DIM; | ||
| } | ||
| impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> TensorSize | ||
| for BMap<'a, R, T, F, DIM> | ||
| { | ||
| fn size(&self) -> [usize; DIM] { | ||
| self.reference.size() | ||
| } | ||
| } | ||
| impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> Broadcastable | ||
| for BMap<'a, R, T, F, DIM> | ||
| { | ||
| type Element = R; | ||
| fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> { | ||
| self.reference.bget(index).map(ns_window) | ||
| } | ||
| } | ||
|
|
||
| impl<T> TensorDimension for Vec<T> { | ||
| const DIM: usize = 1; | ||
| } | ||
| impl<T> TensorSize for Vec<T> { | ||
| fn size(&self) -> [usize; 1] { | ||
| [self.len()] | ||
| } | ||
| } | ||
| impl<T: Clone> Broadcastable for Vec<T> { | ||
| type Element = T; | ||
| fn bget(&self, index: [usize; 1]) -> Option<T> { | ||
| self.get(index[0]).cloned() | ||
| } | ||
| } | ||
|
|
||
| fn main() { | ||
| let v = vec![1, 2, 3]; | ||
| let bv = v.lazy_updim([3, 4]); | ||
| let bbv = bv.bmap(|x| x * x); | ||
|
|
||
| println!("The size of v is {:?}", bbv.bget([0, 2]).expect("Out of bounds.")); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| // Test for #120759, which causes a deadlock bug | ||
| // | ||
| //@ compile-flags: -Z threads=50 | ||
|
|
||
| #![crate_type= "lib"] | ||
| #![feature(transmutability)] | ||
|
|
||
| mod assert { | ||
| use std::mem::{Assume, BikeshedIntrinsicFrom}; | ||
| pub struct Context; | ||
|
|
||
| pub fn is_maybe_transmutable<Src, Dst>(&self, cpu: &mut CPU) | ||
| where | ||
| Dst: BikeshedIntrinsicFrom<Src, Context>, | ||
| { | ||
| } | ||
| } | ||
|
|
||
| fn should_pad_explicitly_packed_field() { | ||
| #[repr(C)] | ||
| struct ExplicitlyPadded(ExplicitlyPadded); | ||
|
|
||
| assert::is_maybe_transmutable::<ExplicitlyPadded, ()>(); | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: and please also document in
rustc-dev-guide(https://rustc-dev-guide.rust-lang.org/tests/compiletest.html#test-suites):