2 * Copyright (c) 2012-2013 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #define IOKIT_ENABLE_SHARED_PTR
31 #define __STDC_LIMIT_MACROS // what are the C++ equivalents?
34 #include <IOKit/IOKernelReportStructs.h>
35 #include <IOKit/IOKernelReporters.h>
36 #include "IOReporterDefs.h"
39 #define super IOReporter
40 OSDefineMetaClassAndStructors(IOHistogramReporter
, IOReporter
);
43 OSSharedPtr
<IOHistogramReporter
>
44 IOHistogramReporter::with(IOService
*reportingService
,
45 IOReportCategories categories
,
47 const char *channelName
,
50 IOHistogramSegmentConfig
*config
)
52 OSSharedPtr
<IOHistogramReporter
> reporter
= OSMakeShared
<IOHistogramReporter
>();
53 OSSharedPtr
<const OSSymbol
> tmpChannelName
;
57 tmpChannelName
= OSSymbol::withCString(channelName
);
60 if (reporter
->initWith(reportingService
, categories
,
61 channelID
, tmpChannelName
.get(),
62 unit
, nSegments
, config
)) {
72 IOHistogramReporter::initWith(IOService
*reportingService
,
73 IOReportCategories categories
,
75 const OSSymbol
*channelName
,
78 IOHistogramSegmentConfig
*config
)
81 IOReturn res
; // for PREFL_MEMOP
82 size_t configSize
, elementsSize
, eCountsSize
, boundsSize
;
83 int cnt
, cnt2
, cnt3
= 0;
84 int64_t bucketBound
= 0, previousBucketBound
= 0;
86 // analyzer appeasement
87 configSize
= elementsSize
= eCountsSize
= boundsSize
= 0;
89 IORLOG("IOHistogramReporter::initWith");
91 // For now, this reporter is currently limited to a single channel
94 IOReportChannelType channelType
= {
95 .categories
= categories
,
96 .report_format
= kIOReportFormatHistogram
,
97 .nelements
= 0, // Initialized when Config is unpacked
101 if (super::init(reportingService
, channelType
, unit
) != true) {
102 IORLOG("%s - ERROR: super::init failed", __func__
);
107 // Make sure to call this after the commit init phase
109 _channelNames
->setObject(channelName
);
112 _segmentCount
= nSegments
;
113 if (_segmentCount
== 0) {
114 IORLOG("IOReportHistogram init ERROR. No configuration provided!");
119 IORLOG("%s - %u segment(s)", __func__
, _segmentCount
);
121 PREFL_MEMOP_FAIL(_segmentCount
, IOHistogramSegmentConfig
);
122 configSize
= (size_t)_segmentCount
* sizeof(IOHistogramSegmentConfig
);
123 _histogramSegmentsConfig
= (IOHistogramSegmentConfig
*)IOMalloc(configSize
);
124 if (!_histogramSegmentsConfig
) {
127 memcpy(_histogramSegmentsConfig
, config
, configSize
);
129 // Find out how many elements are need to store the histogram
130 for (cnt
= 0; cnt
< _segmentCount
; cnt
++) {
131 _nElements
+= _histogramSegmentsConfig
[cnt
].segment_bucket_count
;
132 _channelDimension
+= _histogramSegmentsConfig
[cnt
].segment_bucket_count
;
134 IORLOG("\t\t bucket_base_width: %u | log_scale: %u | buckets: %u",
135 _histogramSegmentsConfig
[cnt
].base_bucket_width
,
136 _histogramSegmentsConfig
[cnt
].scale_flag
,
137 _histogramSegmentsConfig
[cnt
].segment_bucket_count
);
139 if (_histogramSegmentsConfig
[cnt
].scale_flag
> 1
140 || _histogramSegmentsConfig
[cnt
].base_bucket_width
== 0) {
146 // Update the channel type with discovered dimension
147 _channelType
.nelements
= _channelDimension
;
149 IORLOG("%s - %u channel(s) of dimension %u",
150 __func__
, _nChannels
, _channelDimension
);
152 IORLOG("%s %d segments for a total dimension of %d elements",
153 __func__
, _nChannels
, _nElements
);
155 // Allocate memory for the array of report elements
156 PREFL_MEMOP_FAIL(_nElements
, IOReportElement
);
157 elementsSize
= (size_t)_nElements
* sizeof(IOReportElement
);
158 _elements
= (IOReportElement
*)IOMalloc(elementsSize
);
162 memset(_elements
, 0, elementsSize
);
164 // Allocate memory for the array of element watch count
165 PREFL_MEMOP_FAIL(_nElements
, int);
166 eCountsSize
= (size_t)_nChannels
* sizeof(int);
167 _enableCounts
= (int *)IOMalloc(eCountsSize
);
168 if (!_enableCounts
) {
171 memset(_enableCounts
, 0, eCountsSize
);
174 for (cnt2
= 0; cnt2
< _channelDimension
; cnt2
++) {
175 IOHistogramReportValues hist_values
;
176 if (copyElementValues(cnt2
, (IOReportElementValues
*)&hist_values
)) {
179 hist_values
.bucket_min
= kIOReportInvalidIntValue
;
180 hist_values
.bucket_max
= kIOReportInvalidIntValue
;
181 hist_values
.bucket_sum
= kIOReportInvalidIntValue
;
182 if (setElementValues(cnt2
, (IOReportElementValues
*)&hist_values
)) {
186 // Setup IOReporter's channel IDs
187 _elements
[cnt2
].channel_id
= channelID
;
189 // Setup IOReporter's reporting provider service
190 _elements
[cnt2
].provider_id
= _driver_id
;
192 // Setup IOReporter's channel type
193 _elements
[cnt2
].channel_type
= _channelType
;
194 _elements
[cnt2
].channel_type
.element_idx
= ((int16_t) cnt2
);
196 //IOREPORTER_DEBUG_ELEMENT(cnt2);
200 // Allocate memory for the bucket upper bounds
201 PREFL_MEMOP_FAIL(_nElements
, uint64_t);
202 boundsSize
= (size_t)_nElements
* sizeof(uint64_t);
203 _bucketBounds
= (int64_t*)IOMalloc(boundsSize
);
204 if (!_bucketBounds
) {
207 memset(_bucketBounds
, 0, boundsSize
);
208 _bucketCount
= _nElements
;
210 for (cnt
= 0; cnt
< _segmentCount
; cnt
++) {
211 if (_histogramSegmentsConfig
[cnt
].segment_bucket_count
> INT_MAX
212 || _histogramSegmentsConfig
[cnt
].base_bucket_width
> INT_MAX
) {
215 for (cnt2
= 0; cnt2
< (int)_histogramSegmentsConfig
[cnt
].segment_bucket_count
; cnt2
++) {
216 if (cnt3
>= _nElements
) {
217 IORLOG("ERROR: _bucketBounds init");
222 if (_histogramSegmentsConfig
[cnt
].scale_flag
) {
223 // FIXME: Could use pow() but not sure how to include math.h
225 int exponent
= cnt2
+ 1;
227 power
*= _histogramSegmentsConfig
[cnt
].base_bucket_width
;
232 bucketBound
= _histogramSegmentsConfig
[cnt
].base_bucket_width
*
233 ((unsigned)cnt2
+ 1);
236 if (previousBucketBound
>= bucketBound
) {
237 IORLOG("Histogram ERROR: bucket bound does not increase linearly (segment %u / bucket # %u)",
243 _bucketBounds
[cnt3
] = bucketBound
;
244 // IORLOG("_bucketBounds[%u] = %llu", cnt3, bucketBound);
245 previousBucketBound
= _bucketBounds
[cnt3
];
259 IOHistogramReporter::free(void)
262 PREFL_MEMOP_PANIC(_nElements
, int64_t);
263 IOFree(_bucketBounds
, (size_t)_nElements
* sizeof(int64_t));
265 if (_histogramSegmentsConfig
) {
266 PREFL_MEMOP_PANIC(_segmentCount
, IOHistogramSegmentConfig
);
267 IOFree(_histogramSegmentsConfig
,
268 (size_t)_segmentCount
* sizeof(IOHistogramSegmentConfig
));
275 OSSharedPtr
<IOReportLegendEntry
>
276 IOHistogramReporter::handleCreateLegend(void)
278 OSSharedPtr
<IOReportLegendEntry
> legendEntry
;
279 OSSharedPtr
<OSData
> tmpConfigData
;
280 OSDictionary
*tmpDict
; // no refcount
282 legendEntry
= super::handleCreateLegend();
287 PREFL_MEMOP_PANIC(_segmentCount
, IOHistogramSegmentConfig
);
288 tmpConfigData
= OSData::withBytes(_histogramSegmentsConfig
,
289 (unsigned)_segmentCount
*
290 sizeof(IOHistogramSegmentConfig
));
291 if (!tmpConfigData
) {
295 tmpDict
= OSDynamicCast(OSDictionary
,
296 legendEntry
->getObject(kIOReportLegendInfoKey
));
301 tmpDict
->setObject(kIOReportLegendConfigKey
, tmpConfigData
.get());
307 IOHistogramReporter::overrideBucketValues(unsigned int index
,
308 uint64_t bucket_hits
,
314 IOHistogramReportValues bucket
;
317 if (index
>= (unsigned int)_bucketCount
) {
318 result
= kIOReturnBadArgument
;
322 bucket
.bucket_hits
= bucket_hits
;
323 bucket
.bucket_min
= bucket_min
;
324 bucket
.bucket_max
= bucket_max
;
325 bucket
.bucket_sum
= bucket_sum
;
327 result
= setElementValues(index
, (IOReportElementValues
*)&bucket
);
334 IOHistogramReporter::tallyValue(int64_t value
)
337 int cnt
= 0, element_index
= 0;
338 IOHistogramReportValues hist_values
;
342 // Iterate over _bucketCount minus one to make last bucket of infinite width
343 for (cnt
= 0; cnt
< _bucketCount
- 1; cnt
++) {
344 if (value
<= _bucketBounds
[cnt
]) {
351 if (copyElementValues(element_index
, (IOReportElementValues
*)&hist_values
) != kIOReturnSuccess
) {
355 // init stats on first hit
356 if (hist_values
.bucket_hits
== 0) {
357 hist_values
.bucket_min
= hist_values
.bucket_max
= value
;
358 hist_values
.bucket_sum
= 0; // += is below
362 if (value
< hist_values
.bucket_min
) {
363 hist_values
.bucket_min
= value
;
364 } else if (value
> hist_values
.bucket_max
) {
365 hist_values
.bucket_max
= value
;
367 hist_values
.bucket_sum
+= value
;
368 hist_values
.bucket_hits
++;
370 if (setElementValues(element_index
, (IOReportElementValues
*)&hist_values
)
371 != kIOReturnSuccess
) {
376 result
= element_index
;