playtest-unity/playtest/Library/PackageCache/com.unity.performance.profi.../Editor/ProfilerWindowInterface.cs

855 lines
38 KiB
C#
Raw Normal View History

2023-06-19 23:21:21 -04:00
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;
#if UNITY_2021_2_OR_NEWER
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 {}
#endif
namespace UnityEditor.Performance.ProfileAnalyzer
{
internal class ProfilerWindowInterface
{
bool m_ProfilerWindowInitialized = false;
const float k_NsToMs = 1000000;
ProgressBarDisplay m_progressBar;
[NonSerialized] bool m_SendingSelectionEventToProfilerWindowInProgress = false;
[NonSerialized] int m_LastSelectedFrameInProfilerWindow = 0;
#if UNITY_2021_1_OR_NEWER
[NonSerialized] ProfilerWindow m_ProfilerWindow;
[NonSerialized] IProfilerFrameTimeViewSampleSelectionController m_CpuProfilerModule;
#else
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;
#endif
public ProfilerWindowInterface(ProgressBarDisplay progressBar)
{
m_progressBar = progressBar;
#if !UNITY_2021_1_OR_NEWER
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);
}
#endif
}
public bool IsReady()
{
return m_ProfilerWindow != null && m_ProfilerWindowInitialized;
}
public void GetProfilerWindowHandle()
{
Profiler.BeginSample("GetProfilerWindowHandle");
#if UNITY_2021_1_OR_NEWER
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)
{
#if UNITY_2021_2_OR_NEWER
var cpuModuleIdentifier = ProfilerWindow.cpuModuleIdentifier;
#else
var cpuModuleIdentifier = ProfilerWindow.cpuModuleName;
#endif
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;
}
#else
UnityEngine.Object[] windows = Resources.FindObjectsOfTypeAll(m_ProfilerWindowType);
if (windows != null && windows.Length > 0)
m_ProfilerWindow = (EditorWindow)windows[0];
m_ProfilerWindowInitialized = true;
#endif
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)
{
#if UNITY_2021_1_OR_NEWER
m_ProfilerWindow = EditorWindow.GetWindow<ProfilerWindow>();
#if UNITY_2021_2_OR_NEWER
var cpuModuleIdentifier = ProfilerWindow.cpuModuleIdentifier;
#else
var cpuModuleIdentifier = ProfilerWindow.cpuModuleName;
#endif
m_CpuProfilerModule = m_ProfilerWindow.GetFrameTimeViewSampleSelectionController(cpuModuleIdentifier);
m_CpuProfilerModule.selectionChanged -= OnSelectionChangedInCpuProfilerModule;
m_CpuProfilerModule.selectionChanged += OnSelectionChangedInCpuProfilerModule;
#else
// Create new
m_ProfilerWindow = EditorWindow.GetWindow(m_ProfilerWindowType);
#endif
}
}
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();
}
#if !UNITY_2021_1_OR_NEWER
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;
}
#endif
#if UNITY_2021_1_OR_NEWER
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);
}
}
}
#endif
public event Action<string, string, string> selectedMarkerChanged = delegate {};
public void PollProfilerWindowMarkerName()
{
#if !UNITY_2021_1_OR_NEWER
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);
}
}
}
#endif
}
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;
#if UNITY_2021_1_OR_NEWER
#if UNITY_2021_2_OR_NEWER
var cpuModuleIdentifier = ProfilerWindow.cpuModuleIdentifier;
var selectedModuleIdentifier = m_ProfilerWindow.selectedModuleIdentifier;
#else
var cpuModuleIdentifier = ProfilerWindow.cpuModuleName;
var selectedModuleIdentifier = m_ProfilerWindow.selectedModuleName;
#endif
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();
}
#else
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;
}
}
}
#endif
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;
#if UNITY_2021_1_OR_NEWER
m_ProfilerWindow.selectedFrameIndex = index - 1;
#else
m_CurrentFrameFieldInfo.SetValue(m_ProfilerWindow, index - 1);
#endif
m_ProfilerWindow.Repaint();
return true;
}
public int selectedFrame
{
get
{
if (m_ProfilerWindow == null)
return 0;
#if UNITY_2021_1_OR_NEWER
return (int)m_ProfilerWindow.selectedFrameIndex + 1;
#else
return (int)m_CurrentFrameFieldInfo.GetValue(m_ProfilerWindow) + 1;
#endif
}
}
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 UNITY_2021_1_OR_NEWER
if (m_CpuProfilerModule != null)
{
m_CpuProfilerModule.selectionChanged -= OnSelectionChangedInCpuProfilerModule;
m_CpuProfilerModule = null;
}
#endif
}
}
}