stoolap_jemalloc/stats.rs
1// Copyright 2026 Stoolap Contributors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Process-wide counters, updated only on slow paths
16
17use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
18
19pub(crate) static CHUNK_BYTES: Counter = Counter::new();
20pub(crate) static HUGE_BYTES: Counter = Counter::new();
21pub(crate) static HUGE_CACHED_BYTES: Counter = Counter::new();
22pub(crate) static METADATA_BYTES: Counter = Counter::new();
23
24/// Memory the allocator holds from the OS, in bytes
25#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
26pub struct Stats {
27 /// Chunks that hold small and large allocations
28 pub chunks: usize,
29 /// Mappings of huge allocations that are in use
30 pub huge: usize,
31 /// Freed huge mappings kept for reuse
32 pub huge_cached: usize,
33 /// The allocator's own metadata, including the heap profiler's
34 pub metadata: usize,
35}
36
37impl Stats {
38 /// All memory mapped from the OS
39 #[must_use]
40 pub fn mapped(&self) -> usize {
41 self.chunks + self.huge + self.huge_cached + self.metadata
42 }
43}
44
45/// A snapshot of the allocator's counters
46pub fn stats() -> Stats {
47 Stats {
48 chunks: CHUNK_BYTES.get(),
49 huge: HUGE_BYTES.get(),
50 huge_cached: HUGE_CACHED_BYTES.get(),
51 metadata: METADATA_BYTES.get(),
52 }
53}
54
55/// A counter of bytes. Additions and subtractions are separate so that no
56/// size needs a sign: on 32-bit targets a mapping can exceed `isize::MAX`.
57pub(crate) struct Counter(AtomicUsize);
58
59impl Counter {
60 const fn new() -> Self {
61 Counter(AtomicUsize::new(0))
62 }
63
64 fn get(&self) -> usize {
65 self.0.load(Relaxed)
66 }
67
68 pub(crate) fn add(&self, n: usize) {
69 self.0.fetch_add(n, Relaxed);
70 }
71
72 pub(crate) fn sub(&self, n: usize) {
73 self.0.fetch_sub(n, Relaxed);
74 }
75}