private void UpdateSensorStats() { int count; decimal totalTemp = 0, totalPing = 0; for (count = 0; count < CurrentBenchmark.SensorLog.Count; count++) { Benchmark.SensorValue sensorValue = CurrentBenchmark.SensorLog[count]; totalTemp += sensorValue.Temperature; totalPing += sensorValue.ShareAnswerPing; } Benchmark.GpuStat currentStat = CurrentBenchmark.CurrentStatistic; currentStat.AverageTemperature = totalTemp / count; currentStat.AverageShareAnswerPing = Math.Round(totalPing / count, MidpointRounding.AwayFromZero); }
private void UpdateHashRateStats() { // And so the counting begins List <Benchmark.HashEntry> hashList = CurrentBenchmark.HashLogs.ToList(); int hashLogSize = hashList.Count; uint found = 0; decimal sumOfWeightedRates = 0; decimal sumOfInverseWeightedRates = 0; double productOfWeightedLogRates = 0; ulong totalWeight = 0; decimal[] rates = new decimal[hashLogSize]; uint[] weights = new uint[hashLogSize]; uint minItemsMoving = 100; // Min amount of items in the moving average long lower = hashLogSize - minItemsMoving; uint minItemsLimit = lower > 0 ? (uint)lower : 0; uint minTimeMoving = 3600; // Max amount of time in the moving average uint minTimeLimit = hashLogSize > 0 ? (uint)(hashList[(hashLogSize - 1)].TimeStamp - minTimeMoving) : 0; List <decimal> movingRates = new List <decimal>(); List <uint> movingWeights = new List <uint>(); ulong movingTotalWeight = 0; for (int i = 0; i < hashLogSize; i++) { rates[i] = hashList[i].HashRate; weights[i] = hashList[i].HashCount; if (i >= minItemsLimit || hashList[i].TimeStamp >= minTimeLimit) { movingRates.Add(hashList[i].HashRate); movingWeights.Add(hashList[i].HashCount); movingTotalWeight += hashList[i].HashCount; } found += hashList[i].Found; sumOfWeightedRates += (rates[i] * weights[i]); sumOfInverseWeightedRates += (weights[i] / rates[i]); productOfWeightedLogRates += (Math.Log((double)rates[i]) * weights[i]); totalWeight += weights[i]; } // Let's avoid dividing by zero if (totalWeight != 0) { Tuple <List <decimal>, uint>[] groupedRates = new Tuple <List <decimal>, uint> [100]; Dictionary <string, decimal> percentiles = new Dictionary <string, decimal>(); Dictionary <decimal, uint> countModeList = new Dictionary <decimal, uint>(hashLogSize); uint maxModeCount = 0; decimal weightCounter = 0; double sumOfPow2OfDifferences = 0, sumOfPow3OfDifferences = 0, sumOfPow4OfDifferences = 0; Array.Sort(rates, weights); // Sorts the rates from low to high, weights get sorted along decimal lowestRate = rates[0]; decimal highestRate = rates[rates.Length - 1]; decimal range = highestRate - lowestRate; if (range > 0) { decimal step = range / 100; decimal offset = Math.Truncate(lowestRate / step); decimal arithmeticAverageHashRate = sumOfWeightedRates / totalWeight; decimal geometricAverageHashRate = (decimal)Math.Exp(productOfWeightedLogRates / totalWeight); decimal harmonicAverageHashRate = totalWeight / sumOfInverseWeightedRates; decimal movingMedian = 0, movingSpreadTop = 0, movingSpreadBottom = 0, movingWeightCounter = 0; decimal[] movingRatesArray = movingRates.ToArray(); uint[] movingWeightsArray = movingWeights.ToArray(); Array.Sort(movingRatesArray, movingWeightsArray); for (int i = 0; i < hashLogSize; i++) { double difference = (double)(rates[i] - harmonicAverageHashRate); sumOfPow2OfDifferences += (difference * difference * weights[i]); sumOfPow3OfDifferences += (difference * difference * difference * weights[i]); sumOfPow4OfDifferences += (difference * difference * difference * difference * weights[i]); if (!countModeList.ContainsKey(rates[i])) { countModeList.Add(rates[i], 1); } else { countModeList[rates[i]] += weights[i]; if (countModeList[rates[i]] > maxModeCount) { maxModeCount = countModeList[rates[i]]; } } int group = (int)(Math.Truncate(rates[i] / step) - offset); if (group >= 100) { group = 99; // Sometimes, thx to rounding, it gets higher } if (groupedRates[group] == null) { List <decimal> ratesList = new List <decimal> { rates[i] }; groupedRates[group] = new Tuple <List <decimal>, uint>(ratesList, weights[i]); } else { List <decimal> ratesList = groupedRates[group].Item1; ratesList.Add(rates[i]); uint weight = groupedRates[group].Item2 + weights[i]; groupedRates[group] = new Tuple <List <decimal>, uint>(ratesList, weight); } weightCounter += (weights[i] / (decimal)totalWeight); if (weightCounter >= 0.00269979606326M && !percentiles.ContainsKey("-3σ")) { percentiles.Add("-3σ", rates[i]); } if (weightCounter >= 0.012419330651552M && !percentiles.ContainsKey("-2.5σ")) { percentiles.Add("-2.5σ", rates[i]); } if (weightCounter >= 0.045500263896358M && !percentiles.ContainsKey("-2σ")) { percentiles.Add("-2σ", rates[i]); } if (weightCounter >= 0.133614402537716M && !percentiles.ContainsKey("-1.5σ")) { percentiles.Add("-1.5σ", rates[i]); } if (weightCounter >= 0.25M && !percentiles.ContainsKey("Q1")) { percentiles.Add("Q1", rates[i]); } if (weightCounter >= 0.317310507862914M && !percentiles.ContainsKey("-1σ")) { percentiles.Add("-1σ", rates[i]); } if (weightCounter >= 0.5M && !percentiles.ContainsKey("0σ")) { percentiles.Add("0σ", rates[i]); } if (weightCounter >= 0.682689492137086M && !percentiles.ContainsKey("+1σ")) { percentiles.Add("+1σ", rates[i]); } if (weightCounter >= 0.75M && !percentiles.ContainsKey("Q3")) { percentiles.Add("Q3", rates[i]); } if (weightCounter >= 0.866385597462284M && !percentiles.ContainsKey("+1.5σ")) { percentiles.Add("+1.5σ", rates[i]); } if (weightCounter >= 0.954499736103642M && !percentiles.ContainsKey("+2σ")) { percentiles.Add("+2σ", rates[i]); } if (weightCounter >= 0.987580669348448M && !percentiles.ContainsKey("+2.5σ")) { percentiles.Add("+2.5σ", rates[i]); } if (weightCounter >= 0.997300203936740M && !percentiles.ContainsKey("+3σ")) { percentiles.Add("+3σ", rates[i]); } if (i < movingRatesArray.Length) { movingWeightCounter += (movingWeightsArray[i] / (decimal)movingTotalWeight); if (movingWeightCounter >= 0.25M && movingSpreadBottom == 0) { movingSpreadBottom = movingRatesArray[i]; } if (movingWeightCounter >= 0.50M && movingMedian == 0) { movingMedian = movingRatesArray[i]; } if (movingWeightCounter >= 0.75M && movingSpreadTop == 0) { movingSpreadTop = movingRatesArray[i]; } } } List <decimal> modes = new List <decimal>(); foreach (decimal rate in countModeList.Keys) { if (countModeList[rate] >= maxModeCount) { modes.Add(rate); } } decimal interquartileRange = percentiles["Q3"] - percentiles["Q1"]; decimal[] outerWhiskers = new decimal[2]; outerWhiskers[0] = percentiles["Q1"] - 1.5M * interquartileRange <= 0 ? 0 : percentiles["Q1"] - 1.5M * interquartileRange; outerWhiskers[1] = percentiles["Q3"] + 1.5M * interquartileRange >= highestRate ? highestRate : percentiles["Q3"] + 1.5M * interquartileRange; HashSet <decimal> outliers = new HashSet <decimal>(); decimal[] madMedian = new decimal[hashLogSize]; decimal[] madAverage = new decimal[hashLogSize]; decimal sumOfWeightedMedian = 0, sumOfWeightedAverage = 0; // Come on, let's loop again! https://www.youtube.com/watch?v=BqvUkmnDVkM for (int index = 0; index < hashLogSize; index++) { if (rates[index] < outerWhiskers[0] || rates[index] > outerWhiskers[1]) { outliers.Add(rates[index]); } madMedian[index] = Math.Abs((rates[index] - percentiles["0σ"])); madAverage[index] = Math.Abs((rates[index] - harmonicAverageHashRate)); sumOfWeightedMedian += (madMedian[index] * weights[index]); sumOfWeightedAverage += (madAverage[index] * weights[index]); } decimal madMedianMedian = GetMedian(madMedian); decimal madAverageMedian = GetMedian(madAverage); decimal madMedianAverage = sumOfWeightedMedian / totalWeight; decimal madAverageAverage = sumOfWeightedAverage / totalWeight; decimal madMedianMax = madMedian[hashLogSize - 1]; decimal madAverageMax = madAverage[hashLogSize - 1]; decimal[][] absoluteDeviations = new decimal[2][]; absoluteDeviations[0] = new[] { madMedianMedian, madMedianAverage, madMedianMax }; absoluteDeviations[1] = new[] { madAverageMedian, madAverageAverage, madAverageMax }; decimal variance = (decimal)(sumOfPow2OfDifferences / totalWeight); decimal standardDeviation = (decimal)Math.Sqrt((double)variance); decimal stdMadFactor = madMedianMedian != 0 ? standardDeviation / madMedianMedian : 0; decimal dispersionCoefficient = variance / percentiles["0σ"]; decimal variationCoefficient = (standardDeviation / harmonicAverageHashRate) * 100; decimal interquartileSum = percentiles["Q3"] + percentiles["Q1"]; decimal rangeSum = highestRate + lowestRate; decimal midRange = rangeSum / 2; decimal midHinge = interquartileSum / 2; decimal triMean = (percentiles["0σ"] + midHinge) / 2; decimal quartileCoefficient = (interquartileRange / interquartileSum) * 100; decimal rangeCoefficient = (range / rangeSum) * 100; decimal rootMeanSquare = (decimal)Math.Sqrt((double) ((harmonicAverageHashRate * harmonicAverageHashRate) + (standardDeviation * standardDeviation))); decimal skewness = (decimal)(sumOfPow3OfDifferences / (Math.Pow(sumOfPow2OfDifferences, 1.5d))); decimal kurtosis = (decimal)(sumOfPow4OfDifferences / (sumOfPow2OfDifferences * sumOfPow2OfDifferences)) - 3; decimal nonParametricSkew = (harmonicAverageHashRate - percentiles["0σ"]) / standardDeviation; Benchmark.GpuStat stat = new Benchmark.GpuStat { TimeStamp = UnixTimeStamp(), TotalHashCount = totalWeight, TotalHashEntries = hashLogSize, ArithmeticAverageHashRate = arithmeticAverageHashRate, GeometricAverageHashrate = geometricAverageHashRate, HarmonicAverageHashRate = harmonicAverageHashRate, RootMeanSquare = rootMeanSquare, MovingSpreadBottom = movingSpreadBottom, MovingMedian = movingMedian, MovingSpreadTop = movingSpreadTop, Percentiles = percentiles, OuterWhiskers = outerWhiskers, InterquartileRange = interquartileRange, Range = range, LowestHashRate = lowestRate, HighestHashRate = highestRate, MidRange = midRange, MidHinge = midHinge, TriMean = triMean, Variance = variance, StandardDeviation = standardDeviation, AbsoluteDeviations = absoluteDeviations, StdMadFactor = stdMadFactor, DispersionCoefficient = dispersionCoefficient, VariationCoefficient = variationCoefficient, QuartileCoefficient = quartileCoefficient, RangeCoefficient = rangeCoefficient, Skewness = skewness, Kurtosis = kurtosis, NonParametricSkew = nonParametricSkew, Founds = found }; if (CurrentBenchmark.Statistics == null) { CurrentBenchmark.Statistics = new List <Benchmark.GpuStat>(); } CurrentBenchmark.Statistics.Add(stat); CurrentBenchmark.OrderedHashLogs = new Benchmark.OrderedHashLog() { GroupedRates = groupedRates, Outliers = outliers, ModeHashRates = modes, ModeQuantity = maxModeCount, }; } } }