/// <summary> /// Update the weighted moving average for the available results. /// </summary> /// <remarks> /// Results are stored in <see cref="WeightedResult"/> if there are results to compute. /// </remarks> public void Update() { if (m_NumResults == 0) { return; // Nothing to do } // The specified weight is a percentage [0.0f..1.0f], so we'll // use 100.0 as our "arbitrary" weighing value. Do not use a // weight if there is only one result. float currentResultWeight = ((m_NumResults == 1) ? 1.0f : m_Weight) * 100.0f; // Give the current result the appropriate weight. We'll cast back to integer at the end. QosStatsResult currentResult = m_Results[m_CurrentResult]; float weightedLatencyMs = currentResult.LatencyMs * (currentResultWeight / 100.0f); float weightedPacketLoss = currentResult.PacketLoss * (currentResultWeight / 100.0f); // Combine the remaining results and apply the remainder of the weight equally. if (m_NumResults > 1) { float remainingWeightPerResult = (100.0f - currentResultWeight) / (m_NumResults - 1); uint nextValidIndex = NextValidIndex(m_CurrentResult); // find the index of the next set of valid results. for (int i = 0; i < m_NumResults - 1; ++i) // m_NumResults-1 so we don't include the currentResult again { QosStatsResult result = m_Results[(nextValidIndex + i) % m_MaxResults]; weightedLatencyMs += result.LatencyMs * (remainingWeightPerResult / 100.0f); weightedPacketLoss += result.PacketLoss * (remainingWeightPerResult / 100.0f); } } WeightedResult = new QosStatsResult( Mathf.RoundToInt(weightedLatencyMs), Mathf.Min(weightedPacketLoss, 1.0f)); // Make sure precision issues don't yield >100% packet loss }
public WeightedMovingAverage(uint numResults, float weightOfCurrentResult) { m_MaxResults = numResults; m_Weight = weightOfCurrentResult; // Initial results are flagged as invalid until we have some results. m_Results = new QosStatsResult[m_MaxResults]; for (int i = 0; i < m_MaxResults; ++i) { m_Results[i] = new QosStatsResult(-1, -1f); } WeightedResult = new QosStatsResult(-1, -1f); }
public void AddResult(QosStatsResult result, bool updateAfterAdd = false) { if (m_NumResults < m_MaxResults) { ++m_NumResults; } m_CurrentResult = (m_CurrentResult + 1) % m_NumResults; m_Results[m_CurrentResult] = result; if (updateAfterAdd) { Update(); } }
/// <summary> /// Get an array of all the results currently being tracked for the given key. /// </summary> /// <param name="ipAndPort">IP:Port string to get results for</param> /// <param name="results">Array of results (unweighted) used to compute the weighted average.</param> /// <returns>true if record(s) were found, false if key does not exist or no valid records found</returns> /// <remarks>There is no way to determine which results correspond to the most recently added results.</remarks> public bool TryGetAllResults(string ipAndPort, out QosStatsResult[] results) { m_ResultsLock.EnterReadLock(); try { if (!m_Results.TryGetValue(ipAndPort, out WeightedMovingAverage wma)) { results = new QosStatsResult[0]; return(false); } wma.AllResults(out results); return(results.Length > 0); } finally { m_ResultsLock.ExitReadLock(); } }
/// <summary> /// Get the weighted rolling average for the given key. /// </summary> /// <param name="ipAndPort">IP:Port string to get results for</param> /// <param name="result">The weighted rolling average for the given ipAndPort</param> /// <returns>true if the record was found, false otherwise</returns> public bool TryGetWeightedAverage(string ipAndPort, out QosStatsResult result) { m_ResultsLock.EnterReadLock(); try { if (!m_Results.TryGetValue(ipAndPort, out WeightedMovingAverage wma)) { result = new QosStatsResult(-1, -1f); // Make result invalid return(false); } wma.Update(); result = wma.WeightedResult.IsValid() ? wma.WeightedResult : new QosStatsResult(-1, -1f); return(result.IsValid()); } finally { m_ResultsLock.ExitReadLock(); } }
public void AllResults(out QosStatsResult[] results) { results = new QosStatsResult[m_Results.Length]; m_Results.CopyTo(results, 0); }