#[cfg(feature = "test-counters")]
use std::sync::atomic::AtomicU64;
#[cfg(feature = "test-counters")]
use std::sync::atomic::Ordering;
use std::time::Duration;
#[cfg(feature = "test-counters")]
struct SweepCounters {
sweeps: AtomicU64,
files_enumerated: AtomicU64,
files_scanned: AtomicU64,
scopes_enumerated: AtomicU64,
scopes_analyzed: AtomicU64,
file_list_requests: AtomicU64,
file_list_builds: AtomicU64,
file_list_entries: AtomicU64,
signature_hits: AtomicU64,
signature_misses: AtomicU64,
signature_refused: AtomicU64,
}
#[cfg(feature = "test-counters")]
impl SweepCounters {
const fn new() -> Self {
Self {
sweeps: AtomicU64::new(0),
files_enumerated: AtomicU64::new(0),
files_scanned: AtomicU64::new(0),
scopes_enumerated: AtomicU64::new(0),
scopes_analyzed: AtomicU64::new(0),
file_list_requests: AtomicU64::new(0),
file_list_builds: AtomicU64::new(0),
file_list_entries: AtomicU64::new(0),
signature_hits: AtomicU64::new(0),
signature_misses: AtomicU64::new(0),
signature_refused: AtomicU64::new(0),
}
}
}
#[cfg(feature = "test-counters")]
static COUNTERS: SweepCounters = SweepCounters::new();
#[cfg(feature = "test-counters")]
pub(super) fn record_sweep(files_enumerated: usize) {
COUNTERS.sweeps.fetch_add(1, Ordering::Relaxed);
COUNTERS
.files_enumerated
.fetch_add(files_enumerated as u64, Ordering::Relaxed);
}
#[cfg(feature = "test-counters")]
pub(super) fn record_file_scanned(scopes_enumerated: usize) {
COUNTERS.files_scanned.fetch_add(1, Ordering::Relaxed);
COUNTERS
.scopes_enumerated
.fetch_add(scopes_enumerated as u64, Ordering::Relaxed);
}
#[cfg(feature = "test-counters")]
pub(super) fn record_scope_analyzed() { COUNTERS.scopes_analyzed.fetch_add(1, Ordering::Relaxed); }
#[cfg(feature = "test-counters")]
pub(super) fn record_file_list_request() {
COUNTERS.file_list_requests.fetch_add(1, Ordering::Relaxed);
}
#[cfg(feature = "test-counters")]
pub(super) fn record_file_list_build(entries: usize) {
COUNTERS.file_list_builds.fetch_add(1, Ordering::Relaxed);
COUNTERS
.file_list_entries
.fetch_add(entries as u64, Ordering::Relaxed);
}
#[cfg(feature = "test-counters")]
pub(super) fn record_signature_hit() { COUNTERS.signature_hits.fetch_add(1, Ordering::Relaxed); }
#[cfg(feature = "test-counters")]
pub(super) fn record_signature_miss() { COUNTERS.signature_misses.fetch_add(1, Ordering::Relaxed); }
#[cfg(feature = "test-counters")]
pub(super) fn record_signature_refused() {
COUNTERS.signature_refused.fetch_add(1, Ordering::Relaxed);
}
#[cfg(feature = "test-counters")]
pub(super) fn report(crate_name: &str, analysis_elapsed: Duration) {
let Ok(path) = std::env::var("CARGO_MEND_SWEEP_COUNTERS") else {
return;
};
let read = |counter: &AtomicU64| counter.load(Ordering::Relaxed);
let line = format!(
"mend-sweep-counters crate={crate_name} analysis_ms={} sweeps={} files_enumerated={} \
files_scanned={} scopes_enumerated={} scopes_analyzed={} file_list_requests={} \
file_list_builds={} file_list_entries={} signature_hits={} signature_misses={} \
signature_refused={}\n",
analysis_elapsed.as_millis(),
read(&COUNTERS.sweeps),
read(&COUNTERS.files_enumerated),
read(&COUNTERS.files_scanned),
read(&COUNTERS.scopes_enumerated),
read(&COUNTERS.scopes_analyzed),
read(&COUNTERS.file_list_requests),
read(&COUNTERS.file_list_builds),
read(&COUNTERS.file_list_entries),
read(&COUNTERS.signature_hits),
read(&COUNTERS.signature_misses),
read(&COUNTERS.signature_refused),
);
if let Ok(mut file) = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(path)
{
let _ = std::io::Write::write_all(&mut file, line.as_bytes());
}
}
#[cfg(not(feature = "test-counters"))]
pub(super) const fn record_sweep(_: usize) {}
#[cfg(not(feature = "test-counters"))]
pub(super) const fn record_file_scanned(_: usize) {}
#[cfg(not(feature = "test-counters"))]
pub(super) const fn record_scope_analyzed() {}
#[cfg(not(feature = "test-counters"))]
pub(super) const fn record_file_list_request() {}
#[cfg(not(feature = "test-counters"))]
pub(super) const fn record_file_list_build(_: usize) {}
#[cfg(not(feature = "test-counters"))]
pub(super) const fn record_signature_hit() {}
#[cfg(not(feature = "test-counters"))]
pub(super) const fn record_signature_miss() {}
#[cfg(not(feature = "test-counters"))]
pub(super) const fn record_signature_refused() {}
#[cfg(not(feature = "test-counters"))]
pub(super) const fn report(_: &str, _: Duration) {}