Files
FlaxEngine/Source/Tools/Flax.Build/Build/Profiling.cs
2021-01-02 14:28:49 +01:00

162 lines
5.0 KiB
C#

// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
namespace Flax.Build
{
/// <summary>
/// Inserts a profiling event for the given code scope.
/// </summary>
public class ProfileEventScope : IDisposable
{
private int _id;
/// <summary>
/// Initializes a new instance of the <see cref="ProfileEventScope"/> class.
/// </summary>
/// <param name="name">The event name.</param>
public ProfileEventScope(string name)
{
_id = Profiling.Begin(name);
}
/// <summary>
/// Ends the profiling event.
/// </summary>
public void Dispose()
{
Profiling.End(_id);
}
}
/// <summary>
/// The build system performance profiling tools.
/// </summary>
public static class Profiling
{
/// <summary>
/// The performance event data.
/// </summary>
public struct Event
{
/// <summary>
/// The event name.
/// </summary>
public string Name;
/// <summary>
/// The event start time.
/// </summary>
public DateTime StartTime;
/// <summary>
/// The event duration.
/// </summary>
public TimeSpan Duration;
/// <summary>
/// The event call depth (for parent-children events evaluation).
/// </summary>
public int Depth;
}
private static int _depth;
private static readonly List<Event> _events = new List<Event>(1024);
/// <summary>
/// Begins the profiling event.
/// </summary>
/// <param name="name">The name.</param>
/// <returns>The event id. Used by <see cref="End"/> callback.</returns>
public static int Begin(string name)
{
Event e;
e.Name = name;
e.StartTime = DateTime.Now;
e.Duration = TimeSpan.Zero;
e.Depth = _depth++;
_events.Add(e);
return _events.Count - 1;
}
/// <summary>
/// Ends the profiling event.
/// </summary>
/// <param name="id">The event identifier returned by <see cref="Begin"/>.</param>
public static void End(int id)
{
var endTime = DateTime.Now;
var e = _events[id];
e.Duration = endTime - e.StartTime;
_events[id] = e;
_depth--;
}
/// <summary>
/// Logs the recorded profiler events.
/// </summary>
public static void LogStats()
{
TimeSpan add = TimeSpan.Zero;
for (int i = 0; i < _events.Count; i++)
{
var e = _events[i];
if (i + 1 < _events.Count && _events[i + 1].Depth == e.Depth && _events[i + 1].Name == e.Name)
{
// Merge two events times
add += e.Duration;
continue;
}
string str = string.Empty;
while (e.Depth-- > 0)
str += " ";
str += e.Name;
str += " ";
str += e.Duration + add;
add = TimeSpan.Zero;
Log.Info(str);
}
}
/// <summary>
/// Generates the Trace Event file for profiling build system events.
/// </summary>
public static void GenerateTraceEventFile()
{
var traceEventFile = Configuration.TraceEventFile;
if (traceEventFile.Length == 0)
{
var logFile = Configuration.LogFile.Length != 0 ? Configuration.LogFile : "Cache/Intermediate/Log.txt";
traceEventFile = Path.ChangeExtension(logFile, ".trace.json");
}
var path = Path.GetDirectoryName(traceEventFile);
if (!string.IsNullOrEmpty(path) && !Directory.Exists(path))
Directory.CreateDirectory(path);
Log.Info("Saving trace events to " + traceEventFile);
var contents = new StringBuilder();
contents.Append("{\"traceEvents\": [");
var startTime = _events.Count != 0 ? _events[0].StartTime : DateTime.MinValue;
for (int i = 0; i < _events.Count; i++)
{
var e = _events[i];
contents.Append($"{{ \"pid\":1, \"tid\":1, \"ts\":{(int)((e.StartTime - startTime).TotalMilliseconds * 1000.0)}, \"dur\":{(int)(e.Duration.TotalMilliseconds * 1000.0)}, \"ph\":\"X\", \"name\":\"{e.Name}\", \"args\":{{ \"startTime\":\"{e.StartTime.ToShortTimeString()}\" }} }}\n");
if (i + 1 != _events.Count)
contents.Append(",");
}
contents.Append("]}");
File.WriteAllText(traceEventFile, contents.ToString());
}
}
}