unity/EditorPlugin/Profiler/Adapters/ReflectionBasedAdapters/SnapshotAnalysis/RawFrameDataViewAdapter.cs (271 lines of code) (raw):
#nullable enable
using System;
using JetBrains.Diagnostics;
using JetBrains.Rider.Unity.Editor.Profiler.Adapters.Interfaces;
namespace JetBrains.Rider.Unity.Editor.Profiler.Adapters.ReflectionBasedAdapters.SnapshotAnalysis
{
internal class RawFrameDataViewAdapter : IRawFrameDataViewAdapter
{
private static readonly ILog ourLogger = Log.GetLog(nameof(RawFrameDataViewAdapter));
private readonly object? myRawFrameDataViewObject;
private readonly RawFrameDataViewReflectionData? myReflectionData;
private readonly int? myGCAllocMarkerId;
// Cached reflection parameter arrays for common method calls
private readonly object[] mySingleIntParameterArray = new object[1];
private readonly object[] myTwoIntParametersArray = new object[2];
internal RawFrameDataViewAdapter(object? rawFrameDataViewObject, RawFrameDataViewReflectionData? reflectionData)
{
myRawFrameDataViewObject = rawFrameDataViewObject;
myReflectionData = reflectionData;
if (myReflectionData == null)
{
ourLogger.Verbose($"{nameof(myReflectionData)} is null.");
return;
}
if (!myReflectionData.IsValid())
{
ourLogger.Verbose($"{myReflectionData.GetType().Name} is not valid.");
return;
}
// Initialize GC allocation marker ID in constructor
try
{
myGCAllocMarkerId = (int)myReflectionData.GetMarkerIdMethod.Invoke(myRawFrameDataViewObject, new object[] { "GC.Alloc" });
}
catch (Exception ex)
{
ourLogger.Verbose($"Failed to initialize GC allocation marker ID: {ex}");
myGCAllocMarkerId = -1;
}
}
public void Dispose()
{
try
{
var rawFrameDataViewObject = myRawFrameDataViewObject as IDisposable;
rawFrameDataViewObject?.Dispose();
}
catch (Exception e)
{
ourLogger.Verbose($"{nameof(myRawFrameDataViewObject)} dispose error: {e}.");
}
}
public double GetSampleTimeMs(int sampleIndex)
{
if (myReflectionData == null)
{
ourLogger.Verbose($"Can't get {nameof(GetSampleTimeMs)}: {nameof(myReflectionData)} is null.");
return -1;
}
try
{
mySingleIntParameterArray[0] = sampleIndex;
return (float)myReflectionData.GetSampleTimeMsMethod.Invoke(myRawFrameDataViewObject, mySingleIntParameterArray);
}
catch (Exception ex)
{
ourLogger.Verbose($"Error invoking {nameof(myReflectionData.GetSampleTimeMsMethod)}: {ex}");
return -1;
}
}
public int GetSampleMarkerId(int index)
{
if (myReflectionData == null)
{
ourLogger.Verbose($"Can't get {nameof(GetSampleMarkerId)}: {nameof(myReflectionData)} is null.");
return -1;
}
try
{
mySingleIntParameterArray[0] = index;
return (int)myReflectionData.GetSampleMarkerIdMethod.Invoke(myRawFrameDataViewObject, mySingleIntParameterArray);
}
catch (Exception ex)
{
ourLogger.Verbose("Failed to invoke GetSampleMarkerId", ex);
return -1;
}
}
public int GetSampleChildrenCount(int index)
{
if (myReflectionData == null)
{
ourLogger.Verbose($"Can't get {nameof(GetSampleChildrenCount)}: {nameof(myReflectionData)} is null.");
return -1;
}
try
{
mySingleIntParameterArray[0] = index;
return (int)myReflectionData.GetSampleChildrenCountMethod.Invoke(myRawFrameDataViewObject, mySingleIntParameterArray);
}
catch (Exception ex)
{
ourLogger.Verbose("Failed to invoke GetSampleChildrenCount", ex);
return -1;
}
}
public string GetSampleName(int index)
{
if (myReflectionData == null)
{
ourLogger.Verbose($"Can't get {nameof(GetSampleName)}: {nameof(myReflectionData)} is null.");
return string.Empty;
}
try
{
return (string)myReflectionData.GetSampleNameMethod.Invoke(myRawFrameDataViewObject, new object[] { index });
}
catch (Exception ex)
{
ourLogger.Verbose("Failed to invoke GetSampleName", ex);
return string.Empty;
}
}
public double FrameStartTimeMs
{
get
{
if (myReflectionData == null)
{
ourLogger.Verbose($"Can't get {nameof(FrameStartTimeMs)}: {nameof(myReflectionData)} is null.");
return -1;
}
try
{
return (double)myReflectionData.FrameStartTimeMsProperty.GetValue(myRawFrameDataViewObject);
}
catch (Exception ex)
{
ourLogger.Verbose("Failed to access FrameStartTimeMsProperty", ex);
return -1;
}
}
}
public float FrameTimeMs
{
get
{
if (myReflectionData == null)
{
ourLogger.Verbose($"Can't get {nameof(FrameTimeMs)}: {nameof(myReflectionData)} is null.");
return -1;
}
try
{
return (float)myReflectionData.FrameTimeMsProperty.GetValue(myRawFrameDataViewObject);
}
catch (Exception ex)
{
ourLogger.Verbose("Failed to access FrameTimeMsProperty", ex);
return -1;
}
}
}
public int SampleCount
{
get
{
if (myReflectionData == null)
{
ourLogger.Verbose($"Can't get {nameof(SampleCount)}: {nameof(myReflectionData)} is null.");
return -1;
}
try
{
return (int)myReflectionData.SampleCountProperty.GetValue(myRawFrameDataViewObject);
}
catch (Exception ex)
{
ourLogger.Verbose("Failed to access SampleCountProperty", ex);
return -1;
}
}
}
public string ThreadName
{
get
{
if (myReflectionData == null)
{
ourLogger.Verbose($"Can't get {nameof(ThreadName)}: {nameof(myReflectionData)} is null.");
return string.Empty;
}
try
{
return (string)myReflectionData.ThreadNameProperty.GetValue(myRawFrameDataViewObject);
}
catch (Exception ex)
{
ourLogger.Verbose($"Failed to access {nameof(myReflectionData.ThreadNameProperty)}", ex);
return string.Empty;
}
}
}
public int ThreadIndex
{
get
{
if (myReflectionData == null)
{
ourLogger.Verbose($"Can't get {nameof(ThreadIndex)}: {nameof(myReflectionData)} is null.");
return -1;
}
try
{
return (int)myReflectionData.ThreadIndexProperty.GetValue(myRawFrameDataViewObject);
}
catch (Exception ex)
{
ourLogger.Verbose($"Failed to access {nameof(myReflectionData.ThreadIndexProperty)}", ex);
return -1;
}
}
}
public bool Valid
{
get
{
if (myReflectionData == null)
{
ourLogger.Verbose($"Can't get {nameof(Valid)}: {nameof(myReflectionData)} is null.");
return false;
}
try
{
return (bool)myReflectionData.ValidProperty.GetValue(myRawFrameDataViewObject);
}
catch (Exception ex)
{
ourLogger.Verbose($"Failed to access {nameof(myReflectionData.ValidProperty)}", ex);
return false;
}
}
}
public long GetAllocSize(int sampleIndex)
{
if (myReflectionData == null || !myGCAllocMarkerId.HasValue)
{
ourLogger.Verbose($"Can't get {nameof(GetAllocSize)}: required data is not available.");
return 0;
}
// Early return if GC allocation marker ID is not found
if (myGCAllocMarkerId.Value == -1)
return 0;
try
{
// Get the sample marker ID first to avoid unnecessary metadata count check
var sampleMarkerId = GetSampleMarkerId(sampleIndex);
// Early return if the marker ID doesn't match the GC allocation marker ID
if (sampleMarkerId != myGCAllocMarkerId.Value)
return 0;
// Check if the sample has metadata
mySingleIntParameterArray[0] = sampleIndex;
var sampleMetadataCount = (int)myReflectionData.GetSampleMetadataCountMethod.Invoke(myRawFrameDataViewObject, mySingleIntParameterArray);
if (sampleMetadataCount == 0)
return 0;
// Get the allocation size
myTwoIntParametersArray[0] = sampleIndex;
myTwoIntParametersArray[1] = 0;
return (long)myReflectionData.GetSampleMetadataAsLongMethod.Invoke(myRawFrameDataViewObject, myTwoIntParametersArray);
}
catch (Exception ex)
{
ourLogger.Verbose($"Error in {nameof(GetAllocSize)}: {ex}");
return 0;
}
}
}
}