use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct ReadMetrics {
pub x_read_calls: u64,
pub x_read_bytes: u64,
pub x_write_calls: u64,
pub x_write_bytes: u64,
pub x_file_size_calls: u64,
pub x_lock_calls: u64,
pub x_unlock_calls: u64,
pub x_check_reserved_lock_calls: u64,
pub x_file_control_calls: u64,
pub x_device_characteristics_calls: u64,
pub stable_data_read_calls: u64,
pub stable_data_read_bytes: u64,
pub stable_data_write_calls: u64,
pub stable_data_write_bytes: u64,
pub stable_grow_calls: u64,
pub stable_grow_pages: u64,
pub page_table_root_hits: u64,
pub page_table_root_misses: u64,
pub page_table_segment_hits: u64,
pub page_table_segment_misses: u64,
pub superblock_loads: u64,
pub commit_load: u64,
pub commit_build_segments: u64,
pub commit_capacity: u64,
pub commit_page_write: u64,
pub commit_table_write: u64,
pub commit_superblock_store: u64,
}
static METRICS_ENABLED: AtomicBool = AtomicBool::new(false);
static X_READ_CALLS: AtomicU64 = AtomicU64::new(0);
static X_READ_BYTES: AtomicU64 = AtomicU64::new(0);
static X_WRITE_CALLS: AtomicU64 = AtomicU64::new(0);
static X_WRITE_BYTES: AtomicU64 = AtomicU64::new(0);
static X_FILE_SIZE_CALLS: AtomicU64 = AtomicU64::new(0);
static X_LOCK_CALLS: AtomicU64 = AtomicU64::new(0);
static X_UNLOCK_CALLS: AtomicU64 = AtomicU64::new(0);
static X_CHECK_RESERVED_LOCK_CALLS: AtomicU64 = AtomicU64::new(0);
static X_FILE_CONTROL_CALLS: AtomicU64 = AtomicU64::new(0);
static X_DEVICE_CHARACTERISTICS_CALLS: AtomicU64 = AtomicU64::new(0);
static STABLE_DATA_READ_CALLS: AtomicU64 = AtomicU64::new(0);
static STABLE_DATA_READ_BYTES: AtomicU64 = AtomicU64::new(0);
static STABLE_DATA_WRITE_CALLS: AtomicU64 = AtomicU64::new(0);
static STABLE_DATA_WRITE_BYTES: AtomicU64 = AtomicU64::new(0);
static STABLE_GROW_CALLS: AtomicU64 = AtomicU64::new(0);
static STABLE_GROW_PAGES: AtomicU64 = AtomicU64::new(0);
static PAGE_TABLE_ROOT_HITS: AtomicU64 = AtomicU64::new(0);
static PAGE_TABLE_ROOT_MISSES: AtomicU64 = AtomicU64::new(0);
static PAGE_TABLE_SEGMENT_HITS: AtomicU64 = AtomicU64::new(0);
static PAGE_TABLE_SEGMENT_MISSES: AtomicU64 = AtomicU64::new(0);
static SUPERBLOCK_LOADS: AtomicU64 = AtomicU64::new(0);
static COMMIT_LOAD: AtomicU64 = AtomicU64::new(0);
static COMMIT_BUILD_SEGMENTS: AtomicU64 = AtomicU64::new(0);
static COMMIT_CAPACITY: AtomicU64 = AtomicU64::new(0);
static COMMIT_PAGE_WRITE: AtomicU64 = AtomicU64::new(0);
static COMMIT_TABLE_WRITE: AtomicU64 = AtomicU64::new(0);
static COMMIT_SUPERBLOCK_STORE: AtomicU64 = AtomicU64::new(0);
#[doc(hidden)]
#[inline(always)]
pub fn reset_read_metrics() {
for counter in counters() {
counter.store(0, Ordering::Relaxed);
}
METRICS_ENABLED.store(true, Ordering::Relaxed);
}
#[doc(hidden)]
#[inline(always)]
pub fn disable_read_metrics() {
METRICS_ENABLED.store(false, Ordering::Relaxed);
}
#[doc(hidden)]
#[inline(always)]
pub fn read_metrics_snapshot() -> ReadMetrics {
ReadMetrics {
x_read_calls: X_READ_CALLS.load(Ordering::Relaxed),
x_read_bytes: X_READ_BYTES.load(Ordering::Relaxed),
x_write_calls: X_WRITE_CALLS.load(Ordering::Relaxed),
x_write_bytes: X_WRITE_BYTES.load(Ordering::Relaxed),
x_file_size_calls: X_FILE_SIZE_CALLS.load(Ordering::Relaxed),
x_lock_calls: X_LOCK_CALLS.load(Ordering::Relaxed),
x_unlock_calls: X_UNLOCK_CALLS.load(Ordering::Relaxed),
x_check_reserved_lock_calls: X_CHECK_RESERVED_LOCK_CALLS.load(Ordering::Relaxed),
x_file_control_calls: X_FILE_CONTROL_CALLS.load(Ordering::Relaxed),
x_device_characteristics_calls: X_DEVICE_CHARACTERISTICS_CALLS.load(Ordering::Relaxed),
stable_data_read_calls: STABLE_DATA_READ_CALLS.load(Ordering::Relaxed),
stable_data_read_bytes: STABLE_DATA_READ_BYTES.load(Ordering::Relaxed),
stable_data_write_calls: STABLE_DATA_WRITE_CALLS.load(Ordering::Relaxed),
stable_data_write_bytes: STABLE_DATA_WRITE_BYTES.load(Ordering::Relaxed),
stable_grow_calls: STABLE_GROW_CALLS.load(Ordering::Relaxed),
stable_grow_pages: STABLE_GROW_PAGES.load(Ordering::Relaxed),
page_table_root_hits: PAGE_TABLE_ROOT_HITS.load(Ordering::Relaxed),
page_table_root_misses: PAGE_TABLE_ROOT_MISSES.load(Ordering::Relaxed),
page_table_segment_hits: PAGE_TABLE_SEGMENT_HITS.load(Ordering::Relaxed),
page_table_segment_misses: PAGE_TABLE_SEGMENT_MISSES.load(Ordering::Relaxed),
superblock_loads: SUPERBLOCK_LOADS.load(Ordering::Relaxed),
commit_load: COMMIT_LOAD.load(Ordering::Relaxed),
commit_build_segments: COMMIT_BUILD_SEGMENTS.load(Ordering::Relaxed),
commit_capacity: COMMIT_CAPACITY.load(Ordering::Relaxed),
commit_page_write: COMMIT_PAGE_WRITE.load(Ordering::Relaxed),
commit_table_write: COMMIT_TABLE_WRITE.load(Ordering::Relaxed),
commit_superblock_store: COMMIT_SUPERBLOCK_STORE.load(Ordering::Relaxed),
}
}
#[inline(always)]
pub(crate) fn record_x_read(bytes: usize) {
if !metrics_enabled() {
return;
}
X_READ_CALLS.fetch_add(1, Ordering::Relaxed);
X_READ_BYTES.fetch_add(byte_count(bytes), Ordering::Relaxed);
}
#[inline(always)]
pub(crate) fn record_x_write(bytes: usize) {
if !metrics_enabled() {
return;
}
X_WRITE_CALLS.fetch_add(1, Ordering::Relaxed);
X_WRITE_BYTES.fetch_add(byte_count(bytes), Ordering::Relaxed);
}
#[inline(always)]
pub(crate) fn record_x_file_size() {
increment(&X_FILE_SIZE_CALLS);
}
#[inline(always)]
pub(crate) fn record_x_lock() {
increment(&X_LOCK_CALLS);
}
#[inline(always)]
pub(crate) fn record_x_unlock() {
increment(&X_UNLOCK_CALLS);
}
#[inline(always)]
pub(crate) fn record_x_check_reserved_lock() {
increment(&X_CHECK_RESERVED_LOCK_CALLS);
}
#[inline(always)]
pub(crate) fn record_x_file_control() {
increment(&X_FILE_CONTROL_CALLS);
}
#[inline(always)]
pub(crate) fn record_x_device_characteristics() {
increment(&X_DEVICE_CHARACTERISTICS_CALLS);
}
#[inline(always)]
pub(crate) fn record_stable_data_read(bytes: usize) {
if !metrics_enabled() {
return;
}
STABLE_DATA_READ_CALLS.fetch_add(1, Ordering::Relaxed);
STABLE_DATA_READ_BYTES.fetch_add(byte_count(bytes), Ordering::Relaxed);
}
#[inline(always)]
pub(crate) fn record_stable_data_write(bytes: usize) {
if !metrics_enabled() {
return;
}
STABLE_DATA_WRITE_CALLS.fetch_add(1, Ordering::Relaxed);
STABLE_DATA_WRITE_BYTES.fetch_add(byte_count(bytes), Ordering::Relaxed);
}
#[inline(always)]
pub(crate) fn record_stable_grow(pages: u64) {
if !metrics_enabled() {
return;
}
STABLE_GROW_CALLS.fetch_add(1, Ordering::Relaxed);
STABLE_GROW_PAGES.fetch_add(pages, Ordering::Relaxed);
}
#[inline(always)]
pub(crate) fn record_page_table_root_hit() {
increment(&PAGE_TABLE_ROOT_HITS);
}
#[inline(always)]
pub(crate) fn record_page_table_root_miss() {
increment(&PAGE_TABLE_ROOT_MISSES);
}
#[inline(always)]
pub(crate) fn record_page_table_segment_hit() {
increment(&PAGE_TABLE_SEGMENT_HITS);
}
#[inline(always)]
pub(crate) fn record_page_table_segment_miss() {
increment(&PAGE_TABLE_SEGMENT_MISSES);
}
#[inline(always)]
pub(crate) fn record_superblock_load() {
increment(&SUPERBLOCK_LOADS);
}
#[inline(always)]
pub(crate) fn record_commit_load(instructions: u64) {
add(&COMMIT_LOAD, instructions);
}
#[inline(always)]
pub(crate) fn record_commit_build_segments(instructions: u64) {
add(&COMMIT_BUILD_SEGMENTS, instructions);
}
#[inline(always)]
pub(crate) fn record_commit_capacity(instructions: u64) {
add(&COMMIT_CAPACITY, instructions);
}
#[inline(always)]
pub(crate) fn record_commit_page_write(instructions: u64) {
add(&COMMIT_PAGE_WRITE, instructions);
}
#[inline(always)]
pub(crate) fn record_commit_table_write(instructions: u64) {
add(&COMMIT_TABLE_WRITE, instructions);
}
#[inline(always)]
pub(crate) fn record_commit_superblock_store(instructions: u64) {
add(&COMMIT_SUPERBLOCK_STORE, instructions);
}
fn counters() -> [&'static AtomicU64; 27] {
[
&X_READ_CALLS,
&X_READ_BYTES,
&X_WRITE_CALLS,
&X_WRITE_BYTES,
&X_FILE_SIZE_CALLS,
&X_LOCK_CALLS,
&X_UNLOCK_CALLS,
&X_CHECK_RESERVED_LOCK_CALLS,
&X_FILE_CONTROL_CALLS,
&X_DEVICE_CHARACTERISTICS_CALLS,
&STABLE_DATA_READ_CALLS,
&STABLE_DATA_READ_BYTES,
&STABLE_DATA_WRITE_CALLS,
&STABLE_DATA_WRITE_BYTES,
&STABLE_GROW_CALLS,
&STABLE_GROW_PAGES,
&PAGE_TABLE_ROOT_HITS,
&PAGE_TABLE_ROOT_MISSES,
&PAGE_TABLE_SEGMENT_HITS,
&PAGE_TABLE_SEGMENT_MISSES,
&SUPERBLOCK_LOADS,
&COMMIT_LOAD,
&COMMIT_BUILD_SEGMENTS,
&COMMIT_CAPACITY,
&COMMIT_PAGE_WRITE,
&COMMIT_TABLE_WRITE,
&COMMIT_SUPERBLOCK_STORE,
]
}
#[inline(always)]
fn increment(counter: &AtomicU64) {
if metrics_enabled() {
counter.fetch_add(1, Ordering::Relaxed);
}
}
#[inline(always)]
fn add(counter: &AtomicU64, value: u64) {
if metrics_enabled() {
counter.fetch_add(value, Ordering::Relaxed);
}
}
#[inline(always)]
fn byte_count(bytes: usize) -> u64 {
u64::try_from(bytes).unwrap_or(u64::MAX)
}
#[inline(always)]
pub(crate) fn metrics_enabled() -> bool {
METRICS_ENABLED.load(Ordering::Relaxed)
}
#[inline(always)]
pub(crate) fn instruction_counter() -> u64 {
#[cfg(target_arch = "wasm32")]
{
ic_cdk::api::performance_counter(0)
}
#[cfg(not(target_arch = "wasm32"))]
{
0
}
}