You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

238 lines
8.4 KiB
C#

using System;
using System.Globalization;
using UnityEngine.Assertions;
using UnityEngine;
namespace UnityEditor.Performance.ProfileAnalyzer
{
/// <summary>Unit type identifier</summary>
internal enum Units
{
/// <summary>Time in milliseconds</summary>
Milliseconds,
/// <summary>Time in microseconds</summary>
Microseconds,
/// <summary>Count of number of instances</summary>
Count,
};
internal class DisplayUnits
{
public static readonly string[] UnitNames =
{
"Milliseconds",
"Microseconds",
"Count",
};
public static readonly int[] UnitValues = (int[])Enum.GetValues(typeof(Units));
public readonly Units Units;
const bool kShowFullValueWhenBelowZero = true;
const int kTooltipDigitsNumber = 7;
public DisplayUnits(Units units)
{
Assert.AreEqual(UnitNames.Length, UnitValues.Length, "Number of UnitNames should match number of enum values UnitValues: You probably forgot to update one of them.");
Units = units;
}
public string Postfix()
{
switch (Units)
{
default:
case Units.Milliseconds:
return "ms";
case Units.Microseconds:
return "us";
case Units.Count:
return "";
}
}
int ClampToRange(int value, int min, int max)
{
if (value < min)
value = min;
if (value > max)
value = max;
return value;
}
string RemoveTrailingZeros(string numberStr, int minNumberStringLength)
{
// Find out string length without trailing zeroes.
var strLenWithoutTrailingZeros = numberStr.Length;
while (strLenWithoutTrailingZeros > minNumberStringLength && numberStr[strLenWithoutTrailingZeros - 1] == '0')
strLenWithoutTrailingZeros--;
// Remove hanging '.' in case all zeroes can be omitted.
if (strLenWithoutTrailingZeros > 0 && numberStr[strLenWithoutTrailingZeros - 1] == '.')
strLenWithoutTrailingZeros--;
return strLenWithoutTrailingZeros == numberStr.Length ? numberStr : numberStr.Substring(0, strLenWithoutTrailingZeros);
}
public string ToString(float ms, bool showUnits, int limitToNDigits, bool showFullValueWhenBelowZero = false)
{
float value = ms;
int unitPower = -3;
int minNumberStringLength = -1;
int maxDecimalPlaces = 0;
float minValueShownWhenUsingLimitedDecimalPlaces = 1f;
switch (Units)
{
default:
case Units.Milliseconds:
maxDecimalPlaces = 2;
minValueShownWhenUsingLimitedDecimalPlaces = 0.01f;
break;
case Units.Microseconds:
value *= 1000f;
unitPower -= 3;
if (value < 100)
{
maxDecimalPlaces = 1;
minValueShownWhenUsingLimitedDecimalPlaces = 0.1f;
}
else
{
maxDecimalPlaces = 0;
minValueShownWhenUsingLimitedDecimalPlaces = 1f;
}
break;
case Units.Count:
showUnits = false;
break;
}
int sgn = Math.Sign(value);
if (value < 0)
value = -value;
int numberOfDecimalPlaces = maxDecimalPlaces;
int unitsTextLength = showUnits ? 2 : 0;
int signTextLength = sgn == -1 ? 1 : 0;
if (limitToNDigits > 0 && value > float.Epsilon)
{
int numberOfSignificantFigures = limitToNDigits;
if (!showFullValueWhenBelowZero)
numberOfSignificantFigures -= unitsTextLength + signTextLength;
int valueExp = (int)Math.Log10(value);
// Less than 1 values needs exponent correction as (int) rounds to the upper negative.
if (value < 1)
valueExp -= 1;
int originalUnitPower = unitPower;
float limitRange = (float)Math.Pow(10, numberOfSignificantFigures);
if (limitRange > 0)
{
if (value >= limitRange)
{
while (value >= 1000f && unitPower < 9)
{
value /= 1000f;
unitPower += 3;
valueExp -= 3;
}
}
else if (showFullValueWhenBelowZero) // Only upscale and change unit type if we want to see exact number.
{
while (value < 0.01f && unitPower > -9)
{
value *= 1000f;
unitPower -= 3;
valueExp += 3;
}
}
}
if (unitPower != originalUnitPower)
{
showUnits = true;
unitsTextLength = 2;
numberOfSignificantFigures = limitToNDigits;
if (!showFullValueWhenBelowZero)
numberOfSignificantFigures -= unitsTextLength + signTextLength;
}
// Use all allowed digits to display significant digits if we have any beyond maxDecimalPlaces
int numberOfDigitsBeforeDecimalPoint = 1 + Math.Max(0, valueExp);
if (showFullValueWhenBelowZero)
{
numberOfDecimalPlaces = numberOfSignificantFigures - numberOfDigitsBeforeDecimalPoint;
minNumberStringLength = numberOfDigitsBeforeDecimalPoint + signTextLength + maxDecimalPlaces + 1;
}
else
numberOfDecimalPlaces = ClampToRange(numberOfSignificantFigures - numberOfDigitsBeforeDecimalPoint, 0, maxDecimalPlaces);
}
value *= sgn;
string numberStr;
if (value < minValueShownWhenUsingLimitedDecimalPlaces && showFullValueWhenBelowZero)
{
numberStr = string.Format(CultureInfo.InvariantCulture, "{0}", value);
}
else
{
string formatString = string.Concat("{0:f", numberOfDecimalPlaces, "}");
numberStr = string.Format(CultureInfo.InvariantCulture, formatString, value);
}
// Remove trailing 0 if any from string
if (minNumberStringLength > 0 && numberStr.Length > 0)
numberStr = RemoveTrailingZeros(numberStr, minNumberStringLength);
if (!showUnits)
return numberStr;
string siUnitString = GetSIUnitString(unitPower) + "s";
return string.Concat(numberStr, siUnitString);
}
public static string GetSIUnitString(int unitPower)
{
// https://en.wikipedia.org/wiki/Metric_prefix
switch (unitPower)
{
case -9:
return "n";
case -6:
return "u";
case -3:
return "m";
case 0:
return "";
case 3:
return "k";
case 6:
return "M";
case 9:
return "G";
}
return "?";
}
public string ToTooltipString(double ms, bool showUnits, int frameIndex = -1)
{
if (frameIndex >= 0)
return string.Format("{0} on frame {1}", ToString((float)ms, showUnits, kTooltipDigitsNumber, kShowFullValueWhenBelowZero), frameIndex);
return ToString((float)ms, showUnits, kTooltipDigitsNumber, kShowFullValueWhenBelowZero);
}
public GUIContent ToGUIContentWithTooltips(float ms, bool showUnits = false, int limitToNDigits = 5, int frameIndex = -1)
{
return new GUIContent(ToString(ms, showUnits, limitToNDigits), ToTooltipString(ms, true, frameIndex));
}
}
}