TimeSample.cs 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. // TimeSample from Mirror II.
  2. // simple profiling sample, averaged for display in statistics.
  3. // usable in builds without unitiy profiler overhead etc.
  4. //
  5. // .average may safely be called from main thread while Begin/End is in another.
  6. // i.e. worker threads, transport, etc.
  7. using System.Diagnostics;
  8. using System.Threading;
  9. namespace Mirror
  10. {
  11. public struct TimeSample
  12. {
  13. // UnityEngine.Time isn't thread safe. use stopwatch instead.
  14. readonly Stopwatch watch;
  15. // remember when Begin was called
  16. double beginTime;
  17. // keep accumulating times over the given interval.
  18. // (not readonly. we modify its contents.)
  19. ExponentialMovingAverage ema;
  20. // average in seconds.
  21. // code often runs in sub-millisecond time. float is more precise.
  22. //
  23. // set with Interlocked for thread safety.
  24. // can be read from main thread while sampling happens in other thread.
  25. public double average; // THREAD SAFE
  26. // average over N begin/end captures
  27. public TimeSample(int n)
  28. {
  29. watch = new Stopwatch();
  30. watch.Start();
  31. ema = new ExponentialMovingAverage(n);
  32. beginTime = 0;
  33. average = 0;
  34. }
  35. // begin is called before the code to be sampled
  36. public void Begin()
  37. {
  38. // remember when Begin was called.
  39. // keep StopWatch running so we can average over the given interval.
  40. beginTime = watch.Elapsed.TotalSeconds;
  41. // Debug.Log($"Begin @ {beginTime:F4}");
  42. }
  43. // end is called after the code to be sampled
  44. public void End()
  45. {
  46. // add duration in seconds to accumulated durations
  47. double elapsed = watch.Elapsed.TotalSeconds - beginTime;
  48. ema.Add(elapsed);
  49. // expose new average thread safely
  50. Interlocked.Exchange(ref average, ema.Value);
  51. }
  52. }
  53. }