xref: /aosp_15_r20/external/grpc-grpc/src/python/grpcio_tests/tests/qps/histogram.py (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1# Copyright 2016 gRPC authors.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import math
16import threading
17
18from src.proto.grpc.testing import stats_pb2
19
20
21class Histogram(object):
22    """Histogram class used for recording performance testing data.
23
24    This class is thread safe.
25    """
26
27    def __init__(self, resolution, max_possible):
28        self._lock = threading.Lock()
29        self._resolution = resolution
30        self._max_possible = max_possible
31        self._sum = 0
32        self._sum_of_squares = 0
33        self.multiplier = 1.0 + self._resolution
34        self._count = 0
35        self._min = self._max_possible
36        self._max = 0
37        self._buckets = [0] * (self._bucket_for(self._max_possible) + 1)
38
39    def reset(self):
40        with self._lock:
41            self._sum = 0
42            self._sum_of_squares = 0
43            self._count = 0
44            self._min = self._max_possible
45            self._max = 0
46            self._buckets = [0] * (self._bucket_for(self._max_possible) + 1)
47
48    def add(self, val):
49        with self._lock:
50            self._sum += val
51            self._sum_of_squares += val * val
52            self._count += 1
53            self._min = min(self._min, val)
54            self._max = max(self._max, val)
55            self._buckets[self._bucket_for(val)] += 1
56
57    def get_data(self):
58        with self._lock:
59            data = stats_pb2.HistogramData()
60            data.bucket.extend(self._buckets)
61            data.min_seen = self._min
62            data.max_seen = self._max
63            data.sum = self._sum
64            data.sum_of_squares = self._sum_of_squares
65            data.count = self._count
66            return data
67
68    def merge(self, another_data):
69        with self._lock:
70            for i in range(len(self._buckets)):
71                self._buckets[i] += another_data.bucket[i]
72            self._min = min(self._min, another_data.min_seen)
73            self._max = max(self._max, another_data.max_seen)
74            self._sum += another_data.sum
75            self._sum_of_squares += another_data.sum_of_squares
76            self._count += another_data.count
77
78    def _bucket_for(self, val):
79        val = min(val, self._max_possible)
80        return int(math.log(val, self.multiplier))
81