forked from Unity-Technologies/AutoLOD
-
Notifications
You must be signed in to change notification settings - Fork 0
/
TimedEnumerator.cs
124 lines (104 loc) · 4.19 KB
/
TimedEnumerator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
using Debug = UnityEngine.Debug;
namespace Unity.AutoLOD
{
public class TimedEnumerator : IEnumerator
{
public float? maxIterationTimeMS { get; set; }
public bool logEnabled { get; set; }
public float totalExecutionTime { get; private set; }
public float selfExecutionTime { get; private set; }
public float iterationExecutionTime { get; private set; }
float? m_FirstIterationTime;
float? m_FinalIterationTime;
Stack<IEnumerator> m_EnumeratorStack = new Stack<IEnumerator>();
public bool MoveNext()
{
var sw = new Stopwatch();
sw.Start();
// We won't be able to capture time spent in other YieldInstructions because those are objects that get waited
// on separately, so we keep track of absolute time until the iterator is complete
if (!m_FirstIterationTime.HasValue)
m_FirstIterationTime = Time.realtimeSinceStartup;
var routine = m_EnumeratorStack.Peek();
var result = true;
if (maxIterationTimeMS.HasValue)
{
var maxTime = maxIterationTimeMS * 0.001f * Stopwatch.Frequency;
// Execute through as many yields as time permits
do
{
result &= routine.MoveNext();
if (!result)
{
if (m_EnumeratorStack.Count > 1)
{
// Nested coroutine ended
m_EnumeratorStack.Pop();
result = true;
}
else
break;
}
else
{
var current = Current;
if (current is YieldInstruction || current is CustomYieldInstruction)
{
// We have to leave these to Unity to resolve
break;
}
// Handle nesting
var enumerator = current as IEnumerator;
if (enumerator != null)
{
m_EnumeratorStack.Push(enumerator);
}
}
routine = m_EnumeratorStack.Peek();
} while (sw.ElapsedTicks < maxTime);
}
else
{
result = routine.MoveNext();
}
sw.Stop();
var endTime = Time.realtimeSinceStartup;
if (!result && !m_FinalIterationTime.HasValue)
m_FinalIterationTime = endTime;
iterationExecutionTime = (float)sw.ElapsedTicks / Stopwatch.Frequency;
selfExecutionTime += iterationExecutionTime;
if (m_FinalIterationTime.HasValue)
totalExecutionTime = m_FinalIterationTime.Value - m_FirstIterationTime.Value;
else
totalExecutionTime = endTime - m_FirstIterationTime.Value;
if (logEnabled)
Debug.LogFormat("Iteration: {0} / Self: {1} / Total: {2}", iterationExecutionTime, selfExecutionTime, totalExecutionTime);
return result;
}
public void Reset()
{
while (m_EnumeratorStack.Count > 1)
m_EnumeratorStack.Pop();
m_EnumeratorStack.Peek().Reset();
iterationExecutionTime = 0f;
selfExecutionTime = 0f;
totalExecutionTime = 0f;
m_FirstIterationTime = null;
m_FinalIterationTime = null;
}
public object Current
{
get { return m_EnumeratorStack.Count > 0 ? m_EnumeratorStack.Peek().Current : null; }
}
public TimedEnumerator(IEnumerator routine, float? maxIterationTimeMS = null)
{
m_EnumeratorStack.Push(routine);
if (maxIterationTimeMS.HasValue)
this.maxIterationTimeMS = maxIterationTimeMS;
}
}
}