Maze
/
Library
/PackageCache
/com.unity.performance.profile-analyzer@1.2.2
/Editor
/ProfilerWindowInterface.cs
using UnityEditorInternal; | |
using System.Reflection; | |
using System; | |
using System.Collections; | |
using UnityEngine; | |
using System.Collections.Generic; | |
using System.IO; | |
using UnityEngine.Profiling; | |
using UnityEditor.Profiling; | |
using Unity.Profiling.Editor; | |
// stub so that ProfilerWindow can be moved to this namespace in trunk without a need to change PA | |
namespace Unity.Profiling.Editor {} | |
namespace UnityEditor.Performance.ProfileAnalyzer | |
{ | |
internal class ProfilerWindowInterface | |
{ | |
bool m_ProfilerWindowInitialized = false; | |
const float k_NsToMs = 1000000; | |
ProgressBarDisplay m_progressBar; | |
[bool m_SendingSelectionEventToProfilerWindowInProgress = false; | ]|
[int m_LastSelectedFrameInProfilerWindow = 0; | ]|
[ | ] ProfilerWindow m_ProfilerWindow;|
[ | ] IProfilerFrameTimeViewSampleSelectionController m_CpuProfilerModule;|
Type m_ProfilerWindowType; | |
EditorWindow m_ProfilerWindow; | |
FieldInfo m_CurrentFrameFieldInfo; | |
FieldInfo m_TimeLineGUIFieldInfo; | |
FieldInfo m_SelectedEntryFieldInfo; | |
FieldInfo m_SelectedNameFieldInfo; | |
FieldInfo m_SelectedTimeFieldInfo; | |
FieldInfo m_SelectedDurationFieldInfo; | |
FieldInfo m_SelectedInstanceIdFieldInfo; | |
FieldInfo m_SelectedFrameIdFieldInfo; | |
FieldInfo m_SelectedThreadIndexFieldInfo; | |
FieldInfo m_SelectedNativeIndexFieldInfo; | |
FieldInfo m_SelectedInstanceCountFieldInfo; | |
FieldInfo m_SelectedInstanceCountForThreadFieldInfo; | |
FieldInfo m_SelectedInstanceCountForFrameFieldInfo; | |
FieldInfo m_SelectedMetaDataFieldInfo; | |
FieldInfo m_SelectedThreadCountFieldInfo; | |
FieldInfo m_SelectedCallstackInfoFieldInfo; | |
MethodInfo m_GetProfilerModuleInfo; | |
Type m_CPUProfilerModuleType; | |
public ProfilerWindowInterface(ProgressBarDisplay progressBar) | |
{ | |
m_progressBar = progressBar; | |
Assembly assem = typeof(Editor).Assembly; | |
m_ProfilerWindowType = assem.GetType("UnityEditor.ProfilerWindow"); | |
m_CurrentFrameFieldInfo = m_ProfilerWindowType.GetField("m_CurrentFrame", BindingFlags.NonPublic | BindingFlags.Instance); | |
m_TimeLineGUIFieldInfo = m_ProfilerWindowType.GetField("m_CPUTimelineGUI", BindingFlags.NonPublic | BindingFlags.Instance); | |
if (m_TimeLineGUIFieldInfo == null) | |
{ | |
// m_CPUTimelineGUI isn't present in 2019.3.0a8 onward | |
m_GetProfilerModuleInfo = m_ProfilerWindowType.GetMethod("GetProfilerModule", BindingFlags.NonPublic | BindingFlags.Instance); | |
if (m_GetProfilerModuleInfo == null) | |
{ | |
Debug.Log("Unable to initialise link to Profiler Timeline, no GetProfilerModule found"); | |
} | |
m_CPUProfilerModuleType = assem.GetType("UnityEditorInternal.Profiling.CPUProfilerModule"); | |
m_TimeLineGUIFieldInfo = m_CPUProfilerModuleType.GetField("m_TimelineGUI", BindingFlags.NonPublic | BindingFlags.Instance); | |
if (m_TimeLineGUIFieldInfo == null) | |
{ | |
Debug.Log("Unable to initialise link to Profiler Timeline"); | |
} | |
} | |
if (m_TimeLineGUIFieldInfo != null) | |
m_SelectedEntryFieldInfo = m_TimeLineGUIFieldInfo.FieldType.GetField("m_SelectedEntry", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
if (m_SelectedEntryFieldInfo != null) | |
{ | |
m_SelectedNameFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("name", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
m_SelectedTimeFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("time", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
m_SelectedDurationFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("duration", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
m_SelectedInstanceIdFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("instanceId", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
m_SelectedFrameIdFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("frameId", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
// confusingly this is called threadId but is the thread _index_ | |
m_SelectedThreadIndexFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("threadId", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
m_SelectedNativeIndexFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("nativeIndex", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
m_SelectedInstanceCountFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("instanceCount", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
m_SelectedInstanceCountForThreadFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("instanceCountForThread", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
m_SelectedInstanceCountForFrameFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("instanceCountForFrame", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
m_SelectedThreadCountFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("threadCount", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
m_SelectedMetaDataFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("metaData", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
m_SelectedCallstackInfoFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("callstackInfo", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
} | |
} | |
public bool IsReady() | |
{ | |
return m_ProfilerWindow != null && m_ProfilerWindowInitialized; | |
} | |
public void GetProfilerWindowHandle() | |
{ | |
Profiler.BeginSample("GetProfilerWindowHandle"); | |
if (m_CpuProfilerModule != null) | |
{ | |
m_CpuProfilerModule.selectionChanged -= OnSelectionChangedInCpuProfilerModule; | |
m_CpuProfilerModule = null; | |
} | |
var windows = Resources.FindObjectsOfTypeAll<ProfilerWindow>(); | |
if (windows != null && windows.Length > 0) | |
m_ProfilerWindow = windows[0]; | |
if (m_ProfilerWindow != null) | |
{ | |
var cpuModuleIdentifier = ProfilerWindow.cpuModuleIdentifier; | |
var cpuModuleIdentifier = ProfilerWindow.cpuModuleName; | |
m_CpuProfilerModule = | |
m_ProfilerWindow.GetFrameTimeViewSampleSelectionController(cpuModuleIdentifier); | |
m_CpuProfilerModule.selectionChanged -= OnSelectionChangedInCpuProfilerModule; | |
m_CpuProfilerModule.selectionChanged += OnSelectionChangedInCpuProfilerModule; | |
m_ProfilerWindow.Repaint(); | |
m_ProfilerWindowInitialized = false; | |
// wait a frame for the Profiler to get Repainted | |
EditorApplication.delayCall += () => m_ProfilerWindowInitialized = true; | |
} | |
UnityEngine.Object[] windows = Resources.FindObjectsOfTypeAll(m_ProfilerWindowType); | |
if (windows != null && windows.Length > 0) | |
m_ProfilerWindow = (EditorWindow)windows[0]; | |
m_ProfilerWindowInitialized = true; | |
Profiler.EndSample(); | |
} | |
public void OpenProfilerOrUseExisting() | |
{ | |
// Note we use existing if possible to fix a bug after domain reload | |
// Where calling EditorWindow.GetWindow directly causes a second window to open | |
if (m_ProfilerWindow == null) | |
{ | |
m_ProfilerWindow = EditorWindow.GetWindow<ProfilerWindow>(); | |
var cpuModuleIdentifier = ProfilerWindow.cpuModuleIdentifier; | |
var cpuModuleIdentifier = ProfilerWindow.cpuModuleName; | |
m_CpuProfilerModule = m_ProfilerWindow.GetFrameTimeViewSampleSelectionController(cpuModuleIdentifier); | |
m_CpuProfilerModule.selectionChanged -= OnSelectionChangedInCpuProfilerModule; | |
m_CpuProfilerModule.selectionChanged += OnSelectionChangedInCpuProfilerModule; | |
// Create new | |
m_ProfilerWindow = EditorWindow.GetWindow(m_ProfilerWindowType); | |
} | |
} | |
public bool GetFrameRangeFromProfiler(out int first, out int last) | |
{ | |
if (m_ProfilerWindow != null) | |
{ | |
first = 1 + ProfilerDriver.firstFrameIndex; | |
last = 1 + ProfilerDriver.lastFrameIndex; | |
return true; | |
} | |
first = 1; | |
last = 1; | |
return false; | |
} | |
public void CloseProfiler() | |
{ | |
if (m_ProfilerWindow != null) | |
m_ProfilerWindow.Close(); | |
} | |
object GetTimeLineGUI() | |
{ | |
object timeLineGUI = null; | |
if (m_CPUProfilerModuleType != null) | |
{ | |
object[] parametersArray = new object[] { ProfilerArea.CPU }; | |
var getCPUProfilerModuleInfo = m_GetProfilerModuleInfo.MakeGenericMethod(m_CPUProfilerModuleType); | |
var cpuModule = getCPUProfilerModuleInfo.Invoke(m_ProfilerWindow, parametersArray); | |
timeLineGUI = m_TimeLineGUIFieldInfo.GetValue(cpuModule); | |
} | |
else if (m_TimeLineGUIFieldInfo != null) | |
{ | |
timeLineGUI = m_TimeLineGUIFieldInfo.GetValue(m_ProfilerWindow); | |
} | |
return timeLineGUI; | |
} | |
private void OnSelectionChangedInCpuProfilerModule(IProfilerFrameTimeViewSampleSelectionController controller, ProfilerTimeSampleSelection selection) | |
{ | |
if (controller == m_CpuProfilerModule && !m_SendingSelectionEventToProfilerWindowInProgress) | |
{ | |
if (selection != null && selection.markerNamePath != null && selection.markerNamePath.Count > 0) | |
{ | |
selectedMarkerChanged(selection.markerNamePath[selection.markerNamePath.Count - 1], selection.threadGroupName, selection.threadName); | |
} | |
} | |
} | |
public event Action<string, string, string> selectedMarkerChanged = delegate {}; | |
public void PollProfilerWindowMarkerName() | |
{ | |
if (m_ProfilerWindow != null) | |
{ | |
var timeLineGUI = GetTimeLineGUI(); | |
if (timeLineGUI != null && m_SelectedEntryFieldInfo != null) | |
{ | |
var selectedEntry = m_SelectedEntryFieldInfo.GetValue(timeLineGUI); | |
if (selectedEntry != null && m_SelectedNameFieldInfo != null) | |
{ | |
string threadGroupName = null; | |
string threadName = null; | |
if (m_SelectedFrameIdFieldInfo != null && m_SelectedThreadIndexFieldInfo != null) | |
{ | |
using (RawFrameDataView frameData = ProfilerDriver.GetRawFrameDataView((int)m_SelectedFrameIdFieldInfo.GetValue(selectedEntry), (int)m_SelectedThreadIndexFieldInfo.GetValue(selectedEntry))) | |
{ | |
if (frameData != null && frameData.valid) | |
{ | |
threadGroupName = frameData.threadGroupName; | |
threadName = frameData.threadName; | |
} | |
} | |
} | |
selectedMarkerChanged(m_SelectedNameFieldInfo.GetValue(selectedEntry).ToString(), threadGroupName, threadName); | |
} | |
} | |
} | |
} | |
public ProfileData PullFromProfiler(int firstFrameDisplayIndex, int lastFrameDisplayIndex) | |
{ | |
Profiler.BeginSample("ProfilerWindowInterface.PullFromProfiler"); | |
bool recording = IsRecording(); | |
if (recording) | |
StopRecording(); | |
int firstFrameIndex = Mathf.Max(firstFrameDisplayIndex - 1, 0); | |
int lastFrameIndex = lastFrameDisplayIndex - 1; | |
ProfileData profileData = GetData(firstFrameIndex, lastFrameIndex); | |
if (recording) | |
StartRecording(); | |
Profiler.EndSample(); | |
return profileData; | |
} | |
public int GetThreadCountForFrame(int frameIndex) | |
{ | |
if (!IsReady()) | |
return 0; | |
ProfilerFrameDataIterator frameData = new ProfilerFrameDataIterator(); | |
frameData.SetRoot(frameIndex, 0); | |
return frameData.GetThreadCount(frameIndex); | |
} | |
public ProfileFrame GetProfileFrameForThread(int frameIndex, int threadIndex) | |
{ | |
if (!IsReady()) | |
return null; | |
var frame = new ProfileFrame(); | |
using (RawFrameDataView frameData = ProfilerDriver.GetRawFrameDataView(frameIndex, threadIndex)) | |
{ | |
frame.msStartTime = frameData.frameStartTimeMs; | |
frame.msFrame = frameData.frameTimeMs; | |
} | |
return frame; | |
} | |
ProfileData GetDataRaw(ProfileData data, int firstFrameIndex, int lastFrameIndex) | |
{ | |
bool firstError = true; | |
data.SetFrameIndexOffset(firstFrameIndex); | |
var depthStack = new Stack<int>(); | |
var threadNameCount = new Dictionary<string, int>(); | |
var markerIdToNameIndex = new Dictionary<int, int>(); | |
for (int frameIndex = firstFrameIndex; frameIndex <= lastFrameIndex; ++frameIndex) | |
{ | |
m_progressBar.AdvanceProgressBar(); | |
int threadIndex = 0; | |
threadNameCount.Clear(); | |
ProfileFrame frame = null; | |
while (true) | |
{ | |
using (RawFrameDataView frameData = ProfilerDriver.GetRawFrameDataView(frameIndex, threadIndex)) | |
{ | |
if (threadIndex == 0) | |
{ | |
if ((frameIndex == firstFrameIndex || frameIndex == lastFrameIndex) | |
&& firstFrameIndex != lastFrameIndex && (!frameData.valid || frameData.frameTimeNs == 0)) | |
{ | |
// skip incomplete frames when they are at the beginning or end of the capture | |
if (++frameIndex <= lastFrameIndex) | |
{ | |
data.FirstFrameIncomplete = true; | |
data.SetFrameIndexOffset(frameIndex); | |
continue; | |
} | |
else | |
{ | |
// break out entirely if this is the last frame | |
data.LastFrameIncomplete = true; | |
break; | |
} | |
} | |
frame = new ProfileFrame(); | |
if (frameData.valid) | |
{ | |
frame.msStartTime = frameData.frameStartTimeMs; | |
frame.msFrame = frameData.frameTimeMs; | |
} | |
data.Add(frame); | |
} | |
if (!frameData.valid) | |
break; | |
string threadNameWithIndex = null; | |
string threadName = frameData.threadName; | |
if (threadName.Trim() == "") | |
{ | |
Debug.Log(string.Format("Warning: Unnamed thread found on frame {0}. Corrupted data suspected, ignoring frame", frameIndex)); | |
threadIndex++; | |
continue; | |
} | |
var groupName = frameData.threadGroupName; | |
threadName = ProfileData.GetThreadNameWithGroup(threadName, groupName); | |
int nameCount = 0; | |
threadNameCount.TryGetValue(threadName, out nameCount); | |
threadNameCount[threadName] = nameCount + 1; | |
threadNameWithIndex = ProfileData.ThreadNameWithIndex(threadNameCount[threadName], threadName); | |
var thread = new ProfileThread(); | |
data.AddThreadName(threadNameWithIndex, thread); | |
frame.Add(thread); | |
// The markers are in depth first order | |
depthStack.Clear(); | |
// first sample is the thread name | |
for (int i = 1; i < frameData.sampleCount; i++) | |
{ | |
float durationMS = frameData.GetSampleTimeMs(i); | |
int markerId = frameData.GetSampleMarkerId(i); | |
if (durationMS < 0) | |
{ | |
if (firstError) | |
{ | |
int displayIndex = data.OffsetToDisplayFrame(frameIndex); | |
string name = frameData.GetSampleName(i); | |
Debug.LogFormat("Ignoring Invalid marker time found for {0} on frame {1} on thread {2} ({3} < 0)", | |
name, displayIndex, threadName, durationMS); | |
firstError = false; | |
} | |
} | |
else | |
{ | |
int depth = 1 + depthStack.Count; | |
var markerData = ProfileMarker.Create(durationMS, depth); | |
// Use name index directly if we have already stored this named marker before | |
int nameIndex; | |
if (markerIdToNameIndex.TryGetValue(markerId, out nameIndex)) | |
{ | |
markerData.nameIndex = nameIndex; | |
} | |
else | |
{ | |
string name = frameData.GetSampleName(i); | |
data.AddMarkerName(name, markerData); | |
markerIdToNameIndex[markerId] = markerData.nameIndex; | |
} | |
thread.AddMarker(markerData); | |
} | |
int childrenCount = frameData.GetSampleChildrenCount(i); | |
if (childrenCount > 0) | |
{ | |
depthStack.Push(childrenCount); | |
} | |
else | |
{ | |
while (depthStack.Count > 0) | |
{ | |
int remainingChildren = depthStack.Pop(); | |
if (remainingChildren > 1) | |
{ | |
depthStack.Push(remainingChildren - 1); | |
break; | |
} | |
} | |
} | |
} | |
} | |
threadIndex++; | |
} | |
} | |
data.Finalise(); | |
return data; | |
} | |
ProfileData GetDataOriginal(ProfileData data, int firstFrameIndex, int lastFrameIndex) | |
{ | |
ProfilerFrameDataIterator frameData = new ProfilerFrameDataIterator(); | |
bool firstError = true; | |
data.SetFrameIndexOffset(firstFrameIndex); | |
Dictionary<string, int> threadNameCount = new Dictionary<string, int>(); | |
for (int frameIndex = firstFrameIndex; frameIndex <= lastFrameIndex; ++frameIndex) | |
{ | |
m_progressBar.AdvanceProgressBar(); | |
int threadCount = frameData.GetThreadCount(frameIndex); | |
frameData.SetRoot(frameIndex, 0); | |
var msFrame = frameData.frameTimeMS; | |
if ((frameIndex == firstFrameIndex || frameIndex == lastFrameIndex) | |
&& firstFrameIndex != lastFrameIndex && msFrame == 0) | |
{ | |
var nextFrame = frameIndex + 1; | |
// skip incomplete frames when they are at the beginning or end of the capture | |
if (nextFrame <= lastFrameIndex) | |
{ | |
data.FirstFrameIncomplete = true; | |
data.SetFrameIndexOffset(nextFrame); | |
continue; | |
} | |
else | |
{ | |
// break out entirely if this is the last frame | |
data.LastFrameIncomplete = true; | |
break; | |
} | |
} | |
/* | |
if (frameIndex == lastFrameIndex) | |
{ | |
// Check if last frame appears to be invalid data | |
float median; | |
float mean; | |
float standardDeviation; | |
CalculateFrameTimeStats(data, out median, out mean, out standardDeviation); | |
float execessiveDeviation = (3f * standardDeviation); | |
if (msFrame > (median + execessiveDeviation)) | |
{ | |
Debug.LogFormat("Dropping last frame as it is significantly larger than the median of the rest of the data set {0} > {1} (median {2} + 3 * standard deviation {3})", msFrame, median + execessiveDeviation, median, standardDeviation); | |
break; | |
} | |
if (msFrame < (median - execessiveDeviation)) | |
{ | |
Debug.LogFormat("Dropping last frame as it is significantly smaller than the median of the rest of the data set {0} < {1} (median {2} - 3 * standard deviation {3})", msFrame, median - execessiveDeviation, median, standardDeviation); | |
break; | |
} | |
} | |
*/ | |
ProfileFrame frame = new ProfileFrame(); | |
frame.msStartTime = 1000.0 * frameData.GetFrameStartS(frameIndex); | |
frame.msFrame = msFrame; | |
data.Add(frame); | |
threadNameCount.Clear(); | |
for (int threadIndex = 0; threadIndex < threadCount; ++threadIndex) | |
{ | |
frameData.SetRoot(frameIndex, threadIndex); | |
var threadName = frameData.GetThreadName(); | |
if (threadName.Trim() == "") | |
{ | |
Debug.Log(string.Format("Warning: Unnamed thread found on frame {0}. Corrupted data suspected, ignoring frame", frameIndex)); | |
continue; | |
} | |
var groupName = frameData.GetGroupName(); | |
threadName = ProfileData.GetThreadNameWithGroup(threadName, groupName); | |
ProfileThread thread = new ProfileThread(); | |
frame.Add(thread); | |
int nameCount = 0; | |
threadNameCount.TryGetValue(threadName, out nameCount); | |
threadNameCount[threadName] = nameCount + 1; | |
data.AddThreadName(ProfileData.ThreadNameWithIndex(threadNameCount[threadName], threadName), thread); | |
const bool enterChildren = true; | |
// The markers are in depth first order and the depth is known | |
// So we can infer a parent child relationship | |
while (frameData.Next(enterChildren)) | |
{ | |
if (frameData.durationMS < 0) | |
{ | |
if (firstError) | |
{ | |
int displayIndex = data.OffsetToDisplayFrame(frameIndex); | |
Debug.LogFormat("Ignoring Invalid marker time found for {0} on frame {1} on thread {2} ({3} < 0) : Instance id : {4}", | |
frameData.name, displayIndex, threadName, frameData.durationMS, frameData.instanceId); | |
firstError = false; | |
} | |
continue; | |
} | |
var markerData = ProfileMarker.Create(frameData); | |
data.AddMarkerName(frameData.name, markerData); | |
thread.AddMarker(markerData); | |
} | |
} | |
} | |
data.Finalise(); | |
frameData.Dispose(); | |
return data; | |
} | |
ProfileData GetData(int firstFrameIndex, int lastFrameIndex) | |
{ | |
ProfileData data = new ProfileData(ProfileAnalyzerWindow.TmpPath); | |
GetDataRaw(data, firstFrameIndex, lastFrameIndex); | |
data.Write(); | |
return data; | |
} | |
public float GetFrameTimeRaw(int frameIndex) | |
{ | |
using (RawFrameDataView frameData = ProfilerDriver.GetRawFrameDataView(frameIndex, 0)) | |
{ | |
if (!frameData.valid) | |
return 0f; | |
return frameData.frameTimeMs; | |
} | |
} | |
public float GetFrameTime(int frameIndex) | |
{ | |
return GetFrameTimeRaw(frameIndex); | |
} | |
struct ThreadIndexIterator | |
{ | |
public ProfilerFrameDataIterator frameData; | |
public int threadIndex; | |
} | |
IEnumerator<ThreadIndexIterator> GetNextThreadIndexFittingThreadFilters(int frameIndex, List<string> threadFilters) | |
{ | |
ProfilerFrameDataIterator frameData = new ProfilerFrameDataIterator(); | |
int threadCount = frameData.GetThreadCount(frameIndex); | |
Dictionary<string, int> threadNameCount = new Dictionary<string, int>(); | |
for (int threadIndex = 0; threadIndex < threadCount; ++threadIndex) | |
{ | |
frameData.SetRoot(frameIndex, threadIndex); | |
var threadName = frameData.GetThreadName(); | |
// Name here could be "Worker Thread 1" | |
var groupName = frameData.GetGroupName(); | |
threadName = ProfileData.GetThreadNameWithGroup(threadName, groupName); | |
int nameCount = 0; | |
threadNameCount.TryGetValue(threadName, out nameCount); | |
threadNameCount[threadName] = nameCount + 1; | |
var threadNameWithIndex = ProfileData.ThreadNameWithIndex(threadNameCount[threadName], threadName); | |
// To compare on the filter we need to remove the postfix on the thread name | |
// "3:Worker Thread 0" -> "1:Worker Thread" | |
// The index of the thread (0) is used +1 as a prefix | |
// The preceding number (3) is the count of number of threads with this name | |
// Unfortunately multiple threads can have the same name | |
threadNameWithIndex = ProfileData.CorrectThreadName(threadNameWithIndex); | |
if (threadFilters.Contains(threadNameWithIndex)) | |
{ | |
yield return new ThreadIndexIterator {frameData = frameData, threadIndex = threadIndex}; | |
} | |
} | |
frameData.Dispose(); | |
} | |
bool GetMarkerInfo(string markerName, int frameIndex, List<string> threadFilters, out int outThreadIndex, out int outNativeIndex, out float time, out float duration, out int instanceId) | |
{ | |
outThreadIndex = 0; | |
outNativeIndex = 0; | |
time = 0.0f; | |
duration = 0.0f; | |
instanceId = 0; | |
bool found = false; | |
var iterator = GetNextThreadIndexFittingThreadFilters(frameIndex, threadFilters); | |
while (iterator.MoveNext()) | |
{ | |
const bool enterChildren = true; | |
while (iterator.Current.frameData.Next(enterChildren)) | |
{ | |
if (iterator.Current.frameData.name == markerName) | |
{ | |
time = iterator.Current.frameData.startTimeMS; | |
duration = iterator.Current.frameData.durationMS; | |
instanceId = iterator.Current.frameData.instanceId; | |
outNativeIndex = iterator.Current.frameData.sampleId; | |
outThreadIndex = iterator.Current.threadIndex; | |
found = true; | |
break; | |
} | |
} | |
if (found) | |
break; | |
} | |
return found; | |
} | |
public bool SetProfilerWindowMarkerName(string markerName, List<string> threadFilters) | |
{ | |
m_SendingSelectionEventToProfilerWindowInProgress = true; | |
if (m_ProfilerWindow == null) | |
return false; | |
var cpuModuleIdentifier = ProfilerWindow.cpuModuleIdentifier; | |
var selectedModuleIdentifier = m_ProfilerWindow.selectedModuleIdentifier; | |
var cpuModuleIdentifier = ProfilerWindow.cpuModuleName; | |
var selectedModuleIdentifier = m_ProfilerWindow.selectedModuleName; | |
m_CpuProfilerModule = m_ProfilerWindow.GetFrameTimeViewSampleSelectionController(cpuModuleIdentifier); | |
if (m_CpuProfilerModule != null && selectedModuleIdentifier == cpuModuleIdentifier | |
&& m_ProfilerWindow.firstAvailableFrameIndex >= 0) | |
{ | |
// Read profiler data direct from profile to find time/duration | |
int currentFrameIndex = (int)m_ProfilerWindow.selectedFrameIndex; | |
var iterator = GetNextThreadIndexFittingThreadFilters(currentFrameIndex, threadFilters); | |
while (iterator.MoveNext()) | |
{ | |
using (var rawFrameDataView = ProfilerDriver.GetRawFrameDataView(currentFrameIndex, iterator.Current.threadIndex)) | |
{ | |
if (m_CpuProfilerModule.SetSelection(currentFrameIndex, | |
rawFrameDataView.threadGroupName, rawFrameDataView.threadName, markerName, | |
threadId: rawFrameDataView.threadId)) | |
{ | |
m_ProfilerWindow.Repaint(); | |
m_SendingSelectionEventToProfilerWindowInProgress = false; | |
return true; // setting the selection was successful, nothing more to do here. | |
} | |
} | |
} | |
// selection couldn't be found, so clear the current one to avoid confusion | |
m_CpuProfilerModule.ClearSelection(); | |
m_ProfilerWindow.Repaint(); | |
} | |
var timeLineGUI = GetTimeLineGUI(); | |
if (timeLineGUI == null) | |
{ | |
m_SendingSelectionEventToProfilerWindowInProgress = false; | |
return false; | |
} | |
if (m_SelectedEntryFieldInfo != null) | |
{ | |
var selectedEntry = m_SelectedEntryFieldInfo.GetValue(timeLineGUI); | |
if (selectedEntry != null) | |
{ | |
// Read profiler data direct from profile to find time/duration | |
int currentFrameIndex = (int)m_CurrentFrameFieldInfo.GetValue(m_ProfilerWindow); | |
float time; | |
float duration; | |
int instanceId; | |
int nativeIndex; | |
int threadIndex; | |
if (GetMarkerInfo(markerName, currentFrameIndex, threadFilters, out threadIndex, out nativeIndex, out time, out duration, out instanceId)) | |
{ | |
/* | |
Debug.Log(string.Format("Setting profiler to {0} on {1} at frame {2} at {3}ms for {4}ms ({5})", | |
markerName, currentFrameIndex, threadFilter, time, duration, instanceId)); | |
*/ | |
if (m_SelectedNameFieldInfo != null) | |
m_SelectedNameFieldInfo.SetValue(selectedEntry, markerName); | |
if (m_SelectedTimeFieldInfo != null) | |
m_SelectedTimeFieldInfo.SetValue(selectedEntry, time); | |
if (m_SelectedDurationFieldInfo != null) | |
m_SelectedDurationFieldInfo.SetValue(selectedEntry, duration); | |
if (m_SelectedInstanceIdFieldInfo != null) | |
m_SelectedInstanceIdFieldInfo.SetValue(selectedEntry, instanceId); | |
if (m_SelectedFrameIdFieldInfo != null) | |
m_SelectedFrameIdFieldInfo.SetValue(selectedEntry, currentFrameIndex); | |
if (m_SelectedNativeIndexFieldInfo != null) | |
m_SelectedNativeIndexFieldInfo.SetValue(selectedEntry, nativeIndex); | |
if (m_SelectedThreadIndexFieldInfo != null) | |
m_SelectedThreadIndexFieldInfo.SetValue(selectedEntry, threadIndex); | |
// TODO : Update to fill in the total and number of instances. | |
// For now we force Instance count to 1 to avoid the incorrect info showing. | |
if (m_SelectedInstanceCountFieldInfo != null) | |
m_SelectedInstanceCountFieldInfo.SetValue(selectedEntry, 1); | |
if (m_SelectedInstanceCountForThreadFieldInfo != null) | |
m_SelectedInstanceCountForThreadFieldInfo.SetValue(selectedEntry, 1); | |
if (m_SelectedInstanceCountForFrameFieldInfo != null) | |
m_SelectedInstanceCountForFrameFieldInfo.SetValue(selectedEntry, 1); | |
if (m_SelectedThreadCountFieldInfo != null) | |
m_SelectedThreadCountFieldInfo.SetValue(selectedEntry, 1); | |
if (m_SelectedMetaDataFieldInfo != null) | |
m_SelectedMetaDataFieldInfo.SetValue(selectedEntry, ""); | |
if (m_SelectedCallstackInfoFieldInfo != null) | |
m_SelectedCallstackInfoFieldInfo.SetValue(selectedEntry, ""); | |
m_ProfilerWindow.Repaint(); | |
m_SendingSelectionEventToProfilerWindowInProgress = false; | |
return true; | |
} | |
} | |
} | |
m_SendingSelectionEventToProfilerWindowInProgress = false; | |
return false; | |
} | |
public bool JumpToFrame(int index) | |
{ | |
if (m_ProfilerWindow == null) | |
return false; | |
if (index - 1 < ProfilerDriver.firstFrameIndex) | |
return false; | |
if (index - 1 > ProfilerDriver.lastFrameIndex) | |
return false; | |
m_ProfilerWindow.selectedFrameIndex = index - 1; | |
m_CurrentFrameFieldInfo.SetValue(m_ProfilerWindow, index - 1); | |
m_ProfilerWindow.Repaint(); | |
return true; | |
} | |
public int selectedFrame | |
{ | |
get | |
{ | |
if (m_ProfilerWindow == null) | |
return 0; | |
return (int)m_ProfilerWindow.selectedFrameIndex + 1; | |
return (int)m_CurrentFrameFieldInfo.GetValue(m_ProfilerWindow) + 1; | |
} | |
} | |
public event Action<int> selectedFrameChanged = delegate {}; | |
public void PollSelectedFrameChanges() | |
{ | |
var currentlySelectedFrame = selectedFrame; | |
if (m_LastSelectedFrameInProfilerWindow != currentlySelectedFrame && !m_SendingSelectionEventToProfilerWindowInProgress) | |
{ | |
m_LastSelectedFrameInProfilerWindow = currentlySelectedFrame; | |
selectedFrameChanged(currentlySelectedFrame); | |
} | |
} | |
public bool IsRecording() | |
{ | |
return ProfilerDriver.enabled; | |
} | |
public void StopRecording() | |
{ | |
// Stop recording first | |
ProfilerDriver.enabled = false; | |
} | |
public void StartRecording() | |
{ | |
// Stop recording first | |
ProfilerDriver.enabled = true; | |
} | |
public void OnDisable() | |
{ | |
if (m_ProfilerWindow != null) | |
{ | |
m_ProfilerWindow = null; | |
} | |
if (m_CpuProfilerModule != null) | |
{ | |
m_CpuProfilerModule.selectionChanged -= OnSelectionChangedInCpuProfilerModule; | |
m_CpuProfilerModule = null; | |
} | |
} | |
} | |
} | |