The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#)
https://grpc.io/
165 lines
4.8 KiB
165 lines
4.8 KiB
#region Copyright notice and license |
|
|
|
// Copyright 2015 gRPC 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. |
|
|
|
#endregion |
|
|
|
using System; |
|
using System.Collections.Generic; |
|
using System.Diagnostics; |
|
using System.IO; |
|
using System.Linq; |
|
using System.Text.RegularExpressions; |
|
using System.Threading; |
|
using System.Threading.Tasks; |
|
using Google.Protobuf; |
|
using Grpc.Core; |
|
using Grpc.Core.Utils; |
|
using NUnit.Framework; |
|
using Grpc.Testing; |
|
|
|
namespace Grpc.IntegrationTesting |
|
{ |
|
/// <summary> |
|
/// Basic implementation of histogram based on grpc/support/histogram.h. |
|
/// </summary> |
|
public class Histogram |
|
{ |
|
readonly object myLock = new object(); |
|
readonly double multiplier; |
|
readonly double oneOnLogMultiplier; |
|
readonly double maxPossible; |
|
readonly uint[] buckets; |
|
|
|
int count; |
|
double sum; |
|
double sumOfSquares; |
|
double min; |
|
double max; |
|
|
|
public Histogram(double resolution, double maxPossible) |
|
{ |
|
GrpcPreconditions.CheckArgument(resolution > 0); |
|
GrpcPreconditions.CheckArgument(maxPossible > 0); |
|
this.maxPossible = maxPossible; |
|
this.multiplier = 1.0 + resolution; |
|
this.oneOnLogMultiplier = 1.0 / Math.Log(1.0 + resolution); |
|
this.buckets = new uint[FindBucket(maxPossible) + 1]; |
|
|
|
ResetUnsafe(); |
|
} |
|
|
|
public void AddObservation(double value) |
|
{ |
|
lock (myLock) |
|
{ |
|
AddObservationUnsafe(value); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Gets snapshot of stats and optionally resets the histogram. |
|
/// </summary> |
|
public HistogramData GetSnapshot(bool reset = false) |
|
{ |
|
lock (myLock) |
|
{ |
|
var histogramData = new HistogramData(); |
|
GetSnapshotUnsafe(histogramData, reset); |
|
return histogramData; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Merges snapshot of stats into <c>mergeTo</c> and optionally resets the histogram. |
|
/// </summary> |
|
public void GetSnapshot(HistogramData mergeTo, bool reset) |
|
{ |
|
lock (myLock) |
|
{ |
|
GetSnapshotUnsafe(mergeTo, reset); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Finds bucket index to which given observation should go. |
|
/// </summary> |
|
private int FindBucket(double value) |
|
{ |
|
value = Math.Max(value, 1.0); |
|
value = Math.Min(value, this.maxPossible); |
|
return (int)(Math.Log(value) * oneOnLogMultiplier); |
|
} |
|
|
|
private void AddObservationUnsafe(double value) |
|
{ |
|
this.count++; |
|
this.sum += value; |
|
this.sumOfSquares += value * value; |
|
this.min = Math.Min(this.min, value); |
|
this.max = Math.Max(this.max, value); |
|
|
|
this.buckets[FindBucket(value)]++; |
|
} |
|
|
|
private void GetSnapshotUnsafe(HistogramData mergeTo, bool reset) |
|
{ |
|
GrpcPreconditions.CheckArgument(mergeTo.Bucket.Count == 0 || mergeTo.Bucket.Count == buckets.Length); |
|
if (mergeTo.Count == 0) |
|
{ |
|
mergeTo.MinSeen = min; |
|
mergeTo.MaxSeen = max; |
|
} |
|
else |
|
{ |
|
mergeTo.MinSeen = Math.Min(mergeTo.MinSeen, min); |
|
mergeTo.MaxSeen = Math.Max(mergeTo.MaxSeen, max); |
|
} |
|
mergeTo.Count += count; |
|
mergeTo.Sum += sum; |
|
mergeTo.SumOfSquares += sumOfSquares; |
|
|
|
if (mergeTo.Bucket.Count == 0) |
|
{ |
|
mergeTo.Bucket.AddRange(buckets); |
|
} |
|
else |
|
{ |
|
for (int i = 0; i < buckets.Length; i++) |
|
{ |
|
mergeTo.Bucket[i] += buckets[i]; |
|
} |
|
} |
|
|
|
if (reset) |
|
{ |
|
ResetUnsafe(); |
|
} |
|
} |
|
|
|
private void ResetUnsafe() |
|
{ |
|
this.count = 0; |
|
this.sum = 0; |
|
this.sumOfSquares = 0; |
|
this.min = double.PositiveInfinity; |
|
this.max = double.NegativeInfinity; |
|
for (int i = 0; i < this.buckets.Length; i++) |
|
{ |
|
this.buckets[i] = 0; |
|
} |
|
} |
|
} |
|
}
|
|
|