The Pedigree Project 0.1
ActivityDiagnostics.h
1/*
2 * Copyright (c) 2026, Pedigree Developers
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 */
8
9#ifndef PEDIGREE_KERNEL_ACTIVITYDIAGNOSTICS_H
10#define PEDIGREE_KERNEL_ACTIVITYDIAGNOSTICS_H
11
12#include "pedigree/kernel/compiler.h"
13
14#include <config.h>
15#include <stddef.h>
16#include <stdint.h>
17
18namespace ActivityDiagnostics {
19
20static constexpr size_t DurationBucketCount = 16;
21static constexpr size_t InterruptVectorCount = 256;
22static constexpr size_t UserReturnSamplePeriod = 64;
23static constexpr size_t UserEntrySamplePeriod = 256;
24
25enum class UserReturnStage : size_t {
26 InterruptTail,
27 SyscallTail,
28 InterruptWork,
29 SyscallWork,
30 Checkpoint,
31 ProcessStop,
32 DeferredFault,
33 Event,
34 InterruptAffinity,
35 SyscallAffinity,
36 InterruptAccounting,
37 SyscallAccounting,
38 Count,
39};
40
41static constexpr size_t UserReturnStageCount = static_cast<size_t>(UserReturnStage::Count);
42
44struct Snapshot {
45 uint64_t interruptCount;
46 uint64_t exceptionCount;
47 uint64_t hardwareInterruptCount;
48 uint64_t otherInterruptCount;
49 uint64_t interruptVectorCounts[InterruptVectorCount];
50 uint64_t interruptDurationBuckets[DurationBucketCount];
51 uint64_t pageFaultDurationBuckets[DurationBucketCount];
52 uint64_t schedulerTimerDurationBuckets[DurationBucketCount];
53 uint64_t hardDispatchCount;
54 uint64_t hardDurationBuckets[DurationBucketCount];
55 uint64_t threadedDispatchCount;
56 uint64_t threadedDurationBuckets[DurationBucketCount];
57 uint64_t schedulerTimerTicks;
58 uint64_t scheduleCalls;
59 uint64_t sameThreadSelections;
60 uint64_t contextSwitches;
61 uint64_t idleSelections;
62 uint64_t schedulerIdleFallbacks;
63 uint64_t schedulerIdleFallbackCurrentReady;
64 uint64_t schedulerIdleFallbackCurrentPending;
65 uint64_t schedulerNoEligibleSelections;
66 uint64_t readyQueueScanEntries;
67 uint64_t readyQueueCandidateVisits;
68 uint64_t readyQueuePredicateRejects;
69 uint64_t readyQueueSelectionSamples;
70 uint64_t readyQueueSelectionDurationBuckets[DurationBucketCount];
71 uint64_t timeAccountingSamples;
72 uint64_t timeAccountingDurationBuckets[DurationBucketCount];
73 uint64_t idleHaltEntries;
74 uint64_t framebufferFlips;
75 uint64_t framebufferCells;
76 uint64_t framebufferDurationBuckets[DurationBucketCount];
77 uint64_t userReturnStageSamples[UserReturnStageCount];
78 uint64_t userReturnStageTotalNanoseconds[UserReturnStageCount];
79 uint64_t userReturnStageDurationBuckets[UserReturnStageCount][DurationBucketCount];
80 uint64_t userReturnFaultHandledSamples;
81 uint64_t userReturnFaultFallbackSamples;
82 uint64_t userReturnInterruptAffinityWaitedSamples;
83 uint64_t userReturnSyscallAffinityWaitedSamples;
84 uint64_t userEntryCaptureCalls;
85 uint64_t userEntryRestoreCalls;
86 uint64_t userEntryCaptureSamples;
87 uint64_t userEntryRestoreSamples;
88 uint64_t userEntryCaptureTscTotal;
89 uint64_t userEntryRestoreTscTotal;
90 uint64_t userEntryEmptyTscSamples;
91 uint64_t userEntryEmptyTscTotal;
92 uint64_t userEntryCaptureTscBuckets[DurationBucketCount];
93 uint64_t userEntryRestoreTscBuckets[DurationBucketCount];
94 uint64_t userEntryEmptyTscBuckets[DurationBucketCount];
95};
96
97#if PEDIGREE_ACTIVITY_DIAGNOSTICS
98
99EXPORTED_PUBLIC uint64_t timestamp();
100EXPORTED_PUBLIC void snapshot(Snapshot& result);
101
102void recordInterruptEntry(size_t vector);
103void recordInterruptDuration(size_t vector, uint64_t duration);
104void recordHardDispatch(uint8_t irq, uint64_t duration);
105void recordThreadedDispatch(uint8_t irq, uint64_t duration);
106void recordSchedulerTimer();
107void recordScheduleCall();
108void recordSameThreadSelection();
109void recordContextSwitch();
110void recordIdleSelection();
111void recordSchedulerIdleFallback(bool currentReady, bool currentPending);
112void recordSchedulerNoEligibleSelection();
113void recordReadyQueueScanEntry();
114void recordReadyQueueCandidateVisit();
115void recordReadyQueuePredicateReject();
116bool shouldSampleReadyQueueSelection();
117void recordReadyQueueSelection(uint64_t duration);
118bool shouldSampleTimeAccounting();
119void recordTimeAccounting(uint64_t duration);
120void recordIdleHalt();
121EXPORTED_PUBLIC void recordFramebufferFlip(size_t cells, uint64_t duration);
122void recordUserReturnStage(UserReturnStage stage, uint64_t duration);
123void recordUserReturnFaultOutcome(bool handled);
124void recordUserReturnAffinityWait(bool syscall);
125
126class InterruptScope {
127 public:
128 explicit InterruptScope(size_t vector) : m_Vector(vector), m_Start(timestamp()) {
129 recordInterruptEntry(vector);
130 }
131
132 ~InterruptScope() {
133 recordInterruptDuration(m_Vector, timestamp() - m_Start);
134 }
135
136 private:
137 size_t m_Vector;
138 uint64_t m_Start;
139};
140
141class HardDispatchScope {
142 public:
143 explicit HardDispatchScope(uint8_t irq) : m_Irq(irq), m_Start(timestamp()) {}
144
145 ~HardDispatchScope() {
146 recordHardDispatch(m_Irq, timestamp() - m_Start);
147 }
148
149 private:
150 uint8_t m_Irq;
151 uint64_t m_Start;
152};
153
154class ReadyQueueSelectionScope {
155 public:
156 ReadyQueueSelectionScope()
157 : m_Active(shouldSampleReadyQueueSelection()), m_Start(m_Active ? timestamp() : 0) {}
158
159 ~ReadyQueueSelectionScope() {
160 if (m_Active)
161 recordReadyQueueSelection(timestamp() - m_Start);
162 }
163
164 private:
165 bool m_Active;
166 uint64_t m_Start;
167};
168
169class TimeAccountingScope {
170 public:
171 TimeAccountingScope()
172 : m_Active(shouldSampleTimeAccounting()), m_Start(m_Active ? timestamp() : 0) {}
173
174 ~TimeAccountingScope() {
175 if (m_Active)
176 recordTimeAccounting(timestamp() - m_Start);
177 }
178
179 private:
180 bool m_Active;
181 uint64_t m_Start;
182};
183
184#else
185
186inline uint64_t timestamp() {
187 return 0;
188}
189
190inline void snapshot(Snapshot& result) {
191 result = {};
192}
193
194inline void recordInterruptEntry(size_t) {}
195inline void recordInterruptDuration(size_t, uint64_t) {}
196inline void recordHardDispatch(uint8_t, uint64_t) {}
197inline void recordThreadedDispatch(uint8_t, uint64_t) {}
198inline void recordSchedulerTimer() {}
199inline void recordScheduleCall() {}
200inline void recordSameThreadSelection() {}
201inline void recordContextSwitch() {}
202inline void recordIdleSelection() {}
203inline void recordSchedulerIdleFallback(bool, bool) {}
204inline void recordSchedulerNoEligibleSelection() {}
205inline void recordReadyQueueScanEntry() {}
206inline void recordReadyQueueCandidateVisit() {}
207inline void recordReadyQueuePredicateReject() {}
208inline bool shouldSampleReadyQueueSelection() {
209 return false;
210}
211inline void recordReadyQueueSelection(uint64_t) {}
212inline bool shouldSampleTimeAccounting() {
213 return false;
214}
215inline void recordTimeAccounting(uint64_t) {}
216inline void recordIdleHalt() {}
217inline void recordFramebufferFlip(size_t, uint64_t) {}
218inline void recordUserReturnStage(UserReturnStage, uint64_t) {}
219inline void recordUserReturnFaultOutcome(bool) {}
220inline void recordUserReturnAffinityWait(bool) {}
221
223 public:
224 explicit InterruptScope(size_t) {}
225};
226
228 public:
229 explicit HardDispatchScope(uint8_t) {}
230};
231
233 public:
235};
236
238 public:
240};
241
242#endif
243
244} // namespace ActivityDiagnostics
245
246#endif
Definition Event.h:49