123 lines
3.2 KiB
C#
Executable File
123 lines
3.2 KiB
C#
Executable File
#region Copyright & License Information
|
|
/*
|
|
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
|
* This file is part of OpenRA, which is free software. It is made
|
|
* available to you under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation. For more information,
|
|
* see COPYING.
|
|
*/
|
|
#endregion
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
|
|
namespace OpenRA.Support
|
|
{
|
|
public sealed class PerfTimer : IDisposable
|
|
{
|
|
// Tree settings
|
|
const int Digits = 6;
|
|
const string IndentationString = "| ";
|
|
const string FormatSeperation = " ms ";
|
|
static readonly string FormatString = "{0," + Digits + ":0}" + FormatSeperation + "{1}";
|
|
readonly string name;
|
|
readonly float thresholdMs;
|
|
readonly byte depth;
|
|
readonly PerfTimer parent;
|
|
List<PerfTimer> children;
|
|
long ticks;
|
|
|
|
static ThreadLocal<PerfTimer> parentThreadLocal = new ThreadLocal<PerfTimer>();
|
|
|
|
public PerfTimer(string name, float thresholdMs = 0)
|
|
{
|
|
this.name = name;
|
|
this.thresholdMs = thresholdMs;
|
|
|
|
parent = parentThreadLocal.Value;
|
|
depth = parent == null ? (byte)0 : (byte)(parent.depth + 1);
|
|
parentThreadLocal.Value = this;
|
|
|
|
ticks = Stopwatch.GetTimestamp();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
ticks = Stopwatch.GetTimestamp() - ticks;
|
|
|
|
parentThreadLocal.Value = parent;
|
|
|
|
if (parent == null)
|
|
Write();
|
|
else if (ElapsedMs > thresholdMs)
|
|
{
|
|
if (parent.children == null)
|
|
parent.children = new List<PerfTimer>();
|
|
parent.children.Add(this);
|
|
}
|
|
}
|
|
|
|
void Write()
|
|
{
|
|
if (children != null)
|
|
{
|
|
Log.Write("perf", GetHeader(Indentation, name));
|
|
foreach (var child in children)
|
|
child.Write();
|
|
Log.Write("perf", FormatString, ElapsedMs, GetFooter(Indentation));
|
|
}
|
|
else if (ElapsedMs >= thresholdMs)
|
|
Log.Write("perf", FormatString, ElapsedMs, Indentation + name);
|
|
}
|
|
|
|
float ElapsedMs { get { return 1000f * ticks / Stopwatch.Frequency; } }
|
|
|
|
public static void LogLongTick(long startStopwatchTicks, long endStopwatchTicks, string name, object item)
|
|
{
|
|
var type = item.GetType();
|
|
var label = type == typeof(string) || type.IsGenericType ? item.ToString() : type.Name;
|
|
Log.Write("perf", FormatString,
|
|
1000f * (endStopwatchTicks - startStopwatchTicks) / Stopwatch.Frequency,
|
|
"[{0}] {1}: {2}".F(Game.LocalTick, name, label));
|
|
}
|
|
|
|
public static long LongTickThresholdInStopwatchTicks
|
|
{
|
|
get
|
|
{
|
|
return (long)(Stopwatch.Frequency * Game.Settings.Debug.LongTickThresholdMs / 1000f);
|
|
}
|
|
}
|
|
|
|
#region Formatting helpers
|
|
static string GetHeader(string indentation, string label)
|
|
{
|
|
return string.Concat(new string(' ', Digits + FormatSeperation.Length), indentation, label);
|
|
}
|
|
|
|
static string GetFooter(string indentation)
|
|
{
|
|
return string.Concat(indentation, new string('-', Math.Max(15, 50 - indentation.Length)));
|
|
}
|
|
|
|
string Indentation
|
|
{
|
|
get
|
|
{
|
|
if (depth <= 0)
|
|
return string.Empty;
|
|
else if (depth == 1)
|
|
return IndentationString;
|
|
else if (depth == 2)
|
|
return string.Concat(IndentationString, IndentationString);
|
|
else
|
|
return string.Concat(Enumerable.Repeat(IndentationString, depth));
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
}
|