Beispiel #1
0
 internal static void FileSeekMetadataFiller(ref FileAccessMarker marker, RawFrameDataView frameData, int sampleIndex)
 {
     // Filename, Offset, Origin
     marker.filename       = frameData.GetSampleMetadataAsString(sampleIndex, 0);
     marker.newOffsetBytes = (ulong)frameData.GetSampleMetadataAsLong(sampleIndex, 1);
     marker.originBytes    = (ulong)frameData.GetSampleMetadataAsLong(sampleIndex, 2);
 }
        public int GetItemIDFromRawFrameDataViewIndex(HierarchyFrameDataView frameDataView, int rawSampleIndex, ReadOnlyCollection <int> markerIdPath)
        {
            using (var rawFrameDataView = new RawFrameDataView(frameDataView.frameIndex, frameDataView.threadIndex))
            {
                var unreachableDepth = markerIdPath == null ? frameDataView.maxDepth + 1 : markerIdPath.Count;

                m_CachedDeepestRawSampleIndexPath.Clear();
                if (m_CachedDeepestRawSampleIndexPath.Capacity < unreachableDepth)
                {
                    m_CachedDeepestRawSampleIndexPath.Capacity = unreachableDepth;
                }

                string name          = null;
                var    foundRawIndex = ProfilerTimelineGUI.FindNextSampleThroughMarkerPath(rawFrameDataView, m_ProfilerSampleNameProvider, markerIdPath, unreachableDepth, ref name, ref m_CachedDeepestRawSampleIndexPath, specificRawSampleIndexToFind: rawSampleIndex);
                if (foundRawIndex < 0 || foundRawIndex != rawSampleIndex)
                {
                    return(HierarchyFrameDataView.invalidSampleId);
                }

                // We don't care about the path being extended here so, reduce checks by assuming the path is not expanded (this saves calls to IsExpanded)
                var selectedItemsPathIsExpanded = false;
                var newSelectedId = GetItemIdFromRawFrameDataIndexPath(frameDataView, m_CachedDeepestRawSampleIndexPath, out int deepestPath, out selectedItemsPathIsExpanded);
                if (deepestPath < m_CachedDeepestRawSampleIndexPath.Count)
                {
                    // the path has been cut short and the sample wasn't found
                    return(HierarchyFrameDataView.invalidSampleId);
                }
                return(newSelectedId);
            }
        }
        // Used with via Reflection (see MemoryProfilerModuleBridge.cs) from the Profiler Memory Profiler Package for the Memory Profiler Module UI Override. (To avoid pulling platform specifics into the package)
        static string GetPlatformSpecificText(RawFrameDataView f, IProfilerWindowController profilerWindow)
        {
            if (f.valid)
            {
                var totalReservedMemoryId = GetCounterValue(f, "Total Reserved Memory");
                if (totalReservedMemoryId != -1)
                {
                    StringBuilder stringBuilder        = new StringBuilder(1024);
                    var           garlicHeapUsedMemory = GetCounterValue(f, "GARLIC heap used");
                    if (garlicHeapUsedMemory != -1)
                    {
                        var garlicHeapAvailable = GetCounterValue(f, "GARLIC heap available");
                        stringBuilder.Append($"\n\nGARLIC heap used: {EditorUtility.FormatBytes(garlicHeapUsedMemory)}/{EditorUtility.FormatBytes(garlicHeapAvailable + garlicHeapUsedMemory)}   ");
                        stringBuilder.Append($"({EditorUtility.FormatBytes(garlicHeapAvailable)} available)   ");
                        stringBuilder.Append($"peak used: {GetCounterValueAsBytes(f, "GARLIC heap peak used")}   ");
                        stringBuilder.Append($"num allocs: {GetCounterValue(f, "GARLIC heap allocs")}\n");

                        stringBuilder.Append($"ONION heap used: {GetCounterValueAsBytes(f, "ONION heap used")}   ");
                        stringBuilder.Append($"peak used: {GetCounterValueAsBytes(f, "ONION heap peak used")}   ");
                        stringBuilder.Append($"num allocs: {GetCounterValue(f, "ONION heap allocs")}");
                        return(stringBuilder.ToString());
                    }
                }
            }
            return(null);
        }
Beispiel #4
0
 internal static void LoadAllAssetsMetadataFiller(ref AssetLoadMarker marker, RawFrameDataView frameData, int sampleIndex)
 {
     // AssetBundle Name, Asset Name
     marker.sourceName = frameData.GetSampleMetadataAsString(sampleIndex, 0);
     marker.assetName  = "LoadAll";
     marker.subsystem  = "Asset in AssetBundle";
 }
Beispiel #5
0
 internal static void FileWriteMetadataFiller(ref FileAccessMarker marker, RawFrameDataView frameData, int sampleIndex)
 {
     // Filename, Offset, Size
     marker.filename    = frameData.GetSampleMetadataAsString(sampleIndex, 0);
     marker.offsetBytes = (ulong)frameData.GetSampleMetadataAsLong(sampleIndex, 1);
     marker.sizeBytes   = (ulong)frameData.GetSampleMetadataAsLong(sampleIndex, 2);
 }
Beispiel #6
0
        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 UNITY_2020_1_OR_NEWER
                        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;
                                }
                            }
                        }
#endif
                        selectedMarkerChanged(m_SelectedNameFieldInfo.GetValue(selectedEntry).ToString(), threadGroupName, threadName);
                    }
                }
            }
#endif
        }
Beispiel #7
0
        internal void ReadFrameData(RawFrameDataView fRender)
        {
            var frameData = fRender.GetFrameMetaData <int>(m_VTProfilerGuid, 0);

            //This function only gets called when there are tiles on the screen so if we received no cache data this frame we use the old data
            if (frameData.Length == 0)
            {
                return;
            }

            m_FrameData.Clear();

            for (int i = 0; i < frameData.Length; i += 4)
            {
                FrameData data = new FrameData();
                data.format = (GraphicsFormat)frameData[i];
                data.demand = frameData[i + 1];
                data.bias   = frameData[i + 2] / 100.0f;
                data.size   = frameData[i + 3];

                m_FrameData.Add(data);
            }

            SortFrameData();
        }
Beispiel #8
0
 private static bool CheckForContinuationMarker(RawFrameDataView frameData, ref FileAccessCaptureData captureData, int threadIndex, int markerId, int frameIndex, int sampleIndex, ulong markerStartTimeNs, ulong sampleLengthNs)
 {
     // if the marker is right at the start of the frame, it could have been split from another on the previous frame
     if (frameData.frameStartTimeNs == markerStartTimeNs)
     {
         // check for a matching marker that ends at the exact point this one starts
         for (int j = 0; j < captureData.m_FileAccessData.Count; j++)
         {
             if (captureData.m_FileAccessData[j].threadIndex == threadIndex && captureData.m_FileAccessData[j].markerId == markerId)
             {
                 if (AbsDiff(captureData.m_FileAccessData[j].endNs, markerStartTimeNs) < 10) // Account for rounding errors
                 {
                     captureData.m_FileAccessData[j].endNs    += sampleLengthNs;
                     captureData.m_FileAccessData[j].lengthNs += sampleLengthNs;
                     captureData.m_FileAccessData[j].ms        = captureData.m_FileAccessData[j].lengthNs * 0.000001;
                     captureData.m_FileAccessData[j].frameCount++;
                     captureData.m_FileAccessData[j].lastFrameIndex = frameIndex;
                     captureData.m_FileAccessData[j].sampleIds.Add(sampleIndex);
                     return(true);
                 }
             }
         }
     }
     return(false);
 }
 void UpdateObjectRow(RawFrameDataView data, ref ObjectTableRow row, string countMarkerName, string sizeMarkerName = null)
 {
     row.Count.text = data.GetCounterValueAsLong(data.GetMarkerId(countMarkerName)).ToString();
     if (!string.IsNullOrEmpty(sizeMarkerName))
     {
         row.Size.text = EditorUtility.FormatBytes(data.GetCounterValueAsLong(data.GetMarkerId(sizeMarkerName)));
     }
 }
Beispiel #10
0
 internal static void ReadObjectMetadataFiller(ref AssetLoadMarker marker, RawFrameDataView frameData, int sampleIndex)
 {
     // path, offset, size bytes
     marker.filename   = frameData.GetSampleMetadataAsString(sampleIndex, 0);
     marker.sizeBytes  = (ulong)frameData.GetSampleMetadataAsLong(sampleIndex, 2);
     marker.subsystem  = frameData.GetSampleMetadataAsString(sampleIndex, 3);
     marker.sourceName = Path.GetFileName(marker.filename);
 }
Beispiel #11
0
 internal static void LoadSceneMetadataFiller(ref AssetLoadMarker marker, RawFrameDataView frameData, int sampleIndex)
 {
     // Scene path, Scene Name
     marker.sourceName = frameData.GetSampleMetadataAsString(sampleIndex, 0);
     marker.assetName  = frameData.GetSampleMetadataAsString(sampleIndex, 1);
     marker.subsystem  = "Scene";
     marker.filename   = marker.sourceName;
 }
Beispiel #12
0
 private static void GetMarkerIDs(RawFrameDataView frameData, Dictionary <string, FileAccessMarkerInfo> markers, ref Dictionary <string, int> markerToIDMap)
 {
     s_GetMarkerIDs.Begin();
     // iterate over the markers we want to get their markerIDs
     foreach (var markerName in markers.Keys)
     {
         // this markerID can change for the same marker so have to do for each frame
         markerToIDMap[markerName] = frameData.GetMarkerId(markerName);
     }
     s_GetMarkerIDs.End();
 }
Beispiel #13
0
        private long GetPhysicsCounterValue(RawFrameDataView frameData, string markerName)
        {
            // Find the marker.
            if (m_Markers.TryGetValue(markerName, out int markerId))
            {
                return(frameData.GetCounterValueAsLong(markerId));
            }

            // Indicate bad value!
            return(-1);
        }
Beispiel #14
0
 internal static void LoadAssetSyncMetadataFiller(ref AssetLoadMarker marker, RawFrameDataView frameData, int sampleIndex)
 {
     // AssetBundle Name, Asset Name
     marker.sourceName = frameData.GetSampleMetadataAsString(sampleIndex, 0);
     marker.assetName  = frameData.GetSampleMetadataAsString(sampleIndex, 1);
     if (string.IsNullOrWhiteSpace(marker.assetName))
     {
         marker.assetName = "(All)";
     }
     marker.subsystem = "Asset in AssetBundle";
 }
Beispiel #15
0
        public float GetFrameTimeRaw(int frameIndex)
        {
            using (RawFrameDataView frameData = ProfilerDriver.GetRawFrameDataView(frameIndex, 0))
            {
                if (!frameData.valid)
                {
                    return(0f);
                }

                return(frameData.frameTimeMs);
            }
        }
        protected override void SelectionChanged(IList <int> selectedIds)
        {
            ProfilerTimeSampleSelection selection;

            // When we navigate through frames and there is no path exists,
            // we still want to be able to frame and select proper sample once it is present again.
            // Thus we invalidate selection only if user selected new item.
            // Same applies to expanded state.
            if (selectedIds.Count > 0)
            {
                ClearSelection(setClearedSelection: false);
            }

            if (selectedIds.Count > 0 && m_FrameDataView.valid)
            {
                List <int> rawIds = new List <int>();
                if (selectedIds.Count > 1)
                {
                    List <int> ids = new List <int>();
                    for (int i = 0; i < selectedIds.Count; i++)
                    {
                        m_FrameDataView.GetItemRawFrameDataViewIndices(selectedIds[i], ids);
                    }
                }
                else
                {
                    m_FrameDataView.GetItemRawFrameDataViewIndices(selectedIds[0], rawIds);
                }
                selection = new ProfilerTimeSampleSelection(m_FrameDataView.frameIndex, m_FrameDataView.threadGroupName, m_FrameDataView.threadName, m_FrameDataView.threadId, rawIds, m_ProfilerSampleNameProvider.GetItemName(m_FrameDataView, selectedIds[0]));
                var selectedId       = selectedIds[0];
                var rawSampleIndices = new List <int>(m_FrameDataView.GetItemMergedSamplesCount(selectedId));
                m_FrameDataView.GetItemRawFrameDataViewIndices(selectedId, rawSampleIndices);
                var markerIDs = new List <int>(m_FrameDataView.GetItemDepth(selectedId));
                using (var iterator = new RawFrameDataView(m_FrameDataView.frameIndex, m_FrameDataView.threadIndex))
                {
                    string name = null;
                    ProfilerTimelineGUI.GetItemMarkerIdPath(iterator, m_ProfilerSampleNameProvider, rawSampleIndices[0], ref name, ref markerIDs);
                }
                selection.GenerateMarkerNamePath(m_FrameDataView, markerIDs);
            }
            else
            {
                selection = null;
            }

            var id = selectedIds.Count > 0 ? selectedIds[0] : RawFrameDataView.invalidSampleIndex;

            if (selectionChanged != null)
            {
                selectionChanged.Invoke(selection);
            }
        }
Beispiel #17
0
        private void InitializeMarkers(RawFrameDataView frameData)
        {
            // Fetch all the markers.
            var markerInfo = new List <FrameDataView.MarkerInfo>();

            frameData.GetMarkers(markerInfo);

            // Assign the markers.
            m_Markers = new Dictionary <string, int>(64);
            foreach (var marker in markerInfo)
            {
                if (marker.category == k_Physics2DCategoryId)
                {
                    m_Markers.Add(marker.name, marker.id);
                }
            }
        }
        int FindFirstMatchingRawSampleIndexInScopeRecursively(RawFrameDataView frameData, ref List <int> sampleIndexPath, string sampleName, int sampleMarkerId = FrameDataView.invalidMarkerId)
        {
            if (sampleMarkerId == FrameDataView.invalidMarkerId)
            {
                sampleMarkerId = frameData.GetMarkerId(sampleName);
            }
            var firstIndex = sampleIndexPath != null && sampleIndexPath.Count > 0 ? sampleIndexPath[sampleIndexPath.Count - 1] : 0;
            var lastSampleInSearchScope = firstIndex == 0 ? frameData.sampleCount - 1 : firstIndex + frameData.GetSampleChildrenCountRecursive(firstIndex);

            // Check if the enclosing scope matches the searched sample
            if (sampleIndexPath != null && sampleIndexPath.Count > 0 && (sampleMarkerId == FrameDataView.invalidMarkerId && GetItemName(frameData, firstIndex) == sampleName || frameData.GetSampleMarkerId(firstIndex) == sampleMarkerId))
            {
                return(firstIndex);
            }

            var samplePathAndLastSampleInScope = new List <RawSampleIterationInfo>()
            {
            };

            for (int i = firstIndex; i <= lastSampleInSearchScope; i++)
            {
                samplePathAndLastSampleInScope.Add(new RawSampleIterationInfo {
                    sampleIndex = i, lastSampleIndexInScope = i + frameData.GetSampleChildrenCountRecursive(i)
                });
                if (sampleMarkerId == FrameDataView.invalidMarkerId && (sampleName != null && GetItemName(frameData, i) == sampleName) || frameData.GetSampleMarkerId(i) == sampleMarkerId)
                {
                    // ignore the first sample if it's the enclosing sample (which is already in the list)
                    for (int j = sampleIndexPath.Count > 0 ? 1 : 0; j < samplePathAndLastSampleInScope.Count; j++)
                    {
                        // ignore the first sample if it's either the thread root sample.
                        // we can't always assume that there is a thread root sample, as the data may be mal formed, but we need to check if this is one by checking the name
                        if (j == 0 && frameData.GetSampleName(samplePathAndLastSampleInScope[j].sampleIndex) == frameData.threadName)
                        {
                            continue;
                        }
                        sampleIndexPath.Add(samplePathAndLastSampleInScope[j].sampleIndex);
                    }
                    return(i);
                }
                while (samplePathAndLastSampleInScope.Count > 0 && i + 1 > samplePathAndLastSampleInScope[samplePathAndLastSampleInScope.Count - 1].lastSampleIndexInScope)
                {
                    samplePathAndLastSampleInScope.RemoveAt(samplePathAndLastSampleInScope.Count - 1);
                }
            }
            return(RawFrameDataView.invalidSampleIndex);
        }
 // Used with via Reflection (see MemoryProfilerModuleBridge.cs) from the Profiler Memory Profiler Package for the Memory Profiler Module UI Override. (Only when showing old (pre-2020.2 aka pre-memory-counters) profiler data)
 static string GetSimpleMemoryPaneText(RawFrameDataView f, IProfilerWindowController profilerWindow, bool summary = true)
 {
     if (f.valid)
     {
         var totalReservedMemoryId = GetCounterValue(f, "Total Reserved Memory");
         if (totalReservedMemoryId != -1)
         {
             // Counter Data is available, a text form display is not needed
             return(string.Empty);
         }
         else
         {
             // Old data compatibility.
             return(ProfilerDriver.GetOverviewText(ProfilerArea.Memory, profilerWindow.GetActiveVisibleFrameIndex()));
         }
     }
     return(string.Empty);
 }
Beispiel #20
0
 internal RawFrameDataView GetRenderThread(RawFrameDataView frameDataView)
 {
     //Find render thread
     using (ProfilerFrameDataIterator frameDataIterator = new ProfilerFrameDataIterator())
     {
         var threadCount = frameDataIterator.GetThreadCount(frameDataView.frameIndex);
         for (int i = 0; i < threadCount; ++i)
         {
             RawFrameDataView frameData = ProfilerDriver.GetRawFrameDataView(frameDataView.frameIndex, i);
             if (frameData.threadName == "Render Thread")
             {
                 return(frameData);
             }
             else
             {
                 frameData.Dispose();
             }
         }
         // If there's no render thread, metadata was pushed on main thread
         return(frameDataView);
     }
 }
Beispiel #21
0
        public ProfileFrame GetProfileFrameForThread(int frameIndex, int threadIndex)
        {
            if (!IsReady())
            {
                return(null);
            }

            var frame = new ProfileFrame();

#if UNITY_2020_1_OR_NEWER
            using (RawFrameDataView frameData = ProfilerDriver.GetRawFrameDataView(frameIndex, threadIndex))
            {
                frame.msStartTime = frameData.frameStartTimeMs;
                frame.msFrame     = frameData.frameTimeMs;
            }
#else
            ProfilerFrameDataIterator frameData = new ProfilerFrameDataIterator();
            frameData.SetRoot(frameIndex, threadIndex);
            frame.msStartTime = 1000.0 * frameData.GetFrameStartS(frameIndex);
            frame.msFrame     = frameData.frameTimeMS;
#endif
            return(frame);
        }
Beispiel #22
0
        private SampleData GetPhysicsSampleData(RawFrameDataView frameData, string markerName)
        {
            SampleData sampleData = default;

            // Find the marker.
            if (m_Markers.TryGetValue(markerName, out int markerId))
            {
                for (var i = 0; i < frameData.sampleCount; ++i)
                {
                    // Ignore if it's not the marker we want.
                    if (markerId != frameData.GetSampleMarkerId(i))
                    {
                        continue;
                    }

                    // Accumulate sample data.
                    sampleData.timeMs += frameData.GetSampleTimeMs(i);
                    sampleData.count++;
                }
            }

            return(sampleData);
        }
Beispiel #23
0
 internal static void FileCloseMetadataFiller(ref FileAccessMarker marker, RawFrameDataView frameData, int sampleIndex)
 {
     // Filename
     marker.filename = frameData.GetSampleMetadataAsString(sampleIndex, 0);
 }
        int FindMarkerPathAndRawSampleIndexToFirstMatchingSampleInCurrentView(int frameIndex, int threadIndex, ref string sampleName, ref List <int> markerIdPath, string markerNamePath = null, int sampleMarkerId = FrameDataView.invalidMarkerId)
        {
            using (var frameData = new RawFrameDataView(frameIndex, threadIndex))
            {
                List <int> tempMarkerIdPath = null;
                if (markerIdPath != null && markerIdPath.Count > 0)
                {
                    tempMarkerIdPath = markerIdPath;
                }

                var foundSampleIndex = RawFrameDataView.invalidSampleIndex;
                var sampleIndexPath  = new List <int>();

                if (sampleMarkerId == FrameDataView.invalidMarkerId)
                {
                    sampleMarkerId = frameData.GetMarkerId(sampleName);
                }

                int    pathLength       = 0;
                string lastSampleInPath = null;
                Func <int, int, RawFrameDataView, bool> sampleIdFitsMarkerPathIndex = null;

                if (tempMarkerIdPath != null && tempMarkerIdPath.Count > 0)
                {
                    pathLength = tempMarkerIdPath.Count;
                }
                else if (!string.IsNullOrEmpty(markerNamePath))
                {
                    var path = markerNamePath.Split('/');
                    if (path != null && path.Length > 0)
                    {
                        pathLength = path.Length;
                        using (var iterator = new RawFrameDataView(frameIndex, threadIndex))
                        {
                            tempMarkerIdPath = new List <int>(pathLength);
                            for (int i = 0; i < pathLength; i++)
                            {
                                tempMarkerIdPath.Add(iterator.GetMarkerId(path[i]));
                            }
                        }
                        sampleIdFitsMarkerPathIndex = (sampleIndex, markerPathIndex, iterator) =>
                        {
                            return(tempMarkerIdPath[markerPathIndex] == FrameDataView.invalidMarkerId && GetItemName(iterator, sampleIndex) == path[markerPathIndex]);
                        };
                    }
                }

                if (pathLength > 0)
                {
                    var enclosingScopeSampleIndex = RawFrameDataView.invalidSampleIndex;
                    if (sampleIndexPath.Capacity < pathLength)
                    {
                        sampleIndexPath.Capacity = pathLength + 1; // +1 for the presumably often case of the searched sample being part of the path or in the last scope of it
                    }
                    enclosingScopeSampleIndex = ProfilerTimelineGUI.FindNextSampleThroughMarkerPath(
                        frameData, this, tempMarkerIdPath, pathLength, ref lastSampleInPath, ref sampleIndexPath,
                        sampleIdFitsMarkerPathIndex: sampleIdFitsMarkerPathIndex);

                    if (enclosingScopeSampleIndex == RawFrameDataView.invalidSampleIndex)
                    {
                        //enclosing scope not found
                        return(RawFrameDataView.invalidSampleIndex);
                    }
                    foundSampleIndex = FindFirstMatchingRawSampleIndexInScopeRecursively(frameData, ref sampleIndexPath, sampleName, sampleMarkerId);
                    while (foundSampleIndex == RawFrameDataView.invalidSampleIndex && enclosingScopeSampleIndex != RawFrameDataView.invalidSampleIndex)
                    {
                        // sample wasn't found in the current scope, find the next scope ...
                        enclosingScopeSampleIndex = ProfilerTimelineGUI.FindNextSampleThroughMarkerPath(
                            frameData, this, tempMarkerIdPath, pathLength, ref lastSampleInPath, ref sampleIndexPath,
                            sampleIdFitsMarkerPathIndex: sampleIdFitsMarkerPathIndex);

                        if (enclosingScopeSampleIndex == RawFrameDataView.invalidSampleIndex)
                        {
                            return(RawFrameDataView.invalidSampleIndex);
                        }
                        // ... and search there
                        foundSampleIndex = FindFirstMatchingRawSampleIndexInScopeRecursively(frameData, ref sampleIndexPath, sampleName, sampleMarkerId);
                    }
                }
                else
                {
                    if (sampleMarkerId == FrameDataView.invalidMarkerId)
                    {
                        foundSampleIndex = FindFirstMatchingRawSampleIndexInScopeRecursively(frameData, ref sampleIndexPath, sampleName);
                    }
                    else
                    {
                        foundSampleIndex = FindFirstMatchingRawSampleIndexInScopeRecursively(frameData, ref sampleIndexPath, null, sampleMarkerId);
                    }
                }

                if (foundSampleIndex != RawFrameDataView.invalidSampleIndex)
                {
                    if (string.IsNullOrEmpty(sampleName))
                    {
                        sampleName = GetItemName(frameData, foundSampleIndex);
                    }
                    if (markerIdPath == null)
                    {
                        markerIdPath = new List <int>(sampleIndexPath.Count);
                    }
                    // populate marker id path with missing markers
                    for (int i = markerIdPath.Count; i < sampleIndexPath.Count; i++)
                    {
                        markerIdPath.Add(frameData.GetSampleMarkerId(sampleIndexPath[i]));
                    }
                }
                return(foundSampleIndex);
            }
        }
Beispiel #25
0
 internal static void AsyncReadManagerMetadataFiller(ref AssetLoadMarker marker, RawFrameDataView frameData, int sampleIndex)
 {
     // Path, size, subsystem
     marker.filename   = frameData.GetSampleMetadataAsString(sampleIndex, 0);
     marker.sizeBytes  = (ulong)frameData.GetSampleMetadataAsLong(sampleIndex, 1);
     marker.subsystem  = frameData.GetSampleMetadataAsString(sampleIndex, 2);
     marker.assetName  = frameData.GetSampleMetadataAsString(sampleIndex, 3);
     marker.sourceName = Path.GetFileName(marker.filename);
 }
Beispiel #26
0
        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)
                        {
                            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);
        }
Beispiel #27
0
        public static void PullDataStatic(ref AssetCaptureData captureData, Dictionary <string, AssetMarkerInfo> markers, ref Dictionary <string, int> markerToIDMap, int firstFrameIndex, int lastFrameIndex)
        {
            string error = null;

            var depthStack = new Stack <int>();

            captureData.m_AssetLoadMarkers.Clear();
            captureData.m_StartTimeNs = ulong.MaxValue;
            captureData.m_EndTimeNs   = ulong.MinValue;

            ProfilerFrameDataIterator frameIter = new ProfilerFrameDataIterator();
            double nsFrameStart;

            for (int frameIndex = firstFrameIndex; frameIndex <= lastFrameIndex; ++frameIndex)
            {
                frameIter.SetRoot(frameIndex, 0);

                int threadCount = frameIter.GetThreadCount(frameIndex);

                // iterate over the threads
                for (int threadIndex = 0; threadIndex < threadCount; ++threadIndex)
                {
                    using (RawFrameDataView frameData = ProfilerDriver.GetRawFrameDataView(frameIndex, threadIndex))
                    {
                        if (!frameData.valid)
                        {
                            break;
                        }

                        string fullThreadName = GetFullThreadName(frameData.threadGroupName, frameData.threadName);

                        nsFrameStart = frameData.frameStartTimeNs;
                        if (frameIndex == firstFrameIndex) // This may only need to be done for the main thread, but does the main thread have a guaranteed index?
                        {
                            if (captureData.m_StartTimeNs > nsFrameStart)
                            {
                                captureData.m_StartTimeNs = nsFrameStart; // We will assume that this will only be true for the first frame and thus not be changed, and proceed to use this value as the start time
                            }
                        }

                        GetMarkerIDs(frameData, markers, ref markerToIDMap);

                        depthStack.Clear();
                        // iterate over the samples to collect up any markers
                        int sampleCount = frameData.sampleCount;
                        for (int i = 0; i < sampleCount; ++i)
                        {
                            int markerId = frameData.GetSampleMarkerId(i);

                            if (markerId != FrameDataView.invalidMarkerId && markerToIDMap.ContainsValue(markerId))
                            {
                                s_AddNewMarker.Begin();
                                string markerName = frameData.GetMarkerName(markerId);
                                Assert.IsTrue(markers.ContainsKey(markerName), string.Format("Marker {0} is not present in requested markers.", markerName));

                                // if the marker isn't a continuation of a previous marker, add a new asset load marker
                                if (!CheckForContinuationMarker(frameData, ref captureData, threadIndex, markerId, frameIndex, i))
                                {
                                    AssetLoadMarker assetLoadMarker = new AssetLoadMarker();

                                    // fill in contexts from Metadata
                                    AssetMarkerInfo markerInfo = markers[markerName];
                                    if (markerInfo.metadataCount == frameData.GetSampleMetadataCount(i))
                                    {
                                        markerInfo.metaDataFiller(ref assetLoadMarker, frameData, i);
                                    }
                                    else if (string.IsNullOrEmpty(error)) // Check the error is only shown once
                                    {
                                        error = $"Some markers, such as '{markerName}', have unexpected metadata. This may be because of opening a profile captured with an older version of Unity. Certain values may be missing.";
                                        Debug.LogWarning(error);
                                    }

                                    ulong markerStartTimeNs = frameData.GetSampleStartTimeNs(i);
                                    ulong sampleLengthNs    = frameData.GetSampleTimeNs(i);

                                    assetLoadMarker.markerId = markerId;

                                    if (string.IsNullOrEmpty(assetLoadMarker.filename))
                                    {
                                        assetLoadMarker.readablePath     = "Unknown path";
                                        assetLoadMarker.readableFileName = "?";
                                    }
                                    else
                                    {
                                        assetLoadMarker.readablePath     = assetLoadMarker.filename;
                                        assetLoadMarker.readableFileName = Path.GetFileName(assetLoadMarker.readablePath);
                                        if (assetLoadMarker.readablePath.Contains("/Analytics/"))
                                        {
                                            assetLoadMarker.readableFileName += " (Analytics)";
                                        }
                                    }

                                    assetLoadMarker.startNs  = markerStartTimeNs;
                                    assetLoadMarker.lengthNs = sampleLengthNs;
                                    assetLoadMarker.endNs    = markerStartTimeNs + sampleLengthNs;

                                    assetLoadMarker.startTimeMs = (markerStartTimeNs - captureData.m_StartTimeNs) * 0.000001; // could this go negative?
                                    assetLoadMarker.ms          = assetLoadMarker.lengthNs * 0.000001;
                                    assetLoadMarker.frameCount  = 1;

                                    assetLoadMarker.type            = markerInfo.assetMarkerType;
                                    assetLoadMarker.markerName      = markerName;
                                    assetLoadMarker.threadName      = fullThreadName;
                                    assetLoadMarker.firstFrameIndex = frameIndex;
                                    assetLoadMarker.lastFrameIndex  = frameIndex;
                                    assetLoadMarker.threadIndex     = threadIndex;
                                    assetLoadMarker.threadId        = frameData.threadId;
                                    assetLoadMarker.sampleIds.Add(i);
                                    assetLoadMarker.depth = 1 + depthStack.Count;

                                    captureData.m_AssetLoadMarkers.Add(assetLoadMarker);
                                }

                                s_AddNewMarker.End();
                            }
                            UpdateDepthStack(ref depthStack, frameData.GetSampleChildrenCount(i));
                        }
                    }
                }
            }
            frameIter.Dispose();
        }
Beispiel #28
0
        internal void DrawUIPane(IProfilerWindowController win)
        {
            if (Styles.backgroundStyle == null)
            {
                Styles.CreateStyles();
            }
            //make sure all background textures exist
            Styles.CheckBackgroundTextures();

            EditorGUILayout.BeginVertical();
            var rect = EditorGUILayout.GetControlRect(GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true));

            const int padding = 1;

            Rect aggregateHeader = rect;

            aggregateHeader.width  = Mathf.Min(434, rect.width);
            aggregateHeader.height = 34;

            Rect aggregateData = aggregateHeader;

            aggregateData.y += aggregateHeader.height + padding;
            float aggregateBoxHeight = rect.height / 2 - aggregateHeader.height - padding * 2;

            aggregateData.height = aggregateBoxHeight;

            Rect infoBox = new Rect();

            if (ProfilerDriver.GetStatisticsAvailabilityState(ProfilerArea.VirtualTexturing, win.GetActiveVisibleFrameIndex()) == 0)
            {
                GUI.Label(aggregateHeader, "No Virtual Texturing data was collected.");
                EditorGUILayout.EndVertical();
                return;
            }

            GUI.Box(rect, "", Styles.backgroundStyle);

            using (RawFrameDataView frameDataView = ProfilerDriver.GetRawFrameDataView(win.GetActiveVisibleFrameIndex(), 0))
            {
                if (frameDataView.valid)
                {
                    Assert.IsTrue(frameDataView.threadName == "Main Thread");

                    RawFrameDataView fRender = GetRenderThread(frameDataView);

                    //system statistics
                    var stringBuilder = new StringBuilder(1024);
                    int requiredTiles = (int)GetCounterValue(frameDataView, "Required Tiles");
                    stringBuilder.AppendLine($" Tiles required this frame: {requiredTiles}");
                    stringBuilder.AppendLine($" Max Cache Mip Bias: {GetCounterValueAsFloat(frameDataView, "Max Cache Mip Bias")}");
                    stringBuilder.AppendLine($" Max Cache Demand: {GetCounterValue(frameDataView, "Max Cache Demand")}%");
                    stringBuilder.AppendLine($" Total CPU Cache Size: {EditorUtility.FormatBytes(GetCounterValue(frameDataView, "Total CPU Cache Size"))}");
                    stringBuilder.AppendLine($" Total GPU Cache Size: {EditorUtility.FormatBytes(GetCounterValue(frameDataView, "Total GPU Cache Size"))}");
                    stringBuilder.AppendLine($" Atlases: {GetCounterValue(frameDataView, "Atlases")}");

                    string aggregatedText      = stringBuilder.ToString();
                    float  aggregateTextHeight = EditorStyles.wordWrappedLabel.CalcHeight(GUIContent.Temp(aggregatedText), rect.width);
                    float  actualHeight        = Mathf.Max(aggregateBoxHeight, aggregateTextHeight);

                    DrawScrollBackground(new Rect(aggregateData.width - 12, aggregateData.y, 14, aggregateData.height));
                    GUI.Box(aggregateHeader, " System Statistics", Styles.headerStyle);
                    m_SystemScroll = GUI.BeginScrollView(aggregateData, m_SystemScroll, new Rect(0, 0, aggregateData.width / 2, actualHeight));
                    GUI.Box(new Rect(0, 0, aggregateData.width, actualHeight), aggregatedText, Styles.statStyle);
                    GUI.EndScrollView();

                    //player build statistics
                    aggregateHeader.y += aggregateHeader.height + aggregateData.height + padding * 2;
                    aggregateData.y   += aggregateHeader.height + aggregateData.height + padding * 2;
                    stringBuilder.Clear();
                    stringBuilder.AppendLine($" Missing Disk Data: {EditorUtility.FormatBytes(GetCounterValue(frameDataView, "Missing Disk Data"))}");
                    stringBuilder.AppendLine($" Missing Streaming Tiles: {GetCounterValue(frameDataView, "Missing Streaming Tiles")}");
                    stringBuilder.AppendLine($" Read From Disk: {EditorUtility.FormatBytes(GetCounterValue(frameDataView, "Read From Disk"))}");

                    aggregatedText      = stringBuilder.ToString();
                    aggregateTextHeight = EditorStyles.wordWrappedLabel.CalcHeight(GUIContent.Temp(aggregatedText), rect.width);
                    actualHeight        = Mathf.Max(aggregateBoxHeight, aggregateTextHeight);

                    DrawScrollBackground(new Rect(aggregateData.width - 12, aggregateData.y, 14, aggregateData.height));
                    GUI.Box(aggregateHeader, " Player Build Statistics", Styles.headerStyle);
                    m_PlayerScroll = GUI.BeginScrollView(aggregateData, m_PlayerScroll, new Rect(0, 0, aggregateData.width / 2, actualHeight));
                    GUI.Box(new Rect(0, 0, aggregateData.width, actualHeight), aggregatedText, Styles.statStyle);
                    GUI.EndScrollView();

                    //PER CACHE DATA
                    Rect perCacheHeader = rect;
                    perCacheHeader.width  = rect.width - aggregateHeader.width - padding;
                    perCacheHeader.height = 34;
                    perCacheHeader.x     += aggregateHeader.width + padding;

                    Rect formatBox = perCacheHeader;
                    formatBox.height = rect.height - perCacheHeader.height - padding;
                    formatBox.y     += perCacheHeader.height + padding;

                    GUI.Box(perCacheHeader, "  Per Cache Statistics", Styles.headerStyle);

                    if (m_Header == null || m_HeaderState == null)
                    {
                        Init();
                    }

                    //Keep using the last VT tick untill a new one is available.
                    if (requiredTiles > 0)
                    {
                        ReadFrameData(fRender);
                    }

                    if (m_SortingChanged)
                    {
                        SortFrameData();
                    }
                    DrawFormatData(formatBox);

                    if (fRender != frameDataView)
                    {
                        fRender.Dispose();
                    }
                }
                else
                {
                    GUI.Label(aggregateData, "No frame data available");
                }
            }
            EditorGUILayout.EndVertical();

            infoBox.y      = rect.y;
            infoBox.x      = rect.width - 33;
            infoBox.width  = 34;
            infoBox.height = 34;

            DrawDocLink(infoBox);
        }
        public void DoGUI(HierarchyFrameDataView frameDataView, bool fetchData, ref bool updateViewLive, ProfilerViewType viewType)
        {
            using (m_DoGUIMarker.Auto())
            {
                if (Event.current.type != EventType.Layout && m_ThreadIndexDuringLastNonLayoutEvent != threadIndexInThreadNames)
                {
                    m_ThreadIndexDuringLastNonLayoutEvent = threadIndexInThreadNames;
                    EditorGUIUtility.ExitGUI();
                }
                InitIfNeeded();

                var isSearchAllowed = string.IsNullOrEmpty(treeView.searchString) || !(m_ProfilerWindow.ProfilerWindowOverheadIsAffectingProfilingRecordingData() && ProfilerDriver.deepProfiling);

                var isDataAvailable = frameDataView != null && frameDataView.valid;

                var showDetailedView = isDataAvailable && m_DetailedViewType != DetailedViewType.None;
                if (showDetailedView)
                {
                    SplitterGUILayout.BeginHorizontalSplit(m_DetailedViewSpliterState);
                }

                // Hierarchy view area
                GUILayout.BeginVertical();

                if (isDataAvailable && (threadIndex != frameDataView.threadIndex || threadName != frameDataView.threadName))
                {
                    SetFrameDataView(frameDataView);
                }

                DrawToolbar(frameDataView, showDetailedView, ref updateViewLive, viewType);

                if (!string.IsNullOrEmpty(dataAvailabilityMessage))
                {
                    GUILayout.Label(dataAvailabilityMessage, BaseStyles.label);
                }
                else if (!isDataAvailable)
                {
                    if (!fetchData && !updateViewLive)
                    {
                        GUILayout.Label(BaseStyles.liveUpdateMessage, BaseStyles.label);
                    }
                    else
                    {
                        GUILayout.Label(BaseStyles.noData, BaseStyles.label);
                    }
                }
                else if (!isSearchAllowed)
                {
                    GUILayout.Label(BaseStyles.disabledSearchText, BaseStyles.label);
                }
                else
                {
                    var rect = GUILayoutUtility.GetRect(GUIContent.none, GUIStyle.none, GUILayout.ExpandHeight(true), GUILayout.ExpandHeight(true));

                    m_TreeView.SetFrameDataView(frameDataView);
                    m_TreeView.OnGUI(rect, updateViewLive);

                    if (m_TreeView.HasSelection() && m_TreeView.proxySelectionInfo.hasProxySelection)
                    {
                        if (m_TreeView.proxySelectionInfo.cachedDisplayContent == null)
                        {
                            var diff = Math.Abs(m_TreeView.proxySelectionInfo.pathLengthDifferenceForProxy);
                            m_TreeView.proxySelectionInfo.cachedDisplayContent = new GUIContent(
                                BaseStyles.selectionExtraInfoHierarhcyView + string.Format(
                                    BaseStyles.proxySampleMessage,
                                    m_TreeView.proxySelectionInfo.nonProxyName, diff,
                                    diff == 1 ? BaseStyles.proxySampleMessageScopeSingular : BaseStyles.proxySampleMessageScopePlural),
                                BaseStyles.warningTriangle.image);
                        }
                        GUILayout.BeginHorizontal();
                        GUILayout.Box(m_TreeView.proxySelectionInfo.cachedDisplayContent, BaseStyles.selectionExtraInfoArea);
                        var rectForSampleStackButton = GUILayoutUtility.GetRect(BaseStyles.showDetailsDropdownContent, BaseStyles.tooltipDropdown, GUILayout.ExpandHeight(false), GUILayout.ExpandHeight(false));
                        if (GUI.Button(rectForSampleStackButton, BaseStyles.showDetailsDropdownContent, BaseStyles.tooltipDropdown))
                        {
                            var selection  = m_TreeView.GetSelection();
                            var selectedId = (selection != null && selection.Count > 0) ? selection[0] : ProfilerFrameDataHierarchyView.invalidTreeViewId;
                            if (selectedId >= 0)
                            {
                                var menu = new GenericMenu();

                                // Show Sample Selection:
                                var rawSampleIndices = new List <int>(frameDataView.GetItemMergedSamplesCount(selectedId));
                                frameDataView.GetItemRawFrameDataViewIndices(selectedId, rawSampleIndices);
                                var actualMarkerIdPath = new List <int>(frameDataView.GetItemDepth(selectedId));
                                using (var iterator = new RawFrameDataView(frameDataView.frameIndex, frameDataView.threadIndex))
                                {
                                    string name     = null;
                                    var    rawIndex = ProfilerTimelineGUI.GetItemMarkerIdPath(iterator, cpuModule, rawSampleIndices[0], ref name, ref actualMarkerIdPath);
                                }

                                var actualMarkerPath = new List <string>(actualMarkerIdPath.Count);
                                foreach (var id in actualMarkerIdPath)
                                {
                                    if ((frameDataView.GetMarkerFlags(id) & Unity.Profiling.LowLevel.MarkerFlags.AvailabilityEditor) != 0)
                                    {
                                        actualMarkerPath.Add(string.Format("EditorOnly [{0}]", frameDataView.GetMarkerName(id)));
                                    }
                                    else
                                    {
                                        actualMarkerPath.Add(frameDataView.GetMarkerName(id));
                                    }
                                }

                                // admittedly, it'd be nice to only generate the text if sample selection option was chosen...
                                // however, that would need to happen in an OnGui call and not within the callback of the generic menu,
                                // to be able to calculate the needed window size and avoid glitches on first displaying it.
                                // at least the user already clicked on the dropdown for this...

                                string selectedSampleStackText = null;
                                var    sampleStackSb           = new System.Text.StringBuilder();
                                if (m_TreeView.proxySelectionInfo.nonProxySampleStack != null && m_TreeView.proxySelectionInfo.nonProxySampleStack.Count > 0)
                                {
                                    for (int i = m_TreeView.proxySelectionInfo.nonProxySampleStack.Count - 1; i >= 0; i--)
                                    {
                                        sampleStackSb.AppendLine(m_TreeView.proxySelectionInfo.nonProxySampleStack[i]);
                                    }
                                    selectedSampleStackText = sampleStackSb.ToString();
                                }
                                string actualSampleStackText = null;
                                if (actualMarkerPath != null && actualMarkerPath.Count > 0)
                                {
                                    sampleStackSb.Clear();

                                    for (int i = actualMarkerPath.Count - 1; i >= 0; i--)
                                    {
                                        sampleStackSb.AppendLine(actualMarkerPath[i]);
                                    }
                                    actualSampleStackText = sampleStackSb.ToString();
                                }

                                var selectionSampleStackContent = selectedSampleStackText != null ? new GUIContent(selectedSampleStackText) : null;
                                var actualSampleStackContent    = actualSampleStackText != null ? new GUIContent(actualSampleStackText) : null;
                                var sampleStackWindowSize       = SelectedSampleStackWindow.CalculateSize(selectionSampleStackContent, actualSampleStackContent);
                                menu.AddItem(BaseStyles.showSelectedSampleStacks, false, () =>
                                {
                                    SelectedSampleStackWindow.ShowSampleStackWindow(GUIUtility.GUIToScreenRect(rectForSampleStackButton).position, sampleStackWindowSize, selectionSampleStackContent, actualSampleStackContent);
                                });
                                menu.DropDown(rectForSampleStackButton);
                            }
                        }
                        GUILayout.EndHorizontal();
                    }
                }

                GUILayout.EndVertical();

                if (showDetailedView)
                {
                    GUILayout.BeginVertical();

                    // Detailed view area
                    EditorGUILayout.BeginHorizontal(BaseStyles.toolbar);

                    DrawDetailedViewPopup();
                    GUILayout.FlexibleSpace();

                    cpuModule.DrawOptionsMenuPopup();
                    EditorGUILayout.EndHorizontal();

                    switch (m_DetailedViewType)
                    {
                    case DetailedViewType.Objects:
                        detailedObjectsView.DoGUI(BaseStyles.header, frameDataView, m_TreeView.GetSelection());
                        break;

                    case DetailedViewType.CallersAndCallees:
                        detailedCallsView.DoGUI(BaseStyles.header, frameDataView, m_TreeView.GetSelection());
                        break;
                    }

                    GUILayout.EndVertical();

                    SplitterGUILayout.EndHorizontalSplit();
                }

                HandleKeyboardEvents();
            }
        }
Beispiel #30
0
        public static void PullDataStatic(ref FileAccessCaptureData captureData, Dictionary <string, FileAccessMarkerInfo> markers, ref Dictionary <string, int> markerToIDMap, int firstFrameIndex, int lastFrameIndex)
        {
            string error = null;

            captureData.m_FileAccessData.Clear();
            captureData.m_StartTimeNs = ulong.MaxValue;
            captureData.m_EndTimeNs   = ulong.MinValue;

            ProfilerFrameDataIterator frameIter = new ProfilerFrameDataIterator();
            double nsFrameStart;

            for (int frameIndex = firstFrameIndex; frameIndex <= lastFrameIndex; ++frameIndex)
            {
                frameIter.SetRoot(frameIndex, 0);

                int threadCount = frameIter.GetThreadCount(frameIndex);
                // iterate over the threads
                for (int threadIndex = 0; threadIndex < threadCount; ++threadIndex)
                {
                    using (RawFrameDataView frameData = ProfilerDriver.GetRawFrameDataView(frameIndex, threadIndex))
                    {
                        if (!frameData.valid)
                        {
                            break;
                        }

                        nsFrameStart = frameData.frameStartTimeNs;
                        if (frameIndex == firstFrameIndex)
                        {
                            if (captureData.m_StartTimeNs > nsFrameStart)
                            {
                                captureData.m_StartTimeNs = nsFrameStart;
                            }
                        }

                        GetMarkerIDs(frameData, markers, ref markerToIDMap);

                        string fullThreadName = GetFullThreadName(frameData.threadGroupName, frameData.threadName);

                        // iterate over the samples to collect up any markers
                        int sampleCount = frameData.sampleCount;
                        for (int i = 0; i < sampleCount; ++i)
                        {
                            s_CheckSamples.Begin();
                            int markerId = frameData.GetSampleMarkerId(i);
                            if (markerId == FrameDataView.invalidMarkerId || !markerToIDMap.ContainsValue(markerId))
                            {
                                s_CheckSamples.End();
                                continue;
                            }

                            string markerName = frameData.GetMarkerName(markerId);
                            Assert.IsTrue(markers.ContainsKey(markerName), string.Format("Marker {0} is not present in requested markers.", markerName));

                            s_CheckSamples.End();

                            s_AddNewMarker.Begin();

                            ulong markerStartTimeNs = Math.Max(frameData.GetSampleStartTimeNs(i) - (ulong)captureData.m_StartTimeNs, 0);
                            ulong sampleLengthNs    = frameData.GetSampleTimeNs(i);

                            // if the marker isn't a continuation of a previous marker, add a new access
                            if (!CheckForContinuationMarker(frameData, ref captureData, threadIndex, markerId, frameIndex, i, markerStartTimeNs, sampleLengthNs))
                            {
                                FileAccessMarker fileAccessMarker = new FileAccessMarker(frameIndex, threadIndex, i);

                                // fill in contexts from Metadata
                                FileAccessMarkerInfo markerInfo = markers[markerName];
                                if (markerInfo.metadataCount == frameData.GetSampleMetadataCount(i))
                                {
                                    markerInfo.metaDataFiller(ref fileAccessMarker, frameData, i);
                                }
                                else if (error == null) // Check the error is only shown once
                                {
                                    error = $"Some markers, such as '{markerName}', have unexpected metadata. This may be because of opening a profile captured with an older version of Unity. Certain values may be missing.";
                                    Debug.LogWarning(error);
                                }

                                if (string.IsNullOrEmpty(fileAccessMarker.filename))
                                {
                                    fileAccessMarker.readablePath     = "Unknown path";
                                    fileAccessMarker.readableFileName = "?";
                                }
                                else
                                {
                                    fileAccessMarker.readablePath     = fileAccessMarker.filename;
                                    fileAccessMarker.readableFileName = Path.GetFileName(fileAccessMarker.readablePath);
                                    if (fileAccessMarker.readablePath.Contains("/Analytics/"))
                                    {
                                        fileAccessMarker.readableFileName += " (Analytics)";
                                    }
                                }

                                fileAccessMarker.startNs  = markerStartTimeNs;
                                fileAccessMarker.lengthNs = sampleLengthNs;
                                fileAccessMarker.endNs    = markerStartTimeNs + sampleLengthNs;

                                fileAccessMarker.startTimeMs = markerStartTimeNs * 0.000001;
                                fileAccessMarker.ms          = fileAccessMarker.lengthNs * 0.000001;

                                fileAccessMarker.markerId   = markerId;
                                fileAccessMarker.type       = markerInfo.fileAccessType;
                                fileAccessMarker.markerName = markerName;
                                fileAccessMarker.threadName = fullThreadName;
                                fileAccessMarker.threadId   = frameData.threadId;

                                captureData.m_FileAccessData.Add(fileAccessMarker);
                            }
                            s_AddNewMarker.End();
                        }
                    }
                }
            }

            foreach (var fileAccessMarker in captureData.m_FileAccessData)
            {
                fileAccessMarker.averageBandwidthMBps = (fileAccessMarker.ms > 0) ? ((float)fileAccessMarker.sizeBytes / (float)fileAccessMarker.ms) * 0.001f : 0.0f;
            }

            frameIter.Dispose();
        }