/ duct-tape / xnu / iokit / IOKit / IOStatisticsPrivate.h
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 */