/// <summary> /// Pops this from the tracker stack and computes inclusive and exclusive times /// </summary> public void Dispose() { _inclusiveTime.Stop(); _exclusiveTime.Stop(); if (_evaluationProfiler._evaluationStack.Pop() != this) { throw new InvalidOperationException("Evaluation frame disposed out of order"); } if (_evaluationProfiler._evaluationStack.Count > 0) { _evaluationProfiler._evaluationStack.Peek()._exclusiveTime.Start(); } // Add elapsed times to evaluation counter dictionaries if (!_evaluationProfiler.ProfiledResult.Value.ProfiledLocations.TryGetValue(Location, out var previousTimeSpent)) { previousTimeSpent = new ProfiledLocation(TimeSpan.Zero, TimeSpan.Zero, 0); } var updatedTimeSpent = new ProfiledLocation( previousTimeSpent.InclusiveTime + _inclusiveTime.Elapsed, previousTimeSpent.ExclusiveTime + _exclusiveTime.Elapsed, 0 ); _evaluationProfiler._timeSpent[Location] = updatedTimeSpent; }
private static ProfiledLocation AggregateProfiledLocation(ProfiledLocation location, ProfiledLocation otherLocation) { return(new ProfiledLocation( location.InclusiveTime + otherLocation.InclusiveTime, location.ExclusiveTime + otherLocation.ExclusiveTime, location.NumberOfHits + 1 )); }
/// <summary> /// Returns the result of aggregating all profiled projects across a build /// </summary> /// <remarks> /// Not thread safe. After this method is called, the assumption is that no new ProjectEvaluationFinishedEventArgs will arrive. /// In the regular code path, this method is called only once per build. But some test cases may call it multiple times to validate /// the aggregated data /// </remarks> internal ProfilerResult GetAggregatedResult() { if (_aggregatedLocations != null) { return(new ProfilerResult(_aggregatedLocations)); } _aggregatedLocations = new Dictionary <EvaluationLocation, ProfiledLocation>(); while (!_profiledResults.IsEmpty) { ProfilerResult profiledResult; var result = _profiledResults.TryDequeue(out profiledResult); Debug.Assert(result, "Expected a non empty queue, this method is not supposed to be called in a multithreaded way"); foreach (var pair in profiledResult.ProfiledLocations) { // Add elapsed times to evaluation counter dictionaries ProfiledLocation previousTimeSpent; if (!_aggregatedLocations.TryGetValue(pair.Key, out previousTimeSpent)) { previousTimeSpent = new ProfiledLocation(TimeSpan.Zero, TimeSpan.Zero, 0); } var updatedTimeSpent = AggregateProfiledLocation(previousTimeSpent, pair.Value); _aggregatedLocations[pair.Key] = updatedTimeSpent; } } // Add one single item representing the total aggregated evaluation time for globs var aggregatedGlobs = _aggregatedLocations.Keys .Where(key => key.Kind == EvaluationLocationKind.Glob) .Aggregate(new ProfiledLocation(), (profiledLocation, evaluationLocation) => AggregateProfiledLocation(profiledLocation, _aggregatedLocations[evaluationLocation])); _aggregatedLocations[EvaluationLocation.CreateLocationForAggregatedGlob()] = aggregatedGlobs; return(new ProfilerResult(_aggregatedLocations)); }
private void Write(ProfiledLocation e) { Write(e.NumberOfHits); Write(e.ExclusiveTime); Write(e.InclusiveTime); }
/// <inheritdoc/> internal override void AppendLocation(StringBuilder stringBuilder, TimeSpan totalTime, EvaluationLocation evaluationLocation, ProfiledLocation profiledLocation) { AppendDefaultLocationWithSeparator(stringBuilder, totalTime, evaluationLocation, profiledLocation, Separator); }
/// <summary> /// Appends a default representation of an evaluation location with a given separator /// </summary> protected void AppendDefaultLocationWithSeparator(StringBuilder stringBuilder, TimeSpan totalTime, EvaluationLocation evaluationLocation, ProfiledLocation profiledLocation, string separator) { stringBuilder.AppendLine(string.Join(separator, evaluationLocation.Id, evaluationLocation.ParentId?.ToString() ?? string.Empty, evaluationLocation.EvaluationPassDescription, evaluationLocation.File == null ? string.Empty : System.IO.Path.GetFileName(evaluationLocation.File), evaluationLocation.Line?.ToString() ?? string.Empty, NormalizeExpression(evaluationLocation.ElementDescription, evaluationLocation.Kind) ?? string.Empty, GetMilliseconds(profiledLocation.InclusiveTime), GetPercentage(totalTime, profiledLocation.InclusiveTime) + "%", GetMilliseconds(profiledLocation.ExclusiveTime), GetPercentage(totalTime, profiledLocation.ExclusiveTime) + "%", profiledLocation.NumberOfHits, evaluationLocation.Kind + separator)); }
/// <summary> /// Appends a pretty printed location with its associated profiled data /// </summary> internal abstract void AppendLocation(StringBuilder stringBuilder, TimeSpan totalTime, EvaluationLocation evaluationLocation, ProfiledLocation profiledLocation);
private static bool IsTooSmall(ProfiledLocation profiledData) { return(profiledData.InclusiveTime.TotalMilliseconds < 1 || profiledData.ExclusiveTime.TotalMilliseconds < 1); }