SolarManager unter Versionsverwaltung
Erster Stand der Hintergrundprozesse, die auf der Synology unter /volume1/homes/wagner/SolarManager laufen: der Manager selbst, die Sammler je Geraet, die MQTT-Bruecke, der Wecker und - neu hinzugezogen - der AutoAction-Runner, der als Hintergrundprozess hierher gehoert und nicht ins Web-Verzeichnis. Zugangsdaten stehen nicht mehr im Quelltext, sondern in config.ini, die nicht mit eingecheckt wird. Vorlage ist config.ini.example, gelesen wird sie von konfig.py. Betroffen waren solarManager.py (Datenbank und Wattpilot), zeit.py, gatherWaterData.py, wecker.py und skoda_testdaten.py, das sich das Passwort bisher aus dem Quelltext eines anderen Moduls herausgesucht hat. Die Kia-Anbindung ist mit dem Fahrzeug entfallen: kiaTest.py, gatherCarData.py und hyundai_kia_connect_api sind nicht mehr dabei, ebenso gatherInverterData.py, auf das nur noch eine auskommentierte Zeile zeigte. Die mitgelieferten Bibliotheken bleiben im Repository - die NAS hat kein pip, sie muessen neben den Skripten liegen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
# Copyright The OpenTelemetry Authors
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class Mapping(ABC):
|
||||
"""
|
||||
Parent class for `LogarithmMapping` and `ExponentialMapping`.
|
||||
"""
|
||||
|
||||
# pylint: disable=no-member
|
||||
def __new__(cls, scale: int):
|
||||
with cls._mappings_lock:
|
||||
# cls._mappings and cls._mappings_lock are implemented in each of
|
||||
# the child classes as a dictionary and a lock, respectively. They
|
||||
# are not instantiated here because that would lead to both child
|
||||
# classes having the same instance of cls._mappings and
|
||||
# cls._mappings_lock.
|
||||
if scale not in cls._mappings:
|
||||
cls._mappings[scale] = super().__new__(cls)
|
||||
cls._mappings[scale]._init(scale)
|
||||
|
||||
return cls._mappings[scale]
|
||||
|
||||
@abstractmethod
|
||||
def _init(self, scale: int) -> None:
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
|
||||
if scale > self._get_max_scale():
|
||||
raise Exception(f"scale is larger than {self._max_scale}")
|
||||
|
||||
if scale < self._get_min_scale():
|
||||
raise Exception(f"scale is smaller than {self._min_scale}")
|
||||
|
||||
# The size of the exponential histogram buckets is determined by a
|
||||
# parameter known as scale, larger values of scale will produce smaller
|
||||
# buckets. Bucket boundaries of the exponential histogram are located
|
||||
# at integer powers of the base, where:
|
||||
#
|
||||
# base = 2 ** (2 ** (-scale))
|
||||
# https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md#all-scales-use-the-logarithm-function
|
||||
self._scale = scale
|
||||
|
||||
@abstractmethod
|
||||
def _get_min_scale(self) -> int:
|
||||
"""
|
||||
Return the smallest possible value for the mapping scale
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def _get_max_scale(self) -> int:
|
||||
"""
|
||||
Return the largest possible value for the mapping scale
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def map_to_index(self, value: float) -> int:
|
||||
"""
|
||||
Maps positive floating point values to indexes corresponding to
|
||||
`Mapping.scale`. Implementations are not expected to handle zeros,
|
||||
+inf, NaN, or negative values.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def get_lower_boundary(self, index: int) -> float:
|
||||
"""
|
||||
Returns the lower boundary of a given bucket index. The index is
|
||||
expected to map onto a range that is at least partially inside the
|
||||
range of normal floating point values. If the corresponding
|
||||
bucket's upper boundary is less than or equal to 2 ** -1022,
|
||||
:class:`~opentelemetry.sdk.metrics.MappingUnderflowError`
|
||||
will be raised. If the corresponding bucket's lower boundary is greater
|
||||
than ``sys.float_info.max``,
|
||||
:class:`~opentelemetry.sdk.metrics.MappingOverflowError`
|
||||
will be raised.
|
||||
"""
|
||||
|
||||
@property
|
||||
def scale(self) -> int:
|
||||
"""
|
||||
Returns the parameter that controls the resolution of this mapping.
|
||||
See: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/datamodel.md#exponential-scale
|
||||
"""
|
||||
return self._scale
|
||||
@@ -0,0 +1,26 @@
|
||||
# Copyright The OpenTelemetry Authors
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
class MappingUnderflowError(Exception):
|
||||
"""
|
||||
Raised when computing the lower boundary of an index that maps into a
|
||||
denormal floating point value.
|
||||
"""
|
||||
|
||||
|
||||
class MappingOverflowError(Exception):
|
||||
"""
|
||||
Raised when computing the lower boundary of an index that maps into +inf.
|
||||
"""
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
# Copyright The OpenTelemetry Authors
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from math import ldexp
|
||||
from threading import Lock
|
||||
|
||||
from mysql.opentelemetry.sdk.metrics._internal.exponential_histogram.mapping import (
|
||||
Mapping,
|
||||
)
|
||||
from mysql.opentelemetry.sdk.metrics._internal.exponential_histogram.mapping.errors import (
|
||||
MappingOverflowError,
|
||||
MappingUnderflowError,
|
||||
)
|
||||
from mysql.opentelemetry.sdk.metrics._internal.exponential_histogram.mapping.ieee_754 import (
|
||||
MANTISSA_WIDTH,
|
||||
MAX_NORMAL_EXPONENT,
|
||||
MIN_NORMAL_EXPONENT,
|
||||
MIN_NORMAL_VALUE,
|
||||
get_ieee_754_exponent,
|
||||
get_ieee_754_mantissa,
|
||||
)
|
||||
|
||||
|
||||
class ExponentMapping(Mapping):
|
||||
# Reference implementation here:
|
||||
# https://github.com/open-telemetry/opentelemetry-go/blob/0e6f9c29c10d6078e8131418e1d1d166c7195d61/sdk/metric/aggregator/exponential/mapping/exponent/exponent.go
|
||||
|
||||
_mappings = {}
|
||||
_mappings_lock = Lock()
|
||||
|
||||
_min_scale = -10
|
||||
_max_scale = 0
|
||||
|
||||
def _get_min_scale(self):
|
||||
# _min_scale defines the point at which the exponential mapping
|
||||
# function becomes useless for 64-bit floats. With scale -10, ignoring
|
||||
# subnormal values, bucket indices range from -1 to 1.
|
||||
return -10
|
||||
|
||||
def _get_max_scale(self):
|
||||
# _max_scale is the largest scale supported by exponential mapping. Use
|
||||
# a logarithm mapping for larger scales.
|
||||
return 0
|
||||
|
||||
def _init(self, scale: int):
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
|
||||
super()._init(scale)
|
||||
|
||||
# self._min_normal_lower_boundary_index is the largest index such that
|
||||
# base ** index < MIN_NORMAL_VALUE and
|
||||
# base ** (index + 1) >= MIN_NORMAL_VALUE. An exponential histogram
|
||||
# bucket with this index covers the range
|
||||
# (base ** index, base (index + 1)], including MIN_NORMAL_VALUE. This
|
||||
# is the smallest valid index that contains at least one normal value.
|
||||
index = MIN_NORMAL_EXPONENT >> -self._scale
|
||||
|
||||
if -self._scale < 2:
|
||||
# For scales -1 and 0, the maximum value 2 ** -1022 is a
|
||||
# power-of-two multiple, meaning base ** index == MIN_NORMAL_VALUE.
|
||||
# Subtracting 1 so that base ** (index + 1) == MIN_NORMAL_VALUE.
|
||||
index -= 1
|
||||
|
||||
self._min_normal_lower_boundary_index = index
|
||||
|
||||
# self._max_normal_lower_boundary_index is the index such that
|
||||
# base**index equals the greatest representable lower boundary. An
|
||||
# exponential histogram bucket with this index covers the range
|
||||
# ((2 ** 1024) / base, 2 ** 1024], which includes mysql.opentelemetry.sdk.
|
||||
# metrics._internal.exponential_histogram.ieee_754.MAX_NORMAL_VALUE.
|
||||
# This bucket is incomplete, since the upper boundary cannot be
|
||||
# represented. One greater than this index corresponds with the bucket
|
||||
# containing values > 2 ** 1024.
|
||||
self._max_normal_lower_boundary_index = MAX_NORMAL_EXPONENT >> -self._scale
|
||||
|
||||
def map_to_index(self, value: float) -> int:
|
||||
if value < MIN_NORMAL_VALUE:
|
||||
return self._min_normal_lower_boundary_index
|
||||
|
||||
exponent = get_ieee_754_exponent(value)
|
||||
|
||||
# Positive integers are represented in binary as having an infinite
|
||||
# amount of leading zeroes, for example 2 is represented as ...00010.
|
||||
|
||||
# A negative integer -x is represented in binary as the complement of
|
||||
# (x - 1). For example, -4 is represented as the complement of 4 - 1
|
||||
# == 3. 3 is represented as ...00011. Its compliment is ...11100, the
|
||||
# binary representation of -4.
|
||||
|
||||
# get_ieee_754_mantissa(value) gets the positive integer made up
|
||||
# from the rightmost MANTISSA_WIDTH bits (the mantissa) of the IEEE
|
||||
# 754 representation of value. If value is an exact power of 2, all
|
||||
# these MANTISSA_WIDTH bits would be all zeroes, and when 1 is
|
||||
# subtracted the resulting value is -1. The binary representation of
|
||||
# -1 is ...111, so when these bits are right shifted MANTISSA_WIDTH
|
||||
# places, the resulting value for correction is -1. If value is not an
|
||||
# exact power of 2, at least one of the rightmost MANTISSA_WIDTH
|
||||
# bits would be 1 (even for values whose decimal part is 0, like 5.0
|
||||
# since the IEEE 754 of such number is too the product of a power of 2
|
||||
# (defined in the exponent part of the IEEE 754 representation) and the
|
||||
# value defined in the mantissa). Having at least one of the rightmost
|
||||
# MANTISSA_WIDTH bit being 1 means that get_ieee_754(value) will
|
||||
# always be greater or equal to 1, and when 1 is subtracted, the
|
||||
# result will be greater or equal to 0, whose representation in binary
|
||||
# will be of at most MANTISSA_WIDTH ones that have an infinite
|
||||
# amount of leading zeroes. When those MANTISSA_WIDTH bits are
|
||||
# shifted to the right MANTISSA_WIDTH places, the resulting value
|
||||
# will be 0.
|
||||
|
||||
# In summary, correction will be -1 if value is a power of 2, 0 if not.
|
||||
|
||||
# FIXME Document why we can assume value will not be 0, inf, or NaN.
|
||||
correction = (get_ieee_754_mantissa(value) - 1) >> MANTISSA_WIDTH
|
||||
|
||||
return (exponent + correction) >> -self._scale
|
||||
|
||||
def get_lower_boundary(self, index: int) -> float:
|
||||
if index < self._min_normal_lower_boundary_index:
|
||||
raise MappingUnderflowError()
|
||||
|
||||
if index > self._max_normal_lower_boundary_index:
|
||||
raise MappingOverflowError()
|
||||
|
||||
return ldexp(1, index << -self._scale)
|
||||
|
||||
@property
|
||||
def scale(self) -> int:
|
||||
return self._scale
|
||||
@@ -0,0 +1,118 @@
|
||||
# Copyright The OpenTelemetry Authors
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ctypes import c_double, c_uint64
|
||||
from sys import float_info
|
||||
|
||||
# IEEE 754 64-bit floating point numbers use 11 bits for the exponent and 52
|
||||
# bits for the mantissa.
|
||||
MANTISSA_WIDTH = 52
|
||||
EXPONENT_WIDTH = 11
|
||||
|
||||
# This mask is equivalent to 52 "1" bits (there are 13 hexadecimal 4-bit "f"s
|
||||
# in the mantissa mask, 13 * 4 == 52) or 0xfffffffffffff in hexadecimal.
|
||||
MANTISSA_MASK = (1 << MANTISSA_WIDTH) - 1
|
||||
|
||||
# There are 11 bits for the exponent, but the exponent values 0 (11 "0"
|
||||
# bits) and 2047 (11 "1" bits) have special meanings so the exponent range is
|
||||
# from 1 to 2046. To calculate the exponent value, 1023 (the bias) is
|
||||
# subtracted from the exponent, so the exponent value range is from -1022 to
|
||||
# +1023.
|
||||
EXPONENT_BIAS = (2 ** (EXPONENT_WIDTH - 1)) - 1
|
||||
|
||||
# All the exponent mask bits are set to 1 for the 11 exponent bits.
|
||||
EXPONENT_MASK = ((1 << EXPONENT_WIDTH) - 1) << MANTISSA_WIDTH
|
||||
|
||||
# The sign mask has the first bit set to 1 and the rest to 0.
|
||||
SIGN_MASK = 1 << (EXPONENT_WIDTH + MANTISSA_WIDTH)
|
||||
|
||||
# For normal floating point numbers, the exponent can have a value in the
|
||||
# range [-1022, 1023].
|
||||
MIN_NORMAL_EXPONENT = -EXPONENT_BIAS + 1
|
||||
MAX_NORMAL_EXPONENT = EXPONENT_BIAS
|
||||
|
||||
# The smallest possible normal value is 2.2250738585072014e-308.
|
||||
# This value is the result of using the smallest possible number in the
|
||||
# mantissa, 1.0000000000000000000000000000000000000000000000000000 (52 "0"s in
|
||||
# the fractional part) and a single "1" in the exponent.
|
||||
# Finally 1 * (2 ** -1022) = 2.2250738585072014e-308.
|
||||
MIN_NORMAL_VALUE = float_info.min
|
||||
|
||||
# Greatest possible normal value (1.7976931348623157e+308)
|
||||
# The binary representation of a float in scientific notation uses (for the
|
||||
# mantissa) one bit for the integer part (which is implicit) and 52 bits for
|
||||
# the fractional part. Consider a float binary 1.111. It is equal to 1 + 1/2 +
|
||||
# 1/4 + 1/8. The greatest possible value in the 52-bit binary mantissa would be
|
||||
# then 1.1111111111111111111111111111111111111111111111111111 (52 "1"s in the
|
||||
# fractional part) whose decimal value is 1.9999999999999998. Finally,
|
||||
# 1.9999999999999998 * (2 ** 1023) = 1.7976931348623157e+308.
|
||||
MAX_NORMAL_VALUE = float_info.max
|
||||
|
||||
|
||||
def get_ieee_754_exponent(value: float) -> int:
|
||||
"""
|
||||
Gets the exponent of the IEEE 754 representation of a float.
|
||||
"""
|
||||
|
||||
return (
|
||||
(
|
||||
# This step gives the integer that corresponds to the IEEE 754
|
||||
# representation of a float. For example, consider
|
||||
# -MAX_NORMAL_VALUE for an example. We choose this value because
|
||||
# of its binary representation which makes easy to understand the
|
||||
# subsequent operations.
|
||||
#
|
||||
# c_uint64.from_buffer(c_double(-MAX_NORMAL_VALUE)).value == 18442240474082181119
|
||||
# bin(18442240474082181119) == '0b1111111111101111111111111111111111111111111111111111111111111111'
|
||||
#
|
||||
# The first bit of the previous binary number is the sign bit: 1 (1 means negative, 0 means positive)
|
||||
# The next 11 bits are the exponent bits: 11111111110
|
||||
# The next 52 bits are the mantissa bits: 1111111111111111111111111111111111111111111111111111
|
||||
#
|
||||
# This step isolates the exponent bits, turning every bit outside
|
||||
# of the exponent field (sign and mantissa bits) to 0.
|
||||
c_uint64.from_buffer(c_double(value)).value
|
||||
& EXPONENT_MASK
|
||||
# For the example this means:
|
||||
# 18442240474082181119 & EXPONENT_MASK == 9214364837600034816
|
||||
# bin(9214364837600034816) == '0b111111111100000000000000000000000000000000000000000000000000000'
|
||||
# Notice that the previous binary representation does not include
|
||||
# leading zeroes, so the sign bit is not included since it is a
|
||||
# zero.
|
||||
)
|
||||
# This step moves the exponent bits to the right, removing the
|
||||
# mantissa bits that were set to 0 by the previous step. This
|
||||
# leaves the IEEE 754 exponent value, ready for the next step.
|
||||
>> MANTISSA_WIDTH
|
||||
# For the example this means:
|
||||
# 9214364837600034816 >> MANTISSA_WIDTH == 2046
|
||||
# bin(2046) == '0b11111111110'
|
||||
# As shown above, these are the original 11 bits that correspond to the
|
||||
# exponent.
|
||||
# This step subtracts the exponent bias from the IEEE 754 value,
|
||||
# leaving the actual exponent value.
|
||||
) - EXPONENT_BIAS
|
||||
# For the example this means:
|
||||
# 2046 - EXPONENT_BIAS == 1023
|
||||
# As mentioned in a comment above, the largest value for the exponent is
|
||||
|
||||
|
||||
def get_ieee_754_mantissa(value: float) -> int:
|
||||
return (
|
||||
c_uint64.from_buffer(c_double(value)).value
|
||||
# This step isolates the mantissa bits. There is no need to do any
|
||||
# bit shifting as the mantissa bits are already the rightmost field
|
||||
# in an IEEE 754 representation.
|
||||
& MANTISSA_MASK
|
||||
)
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
# Copyright The OpenTelemetry Authors
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from math import exp, floor, ldexp, log
|
||||
from threading import Lock
|
||||
|
||||
from mysql.opentelemetry.sdk.metrics._internal.exponential_histogram.mapping import (
|
||||
Mapping,
|
||||
)
|
||||
from mysql.opentelemetry.sdk.metrics._internal.exponential_histogram.mapping.errors import (
|
||||
MappingOverflowError,
|
||||
MappingUnderflowError,
|
||||
)
|
||||
from mysql.opentelemetry.sdk.metrics._internal.exponential_histogram.mapping.ieee_754 import (
|
||||
MAX_NORMAL_EXPONENT,
|
||||
MIN_NORMAL_EXPONENT,
|
||||
MIN_NORMAL_VALUE,
|
||||
get_ieee_754_exponent,
|
||||
get_ieee_754_mantissa,
|
||||
)
|
||||
|
||||
|
||||
class LogarithmMapping(Mapping):
|
||||
# Reference implementation here:
|
||||
# https://github.com/open-telemetry/opentelemetry-go/blob/0e6f9c29c10d6078e8131418e1d1d166c7195d61/sdk/metric/aggregator/exponential/mapping/logarithm/logarithm.go
|
||||
|
||||
_mappings = {}
|
||||
_mappings_lock = Lock()
|
||||
|
||||
_min_scale = 1
|
||||
_max_scale = 20
|
||||
|
||||
def _get_min_scale(self):
|
||||
# _min_scale ensures that ExponentMapping is used for zero and negative
|
||||
# scale values.
|
||||
return self._min_scale
|
||||
|
||||
def _get_max_scale(self):
|
||||
# FIXME The Go implementation uses a value of 20 here, find out the
|
||||
# right value for this implementation, more information here:
|
||||
# https://github.com/lightstep/otel-launcher-go/blob/c9ca8483be067a39ab306b09060446e7fda65f35/lightstep/sdk/metric/aggregator/histogram/structure/README.md#mapping-function
|
||||
# https://github.com/open-telemetry/opentelemetry-go/blob/0e6f9c29c10d6078e8131418e1d1d166c7195d61/sdk/metric/aggregator/exponential/mapping/logarithm/logarithm.go#L32-L45
|
||||
return self._max_scale
|
||||
|
||||
def _init(self, scale: int):
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
|
||||
super()._init(scale)
|
||||
|
||||
# self._scale_factor is defined as a multiplier because multiplication
|
||||
# is faster than division. self._scale_factor is defined as:
|
||||
# index = log(value) * self._scale_factor
|
||||
# Where:
|
||||
# index = log(value) / log(base)
|
||||
# index = log(value) / log(2 ** (2 ** -scale))
|
||||
# index = log(value) / ((2 ** -scale) * log(2))
|
||||
# index = log(value) * ((1 / log(2)) * (2 ** scale))
|
||||
# self._scale_factor = ((1 / log(2)) * (2 ** scale))
|
||||
# self._scale_factor = (1 /log(2)) * (2 ** scale)
|
||||
# self._scale_factor = ldexp(1 / log(2), scale)
|
||||
# This implementation was copied from a Java prototype. See:
|
||||
# https://github.com/newrelic-experimental/newrelic-sketch-java/blob/1ce245713603d61ba3a4510f6df930a5479cd3f6/src/main/java/com/newrelic/nrsketch/indexer/LogIndexer.java
|
||||
# for the equations used here.
|
||||
self._scale_factor = ldexp(1 / log(2), scale)
|
||||
|
||||
# self._min_normal_lower_boundary_index is the index such that
|
||||
# base ** index == MIN_NORMAL_VALUE. An exponential histogram bucket
|
||||
# with this index covers the range
|
||||
# (MIN_NORMAL_VALUE, MIN_NORMAL_VALUE * base]. One less than this index
|
||||
# corresponds with the bucket containing values <= MIN_NORMAL_VALUE.
|
||||
self._min_normal_lower_boundary_index = MIN_NORMAL_EXPONENT << self._scale
|
||||
|
||||
# self._max_normal_lower_boundary_index is the index such that
|
||||
# base ** index equals the greatest representable lower boundary. An
|
||||
# exponential histogram bucket with this index covers the range
|
||||
# ((2 ** 1024) / base, 2 ** 1024], which includes mysql.opentelemetry.sdk.
|
||||
# metrics._internal.exponential_histogram.ieee_754.MAX_NORMAL_VALUE.
|
||||
# This bucket is incomplete, since the upper boundary cannot be
|
||||
# represented. One greater than this index corresponds with the bucket
|
||||
# containing values > 2 ** 1024.
|
||||
self._max_normal_lower_boundary_index = (
|
||||
(MAX_NORMAL_EXPONENT + 1) << self._scale
|
||||
) - 1
|
||||
|
||||
def map_to_index(self, value: float) -> int:
|
||||
"""
|
||||
Maps positive floating point values to indexes corresponding to scale.
|
||||
"""
|
||||
|
||||
# value is subnormal
|
||||
if value <= MIN_NORMAL_VALUE:
|
||||
return self._min_normal_lower_boundary_index - 1
|
||||
|
||||
# value is an exact power of two.
|
||||
if get_ieee_754_mantissa(value) == 0:
|
||||
exponent = get_ieee_754_exponent(value)
|
||||
return (exponent << self._scale) - 1
|
||||
|
||||
return min(
|
||||
floor(log(value) * self._scale_factor),
|
||||
self._max_normal_lower_boundary_index,
|
||||
)
|
||||
|
||||
def get_lower_boundary(self, index: int) -> float:
|
||||
if index >= self._max_normal_lower_boundary_index:
|
||||
if index == self._max_normal_lower_boundary_index:
|
||||
return 2 * exp((index - (1 << self._scale)) / self._scale_factor)
|
||||
raise MappingOverflowError()
|
||||
|
||||
if index <= self._min_normal_lower_boundary_index:
|
||||
if index == self._min_normal_lower_boundary_index:
|
||||
return MIN_NORMAL_VALUE
|
||||
if index == self._min_normal_lower_boundary_index - 1:
|
||||
return exp((index + (1 << self._scale)) / self._scale_factor) / 2
|
||||
raise MappingUnderflowError()
|
||||
|
||||
return exp(index / self._scale_factor)
|
||||
|
||||
@property
|
||||
def scale(self) -> int:
|
||||
return self._scale
|
||||
Reference in New Issue
Block a user