Loading...
iokit/Kernel/IOHistogramReporter.cpp xnu-12377.101.15 xnu-4570.31.3
--- xnu/xnu-12377.101.15/iokit/Kernel/IOHistogramReporter.cpp
+++ xnu/xnu-4570.31.3/iokit/Kernel/IOHistogramReporter.cpp
@@ -1,8 +1,8 @@
 /*
  * 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
@@ -11,10 +11,10 @@
  * 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,
@@ -22,18 +22,15 @@
  * 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"
 
 
@@ -41,391 +38,342 @@
 OSDefineMetaClassAndStructors(IOHistogramReporter, IOReporter);
 
 /* static */
-OSSharedPtr<IOHistogramReporter>
+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;
+                          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;
 }
 
 
 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;
-
+                              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;
+    
 finish:
-	return result;
+    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>
+    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)
 {
-	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;
+    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();
+    }
+
+    return rval;
 }
 
 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);
+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;
+    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;
-
+    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;
-}
-
-/* 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;
-}
+    unlockReporter();
+    return result;
+}