using System; using System.Collections; using System.Diagnostics; using System.Threading.Tasks; using UnityEngine; using Debug = UnityEngine.Debug; namespace LibMMD.Unity3D { /// Measures load stages without mixing timing and log formatting into the loader. internal sealed class MmdLoadDiagnostics { private readonly Func _isEnabled; private readonly string _modelPath; private readonly Stopwatch _total = Stopwatch.StartNew(); internal MmdLoadDiagnostics(Func isEnabled, string modelPath) { _isEnabled = isEnabled ?? throw new ArgumentNullException(nameof(isEnabled)); _modelPath = modelPath; } internal IEnumerator Measure(string stage, IEnumerator routine) { if (!_isEnabled()) { while (routine.MoveNext()) yield return routine.Current; yield break; } var wall = Stopwatch.StartNew(); var activeTicks = 0L; var maximumSliceTicks = 0L; var steps = 0; while (true) { var started = Stopwatch.GetTimestamp(); var moved = routine.MoveNext(); var elapsed = Stopwatch.GetTimestamp() - started; activeTicks += elapsed; if (elapsed > maximumSliceTicks) maximumSliceTicks = elapsed; steps++; if (!moved) break; yield return routine.Current; } wall.Stop(); var tickToMilliseconds = 1000d / Stopwatch.Frequency; Debug.LogFormat( "[LibMMD.Load] {0}: wall={1:F1} ms, main={2:F1} ms, maxSlice={3:F1} ms, steps={4}", stage, wall.Elapsed.TotalMilliseconds, activeTicks * tickToMilliseconds, maximumSliceTicks * tickToMilliseconds, steps); } internal void MeasureAtomic(string stage, Action action) { if (!_isEnabled()) { action(); return; } var timer = Stopwatch.StartNew(); action(); timer.Stop(); Debug.LogFormat("[LibMMD.Load] {0}: main={1:F1} ms, maxSlice={1:F1} ms", stage, timer.Elapsed.TotalMilliseconds); } internal void Complete() { _total.Stop(); if (_isEnabled()) Debug.LogFormat("[LibMMD.Load] total: wall={0:F1} ms ({1})", _total.Elapsed.TotalMilliseconds, _modelPath); } internal static IEnumerator WaitForTask(Task task) { while (!task.IsCompleted) yield return null; } } }