use crate::common::{CoreId, HartId};
use super::StatId;
macro_rules! stat_paths {
($(#[$meta:meta])* $name:ident { $( $(#[$fmeta:meta])* $field:ident: $tail:literal ),* $(,)? }) => {
$(#[$meta])*
#[derive(Clone, Copy, Debug)]
pub struct $name {
$( $(#[$fmeta])* pub $field: StatId, )*
}
impl $name {
fn under(subject: &str) -> Self {
Self { $( $field: StatId::of(&format!("{subject}.{}", $tail)), )* }
}
}
};
}
stat_paths! {
HartPaths {
retired_insts: "retired_insts",
traps: "traps",
cycles_user: "cycles.user",
cycles_kernel: "cycles.kernel",
cycles_machine: "cycles.machine",
}
}
impl HartPaths {
#[must_use]
pub fn new(hart: HartId) -> Self {
Self::under(&format!("hart{}", hart.val()))
}
}
stat_paths! {
CommitPaths {
op_load: "commit.op.load",
op_store: "commit.op.store",
op_branch: "commit.op.branch",
op_alu: "commit.op.alu",
op_system: "commit.op.system",
op_atomic: "commit.op.atomic",
fp_load: "commit.fp.load",
fp_store: "commit.fp.store",
fp_arith: "commit.fp.arith",
fp_fma: "commit.fp.fma",
fp_div_sqrt: "commit.fp.div_sqrt",
vec_int: "commit.vec.int",
vec_fp: "commit.vec.fp",
vec_load: "commit.vec.load",
vec_store: "commit.vec.store",
vec_misc: "commit.vec.misc",
vec_crypto: "commit.vec.crypto",
retire_hist_zero: "commit.retire_histogram.zero",
retire_hist_one: "commit.retire_histogram.one",
retire_hist_two: "commit.retire_histogram.two",
retire_hist_three_plus: "commit.retire_histogram.three_plus",
}
}
stat_paths! {
PipelinePaths {
cycles_total: "pipeline.cycles.total",
cycles_wfi: "pipeline.cycles.wfi",
cycles_rob_empty: "pipeline.cycles.rob_empty",
stalls_control: "pipeline.stalls.control",
stalls_fetch_wait: "pipeline.stalls.fetch_wait",
stalls_data: "pipeline.stalls.data",
stalls_fu_structural: "pipeline.stalls.fu_structural",
stalls_ordering: "pipeline.stalls.ordering",
stalls_backpressure: "pipeline.stalls.backpressure",
stalls_dispatch: "pipeline.stalls.dispatch",
stalls_checkpoint: "pipeline.stalls.checkpoint",
stalls_serialize: "pipeline.stalls.serialize",
stalls_squash: "pipeline.stalls.squash",
flushes_total: "pipeline.flushes.total",
flushes_branch: "pipeline.flushes.branch",
flushes_system: "pipeline.flushes.system",
flushes_mem_violations: "pipeline.flushes.mem_violations",
flushes_coherence: "pipeline.flushes.coherence",
flushes_trap: "pipeline.flushes.trap",
flushes_squashed_insns: "pipeline.flushes.squashed_insns",
}
}
stat_paths! {
BpPaths {
committed_hits: "bp.committed.hits",
committed_mispredicts: "bp.committed.mispredicts",
spec_hits: "bp.spec.hits",
spec_mispredicts: "bp.spec.mispredicts",
decode_redirects: "bp.decode_redirects",
committed_accuracy: "bp.committed.accuracy",
spec_accuracy: "bp.spec.accuracy",
}
}
stat_paths! {
MdpPaths {
predictions_bypass: "mdp.predictions.bypass",
predictions_wait_all: "mdp.predictions.wait_all",
predictions_wait_for: "mdp.predictions.wait_for",
violations: "mdp.violations",
}
}
stat_paths! {
LsqPaths {
rescheduled_mem_ops: "lsq.rescheduled_mem_ops",
split_stores: "lsq.split_stores",
coherence_replays: "lsq.coherence_replays",
coherence_violations: "lsq.coherence_violations",
}
}
stat_paths! {
WcbPaths {
coalesces: "wcb.coalesces",
drains: "wcb.drains",
}
}
stat_paths! {
LoadPrefetchPaths {
l1: "prefetch.loads.l1",
l2: "prefetch.loads.l2",
page_boundary: "prefetch.loads.dropped.page_boundary",
tlb_miss: "prefetch.loads.dropped.tlb_miss",
denied: "prefetch.loads.dropped.denied",
not_ram: "prefetch.loads.dropped.not_ram",
}
}
const FU_NAMES: [&str; 17] = [
"int_alu",
"int_mul",
"int_div",
"fp_add",
"fp_mul",
"fp_fma",
"fp_div_sqrt",
"branch",
"mem",
"vec_int_alu",
"vec_int_mul",
"vec_int_div",
"vec_fp_alu",
"vec_fp_fma",
"vec_fp_div_sqrt",
"vec_mem",
"vec_permute",
];
#[derive(Clone, Copy, Debug)]
pub struct FuPaths {
pub all: [StatId; FU_NAMES.len()],
}
impl FuPaths {
fn under(subject: &str) -> Self {
let all =
std::array::from_fn(|i| StatId::of(&format!("{subject}.fu.util.{}", FU_NAMES[i])));
Self { all }
}
}
#[derive(Clone, Copy, Debug)]
pub struct CorePaths {
pub commit: CommitPaths,
pub pipeline: PipelinePaths,
pub bp: BpPaths,
pub mdp: MdpPaths,
pub lsq: LsqPaths,
pub wcb: WcbPaths,
pub load_prefetch: LoadPrefetchPaths,
pub fu: FuPaths,
pub ipc: StatId,
pub cpi: StatId,
}
impl CorePaths {
#[must_use]
pub fn new(core: CoreId) -> Self {
let subject = format!("core{}", core.val());
Self {
commit: CommitPaths::under(&subject),
pipeline: PipelinePaths::under(&subject),
bp: BpPaths::under(&subject),
mdp: MdpPaths::under(&subject),
lsq: LsqPaths::under(&subject),
wcb: WcbPaths::under(&subject),
load_prefetch: LoadPrefetchPaths::under(&subject),
fu: FuPaths::under(&subject),
ipc: StatId::of(&format!("{subject}.ipc")),
cpi: StatId::of(&format!("{subject}.cpi")),
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct SystemPaths {
pub retired_insts: StatId,
pub traps: StatId,
}
impl SystemPaths {
#[must_use]
pub fn new() -> Self {
Self {
retired_insts: StatId::of("system.retired_insts"),
traps: StatId::of("system.traps"),
}
}
}
impl Default for SystemPaths {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn paths_carry_their_subject_index() {
let core = CorePaths::new(CoreId::new(3));
assert_eq!(core.commit.op_load.path(), "core3.commit.op.load");
assert_eq!(core.fu.all[0].path(), "core3.fu.util.int_alu");
assert_eq!(core.fu.all[16].path(), "core3.fu.util.vec_permute");
assert_eq!(core.ipc.path(), "core3.ipc");
let hart = HartPaths::new(HartId::new(7));
assert_eq!(hart.cycles_kernel.path(), "hart7.cycles.kernel");
}
}