-
Notifications
You must be signed in to change notification settings - Fork 162
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,73 +1,74 @@ | ||
// | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
// | ||
|
||
import Foundation | ||
import OpenTelemetryApi | ||
|
||
public class Base2ExponentialHistogramIndexer { | ||
private static var cache = [Int: Base2ExponentialHistogramIndexer]() | ||
private static var cacheLock = Lock() | ||
private static let LOG_BASE2_E = 1.0 / log(2) | ||
private static let EXPONENT_BIT_MASK : Int = 0x7FF0_0000_0000_0000 | ||
private static let SIGNIFICAND_BIT_MASK : Int = 0xF_FFFF_FFFF_FFFF | ||
private static let EXPONENT_BIAS : Int = 1023 | ||
private static let SIGNIFICAND_WIDTH : Int = 52 | ||
private static let EXPONENT_WIDTH : Int = 11 | ||
private static var cache = [Int: Base2ExponentialHistogramIndexer]() | ||
private static var cacheLock = Lock() | ||
private static let LOG_BASE2_E = 1.0 / log(2) | ||
private static let EXPONENT_BIT_MASK : Int = 0x7FF0_0000_0000_0000 | ||
private static let SIGNIFICAND_BIT_MASK : Int = 0xF_FFFF_FFFF_FFFF | ||
private static let EXPONENT_BIAS : Int = 1023 | ||
private static let SIGNIFICAND_WIDTH : Int = 52 | ||
private static let EXPONENT_WIDTH : Int = 11 | ||
|
||
private let scale : Int | ||
private let scaleFactor : Double | ||
private let scale : Int | ||
private let scaleFactor : Double | ||
|
||
init(scale: Int) { | ||
self.scale = scale | ||
self.scaleFactor = Self.computeScaleFactor(scale: scale) | ||
} | ||
init(scale: Int) { | ||
self.scale = scale | ||
self.scaleFactor = Self.computeScaleFactor(scale: scale) | ||
} | ||
|
||
func get(_ scale: Int) -> Base2ExponentialHistogramIndexer { | ||
Self.cacheLock.lock() | ||
defer { | ||
Self.cacheLock.unlock() | ||
} | ||
if let indexer = Self.cache[scale] { | ||
return indexer | ||
} else { | ||
let indexer = Base2ExponentialHistogramIndexer(scale: scale) | ||
Self.cache[scale] = indexer | ||
return indexer | ||
} | ||
} | ||
func get(_ scale: Int) -> Base2ExponentialHistogramIndexer { | ||
Self.cacheLock.lock() | ||
defer { | ||
Self.cacheLock.unlock() | ||
} | ||
if let indexer = Self.cache[scale] { | ||
return indexer | ||
} else { | ||
let indexer = Base2ExponentialHistogramIndexer(scale: scale) | ||
Self.cache[scale] = indexer | ||
return indexer | ||
} | ||
} | ||
Check warning on line 39 in Sources/OpenTelemetrySdk/Metrics/Stable/Data/Internal/Base2ExponentialHistogramIndexer.swift
|
||
|
||
func computeIndex(_ value: Double) -> Int { | ||
let absValue = abs(value) | ||
if scale > 0 { | ||
return indexByLogarithm(absValue) | ||
} | ||
if scale == 0 { | ||
return mapToIndexScaleZero(absValue) | ||
} | ||
return mapToIndexScaleZero(absValue) >> -scale | ||
} | ||
func computeIndex(_ value: Double) -> Int { | ||
let absValue = abs(value) | ||
if scale > 0 { | ||
return indexByLogarithm(absValue) | ||
} | ||
if scale == 0 { | ||
return mapToIndexScaleZero(absValue) | ||
} | ||
return mapToIndexScaleZero(absValue) >> -scale | ||
Check warning on line 49 in Sources/OpenTelemetrySdk/Metrics/Stable/Data/Internal/Base2ExponentialHistogramIndexer.swift
|
||
} | ||
|
||
func indexByLogarithm(_ value : Double) -> Int { | ||
Int(ceil(log(value) * scaleFactor) - 1) | ||
} | ||
func indexByLogarithm(_ value : Double) -> Int { | ||
Int(ceil(log(value) * scaleFactor) - 1) | ||
} | ||
|
||
func mapToIndexScaleZero(_ value : Double) -> Int { | ||
let raw = value.bitPattern | ||
var rawExponent = (Int(raw) & Self.EXPONENT_BIT_MASK) >> Self.SIGNIFICAND_WIDTH // does `value.exponentBitPattern` work here? | ||
let rawSignificand = Int(raw) & Self.SIGNIFICAND_BIT_MASK // does `value.significandBitPattern` work here? | ||
if rawExponent == 0 { | ||
rawExponent -= (rawSignificand - 1).leadingZeroBitCount - Self.EXPONENT_WIDTH - 1 | ||
} | ||
let ieeeExponent = rawExponent - Self.EXPONENT_BIAS | ||
if rawSignificand == 0 { | ||
return ieeeExponent - 1 | ||
} | ||
return ieeeExponent | ||
} | ||
func mapToIndexScaleZero(_ value : Double) -> Int { | ||
let raw = value.bitPattern | ||
var rawExponent = (Int(raw) & Self.EXPONENT_BIT_MASK) >> Self.SIGNIFICAND_WIDTH // does `value.exponentBitPattern` work here? | ||
let rawSignificand = Int(raw) & Self.SIGNIFICAND_BIT_MASK // does `value.significandBitPattern` work here? | ||
if rawExponent == 0 { | ||
rawExponent -= (rawSignificand - 1).leadingZeroBitCount - Self.EXPONENT_WIDTH - 1 | ||
Check warning on line 61 in Sources/OpenTelemetrySdk/Metrics/Stable/Data/Internal/Base2ExponentialHistogramIndexer.swift
|
||
} | ||
let ieeeExponent = rawExponent - Self.EXPONENT_BIAS | ||
if rawSignificand == 0 { | ||
return ieeeExponent - 1 | ||
} | ||
return ieeeExponent | ||
} | ||
|
||
static func computeScaleFactor(scale: Int) -> Double { | ||
Self.LOG_BASE2_E * pow(2.0, Double(scale)) | ||
} | ||
static func computeScaleFactor(scale: Int) -> Double { | ||
Self.LOG_BASE2_E * pow(2.0, Double(scale)) | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,123 +1,124 @@ | ||
// | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
// | ||
|
||
import Foundation | ||
import OpenTelemetryApi | ||
|
||
public class DoubleBase2ExponentialHistogramBuckets: ExponentialHistogramBuckets, NSCopying { | ||
public func copy(with zone: NSZone? = nil) -> Any { | ||
let copy = DoubleBase2ExponentialHistogramBuckets(scale: scale, maxBuckets: 0) | ||
copy.counts = counts.copy() as! AdaptingCircularBufferCounter | ||
copy.base2ExponentialHistogramIndexer = base2ExponentialHistogramIndexer | ||
copy.totalCount = totalCount | ||
return copy | ||
} | ||
public var totalCount: Int | ||
public var scale: Int | ||
public var offset: Int { | ||
get { | ||
if self.counts.isEmpty() { | ||
return 0 | ||
} else { | ||
return self.counts.startIndex | ||
} | ||
} | ||
} | ||
public var bucketCounts: [Int64] { | ||
get { | ||
if self.counts.isEmpty() { | ||
return [] | ||
} | ||
let length = self.counts.endIndex - self.counts.startIndex + 1 | ||
var countsArr: Array<Int64> = Array(repeating: Int64(0), count: length) | ||
for i in 0..<length { | ||
countsArr[i] = self.counts.get(index: (i + self.counts.startIndex)) | ||
} | ||
return countsArr | ||
} | ||
} | ||
var counts: AdaptingCircularBufferCounter | ||
var base2ExponentialHistogramIndexer: Base2ExponentialHistogramIndexer | ||
public func copy(with zone: NSZone? = nil) -> Any { | ||
let copy = DoubleBase2ExponentialHistogramBuckets(scale: scale, maxBuckets: 0) | ||
copy.counts = counts.copy() as! AdaptingCircularBufferCounter | ||
copy.base2ExponentialHistogramIndexer = base2ExponentialHistogramIndexer | ||
copy.totalCount = totalCount | ||
return copy | ||
} | ||
public var totalCount: Int | ||
public var scale: Int | ||
public var offset: Int { | ||
get { | ||
if self.counts.isEmpty() { | ||
return 0 | ||
} else { | ||
return self.counts.startIndex | ||
} | ||
} | ||
Check warning on line 28 in Sources/OpenTelemetrySdk/Metrics/Stable/Data/Internal/DoubleBase2ExponentialHistogramBuckets.swift
|
||
} | ||
public var bucketCounts: [Int64] { | ||
get { | ||
if self.counts.isEmpty() { | ||
return [] | ||
} | ||
let length = self.counts.endIndex - self.counts.startIndex + 1 | ||
var countsArr: Array<Int64> = Array(repeating: Int64(0), count: length) | ||
for i in 0..<length { | ||
countsArr[i] = self.counts.get(index: (i + self.counts.startIndex)) | ||
} | ||
return countsArr | ||
} | ||
} | ||
var counts: AdaptingCircularBufferCounter | ||
var base2ExponentialHistogramIndexer: Base2ExponentialHistogramIndexer | ||
|
||
init(scale: Int, maxBuckets: Int) { | ||
self.counts = AdaptingCircularBufferCounter(maxSize: maxBuckets) | ||
self.scale = scale | ||
self.base2ExponentialHistogramIndexer = Base2ExponentialHistogramIndexer(scale: scale) | ||
self.totalCount = 0 | ||
} | ||
func clear(scale: Int) { | ||
self.totalCount = 0 | ||
self.scale = scale | ||
self.base2ExponentialHistogramIndexer = Base2ExponentialHistogramIndexer(scale: scale) | ||
self.counts.clear() | ||
} | ||
@discardableResult func record(value: Double) -> Bool { | ||
guard value != 0.0 else { return false } | ||
let index = self.base2ExponentialHistogramIndexer.computeIndex(value) | ||
let recordingSuccessful = self.counts.increment(index: index, delta: 1) | ||
if recordingSuccessful { | ||
self.totalCount += 1 | ||
} | ||
return recordingSuccessful | ||
} | ||
func downscale(by: Int) { | ||
if by == 0 { | ||
return | ||
} else if by < 0 { | ||
return | ||
} | ||
if !self.counts.isEmpty() { | ||
let newCounts = self.counts.copy() as! AdaptingCircularBufferCounter | ||
newCounts.clear() | ||
for i in self.counts.startIndex...self.counts.endIndex { | ||
let count = self.counts.get(index: i) | ||
if count > 0 { | ||
if !newCounts.increment(index: i >> by, delta: count) { | ||
return | ||
} | ||
} | ||
} | ||
self.counts = newCounts | ||
} | ||
self.scale = self.scale - by | ||
self.base2ExponentialHistogramIndexer = Base2ExponentialHistogramIndexer(scale: self.scale) | ||
} | ||
func getScaleReduction(_ value: Double) -> Int { | ||
let index = self.base2ExponentialHistogramIndexer.computeIndex(value) | ||
let newStart = Swift.min(index, self.counts.startIndex) | ||
let newEnd = Swift.max(index, self.counts.endIndex) | ||
return getScaleReduction(newStart: newStart, newEnd: newEnd) | ||
} | ||
func getScaleReduction(newStart: Int, newEnd: Int) -> Int { | ||
var scaleReduction = 0 | ||
var newStart = newStart | ||
var newEnd = newEnd | ||
while (newEnd - newStart + 1 > self.counts.getMaxSize()) { | ||
newStart >>= 1 | ||
newEnd >>= 1 | ||
scaleReduction += 1 | ||
} | ||
return scaleReduction | ||
} | ||
init(scale: Int, maxBuckets: Int) { | ||
self.counts = AdaptingCircularBufferCounter(maxSize: maxBuckets) | ||
self.scale = scale | ||
self.base2ExponentialHistogramIndexer = Base2ExponentialHistogramIndexer(scale: scale) | ||
self.totalCount = 0 | ||
} | ||
func clear(scale: Int) { | ||
self.totalCount = 0 | ||
self.scale = scale | ||
self.base2ExponentialHistogramIndexer = Base2ExponentialHistogramIndexer(scale: scale) | ||
self.counts.clear() | ||
} | ||
@discardableResult func record(value: Double) -> Bool { | ||
guard value != 0.0 else { return false } | ||
let index = self.base2ExponentialHistogramIndexer.computeIndex(value) | ||
let recordingSuccessful = self.counts.increment(index: index, delta: 1) | ||
if recordingSuccessful { | ||
self.totalCount += 1 | ||
} | ||
return recordingSuccessful | ||
} | ||
func downscale(by: Int) { | ||
if by == 0 { | ||
return | ||
Check warning on line 78 in Sources/OpenTelemetrySdk/Metrics/Stable/Data/Internal/DoubleBase2ExponentialHistogramBuckets.swift
|
||
} else if by < 0 { | ||
return | ||
Check warning on line 80 in Sources/OpenTelemetrySdk/Metrics/Stable/Data/Internal/DoubleBase2ExponentialHistogramBuckets.swift
|
||
} | ||
if !self.counts.isEmpty() { | ||
let newCounts = self.counts.copy() as! AdaptingCircularBufferCounter | ||
newCounts.clear() | ||
for i in self.counts.startIndex...self.counts.endIndex { | ||
let count = self.counts.get(index: i) | ||
if count > 0 { | ||
if !newCounts.increment(index: i >> by, delta: count) { | ||
return | ||
Check warning on line 91 in Sources/OpenTelemetrySdk/Metrics/Stable/Data/Internal/DoubleBase2ExponentialHistogramBuckets.swift
|
||
} | ||
} | ||
} | ||
self.counts = newCounts | ||
} | ||
self.scale = self.scale - by | ||
self.base2ExponentialHistogramIndexer = Base2ExponentialHistogramIndexer(scale: self.scale) | ||
} | ||
func getScaleReduction(_ value: Double) -> Int { | ||
let index = self.base2ExponentialHistogramIndexer.computeIndex(value) | ||
let newStart = Swift.min(index, self.counts.startIndex) | ||
let newEnd = Swift.max(index, self.counts.endIndex) | ||
return getScaleReduction(newStart: newStart, newEnd: newEnd) | ||
} | ||
func getScaleReduction(newStart: Int, newEnd: Int) -> Int { | ||
var scaleReduction = 0 | ||
var newStart = newStart | ||
var newEnd = newEnd | ||
while (newEnd - newStart + 1 > self.counts.getMaxSize()) { | ||
newStart >>= 1 | ||
newEnd >>= 1 | ||
scaleReduction += 1 | ||
} | ||
return scaleReduction | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,19 @@ | ||
// | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
// | ||
|
||
import Foundation | ||
|
||
public class EmptyExponentialHistogramBuckets: ExponentialHistogramBuckets { | ||
public var scale: Int | ||
public var offset: Int = 0 | ||
public var bucketCounts: [Int64] = [] | ||
public var totalCount: Int = 0 | ||
init(scale: Int) { | ||
self.scale = scale | ||
} | ||
public var scale: Int | ||
public var offset: Int = 0 | ||
public var bucketCounts: [Int64] = [] | ||
public var totalCount: Int = 0 | ||
init(scale: Int) { | ||
self.scale = scale | ||
} | ||
} | ||
|