/// <summary> /// Aggregates the current statistics with another statistics counter. /// </summary> /// <param name="other">The other counter to aggregate with the current instance.</param> /// <returns>Current instance, summarized with the given statistics.</returns> public Statistics SummarizeWith(Statistics other) { if (other != null) { this._StartTick = Math.Min(this._StartTick, other._StartTick); this._EndTick = Math.Max(this._EndTick, other._EndTick); this._RequestCount += other._RequestCount; this._ResponseCount += other._ResponseCount; this._FailureCount += other._FailureCount; this._TimeoutCount += other._TimeoutCount; this._AbortCount += other._AbortCount; this._MinimumLatency = Math.Min(this._MinimumLatency, other._MinimumLatency); this._MaximumLatency = Math.Max(this._MaximumLatency, other._MaximumLatency); this._TotalExecutionDuration += other._TotalExecutionDuration; for (byte i = 0; i < 9; i++) this._LatencyBucketCount[i] += other._LatencyBucketCount[i]; this._BytesSent += other._BytesSent; this._BytesReceived += other._BytesReceived; } return this; }
/// <summary> /// Creates a frozen snapshot of the statistics counter - this is the state under which counters will be /// provided by the connection. /// </summary> /// <returns>Deep copy of the source.</returns> internal Statistics Snapshot() { // The future copy Statistics copy = null; // Wait for writers to complete while (this.WriteLock > 0) ; // Wait for other snapshots to complete while (this.SnapshotLock > 0) ; try { // Increment the snapshot lock so writers know to wait Interlocked.Increment(ref this.SnapshotLock); // Make the copy - there are no writers on the object right now, so the snapshot should be consistent // (don't really need interlocked access either as it is, since we're in snapshot lock, but it doesn't // hurt to stay safe...) copy = new Statistics(); copy._StartTick = Interlocked.Read(ref this._StartTick); copy._EndTick = copy._EndTick == 0 ? Stopwatch.GetTimestamp() : Interlocked.Read(ref this._EndTick); copy._RequestCount = Interlocked.Read(ref this._RequestCount); copy._ResponseCount = Interlocked.Read(ref this._ResponseCount); copy._FailureCount = Interlocked.Read(ref this._FailureCount); copy._TimeoutCount = Interlocked.Read(ref this._TimeoutCount); copy._AbortCount = Interlocked.Read(ref this._AbortCount); copy._MinimumLatency = Interlocked.Read(ref this._MinimumLatency); copy._MaximumLatency = Interlocked.Read(ref this._MaximumLatency); copy._TotalExecutionDuration = Interlocked.Read(ref this._TotalExecutionDuration); for (byte i = 0; i < 9; i++) copy._LatencyBucketCount[i] = Interlocked.Read(ref this._LatencyBucketCount[i]); copy._BytesSent = Interlocked.Read(ref this._BytesSent); copy._BytesReceived = Interlocked.Read(ref this._BytesReceived); // If the counter was never updated, those will have startup values - fix that. if (copy._MinimumLatency == long.MaxValue) copy._MinimumLatency = 0; if (copy._MaximumLatency == long.MinValue) copy._MaximumLatency = 0; } finally { // Decrement the snapshot lock. Interlocked.Decrement(ref this.SnapshotLock); } return copy; }
/// <summary> /// Aggregate multiple counters with the current instance. /// </summary> /// <param name="others">List of counters to aggregate to the current instance.</param> /// <returns>Current instance, summarized with the given statistics.</returns> public Statistics SummarizeWith(IEnumerable <Statistics> others) { return(this.SummarizeWith(Statistics.Summarize(others))); }