]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2014 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_IOINTERRUPTACCOUNTING_PRIVATE_H | |
30 | #define __IOKIT_IOINTERRUPTACCOUNTING_PRIVATE_H | |
31 | ||
32 | /* | |
33 | * Header containing interrupt accounting related prototypes/defines that should be kept private to | |
34 | * xnu itself (no userspace, no kexts, no nothing!). | |
35 | */ | |
36 | ||
37 | #include <stdint.h> | |
38 | #include <IOKit/IOInterruptAccounting.h> | |
39 | #include <kern/queue.h> | |
40 | ||
41 | class OSObject; | |
42 | class IOSimpleReporter; | |
43 | ||
44 | /* | |
45 | * A brief overview. Interrupt accounting (as implemented in IOKit) pertains to infrastructure for | |
46 | * gathering information (currently, statistics only) on interrupts, and allowing them to be reported | |
47 | * (either to userspace through IOReporting, or through lldb; lldb macros have yet to be implemented). | |
48 | * | |
49 | * Currently, interrupt accounting consists of of a relationship between an IOService (a nub, which | |
50 | * will contain interrupt specifiers), an IOInterruptEventSource (if we add other interrupt target | |
51 | * abstractions, support could be added for them as well), and objects necessary to support them. An | |
52 | * interrupt is "named" by a tuple of {provider, interrupt index}; no nub should ever have more than | |
53 | * one interrupt registered for a given index, so this tuple should be unique. | |
54 | * | |
55 | * The "additional objects" mentioned above consist of an IOReporter object (lazily allocated and | |
56 | * tied to the nub; once allocated it will live until the nub is freed), and a statistics object | |
57 | * (effectively part of the IOIES in terms of lifecycle). The statistics object is used by the | |
58 | * interrupt codepath itself, and by the nub when it needs to update the reporter; the reporter is | |
59 | * used to report values to userspace. | |
60 | * | |
61 | * As a consequence of the above relationship, we do not track statistics for directly registered | |
62 | * interrupt handlers. We have no guarantees what the handler or the target may be; if you don't | |
63 | * follow the generic IOKit interrupt model, you will not be tracked by interrupt accounting. For | |
64 | * now, this means you must use an IOIES to be eligible for interrupt accounting. We also do not | |
65 | * track IOIES' that do not have providers (this is indicative that it is only being used to drive | |
66 | * workloop activity, and is not actually handling interrupts). | |
67 | */ | |
68 | ||
69 | /* | |
70 | * This is meant to let us set up the set of interrupt statistics we are actually interested in, by | |
71 | * setting a boot-arg. If we want to track a statistic, the bit corresponding to the index for that | |
72 | * statistic should be set in the bitmask. | |
73 | * | |
74 | * There is a bit of a mismatch here, in that our IOReporting channel namespace allows for 256 statistics, | |
75 | * but this bitmask actually limits it to 32. | |
76 | */ | |
77 | extern uint32_t gInterruptAccountingStatisticBitmask; | |
78 | ||
79 | /* | |
80 | * Check the bitmask by statistic index; useful for setting the initial value and conditionalizing code. | |
81 | */ | |
82 | #define IA_GET_ENABLE_BIT(statisticIndex) \ | |
83 | (((uint32_t) 1) << ((uint32_t) statisticIndex)) | |
84 | ||
85 | #define IA_GET_STATISTIC_ENABLED(statisticIndex) \ | |
86 | (IA_GET_ENABLE_BIT(statisticIndex) & gInterruptAccountingStatisticBitmask) | |
87 | ||
88 | /* | |
89 | * Check if any valid statistics are enabled. | |
90 | */ | |
91 | #define IA_ANY_STATISTICS_ENABLED \ | |
92 | ((IA_GET_ENABLE_BIT(kInterruptAccountingInvalidStatisticIndex) - 1) & gInterruptAccountingStatisticBitmask) | |
93 | ||
94 | /* | |
95 | * Actual string names for the statistics we gather. | |
96 | */ | |
97 | #define kInterruptAccountingChannelNameFirstLevelCount (" First Level Interrupt Handler Count") | |
98 | #define kInterruptAccountingChannelNameSecondLevelCount (" Second Level Interrupt Handler Count") | |
99 | #define kInterruptAccountingChannelNameFirstLevelTime (" First Level Interrupt Handler Time (MATUs)") | |
100 | #define kInterruptAccountingChannelNameSecondLevelCPUTime (" Second Level Interrupt Handler CPU Time (MATUs)") | |
101 | #define kInterruptAccountingChannelNameSecondLevelSystemTime ("Second Level Interrupt Handler System Time (MATUs)") | |
102 | #define kInterruptAccountingChannelNameNoThreadWakeups (" Interrupts that did not try to wake a thread") | |
103 | #define kInterruptAccountingChannelNameTotalThreadWakeups (" Sleeping threads woken up by this interrupt") | |
104 | #define kInterruptAccountingChannelNamePackageWakeups (" Package wakeups caused by this interrupt") | |
105 | #define kInterruptAccountingChannelNameCPUWakeups (" CPU wakeups caused by this interrupt") | |
106 | #define kInterruptAccountingChannelNameIdleExits (" Idle exits caused by this interrupt") | |
107 | ||
108 | static const char * const kInterruptAccountingStatisticNameArray[IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS] = { | |
109 | [kInterruptAccountingFirstLevelCountIndex] = kInterruptAccountingChannelNameFirstLevelCount, | |
110 | [kInterruptAccountingSecondLevelCountIndex] = kInterruptAccountingChannelNameSecondLevelCount, | |
111 | [kInterruptAccountingFirstLevelTimeIndex] = kInterruptAccountingChannelNameFirstLevelTime, | |
112 | [kInterruptAccountingSecondLevelCPUTimeIndex] = kInterruptAccountingChannelNameSecondLevelCPUTime, | |
113 | [kInterruptAccountingSecondLevelSystemTimeIndex] = kInterruptAccountingChannelNameSecondLevelSystemTime, | |
114 | [kInterruptAccountingNoThreadWakeupsIndex] = kInterruptAccountingChannelNameNoThreadWakeups, | |
115 | [kInterruptAccountingTotalThreadWakeupsIndex] = kInterruptAccountingChannelNameTotalThreadWakeups, | |
116 | [kInterruptAccountingPackageWakeupsIndex] = kInterruptAccountingChannelNamePackageWakeups, | |
117 | [kInterruptAccountingCPUWakeupsIndex] = kInterruptAccountingChannelNameCPUWakeups, | |
118 | [kInterruptAccountingIdleExitsIndex] = kInterruptAccountingChannelNameIdleExits, | |
119 | }; | |
120 | ||
121 | /* | |
122 | * IOReporting group names. | |
123 | */ | |
124 | static const char * const kInterruptAccountingGroupName = "Interrupt Statistics (by index)"; | |
125 | ||
126 | /* | |
127 | * TODO: Generate the subgroup name strings? | |
128 | */ | |
129 | #define IA_MAX_SUBGROUP_NAME (32) | |
130 | ||
131 | static const char * const kInterruptAccountingSubgroupNames[IA_MAX_SUBGROUP_NAME] = { | |
132 | "0", "1", "2" , "3", "4", "5", "6", "7", | |
133 | "8", "9", "10", "11", "12", "13", "14", "15", | |
134 | "16", "17", "18", "19", "20", "21", "22", "23", | |
135 | "24", "25", "26", "27", "28", "29", "30", "31"}; | |
136 | ||
137 | /* | |
138 | * As long as we use a lookup table, we may be out of bounds for a valid index. In this case, fall | |
139 | * back on a generic subgroup name that indicates we have screwed up. | |
140 | */ | |
141 | static const char * const kInterruptAccountingGenericSubgroupName = "(Index > 31)"; | |
142 | ||
143 | /* | |
144 | * For updating the statistics in the data structure. We cannot guarantee all of our platforms will be | |
145 | * able to do a 64-bit store in a single transaction. So, for new platforms, call out to the hardware | |
146 | * atomic add routine; it will either be unsupported, or do the right thing. For architectures or | |
147 | * platforms that do support it; just do regular assignment. | |
148 | * | |
149 | * We use this routine instead of a lock because at the moment, there is no way (in the interrupt context) | |
150 | * to reconcile a lock (even a spinlock) with the IOReporting synchonization (as we have no guarantee that | |
151 | * IOReporting will not block on a mutex, which would result in a panic if it held a spinlock). This | |
152 | * means that reported values may have a disparity if we update the reporter values while an interrupt is | |
153 | * being handled. | |
154 | * | |
155 | * Atomic modification should not be strictly required, as a given interrupt should not be dispatched to | |
156 | * two processors at once (and the interrupt should serve to force out stores), and the second level | |
157 | * handler should be synchonized by the work loop it runs on. | |
158 | */ | |
159 | #if __x86_64__ || __arm64 | |
160 | #define IA_ADD_VALUE(target, value) \ | |
161 | (*(target) += (value)) | |
162 | #else | |
163 | #define IA_ADD_VALUE(target, value) \ | |
164 | (OSAddAtomic64((value), (target))) | |
165 | #endif | |
166 | ||
167 | /* | |
168 | * TODO: Should this be an OSObject? Or properly pull in its methods as member functions? | |
169 | */ | |
170 | struct IOInterruptAccountingData { | |
171 | OSObject * owner; /* The owner of the statistics; currently always an IOIES or a subclass of it */ | |
172 | queue_chain_t chain; | |
173 | /* | |
174 | * We have no guarantee that the owner will not temporarily mutate its index value (i.e, in setWorkLoop | |
175 | * for IOIES). To ensure we can properly recalculate our own identity (and our channel IDs for the | |
176 | * reporter), stash the index we set up the reporter with here. | |
177 | * | |
178 | * Note that we should never remap the interrupt (point it to a different specifier). The mutation of | |
179 | * the index value is usually to negate it; I am uncertain of the reason for this at the moment. The | |
180 | * practical impact being that we should never need to update the stashed index value; it should stay | |
181 | * valid for the lifetime of the owner. | |
182 | */ | |
183 | int interruptIndex; | |
184 | ||
185 | /* | |
186 | * As long as we are based on the simple reporter, all our channels will be 64 bits. Align the data | |
187 | * to allow for safe atomic updates (we don't want to cross a cache line on any platform, but for some | |
188 | * it would cause a panic). | |
189 | */ | |
190 | volatile uint64_t interruptStatistics[IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS] __attribute__((aligned(8))); | |
191 | }; | |
192 | ||
193 | /* | |
194 | * Initializes global values/structures related to interrupt accounting. | |
195 | */ | |
196 | void interruptAccountingInit(void); | |
197 | ||
198 | /* | |
199 | * Routines for adding and removing objects from the global queue of IOInterruptAccountingData objects; | |
200 | * the queue exists as a debugging aid (no entities other than these routines should care about the | |
201 | * queue at runtime). | |
202 | */ | |
203 | void interruptAccountingDataAddToList(IOInterruptAccountingData * data); | |
204 | void interruptAccountingDataRemoveFromList(IOInterruptAccountingData * data); | |
205 | ||
206 | /* | |
207 | * Updates reporter with the statistics contained within data. Invoked when IOReporting has been asked | |
208 | * for updated statistics; requiring explicit synchronization of data between the statistic fields and | |
209 | * the reporter helps keep interrupt accounting overhead down. | |
210 | */ | |
211 | void interruptAccountingDataUpdateChannels(IOInterruptAccountingData * data, IOSimpleReporter * reporter); | |
212 | ||
213 | /* | |
214 | * Initializes the statistics in data using the statistics currently held by reporter. Typically invoked | |
215 | * when data is first associated with reporter. The nub that an interrupt is associated with will be | |
216 | * longer lived than the interrupt; as a result, our owner may not be the first to register for a | |
217 | * particular interrupt index with that nub, so we need to inherit the existing statistics (as we describe | |
218 | * statistics in terms of {nub id, index}, not in terms of our owner). | |
219 | */ | |
220 | void interruptAccountingDataInheritChannels(IOInterruptAccountingData * data, IOSimpleReporter * reporter); | |
221 | ||
222 | #endif /* __IOKIT_IOINTERRUPTACCOUNTING_PRIVATE_H */ | |
223 |