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 */
55class IOWorkLoop;
56class IOUserClient;
57class IOEventSource;
58
59struct IOEventSourceCounter;
60struct IOUserClientCounter;
61struct IOWorkLoopCounter;
62struct IOUserClientProcessEntry;
63
64struct KextNode;
65
66/* Allocation tracking */
67
68enum {
69	kIOStatisticsMalloc = 0,
70	kIOStatisticsFree,
71	kIOStatisticsMallocAligned,
72	kIOStatisticsFreeAligned,
73	kIOStatisticsMallocContiguous,
74	kIOStatisticsFreeContiguous,
75	kIOStatisticsMallocPageable,
76	kIOStatisticsFreePageable,
77	kIOStatisticsAllocCount
78};
79
80TAILQ_HEAD(ProcessEntryList, IOUserClientProcessEntry);
81
82/* Tree and list structs */
83
84typedef 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
95typedef 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
111typedef 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
120typedef struct IOInterruptEventSourceCounter {
121	uint32_t produced;
122	uint32_t checksForWork;
123} IOInterruptEventSourceCounter;
124
125typedef struct IOTimerEventSourceCounter {
126	uint32_t timeouts;
127	uint32_t checksForWork;
128} IOTimerEventSourceCounter;
129
130typedef struct IOCommandGateCounter {
131	uint32_t actionCalls;
132} IOCommandGateCounter;
133
134typedef struct IOCommandQueueCounter {
135	uint32_t actionCalls;
136} IOCommandQueueCounter;
137
138typedef 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
155typedef struct IOWorkLoopDependency {
156	RB_ENTRY(IOWorkLoopDependency) link;
157	OSKextLoadTag loadTag;
158} IOWorkLoopDependency;
159
160typedef 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
175typedef struct IOUserClientCounter {
176	SLIST_ENTRY(IOUserClientCounter) link;
177	ClassNode *parentClass;
178	uint32_t clientCalls;
179} IOUserClientCounter;
180
181class 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
238public:
239
240	static void initialize();
241
242	static void onKextLoad(OSKext *kext, kmod_info_t *kmod_info);
243	static void onKextUnload(OSKext *kext);
244	static void onClassAdded(OSKext *parentKext, OSMetaClass *metaClass);
245	static void onClassRemoved(OSKext *parentKext, OSMetaClass *metaClass);
246
247	static IOEventSourceCounter *registerEventSource(OSObject *inOwner);
248	static void unregisterEventSource(IOEventSourceCounter *counter);
249
250	static IOWorkLoopCounter *registerWorkLoop(IOWorkLoop *workLoop);
251	static void unregisterWorkLoop(IOWorkLoopCounter *counter);
252
253	static IOUserClientCounter *registerUserClient(IOUserClient *userClient);
254	static void unregisterUserClient(IOUserClientCounter *counter);
255
256	static int getStatistics(sysctl_req *req);
257	static int getWorkLoopStatistics(sysctl_req *req);
258	static int getUserClientStatistics(sysctl_req *req);
259
260	/* Inlines for counter manipulation.
261	 *
262	 * NOTE: counter access is not expressly guarded here so as not to incur performance penalties
263	 * in the instrumented parent objects. Writes are arranged so as to be protected by pre-existing
264	 * locks in the parent where appropriate, but reads have no such guarantee. Counters should
265	 * therefore be regarded as providing an indication of current state, rather than precisely
266	 * accurate statistics.
267	 */
268
269	static inline void setCounterType(IOEventSourceCounter *counter, IOStatisticsCounterType type) {
270		if (counter) {
271			counter->type = type;
272		}
273	}
274
275	static inline void countOpenGate(IOEventSourceCounter *counter) {
276		if (counter) {
277			counter->timeOnGate += mach_absolute_time() - counter->startTimeStamp;
278			counter->openGateCalls++;
279		}
280	}
281
282	static inline void countCloseGate(IOEventSourceCounter *counter) {
283		if (counter) {
284			counter->startTimeStamp = mach_absolute_time();
285			counter->closeGateCalls++;
286		}
287	}
288
289	/* Interrupt */
290	static inline void countInterruptCheckForWork(IOEventSourceCounter *counter) {
291		if (counter) {
292			counter->u.interrupt.checksForWork++;
293		}
294	}
295
296	static inline void countInterrupt(IOEventSourceCounter *counter) {
297		if (counter) {
298			counter->u.interrupt.produced++;
299		}
300	}
301
302	/* CommandQueue */
303	static inline void countCommandQueueActionCall(IOEventSourceCounter *counter) {
304		if (counter) {
305			counter->u.commandQueue.actionCalls++;
306		}
307	}
308
309	/* CommandGate */
310	static inline void countCommandGateActionCall(IOEventSourceCounter *counter) {
311		if (counter) {
312			counter->u.commandGate.actionCalls++;
313		}
314	}
315
316	/* Timer */
317	static inline void countTimerTimeout(IOEventSourceCounter *counter) {
318		if (counter) {
319			counter->u.timer.timeouts++;
320		}
321	}
322
323	/* WorkLoop */
324	static void attachWorkLoopEventSource(IOWorkLoopCounter *wlc, IOEventSourceCounter *esc);
325	static void detachWorkLoopEventSource(IOWorkLoopCounter *wlc, IOEventSourceCounter *esc);
326
327	static inline void countWorkLoopOpenGate(IOWorkLoopCounter *counter) {
328		if (counter) {
329			counter->timeOnGate += mach_absolute_time() - counter->startTimeStamp;
330			counter->openGateCalls++;
331		}
332	}
333
334	static inline void countWorkLoopCloseGate(IOWorkLoopCounter *counter) {
335		if (counter) {
336			counter->startTimeStamp = mach_absolute_time();
337			counter->closeGateCalls++;
338		}
339	}
340
341	/* IOLib allocations */
342	static void countAlloc(uint32_t index, vm_size_t size);
343
344	/* UserClient */
345	static void countUserClientCall(IOUserClient *client);
346};
347
348#else
349
350/* Statistics disabled */
351
352class IOStatistics {
353public:
354	static void initialize() {}
355};
356
357#endif /* IOKITSTATS */
358
359#endif /* __IOKIT_STATISTICS_PRIVATE_H */
360