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
isEnabled()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
setCounterType(IOEventSourceCounter * counter,IOStatisticsCounterType type)276 	setCounterType(IOEventSourceCounter *counter, IOStatisticsCounterType type)
277 	{
278 		if (counter) {
279 			counter->type = type;
280 		}
281 	}
282 
283 	static inline void
countOpenGate(IOEventSourceCounter * counter)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
countCloseGate(IOEventSourceCounter * counter)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
countInterruptCheckForWork(IOEventSourceCounter * counter)303 	countInterruptCheckForWork(IOEventSourceCounter *counter)
304 	{
305 		if (counter) {
306 			counter->u.interrupt.checksForWork++;
307 		}
308 	}
309 
310 	static inline void
countInterrupt(IOEventSourceCounter * counter)311 	countInterrupt(IOEventSourceCounter *counter)
312 	{
313 		if (counter) {
314 			counter->u.interrupt.produced++;
315 		}
316 	}
317 
318 /* CommandQueue */
319 	static inline void
countCommandQueueActionCall(IOEventSourceCounter * counter)320 	countCommandQueueActionCall(IOEventSourceCounter *counter)
321 	{
322 		if (counter) {
323 			counter->u.commandQueue.actionCalls++;
324 		}
325 	}
326 
327 /* CommandGate */
328 	static inline void
countCommandGateActionCall(IOEventSourceCounter * counter)329 	countCommandGateActionCall(IOEventSourceCounter *counter)
330 	{
331 		if (counter) {
332 			counter->u.commandGate.actionCalls++;
333 		}
334 	}
335 
336 /* Timer */
337 	static inline void
countTimerTimeout(IOEventSourceCounter * counter)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
countWorkLoopOpenGate(IOWorkLoopCounter * counter)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
countWorkLoopCloseGate(IOWorkLoopCounter * counter)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
initialize()381 	initialize()
382 	{
383 	}
384 };
385 
386 #endif /* IOKITSTATS */
387 
388 #endif /* __IOKIT_STATISTICS_PRIVATE_H */
389