Skip to content
Draft
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
8 changes: 4 additions & 4 deletions ci/intrinsic-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ case ${TARGET} in
TEST_CXX_COMPILER="clang++"
TEST_RUNNER="${CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER}"
TEST_SKIP_INTRINSICS=crates/intrinsic-test/missing_x86.txt
: "${TEST_SAMPLE_INTRINSICS_PERCENTAGE:=20}"
: "${TEST_SAMPLE_INTRINSICS_PERCENTAGE:=50}"
;;
*)
;;
Expand All @@ -85,7 +85,7 @@ esac
# Arm specific
case "${TARGET}" in
aarch64-unknown-linux-gnu*|armv7-unknown-linux-gnueabihf*)
CPPFLAGS="${TEST_CPPFLAGS}" RUSTFLAGS="${HOST_RUSTFLAGS}" RUST_LOG=info \
CPPFLAGS="${TEST_CPPFLAGS}" RUSTFLAGS="${HOST_RUSTFLAGS}" RUST_LOG=trace \
cargo run "${INTRINSIC_TEST}" "${PROFILE}" \
--bin intrinsic-test -- intrinsics_data/arm_intrinsics.json \
--runner "${TEST_RUNNER}" \
Expand All @@ -96,7 +96,7 @@ case "${TARGET}" in
;;

aarch64_be-unknown-linux-gnu*)
CPPFLAGS="${TEST_CPPFLAGS}" RUSTFLAGS="${HOST_RUSTFLAGS}" RUST_LOG=info \
CPPFLAGS="${TEST_CPPFLAGS}" RUSTFLAGS="${HOST_RUSTFLAGS}" RUST_LOG=trace \
cargo run "${INTRINSIC_TEST}" "${PROFILE}" \
--bin intrinsic-test -- intrinsics_data/arm_intrinsics.json \
--runner "${TEST_RUNNER}" \
Expand All @@ -114,7 +114,7 @@ case "${TARGET}" in
# Hence the use of `env -u`.
env -u CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER \
CPPFLAGS="${TEST_CPPFLAGS}" RUSTFLAGS="${HOST_RUSTFLAGS}" \
RUST_LOG=info RUST_BACKTRACE=1 \
RUST_LOG=trace RUST_BACKTRACE=1 \
cargo run "${INTRINSIC_TEST}" "${PROFILE}" \
--bin intrinsic-test -- intrinsics_data/x86-intel.xml \
--runner "${TEST_RUNNER}" \
Expand Down
3 changes: 3 additions & 0 deletions crates/intrinsic-test/src/arm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ pub struct ArmArchitectureTest {
cli_options: ProcessedCli,
}

unsafe impl Send for ArmArchitectureTest {}
unsafe impl Sync for ArmArchitectureTest {}

impl SupportedArchitectureTest for ArmArchitectureTest {
type IntrinsicImpl = ArmIntrinsicType;

Expand Down
85 changes: 53 additions & 32 deletions crates/intrinsic-test/src/common/compare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,50 +12,71 @@ fn runner_command(runner: &str) -> Command {
}

pub fn compare_outputs(intrinsic_name_list: &Vec<String>, runner: &str, target: &str) -> bool {
let (c, rust) = rayon::join(
|| {
let available_parallelism = std::thread::available_parallelism().unwrap().get();
let c_outputs = (0..available_parallelism)
.into_par_iter()
.map(|i| {
runner_command(runner)
.arg("./intrinsic-test-programs")
.arg(format!("./intrinsic-test-programs-{i}"))
.current_dir("c_programs")
.output()
},
|| {
})
.collect::<Vec<_>>();

let rust_outputs = (0..available_parallelism)
.into_par_iter()
.map(|i| {
runner_command(runner)
.arg(format!("./target/{target}/release/intrinsic-test-programs"))
.arg(format!(
"./target/{target}/release/intrinsic-test-programs-{i}"
))
.current_dir("rust_programs")
.output()
},
);
let (c, rust) = match (c, rust) {
(Ok(c), Ok(rust)) => (c, rust),
})
.collect::<Vec<_>>();

let c_error = c_outputs.iter().filter(|elem| elem.is_err()).next();
let rust_error = rust_outputs.iter().filter(|elem| elem.is_err()).next();
match (c_error, rust_error) {
(None, None) => (),
failure => panic!("Failed to run: {failure:#?}"),
};

if !c.status.success() {
error!(
"Failed to run C program.\nstdout: {stdout}\nstderr: {stderr}",
stdout = std::str::from_utf8(&c.stdout).unwrap_or(""),
stderr = std::str::from_utf8(&c.stderr).unwrap_or(""),
);
}
let c_stdout = c_outputs
.into_iter()
.map(|c_elem| {
let c = c_elem.unwrap();
let c_stdout = std::str::from_utf8(&c.stdout).unwrap_or("").to_string();
if !c.status.success() {
error!(
"Failed to run C program.\nstdout: {c_stdout}\nstderr: {stderr}",
stderr = std::str::from_utf8(&c.stderr).unwrap_or(""),
);
}
c_stdout
})
.collect_vec()
.join("\n");

if !rust.status.success() {
error!(
"Failed to run Rust program.\nstdout: {stdout}\nstderr: {stderr}",
stdout = std::str::from_utf8(&rust.stdout).unwrap_or(""),
stderr = std::str::from_utf8(&rust.stderr).unwrap_or(""),
);
}
let rust_stdout = rust_outputs
.into_iter()
.map(|rust_elem| {
let rust = rust_elem.unwrap();
let rust_stdout = std::str::from_utf8(&rust.stdout).unwrap_or("").to_string();
if !rust.status.success() {
error!(
"Failed to run Rust program.\nstdout: {rust_stdout}\nstderr: {stderr}",
stderr = std::str::from_utf8(&rust.stderr).unwrap_or(""),
);
}
rust_stdout
})
.collect_vec()
.join("\n");

info!("Completed running C++ and Rust test binaries");
let c = std::str::from_utf8(&c.stdout)
.unwrap()
.to_lowercase()
.replace("-nan", "nan");
let rust = std::str::from_utf8(&rust.stdout)
.unwrap()
.to_lowercase()
.replace("-nan", "nan");
let c = c_stdout.to_lowercase().replace("-nan", "nan");
let rust = rust_stdout.to_lowercase().replace("-nan", "nan");

let c_output_map = c
.split(INTRINSIC_DELIMITER)
Expand Down
7 changes: 7 additions & 0 deletions crates/intrinsic-test/src/common/gen_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ fn write_cargo_toml_header(w: &mut impl std::io::Write, name: &str) -> std::io::
pub fn write_bin_cargo_toml(
w: &mut impl std::io::Write,
module_count: usize,
binary_count: usize,
) -> std::io::Result<()> {
write_cargo_toml_header(w, "intrinsic-test-programs")?;

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

for i in 0..binary_count {
writeln!(w, "\n[[bin]]")?;
writeln!(w, "name = \"intrinsic-test-programs-{i}\"")?;
writeln!(w, "path = \"src/main_{i}.rs\"")?;
}

Ok(())
}

Expand Down
130 changes: 84 additions & 46 deletions crates/intrinsic-test/src/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ pub mod values;

/// Architectures must support this trait
/// to be successfully tested.
pub trait SupportedArchitectureTest {
pub trait SupportedArchitectureTest
where
Self: Sync + Send,
{
type IntrinsicImpl: IntrinsicTypeDefinition + Sync;

fn cli_options(&self) -> &ProcessedCli;
Expand All @@ -49,7 +52,7 @@ pub trait SupportedArchitectureTest {
fn cpp_compilation(&self) -> Option<CppCompilation>;

fn build_c_file(&self) -> bool {
let (chunk_size, chunk_count) = manual_chunk(self.intrinsics().len(), 400);
let (chunk_size, chunk_count) = manual_chunk(self.intrinsics().len(), 50);

let cpp_compiler_wrapped = self.cpp_compilation();

Expand Down Expand Up @@ -95,55 +98,90 @@ pub trait SupportedArchitectureTest {
.collect::<Result<(), String>>()
.unwrap();

let mut file = File::create("c_programs/main.cpp").unwrap();
write_main_cpp(
&mut file,
Self::PLATFORM_C_DEFINITIONS,
Self::PLATFORM_C_HEADERS,
self.intrinsics().iter().map(|i| i.name.as_str()),
)
.unwrap();

// This is done because `cpp_compiler_wrapped` is None when
// the --generate-only flag is passed
let (auto_chunk_size, auto_chunk_count) = auto_chunk(self.intrinsics().len());

self.intrinsics()
.par_chunks(auto_chunk_size)
.enumerate()
.map(|(i, chunk)| {
let mut file = File::create(format!("c_programs/main_{i}.cpp")).unwrap();
write_main_cpp(
&mut file,
Self::PLATFORM_C_DEFINITIONS,
Self::PLATFORM_C_HEADERS,
chunk.iter().map(|i| i.name.as_str()),
)
})
.collect::<Result<(), std::io::Error>>()
.unwrap();

if let Some(cpp_compiler) = cpp_compiler_wrapped.as_ref() {
// compile this cpp file into a .o file
trace!("compiling main.cpp");
let output = cpp_compiler
.compile_object_file("main.cpp", "intrinsic-test-programs.o")
.unwrap();
assert!(output.status.success(), "{output:?}");

let object_files = (0..chunk_count)
.map(|i| format!("mod_{i}.o"))
.chain(["intrinsic-test-programs.o".to_owned()]);

let output = cpp_compiler
.link_executable(object_files, "intrinsic-test-programs")
.unwrap();
assert!(output.status.success(), "{output:?}");
}
(0..auto_chunk_count)
.into_par_iter()
.map(|index| {
// This is done because `cpp_compiler_wrapped` is None when
// the --generate-only flag is passed
// compile this cpp file into a .o file
trace!("compiling main_{index}.cpp");
let output = cpp_compiler.compile_object_file(
format!("main_{index}.cpp").as_str(),
format!("main_{index}.o").as_str(),
);

if output.is_err() {
return output;
};

let object_files = (0..chunk_count)
.map(|i| format!("mod_{i}.o"))
.chain([format!("main_{index}.o").to_owned()]);

true
let output = cpp_compiler.link_executable(
object_files,
format!("intrinsic-test-programs-{index}").as_str(),
);
trace!("finished compiling main_{index}.cpp");

return output;
})
.inspect(|output| {
trace!("{output:?}");
assert!(output.is_ok(), "{output:?}");
if let Ok(out) = &output {
trace!("{:?}", out.status.success());
assert!(out.status.success(), "{output:?}")
}
})
.all(|output| output.is_ok())
} else {
true
}
}

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

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

let mut cargo = File::create("rust_programs/Cargo.toml").unwrap();
write_bin_cargo_toml(&mut cargo, chunk_count).unwrap();

let mut main_rs = File::create("rust_programs/src/main.rs").unwrap();
write_main_rs(
&mut main_rs,
chunk_count,
Self::PLATFORM_RUST_CFGS,
"",
self.intrinsics().iter().map(|i| i.name.as_str()),
)
.unwrap();
write_bin_cargo_toml(&mut cargo, chunk_count, auto_chunk_count).unwrap();

self.intrinsics()
.par_chunks(auto_chunk_size)
.enumerate()
.map(|(i, chunk)| {
let mut main_rs = File::create(format!("rust_programs/src/main_{i}.rs")).unwrap();
write_main_rs(
&mut main_rs,
chunk_count,
Self::PLATFORM_RUST_CFGS,
"",
chunk.iter().map(|i| i.name.as_str()),
)
})
.collect::<Result<(), std::io::Error>>()
.unwrap();

let target = &self.cli_options().target;
let toolchain = self.cli_options().toolchain.as_deref();
Expand Down Expand Up @@ -200,12 +238,12 @@ pub trait SupportedArchitectureTest {
}
}

// pub fn chunk_info(intrinsic_count: usize) -> (usize, usize) {
// let available_parallelism = std::thread::available_parallelism().unwrap().get();
// let chunk_size = intrinsic_count.div_ceil(Ord::min(available_parallelism, intrinsic_count));
pub fn auto_chunk(intrinsic_count: usize) -> (usize, usize) {
let available_parallelism = std::thread::available_parallelism().unwrap().get();
let chunk_size = intrinsic_count.div_ceil(Ord::min(available_parallelism, intrinsic_count));

// (chunk_size, intrinsic_count.div_ceil(chunk_size))
// }
(chunk_size, intrinsic_count.div_ceil(chunk_size))
}

pub fn manual_chunk(intrinsic_count: usize, chunk_size: usize) -> (usize, usize) {
(chunk_size, intrinsic_count.div_ceil(chunk_size))
Expand Down
19 changes: 14 additions & 5 deletions crates/intrinsic-test/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,22 @@ fn main() {
}
}

fn run(test_environment: impl SupportedArchitectureTest) {
info!("building C binaries");
if !test_environment.build_c_file() {
fn run(test_environment: impl SupportedArchitectureTest + Sync) {
let (c_output, rust_output) = rayon::join(
|| {
info!("building C binaries");
test_environment.build_c_file()
},
|| {
info!("building Rust binaries");
test_environment.build_rust_file()
},
);

if !c_output {
std::process::exit(2);
}
info!("building Rust binaries");
if !test_environment.build_rust_file() {
if !rust_output {
std::process::exit(3);
}
info!("Running binaries");
Expand Down
2 changes: 1 addition & 1 deletion crates/intrinsic-test/src/x86/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub fn build_cpp_compilation(config: &ProcessedCli) -> Option<CppCompilation> {
.add_arch_flags(["icelake-client"])
.set_compiler(cpp_compiler)
.set_target(&config.target)
.set_opt_level("2")
.set_opt_level("1")
.set_cxx_toolchain_dir(config.cxx_toolchain_dir.as_deref())
.set_project_root("c_programs")
.add_extra_flags(vec![
Expand Down
3 changes: 3 additions & 0 deletions crates/intrinsic-test/src/x86/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ pub struct X86ArchitectureTest {
cli_options: ProcessedCli,
}

unsafe impl Send for X86ArchitectureTest {}
unsafe impl Sync for X86ArchitectureTest {}

impl SupportedArchitectureTest for X86ArchitectureTest {
type IntrinsicImpl = X86IntrinsicType;

Expand Down
Loading