]> git.saurik.com Git - apple/xnu.git/blob - iokit/IOKit/IOStatisticsPrivate.h
xnu-7195.101.1.tar.gz
[apple/xnu.git] / iokit / IOKit / IOStatisticsPrivate.h
1 /*
2 * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #ifndef __IOKIT_STATISTICS_PRIVATE_H
30 #define __IOKIT_STATISTICS_PRIVATE_H
31
32 #if IOKITSTATS
33
34 #include <sys/queue.h>
35 #include <sys/tree.h>
36
37 #include <libkern/c++/OSKext.h>
38 #include <libkern/OSDebug.h>
39
40 #include <IOKit/IOMemoryDescriptor.h>
41 #include <IOKit/IOStatistics.h>
42
43 #ifndef KERNEL
44 #error IOStatisticsPrivate.h is for kernel use only
45 #endif
46
47 /* Defines */
48 #define IOKIT_STATISTICS_RECORDED_USERCLIENT_PROCS 20
49
50 #ifndef __probable
51 #define __probable(x) x
52 #endif
53
54 /* Forward declarations */
55 class IOWorkLoop;
56 class IOUserClient;
57 class IOEventSource;
58
59 struct IOEventSourceCounter;
60 struct IOUserClientCounter;
61 struct IOWorkLoopCounter;
62 struct IOUserClientProcessEntry;
63
64 struct KextNode;
65
66 /* Allocation tracking */
67
68 enum {
69 kIOStatisticsMalloc = 0,
70 kIOStatisticsFree,
71 kIOStatisticsMallocAligned,
72 kIOStatisticsFreeAligned,
73 kIOStatisticsMallocContiguous,
74 kIOStatisticsFreeContiguous,
75 kIOStatisticsMallocPageable,
76 kIOStatisticsFreePageable,
77 kIOStatisticsAllocCount
78 };
79
80 TAILQ_HEAD(ProcessEntryList, IOUserClientProcessEntry);
81
82 /* Tree and list structs */
83
84 typedef struct ClassNode {
85 RB_ENTRY(ClassNode) tLink;
86 SLIST_ENTRY(ClassNode) lLink;
87 struct KextNode *parentKext;
88 uint32_t classID;
89 uint32_t superClassID;
90 const OSMetaClass *metaClass;
91 SLIST_HEAD(, IOEventSourceCounter) counterList;
92 SLIST_HEAD(, IOUserClientCounter) userClientList;
93 } ClassNode;
94
95 typedef struct KextNode {
96 RB_ENTRY(KextNode) link;
97 RB_ENTRY(KextNode) addressLink;
98 OSKext *kext;
99 OSKextLoadTag loadTag;
100 vm_offset_t address;
101 vm_offset_t address_end;
102 uint32_t memoryCounters[kIOStatisticsAllocCount];
103 uint32_t classes;
104 SLIST_HEAD(, ClassNode) classList;
105 SLIST_HEAD(, IOWorkLoopCounter) workLoopList;
106 ProcessEntryList userClientCallList;
107 } KextNode;
108
109 /* User client tracing */
110
111 typedef struct IOUserClientProcessEntry {
112 TAILQ_ENTRY(IOUserClientProcessEntry) link;
113 char processName[kIOStatisticsProcessNameLength];
114 int32_t pid;
115 uint32_t calls;
116 } IOUserClientProcessEntry;
117
118 /* Counters */
119
120 typedef struct IOInterruptEventSourceCounter {
121 uint32_t produced;
122 uint32_t checksForWork;
123 } IOInterruptEventSourceCounter;
124
125 typedef struct IOTimerEventSourceCounter {
126 uint32_t timeouts;
127 uint32_t checksForWork;
128 } IOTimerEventSourceCounter;
129
130 typedef struct IOCommandGateCounter {
131 uint32_t actionCalls;
132 } IOCommandGateCounter;
133
134 typedef struct IOCommandQueueCounter {
135 uint32_t actionCalls;
136 } IOCommandQueueCounter;
137
138 typedef struct IOEventSourceCounter {
139 SLIST_ENTRY(IOEventSourceCounter) link;
140 ClassNode *parentClass;
141 IOStatisticsCounterType type;
142 uint64_t startTimeStamp;
143 uint64_t timeOnGate;
144 uint32_t closeGateCalls;
145 uint32_t openGateCalls;
146 union {
147 IOInterruptEventSourceCounter interrupt;
148 IOInterruptEventSourceCounter filter;
149 IOTimerEventSourceCounter timer;
150 IOCommandGateCounter commandGate;
151 IOCommandQueueCounter commandQueue;
152 } u;
153 } IOEventSourceCounter;
154
155 typedef struct IOWorkLoopDependency {
156 RB_ENTRY(IOWorkLoopDependency) link;
157 OSKextLoadTag loadTag;
158 } IOWorkLoopDependency;
159
160 typedef struct IOWorkLoopCounter {
161 SLIST_ENTRY(IOWorkLoopCounter) link;
162 KextNode *parentKext;
163 int attachedEventSources;
164 IOWorkLoop *workLoop;
165 uint64_t startTimeStamp;
166 uint64_t timeOnGate;
167 uint32_t closeGateCalls;
168 uint32_t openGateCalls;
169 typedef RB_HEAD(DependencyTree, IOWorkLoopDependency) DependencyTreeHead;
170 DependencyTreeHead dependencyHead;
171 static int loadTagCompare(IOWorkLoopDependency *e1, IOWorkLoopDependency *e2);
172 RB_PROTOTYPE_SC(static, DependencyTree, IOWorkLoopDependency, dependencyLink, KextTagCompare);
173 } IOWorkLoopCounter;
174
175 typedef struct IOUserClientCounter {
176 SLIST_ENTRY(IOUserClientCounter) link;
177 ClassNode *parentClass;
178 uint32_t clientCalls;
179 } IOUserClientCounter;
180
181 class IOStatistics {
182 static bool enabled;
183
184 static IORWLock *lock;
185
186 static uint32_t sequenceID;
187
188 static uint32_t lastKextIndex;
189 static uint32_t lastClassIndex;
190
191 static uint32_t loadedKexts;
192 static uint32_t registeredClasses;
193 static uint32_t registeredCounters;
194 static uint32_t registeredWorkloops;
195
196 static uint32_t attachedEventSources;
197
198 static KextNode *kextHint;
199
200 static IOWorkLoopDependency *nextWorkLoopDependency;
201
202 typedef RB_HEAD(KextTree, KextNode) KextTreeHead;
203 static KextTreeHead kextHead;
204 static int kextNodeCompare(KextNode *e1, KextNode *e2);
205 RB_PROTOTYPE_SC(static, KextTree, KextNode, link, kextNodeCompare);
206
207 typedef RB_HEAD(KextAddressTree, KextNode) KextAddressTreeHead;
208 static KextAddressTreeHead kextAddressHead;
209 static int kextAddressNodeCompare(KextNode *e1, KextNode *e2);
210 RB_PROTOTYPE_SC(static, KextAddressTree, KextNode, addressLink, kextAddressNodeCompare);
211
212 typedef RB_HEAD(ClassTree, ClassNode) ClassTreeHead;
213 static ClassTreeHead classHead;
214 static int classNodeCompare(ClassNode *e1, ClassNode *e2);
215 RB_PROTOTYPE_SC(static, ClassTree, ClassNode, tLink, classNodeCompare);
216
217 static int oid_sysctl(__unused struct sysctl_oid *oidp, __unused void *arg1, int arg2, struct sysctl_req *req);
218
219 static uint32_t copyGlobalStatistics(IOStatisticsGlobal *stats);
220 static uint32_t copyKextStatistics(IOStatisticsKext *stats);
221 static uint32_t copyMemoryStatistics(IOStatisticsMemory *stats);
222 static uint32_t copyClassStatistics(IOStatisticsClass *stats);
223 static uint32_t copyCounterStatistics(IOStatisticsCounter *stats);
224 static uint32_t copyKextIdentifiers(IOStatisticsKextIdentifier *kextIDs);
225 static uint32_t copyClassNames(IOStatisticsClassName *classNames);
226
227 static uint32_t copyWorkLoopStatistics(IOStatisticsWorkLoop *workLoopStats);
228
229 static uint32_t copyUserClientStatistics(IOStatisticsUserClientHeader *stats, uint32_t loadTag);
230
231 static void updateAllocationCounter(vm_offset_t address, uint32_t index, vm_size_t size);
232
233 static void storeUserClientCallInfo(IOUserClient *userClient, IOUserClientCounter *counter);
234
235 static KextNode *getKextNodeFromBacktrace(boolean_t write);
236 static void releaseKextNode(KextNode *node);
237
238 public:
239
240 static void initialize();
241
242 inline static bool
243 isEnabled()
244 {
245 return enabled;
246 }
247
248 static void onKextLoad(OSKext *kext, kmod_info_t *kmod_info);
249 static void onKextUnload(OSKext *kext);
250 static void onClassAdded(OSKext *parentKext, OSMetaClass *metaClass);
251 static void onClassRemoved(OSKext *parentKext, OSMetaClass *metaClass);
252
253 static IOEventSourceCounter *registerEventSource(OSObject *inOwner);
254 static void unregisterEventSource(IOEventSourceCounter *counter);
255
256 static IOWorkLoopCounter *registerWorkLoop(IOWorkLoop *workLoop);
257 static void unregisterWorkLoop(IOWorkLoopCounter *counter);
258
259 static IOUserClientCounter *registerUserClient(IOUserClient *userClient);
260 static void unregisterUserClient(IOUserClientCounter *counter);
261
262 static int getStatistics(sysctl_req *req);
263 static int getWorkLoopStatistics(sysctl_req *req);
264 static int getUserClientStatistics(sysctl_req *req);
265
266 /* Inlines for counter manipulation.
267 *
268 * NOTE: counter access is not expressly guarded here so as not to incur performance penalties
269 * in the instrumented parent objects. Writes are arranged so as to be protected by pre-existing
270 * locks in the parent where appropriate, but reads have no such guarantee. Counters should
271 * therefore be regarded as providing an indication of current state, rather than precisely
272 * accurate statistics.
273 */
274
275 static inline void
276 setCounterType(IOEventSourceCounter *counter, IOStatisticsCounterType type)
277 {
278 if (counter) {
279 counter->type = type;
280 }
281 }
282
283 static inline void
284 countOpenGate(IOEventSourceCounter *counter)
285 {
286 if (counter) {
287 counter->timeOnGate += mach_absolute_time() - counter->startTimeStamp;
288 counter->openGateCalls++;
289 }
290 }
291
292 static inline void
293 countCloseGate(IOEventSourceCounter *counter)
294 {
295 if (counter) {
296 counter->startTimeStamp = mach_absolute_time();
297 counter->closeGateCalls++;
298 }
299 }
300
301 /* Interrupt */
302 static inline void
303 countInterruptCheckForWork(IOEventSourceCounter *counter)
304 {
305 if (counter) {
306 counter->u.interrupt.checksForWork++;
307 }
308 }
309
310 static inline void
311 countInterrupt(IOEventSourceCounter *counter)
312 {
313 if (counter) {
314 counter->u.interrupt.produced++;
315 }
316 }
317
318 /* CommandQueue */
319 static inline void
320 countCommandQueueActionCall(IOEventSourceCounter *counter)
321 {
322 if (counter) {
323 counter->u.commandQueue.actionCalls++;
324 }
325 }
326
327 /* CommandGate */
328 static inline void
329 countCommandGateActionCall(IOEventSourceCounter *counter)
330 {
331 if (counter) {
332 counter->u.commandGate.actionCalls++;
333 }
334 }
335
336 /* Timer */
337 static inline void
338 countTimerTimeout(IOEventSourceCounter *counter)
339 {
340 if (counter) {
341 counter->u.timer.timeouts++;
342 }
343 }
344
345 /* WorkLoop */
346 static void attachWorkLoopEventSource(IOWorkLoopCounter *wlc, IOEventSourceCounter *esc);
347 static void detachWorkLoopEventSource(IOWorkLoopCounter *wlc, IOEventSourceCounter *esc);
348
349 static inline void
350 countWorkLoopOpenGate(IOWorkLoopCounter *counter)
351 {
352 if (counter) {
353 counter->timeOnGate += mach_absolute_time() - counter->startTimeStamp;
354 counter->openGateCalls++;
355 }
356 }
357
358 static inline void
359 countWorkLoopCloseGate(IOWorkLoopCounter *counter)
360 {
361 if (counter) {
362 counter->startTimeStamp = mach_absolute_time();
363 counter->closeGateCalls++;
364 }
365 }
366
367 /* IOLib allocations */
368 static void countAlloc(uint32_t index, vm_size_t size);
369
370 /* UserClient */
371 static void countUserClientCall(IOUserClient *client);
372 };
373
374 #else
375
376 /* Statistics disabled */
377
378 class IOStatistics {
379 public:
380 static void
381 initialize()
382 {
383 }
384 };
385
386 #endif /* IOKITSTATS */
387
388 #endif /* __IOKIT_STATISTICS_PRIVATE_H */