]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/IOKit/IOStatisticsPrivate.h
xnu-1699.22.73.tar.gz
[apple/xnu.git] / iokit / IOKit / IOStatisticsPrivate.h
diff --git a/iokit/IOKit/IOStatisticsPrivate.h b/iokit/IOKit/IOStatisticsPrivate.h
new file mode 100644 (file)
index 0000000..a41230c
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ * 
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#ifndef __IOKIT_STATISTICS_PRIVATE_H
+#define __IOKIT_STATISTICS_PRIVATE_H
+
+#if IOKITSTATS
+
+#include <sys/queue.h>
+#include <sys/tree.h>
+
+#include <libkern/c++/OSKext.h>
+#include <libkern/OSDebug.h>
+
+#include <IOKit/IOMemoryDescriptor.h>
+#include <IOKit/IOStatistics.h>
+
+#ifndef KERNEL
+#error IOStatisticsPrivate.h is for kernel use only
+#endif
+
+/* Defines */
+#define IOKIT_STATISTICS_RECORDED_USERCLIENT_PROCS 20
+
+#ifndef __probable
+#define __probable(x) x
+#endif
+
+/* Forward declarations */
+class IOWorkLoop;
+class IOUserClient;
+class IOEventSource;
+
+struct IOEventSourceCounter;
+struct IOUserClientCounter;
+struct IOWorkLoopCounter;
+struct IOUserClientProcessEntry;
+
+struct KextNode;
+
+/* Allocation tracking */
+
+enum {
+       kIOStatisticsMalloc = 0,
+       kIOStatisticsFree,
+       kIOStatisticsMallocAligned,
+       kIOStatisticsFreeAligned,
+       kIOStatisticsMallocContiguous,
+       kIOStatisticsFreeContiguous,
+       kIOStatisticsMallocPageable,
+       kIOStatisticsFreePageable,
+       kIOStatisticsAllocCount
+};
+
+TAILQ_HEAD(ProcessEntryList, IOUserClientProcessEntry);
+
+/* Tree and list structs */
+
+typedef struct ClassNode {
+       RB_ENTRY(ClassNode) tLink;
+       SLIST_ENTRY(ClassNode) lLink;
+       struct KextNode *parentKext;
+       uint32_t classID;
+       uint32_t superClassID;
+       const OSMetaClass *metaClass;
+       SLIST_HEAD(, IOEventSourceCounter) counterList;
+       SLIST_HEAD(, IOUserClientCounter) userClientList;
+} ClassNode;
+
+typedef struct KextNode {
+       RB_ENTRY(KextNode) link;
+       RB_ENTRY(KextNode) addressLink;
+       OSKext *kext;
+       OSKextLoadTag loadTag;
+       vm_offset_t address;
+       vm_offset_t address_end;
+       uint32_t memoryCounters[kIOStatisticsAllocCount];
+       uint32_t classes;
+       SLIST_HEAD(, ClassNode) classList;
+       SLIST_HEAD(, IOWorkLoopCounter) workLoopList;
+       ProcessEntryList userClientCallList;
+} KextNode;
+
+/* User client tracing */
+
+typedef struct IOUserClientProcessEntry {
+       TAILQ_ENTRY(IOUserClientProcessEntry) link;
+       char processName[kIOStatisticsProcessNameLength];
+       int32_t pid;
+       uint32_t calls;
+} IOUserClientProcessEntry;
+
+/* Counters */
+
+typedef struct IOInterruptEventSourceCounter {
+       uint32_t produced;
+       uint32_t checksForWork;
+} IOInterruptEventSourceCounter;
+
+typedef struct IOTimerEventSourceCounter {
+       uint32_t timeouts;
+       uint32_t checksForWork;
+} IOTimerEventSourceCounter;
+
+typedef struct IOCommandGateCounter {
+       uint32_t actionCalls;
+} IOCommandGateCounter;
+
+typedef struct IOCommandQueueCounter {
+       uint32_t actionCalls;
+} IOCommandQueueCounter;
+
+typedef struct IOEventSourceCounter {
+       SLIST_ENTRY(IOEventSourceCounter) link;
+       ClassNode *parentClass;
+       IOStatisticsCounterType type;
+       uint64_t startTimeStamp;
+       uint64_t timeOnGate;
+       uint32_t closeGateCalls;
+       uint32_t openGateCalls;
+       union {
+               IOInterruptEventSourceCounter interrupt;
+               IOInterruptEventSourceCounter filter;
+               IOTimerEventSourceCounter timer;
+               IOCommandGateCounter commandGate;
+               IOCommandQueueCounter commandQueue;
+       } u;
+} IOEventSourceCounter;
+
+typedef struct IOWorkLoopDependency {
+       RB_ENTRY(IOWorkLoopDependency) link;
+       OSKextLoadTag loadTag;
+} IOWorkLoopDependency;
+
+typedef struct IOWorkLoopCounter {    
+       SLIST_ENTRY(IOWorkLoopCounter) link;
+       KextNode *parentKext;
+       int attachedEventSources;
+       IOWorkLoop *workLoop;
+       uint64_t startTimeStamp;
+    uint64_t timeOnGate;
+       uint32_t closeGateCalls;
+       uint32_t openGateCalls;
+       typedef RB_HEAD(DependencyTree, IOWorkLoopDependency) DependencyTreeHead;
+       DependencyTreeHead dependencyHead;
+       static int loadTagCompare(IOWorkLoopDependency *e1, IOWorkLoopDependency *e2);
+       RB_PROTOTYPE_SC(static, DependencyTree, IOWorkLoopDependency, dependencyLink, KextTagCompare);
+} IOWorkLoopCounter;
+
+typedef struct IOUserClientCounter {
+       SLIST_ENTRY(IOUserClientCounter) link;
+       ClassNode *parentClass;
+       uint32_t clientCalls;
+} IOUserClientCounter;
+
+class IOStatistics {
+       static bool enabled;
+
+       static IORWLock *lock;
+
+       static uint32_t sequenceID;
+
+       static uint32_t lastKextIndex;
+       static uint32_t lastClassIndex;
+
+       static uint32_t loadedKexts;
+       static uint32_t registeredClasses;
+       static uint32_t registeredCounters;
+       static uint32_t registeredWorkloops;
+
+       static uint32_t attachedEventSources;
+
+       static KextNode *kextHint;
+       
+       static IOWorkLoopDependency *nextWorkLoopDependency;
+
+       typedef RB_HEAD(KextTree, KextNode) KextTreeHead;
+       static KextTreeHead kextHead;
+       static int kextNodeCompare(KextNode *e1, KextNode *e2);
+       RB_PROTOTYPE_SC(static, KextTree, KextNode, link, kextNodeCompare);
+
+       typedef RB_HEAD(KextAddressTree, KextNode) KextAddressTreeHead;
+       static KextAddressTreeHead kextAddressHead;
+       static int kextAddressNodeCompare(KextNode *e1, KextNode *e2);
+       RB_PROTOTYPE_SC(static, KextAddressTree, KextNode, addressLink, kextAddressNodeCompare);
+
+       typedef RB_HEAD(ClassTree, ClassNode) ClassTreeHead;
+       static ClassTreeHead classHead;
+       static int classNodeCompare(ClassNode *e1, ClassNode *e2);
+       RB_PROTOTYPE_SC(static, ClassTree, ClassNode, tLink, classNodeCompare);
+
+       static int oid_sysctl(__unused struct sysctl_oid *oidp, __unused void *arg1, int arg2, struct sysctl_req *req);
+
+       static uint32_t copyGlobalStatistics(IOStatisticsGlobal *stats);
+       static uint32_t copyKextStatistics(IOStatisticsKext *stats);
+       static uint32_t copyMemoryStatistics(IOStatisticsMemory *stats);
+       static uint32_t copyClassStatistics(IOStatisticsClass *stats);
+       static uint32_t copyCounterStatistics(IOStatisticsCounter *stats);
+       static uint32_t copyKextIdentifiers(IOStatisticsKextIdentifier *kextIDs);
+       static uint32_t copyClassNames(IOStatisticsClassName *classNames);
+
+       static uint32_t copyWorkLoopStatistics(IOStatisticsWorkLoop *workLoopStats);
+
+       static uint32_t copyUserClientStatistics(IOStatisticsUserClientHeader *stats, uint32_t loadTag);
+
+       static void updateAllocationCounter(vm_offset_t address, uint32_t index, vm_size_t size);
+
+       static void storeUserClientCallInfo(IOUserClient *userClient, IOUserClientCounter *counter);
+
+       static KextNode *getKextNodeFromBacktrace(boolean_t write);
+       static void releaseKextNode(KextNode *node);
+
+public:
+       
+       static void initialize();
+
+       static void onKextLoad(OSKext *kext, kmod_info_t *kmod_info);
+       static void onKextUnload(OSKext *kext);
+       static void onClassAdded(OSKext *parentKext, OSMetaClass *metaClass);
+       static void onClassRemoved(OSKext *parentKext, OSMetaClass *metaClass);
+
+       static IOEventSourceCounter *registerEventSource(OSObject *inOwner);
+       static void unregisterEventSource(IOEventSourceCounter *counter);
+       
+       static IOWorkLoopCounter *registerWorkLoop(IOWorkLoop *workLoop);
+       static void unregisterWorkLoop(IOWorkLoopCounter *counter);
+
+       static IOUserClientCounter *registerUserClient(IOUserClient *userClient);
+       static void unregisterUserClient(IOUserClientCounter *counter);
+
+       static int getStatistics(sysctl_req *req);
+       static int getWorkLoopStatistics(sysctl_req *req);
+       static int getUserClientStatistics(sysctl_req *req);
+
+       /* Inlines for counter manipulation.
+        *                              
+        * NOTE: counter access is not expressly guarded here so as not to incur performance penalties
+        * in the instrumented parent objects. Writes are arranged so as to be protected by pre-existing
+        * locks in the parent where appropriate, but reads have no such guarantee. Counters should
+        * therefore be regarded as providing an indication of current state, rather than precisely
+        * accurate statistics. 
+        */
+       
+       static inline void setCounterType(IOEventSourceCounter *counter, IOStatisticsCounterType type) {
+               if (counter) {
+                       counter->type = type;
+               }
+       }
+
+       static inline void countOpenGate(IOEventSourceCounter *counter) {
+               if (counter) {
+                       counter->timeOnGate += mach_absolute_time() - counter->startTimeStamp;
+                       counter->openGateCalls++;
+               }
+       }
+
+       static inline void countCloseGate(IOEventSourceCounter *counter) {
+               if (counter) {
+                       counter->startTimeStamp = mach_absolute_time();
+                       counter->closeGateCalls++;
+               }
+       }
+
+       /* Interrupt */
+       static inline void countInterruptCheckForWork(IOEventSourceCounter *counter) {
+               if (counter) {
+                       counter->u.interrupt.checksForWork++;
+               }
+       }
+
+       static inline void countInterrupt(IOEventSourceCounter *counter) {
+               if (counter) {
+                       counter->u.interrupt.produced++;
+               }
+       }
+
+       /* CommandQueue */
+       static inline void countCommandQueueActionCall(IOEventSourceCounter *counter) {
+               if (counter) {
+                       counter->u.commandQueue.actionCalls++;
+               }
+       }
+
+       /* CommandGate */
+       static inline void countCommandGateActionCall(IOEventSourceCounter *counter) {
+               if (counter) {
+                       counter->u.commandGate.actionCalls++;
+               }
+       }
+
+       /* Timer */
+       static inline void countTimerTimeout(IOEventSourceCounter *counter) {
+               if (counter) {
+                       counter->u.timer.timeouts++;
+               }
+       }
+
+       /* WorkLoop */
+       static void attachWorkLoopEventSource(IOWorkLoopCounter *wlc, IOEventSourceCounter *esc);
+       static void detachWorkLoopEventSource(IOWorkLoopCounter *wlc, IOEventSourceCounter *esc);
+
+       static inline void countWorkLoopOpenGate(IOWorkLoopCounter *counter) {
+               if (counter) {
+                       counter->timeOnGate += mach_absolute_time() - counter->startTimeStamp;
+                       counter->openGateCalls++;
+               }
+       }
+
+       static inline void countWorkLoopCloseGate(IOWorkLoopCounter *counter) {
+               if (counter) {
+                       counter->startTimeStamp = mach_absolute_time();
+                       counter->closeGateCalls++;
+               }
+       }
+
+       /* IOLib allocations */ 
+       static void countAlloc(uint32_t index, vm_size_t size);
+
+       /* UserClient */
+       static void countUserClientCall(IOUserClient *client);
+};
+
+#else
+
+/* Statistics disabled */
+
+class IOStatistics {
+public:
+       static void initialize() {}
+};
+
+#endif /* IOKITSTATS */
+
+#endif /* __IOKIT_STATISTICS_PRIVATE_H */