Skip to content

Commit

Permalink
Measure the Costs of Traps, World Switches, and Misaligned Operations…
Browse files Browse the repository at this point in the history
… with the Protect Payload Policy

This commit extends the tracing firmware by introducing three new latency measurements in the Protect Payload policy and ensures that no additional performance losses are incurred.
  • Loading branch information
francois141 committed Jan 4, 2025
1 parent 851f56c commit e66ee3a
Show file tree
Hide file tree
Showing 11 changed files with 443 additions and 169 deletions.
19 changes: 19 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ members = [
"firmware/os_ecall",
"firmware/device",
"firmware/tracing_firmware",
"firmware/tracing_firmware_protect_payload",
"firmware/vectored_mtvec",
"firmware/benchmark/ecall_benchmark",
"firmware/benchmark/csr_write",
Expand Down
23 changes: 23 additions & 0 deletions config/test/spike-latency-benchmark-protect-payload.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# A simple configuration to run on the Spike platform

[log]
level = "info"
color = true

[vcpu]
max_pmp = 8
delegate_perf_counters=true

[platform]
name = "spike"

[target.miralis]
# Build profile for Miralis (dev profile is set by default)
profile = "release"

[target.firmware]
# Build profile for the firmware (dev profile is set by default)
profile = "release"

[policy]
name = "protect_payload"
12 changes: 12 additions & 0 deletions crates/tracing/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "tracing"
version = "0.1.0"
edition = "2021"

license = "MIT"

[dependencies]
miralis_core = { path = "../core" }
log = { workspace = true }
config_helpers = { path = "../config_helpers"}
miralis_abi = { path = "../abi" }
220 changes: 220 additions & 0 deletions crates/tracing/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
//! Miralis ABI
//!
//! While miralis forwards standard SBI calls to the virtualized firmware, miralis do expose its own
//! ABI for the firmware to interact with.
//!
//! The Miralis ABI tries to be compatible with the SBI specification as best as it can.
//! See: https://github.com/riscv-non-isa/riscv-sbi-doc
#![no_std]

use core::arch::{asm, global_asm};

use miralis_abi::failure;

pub fn print_statistics(stats: Statistics) {
log::info!("{:?}", stats);
}

#[macro_export]
macro_rules! measure {
($policy_name:literal, $out:literal, $in:expr, $in2:expr) => {
let mut values: [usize; NB_REPEATS] = [0; NB_REPEATS];

for i in 0..NB_REPEATS {
values[i] = $in();
}

let stats = get_statistics(values);

let average_measure = $in2();

log::info!("{} cost {} : {}", $policy_name, $out, average_measure);

print_statistics(stats);
};
}

pub fn enable_mcycle_in_smode() {
unsafe {
// This allows to read cycle in S-mode - for the payload
let mcounteren: u32;
asm!("csrr {}, mcounteren", out(reg) mcounteren);
asm!("csrw mcounteren, {}", in(reg) mcounteren | 1);
}
}

// —————————————————————————————— Trap Handler —————————————————————————————— //

global_asm!(
r#"
.text
.align 4
.global _empty_handler
_empty_handler:
// Skip illegal instruction (pc += 4)
csrrw x5, mepc, x5
addi x5, x5, 4
csrrw x5, mepc, x5
// Return back to OS
mret
"#,
);

extern "C" {
pub fn _empty_handler();
}

// —————————————————————————————— Benchmark operating system —————————————————————————————— //

pub const NB_REPEATS: usize = 1000;

pub fn bubble_sort(arr: &mut [usize; NB_REPEATS]) {
let len = arr.len();
let mut swapped;

for i in 0..len {
swapped = false;

for j in 0..len - 1 - i {
if arr[j] > arr[j + 1] {
arr.swap(j, j + 1);
swapped = true;
}
}

if !swapped {
break;
}
}

for i in 1..len {
if arr[i - 1] > arr[i] {
log::error!("Error in sorting, results aren't reliable");
failure();
}
}
}

pub fn trigger_ctx_switch_to_firmware() -> usize {
let begin: u64;
let end: u64;

unsafe {
// Read the `mcycle` register (assuming 64-bit RISC-V)
asm!("csrr {}, cycle", out(reg) begin);
// We trigger an illegal instruction
asm!("csrw mscratch, zero");
// Read the `mcycle` register (assuming 64-bit RISC-V)
asm!("csrr {}, cycle", out(reg) end);
}

(end - begin) as usize
}

pub fn trigger_misaligned_op() -> usize {
let begin: u64;
let end: u64;

let misaligned_address_8_bytes: usize = 0x80600301;

unsafe {
// Read the `mcycle` register (assuming 64-bit RISC-V)
asm!("csrr {}, cycle", out(reg) begin);
// We trigger a misaligned operation
asm!(
"ld {r}, 0({addr})",
addr = in(reg) misaligned_address_8_bytes,
r = out(reg) _,
);
// Read the `mcycle` register (assuming 64-bit RISC-V)
asm!("csrr {}, cycle", out(reg) end);
}

(end - begin) as usize
}

pub fn trigger_misaligned_op_batched() -> usize {
let begin: u64;
let end: u64;

let misaligned_address_8_bytes: usize = 0x80600301;

unsafe {
// Read the `mcycle` register (assuming 64-bit RISC-V)
asm!("csrr {}, cycle", out(reg) begin);

for _ in 0..NB_REPEATS {
// We trigger a misaligned operation
asm!(
"ld {r}, 0({addr})",
addr = in(reg) misaligned_address_8_bytes,
r = out(reg) _,
);
}
// Read the `mcycle` register (assuming 64-bit RISC-V)
asm!("csrr {}, cycle", out(reg) end);
}

(end - begin) as usize / NB_REPEATS
}

pub fn trigger_ctx_switch_to_firmware_batched() -> usize {
let begin: u64;
let end: u64;

unsafe {
// Read the `mcycle` register (assuming 64-bit RISC-V)
asm!("csrr {}, cycle", out(reg) begin);
for _ in 0..NB_REPEATS {
// We can trigger an illegal instruction
asm!("csrw mscratch, zero");
}

// Read the `mcycle` register (assuming 64-bit RISC-V)
asm!("csrr {}, cycle", out(reg) end);
}

(end - begin) as usize / NB_REPEATS
}

#[derive(Debug)]
pub struct Statistics {
mean: usize,
min: usize,
max: usize,

p25: usize,
p50: usize,
p75: usize,
p95: usize,
p99: usize,
}

pub fn get_statistics(mut arr: [usize; NB_REPEATS]) -> Statistics {
bubble_sort(&mut arr);

let mut output: Statistics = Statistics {
mean: 0,
min: 0,
max: 0,
p25: 0,
p50: 0,
p75: 0,
p95: 0,
p99: 0,
};

output.min = arr[0];
output.max = arr[arr.len() - 1];
output.mean = arr.iter().sum::<usize>() / arr.len();

let percentile = |per: f64| -> usize { arr[(per * arr.len() as f64) as usize] };

output.p25 = percentile(0.25);
output.p50 = percentile(0.50);
output.p75 = percentile(0.75);
output.p95 = percentile(0.95);
output.p99 = percentile(0.99);

output
}
1 change: 1 addition & 0 deletions firmware/tracing_firmware/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ path = "main.rs"

[dependencies]
miralis_abi = { path = "../../crates/abi" }
tracing = {path = "../../crates/tracing"}
Loading

0 comments on commit e66ee3a

Please sign in to comment.