in unity/EditorPlugin/Profiler/SnapshotAnalysis/ProfilerSnapshotCrawler.cs [36:120]
public Task<UnityProfilerSnapshot?> GetUnityProfilerSnapshot(ProfilerSnapshotRequest snapshotRequestInfo,
Lifetime lifetime, IProgress<UnityProfilerSnapshotStatus>? progress = null)
{
ourLogger.Verbose($"GetUnityProfilerSnapshot: {nameof(snapshotRequestInfo.FrameIndex)}:{snapshotRequestInfo.FrameIndex} {nameof(snapshotRequestInfo.ThreadIndex)}:{snapshotRequestInfo.ThreadIndex}");
if (snapshotRequestInfo.FrameIndex < 0 || snapshotRequestInfo.ThreadIndex < 0)
{
ourLogger.Verbose($"GetUnityProfilerSnapshot: {nameof(snapshotRequestInfo.FrameIndex)}:{snapshotRequestInfo.FrameIndex} {nameof(snapshotRequestInfo.ThreadIndex)}:{snapshotRequestInfo.ThreadIndex} is invalid");
return Task.FromResult<UnityProfilerSnapshot?>(null);
}
using var rawFrameDataView =
myProfilerSnapshotDriverAdapter?.GetRawFrameDataView(snapshotRequestInfo.FrameIndex,
snapshotRequestInfo.ThreadIndex);
if (rawFrameDataView == null)
{
ourLogger.Verbose($"GetUnityProfilerSnapshot: {nameof(rawFrameDataView)} is null");
return Task.FromResult<UnityProfilerSnapshot?>(null);
}
var sampleCount = rawFrameDataView.SampleCount;
var threadName = rawFrameDataView.ThreadName;
var threadId = rawFrameDataView.ThreadIndex;
var snapshotStatus = rawFrameDataView.ToSnapshotStatus(snapshotRequestInfo.FrameIndex,
SnapshotStatus.SnapshotDataFetchingInProgress);
progress?.Report(snapshotStatus);
// Pre-allocate collections with capacity to avoid resizing
var markerIdToName = new List<MarkerToNamePair>(sampleCount / 4); // Assuming ~25% unique markers
var samples = new List<SampleInfo>(sampleCount);
var currentProfilerFrameSnapshot = new UnityProfilerSnapshot(
snapshotRequestInfo.FrameIndex,
rawFrameDataView.FrameStartTimeMs,
rawFrameDataView.FrameTimeMs,
threadId, threadName,
markerIdToName,
samples,
snapshotStatus);
lifetime.ThrowIfNotAlive();
// Use HashSet for faster lookups
var knownMarkerIds =
#if UNITY_2022_3_OR_NEWER
new HashSet<int>(sampleCount / 4);
#else
new HashSet<int>();
#endif
var batchSize = Math.Max(1, sampleCount / 20); // Ensure batchSize is at least 1
// Start from 1 as the first sample is usually the frame itself
for (var i = 1; i < sampleCount; i++)
{
// Get all sample data at once to minimize method calls
var markerId = rawFrameDataView.GetSampleMarkerId(i);
var duration = rawFrameDataView.GetSampleTimeMs(i);
var childrenCount = rawFrameDataView.GetSampleChildrenCount(i);
var memoryAllocSize = rawFrameDataView.GetAllocSize(i);
// Create and add sample info
samples.Add(new SampleInfo(duration, markerId, memoryAllocSize, childrenCount));
// Report progress periodically
if (i % batchSize == 0)
progress?.Report(rawFrameDataView.ToSnapshotStatus(snapshotRequestInfo.FrameIndex,
SnapshotStatus.SnapshotDataFetchingInProgress,
i / (float)sampleCount));
lifetime.ThrowIfNotAlive();
// Only get sample name if we haven't seen this marker ID before
if (!knownMarkerIds.Contains(markerId))
{
var sampleName = rawFrameDataView.GetSampleName(i);
knownMarkerIds.Add(markerId);
markerIdToName.Add(new MarkerToNamePair(markerId, sampleName));
}
}
ourLogger.Verbose($"GetUnityProfilerSnapshot: {nameof(currentProfilerFrameSnapshot)} is ready");
return Task.FromResult<UnityProfilerSnapshot?>(currentProfilerFrameSnapshot);
}