// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.IO; using System.Collections.Generic; using System.Linq; using System.Xml.Linq; using PerfReportTool; using CSVStats; using System.Collections; namespace PerfSummaries { class BucketSummary : Summary { private enum ESortMode { None, Alpha, BucketIndex } private enum ESortDirection { Ascending, Descending, } public BucketSummary(XElement element, XmlVariableMappings vars, string baseXmlDirectory) { ReadStatsFromXML(element, vars); Title = element.GetSafeAttribute(vars, "title", "Untitled Bucket Summary"); XElement BucketElement = element.Element("buckets"); bool ReportOutOfRangeDefault = BucketElement.GetSafeAttribute(vars, "reportOutOfRange", false); // eg. ReportBelowRange = BucketElement.GetSafeAttribute(vars, "reportBelowRange", ReportOutOfRangeDefault); ReportAboveRange = BucketElement.GetSafeAttribute(vars, "reportAboveRange", ReportOutOfRangeDefault); ColumnHeaderPrecision = BucketElement.GetSafeAttribute(vars, "precision", "0"); string[] XmlBuckets = BucketElement.Value.Split(','); Buckets = new double[XmlBuckets.Length]; for (int i = 0; i < XmlBuckets.Length; i++) { Buckets[i] = Convert.ToDouble(XmlBuckets[i], System.Globalization.CultureInfo.InvariantCulture); } LowEndColor = new Colour(1.0f, 1.0f, 1.0f, 1.0f); HighEndColor = new Colour(1.0f, 1.0f, 1.0f, 1.0f); XElement ColorElement = element.Element("colorDisplay"); if (ColorElement != null) { LowEndColor = new Colour(ColorElement.GetSafeAttribute(vars, "lowEndColor")); HighEndColor = new Colour(ColorElement.GetSafeAttribute(vars, "highEndColor")); } // eg. XElement SortElement = element.Element("sort"); if (SortElement != null) { string SortModeStr = SortElement.GetSafeAttribute(vars, "mode", null); SortModeStr = SortModeStr != null ? SortModeStr.ToLower() : null; if (SortModeStr == "alpha") { SortMode = ESortMode.Alpha; } else if (SortModeStr == "bucketindex") { SortMode = ESortMode.BucketIndex; SortByBucketIndex = SortElement.GetRequiredAttribute(vars, "bucketIndex"); } string SortDirectionStr = SortElement.GetSafeAttribute(vars, "sortDirection", "ascending").ToLower(); SortDirection = SortDirectionStr == "ascending" ? ESortDirection.Ascending : ESortDirection.Descending; } } public BucketSummary() { } public override string GetName() { return "bucketsummary"; } public override HtmlSection WriteSummaryData(bool bWriteHtml, CsvStats csvStats, CsvStats csvStatsUnstripped, bool bWriteSummaryCsv, SummaryTableRowData rowData, string htmlFileName) { // Only HTML reporting is supported (does not summary table row data) if (!bWriteHtml) { return null; } if (Buckets.Length == 0) { return null; } HtmlSection htmlSection = new HtmlSection(Title, bStartCollapsed); htmlSection.WriteLine(" "); htmlSection.WriteLine(" "); List Hitches = new List(); if (ReportBelowRange) { htmlSection.WriteLine(" "); // Create a copy of the stats if we need to sort them. List sortedStats = SortMode == ESortMode.None ? stats : new List(stats); if (SortMode == ESortMode.Alpha) { sortedStats.Sort((string a, string b) => { return SortDirection == ESortDirection.Ascending ? a.CompareTo(b) : b.CompareTo(a); }); } else if (SortMode == ESortMode.BucketIndex) { if (SortByBucketIndex >= 0 && SortByBucketIndex < Buckets.Length) { float BucketValue = (float)Buckets[SortByBucketIndex]; sortedStats.Sort((string a, string b) => { StatSamples StatsA = csvStats.GetStat(a.ToLower()); StatSamples StatsB = csvStats.GetStat(b.ToLower()); int CountA = StatsA.GetCountOfFramesAtOrOverBudget(BucketValue); int CountB = StatsB.GetCountOfFramesAtOrOverBudget(BucketValue); return SortDirection == ESortDirection.Ascending ? CountA.CompareTo(CountB) : CountB.CompareTo(CountA); }); } } foreach (string unitStat in sortedStats) { string StatToCheck = unitStat.Split('(')[0]; StatSamples Stats = csvStats.GetStat(StatToCheck.ToLower()); if (Stats == null) { continue; } Hitches.Clear(); htmlSection.WriteLine(" "); Hitches.Add(StatToCheck); int[] BucketCounts = new int[Buckets.Length + 1]; int TotalSamples = Stats.GetNumSamples(); TotalSamples -= 2; // First and last frames are not counted in GetCountOfFramesAtOrOverBudget. BucketCounts[0] = TotalSamples - Stats.GetCountOfFramesAtOrOverBudget((float)Buckets[0]); int SamplesAccountedFor = BucketCounts[0]; for (int i = 0; i < Buckets.Length - 1; ++i) { double Begin = Buckets[i]; double End = Buckets[i + 1]; int BeginCount = (int)Stats.GetCountOfFramesAtOrOverBudget((float)Buckets[i]); int EndCount = (int)Stats.GetCountOfFramesAtOrOverBudget((float)Buckets[i + 1]); int BucketCount = BeginCount - EndCount; BucketCounts[i + 1] = BucketCount; SamplesAccountedFor += BucketCount; } BucketCounts[BucketCounts.Length - 1] = TotalSamples - SamplesAccountedFor; int FirstIndex = ReportBelowRange ? 0 : 1; int IndexCount = ReportAboveRange ? BucketCounts.Length : BucketCounts.Length - 1; int HighestBucketCount = 0; for (int i = FirstIndex; i < IndexCount; ++i) { HighestBucketCount = Math.Max(HighestBucketCount, BucketCounts[i]); } Colour White = new Colour(1.0f, 1.0f, 1.0f, 1.0f); for (int i = FirstIndex; i < IndexCount; ++i) { int Count = BucketCounts[i]; float T = (float)i / (float)(IndexCount - 1); Colour Color = Colour.LerpUsingHSV(LowEndColor, HighEndColor, T); float Intensity = Count / (float)HighestBucketCount; Color = Colour.Lerp(White, Color, Intensity); string ColorString = Color.ToHTMLString(); htmlSection.WriteLine(" "); Hitches.Add(Count.ToString("0")); } htmlSection.WriteLine(" "); } htmlSection.WriteLine("
<" + Buckets[0].ToString(ColumnHeaderPrecision) + ""); } for (int i = 1; i < Buckets.Length; ++i) { double Begin = Buckets[i - 1]; double End = Buckets[i]; htmlSection.WriteLine(" [" + Begin.ToString(ColumnHeaderPrecision) + ", " + End.ToString(ColumnHeaderPrecision) + ")"+ ""); } if (ReportAboveRange) { htmlSection.WriteLine(" >=" + Buckets.Last().ToString(ColumnHeaderPrecision) + ""); } htmlSection.WriteLine("
" + StatToCheck + "" + Count.ToString("0") + "
"); return htmlSection; } public double[] Buckets; public string Title; public bool ReportBelowRange; public bool ReportAboveRange; public Colour LowEndColor; public Colour HighEndColor; private string ColumnHeaderPrecision = "0"; // Sorting ESortMode SortMode = ESortMode.None; ESortDirection SortDirection; private int SortByBucketIndex = -1; }; }