diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 17cb99b1..72a26554 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -31,7 +31,6 @@ jobs: pushd $t cargo fmt --check cargo clippy -- -D warnings - cargo test --no-fail-fast --all-features popd done @@ -52,7 +51,8 @@ jobs: - name: Install rust uses: actions-rust-lang/setup-rust-toolchain@v1 with: - components: rustfmt, clippy + toolchain: nightly + components: llvm-tools target: wasm32-unknown-unknown, x86_64-unknown-uefi cache-workspaces: | pixie-server @@ -60,6 +60,9 @@ jobs: pixie-uefi pixie-web + - name: Install rustfilt + run: cargo install rustfilt + - name: Install trunk uses: jetli/trunk-action@v0.5.0 diff --git a/.gitignore b/.gitignore index 246d80c1..b6127365 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ buildroot/pixie.tar.gz pixie-web/dist .*.swp pixie-shared/Cargo.lock +/prof-out diff --git a/pixie-uefi/Cargo.lock b/pixie-uefi/Cargo.lock index b064fbdb..e1a065b1 100644 --- a/pixie-uefi/Cargo.lock +++ b/pixie-uefi/Cargo.lock @@ -304,6 +304,16 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" +[[package]] +name = "minicov" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" +dependencies = [ + "cc", + "walkdir", +] + [[package]] name = "pin-project-lite" version = "0.2.15" @@ -337,6 +347,7 @@ dependencies = [ "log", "lz4_flex", "managed", + "minicov", "pixie-shared", "postcard", "rand", @@ -441,6 +452,15 @@ dependencies = [ "rand_core", ] +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "serde" version = "1.0.219" @@ -590,3 +610,37 @@ name = "unicode-ident" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-sys" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +dependencies = [ + "windows-link", +] diff --git a/pixie-uefi/Cargo.toml b/pixie-uefi/Cargo.toml index 14f4d04b..9f3c6006 100644 --- a/pixie-uefi/Cargo.toml +++ b/pixie-uefi/Cargo.toml @@ -9,6 +9,9 @@ path = "src/main.rs" test = false bench = false +[features] +coverage = ["dep:minicov"] + [dependencies] anstyle = { version = "1.0.11", default-features = false } blake3 = { version = "1.8.2", default-features = false, features = ["prefer_intrinsics", "no_avx512", "pure"] } @@ -18,6 +21,7 @@ gpt_disk_io = "0.16.2" log = "0.4.27" lz4_flex = { version = "0.11.5", default-features = false } managed = { version = "0.8.0", default-features = false, features = ["alloc"] } +minicov = { version = "0.3.7", optional = true } postcard = { version = "1.1.3", default-features = false, features = ["alloc"] } rand = { version = "0.8.5", default-features = false } rand_xoshiro = { version = "0.6.0", default-features = false } diff --git a/pixie-uefi/src/export_cov.rs b/pixie-uefi/src/export_cov.rs new file mode 100644 index 00000000..b665af8d --- /dev/null +++ b/pixie-uefi/src/export_cov.rs @@ -0,0 +1,10 @@ +use crate::os::{disk::Disk, UefiOS}; + +pub async fn export(os: UefiOS) { + let mut disk = Disk::open_with_size(os, 500 << 20); + + let mut coverage = vec![]; + // SAFETY: we never create threads anyway. + unsafe { minicov::capture_coverage(&mut coverage).unwrap() }; + disk.write_(0, &coverage).unwrap(); +} diff --git a/pixie-uefi/src/main.rs b/pixie-uefi/src/main.rs index 8b12177f..a90efafb 100644 --- a/pixie-uefi/src/main.rs +++ b/pixie-uefi/src/main.rs @@ -28,6 +28,9 @@ mod reboot_to_os; mod register; mod store; +#[cfg(feature = "coverage")] +mod export_cov; + const MIN_MEMORY: u64 = 500 << 20; async fn server_discover(os: UefiOS) -> Result { @@ -63,6 +66,9 @@ async fn server_discover(os: UefiOS) -> Result { } async fn shutdown(os: UefiOS) -> ! { + #[cfg(feature = "coverage")] + export_cov::export(os).await; + log::info!("Shutting down..."); os.sleep_us(1_000_000).await; os.shutdown() diff --git a/pixie-uefi/src/os/disk.rs b/pixie-uefi/src/os/disk.rs index dbb3fb17..76b892eb 100644 --- a/pixie-uefi/src/os/disk.rs +++ b/pixie-uefi/src/os/disk.rs @@ -50,18 +50,46 @@ pub struct Disk { // available; support having more than one disk. impl Disk { pub fn new(os: UefiOS) -> Disk { - let handle = uefi::boot::find_handles::() + let (_size, handle) = uefi::boot::find_handles::() .unwrap() .into_iter() - .find(|handle| { - let op = open_disk(*handle); - if let Ok((_, block)) = op { - if block.media().is_media_present() { - return true; - } + .filter_map(|handle| { + let op = open_disk(handle); + let Ok((_, block)) = op else { + return None; + }; + let m = block.media(); + if !m.is_media_present() { + return None; } - false + let size = (m.last_block() as u128 + 1) * (m.block_size() as u128); + Some((size, handle)) }) + .max_by_key(|(size, _)| *size) + .expect("Disk not found"); + + let (disk, block) = open_disk(handle).unwrap(); + Disk { disk, block, os } + } + + #[cfg(feature = "coverage")] + pub fn open_with_size(os: UefiOS, base_size: i64) -> Disk { + let (_size, handle) = uefi::boot::find_handles::() + .unwrap() + .into_iter() + .filter_map(|handle| { + let op = open_disk(handle); + let Ok((_, block)) = op else { + return None; + }; + let m = block.media(); + if !m.is_media_present() { + return None; + } + let size = (m.last_block() as i64 + 1) * (m.block_size() as i64); + Some(((size - base_size).abs(), handle)) + }) + .min_by_key(|(size, _)| *size) .expect("Disk not found"); let (disk, block) = open_disk(handle).unwrap(); @@ -83,6 +111,13 @@ impl Disk { .read_disk(self.block.media().media_id(), offset, buf)?) } + #[cfg(feature = "coverage")] + pub fn write_(&mut self, offset: u64, buf: &[u8]) -> Result<()> { + Ok(self + .disk + .write_disk(self.block.media().media_id(), offset, buf)?) + } + pub async fn write(&mut self, offset: u64, buf: &[u8]) -> Result<()> { self.os.schedule().await; Ok(self diff --git a/run_test.sh b/run_test.sh index 9deb99df..d36eba19 100755 --- a/run_test.sh +++ b/run_test.sh @@ -43,7 +43,7 @@ if ! ip link show br-pixie; then ip addr add 10.0.0.1/8 brd 10.255.255.255 dev br-pixie fi -RUST_BACKTRACE=short RUST_LOG=debug RUST_LOG_STYLE=always ./pixie-server/target/debug/pixie-server -s $TEMPDIR/storage & +RUST_BACKTRACE=short RUST_LOG=debug RUST_LOG_STYLE=always LLVM_PROFILE_FILE=prof-out/pixie-server-%m-%p.profraw ./pixie-server/target/debug/pixie-server -s $TEMPDIR/storage & run_qemu() { OVMF=/usr/share/OVMF/OVMF_CODE_4M.fd @@ -51,6 +51,8 @@ run_qemu() { then OVMF=/usr/share/edk2/x64/OVMF_CODE.4m.fd fi + FILE=prof-out/pixie-uefi-$RANDOM.profraw + truncate -s 500M $FILE qemu-system-x86_64 \ -nographic \ -chardev stdio,id=char0,logfile=$1,signal=off \ @@ -61,6 +63,7 @@ run_qemu() { -m 1G \ -drive if=pflash,format=raw,file=$OVMF \ -drive file=$TEMPDIR/disk.img,if=none,id=nvm,format=raw \ + -drive file=$FILE,format=raw \ -device nvme,serial=deadbeef,drive=nvm \ -nic bridge,mac=52:54:00:12:34:56,br=br-pixie,model=virtio-net-pci } diff --git a/test.sh b/test.sh index 7637de24..9478388f 100755 --- a/test.sh +++ b/test.sh @@ -4,7 +4,62 @@ set -xe SELFDIR="$(realpath "$(dirname "$0")")" cd "$SELFDIR" -./setup.sh +STORAGE_DIR="${SELFDIR}/storage" + +rm -rf prof-out +mkdir -p prof-out + +SYSROOT=$(rustc +nightly --print sysroot) +LLVM_TOOLS_DIR="$SYSROOT/lib/rustlib/$(rustc +nightly -Vv | grep host | awk '{print $2}')/bin" +LLVM_COV="$LLVM_TOOLS_DIR/llvm-cov" +LLVM_PROFDATA="$LLVM_TOOLS_DIR/llvm-profdata" + +pushd pixie-shared +RUSTFLAGS='-C instrument-coverage' LLVM_PROFILE_FILE=../prof-out/pixie-shared-test-%m-%p.profraw cargo +nightly test --no-fail-fast --all-features +popd + +pushd pixie-uefi +RUSTFLAGS='-Cinstrument-coverage -Zno-profiler-runtime' cargo +nightly build -F coverage +popd + +pushd pixie-web +trunk build +popd + +pushd pixie-server +RUSTFLAGS='-C instrument-coverage' cargo +nightly build +popd + +mkdir -p "${STORAGE_DIR}/tftpboot" "${STORAGE_DIR}/images" "${STORAGE_DIR}/chunks" "${STORAGE_DIR}/admin" +cp "pixie-uefi/target/x86_64-unknown-uefi/debug/pixie-uefi.efi" "${STORAGE_DIR}/tftpboot/" +cp -r pixie-web/dist/* "${STORAGE_DIR}/admin/" + +[ -f "${STORAGE_DIR}/config.yaml" ] || cp pixie-server/example.config.yaml "${STORAGE_DIR}/config.yaml" trap '' SIGTERM sudo ./run_test.sh ${SELFDIR}/storage + +TEST_OBJECTS=$( \ + for file in \ + $( \ + RUSTFLAGS="-C instrument-coverage" \ + cargo +nightly test --manifest-path pixie-shared/Cargo.toml --no-fail-fast --all-features --no-run --message-format=json \ + | jq -r "select(.profile.test == true) | .filenames[]" \ + | grep -v dSYM - \ + ); \ + do \ + printf "%s %s " -object $file; \ + done \ + ) + +"$LLVM_PROFDATA" merge -sparse prof-out/*.profraw -o prof-out/pixie.profdata +"$LLVM_COV" show \ + -instr-profile=prof-out/pixie.profdata \ + -object pixie-server/target/debug/pixie-server \ + -object pixie-uefi/target/x86_64-unknown-uefi/debug/pixie-uefi.efi \ + $TEST_OBJECTS \ + -Xdemangler=rustfilt \ + --ignore-filename-regex='/.cargo' \ + --ignore-filename-regex='/.rustup' \ + --format html \ + -o prof-out/html