Loading...
--- xnu/xnu-12377.101.15/iokit/Kernel/IOHistogramReporter.cpp
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * 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
- * compliance with the License. The rights granted to you under the License
- * may not be used to create, or enable the creation or redistribution of,
- * 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,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * 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@
- */
-
-#define IOKIT_ENABLE_SHARED_PTR
-
-#define __STDC_LIMIT_MACROS // what are the C++ equivalents?
-#include <stdint.h>
-
-#include <IOKit/IOKernelReportStructs.h>
-#include <IOKit/IOKernelReporters.h>
-#include <os/overflow.h>
-#include "IOReporterDefs.h"
-
-
-#define super IOReporter
-OSDefineMetaClassAndStructors(IOHistogramReporter, IOReporter);
-
-/* static */
-OSSharedPtr<IOHistogramReporter>
-IOHistogramReporter::with(IOService *reportingService,
- IOReportCategories categories,
- uint64_t channelID,
- const char *channelName,
- IOReportUnit unit,
- int nSegments,
- IOHistogramSegmentConfig *config)
-{
- OSSharedPtr<IOHistogramReporter> reporter = OSMakeShared<IOHistogramReporter>();
- OSSharedPtr<const OSSymbol> tmpChannelName;
-
- if (reporter) {
- if (channelName) {
- tmpChannelName = OSSymbol::withCString(channelName);
- }
-
- if (reporter->initWith(reportingService, categories,
- channelID, tmpChannelName.get(),
- unit, nSegments, config)) {
- return reporter;
- }
- }
-
- return nullptr;
-}
-
-
-bool
-IOHistogramReporter::initWith(IOService *reportingService,
- 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*)IOMallocData(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 *)IOMallocZeroData(elementsSize);
- if (!_elements) {
- goto finish;
- }
-
- // Allocate memory for the array of element watch count
- PREFL_MEMOP_FAIL(_nElements, int);
- eCountsSize = (size_t)_nChannels * sizeof(int);
- _enableCounts = (int *)IOMallocZeroData(eCountsSize);
- if (!_enableCounts) {
- goto finish;
- }
-
- 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 = ((int16_t) 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*)IOMallocZeroData(boundsSize);
- if (!_bucketBounds) {
- goto finish;
- }
- _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) {
- 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;
-}
-
-
-void
-IOHistogramReporter::free(void)
-{
- if (_bucketBounds) {
- PREFL_MEMOP_PANIC(_nElements, int64_t);
- IOFreeData(_bucketBounds, (size_t)_nElements * sizeof(int64_t));
- }
- if (_histogramSegmentsConfig) {
- PREFL_MEMOP_PANIC(_segmentCount, IOHistogramSegmentConfig);
- IOFreeData(_histogramSegmentsConfig,
- (size_t)_segmentCount * sizeof(IOHistogramSegmentConfig));
- }
-
- super::free();
-}
-
-
-OSSharedPtr<IOReportLegendEntry>
-IOHistogramReporter::handleCreateLegend(void)
-{
- OSSharedPtr<IOReportLegendEntry> legendEntry;
- OSSharedPtr<OSData> tmpConfigData;
- OSDictionary *tmpDict; // no refcount
-
- legendEntry = super::handleCreateLegend();
- if (!legendEntry) {
- return nullptr;
- }
-
- PREFL_MEMOP_PANIC(_segmentCount, IOHistogramSegmentConfig);
- tmpConfigData = OSData::withBytes(_histogramSegmentsConfig,
- (unsigned)_segmentCount *
- sizeof(IOHistogramSegmentConfig));
- if (!tmpConfigData) {
- return nullptr;
- }
-
- tmpDict = OSDynamicCast(OSDictionary,
- legendEntry->getObject(kIOReportLegendInfoKey));
- if (!tmpDict) {
- return nullptr;
- }
-
- tmpDict->setObject(kIOReportLegendConfigKey, tmpConfigData.get());
-
- return legendEntry;
-}
-
-IOReturn
-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();
-
- 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;
-
- result = setElementValues(index, (IOReportElementValues *)&bucket);
-finish:
- unlockReporter();
- return result;
-}
-
-int
-IOHistogramReporter::tallyValue(int64_t value)
-{
- int result = -1;
- int cnt = 0, element_index = 0;
- int64_t sum = 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;
- }
- if (os_add_overflow(hist_values.bucket_sum, value, &sum)) {
- hist_values.bucket_sum = INT64_MAX;
- } else {
- hist_values.bucket_sum = sum;
- }
- hist_values.bucket_hits++;
-
- if (setElementValues(element_index, (IOReportElementValues *)&hist_values)
- != kIOReturnSuccess) {
- goto finish;
- }
-
- // success!
- result = element_index;
-
-finish:
- unlockReporter();
- return result;
-}
-
-/* static */ OSPtr<IOReportLegendEntry>
-IOHistogramReporter::createLegend(uint64_t channelID,
- const char *channelName,
- int segmentCount,
- IOHistogramSegmentConfig *config,
- IOReportCategories categories,
- IOReportUnit unit)
-{
- OSSharedPtr<IOReportLegendEntry> legendEntry;
- OSSharedPtr<OSData> tmpConfigData;
- OSDictionary *tmpDict; // no refcount
- int cnt;
-
- IOReportChannelType channelType = {
- .categories = categories,
- .report_format = kIOReportFormatHistogram,
- .nelements = 0,
- .element_idx = 0
- };
-
- for (cnt = 0; cnt < segmentCount; cnt++) {
- channelType.nelements += config[cnt].segment_bucket_count;
- }
-
- legendEntry = IOReporter::legendWith(&channelID, &channelName, 1, channelType, unit);
- if (!legendEntry) {
- return nullptr;
- }
-
- PREFL_MEMOP_PANIC(segmentCount, IOHistogramSegmentConfig);
- tmpConfigData = OSData::withBytes(config,
- (unsigned)segmentCount *
- sizeof(IOHistogramSegmentConfig));
- if (!tmpConfigData) {
- return nullptr;
- }
-
- tmpDict = OSDynamicCast(OSDictionary,
- legendEntry->getObject(kIOReportLegendInfoKey));
- if (!tmpDict) {
- return nullptr;
- }
-
- tmpDict->setObject(kIOReportLegendConfigKey, tmpConfigData.get());
-
- return legendEntry;
-}