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