|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Text;
using Microsoft.Build.Framework.Profiler;
#nullable disable
namespace Microsoft.Build.Evaluation
{
/// <summary>
/// Pretty prints an evaluation location with its associated profiled location
/// </summary>
internal abstract class EvaluationLocationPrettyPrinterBase
{
/// <summary>
/// Appends the header of all the locations to the string builder
/// </summary>
/// <param name="stringBuilder"></param>
internal abstract void AppendHeader(StringBuilder stringBuilder);
/// <summary>
/// Appends a pretty printed location with its associated profiled data
/// </summary>
internal abstract void AppendLocation(StringBuilder stringBuilder, TimeSpan totalTime, EvaluationLocation evaluationLocation, ProfiledLocation profiledLocation);
/// <summary>
/// Normalizes the expression returned by <see cref="GetElementOrConditionText"/>
/// </summary>
protected abstract string NormalizeExpression(string description, EvaluationLocationKind kind);
/// <nodoc/>
protected static double GetMilliseconds(TimeSpan timeSpan)
{
return Math.Round(timeSpan.TotalMilliseconds, 0, MidpointRounding.AwayFromZero);
}
/// <nodoc/>
protected static double GetPercentage(TimeSpan total, TimeSpan time)
{
var percentage = (time.TotalMilliseconds / total.TotalMilliseconds) * 100;
return Math.Round(percentage, 1, MidpointRounding.AwayFromZero);
}
/// <nodoc/>
protected static string GetElementOrConditionText(string description, EvaluationLocationKind kind)
{
if (description == null)
{
return null;
}
if (kind == EvaluationLocationKind.Condition)
{
return $"Condition=\"{description}\")";
}
if (kind == EvaluationLocationKind.Glob)
{
return $"Glob=\"{description}\")";
}
var outerXml = description;
outerXml = outerXml.Replace(@"xmlns=""http://schemas.microsoft.com/developer/msbuild/2003""", "");
var newLineIndex = outerXml.IndexOfAny(['\r', '\n']);
return newLineIndex == -1 ? outerXml : outerXml.Remove(newLineIndex);
}
/// <summary>
/// Appends a default header with a given separator
/// </summary>
protected void AppendDefaultHeaderWithSeparator(StringBuilder stringBuilder, string separator)
{
stringBuilder.AppendLine(
string.Join(separator, "Id", "ParentId", "Pass", "File", "Line #", "Expression", "Inc (ms)", "Inc (%)", "Exc (ms)",
"Exc (%)", "#", "Kind", "Bug"));
}
/// <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));
}
}
}
|