#if ZEN_INTERNAL_PROFILING using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using ModestTree; namespace Zenject { // Similar to ProfileBlock except used for measuring speed of zenject specifically // And does not use unity's profiler public static class ProfileTimers { static Dictionary _timers = new Dictionary(); public static void ResetAll() { foreach (var timer in _timers.Values) { timer.Reset(); } } public static string FormatResults() { var result = new StringBuilder(); // Uncomment if you only want to see zenject related info //var timers = _timers.Where(x => x.Key != "User Code"); var timers = _timers; var total = timers.Select(x => x.Value.TotalMilliseconds).Sum(); result.Append("Total time tracked: {0:0.00} ms. Details:".Fmt(total)); foreach (var pair in timers.OrderByDescending(x => x.Value.TotalMilliseconds)) { var time = pair.Value.TotalMilliseconds; var percent = 100.0 * (time / total); var name = pair.Key; result.Append("\n {0:00.0}% ({1:00000}x) ({2:0000} ms) {3}".Fmt(percent, pair.Value.CallCount, time, name)); } return result.ToString(); } public static double GetTimerElapsedMilliseconds(string name) { return _timers[name].TotalMilliseconds; } public static IDisposable CreateTimedBlock(string name) { TimerInfo timer; if (!_timers.TryGetValue(name, out timer)) { timer = new TimerInfo(); _timers.Add(name, timer); } timer.CallCount++; if (timer.IsRunning) { return null; } return TimedBlock.Pool.Spawn(timer); } class TimedBlock : IDisposable { public static StaticMemoryPool Pool = new StaticMemoryPool(OnSpawned, OnDespawned); readonly List _pausedTimers = new List(); TimerInfo _exclusiveTimer; static void OnSpawned( TimerInfo exclusiveTimer, TimedBlock instance) { Assert.That(instance._pausedTimers.Count == 0); instance._exclusiveTimer = exclusiveTimer; foreach (var timer in _timers.Values) { if (exclusiveTimer == timer) { Assert.That(!timer.IsRunning); timer.Resume(); } else if (timer.IsRunning) { timer.Pause(); instance._pausedTimers.Add(timer); } } } static void OnDespawned(TimedBlock instance) { Assert.That(instance._exclusiveTimer.IsRunning); instance._exclusiveTimer.Pause(); foreach (var timer in instance._pausedTimers) { Assert.That(!timer.IsRunning); timer.Resume(); } instance._pausedTimers.Clear(); } public void Dispose() { Pool.Despawn(this); } } public class TimerInfo { readonly Stopwatch _timer; public TimerInfo() { _timer = new Stopwatch(); } public int CallCount { get; set; } public double TotalMilliseconds { get { return _timer.Elapsed.TotalMilliseconds; } } public bool IsRunning { get { return _timer.IsRunning; } } public void Reset() { _timer.Reset(); } public void Resume() { _timer.Start(); } public void Pause() { _timer.Stop(); } } } } #endif