public QuickPulseDataSample(QuickPulseDataAccumulator accumulator, IDictionary <string, Tuple <PerformanceCounterData, double> > perfData) { if (accumulator == null) { throw new ArgumentNullException(nameof(accumulator)); } if (perfData == null) { throw new ArgumentNullException(nameof(perfData)); } if (accumulator.StartTimestamp == null) { throw new ArgumentNullException(nameof(accumulator.StartTimestamp)); } if (accumulator.EndTimestamp == null) { throw new ArgumentNullException(nameof(accumulator.EndTimestamp)); } this.StartTimestamp = accumulator.StartTimestamp.Value; this.EndTimestamp = accumulator.EndTimestamp.Value; if ((this.EndTimestamp - this.StartTimestamp) < TimeSpan.Zero) { throw new InvalidOperationException("StartTimestamp must be less than EndTimestamp."); } TimeSpan sampleDuration = this.EndTimestamp - this.StartTimestamp; Tuple <long, long> requestCountAndDuration = QuickPulseDataAccumulator.DecodeCountAndDuration(accumulator.AIRequestCountAndDurationInTicks); long requestCount = requestCountAndDuration.Item1; long requestDurationInTicks = requestCountAndDuration.Item2; this.AIRequests = (int)requestCount; this.AIRequestsPerSecond = sampleDuration.TotalSeconds > 0 ? requestCount / sampleDuration.TotalSeconds : 0; this.AIRequestDurationAveInMs = requestCount > 0 ? (double)requestDurationInTicks / TimeSpan.TicksPerMillisecond / requestCount : 0; this.AIRequestsFailedPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIRequestFailureCount / sampleDuration.TotalSeconds : 0; this.AIRequestsSucceededPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIRequestSuccessCount / sampleDuration.TotalSeconds : 0; Tuple <long, long> dependencyCountAndDuration = QuickPulseDataAccumulator.DecodeCountAndDuration(accumulator.AIDependencyCallCountAndDurationInTicks); long dependencyCount = dependencyCountAndDuration.Item1; long dependencyDurationInTicks = dependencyCountAndDuration.Item2; this.AIDependencyCalls = (int)dependencyCount; this.AIDependencyCallsPerSecond = sampleDuration.TotalSeconds > 0 ? dependencyCount / sampleDuration.TotalSeconds : 0; this.AIDependencyCallDurationAveInMs = dependencyCount > 0 ? (double)dependencyDurationInTicks / TimeSpan.TicksPerMillisecond / dependencyCount : 0; this.AIDependencyCallsFailedPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIDependencyCallFailureCount / sampleDuration.TotalSeconds : 0; this.AIDependencyCallsSucceededPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIDependencyCallSuccessCount / sampleDuration.TotalSeconds : 0; this.AIExceptionsPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIExceptionCount / sampleDuration.TotalSeconds : 0; this.PerfCountersLookup = perfData.ToDictionary( p => (QuickPulseDefaults.CounterOriginalStringMapping.ContainsKey(p.Value.Item1.OriginalString) ? QuickPulseDefaults.CounterOriginalStringMapping[p.Value.Item1.OriginalString] : p.Value.Item1.OriginalString), p => p.Value.Item2); this.TelemetryDocuments = accumulator.TelemetryDocuments.ToArray(); }
public QuickPulseDataAccumulatorManager(CollectionConfiguration collectionConfiguration) { if (collectionConfiguration == null) { throw new ArgumentNullException(nameof(collectionConfiguration)); } this.currentDataAccumulator = new QuickPulseDataAccumulator(collectionConfiguration); }
public void QuickPulseDataSampleCalculatesAIDependencyCallsFailedPerSecondCorrectly() { // ARRANGE var accumulator = new QuickPulseDataAccumulator { StartTimestamp = DateTimeOffset.UtcNow, EndTimestamp = DateTimeOffset.UtcNow.AddSeconds(2), AIDependencyCallFailureCount = 10 }; // ACT var dataSample = new QuickPulseDataSample(accumulator, this.dummyDictionary); // ASSERT Assert.AreEqual(10.0 / 2, dataSample.AIDependencyCallsFailedPerSecond); }
public void QuickPulseDataSampleCalculatesAIDependencyCallDurationAveWhenDependencyCallCountIsZeroCorrectly() { // ARRANGE var accumulator = new QuickPulseDataAccumulator { StartTimestamp = DateTimeOffset.UtcNow, EndTimestamp = DateTimeOffset.UtcNow.AddSeconds(2), AIDependencyCallCountAndDurationInTicks = QuickPulseDataAccumulator.EncodeCountAndDuration(0, TimeSpan.FromSeconds(5).Ticks) }; // ACT var dataSample = new QuickPulseDataSample(accumulator, this.dummyDictionary); // ASSERT Assert.AreEqual(0.0, dataSample.AIDependencyCallDurationAveInMs); }
public void QuickPulseDataAccumulatorCollectsTelemetryItemsInThreadSafeManner() { // ARRANGE var accumulator = new QuickPulseDataAccumulator(); // ACT var iterationCount = 1000; var concurrency = 12; Action addItemTask = () => Enumerable.Range(0, iterationCount) .ToList() .ForEach( i => accumulator.TelemetryDocuments.Push(new RequestTelemetryDocument() { Name = i.ToString(CultureInfo.InvariantCulture) })); var tasks = new List<Action>(); for (int i = 0; i < concurrency; i++) { tasks.Add(addItemTask); } Parallel.Invoke(new ParallelOptions() { MaxDegreeOfParallelism = concurrency }, tasks.ToArray()); // ASSERT var dict = new Dictionary<int, int>(); foreach (var item in accumulator.TelemetryDocuments) { int requestNumber = int.Parse(((RequestTelemetryDocument)item).Name, CultureInfo.InvariantCulture); if (dict.ContainsKey(requestNumber)) { dict[requestNumber]++; } else { dict[requestNumber] = 1; } } Assert.AreEqual(iterationCount, dict.Count); Assert.IsTrue(dict.All(pair => pair.Value == concurrency)); }
public QuickPulseDataAccumulator CompleteCurrentDataAccumulator() { /* Here we need to - promote currentDataAccumulator to completedDataAccumulator - reset (zero out) the new currentDataAccumulator Certain telemetry items will be "sprayed" between two neighboring accumulators due to the fact that the snap might occure in the middle of a reader executing its Interlocked's. */ this.completedDataAccumulator = Interlocked.Exchange(ref this.currentDataAccumulator, new QuickPulseDataAccumulator()); var timestamp = DateTimeOffset.UtcNow; this.completedDataAccumulator.EndTimestamp = timestamp; this.currentDataAccumulator.StartTimestamp = timestamp; return this.completedDataAccumulator; }
public QuickPulseDataAccumulator CompleteCurrentDataAccumulator() { /* * Here we need to * - promote currentDataAccumulator to completedDataAccumulator * - reset (zero out) the new currentDataAccumulator * * Certain telemetry items will be "sprayed" between two neighboring accumulators due to the fact that the snap might occure in the middle of a reader executing its Interlocked's. */ this.completedDataAccumulator = Interlocked.Exchange(ref this.currentDataAccumulator, new QuickPulseDataAccumulator()); var timestamp = DateTimeOffset.UtcNow; this.completedDataAccumulator.EndTimestamp = timestamp; this.currentDataAccumulator.StartTimestamp = timestamp; return(this.completedDataAccumulator); }
public QuickPulseDataSample(QuickPulseDataAccumulator accumulator, IDictionary <string, Tuple <PerformanceCounterData, double> > perfData, IEnumerable <Tuple <string, int> > topCpuData, bool topCpuDataAccessDenied) { // NOTE: it is crucial not to keep any heap references on input parameters, new objects with separate roots must be created! // CollectionConfiguration is an exception to this rule as it may be still processed, and the sender will check the reference count before sending it out if (accumulator == null) { throw new ArgumentNullException(nameof(accumulator)); } if (perfData == null) { throw new ArgumentNullException(nameof(perfData)); } if (accumulator.StartTimestamp == null) { throw new ArgumentNullException(nameof(accumulator.StartTimestamp)); } if (accumulator.EndTimestamp == null) { throw new ArgumentNullException(nameof(accumulator.EndTimestamp)); } this.StartTimestamp = accumulator.StartTimestamp.Value; this.EndTimestamp = accumulator.EndTimestamp.Value; if ((this.EndTimestamp - this.StartTimestamp) < TimeSpan.Zero) { throw new InvalidOperationException("StartTimestamp must be less than EndTimestamp."); } TimeSpan sampleDuration = this.EndTimestamp - this.StartTimestamp; Tuple <long, long> requestCountAndDuration = QuickPulseDataAccumulator.DecodeCountAndDuration(accumulator.AIRequestCountAndDurationInTicks); long requestCount = requestCountAndDuration.Item1; long requestDurationInTicks = requestCountAndDuration.Item2; this.AIRequests = (int)requestCount; this.AIRequestsPerSecond = sampleDuration.TotalSeconds > 0 ? requestCount / sampleDuration.TotalSeconds : 0; this.AIRequestDurationAveInMs = requestCount > 0 ? (double)requestDurationInTicks / TimeSpan.TicksPerMillisecond / requestCount : 0; this.AIRequestsFailedPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIRequestFailureCount / sampleDuration.TotalSeconds : 0; this.AIRequestsSucceededPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIRequestSuccessCount / sampleDuration.TotalSeconds : 0; Tuple <long, long> dependencyCountAndDuration = QuickPulseDataAccumulator.DecodeCountAndDuration(accumulator.AIDependencyCallCountAndDurationInTicks); long dependencyCount = dependencyCountAndDuration.Item1; long dependencyDurationInTicks = dependencyCountAndDuration.Item2; this.AIDependencyCalls = (int)dependencyCount; this.AIDependencyCallsPerSecond = sampleDuration.TotalSeconds > 0 ? dependencyCount / sampleDuration.TotalSeconds : 0; this.AIDependencyCallDurationAveInMs = dependencyCount > 0 ? (double)dependencyDurationInTicks / TimeSpan.TicksPerMillisecond / dependencyCount : 0; this.AIDependencyCallsFailedPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIDependencyCallFailureCount / sampleDuration.TotalSeconds : 0; this.AIDependencyCallsSucceededPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIDependencyCallSuccessCount / sampleDuration.TotalSeconds : 0; this.AIExceptionsPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIExceptionCount / sampleDuration.TotalSeconds : 0; this.GlobalDocumentQuotaReached = accumulator.GlobalDocumentQuotaReached; try { this.PerfCountersLookup = perfData.ToDictionary( p => (QuickPulseDefaults.DefaultCounterOriginalStringMapping.ContainsKey(p.Value.Item1.ReportAs) ? QuickPulseDefaults.DefaultCounterOriginalStringMapping[p.Value.Item1.ReportAs] : p.Value.Item1.ReportAs), p => p.Value.Item2); } catch (Exception e) { // something went wrong with counter names, log an error QuickPulseEventSource.Log.UnknownErrorEvent(e.ToString()); } this.TopCpuData = topCpuData.ToArray(); this.TelemetryDocuments = accumulator.TelemetryDocuments.ToArray(); this.TopCpuDataAccessDenied = topCpuDataAccessDenied; this.CollectionConfigurationAccumulator = accumulator.CollectionConfigurationAccumulator; }
public QuickPulseDataSample(QuickPulseDataAccumulator accumulator, IDictionary<string, Tuple<PerformanceCounterData, float>> perfData) { if (accumulator == null) { throw new ArgumentNullException(nameof(accumulator)); } if (perfData == null) { throw new ArgumentNullException(nameof(perfData)); } if (accumulator.StartTimestamp == null) { throw new ArgumentNullException(nameof(accumulator.StartTimestamp)); } if (accumulator.EndTimestamp == null) { throw new ArgumentNullException(nameof(accumulator.EndTimestamp)); } this.StartTimestamp = accumulator.StartTimestamp.Value; this.EndTimestamp = accumulator.EndTimestamp.Value; if ((this.EndTimestamp - this.StartTimestamp) < TimeSpan.Zero) { throw new InvalidOperationException("StartTimestamp must be lesser than EndTimestamp."); } TimeSpan sampleDuration = this.EndTimestamp - this.StartTimestamp; Tuple<long, long> requestCountAndDuration = QuickPulseDataAccumulator.DecodeCountAndDuration(accumulator.AIRequestCountAndDurationInTicks); long requestCount = requestCountAndDuration.Item1; long requestDurationInTicks = requestCountAndDuration.Item2; this.AIRequests = (int)requestCount; this.AIRequestsPerSecond = sampleDuration.TotalSeconds > 0 ? requestCount / sampleDuration.TotalSeconds : 0; this.AIRequestDurationAveInMs = requestCount > 0 ? (double)requestDurationInTicks / TimeSpan.TicksPerMillisecond / requestCount : 0; this.AIRequestsFailedPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIRequestFailureCount / sampleDuration.TotalSeconds : 0; this.AIRequestsSucceededPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIRequestSuccessCount / sampleDuration.TotalSeconds : 0; Tuple<long, long> dependencyCountAndDuration = QuickPulseDataAccumulator.DecodeCountAndDuration(accumulator.AIDependencyCallCountAndDurationInTicks); long dependencyCount = dependencyCountAndDuration.Item1; long dependencyDurationInTicks = dependencyCountAndDuration.Item2; this.AIDependencyCalls = (int)dependencyCount; this.AIDependencyCallsPerSecond = sampleDuration.TotalSeconds > 0 ? dependencyCount / sampleDuration.TotalSeconds : 0; this.AIDependencyCallDurationAveInMs = dependencyCount > 0 ? (double)dependencyDurationInTicks / TimeSpan.TicksPerMillisecond / dependencyCount : 0; this.AIDependencyCallsFailedPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIDependencyCallFailureCount / sampleDuration.TotalSeconds : 0; this.AIDependencyCallsSucceededPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIDependencyCallSuccessCount / sampleDuration.TotalSeconds : 0; this.AIExceptionsPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIExceptionCount / sampleDuration.TotalSeconds : 0; // avoiding reflection (Enum.GetNames()) to speed things up Tuple<PerformanceCounterData, float> value; if (perfData.TryGetValue(QuickPulsePerfCounters.PerfIisQueueSize.ToString(), out value)) { this.PerfIisQueueSize = value.Item2; } if (perfData.TryGetValue(QuickPulsePerfCounters.PerfCpuUtilization.ToString(), out value)) { this.PerfCpuUtilization = value.Item2; } if (perfData.TryGetValue(QuickPulsePerfCounters.PerfMemoryInBytes.ToString(), out value)) { this.PerfMemoryInBytes = value.Item2; } this.PerfCountersLookup = perfData.ToDictionary(p => p.Value.Item1.OriginalString, p => p.Value.Item2); }
public void QuickPulseDataSampleTimestampsItselfCorrectly() { // ARRANGE var timestampStart = DateTimeOffset.UtcNow; var timestampEnd = DateTimeOffset.UtcNow.AddSeconds(3); var accumulator = new QuickPulseDataAccumulator { StartTimestamp = timestampStart, EndTimestamp = timestampEnd }; // ACT var dataSample = new QuickPulseDataSample(accumulator, this.dummyDictionary); // ASSERT Assert.AreEqual(timestampStart, dataSample.StartTimestamp); Assert.AreEqual(timestampEnd, dataSample.EndTimestamp); }
public void QuickPulseDataSampleHandlesAbsentCounterInPerfData() { // ARRANGE var accumulator = new QuickPulseDataAccumulator { StartTimestamp = DateTimeOffset.UtcNow, EndTimestamp = DateTimeOffset.UtcNow.AddSeconds(2) }; // ACT var dataSample = new QuickPulseDataSample(accumulator, this.dummyDictionary); // ASSERT Assert.IsFalse(dataSample.PerfCountersLookup.Any()); }
public void QuickPulseDataSampleCalculatesAIRpsCorrectly() { // ARRANGE var accumulator = new QuickPulseDataAccumulator { StartTimestamp = DateTimeOffset.UtcNow, EndTimestamp = DateTimeOffset.UtcNow.AddSeconds(2), AIRequestCountAndDurationInTicks = QuickPulseDataAccumulator.EncodeCountAndDuration(10, 0) }; // ACT var dataSample = new QuickPulseDataSample(accumulator, this.dummyDictionary); // ASSERT Assert.AreEqual(10.0 / 2, dataSample.AIRequestsPerSecond); }
public void QuickPulseDataSampleCalculatesAIRequestDurationAveCorrectly() { // ARRANGE var accumulator = new QuickPulseDataAccumulator { StartTimestamp = DateTimeOffset.UtcNow, EndTimestamp = DateTimeOffset.UtcNow.AddSeconds(2), AIRequestCountAndDurationInTicks = QuickPulseDataAccumulator.EncodeCountAndDuration(10, TimeSpan.FromSeconds(5).Ticks) }; // ACT var dataSample = new QuickPulseDataSample(accumulator, this.dummyDictionary); // ASSERT Assert.AreEqual(TimeSpan.FromSeconds(5).TotalMilliseconds / 10.0, dataSample.AIRequestDurationAveInMs); }
public void QuickPulseDataSampleCalculatesAIExceptionsPerSecondCorrectly() { // ARRANGE var accumulator = new QuickPulseDataAccumulator { StartTimestamp = DateTimeOffset.UtcNow, EndTimestamp = DateTimeOffset.UtcNow.AddSeconds(2), AIExceptionCount = 3 }; // ACT var dataSample = new QuickPulseDataSample(accumulator, this.dummyDictionary); // ASSERT Assert.AreEqual(3.0 / 2, dataSample.AIExceptionsPerSecond); }
private QuickPulseDataSample CreateDataSample( QuickPulseDataAccumulator accumulator, IEnumerable<Tuple<PerformanceCounterData, double>> perfData) { return new QuickPulseDataSample(accumulator, perfData.ToDictionary(tuple => tuple.Item1.ReportAs, tuple => tuple)); }
public QuickPulseDataSample(QuickPulseDataAccumulator accumulator, IDictionary <string, Tuple <PerformanceCounterData, float> > perfData) { if (accumulator == null) { throw new ArgumentNullException(nameof(accumulator)); } if (perfData == null) { throw new ArgumentNullException(nameof(perfData)); } if (accumulator.StartTimestamp == null) { throw new ArgumentNullException(nameof(accumulator.StartTimestamp)); } if (accumulator.EndTimestamp == null) { throw new ArgumentNullException(nameof(accumulator.EndTimestamp)); } this.StartTimestamp = accumulator.StartTimestamp.Value; this.EndTimestamp = accumulator.EndTimestamp.Value; if ((this.EndTimestamp - this.StartTimestamp) < TimeSpan.Zero) { throw new InvalidOperationException("StartTimestamp must be lesser than EndTimestamp."); } TimeSpan sampleDuration = this.EndTimestamp - this.StartTimestamp; Tuple <long, long> requestCountAndDuration = QuickPulseDataAccumulator.DecodeCountAndDuration(accumulator.AIRequestCountAndDurationInTicks); long requestCount = requestCountAndDuration.Item1; long requestDurationInTicks = requestCountAndDuration.Item2; this.AIRequests = (int)requestCount; this.AIRequestsPerSecond = sampleDuration.TotalSeconds > 0 ? requestCount / sampleDuration.TotalSeconds : 0; this.AIRequestDurationAveInMs = requestCount > 0 ? (double)requestDurationInTicks / TimeSpan.TicksPerMillisecond / requestCount : 0; this.AIRequestsFailedPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIRequestFailureCount / sampleDuration.TotalSeconds : 0; this.AIRequestsSucceededPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIRequestSuccessCount / sampleDuration.TotalSeconds : 0; Tuple <long, long> dependencyCountAndDuration = QuickPulseDataAccumulator.DecodeCountAndDuration(accumulator.AIDependencyCallCountAndDurationInTicks); long dependencyCount = dependencyCountAndDuration.Item1; long dependencyDurationInTicks = dependencyCountAndDuration.Item2; this.AIDependencyCalls = (int)dependencyCount; this.AIDependencyCallsPerSecond = sampleDuration.TotalSeconds > 0 ? dependencyCount / sampleDuration.TotalSeconds : 0; this.AIDependencyCallDurationAveInMs = dependencyCount > 0 ? (double)dependencyDurationInTicks / TimeSpan.TicksPerMillisecond / dependencyCount : 0; this.AIDependencyCallsFailedPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIDependencyCallFailureCount / sampleDuration.TotalSeconds : 0; this.AIDependencyCallsSucceededPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIDependencyCallSuccessCount / sampleDuration.TotalSeconds : 0; this.AIExceptionsPerSecond = sampleDuration.TotalSeconds > 0 ? accumulator.AIExceptionCount / sampleDuration.TotalSeconds : 0; // avoiding reflection (Enum.GetNames()) to speed things up Tuple <PerformanceCounterData, float> value; if (perfData.TryGetValue(QuickPulsePerfCounters.PerfIisQueueSize.ToString(), out value)) { this.PerfIisQueueSize = value.Item2; } if (perfData.TryGetValue(QuickPulsePerfCounters.PerfCpuUtilization.ToString(), out value)) { this.PerfCpuUtilization = value.Item2; } if (perfData.TryGetValue(QuickPulsePerfCounters.PerfMemoryInBytes.ToString(), out value)) { this.PerfMemoryInBytes = value.Item2; } this.PerfCountersLookup = perfData.ToDictionary(p => p.Value.Item1.OriginalString, p => p.Value.Item2); }