// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using PerfReportTool;
using CSVStats;
/*
This summary sums up multiple CsvStat averages and emits the total as a SummaryTableMetric named metricName (if specified).
Budget colors can optionally be applied to individual stats and/or the total via colourThresholds and colourThresholdsTotal nodes
If emitStatMetrics is enabled, each stat will emit a SummaryTableMetric, named metricName/strippedStatName (with the same value as the existing CsvStatAverage element if it exists)
Budget coloring is applied to existing CsvStatAverage elements.
The budget for a given stat is assumed to be the first element of its colourThresholds. This value is displayed in the report
Example:
3,4,5,61,2,3,4Exclusive/GameThread/Buildings,Exclusive/GameThread/Camera,Exclusive/GameThread/Curie,Exclusive/GameThread/Network*,Exclusive/GameThread/PlayerController*,Exclusive/GameThread/WorldTickMisc,Exclusive/GameThread/FlushLatentActions,Exclusive/GameThread/Tickables,Exclusive/GameThread/SyncBodies,Exclusive/GameThread/CharPhys*,Exclusive/GameThread/Character*,Exclusive/GameThread/FortPawnTickSubsystem,Exclusive/GameThread/SignificanceManager,exclusive/gamethread/vehicle*,Exclusive/GameThread/AbilityTasks,Exclusive/GameThread/Actor*,Exclusive/GameThread/HandleRPC,Exclusive/GameThread/RepNotifies,Exclusive/GameThread/TickActors,Exclusive/GameThread/Pickups,Exclusive/GameThread/ProjectileMovement,Exclusive/GameThread/TimelineComponent,Exclusive/GameThread/TimerManager,Exclusive/GameThread/FortTrainManager
*/
namespace PerfSummaries
{
class StatInfo
{
public StatInfo( StatSamples inCsvStat )
{
name = inCsvStat.Name;
averageValue = inCsvStat.average;
csvStat = inCsvStat;
}
public StatInfo(string inName, double inAverageValue )
{
name = inName;
averageValue = inAverageValue;
}
public string name;
public double averageValue;
public StatSamples csvStat = null;
public ColourThresholdList colorThresholds = null;
};
class StatBudgetsSummary : Summary
{
public StatBudgetsSummary(XElement element, XmlVariableMappings vars, string baseXmlDirectory)
{
ReadStatsFromXML(element, vars);
colorThresholdsTotal = ReadColourThresholdListXML(element.Element("colourThresholdsTotal"), vars);
foreach (XElement child in element.Elements("colourThresholds"))
{
ColourThresholdList colorThresholds = ReadColourThresholdListXML(child, vars);
string statName = child.GetRequiredAttribute(vars, "stat");
statColorThresholds.Add(statName, colorThresholds);
}
metricName = element.GetSafeAttribute(vars, "metricName");
title = element.GetSafeAttribute(vars, "title", "Budgets summary");
stripStatPrefix = element.GetSafeAttribute(vars, "stripStatPrefix");
emitStatMetrics = element.GetSafeAttribute(vars, "emitStatMetrics", false);
showTotal = element.GetSafeAttribute(vars, "showTotal", true);
totalStatName = element.GetSafeAttribute(vars, "totalStat");
if ( emitStatMetrics && metricName == null )
{
throw new Exception("StatBudgetsSummary error: metricName must be specified if emitStatMetrics is enabled. XML element: " + element.ToString());
}
}
public StatBudgetsSummary() { }
public override string GetName() { return "statBudgets"; }
string StripStatPrefix(string statName)
{
if (stripStatPrefix != null)
{
if (statName.ToLower().StartsWith(stripStatPrefix.ToLower()))
{
return statName.Substring(stripStatPrefix.Length);
}
}
return statName;
}
public override HtmlSection WriteSummaryData(bool bWriteHtml, CsvStats csvStats, CsvStats csvStatsUnstripped, bool bWriteSummaryCsv, SummaryTableRowData rowData, string htmlFileName)
{
HtmlSection htmlSection = null;
// Find all referenced stats/metadata and sum them
double totalValue = 0.0;
List statInfoList = new List();
StatInfo totalStatInfo = null;
foreach (string statName in stats)
{
StatSamples csvStat = csvStats.GetStat(statName);
if (csvStat == null)
{
continue;
}
StatInfo statInfo = new StatInfo(csvStat);
if (statColorThresholds.TryGetValue(statName, out ColourThresholdList colorThresholds))
{
statInfo.colorThresholds = colorThresholds;
}
if (totalStatName != null && totalStatName.ToLower() == statName.ToLower())
{
totalStatInfo = statInfo;
totalStatInfo.name = "Total (" + StripStatPrefix(statName) + ")";
}
else
{
statInfoList.Add(statInfo);
totalValue += statInfo.averageValue;
}
}
// Sort largest to smallest
statInfoList.Sort((a, b) => b.averageValue.CompareTo(a.averageValue));
if (totalStatInfo != null)
{
// Add an "other" stat if the provided total stat is greater than the computed total
double otherValue = totalStatInfo.averageValue - totalValue;
if (otherValue > 0.0001)
{
StatInfo otherStatInfo = new StatInfo("Other", otherValue);
totalStatInfo.colorThresholds = colorThresholdsTotal;
statInfoList.Add(otherStatInfo);
}
}
else
{
totalStatInfo = new StatInfo("Total", totalValue);
totalStatInfo.colorThresholds = colorThresholdsTotal;
}
statInfoList.Add(totalStatInfo);
if (rowData != null)
{
// If we have rowData then apply thresholds to the CsvStatAverage elements (and ensure they exist)
foreach (StatInfo statInfo in statInfoList)
{
if ( statInfo.csvStat != null )
{
// Do we have an existing CsvStatAverage metric already?
SummaryTableElement element = rowData.Get(statInfo.csvStat.Name.ToLower());
if (element == null)
{
throw new Exception("Stat not found: "+ statInfo.csvStat.Name + " in budget summary "+title);
}
// Emit the stat metric if requested
if (emitStatMetrics)
{
string shortStatName = StripStatPrefix(statInfo.name);
string statMetricName = metricName + "/" + shortStatName;
rowData.Add(SummaryTableElement.Type.SummaryTableMetric, statMetricName, statInfo.averageValue, statInfo.colorThresholds);
}
// Update the color color threshold to the CSV stat if specified
if (statInfo.colorThresholds != null)
{
element.colorThresholdList = statInfo.colorThresholds;
}
}
}
// Output the total metric, if specified
if (metricName != null)
{
rowData.Add(SummaryTableElement.Type.SummaryTableMetric, metricName, totalStatInfo.averageValue, totalStatInfo.colorThresholds);
}
}
// Output HTML
if (bWriteHtml)
{
htmlSection = new HtmlSection(title, bStartCollapsed);
htmlSection.WriteLine("
");
}
return htmlSection;
}
ColourThresholdList colorThresholdsTotal = null;
Dictionary statColorThresholds = new Dictionary();
string title = "";
string metricName = null; // This is the output metric name used for the total, and also a prefix
string stripStatPrefix = null; // Specifies a stat prefix to strip (applies to metric names and report HTML)
string totalStatName = null; // If a total is specified then we'll use that if it's greater than the summed total. An "other" value stat will be displayed to show the difference
bool emitStatMetrics = false; // Whether to emit a separate summaryTableMetric for each stat. The name of each metric will be metricName/strippedStatName
bool showTotal = true; // Whether to display the total in the detailed report
};
}