private void WriteHistogram(HistogramBase histogram) { var targetBuffer = ByteBuffer.Allocate(histogram.GetNeededByteBufferCapacity()); var compressedLength = histogram.EncodeIntoCompressedByteBuffer(targetBuffer); byte[] compressedArray = new byte[compressedLength]; targetBuffer.BlockGet(compressedArray, 0, 0, compressedLength); var startTimeStampSec = histogram.StartTimeStamp / 1000.0; var endTimeStampSec = histogram.EndTimeStamp / 1000.0; var intervalLength = endTimeStampSec - startTimeStampSec; var maxValueUnitRatio = 1000000.0; var intervalMax = histogram.GetMaxValue() / maxValueUnitRatio; var binary = Convert.ToBase64String(compressedArray); var payload = $"{startTimeStampSec:F3},{intervalLength:F3},{intervalMax:F3},{binary}"; _log.WriteLine(payload); _log.Flush(); }
/// <summary> /// Produce textual representation of the value distribution of histogram data by percentile. /// The distribution is output with exponentially increasing resolution, with each exponentially decreasing /// half-distance containing <paramref name="percentileTicksPerHalfDistance"/> percentile reporting tick points. /// </summary> /// <param name="histogram">The histogram to operate on</param> /// <param name="printStream">Stream into which the distribution will be output</param> /// <param name="percentileTicksPerHalfDistance"> /// The number of reporting points per exponentially decreasing half-distance /// </param> /// <param name="outputValueUnitScalingRatio"> /// The scaling factor by which to divide histogram recorded values units in output. /// Use the <see cref="OutputScalingFactor"/> constant values to help choose an appropriate output measurement. /// </param> /// <param name="useCsvFormat">Output in CSV (Comma Separated Values) format if <c>true</c>, else use plain text form.</param> public static void OutputPercentileDistribution(this HistogramBase histogram, TextWriter printStream, int percentileTicksPerHalfDistance = 5, double outputValueUnitScalingRatio = OutputScalingFactor.TicksToMilliseconds, bool useCsvFormat = false) { if (useCsvFormat) { printStream.Write("\"Value\",\"Percentile\",\"TotalCount\",\"1/(1-Percentile)\"\n"); } else { printStream.Write("{0,12} {1,14} {2,10} {3,14}\n\n", "Value", "Percentile", "TotalCount", "1/(1-Percentile)"); } string percentileFormatString; string lastLinePercentileFormatString; if (useCsvFormat) { percentileFormatString = "{0:F" + histogram.NumberOfSignificantValueDigits + "},{1:F12},{2},{3:F2}\n"; lastLinePercentileFormatString = "{0:F" + histogram.NumberOfSignificantValueDigits + "},{1:F12},{2},Infinity\n"; } else { percentileFormatString = "{0,12:F" + histogram.NumberOfSignificantValueDigits + "}" + " {1,2:F12} {2,10} {3,14:F2}\n"; lastLinePercentileFormatString = "{0,12:F" + histogram.NumberOfSignificantValueDigits + "} {1,2:F12} {2,10}\n"; } try { foreach (var iterationValue in histogram.Percentiles(percentileTicksPerHalfDistance)) { if (iterationValue.PercentileLevelIteratedTo != 100.0D) { printStream.Write(percentileFormatString, iterationValue.ValueIteratedTo / outputValueUnitScalingRatio, iterationValue.PercentileLevelIteratedTo / 100.0D, iterationValue.TotalCountToThisValue, 1 / (1.0D - (iterationValue.PercentileLevelIteratedTo / 100.0D))); } else { printStream.Write(lastLinePercentileFormatString, iterationValue.ValueIteratedTo / outputValueUnitScalingRatio, iterationValue.PercentileLevelIteratedTo / 100.0D, iterationValue.TotalCountToThisValue); } } if (!useCsvFormat) { // Calculate and output mean and std. deviation. // Note: mean/std. deviation numbers are very often completely irrelevant when // data is extremely non-normal in distribution (e.g. in cases of strong multi-modal // response time distribution associated with GC pauses). However, reporting these numbers // can be very useful for contrasting with the detailed percentile distribution // reported by outputPercentileDistribution(). It is not at all surprising to find // percentile distributions where results fall many tens or even hundreds of standard // deviations away from the mean - such results simply indicate that the data sampled // exhibits a very non-normal distribution, highlighting situations for which the std. // deviation metric is a useless indicator. var mean = histogram.GetMean() / outputValueUnitScalingRatio; var stdDeviation = histogram.GetStdDeviation() / outputValueUnitScalingRatio; printStream.Write("#[Mean = {0,12:F" + histogram.NumberOfSignificantValueDigits + "}, " + "StdDeviation = {1,12:F" + histogram.NumberOfSignificantValueDigits + "}]\n", mean, stdDeviation); printStream.Write("#[Max = {0,12:F" + histogram.NumberOfSignificantValueDigits + "}, Total count = {1,12}]\n", histogram.GetMaxValue() / outputValueUnitScalingRatio, histogram.TotalCount); printStream.Write("#[Buckets = {0,12}, SubBuckets = {1,12}]\n", histogram.BucketCount, histogram.SubBucketCount); } } catch (ArgumentOutOfRangeException) { // Overflow conditions on histograms can lead to ArgumentOutOfRangeException on iterations: if (histogram.HasOverflowed()) { printStream.Write("# Histogram counts indicate OVERFLOW values"); } else { // Re-throw if reason is not a known overflow: throw; } } }