using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Threading; using Unity.Collections.LowLevel.Unsafe; namespace UnityEditor.Rendering { /// <summary> /// Allows time measurements /// </summary> /// <example> /// double duration = 0; /// using (TimedScope.FromPtr(&duration)) /// { /// // something to get the time /// } /// Debug.Log($"Duration: {duration}") /// </example> public unsafe struct TimedScope : IDisposable { static readonly ThreadLocal<Stopwatch> s_StopWatch = new ThreadLocal<Stopwatch>(() => new Stopwatch()); double* m_DurationMsPtr; TimedScope(double* durationMsPtr) { m_DurationMsPtr = durationMsPtr; s_StopWatch.Value.Start(); } /// <summary> /// Dispose method to retrieve the time /// </summary> void IDisposable.Dispose() { s_StopWatch.Value.Stop(); *m_DurationMsPtr = s_StopWatch.Value.Elapsed.TotalMilliseconds; s_StopWatch.Value.Reset(); } /// <summary> /// Obtains a <see cref="TimedScope"/>. /// /// Safety: <paramref name="durationMsPtr"/> must be a non-null pointer to a valid memory location for a double. /// </summary> /// <param name="durationMsPtr">The location to write the duration in milliseconds to.</param> /// <returns>A <see cref="TimedScope"/></returns> public static unsafe TimedScope FromPtr([DisallowNull] double* durationMsPtr) { return new TimedScope(durationMsPtr); } /// <summary> /// Obtains a <see cref="TimedScope"/> /// </summary> /// <param name="durationMs">The location to write the duration in milliseconds to.</param> /// <returns>A <see cref="TimedScope"/></returns> public static TimedScope FromRef(ref double durationMs) { return new TimedScope((double*)UnsafeUtility.AddressOf(ref durationMs)); } } }