use std::sync::atomic::{AtomicU64, Ordering};
static REQUESTS_IN_FLIGHT: AtomicU64 = AtomicU64::new(0);
static REQUESTS_COMPLETED: AtomicU64 = AtomicU64::new(0);
static REQUEST_ERRORS: AtomicU64 = AtomicU64::new(0);
static NETWORK_BYTES_IN_FLIGHT: AtomicU64 = AtomicU64::new(0);
static NETWORK_BYTES_RECEIVED: AtomicU64 = AtomicU64::new(0);
static PAGES_IN_MEMORY: AtomicU64 = AtomicU64::new(0);
#[cfg(feature = "chrome")]
static CHROME_TABS_ACTIVE: AtomicU64 = AtomicU64::new(0);
#[inline]
pub fn request_start() {
REQUESTS_IN_FLIGHT.fetch_add(1, Ordering::Relaxed);
}
#[inline]
pub fn request_end() {
REQUESTS_IN_FLIGHT.fetch_sub(1, Ordering::Relaxed);
REQUESTS_COMPLETED.fetch_add(1, Ordering::Relaxed);
}
#[inline]
pub fn request_error() {
REQUEST_ERRORS.fetch_add(1, Ordering::Relaxed);
}
#[inline]
pub fn network_bytes_add(n: u64) {
NETWORK_BYTES_IN_FLIGHT.fetch_add(n, Ordering::Relaxed);
}
#[inline]
pub fn network_bytes_done(n: u64) {
NETWORK_BYTES_IN_FLIGHT.fetch_sub(n, Ordering::Relaxed);
NETWORK_BYTES_RECEIVED.fetch_add(n, Ordering::Relaxed);
}
#[inline]
pub fn page_add() {
PAGES_IN_MEMORY.fetch_add(1, Ordering::Relaxed);
}
#[inline]
pub fn page_drop() {
let _ = PAGES_IN_MEMORY.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |v| {
if v > 0 {
Some(v - 1)
} else {
None
}
});
}
#[cfg(feature = "chrome")]
#[inline]
pub fn chrome_tab_open() {
CHROME_TABS_ACTIVE.fetch_add(1, Ordering::Relaxed);
}
#[cfg(feature = "chrome")]
#[inline]
pub fn chrome_tab_close() {
let _ = CHROME_TABS_ACTIVE.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |v| {
if v > 0 {
Some(v - 1)
} else {
None
}
});
}
#[derive(Debug, Clone, Copy, Default)]
pub struct VitalsSnapshot {
pub requests_in_flight: u64,
pub requests_completed: u64,
pub request_errors: u64,
pub network_bytes_in_flight: u64,
pub network_bytes_received: u64,
pub pages_in_memory: u64,
pub chrome_tabs_active: u64,
}
#[inline]
pub fn snapshot() -> VitalsSnapshot {
VitalsSnapshot {
requests_in_flight: REQUESTS_IN_FLIGHT.load(Ordering::Relaxed),
requests_completed: REQUESTS_COMPLETED.load(Ordering::Relaxed),
request_errors: REQUEST_ERRORS.load(Ordering::Relaxed),
network_bytes_in_flight: NETWORK_BYTES_IN_FLIGHT.load(Ordering::Relaxed),
network_bytes_received: NETWORK_BYTES_RECEIVED.load(Ordering::Relaxed),
pages_in_memory: PAGES_IN_MEMORY.load(Ordering::Relaxed),
#[cfg(feature = "chrome")]
chrome_tabs_active: CHROME_TABS_ACTIVE.load(Ordering::Relaxed),
#[cfg(not(feature = "chrome"))]
chrome_tabs_active: 0,
}
}
#[inline]
pub fn error_rate_pct() -> u64 {
let completed = REQUESTS_COMPLETED.load(Ordering::Relaxed);
if completed == 0 {
return 0;
}
REQUEST_ERRORS.load(Ordering::Relaxed) * 100 / completed
}
#[inline]
pub fn is_under_load(threshold: u64) -> bool {
REQUESTS_IN_FLIGHT.load(Ordering::Relaxed) > threshold
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_request_lifecycle() {
let before = REQUESTS_COMPLETED.load(Ordering::Relaxed);
let before_flight = REQUESTS_IN_FLIGHT.load(Ordering::Relaxed);
request_start();
assert_eq!(
REQUESTS_IN_FLIGHT.load(Ordering::Relaxed),
before_flight + 1
);
request_end();
assert_eq!(REQUESTS_IN_FLIGHT.load(Ordering::Relaxed), before_flight);
assert_eq!(REQUESTS_COMPLETED.load(Ordering::Relaxed), before + 1);
}
#[test]
fn test_network_bytes() {
let before = NETWORK_BYTES_IN_FLIGHT.load(Ordering::Relaxed);
let before_total = NETWORK_BYTES_RECEIVED.load(Ordering::Relaxed);
network_bytes_add(1000);
assert_eq!(
NETWORK_BYTES_IN_FLIGHT.load(Ordering::Relaxed),
before + 1000
);
network_bytes_done(1000);
assert_eq!(NETWORK_BYTES_IN_FLIGHT.load(Ordering::Relaxed), before);
assert_eq!(
NETWORK_BYTES_RECEIVED.load(Ordering::Relaxed),
before_total + 1000
);
}
#[test]
fn test_page_tracking() {
let before = PAGES_IN_MEMORY.load(Ordering::Relaxed);
page_add();
page_add();
assert_eq!(PAGES_IN_MEMORY.load(Ordering::Relaxed), before + 2);
page_drop();
assert_eq!(PAGES_IN_MEMORY.load(Ordering::Relaxed), before + 1);
page_drop();
assert_eq!(PAGES_IN_MEMORY.load(Ordering::Relaxed), before);
let current = PAGES_IN_MEMORY.load(Ordering::Relaxed);
if current == 0 {
page_drop();
assert_eq!(PAGES_IN_MEMORY.load(Ordering::Relaxed), 0);
}
}
#[test]
fn test_snapshot() {
let snap = snapshot();
assert!(snap.requests_completed >= 0);
assert!(snap.network_bytes_received >= 0);
}
#[test]
fn test_error_rate() {
let base_completed = REQUESTS_COMPLETED.load(Ordering::Relaxed);
let base_errors = REQUEST_ERRORS.load(Ordering::Relaxed);
for _ in 0..10 {
request_start();
request_end();
}
request_error();
request_error();
let rate = error_rate_pct();
assert!(rate <= 100);
}
#[cfg(feature = "chrome")]
#[test]
fn test_chrome_tabs() {
let before = CHROME_TABS_ACTIVE.load(Ordering::Relaxed);
chrome_tab_open();
assert_eq!(CHROME_TABS_ACTIVE.load(Ordering::Relaxed), before + 1);
chrome_tab_close();
assert_eq!(CHROME_TABS_ACTIVE.load(Ordering::Relaxed), before);
}
}