• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #endregion
18 
19 using System;
20 using System.Collections.Generic;
21 using System.Diagnostics;
22 using System.IO;
23 using System.Linq;
24 using System.Text.RegularExpressions;
25 using System.Threading;
26 using System.Threading.Tasks;
27 using Google.Protobuf;
28 using Grpc.Core;
29 using Grpc.Core.Utils;
30 using NUnit.Framework;
31 using Grpc.Testing;
32 
33 namespace Grpc.IntegrationTesting
34 {
35     /// <summary>
36     /// Basic implementation of histogram based on grpc/support/histogram.h.
37     /// </summary>
38     public class Histogram
39     {
40         readonly object myLock = new object();
41         readonly double multiplier;
42         readonly double oneOnLogMultiplier;
43         readonly double maxPossible;
44         readonly uint[] buckets;
45 
46         int count;
47         double sum;
48         double sumOfSquares;
49         double min;
50         double max;
51 
Histogram(double resolution, double maxPossible)52         public Histogram(double resolution, double maxPossible)
53         {
54             GrpcPreconditions.CheckArgument(resolution > 0);
55             GrpcPreconditions.CheckArgument(maxPossible > 0);
56             this.maxPossible = maxPossible;
57             this.multiplier = 1.0 + resolution;
58             this.oneOnLogMultiplier = 1.0 / Math.Log(1.0 + resolution);
59             this.buckets = new uint[FindBucket(maxPossible) + 1];
60 
61             ResetUnsafe();
62         }
63 
AddObservation(double value)64         public void AddObservation(double value)
65         {
66             lock (myLock)
67             {
68                 AddObservationUnsafe(value);
69             }
70         }
71 
72         /// <summary>
73         /// Gets snapshot of stats and optionally resets the histogram.
74         /// </summary>
GetSnapshot(bool reset = false)75         public HistogramData GetSnapshot(bool reset = false)
76         {
77             lock (myLock)
78             {
79                 var histogramData = new HistogramData();
80                 GetSnapshotUnsafe(histogramData, reset);
81                 return histogramData;
82             }
83         }
84 
85         /// <summary>
86         /// Merges snapshot of stats into <c>mergeTo</c> and optionally resets the histogram.
87         /// </summary>
GetSnapshot(HistogramData mergeTo, bool reset)88         public void GetSnapshot(HistogramData mergeTo, bool reset)
89         {
90             lock (myLock)
91             {
92                 GetSnapshotUnsafe(mergeTo, reset);
93             }
94         }
95 
96         /// <summary>
97         /// Finds bucket index to which given observation should go.
98         /// </summary>
FindBucket(double value)99         private int FindBucket(double value)
100         {
101             value = Math.Max(value, 1.0);
102             value = Math.Min(value, this.maxPossible);
103             return (int)(Math.Log(value) * oneOnLogMultiplier);
104         }
105 
AddObservationUnsafe(double value)106         private void AddObservationUnsafe(double value)
107         {
108             this.count++;
109             this.sum += value;
110             this.sumOfSquares += value * value;
111             this.min = Math.Min(this.min, value);
112             this.max = Math.Max(this.max, value);
113 
114             this.buckets[FindBucket(value)]++;
115         }
116 
GetSnapshotUnsafe(HistogramData mergeTo, bool reset)117         private void GetSnapshotUnsafe(HistogramData mergeTo, bool reset)
118         {
119             GrpcPreconditions.CheckArgument(mergeTo.Bucket.Count == 0 || mergeTo.Bucket.Count == buckets.Length);
120             if (mergeTo.Count == 0)
121             {
122                 mergeTo.MinSeen = min;
123                 mergeTo.MaxSeen = max;
124             }
125             else
126             {
127                 mergeTo.MinSeen = Math.Min(mergeTo.MinSeen, min);
128                 mergeTo.MaxSeen = Math.Max(mergeTo.MaxSeen, max);
129             }
130             mergeTo.Count += count;
131             mergeTo.Sum += sum;
132             mergeTo.SumOfSquares += sumOfSquares;
133 
134             if (mergeTo.Bucket.Count == 0)
135             {
136                 mergeTo.Bucket.AddRange(buckets);
137             }
138             else
139             {
140                 for (int i = 0; i < buckets.Length; i++)
141                 {
142                     mergeTo.Bucket[i] += buckets[i];
143                 }
144             }
145 
146             if (reset)
147             {
148               ResetUnsafe();
149             }
150         }
151 
ResetUnsafe()152         private void ResetUnsafe()
153         {
154             this.count = 0;
155             this.sum = 0;
156             this.sumOfSquares = 0;
157             this.min = double.PositiveInfinity;
158             this.max = double.NegativeInfinity;
159             for (int i = 0; i < this.buckets.Length; i++)
160             {
161                 this.buckets[i] = 0;
162             }
163         }
164     }
165 }
166