");
sb.AppendLine($"{indentation}
{ToTimeString(ag.Time)}
");
sb.AppendLine($"{indentation}
{ToPercentageString(ag.Percentage)}
");
sb.AppendLine($"{indentation}
{ag.Name} (Found Instances: {ag.Calls})
");
sb.AppendLine($"{indentation}
");
sb.AppendLine(ag.ToString());
sb.AppendLine($"{indentation}
");
}
else
{
sb.AppendLine($"{indentation}
");
sb.AppendLine($"{indentation}
{ToTimeString(ag.Time)}
");
sb.AppendLine($"{indentation}
{ToPercentageString(ag.Percentage)}
");
sb.AppendLine($"{indentation}
{ag.Name} ({ag.Calls})
");
}
sb.AppendLine($"{indentation}
");
return sb;
}
public override string ToString()
{
return GetType().Name;
}
}
}
================================================
FILE: Editor/Formatters/Reporters/HTMLPerfReport.cs.meta
================================================
fileFormatVersion: 2
guid: 5982d768475803a4185fccf2a6ac8642
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/Formatters/Reporters/HTMLReporter.cs
================================================
using System.Text;
using UnityEditor.EditorIterationProfiler.Formatting;
using System.IO;
using System.Linq;
using UnityEngine;
namespace UnityEditor.EditorIterationProfiler
{
sealed class HTMLReporter : FileReporter
{
string m_Extension = "html";
public override string Extension => m_Extension;
string m_Name = "HTML";
public override string Name => m_Name;
double m_ParentTotalDuration;
protected override StringBuilder GetPrefixStringBuilder(in IIterationList iterationList = null)
{
var sb = new StringBuilder();
var fileGUID = AssetDatabase.FindAssets("HTMLReporterPrefix").FirstOrDefault();
var filePath = AssetDatabase.GUIDToAssetPath(fileGUID);
var file = AssetDatabase.LoadAssetAtPath
(filePath);
sb.Append(file.text);
sb.AppendLine($"{EditorIterationProfilerIntegration.Instance.Settings}
");
sb.AppendLine($"
");
sb.AppendLine();
sb.AppendLine($"");
sb.AppendLine($"Expand all
");
sb.AppendLine($"Collapse all
");
return sb;
}
protected override StringBuilder GetMainStringBuilder(in IIterationList iterationList)
{
var sb = new StringBuilder();
if (iterationList.IterationEventRoots.Count > 0)
{
RecursiveIterationList(iterationList, ref sb);
}
else
{
sb.AppendLine($"ERROR: No data to export!
");
}
return sb;
}
void RecursiveIterationList(in IIterationList iterationList, ref StringBuilder sb)
{
if (iterationList.IterationEventRoots.Count == 0)
{
return;
}
for (int i = 0; i < iterationList.IterationEventRoots.Count; ++i)
{
RecursiveIterationEventRoot(iterationList.IterationEventRoots[i], ref sb);
}
}
void RecursiveIterationEventRoot(in IterationEventRoot iterationEventRoot, ref StringBuilder sb)
{
double totalDuration = 0;
foreach (var ed in iterationEventRoot.Events)
{
if (ed.ParentIndex < 0 && ed.Duration > 0)
{
totalDuration += ed.Duration;
}
}
m_ParentTotalDuration = totalDuration;
var indentation1 = IndentationProvider.Get(1);
sb.AppendLine($"");
sb.AppendLine(TimeDisplay(1, totalDuration));
sb.AppendLine(PercentageDisplay(1, 100));
sb.AppendLine($"{indentation1}
Iteration {iterationEventRoot.IterationIndex + 1} ({iterationEventRoot.IterationEventKind})
");
foreach (var ed in iterationEventRoot.Events)
{
if (ed.ParentIndex < 0)
{
RecursiveEventData(ed, iterationEventRoot, ref sb, 1, 100);
sb.AppendLine($"{indentation1}
");
}
}
sb.AppendLine($" ");
}
void RecursiveEventData(in EventData ed, in IterationEventRoot parent, ref StringBuilder sb, int depth, double parentPercentage)
{
var indentation1 = IndentationProvider.Get(depth);
var indentation2 = IndentationProvider.Get(depth + 1);
double percentage = ed.Duration / m_ParentTotalDuration * 100;
if (ed.Children.Count > 0)
{
sb.AppendLine($"{indentation1}");
sb.AppendLine(TimeDisplay(depth + 1, ed.Duration));
sb.AppendLine(PercentageDisplay(depth + 1, percentage));
if (!string.IsNullOrEmpty(ed.Details))
{
sb.AppendLine($"{indentation2}
{ed.Identifier} ({ed.Details})
");
}
else
{
sb.AppendLine($"{indentation2}
{ed.Identifier}
");
}
}
else
{
sb.AppendLine($"{indentation1}
");
sb.AppendLine(TimeDisplay(depth + 1, ed.Duration));
sb.AppendLine(PercentageDisplay(depth + 1, percentage));
if (!string.IsNullOrEmpty(ed.Details))
{
sb.AppendLine(SimpleLabel(depth + 1, $"[{ed.Identifier}] ({ed.Details})"));
}
else
{
sb.AppendLine(SimpleLabel(depth + 1, $"[{ed.Identifier}]"));
}
}
RecursiveEventDataWalker(in ed, in parent, ref sb, depth, percentage);
if (depth != 1)
{
sb.AppendLine($"{indentation1}
");
}
}
void RecursiveEventDataWalker(in EventData ed, in IterationEventRoot iterationEventRoot, ref StringBuilder sb, int depth, double percentage)
{
if (ed.Children == null || ed.Children.Count == 0)
{
return;
}
foreach (var child in ed.Children)
{
RecursiveEventData(child, iterationEventRoot, ref sb, depth + 1, percentage);
}
}
string TimeDisplay(int depth, double time)
{
return $"{IndentationProvider.Get(depth)}
{ToTimeString(time)}
";
}
string PercentageDisplay(int depth, double percentage)
{
return $"{IndentationProvider.Get(depth)}
{ToPercentageString(percentage)}
";
}
string SimpleLabel(int depth, string s, string style = "")
{
if (!string.IsNullOrEmpty(style))
{
return $"{IndentationProvider.Get(depth)}
{s}
";
}
return $"{IndentationProvider.Get(depth)}
{s}
";
}
public override string ToString()
{
return GetType().Name;
}
}
}
================================================
FILE: Editor/Formatters/Reporters/HTMLReporter.cs.meta
================================================
fileFormatVersion: 2
guid: e616717ebe9a5aa41a86a75e07d38c16
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/Formatters/Reporters/HTMLReporterPrefix.txt
================================================
================================================
FILE: Editor/Formatters/Reporters/HTMLReporterPrefix.txt.meta
================================================
fileFormatVersion: 2
guid: fa0a687d251c5484281dc568e5a0e2ad
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/Formatters/Reporters/PlaintextReporter.cs
================================================
namespace UnityEditor.EditorIterationProfiler.Formatting
{
public sealed class PlaintextReporter : FileReporter
{
string m_Extension = "txt";
public override string Extension => m_Extension;
string m_Name = "Plaintext";
public override string Name => m_Name;
IDataReporter m_El = new EditorLogReporter();
public override void Report(in IIterationList iterationList, string path)
{
ReportToFile(m_El.GetFormatString(iterationList), path);
}
public override string ToString()
{
return GetType().Name;
}
}
}
================================================
FILE: Editor/Formatters/Reporters/PlaintextReporter.cs.meta
================================================
fileFormatVersion: 2
guid: 843fc8e922ce90b4fb75e591fe507647
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/Formatters/Reporters.meta
================================================
fileFormatVersion: 2
guid: dded3bae191a0ba46be87613decab5af
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/Formatters.meta
================================================
fileFormatVersion: 2
guid: 313fa6debd8d20c46ad511bfbb6b4213
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/IterationEventKind.cs
================================================
using System;
namespace UnityEditor.EditorIterationProfiler
{
public enum IterationEventKind
{
None = 0,
AssetImport,
AssetPostProcess,
ScriptCompilation,
AssemblyCompilation,
EnterPlayMode,
ExitPlayMode,
AssemblyReload,
AssemblyCompilationStart,
AssemblyCompilationFinish
}
}
================================================
FILE: Editor/IterationEventKind.cs.meta
================================================
fileFormatVersion: 2
guid: c0ea77b406086944dbb826a1c0895a29
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/IterationEventRoot.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace UnityEditor.EditorIterationProfiler
{
[Serializable]
public class IterationEventRoot
{
[SerializeField]
List
m_Events = new List();
public List Events => m_Events;
[SerializeField]
int m_IterationIndex;
public int IterationIndex
{
get => m_IterationIndex;
set => m_IterationIndex = value;
}
[SerializeField]
IterationEventKind m_IterationEventKind;
public IterationEventKind IterationEventKind => m_IterationEventKind;
[SerializeField]
Dictionary m_EventDictionary = new Dictionary();
public IterationEventKind LastIterationEventKind
{
get
{
if (Events.Count == 0)
{
return IterationEventKind.None;
}
return Events.Last().Kind;
}
}
public IterationEventRoot(int index)
{
IterationIndex = index;
m_IterationEventKind = IterationEventKind.None;
}
public IterationEventRoot(int index, IterationEventKind eventKind)
{
IterationIndex = index;
m_IterationEventKind = eventKind;
}
public void Reload()
{
foreach (var eventData in Events)
{
eventData.Children = new List();
}
foreach (var eventData in Events)
{
int parentIndex = eventData.ParentIndex;
if (parentIndex >= 0)
{
Events[parentIndex].Children.Add(eventData);
}
}
}
public EventData StartEvent(IterationEventKind kind, string identifier, string metadata)
{
int index = Events.Count;
var eventData = new EventData(kind, identifier, metadata, index);
Events.Add(eventData);
m_EventDictionary[identifier] = eventData;
return eventData;
}
public EventData StartEvent(IterationEventKind kind)
{
return StartEvent(kind, kind.ToString(), null);
}
public void FinishEvent(string identifier)
{
var eventData = FindLastEvent(identifier);
eventData?.Finish();
}
public void FinishEvent(IterationEventKind kind)
{
string identifier = kind.ToString();
FinishEvent(identifier);
}
public EventData AddChildEvent(string identifier, string metadata, double startTime, double finishTime, EventData parentEvent, EventDataFlags flags = EventDataFlags.None)
{
int index = Events.Count;
var eventData = new EventData(identifier, metadata, index, startTime, finishTime, flags);
Events.Add(eventData);
SetParent(eventData, parentEvent);
return eventData;
}
public static void SetParent(EventData child, EventData parent)
{
if (child == null)
{
throw new ArgumentNullException(nameof(child), "Argument is null");
}
if (parent == null)
{
throw new ArgumentNullException(nameof(parent), "Argument is null");
}
child.ParentIndex = parent.Index;
parent.Children.Add(child);
}
public void SetParent(EventData child, IterationEventKind kind)
{
var parent = FindLastEvent(kind);
SetParent(child, parent);
}
public EventData FindLastEvent(IterationEventKind kind)
{
string identifier = kind.ToString();
return FindLastEvent(identifier);
}
public EventData FindLastEvent(string identifier)
{
if (m_EventDictionary != null && m_EventDictionary.TryGetValue(identifier, out var eventData))
{
return eventData;
}
// If an assembly reload happens, then eventDictionary is
// empty and we search for the last event with matching
// identifier.
for (int i = Events.Count - 1; i >= 0; --i)
{
if (Events[i].Identifier == identifier)
{
return Events[i];
}
}
return null;
}
}
}
================================================
FILE: Editor/IterationEventRoot.cs.meta
================================================
fileFormatVersion: 2
guid: 6efa6c94e301cfc4da89c7584f3ceb2a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/IterationList.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace UnityEditor.EditorIterationProfiler
{
[Serializable]
class IterationList : IIterationList
{
[SerializeField]
List m_IterationIterationEventRoots;
public List IterationEventRoots => m_IterationIterationEventRoots;
public IterationEventRoot LastIterationEventRoot => m_IterationIterationEventRoots.LastOrDefault();
[SerializeField]
List m_IterationEventKinds;
public List IterationEventKinds => m_IterationEventKinds;
[SerializeField]
Action m_Updated;
public Action Updated { get; set; }
public IterationList()
{
m_IterationIterationEventRoots = new List();
m_IterationEventKinds = new List();
}
public void NewIteration(IterationEventKind kind)
{
int index = IterationEventRoots.Count;
IterationEventRoots.Add(new IterationEventRoot(index, kind));
IterationEventKinds.Add(kind);
}
public void Clear()
{
IterationEventRoots.Clear();
IterationEventKinds.Clear();
NotifyUpdated();
}
public void Reload()
{
foreach (var eventDataList in IterationEventRoots)
{
eventDataList.Reload();
}
NotifyUpdated();
}
public void NotifyUpdated()
{
Updated?.Invoke(this);
}
}
}
================================================
FILE: Editor/IterationList.cs.meta
================================================
fileFormatVersion: 2
guid: 685ab7a1693ff6d4588b129ce76cef56
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/ProfilerDataCollector.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEditor.EditorIterationProfiler.API;
using UnityEditor.Profiling;
using UnityEditorInternal;
using UnityEngine;
using UnityEngine.Profiling;
namespace UnityEditor.EditorIterationProfiler
{
[Serializable]
public class ProfilerDataCollector : IProfilerDataCollector
{
IIterationList m_IterationList;
//static Dictionary s_FlattenMarkers = new Dictionary();
static Dictionary s_KeyMarkers = new Dictionary();
static Dictionary s_MarkerFlags = new Dictionary();
static Dictionary s_MarkerThread = new Dictionary();
[SerializeField]
List m_FrameSearchDataList = new List();
public ProfilerDataCollector(IIterationList iterationList)
{
Initialize(iterationList);
// Find frame where asset import kicks off compilation.
AddKeyMarkers(IterationEventKind.AssetImport, "CompilationPipeline.CompileScripts");
//AddKeyMarkers(IterationEventKind.AssemblyCompilationStart, "CompilationPipeline.CompileAssemblyStart");
//AddKeyMarkers(IterationEventKind.AssemblyCompilationFinish, "CompilationPipeline.CompileAssemblyFinish");
AddKeyMarkers(IterationEventKind.AssemblyReload, "ReloadAssemblies");
AddKeyMarkers(IterationEventKind.EnterPlayMode, "EnterPlayMode");
AddKeyMarkers(IterationEventKind.ExitPlayMode, "ExitPlayMode");
//AddFlattenMarker("ReloadAssembly", "ReloadAssemblies");
//AddFlattenMarker("BeginReloadAssembly", "ReloadAssemblies");
//AddFlattenMarker("EndReloadAssembly", "ReloadAssemblies");
string[] userCodeMarkers =
{
"AssemblyReloadEvents.OnBeforeAssemblyReload()",
"AssemblyReloadEvents.OnAfterAssemblyReload()",
"DisabledScriptedObjects",
"BackupScriptedObjects",
"RestoreManagedReferences",
"ProcessInitializeOnLoadAttributes",
"ProcessInitializeOnLoadMethodAttributes",
"AwakeScriptedObjects",
"UnloadDomain"
};
foreach (string marker in userCodeMarkers)
{
AddMarkerFlags(marker, EventDataFlags.UserCode);
}
#if UNITY_2020_3_OR_NEWER
AddThreadMarker("UnloadDomain", "Domain Unloader", "Finalizer");
#else
AddThreadMarker("UnloadDomain", "Domain unloader", "Finalizer");
#endif
}
void Initialize(IIterationList iterationList)
{
m_IterationList = iterationList;
}
public void Clear()
{
m_FrameSearchDataList.Clear();
}
public void Subscribe()
{
UnityProfiling.NewProfilerFrameRecorded += ProfilerNewFrame;
}
public void Unsubscribe()
{
UnityProfiling.NewProfilerFrameRecorded -= ProfilerNewFrame;
}
static void AddKeyMarkers(IterationEventKind iterationEventKind, params string[] markers)
{
s_KeyMarkers[iterationEventKind] = markers;
}
static string[] GetKeyMarkers(IterationEventKind iterationEventKind)
{
if (s_KeyMarkers.TryGetValue(iterationEventKind, out string[] marker))
{
return marker;
}
return null;
}
//static void AddFlattenMarker(string marker, string parentMarker)
//{
// s_FlattenMarkers[marker] = parentMarker;
//}
static void AddMarkerFlags(string marker, EventDataFlags flags)
{
s_MarkerFlags[marker] = flags;
}
static void AddThreadMarker(string marker, params string[] threadNames)
{
s_MarkerThread[marker] = threadNames;
}
public void Collect(IterationEventKind iterationEventKind, IterationEventRoot iterationEventRoot, EventData rootEvent)
{
var frameSearchData = new FrameSearchData
{
IterationEventKind = iterationEventKind,
EventListIndex = iterationEventRoot.IterationIndex,
EventDataIndex = rootEvent.Index,
MaxNumFrames = 600
};
m_FrameSearchDataList.Add(frameSearchData);
#if DEVELOPMENT_BUILD
Debug.Log($"Starting to look for {iterationEventKind}");
#endif
}
void ProfilerNewFrame(int connectionId, int newFrameIndex)
{
// Remove frames which exceeded the search limit.
for (var i = m_FrameSearchDataList.Count - 1; i >= 0; --i)
{
m_FrameSearchDataList[i].MaxNumFrames -= 1;
if (m_FrameSearchDataList[i].MaxNumFrames <= 0)
{
#if DEVELOPMENT_BUILD
Debug.Log($"Stopping search for event {m_FrameSearchDataList[i].IterationEventKind}");
#endif
m_FrameSearchDataList.RemoveAt(i);
}
}
if (m_FrameSearchDataList.Count == 0)
{
return;
}
var frameData = UnityProfiling.GetFrame(newFrameIndex, 0);
if (!frameData.valid)
{
#if DEVELOPMENT_BUILD
Debug.LogErrorFormat($"Unable to retrieve profiler data for frame {newFrameIndex}");
#endif
return;
}
var markerData = new MarkerData(m_FrameSearchDataList.Count);
for (var i = 0; i < markerData.Length; ++i)
{
var frameSearchData = m_FrameSearchDataList[i];
frameSearchData.MaxNumFrames -= 1;
markerData.Markers[i] = GetKeyMarkers(frameSearchData.IterationEventKind);
}
var framesNotFound = new List();
for (int i = 0; i < m_FrameSearchDataList.Count; ++i)
{
if (markerData.FrameIndices[i] == 0)
{
framesNotFound.Add(m_FrameSearchDataList[i]);
}
}
#if DEVELOPMENT_BUILD
Debug.Log($"Searching for events {string.Join(",", framesNotFound.Select(f => f.IterationEventKind.ToString()).ToArray())} in frame {newFrameIndex}");
#endif
if (!FindMarkersInFrameData(frameData, frameData.GetRootItemID(), markerData, ProfilerDriver.deepProfiling ? 12 : 8))
{
#if DEVELOPMENT_BUILD
Debug.LogWarning($"Didn't find all markers in {newFrameIndex}");
#endif
return;
}
var iterationListUpdated = false;
for (int i = markerData.Length - 1; i >= 0; --i)
{
var frameSearchData = m_FrameSearchDataList[i];
if (markerData.SampleIds[i] == UnityProfiling.InvalidSampleId)
{
if (frameSearchData.MaxNumFrames <= 0)
{
#if DEVELOPMENT_BUILD
Debug.Log($"Stopping search for event {frameSearchData.IterationEventKind}");
#endif
m_FrameSearchDataList.RemoveAt(i);
}
continue;
}
#if DEVELOPMENT_BUILD
Debug.Log($"Reading profiling data for event {frameSearchData.IterationEventKind} from frame {markerData.FrameIndices[i]}");
#endif
var eventDataList = m_IterationList.IterationEventRoots[frameSearchData.EventListIndex];
var eventData = eventDataList.Events[frameSearchData.EventDataIndex];
ReadProfilingData(eventDataList, eventData, markerData.FrameData[i], markerData.FrameData[i].GetRootItemID(), EventDataFlags.None, false);
eventData.SetStartFinishTimeFromChildren();
eventData.PostProcess();
iterationListUpdated = true;
m_FrameSearchDataList.RemoveAt(i);
}
if (iterationListUpdated)
{
m_IterationList.NotifyUpdated();
}
}
internal static void ReadProfilingData(IterationEventRoot iterationEventRoot, EventData parentEventData, HierarchyFrameDataView frameData, int sampleId, EventDataFlags flags, bool parentHasSingleChild)
{
double duration = frameData.GetItemColumnDataAsDouble(sampleId, HierarchyFrameDataView.columnTotalTime);
if (duration < 0.01)
{
return;
}
string markerName = frameData.GetItemName(sampleId);
double startTime = frameData.GetItemColumnDataAsDouble(sampleId, HierarchyFrameDataView.columnStartTime);
double finishTime = startTime + duration;
int metadataCount = frameData.GetItemMetadataCount(sampleId);
var sb = new StringBuilder();
sb.Append("GC Alloc: " + frameData.GetItemColumnData(sampleId, 4) + "; ");
sb.Append("Calls: " + frameData.GetItemColumnData(sampleId, 3) + "; ");
if (metadataCount > 0)
{
sb.Append("Metadata: ");
for (var i = 0; i < metadataCount; ++i)
{
sb.Append(frameData.GetItemMetadata(sampleId, i));
sb.Append("; ");
}
}
var markerMetadata = sb.Replace(',', ';').Remove(sb.Length - 2, 1).ToString().Trim();
if (s_MarkerFlags.TryGetValue(markerName, out var eventMarkerFlags))
{
flags |= eventMarkerFlags;
}
var childEvent = iterationEventRoot.AddChildEvent(markerName, markerMetadata, startTime, finishTime, parentEventData, flags);
if (s_MarkerThread.TryGetValue(markerName, out string[] threadNames))
{
foreach (string threadName in threadNames)
{
var threadFrameData = UnityProfiling.GetFrame(frameData.frameIndex, threadName);
var threadEvent = iterationEventRoot.AddChildEvent($"Thread: {threadName}", markerMetadata, parentEventData.StartTime, parentEventData.FinishTime, childEvent, flags);
var threadChildIds = new List();
threadFrameData.GetItemChildren(threadFrameData.GetRootItemID(), threadChildIds);
foreach (int childId in threadChildIds)
{
ReadProfilingData(iterationEventRoot, threadEvent, threadFrameData, childId, flags, threadChildIds.Count == 1);
}
threadEvent.SetStartFinishTimeFromChildren();
}
}
var childIds = new List();
frameData.GetItemChildren(sampleId, childIds);
foreach (int childId in childIds)
{
ReadProfilingData(iterationEventRoot, childEvent, frameData, childId, flags, childIds.Count == 1);
}
}
static bool FindMarkersInFrameData(HierarchyFrameDataView frameData, int parentId, MarkerData markerData, int maxDepth)
{
if (maxDepth == 0)
{
return false;
}
var childrenIds = new List();
frameData.GetItemChildren(parentId, childrenIds);
string[][] markers = markerData.Markers;
int[] sampleIds = markerData.SampleIds;
int[] frameIndices = markerData.FrameIndices;
foreach (int childId in childrenIds)
{
string name = frameData.GetItemName(childId);
for (var i = 0; i < markers.Length; ++i)
{
if (markers[i] == null)
{
continue;
}
string[] localKeyMarkers = markers[i];
for (var j = 0; j < localKeyMarkers.Length; ++j)
{
if (name == localKeyMarkers[j])
{
sampleIds[i] = childId;
frameIndices[i] = frameData.frameIndex;
markerData.FrameData[i] = frameData;
}
}
}
if (markerData.FoundAllSampleIds)
{
return true;
}
if (FindMarkersInFrameData(frameData, childId, markerData, maxDepth - 1))
{
return true;
}
}
return false;
}
[Serializable]
public class FrameSearchData
{
public int EventDataIndex;
public int EventListIndex;
public IterationEventKind IterationEventKind;
public int MaxNumFrames;
}
struct MarkerData
{
public string[][] Markers;
public int[] SampleIds;
public int[] FrameIndices;
public HierarchyFrameDataView[] FrameData;
public MarkerData(int length)
{
Markers = new string[length][];
SampleIds = new int[length];
FrameIndices = new int[length];
FrameData = new HierarchyFrameDataView[length];
for (var i = 0; i < length; ++i)
{
SampleIds[i] = UnityProfiling.InvalidSampleId;
}
}
public bool FoundAllSampleIds
{
get
{
for (var i = 0; i < Length; ++i)
{
if (SampleIds[i] == UnityProfiling.InvalidSampleId)
{
return false;
}
}
return true;
}
}
public int Length => Markers.Length;
}
}
}
================================================
FILE: Editor/ProfilerDataCollector.cs.meta
================================================
fileFormatVersion: 2
guid: d1e3dc04d1e8e8344a237bfc5e3b756b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/Unity.EditorIterationProfiler.Editor.asmdef
================================================
{
"name": "Unity.EditorIterationProfiler.Editor",
"references": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
================================================
FILE: Editor/Unity.EditorIterationProfiler.Editor.asmdef.meta
================================================
fileFormatVersion: 2
guid: 00680d720d027674dbb1d8c51e1aaa52
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/UnityEditorEvents.cs
================================================
using System;
using System.IO;
using UnityEditor.Compilation;
namespace UnityEditor.EditorIterationProfiler
{
static class UnityEditorEvents
{
public enum Event
{
None = 0,
ScriptCompilationStarted,
ScriptCompilationFinished,
AssemblyCompilationStarted,
AssemblyCompilationFinished,
AssemblyReloadStarted,
AssemblyReloadFinished,
EnteringPlayMode,
EnteredPlayMode,
ExitingPlayMode,
ExitedPlayMode
}
public static event Action EditorEvent;
public static void Subscribe()
{
CompilationPipeline.compilationStarted += ScriptCompilationStarted;
CompilationPipeline.compilationFinished += ScriptCompilationFinished;
CompilationPipeline.assemblyCompilationStarted += AssemblyCompilationStarted;
CompilationPipeline.assemblyCompilationFinished += AssemblyCompilationFinished;
AssemblyReloadEvents.beforeAssemblyReload += AssemblyReloadStarted;
AssemblyReloadEvents.afterAssemblyReload += AssemblyReloadFinished;
EditorApplication.playModeStateChanged += PlayModeStateChanged;
}
public static void Unsubscribe()
{
CompilationPipeline.compilationStarted -= ScriptCompilationStarted;
CompilationPipeline.compilationFinished -= ScriptCompilationFinished;
CompilationPipeline.assemblyCompilationStarted -= AssemblyCompilationStarted;
CompilationPipeline.assemblyCompilationFinished -= AssemblyCompilationFinished;
AssemblyReloadEvents.beforeAssemblyReload -= AssemblyReloadStarted;
AssemblyReloadEvents.afterAssemblyReload -= AssemblyReloadFinished;
EditorApplication.playModeStateChanged -= PlayModeStateChanged;
}
static void ScriptCompilationStarted(object obj)
{
EditorEvent?.Invoke(Event.ScriptCompilationStarted, null);
}
static void ScriptCompilationFinished(object obj)
{
EditorEvent?.Invoke(Event.ScriptCompilationFinished, null);
}
static void AssemblyCompilationStarted(string assembly)
{
EditorEvent?.Invoke(Event.AssemblyCompilationStarted, Path.GetFileName(assembly));
}
static void AssemblyCompilationFinished(string assembly, CompilerMessage[] messages)
{
EditorEvent?.Invoke(Event.AssemblyCompilationFinished, Path.GetFileName(assembly));
}
static void AssemblyReloadStarted()
{
EditorEvent?.Invoke(Event.AssemblyReloadStarted, null);
}
static void AssemblyReloadFinished()
{
EditorEvent?.Invoke(Event.AssemblyReloadFinished, null);
}
static void PlayModeStateChanged(PlayModeStateChange state)
{
switch (state)
{
case PlayModeStateChange.ExitingEditMode:
{
EditorEvent?.Invoke(Event.EnteringPlayMode, null);
}
break;
case PlayModeStateChange.EnteredPlayMode:
{
EditorEvent?.Invoke(Event.EnteredPlayMode, null);
}
break;
case PlayModeStateChange.ExitingPlayMode:
{
EditorEvent?.Invoke(Event.ExitingPlayMode, null);
}
break;
case PlayModeStateChange.EnteredEditMode:
{
EditorEvent?.Invoke(Event.ExitedPlayMode, null);
}
break;
}
}
}
}
================================================
FILE: Editor/UnityEditorEvents.cs.meta
================================================
fileFormatVersion: 2
guid: 521d993316e2dc54f9f64b52fe96eadf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/UnityProfiling.cs
================================================
using System;
using UnityEditor.Profiling;
using UnityEditorInternal;
namespace UnityEditor.EditorIterationProfiler
{
static class UnityProfiling
{
public static bool EditorProfilingEnabled
{
get => ProfilerDriver.enabled && ProfilerDriver.profileEditor;
set
{
ProfilerDriver.enabled = value;
ProfilerDriver.profileEditor = value;
}
}
public static void SetProfileDeepScripts(bool deep)
{
if (ProfilerDriver.deepProfiling == deep)
return;
bool doApply = true;
// When enabling / disabling deep script profiling we need to reload scripts. In play mode this might be intrusive, so we ask the user first.
if (EditorApplication.isPlaying)
{
if (deep)
{
doApply = EditorUtility.DisplayDialog("Enable deep script profiling", "Enabling deep profiling requires reloading scripts.", "Reload", "Cancel");
}
else
{
doApply = EditorUtility.DisplayDialog("Disable deep script profiling", "Disabling deep profiling requires reloading all scripts", "Reload", "Cancel");
}
}
if (doApply)
{
EditorIterationProfilerAnalytics.SendInteractionEvent(EditorProfilingEnabled, EditorApplication.isPlaying, ProfilerDriver.deepProfiling, EditorIterationProfilerIntegration.Instance.Settings.Flatten, EditorIterationProfilerIntegration.Instance.Settings.UserCode);
ProfilerDriver.deepProfiling = deep;
EditorPrefs.SetBool(EditorIterationProfilerWindow.Styles.k_EnableDeepProfile, deep);
EditorIterationProfilerIntegration.Instance.Settings.DeepProfile = deep;
EditorUtility.RequestScriptReload();
}
}
public static int InvalidSampleId => HierarchyFrameDataView.invalidSampleId;
public static event Action NewProfilerFrameRecorded
{
add => ProfilerDriver.NewProfilerFrameRecorded += value;
remove => ProfilerDriver.NewProfilerFrameRecorded -= value;
}
public static HierarchyFrameDataView GetFrame(int frameIndex, int threadIndex)
{
var frame = ProfilerDriver.GetHierarchyFrameDataView(frameIndex, threadIndex, HierarchyFrameDataView.ViewModes.MergeSamplesWithTheSameName, HierarchyFrameDataView.columnTotalTime, false);
return frame;
}
public static HierarchyFrameDataView GetFrame(int frameIndex, string threadName)
{
var iter = new ProfilerFrameDataIterator();
iter.SetRoot(frameIndex, 0);
int threadCount = iter.GetThreadCount(frameIndex);
for (var i = 0; i < threadCount; ++i)
{
iter.SetRoot(frameIndex, i);
string currentThreadName = iter.GetThreadName();
if (currentThreadName.Equals(threadName, StringComparison.OrdinalIgnoreCase))
{
iter.Dispose();
return GetFrame(frameIndex, i);
}
}
iter.Dispose();
throw new ArgumentException($"Could not find thread named '{threadName}'. Depending on the Unity version, it could have been renamed.");
}
}
}
================================================
FILE: Editor/UnityProfiling.cs.meta
================================================
fileFormatVersion: 2
guid: dc5baee3fb0bc9f41ba836bff674eb06
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor.meta
================================================
fileFormatVersion: 2
guid: 9949f7c4ae59ee7499a083d831233f16
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: LICENSE.md
================================================
Editor Iteration Profiler copyright © 2020 Unity Technologies ApS
Licensed under the Unity Companion License for Unity-dependent projects--see [Unity Companion License](https://unity3d.com/legal/licenses/Unity_Companion_License).
Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the license for details on these and other terms and conditions.
================================================
FILE: LICENSE.md.meta
================================================
fileFormatVersion: 2
guid: 0515e52add3ab464880c7466bcf136b8
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: README.md
================================================
# Editor Iteration Profiler
Assists in capturing frames from the Profiler of Domain Reloads in the Unity Editor. Compatible with Unity 2019.3+.
# Please see the forum post for details on how to use, gotchas, etc. https://forum.unity.com/threads/introducing-the-editor-iteration-profiler.908390/
================================================
FILE: README.md.meta
================================================
fileFormatVersion: 2
guid: 41ae1fb9d1a93684bb23091b2c54ad2b
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: package.json
================================================
{
"name": "com.unity.editoriterationprofiler",
"displayName":"Editor Iteration Profiler",
"version": "0.1.2-preview",
"unity": "2019.3",
"description": "The Editor Iteration Profiler is an Editor tool which monitors domain reloads. It makes use of the Profiler and works by collecting and storing the relevant frames of the domain reload.\n\nMain features:\n▪ Enter/Exit playmode domain reload monitoring\n▪ Script Compilation monitoring\n▪ Ability to export its data or Profiler data to a number of formats such as CSV, HTML, JSON, etc.\n",
"dependencies": {
}
}
================================================
FILE: package.json.meta
================================================
fileFormatVersion: 2
guid: 9d114ba67f600c34994534b2b6994a8a
PackageManifestImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: