Skip to content

Commit ede91c6

Browse files
feat: parallelizing the execution of C++ and Rust test-files
1 parent bb674f3 commit ede91c6

File tree

3 files changed

+141
-77
lines changed

3 files changed

+141
-77
lines changed

crates/intrinsic-test/src/common/compare.rs

Lines changed: 53 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,50 +12,71 @@ fn runner_command(runner: &str) -> Command {
1212
}
1313

1414
pub fn compare_outputs(intrinsic_name_list: &Vec<String>, runner: &str, target: &str) -> bool {
15-
let (c, rust) = rayon::join(
16-
|| {
15+
let available_parallelism = std::thread::available_parallelism().unwrap().get();
16+
let c_outputs = (0..available_parallelism)
17+
.into_par_iter()
18+
.map(|i| {
1719
runner_command(runner)
18-
.arg("./intrinsic-test-programs")
20+
.arg(format!("./intrinsic-test-programs_{i}"))
1921
.current_dir("c_programs")
2022
.output()
21-
},
22-
|| {
23+
})
24+
.collect::<Vec<_>>();
25+
26+
let rust_outputs = (0..available_parallelism)
27+
.into_par_iter()
28+
.map(|i| {
2329
runner_command(runner)
24-
.arg(format!("./target/{target}/release/intrinsic-test-programs"))
30+
.arg(format!(
31+
"./target/{target}/release/intrinsic-test-programs-{i}"
32+
))
2533
.current_dir("rust_programs")
2634
.output()
27-
},
28-
);
29-
let (c, rust) = match (c, rust) {
30-
(Ok(c), Ok(rust)) => (c, rust),
35+
})
36+
.collect::<Vec<_>>();
37+
38+
let c_error = c_outputs.iter().filter(|elem| elem.is_err()).next();
39+
let rust_error = rust_outputs.iter().filter(|elem| elem.is_err()).next();
40+
match (c_error, rust_error) {
41+
(None, None) => (),
3142
failure => panic!("Failed to run: {failure:#?}"),
3243
};
3344

34-
if !c.status.success() {
35-
error!(
36-
"Failed to run C program.\nstdout: {stdout}\nstderr: {stderr}",
37-
stdout = std::str::from_utf8(&c.stdout).unwrap_or(""),
38-
stderr = std::str::from_utf8(&c.stderr).unwrap_or(""),
39-
);
40-
}
45+
let c_stdout = c_outputs
46+
.into_iter()
47+
.map(|c_elem| {
48+
let c = c_elem.unwrap();
49+
let c_stdout = std::str::from_utf8(&c.stdout).unwrap_or("").to_string();
50+
if !c.status.success() {
51+
error!(
52+
"Failed to run C program.\nstdout: {c_stdout}\nstderr: {stderr}",
53+
stderr = std::str::from_utf8(&c.stderr).unwrap_or(""),
54+
);
55+
}
56+
c_stdout
57+
})
58+
.collect_vec()
59+
.join("\n");
4160

42-
if !rust.status.success() {
43-
error!(
44-
"Failed to run Rust program.\nstdout: {stdout}\nstderr: {stderr}",
45-
stdout = std::str::from_utf8(&rust.stdout).unwrap_or(""),
46-
stderr = std::str::from_utf8(&rust.stderr).unwrap_or(""),
47-
);
48-
}
61+
let rust_stdout = rust_outputs
62+
.into_iter()
63+
.map(|rust_elem| {
64+
let rust = rust_elem.unwrap();
65+
let rust_stdout = std::str::from_utf8(&rust.stdout).unwrap_or("").to_string();
66+
if !rust.status.success() {
67+
error!(
68+
"Failed to run Rust program.\nstdout: {rust_stdout}\nstderr: {stderr}",
69+
stderr = std::str::from_utf8(&rust.stderr).unwrap_or(""),
70+
);
71+
}
72+
rust_stdout
73+
})
74+
.collect_vec()
75+
.join("\n");
4976

5077
info!("Completed running C++ and Rust test binaries");
51-
let c = std::str::from_utf8(&c.stdout)
52-
.unwrap()
53-
.to_lowercase()
54-
.replace("-nan", "nan");
55-
let rust = std::str::from_utf8(&rust.stdout)
56-
.unwrap()
57-
.to_lowercase()
58-
.replace("-nan", "nan");
78+
let c = c_stdout.to_lowercase().replace("-nan", "nan");
79+
let rust = rust_stdout.to_lowercase().replace("-nan", "nan");
5980

6081
let c_output_map = c
6182
.split(INTRINSIC_DELIMITER)

crates/intrinsic-test/src/common/gen_rust.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ fn write_cargo_toml_header(w: &mut impl std::io::Write, name: &str) -> std::io::
3939
pub fn write_bin_cargo_toml(
4040
w: &mut impl std::io::Write,
4141
module_count: usize,
42+
binary_count: usize,
4243
) -> std::io::Result<()> {
4344
write_cargo_toml_header(w, "intrinsic-test-programs")?;
4445

@@ -49,6 +50,12 @@ pub fn write_bin_cargo_toml(
4950
writeln!(w, "mod_{i} = {{ path = \"mod_{i}/\" }}")?;
5051
}
5152

53+
for i in 0..binary_count {
54+
writeln!(w, "[[bin]]")?;
55+
writeln!(w, "name = \"intrinsic-test-programs_{i}\"")?;
56+
writeln!(w, "path = \"src/main_{i}.rs\"")?;
57+
}
58+
5259
Ok(())
5360
}
5461

crates/intrinsic-test/src/common/mod.rs

Lines changed: 81 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ pub mod values;
2929

3030
/// Architectures must support this trait
3131
/// to be successfully tested.
32-
pub trait SupportedArchitectureTest {
32+
pub trait SupportedArchitectureTest
33+
where
34+
Self: Sync + Send,
35+
{
3336
type IntrinsicImpl: IntrinsicTypeDefinition + Sync;
3437

3538
fn cli_options(&self) -> &ProcessedCli;
@@ -95,55 +98,88 @@ pub trait SupportedArchitectureTest {
9598
.collect::<Result<(), String>>()
9699
.unwrap();
97100

98-
let mut file = File::create("c_programs/main.cpp").unwrap();
99-
write_main_cpp(
100-
&mut file,
101-
Self::PLATFORM_C_DEFINITIONS,
102-
Self::PLATFORM_C_HEADERS,
103-
self.intrinsics().iter().map(|i| i.name.as_str()),
104-
)
105-
.unwrap();
106-
107-
// This is done because `cpp_compiler_wrapped` is None when
108-
// the --generate-only flag is passed
101+
let (auto_chunk_size, auto_chunk_count) = auto_chunk(self.intrinsics().len());
102+
103+
self.intrinsics()
104+
.par_chunks(auto_chunk_size)
105+
.enumerate()
106+
.map(|(i, chunk)| {
107+
let mut file = File::create(format!("c_programs/main_{i}.cpp")).unwrap();
108+
write_main_cpp(
109+
&mut file,
110+
Self::PLATFORM_C_DEFINITIONS,
111+
Self::PLATFORM_C_HEADERS,
112+
chunk.iter().map(|i| i.name.as_str()),
113+
)
114+
})
115+
.collect::<Result<(), std::io::Error>>()
116+
.unwrap();
117+
109118
if let Some(cpp_compiler) = cpp_compiler_wrapped.as_ref() {
110-
// compile this cpp file into a .o file
111-
trace!("compiling main.cpp");
112-
let output = cpp_compiler
113-
.compile_object_file("main.cpp", "intrinsic-test-programs.o")
114-
.unwrap();
115-
assert!(output.status.success(), "{output:?}");
116-
117-
let object_files = (0..chunk_count)
118-
.map(|i| format!("mod_{i}.o"))
119-
.chain(["intrinsic-test-programs.o".to_owned()]);
120-
121-
let output = cpp_compiler
122-
.link_executable(object_files, "intrinsic-test-programs")
123-
.unwrap();
124-
assert!(output.status.success(), "{output:?}");
125-
}
119+
(0..auto_chunk_count)
120+
.into_par_iter()
121+
.map(|index| {
122+
// This is done because `cpp_compiler_wrapped` is None when
123+
// the --generate-only flag is passed
124+
// compile this cpp file into a .o file
125+
trace!("compiling main_{index}.cpp");
126+
let output = cpp_compiler.compile_object_file(
127+
format!("main_{index}.cpp").as_str(),
128+
format!("main_{index}.o").as_str(),
129+
);
126130

127-
true
131+
if output.is_err() {
132+
return output;
133+
};
134+
135+
let object_files = (0..chunk_count)
136+
.map(|i| format!("mod_{i}.o"))
137+
.chain([format!("main_{index}.o").to_owned()]);
138+
139+
let output = cpp_compiler.link_executable(
140+
object_files,
141+
format!("intrinsic-test-programs-{index}").as_str(),
142+
);
143+
trace!("finished compiling main_{index}.cpp");
144+
145+
return output;
146+
})
147+
.inspect(|output| {
148+
assert!(output.is_ok(), "{output:?}");
149+
if let Ok(out) = &output {
150+
assert!(out.status.success(), "{output:?}")
151+
}
152+
})
153+
.all(|output| output.is_ok())
154+
} else {
155+
true
156+
}
128157
}
129158

130159
fn build_rust_file(&self) -> bool {
131160
std::fs::create_dir_all("rust_programs/src").unwrap();
132161

133162
let (chunk_size, chunk_count) = manual_chunk(self.intrinsics().len(), 400);
163+
let (auto_chunk_size, auto_chunk_count) = auto_chunk(self.intrinsics().len());
134164

135165
let mut cargo = File::create("rust_programs/Cargo.toml").unwrap();
136-
write_bin_cargo_toml(&mut cargo, chunk_count).unwrap();
137-
138-
let mut main_rs = File::create("rust_programs/src/main.rs").unwrap();
139-
write_main_rs(
140-
&mut main_rs,
141-
chunk_count,
142-
Self::PLATFORM_RUST_CFGS,
143-
"",
144-
self.intrinsics().iter().map(|i| i.name.as_str()),
145-
)
146-
.unwrap();
166+
write_bin_cargo_toml(&mut cargo, chunk_count, auto_chunk_count).unwrap();
167+
168+
self.intrinsics()
169+
.par_chunks(auto_chunk_size)
170+
.enumerate()
171+
.map(|(i, chunk)| {
172+
let mut main_rs = File::create(format!("rust_programs/src/main_{i}.rs")).unwrap();
173+
write_main_rs(
174+
&mut main_rs,
175+
chunk_count,
176+
Self::PLATFORM_RUST_CFGS,
177+
"",
178+
chunk.iter().map(|i| i.name.as_str()),
179+
)
180+
})
181+
.collect::<Result<(), std::io::Error>>()
182+
.unwrap();
147183

148184
let target = &self.cli_options().target;
149185
let toolchain = self.cli_options().toolchain.as_deref();
@@ -200,12 +236,12 @@ pub trait SupportedArchitectureTest {
200236
}
201237
}
202238

203-
// pub fn chunk_info(intrinsic_count: usize) -> (usize, usize) {
204-
// let available_parallelism = std::thread::available_parallelism().unwrap().get();
205-
// let chunk_size = intrinsic_count.div_ceil(Ord::min(available_parallelism, intrinsic_count));
239+
pub fn auto_chunk(intrinsic_count: usize) -> (usize, usize) {
240+
let available_parallelism = std::thread::available_parallelism().unwrap().get();
241+
let chunk_size = intrinsic_count.div_ceil(Ord::min(available_parallelism, intrinsic_count));
206242

207-
// (chunk_size, intrinsic_count.div_ceil(chunk_size))
208-
// }
243+
(chunk_size, intrinsic_count.div_ceil(chunk_size))
244+
}
209245

210246
pub fn manual_chunk(intrinsic_count: usize, chunk_size: usize) -> (usize, usize) {
211247
(chunk_size, intrinsic_count.div_ceil(chunk_size))

0 commit comments

Comments
 (0)