IOStatisticsPrivate.h [plain text]
#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
#define IOKIT_STATISTICS_RECORDED_USERCLIENT_PROCS 20
#ifndef __probable
#define __probable(x) x
#endif
class IOWorkLoop;
class IOUserClient;
class IOEventSource;
struct IOEventSourceCounter;
struct IOUserClientCounter;
struct IOWorkLoopCounter;
struct IOUserClientProcessEntry;
struct KextNode;
enum {
kIOStatisticsMalloc = 0,
kIOStatisticsFree,
kIOStatisticsMallocAligned,
kIOStatisticsFreeAligned,
kIOStatisticsMallocContiguous,
kIOStatisticsFreeContiguous,
kIOStatisticsMallocPageable,
kIOStatisticsFreePageable,
kIOStatisticsAllocCount
};
TAILQ_HEAD(ProcessEntryList, IOUserClientProcessEntry);
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;
typedef struct IOUserClientProcessEntry {
TAILQ_ENTRY(IOUserClientProcessEntry) link;
char processName[kIOStatisticsProcessNameLength];
int32_t pid;
uint32_t calls;
} IOUserClientProcessEntry;
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);
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++;
}
}
static inline void countInterruptCheckForWork(IOEventSourceCounter *counter) {
if (counter) {
counter->u.interrupt.checksForWork++;
}
}
static inline void countInterrupt(IOEventSourceCounter *counter) {
if (counter) {
counter->u.interrupt.produced++;
}
}
static inline void countCommandQueueActionCall(IOEventSourceCounter *counter) {
if (counter) {
counter->u.commandQueue.actionCalls++;
}
}
static inline void countCommandGateActionCall(IOEventSourceCounter *counter) {
if (counter) {
counter->u.commandGate.actionCalls++;
}
}
static inline void countTimerTimeout(IOEventSourceCounter *counter) {
if (counter) {
counter->u.timer.timeouts++;
}
}
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++;
}
}
static void countAlloc(uint32_t index, vm_size_t size);
static void countUserClientCall(IOUserClient *client);
};
#else
class IOStatistics {
public:
static void initialize() {}
};
#endif
#endif