The Pedigree Project 0.1
Metrics.h
1/* Copyright (c) 2026, Pedigree Developers. SPDX-License-Identifier: ISC */
2#ifndef PEDIGREE_KERNEL_METRICS_H
3#define PEDIGREE_KERNEL_METRICS_H
4
5#include "pedigree/kernel/compiler.h"
6
7#include <config.h>
8#include <stddef.h>
9#include <stdint.h>
10
11#if PEDIGREE_METRICS && !defined(PEDIGREE_BUILDUTILS)
12#include "pedigree/kernel/process/CpuAffinity.h"
13#include "pedigree/kernel/processor/Processor.h"
14#endif
15
16namespace Metrics {
17enum Counter : size_t {
18 Schedule,
19 Yield,
20 ContextSwitch,
21 SameThread,
22 IdleSelection,
23 Timer,
24 RescheduleService,
25 WorkerWake,
26 Interrupt,
27 Exception,
28 Syscall,
29 SpinlockAcquire,
30 SpinlockContended,
31 ProcessCreated,
32 ProcessExited,
33 ProcessDestroyed,
34 ThreadCreated,
35 ThreadExitStarted,
36 ThreadReapable,
37 ThreadDestroyed,
38 WaitQueueWait,
39 WaitQueueUnqueue,
40 WaitQueueWake,
41 WaitQueueEarlyWake,
42 WaitQueueCancel,
43 WaitQueueRequeue,
44 SemaphoreContended,
45 PhysicalPageAlloc,
46 PhysicalPageAllocFailure,
47 PhysicalPageFree,
48 MemoryPressurePass,
49 MemoryPressurePassSuccess,
50 MemoryPressureKill,
51 PageFault,
52 PageFaultCopyOnWrite,
53 PageFaultHandled,
54 PageFaultDeferred,
55 CacheLookupHit,
56 CacheLookupMiss,
57 CacheReadBytes,
58 CacheEvictedPages,
59 CacheWritebackPages,
60 CacheWritebackFailures,
61 NetworkRxAccepted,
62 NetworkRxBytes,
63 NetworkRxNoDevice,
64 NetworkRxFiltered,
65 NetworkRxNoBuffer,
66 NetworkRxInputFailed,
67 NetworkTxAccepted,
68 NetworkTxBytes,
69 NetworkTxFiltered,
70 NetworkTxSendFailed,
71 FileReadCalls,
72 FileCachedReadCalls,
73 FileReadBytes,
74 FileWriteCalls,
75 FileWriteBytes,
76 VfsSyncCalls,
77 VfsSyncUnsupported,
78 VfsSyncFailed,
79 VfsFindCalls,
80 VfsFindMisses,
81 Count,
82};
83
84struct Snapshot {
85 uint64_t values[Count] = {};
86};
87
88#if PEDIGREE_METRICS && !defined(PEDIGREE_BUILDUTILS)
89struct alignas(64) CpuCounters {
90 uint64_t values[Count];
91};
92extern EXPORTED_PUBLIC CpuCounters counters[CpuAffinityMask::MaximumCpus];
93
94// A writer can be interrupted or migrate after observing its CPU. Relaxed
95// atomic increments preserve counts without masking IRQs or pinning execution.
96ALWAYS_INLINE inline void add(Counter counter, uint64_t amount) {
97 if (!amount) {
98 return;
99 }
100 const size_t cpu = Processor::index();
101 if (cpu < CpuAffinityMask::MaximumCpus) {
102 __atomic_fetch_add(&counters[cpu].values[counter], amount, __ATOMIC_RELAXED);
103 }
104}
105ALWAYS_INLINE inline void increment(Counter counter) {
106 add(counter, 1);
107}
108EXPORTED_PUBLIC bool snapshot(size_t cpu, Snapshot& result);
109#else
110inline void add(Counter, uint64_t) {}
111inline void increment(Counter) {}
112inline bool snapshot(size_t, Snapshot& result) {
113 result = {};
114 return false;
115}
116#endif
117} // namespace Metrics
118#endif
static size_t index()