/*
* Copyright (c) 2012-2013 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
* 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,
* 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@
*/
/* static */
IOHistogramReporter*
IOHistogramReporter::with(IOService *reportingService,
- IOReportCategories categories,
- uint64_t channelID,
- const char *channelName,
- IOReportUnit unit,
- int nSegments,
- IOHistogramSegmentConfig *config)
+ IOReportCategories categories,
+ uint64_t channelID,
+ const char *channelName,
+ IOReportUnit unit,
+ int nSegments,
+ IOHistogramSegmentConfig *config)
{
- IOHistogramReporter *reporter = new IOHistogramReporter;
-
- const OSSymbol *tmpChannelName = NULL;
-
- if (reporter) {
-
- if (channelName)
- tmpChannelName = OSSymbol::withCString(channelName);
-
- if(reporter->initWith(reportingService, categories,
- channelID, tmpChannelName,
- unit, nSegments, config)) {
- return reporter;
- }
- }
- OSSafeReleaseNULL(reporter);
- OSSafeReleaseNULL(tmpChannelName);
-
- return 0;
+ IOHistogramReporter *reporter = new IOHistogramReporter;
+
+ const OSSymbol *tmpChannelName = NULL;
+
+ if (reporter) {
+ if (channelName) {
+ tmpChannelName = OSSymbol::withCString(channelName);
+ }
+
+ if (reporter->initWith(reportingService, categories,
+ channelID, tmpChannelName,
+ unit, nSegments, config)) {
+ return reporter;
+ }
+ }
+ OSSafeReleaseNULL(reporter);
+ OSSafeReleaseNULL(tmpChannelName);
+
+ return 0;
}
bool
IOHistogramReporter::initWith(IOService *reportingService,
- IOReportCategories categories,
- uint64_t channelID,
- const OSSymbol *channelName,
- IOReportUnit unit,
- int nSegments,
- IOHistogramSegmentConfig *config)
+ IOReportCategories categories,
+ uint64_t channelID,
+ const OSSymbol *channelName,
+ IOReportUnit unit,
+ int nSegments,
+ IOHistogramSegmentConfig *config)
{
- bool result = false;
- IOReturn res; // for PREFL_MEMOP
- size_t configSize, elementsSize, eCountsSize, boundsSize;
- int cnt, cnt2, cnt3 = 0;
- int64_t bucketBound = 0, previousBucketBound = 0;
-
- // analyzer appeasement
- configSize = elementsSize = eCountsSize = boundsSize = 0;
-
- IORLOG("IOHistogramReporter::initWith");
-
- // For now, this reporter is currently limited to a single channel
- _nChannels = 1;
-
- IOReportChannelType channelType = {
- .categories = categories,
- .report_format = kIOReportFormatHistogram,
- .nelements = 0, // Initialized when Config is unpacked
- .element_idx = 0
- };
-
- if (super::init(reportingService, channelType, unit) != true) {
- IORLOG("%s - ERROR: super::init failed", __func__);
- result = false;
- goto finish;
- }
-
- // Make sure to call this after the commit init phase
- if (channelName) _channelNames->setObject(channelName);
-
- _segmentCount = nSegments;
- if (_segmentCount == 0) {
- IORLOG("IOReportHistogram init ERROR. No configuration provided!");
- result = false;
- goto finish;
- }
-
- IORLOG("%s - %u segment(s)", __func__, _segmentCount);
-
- PREFL_MEMOP_FAIL(_segmentCount, IOHistogramSegmentConfig);
- configSize = (size_t)_segmentCount * sizeof(IOHistogramSegmentConfig);
- _histogramSegmentsConfig = (IOHistogramSegmentConfig*)IOMalloc(configSize);
- if (!_histogramSegmentsConfig) goto finish;
- memcpy(_histogramSegmentsConfig, config, configSize);
-
- // Find out how many elements are need to store the histogram
- for (cnt = 0; cnt < _segmentCount; cnt++) {
-
- _nElements += _histogramSegmentsConfig[cnt].segment_bucket_count;
- _channelDimension += _histogramSegmentsConfig[cnt].segment_bucket_count;
-
- IORLOG("\t\t bucket_base_width: %u | log_scale: %u | buckets: %u",
- _histogramSegmentsConfig[cnt].base_bucket_width,
- _histogramSegmentsConfig[cnt].scale_flag,
- _histogramSegmentsConfig[cnt].segment_bucket_count);
-
- if (_histogramSegmentsConfig[cnt].scale_flag > 1
- || _histogramSegmentsConfig[cnt].base_bucket_width == 0) {
- result = false;
- goto finish;
- }
-
- }
-
- // Update the channel type with discovered dimension
- _channelType.nelements = _channelDimension;
-
- IORLOG("%s - %u channel(s) of dimension %u",
- __func__, _nChannels, _channelDimension);
-
- IORLOG("%s %d segments for a total dimension of %d elements",
- __func__, _nChannels, _nElements);
-
- // Allocate memory for the array of report elements
- PREFL_MEMOP_FAIL(_nElements, IOReportElement);
- elementsSize = (size_t)_nElements * sizeof(IOReportElement);
- _elements = (IOReportElement *)IOMalloc(elementsSize);
- if (!_elements) goto finish;
- memset(_elements, 0, elementsSize);
-
- // Allocate memory for the array of element watch count
- PREFL_MEMOP_FAIL(_nElements, int);
- eCountsSize = (size_t)_nChannels * sizeof(int);
- _enableCounts = (int *)IOMalloc(eCountsSize);
- if (!_enableCounts) goto finish;
- memset(_enableCounts, 0, eCountsSize);
-
- lockReporter();
- for (cnt2 = 0; cnt2 < _channelDimension; cnt2++) {
- IOHistogramReportValues hist_values;
- if (copyElementValues(cnt2, (IOReportElementValues*)&hist_values)){
- goto finish;
- }
- hist_values.bucket_min = kIOReportInvalidIntValue;
- hist_values.bucket_max = kIOReportInvalidIntValue;
- hist_values.bucket_sum = kIOReportInvalidIntValue;
- if (setElementValues(cnt2, (IOReportElementValues*)&hist_values)){
- goto finish;
- }
-
- // Setup IOReporter's channel IDs
- _elements[cnt2].channel_id = channelID;
-
- // Setup IOReporter's reporting provider service
- _elements[cnt2].provider_id = _driver_id;
-
- // Setup IOReporter's channel type
- _elements[cnt2].channel_type = _channelType;
- _elements[cnt2].channel_type.element_idx = cnt2;
-
- //IOREPORTER_DEBUG_ELEMENT(cnt2);
- }
- unlockReporter();
-
- // Allocate memory for the bucket upper bounds
- PREFL_MEMOP_FAIL(_nElements, uint64_t);
- boundsSize = (size_t)_nElements * sizeof(uint64_t);
- _bucketBounds = (int64_t*)IOMalloc(boundsSize);
- if (!_bucketBounds) goto finish;
- memset(_bucketBounds, 0, boundsSize);
- _bucketCount = _nElements;
-
- for (cnt = 0; cnt < _segmentCount; cnt++) {
-
- if (_histogramSegmentsConfig[cnt].segment_bucket_count > INT_MAX
- || _histogramSegmentsConfig[cnt].base_bucket_width > INT_MAX) {
- goto finish;
- }
- for (cnt2 = 0; cnt2 < (int)_histogramSegmentsConfig[cnt].segment_bucket_count; cnt2++) {
-
- if (cnt3 >= _nElements) {
- IORLOG("ERROR: _bucketBounds init");
- result = false;
- goto finish;
- }
-
- if (_histogramSegmentsConfig[cnt].scale_flag) {
- // FIXME: Could use pow() but not sure how to include math.h
- int64_t power = 1;
- int exponent = cnt2 + 1;
- while (exponent) {
- power *= _histogramSegmentsConfig[cnt].base_bucket_width;
- exponent--;
- }
- bucketBound = power;
- }
-
- else {
- bucketBound = _histogramSegmentsConfig[cnt].base_bucket_width *
- ((unsigned)cnt2 + 1);
- }
-
- if (previousBucketBound >= bucketBound) {
- IORLOG("Histogram ERROR: bucket bound does not increase linearly (segment %u / bucket # %u)",
- cnt, cnt2);
- result = false;
- goto finish;
- }
-
- _bucketBounds[cnt3] = bucketBound;
- // IORLOG("_bucketBounds[%u] = %llu", cnt3, bucketBound);
- previousBucketBound = _bucketBounds[cnt3];
- cnt3++;
- }
- }
-
- // success
- result = true;
-
+ bool result = false;
+ IOReturn res; // for PREFL_MEMOP
+ size_t configSize, elementsSize, eCountsSize, boundsSize;
+ int cnt, cnt2, cnt3 = 0;
+ int64_t bucketBound = 0, previousBucketBound = 0;
+
+ // analyzer appeasement
+ configSize = elementsSize = eCountsSize = boundsSize = 0;
+
+ IORLOG("IOHistogramReporter::initWith");
+
+ // For now, this reporter is currently limited to a single channel
+ _nChannels = 1;
+
+ IOReportChannelType channelType = {
+ .categories = categories,
+ .report_format = kIOReportFormatHistogram,
+ .nelements = 0, // Initialized when Config is unpacked
+ .element_idx = 0
+ };
+
+ if (super::init(reportingService, channelType, unit) != true) {
+ IORLOG("%s - ERROR: super::init failed", __func__);
+ result = false;
+ goto finish;
+ }
+
+ // Make sure to call this after the commit init phase
+ if (channelName) {
+ _channelNames->setObject(channelName);
+ }
+
+ _segmentCount = nSegments;
+ if (_segmentCount == 0) {
+ IORLOG("IOReportHistogram init ERROR. No configuration provided!");
+ result = false;
+ goto finish;
+ }
+
+ IORLOG("%s - %u segment(s)", __func__, _segmentCount);
+
+ PREFL_MEMOP_FAIL(_segmentCount, IOHistogramSegmentConfig);
+ configSize = (size_t)_segmentCount * sizeof(IOHistogramSegmentConfig);
+ _histogramSegmentsConfig = (IOHistogramSegmentConfig*)IOMalloc(configSize);
+ if (!_histogramSegmentsConfig) {
+ goto finish;
+ }
+ memcpy(_histogramSegmentsConfig, config, configSize);
+
+ // Find out how many elements are need to store the histogram
+ for (cnt = 0; cnt < _segmentCount; cnt++) {
+ _nElements += _histogramSegmentsConfig[cnt].segment_bucket_count;
+ _channelDimension += _histogramSegmentsConfig[cnt].segment_bucket_count;
+
+ IORLOG("\t\t bucket_base_width: %u | log_scale: %u | buckets: %u",
+ _histogramSegmentsConfig[cnt].base_bucket_width,
+ _histogramSegmentsConfig[cnt].scale_flag,
+ _histogramSegmentsConfig[cnt].segment_bucket_count);
+
+ if (_histogramSegmentsConfig[cnt].scale_flag > 1
+ || _histogramSegmentsConfig[cnt].base_bucket_width == 0) {
+ result = false;
+ goto finish;
+ }
+ }
+
+ // Update the channel type with discovered dimension
+ _channelType.nelements = _channelDimension;
+
+ IORLOG("%s - %u channel(s) of dimension %u",
+ __func__, _nChannels, _channelDimension);
+
+ IORLOG("%s %d segments for a total dimension of %d elements",
+ __func__, _nChannels, _nElements);
+
+ // Allocate memory for the array of report elements
+ PREFL_MEMOP_FAIL(_nElements, IOReportElement);
+ elementsSize = (size_t)_nElements * sizeof(IOReportElement);
+ _elements = (IOReportElement *)IOMalloc(elementsSize);
+ if (!_elements) {
+ goto finish;
+ }
+ memset(_elements, 0, elementsSize);
+
+ // Allocate memory for the array of element watch count
+ PREFL_MEMOP_FAIL(_nElements, int);
+ eCountsSize = (size_t)_nChannels * sizeof(int);
+ _enableCounts = (int *)IOMalloc(eCountsSize);
+ if (!_enableCounts) {
+ goto finish;
+ }
+ memset(_enableCounts, 0, eCountsSize);
+
+ lockReporter();
+ for (cnt2 = 0; cnt2 < _channelDimension; cnt2++) {
+ IOHistogramReportValues hist_values;
+ if (copyElementValues(cnt2, (IOReportElementValues*)&hist_values)) {
+ goto finish;
+ }
+ hist_values.bucket_min = kIOReportInvalidIntValue;
+ hist_values.bucket_max = kIOReportInvalidIntValue;
+ hist_values.bucket_sum = kIOReportInvalidIntValue;
+ if (setElementValues(cnt2, (IOReportElementValues*)&hist_values)) {
+ goto finish;
+ }
+
+ // Setup IOReporter's channel IDs
+ _elements[cnt2].channel_id = channelID;
+
+ // Setup IOReporter's reporting provider service
+ _elements[cnt2].provider_id = _driver_id;
+
+ // Setup IOReporter's channel type
+ _elements[cnt2].channel_type = _channelType;
+ _elements[cnt2].channel_type.element_idx = cnt2;
+
+ //IOREPORTER_DEBUG_ELEMENT(cnt2);
+ }
+ unlockReporter();
+
+ // Allocate memory for the bucket upper bounds
+ PREFL_MEMOP_FAIL(_nElements, uint64_t);
+ boundsSize = (size_t)_nElements * sizeof(uint64_t);
+ _bucketBounds = (int64_t*)IOMalloc(boundsSize);
+ if (!_bucketBounds) {
+ goto finish;
+ }
+ memset(_bucketBounds, 0, boundsSize);
+ _bucketCount = _nElements;
+
+ for (cnt = 0; cnt < _segmentCount; cnt++) {
+ if (_histogramSegmentsConfig[cnt].segment_bucket_count > INT_MAX
+ || _histogramSegmentsConfig[cnt].base_bucket_width > INT_MAX) {
+ goto finish;
+ }
+ for (cnt2 = 0; cnt2 < (int)_histogramSegmentsConfig[cnt].segment_bucket_count; cnt2++) {
+ if (cnt3 >= _nElements) {
+ IORLOG("ERROR: _bucketBounds init");
+ result = false;
+ goto finish;
+ }
+
+ if (_histogramSegmentsConfig[cnt].scale_flag) {
+ // FIXME: Could use pow() but not sure how to include math.h
+ int64_t power = 1;
+ int exponent = cnt2 + 1;
+ while (exponent) {
+ power *= _histogramSegmentsConfig[cnt].base_bucket_width;
+ exponent--;
+ }
+ bucketBound = power;
+ } else {
+ bucketBound = _histogramSegmentsConfig[cnt].base_bucket_width *
+ ((unsigned)cnt2 + 1);
+ }
+
+ if (previousBucketBound >= bucketBound) {
+ IORLOG("Histogram ERROR: bucket bound does not increase linearly (segment %u / bucket # %u)",
+ cnt, cnt2);
+ result = false;
+ goto finish;
+ }
+
+ _bucketBounds[cnt3] = bucketBound;
+ // IORLOG("_bucketBounds[%u] = %llu", cnt3, bucketBound);
+ previousBucketBound = _bucketBounds[cnt3];
+ cnt3++;
+ }
+ }
+
+ // success
+ result = true;
+
finish:
- return result;
+ return result;
}
void
IOHistogramReporter::free(void)
{
- if (_bucketBounds) {
- PREFL_MEMOP_PANIC(_nElements, int64_t);
- IOFree(_bucketBounds, (size_t)_nElements * sizeof(int64_t));
- }
- if (_histogramSegmentsConfig) {
- PREFL_MEMOP_PANIC(_segmentCount, IOHistogramSegmentConfig);
- IOFree(_histogramSegmentsConfig,
- (size_t)_segmentCount * sizeof(IOHistogramSegmentConfig));
- }
-
- super::free();
+ if (_bucketBounds) {
+ PREFL_MEMOP_PANIC(_nElements, int64_t);
+ IOFree(_bucketBounds, (size_t)_nElements * sizeof(int64_t));
+ }
+ if (_histogramSegmentsConfig) {
+ PREFL_MEMOP_PANIC(_segmentCount, IOHistogramSegmentConfig);
+ IOFree(_histogramSegmentsConfig,
+ (size_t)_segmentCount * sizeof(IOHistogramSegmentConfig));
+ }
+
+ super::free();
}
IOReportLegendEntry*
IOHistogramReporter::handleCreateLegend(void)
{
- IOReportLegendEntry *rval = NULL, *legendEntry = NULL;
- OSData *tmpConfigData = NULL;
- OSDictionary *tmpDict; // no refcount
-
- legendEntry = super::handleCreateLegend();
- if (!legendEntry) goto finish;
-
- PREFL_MEMOP_PANIC(_segmentCount, IOHistogramSegmentConfig);
- tmpConfigData = OSData::withBytes(_histogramSegmentsConfig,
- (unsigned)_segmentCount *
- sizeof(IOHistogramSegmentConfig));
- if (!tmpConfigData) goto finish;
-
- tmpDict = OSDynamicCast(OSDictionary,
- legendEntry->getObject(kIOReportLegendInfoKey));
- if (!tmpDict) goto finish;
-
- tmpDict->setObject(kIOReportLegendConfigKey, tmpConfigData);
-
- // success
- rval = legendEntry;
+ IOReportLegendEntry *rval = NULL, *legendEntry = NULL;
+ OSData *tmpConfigData = NULL;
+ OSDictionary *tmpDict; // no refcount
+
+ legendEntry = super::handleCreateLegend();
+ if (!legendEntry) {
+ goto finish;
+ }
+
+ PREFL_MEMOP_PANIC(_segmentCount, IOHistogramSegmentConfig);
+ tmpConfigData = OSData::withBytes(_histogramSegmentsConfig,
+ (unsigned)_segmentCount *
+ sizeof(IOHistogramSegmentConfig));
+ if (!tmpConfigData) {
+ goto finish;
+ }
+
+ tmpDict = OSDynamicCast(OSDictionary,
+ legendEntry->getObject(kIOReportLegendInfoKey));
+ if (!tmpDict) {
+ goto finish;
+ }
+
+ tmpDict->setObject(kIOReportLegendConfigKey, tmpConfigData);
+
+ // success
+ rval = legendEntry;
finish:
- if (tmpConfigData) tmpConfigData->release();
- if (!rval && legendEntry) {
- legendEntry->release();
- }
+ if (tmpConfigData) {
+ tmpConfigData->release();
+ }
+ if (!rval && legendEntry) {
+ legendEntry->release();
+ }
- return rval;
+ return rval;
}
IOReturn
-IOHistogramReporter::overrideBucketValues(unsigned int index,
- uint64_t bucket_hits,
- int64_t bucket_min,
- int64_t bucket_max,
- int64_t bucket_sum)
+IOHistogramReporter::overrideBucketValues(unsigned int index,
+ uint64_t bucket_hits,
+ int64_t bucket_min,
+ int64_t bucket_max,
+ int64_t bucket_sum)
{
- IOReturn result;
- IOHistogramReportValues bucket;
- lockReporter();
+ IOReturn result;
+ IOHistogramReportValues bucket;
+ lockReporter();
- if (index >= (unsigned int)_bucketCount) {
- result = kIOReturnBadArgument;
- goto finish;
- }
+ if (index >= (unsigned int)_bucketCount) {
+ result = kIOReturnBadArgument;
+ goto finish;
+ }
- bucket.bucket_hits = bucket_hits;
- bucket.bucket_min = bucket_min;
- bucket.bucket_max = bucket_max;
- bucket.bucket_sum = bucket_sum;
+ bucket.bucket_hits = bucket_hits;
+ bucket.bucket_min = bucket_min;
+ bucket.bucket_max = bucket_max;
+ bucket.bucket_sum = bucket_sum;
- result = setElementValues(index, (IOReportElementValues *)&bucket);
+ result = setElementValues(index, (IOReportElementValues *)&bucket);
finish:
- unlockReporter();
- return result;
+ unlockReporter();
+ return result;
}
int
IOHistogramReporter::tallyValue(int64_t value)
{
- int result = -1;
- int cnt = 0, element_index = 0;
- IOHistogramReportValues hist_values;
-
- lockReporter();
-
- // Iterate over _bucketCount minus one to make last bucket of infinite width
- for (cnt = 0; cnt < _bucketCount - 1; cnt++) {
- if (value <= _bucketBounds[cnt]) break;
- }
-
- element_index = cnt;
-
- if (copyElementValues(element_index, (IOReportElementValues *)&hist_values) != kIOReturnSuccess) {
- goto finish;
- }
-
- // init stats on first hit
- if (hist_values.bucket_hits == 0) {
- hist_values.bucket_min = hist_values.bucket_max = value;
- hist_values.bucket_sum = 0; // += is below
- }
-
- // update all values
- if (value < hist_values.bucket_min) {
- hist_values.bucket_min = value;
- } else if (value > hist_values.bucket_max) {
- hist_values.bucket_max = value;
- }
- hist_values.bucket_sum += value;
- hist_values.bucket_hits++;
-
- if (setElementValues(element_index, (IOReportElementValues *)&hist_values)
- != kIOReturnSuccess) {
- goto finish;
- }
-
- // success!
- result = element_index;
-
+ int result = -1;
+ int cnt = 0, element_index = 0;
+ IOHistogramReportValues hist_values;
+
+ lockReporter();
+
+ // Iterate over _bucketCount minus one to make last bucket of infinite width
+ for (cnt = 0; cnt < _bucketCount - 1; cnt++) {
+ if (value <= _bucketBounds[cnt]) {
+ break;
+ }
+ }
+
+ element_index = cnt;
+
+ if (copyElementValues(element_index, (IOReportElementValues *)&hist_values) != kIOReturnSuccess) {
+ goto finish;
+ }
+
+ // init stats on first hit
+ if (hist_values.bucket_hits == 0) {
+ hist_values.bucket_min = hist_values.bucket_max = value;
+ hist_values.bucket_sum = 0; // += is below
+ }
+
+ // update all values
+ if (value < hist_values.bucket_min) {
+ hist_values.bucket_min = value;
+ } else if (value > hist_values.bucket_max) {
+ hist_values.bucket_max = value;
+ }
+ hist_values.bucket_sum += value;
+ hist_values.bucket_hits++;
+
+ if (setElementValues(element_index, (IOReportElementValues *)&hist_values)
+ != kIOReturnSuccess) {
+ goto finish;
+ }
+
+ // success!
+ result = element_index;
+
finish:
- unlockReporter();
- return result;
+ unlockReporter();
+ return result;
}