mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-04-18 13:29:22 -04:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
1317 lines
31 KiB
C#
1317 lines
31 KiB
C#
// Copyright (c) Alexandre Mutel. All rights reserved.
|
|
// Licensed under the BSD-Clause 2 license.
|
|
// See license.txt file in the project root for full license information.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
using System.Text.Json.Serialization.Metadata;
|
|
|
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
#nullable enable
|
|
|
|
// ReSharper disable InconsistentNaming
|
|
|
|
namespace Sandbox;
|
|
|
|
/// <summary>
|
|
/// The Firefox profiler JSON format.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This file was manually converted from https://github.com/xoofx/firefox-profiler/blob/main/src/types/profile.js
|
|
/// </remarks>
|
|
public static partial class FirefoxProfiler
|
|
{
|
|
[JsonSourceGenerationOptions(
|
|
WriteIndented = false, // Set to true when debugging
|
|
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
|
//Converters = [
|
|
// //typeof(KebabCaseEnumConverter<MarkerDisplayLocation>),
|
|
// //typeof(KebabCaseEnumConverter<MarkerGraphType>),
|
|
// //typeof(MarkerPayloadConverter),
|
|
// //typeof(ProfileColorEnumConverter)
|
|
// ]
|
|
)
|
|
]
|
|
[JsonSerializable( typeof( Profile ) )]
|
|
[JsonSerializable( typeof( MarkerTableFormatType ) )]
|
|
//[JsonSerializable(typeof(MarkerDisplayLocation))]
|
|
//[JsonSerializable(typeof(MarkerGraphType))]
|
|
//[JsonSerializable(typeof(ProfileColor))]
|
|
public partial class JsonProfilerContext : JsonSerializerContext
|
|
{
|
|
}
|
|
|
|
public class StackTable
|
|
{
|
|
public StackTable()
|
|
{
|
|
Frame = new List<int>();
|
|
Category = new List<int?>();
|
|
Subcategory = new List<int?>();
|
|
Prefix = new List<int?>();
|
|
}
|
|
|
|
public List<int> Frame { get; set; }
|
|
|
|
public List<int?> Category { get; set; }
|
|
|
|
public List<int?> Subcategory { get; set; }
|
|
|
|
public List<int?> Prefix { get; set; }
|
|
|
|
public int Length { get; set; }
|
|
}
|
|
|
|
public abstract class SamplesLikeTable
|
|
{
|
|
public SamplesLikeTable()
|
|
{
|
|
Stack = new List<int?>();
|
|
}
|
|
|
|
public List<int?> Stack { get; set; }
|
|
|
|
public List<double>? Time { get; set; }
|
|
|
|
public List<double>? TimeDeltas { get; set; }
|
|
|
|
public List<int>? Weight { get; set; }
|
|
|
|
public string WeightType { get; set; } = string.Empty;
|
|
|
|
public int Length { get; set; }
|
|
}
|
|
|
|
public class SamplesTable : SamplesLikeTable
|
|
{
|
|
public SamplesTable()
|
|
{
|
|
}
|
|
|
|
public List<double?>? Responsiveness { get; set; }
|
|
|
|
public List<double?>? EventDelay { get; set; }
|
|
|
|
public List<int?>? ThreadCPUDelta { get; set; }
|
|
|
|
public List<int>? ThreadId { get; set; }
|
|
}
|
|
|
|
public class JsAllocationsTable : SamplesLikeTable
|
|
{
|
|
public JsAllocationsTable()
|
|
{
|
|
ClassName = new List<string>();
|
|
TypeName = new List<string>();
|
|
CoarseType = new List<string>();
|
|
InNursery = new List<bool>();
|
|
}
|
|
|
|
public List<string> ClassName { get; set; }
|
|
|
|
public List<string> TypeName { get; set; }
|
|
|
|
public List<string> CoarseType { get; set; }
|
|
|
|
public List<bool> InNursery { get; set; }
|
|
}
|
|
|
|
public class RawMarkerTable
|
|
{
|
|
public RawMarkerTable()
|
|
{
|
|
Data = new List<MarkerPayload?>();
|
|
Name = new List<int>();
|
|
StartTime = new List<double?>();
|
|
EndTime = new List<double?>();
|
|
Phase = new List<MarkerPhase>();
|
|
Category = new List<int>();
|
|
ThreadId = new List<int>();
|
|
}
|
|
|
|
public List<MarkerPayload?> Data { get; set; }
|
|
|
|
public List<int> Name { get; set; }
|
|
|
|
public List<double?> StartTime { get; set; }
|
|
|
|
public List<double?> EndTime { get; set; }
|
|
|
|
public List<MarkerPhase> Phase { get; set; }
|
|
|
|
public List<int> Category { get; set; }
|
|
|
|
public List<int> ThreadId { get; set; }
|
|
|
|
public int Length { get; set; }
|
|
}
|
|
|
|
public enum MarkerPhase
|
|
{
|
|
Instance = 0,
|
|
Interval = 1,
|
|
IntervalStart = 2,
|
|
IntervalEnd = 3,
|
|
}
|
|
|
|
public class FrameTable
|
|
{
|
|
public FrameTable()
|
|
{
|
|
Address = new List<int>();
|
|
InlineDepth = new List<int>();
|
|
Category = new List<int?>();
|
|
Subcategory = new List<int?>();
|
|
Func = new List<int>();
|
|
NativeSymbol = new List<int?>();
|
|
InnerWindowID = new List<int?>();
|
|
Implementation = new List<int?>();
|
|
Line = new List<int?>();
|
|
Column = new List<int?>();
|
|
}
|
|
|
|
public List<int> Address { get; set; }
|
|
|
|
public List<int> InlineDepth { get; set; }
|
|
|
|
public List<int?> Category { get; set; }
|
|
|
|
public List<int?> Subcategory { get; set; }
|
|
|
|
public List<int> Func { get; set; }
|
|
|
|
public List<int?> NativeSymbol { get; set; }
|
|
|
|
public List<int?> InnerWindowID { get; set; }
|
|
|
|
public List<int?> Implementation { get; set; }
|
|
|
|
public List<int?> Line { get; set; }
|
|
|
|
public List<int?> Column { get; set; }
|
|
|
|
public int Length { get; set; }
|
|
}
|
|
|
|
public class FuncTable
|
|
{
|
|
public FuncTable()
|
|
{
|
|
Name = new List<int>();
|
|
IsJS = new List<bool>();
|
|
RelevantForJS = new List<bool>();
|
|
Resource = new List<int>();
|
|
FileName = new List<int?>();
|
|
LineNumber = new List<int?>();
|
|
ColumnNumber = new List<int?>();
|
|
}
|
|
|
|
public List<int> Name { get; set; }
|
|
|
|
public List<bool> IsJS { get; set; }
|
|
|
|
public List<bool> RelevantForJS { get; set; }
|
|
|
|
public List<int> Resource { get; set; }
|
|
|
|
public List<int?> FileName { get; set; }
|
|
|
|
public List<int?> LineNumber { get; set; }
|
|
|
|
public List<int?> ColumnNumber { get; set; }
|
|
|
|
public int Length { get; set; }
|
|
}
|
|
|
|
public class NativeSymbolTable
|
|
{
|
|
public NativeSymbolTable()
|
|
{
|
|
LibIndex = new List<int>();
|
|
Address = new List<int>();
|
|
Name = new List<int>();
|
|
FunctionSize = new List<int?>();
|
|
}
|
|
|
|
public List<int> LibIndex { get; set; }
|
|
|
|
public List<int> Address { get; set; }
|
|
|
|
public List<int> Name { get; set; }
|
|
|
|
public List<int?> FunctionSize { get; set; }
|
|
|
|
public int Length { get; set; }
|
|
}
|
|
|
|
public class ResourceTable
|
|
{
|
|
public ResourceTable()
|
|
{
|
|
Lib = new List<int?>();
|
|
Name = new List<int>();
|
|
Host = new List<int?>();
|
|
Type = new List<int>();
|
|
}
|
|
|
|
public List<int?> Lib { get; set; }
|
|
|
|
public List<int> Name { get; set; }
|
|
|
|
public List<int?> Host { get; set; }
|
|
|
|
public List<int> Type { get; set; }
|
|
|
|
public int Length { get; set; }
|
|
}
|
|
|
|
public class Lib
|
|
{
|
|
public Lib()
|
|
{
|
|
Arch = string.Empty;
|
|
Name = string.Empty;
|
|
Path = string.Empty;
|
|
DebugName = string.Empty;
|
|
DebugPath = string.Empty;
|
|
BreakpadId = string.Empty;
|
|
}
|
|
|
|
public ulong? AddressStart { get; set; }
|
|
|
|
public ulong? AddressEnd { get; set; }
|
|
|
|
public ulong? AddressOffset { get; set; }
|
|
|
|
public string Arch { get; set; }
|
|
|
|
public string Name { get; set; }
|
|
|
|
public string Path { get; set; }
|
|
|
|
public string DebugName { get; set; }
|
|
|
|
public string DebugPath { get; set; }
|
|
|
|
public string BreakpadId { get; set; }
|
|
|
|
public string? CodeId { get; set; }
|
|
}
|
|
|
|
public class Category
|
|
{
|
|
public Category()
|
|
{
|
|
Name = string.Empty;
|
|
Color = ProfileColor.Grey;
|
|
Subcategories = new List<string>();
|
|
}
|
|
|
|
public string Name { get; set; }
|
|
|
|
public ProfileColor Color { get; set; }
|
|
|
|
public List<string> Subcategories { get; set; }
|
|
}
|
|
|
|
public class Page
|
|
{
|
|
public Page()
|
|
{
|
|
Url = string.Empty;
|
|
}
|
|
|
|
public int TabID { get; set; }
|
|
|
|
public int InnerWindowID { get; set; }
|
|
|
|
public string Url { get; set; }
|
|
|
|
public int EmbedderInnerWindowID { get; set; }
|
|
|
|
public bool? IsPrivateBrowsing { get; set; }
|
|
|
|
public string? Favicon { get; set; }
|
|
}
|
|
|
|
public class PausedRange
|
|
{
|
|
public double? StartTime { get; set; }
|
|
|
|
public double? EndTime { get; set; }
|
|
|
|
public string Reason { get; set; } = string.Empty;
|
|
}
|
|
|
|
public class ProfilerConfiguration
|
|
{
|
|
public ProfilerConfiguration()
|
|
{
|
|
Threads = new List<string>();
|
|
Features = new List<string>();
|
|
}
|
|
|
|
public List<string> Threads { get; set; }
|
|
|
|
public List<string> Features { get; set; }
|
|
|
|
public int Capacity { get; set; }
|
|
|
|
public int? Duration { get; set; }
|
|
|
|
public int? ActiveTabID { get; set; }
|
|
}
|
|
|
|
public class VisualMetrics
|
|
{
|
|
public VisualMetrics()
|
|
{
|
|
VisualProgress = new List<ProgressGraphData>();
|
|
ContentfulSpeedIndexProgress = new List<ProgressGraphData>();
|
|
PerceptualSpeedIndexProgress = new List<ProgressGraphData>();
|
|
}
|
|
|
|
[JsonPropertyName( "FirstVisualChange" )]
|
|
public int FirstVisualChange { get; set; }
|
|
|
|
[JsonPropertyName( "LastVisualChange" )]
|
|
public int LastVisualChange { get; set; }
|
|
|
|
[JsonPropertyName( "SpeedIndex" )]
|
|
public int SpeedIndex { get; set; }
|
|
|
|
[JsonPropertyName( "VisualProgress" )]
|
|
public List<ProgressGraphData> VisualProgress { get; set; }
|
|
|
|
[JsonPropertyName( "ContentfulSpeedIndex" )]
|
|
public int? ContentfulSpeedIndex { get; set; }
|
|
|
|
[JsonPropertyName( "ContentfulSpeedIndexProgress" )]
|
|
public List<ProgressGraphData> ContentfulSpeedIndexProgress { get; set; }
|
|
|
|
[JsonPropertyName( "PerceptualSpeedIndex" )]
|
|
public int? PerceptualSpeedIndex { get; set; }
|
|
|
|
[JsonPropertyName( "PerceptualSpeedIndexProgress" )]
|
|
public List<ProgressGraphData> PerceptualSpeedIndexProgress { get; set; }
|
|
|
|
[JsonPropertyName( "VisualReadiness" )]
|
|
public int VisualReadiness { get; set; }
|
|
|
|
[JsonPropertyName( "VisualComplete85" )]
|
|
public int VisualComplete85 { get; set; }
|
|
|
|
[JsonPropertyName( "VisualComplete95" )]
|
|
public int VisualComplete95 { get; set; }
|
|
|
|
[JsonPropertyName( "VisualComplete99" )]
|
|
public int VisualComplete99 { get; set; }
|
|
}
|
|
|
|
public class ProgressGraphData
|
|
{
|
|
public int Percent { get; set; }
|
|
|
|
public double? Timestamp { get; set; }
|
|
}
|
|
|
|
public class ProfilerOverheadStats
|
|
{
|
|
public int MaxCleaning { get; set; }
|
|
|
|
public int MaxCounter { get; set; }
|
|
|
|
public int MaxInterval { get; set; }
|
|
|
|
public int MaxLockings { get; set; }
|
|
|
|
public int MaxOverhead { get; set; }
|
|
|
|
public int MaxThread { get; set; }
|
|
|
|
public int MeanCleaning { get; set; }
|
|
|
|
public int MeanCounter { get; set; }
|
|
|
|
public int MeanInterval { get; set; }
|
|
|
|
public int MeanLockings { get; set; }
|
|
|
|
public int MeanOverhead { get; set; }
|
|
|
|
public int MeanThread { get; set; }
|
|
|
|
public int MinCleaning { get; set; }
|
|
|
|
public int MinCounter { get; set; }
|
|
|
|
public int MinInterval { get; set; }
|
|
|
|
public int MinLockings { get; set; }
|
|
|
|
public int MinOverhead { get; set; }
|
|
|
|
public int MinThread { get; set; }
|
|
|
|
public int OverheadDurations { get; set; }
|
|
|
|
public int OverheadPercentage { get; set; }
|
|
|
|
public int ProfiledDuration { get; set; }
|
|
|
|
public int SamplingCount { get; set; }
|
|
}
|
|
|
|
public class ProfilerOverheadSamplesTable
|
|
{
|
|
public ProfilerOverheadSamplesTable()
|
|
{
|
|
Counters = new List<int>();
|
|
ExpiredMarkerCleaning = new List<int>();
|
|
Locking = new List<int>();
|
|
Threads = new List<int>();
|
|
Time = new List<int>();
|
|
}
|
|
|
|
public List<int> Counters { get; set; }
|
|
|
|
public List<int> ExpiredMarkerCleaning { get; set; }
|
|
|
|
public List<int> Locking { get; set; }
|
|
|
|
public List<int> Threads { get; set; }
|
|
|
|
public List<int> Time { get; set; }
|
|
|
|
public int Length { get; set; }
|
|
}
|
|
|
|
public class ProfilerOverhead
|
|
{
|
|
public ProfilerOverhead()
|
|
{
|
|
Samples = new ProfilerOverheadSamplesTable();
|
|
Pid = string.Empty;
|
|
}
|
|
|
|
public ProfilerOverheadSamplesTable Samples { get; set; }
|
|
|
|
public ProfilerOverheadStats? Statistics { get; set; }
|
|
|
|
public string Pid { get; set; }
|
|
|
|
public int MainThreadIndex { get; set; }
|
|
}
|
|
|
|
public class Thread
|
|
{
|
|
public Thread()
|
|
{
|
|
PausedRanges = new List<PausedRange>();
|
|
Name = string.Empty;
|
|
Samples = new SamplesTable();
|
|
Markers = new RawMarkerTable();
|
|
StackTable = new StackTable();
|
|
FrameTable = new FrameTable();
|
|
StringArray = new List<string>();
|
|
FuncTable = new FuncTable();
|
|
ResourceTable = new ResourceTable();
|
|
NativeSymbols = new NativeSymbolTable();
|
|
Pid = string.Empty;
|
|
Tid = string.Empty;
|
|
}
|
|
|
|
public string ProcessType { get; set; } = string.Empty;
|
|
|
|
public double ProcessStartupTime { get; set; }
|
|
|
|
public double? ProcessShutdownTime { get; set; }
|
|
|
|
public double RegisterTime { get; set; }
|
|
|
|
public double? UnregisterTime { get; set; }
|
|
|
|
public List<PausedRange> PausedRanges { get; set; }
|
|
|
|
public bool? ShowMarkersInTimeline { get; set; }
|
|
|
|
public string Name { get; set; }
|
|
|
|
public bool IsMainThread { get; set; }
|
|
|
|
[JsonPropertyName( "eTLD+1" )]
|
|
public string? ETLDPlus1 { get; set; }
|
|
|
|
public string? ProcessName { get; set; }
|
|
|
|
public bool? IsJsTracer { get; set; }
|
|
|
|
public string Pid { get; set; }
|
|
|
|
public string Tid { get; set; }
|
|
|
|
public SamplesTable Samples { get; set; }
|
|
|
|
//[JsonPropertyName("jsAllocations")]
|
|
//public JsAllocationsTable? JsAllocations { get; set; }
|
|
|
|
//[JsonPropertyName("nativeAllocations")]
|
|
//public NativeAllocationsTable? NativeAllocations { get; set; }
|
|
|
|
public RawMarkerTable Markers { get; set; }
|
|
|
|
public StackTable StackTable { get; set; }
|
|
|
|
public FrameTable FrameTable { get; set; }
|
|
|
|
public List<string> StringArray { get; set; }
|
|
|
|
public FuncTable FuncTable { get; set; }
|
|
|
|
public ResourceTable ResourceTable { get; set; }
|
|
|
|
public NativeSymbolTable NativeSymbols { get; set; }
|
|
|
|
public JsTracerTable? JsTracer { get; set; }
|
|
|
|
public bool? IsPrivateBrowsing { get; set; }
|
|
|
|
public int? UserContextId { get; set; }
|
|
}
|
|
|
|
|
|
public abstract class NativeAllocationsTable : SamplesLikeTable
|
|
{
|
|
}
|
|
|
|
public class BalancedNativeAllocationsTable : NativeAllocationsTable
|
|
{
|
|
public BalancedNativeAllocationsTable()
|
|
{
|
|
MemoryAddress = new();
|
|
ThreadId = new();
|
|
}
|
|
|
|
public List<int> MemoryAddress { get; set; }
|
|
|
|
public List<int> ThreadId { get; set; }
|
|
}
|
|
|
|
public class UnbalancedNativeAllocationsTable : NativeAllocationsTable
|
|
{
|
|
}
|
|
|
|
|
|
public class ProfileMeta
|
|
{
|
|
public ProfileMeta()
|
|
{
|
|
MarkerSchema = new List<MarkerSchema>();
|
|
Interval = 0;
|
|
StartTime = 0;
|
|
Product = string.Empty;
|
|
}
|
|
|
|
public double Interval { get; set; }
|
|
|
|
public double StartTime { get; set; }
|
|
|
|
public double? EndTime { get; set; }
|
|
|
|
public double? ProfilingStartTime { get; set; }
|
|
|
|
public double? ProfilingEndTime { get; set; }
|
|
|
|
public int ProcessType { get; set; }
|
|
|
|
public ExtensionTable? Extensions { get; set; }
|
|
|
|
public List<Category>? Categories { get; set; }
|
|
|
|
public string Product { get; set; }
|
|
|
|
public int Stackwalk { get; set; }
|
|
|
|
public bool? Debug { get; set; }
|
|
|
|
public int Version { get; set; }
|
|
|
|
public int PreprocessedProfileVersion { get; set; }
|
|
|
|
public string? Abi { get; set; }
|
|
|
|
public string? Misc { get; set; }
|
|
|
|
public string? Oscpu { get; set; }
|
|
|
|
public int? MainMemory { get; set; }
|
|
|
|
public string? Platform { get; set; }
|
|
|
|
public string? Toolkit { get; set; }
|
|
|
|
public string? AppBuildID { get; set; }
|
|
|
|
public string? Arguments { get; set; }
|
|
|
|
public string? SourceURL { get; set; }
|
|
|
|
public int? PhysicalCPUs { get; set; }
|
|
|
|
public int? LogicalCPUs { get; set; }
|
|
|
|
public string? CPUName { get; set; }
|
|
|
|
public bool? Symbolicated { get; set; }
|
|
|
|
public bool? SymbolicationNotSupported { get; set; }
|
|
|
|
public string? UpdateChannel { get; set; }
|
|
|
|
public VisualMetrics? VisualMetrics { get; set; }
|
|
|
|
public ProfilerConfiguration? Configuration { get; set; }
|
|
|
|
public List<MarkerSchema> MarkerSchema { get; set; }
|
|
|
|
public SampleUnits? SampleUnits { get; set; }
|
|
|
|
public string? Device { get; set; }
|
|
|
|
public string? ImportedFrom { get; set; }
|
|
|
|
public bool? UsesOnlyOneStackType { get; set; }
|
|
|
|
public bool? DoesNotUseFrameImplementation { get; set; }
|
|
|
|
public bool? SourceCodeIsNotOnSearchfox { get; set; }
|
|
|
|
public List<ExtraProfileInfoSection>? Extra { get; set; }
|
|
|
|
public List<int>? InitialVisibleThreads { get; set; }
|
|
|
|
public List<int>? InitialSelectedThreads { get; set; }
|
|
|
|
public bool? KeepProfileThreadOrder { get; set; }
|
|
|
|
public double? GramsOfCO2ePerKWh { get; set; }
|
|
}
|
|
|
|
public class Profile
|
|
{
|
|
public Profile()
|
|
{
|
|
Meta = new ProfileMeta();
|
|
Libs = new List<Lib>();
|
|
Threads = new List<Thread>();
|
|
}
|
|
|
|
public ProfileMeta Meta { get; set; }
|
|
|
|
public List<Lib> Libs { get; set; }
|
|
|
|
public List<Page>? Pages { get; set; }
|
|
|
|
public List<Counter>? Counters { get; set; }
|
|
|
|
public List<ProfilerOverhead>? ProfilerOverhead { get; set; }
|
|
|
|
public List<Thread> Threads { get; set; }
|
|
}
|
|
|
|
public class ExtensionTable
|
|
{
|
|
public ExtensionTable()
|
|
{
|
|
BaseURL = new List<string>();
|
|
Id = new List<string>();
|
|
Name = new List<string>();
|
|
}
|
|
|
|
public List<string> BaseURL { get; set; }
|
|
|
|
public List<string> Id { get; set; }
|
|
|
|
public List<string> Name { get; set; }
|
|
|
|
public int Length { get; set; }
|
|
}
|
|
|
|
public class CounterSamplesTable
|
|
{
|
|
public CounterSamplesTable()
|
|
{
|
|
Count = new List<long>();
|
|
}
|
|
|
|
public List<double>? Time { get; set; }
|
|
|
|
public List<double>? TimeDeltas { get; set; }
|
|
|
|
public List<int>? Number { get; set; }
|
|
|
|
public List<long> Count { get; set; }
|
|
|
|
public int Length { get; set; }
|
|
}
|
|
|
|
public class Counter
|
|
{
|
|
public Counter()
|
|
{
|
|
Name = string.Empty;
|
|
Category = string.Empty;
|
|
Description = string.Empty;
|
|
Pid = string.Empty;
|
|
Samples = new CounterSamplesTable();
|
|
}
|
|
|
|
public string Name { get; set; }
|
|
|
|
public string Category { get; set; } // 'Memory', 'power', 'Bandwidth'
|
|
|
|
public string Description { get; set; }
|
|
|
|
public ProfileColor? Color { get; set; }
|
|
|
|
public string Pid { get; set; }
|
|
|
|
public int MainThreadIndex { get; set; }
|
|
|
|
public CounterSamplesTable Samples { get; set; }
|
|
}
|
|
|
|
public class JsTracerTable
|
|
{
|
|
public JsTracerTable()
|
|
{
|
|
Events = new List<int>();
|
|
Timestamps = new List<int>();
|
|
Durations = new List<int?>();
|
|
Line = new List<int?>();
|
|
Column = new List<int?>();
|
|
}
|
|
|
|
public List<int> Events { get; set; }
|
|
|
|
public List<int> Timestamps { get; set; }
|
|
|
|
public List<int?> Durations { get; set; }
|
|
|
|
public List<int?> Line { get; set; }
|
|
|
|
public List<int?> Column { get; set; }
|
|
|
|
public int Length { get; set; }
|
|
}
|
|
|
|
public class SampleUnits
|
|
{
|
|
public SampleUnits()
|
|
{
|
|
Time = string.Empty;
|
|
EventDelay = string.Empty;
|
|
ThreadCPUDelta = string.Empty;
|
|
}
|
|
|
|
public string Time { get; set; }
|
|
|
|
public string EventDelay { get; set; }
|
|
|
|
public string ThreadCPUDelta { get; set; }
|
|
}
|
|
|
|
public class ExtraProfileInfoSection
|
|
{
|
|
public ExtraProfileInfoSection()
|
|
{
|
|
Label = string.Empty;
|
|
Entries = new List<ProfileInfoEntry>();
|
|
}
|
|
|
|
public string Label { get; set; }
|
|
|
|
public List<ProfileInfoEntry> Entries { get; set; }
|
|
}
|
|
|
|
public class ProfileInfoEntry
|
|
{
|
|
public ProfileInfoEntry()
|
|
{
|
|
Label = string.Empty;
|
|
Format = string.Empty;
|
|
Value = string.Empty;
|
|
}
|
|
|
|
public string Label { get; set; }
|
|
|
|
public string Format { get; set; }
|
|
|
|
public string Value { get; set; }
|
|
}
|
|
|
|
public abstract class MarkerFormatType
|
|
{
|
|
protected MarkerFormatType( string type )
|
|
{
|
|
Type = type;
|
|
}
|
|
|
|
[JsonIgnore]
|
|
public string Type { get; set; }
|
|
|
|
// ----------------------------------------------------
|
|
// String types.
|
|
|
|
/// <summary>
|
|
/// Show the URL, and handle PII sanitization
|
|
/// </summary>
|
|
public static readonly MarkerSimpleFormatType Url = new( "url" );
|
|
|
|
/// <summary>
|
|
/// Show the file path, and handle PII sanitization.
|
|
/// </summary>
|
|
public static readonly MarkerSimpleFormatType FilePath = new( "file-path" );
|
|
|
|
/// <summary>
|
|
/// Show regular string, and handle PII sanitization.
|
|
/// </summary>
|
|
public static readonly MarkerSimpleFormatType SanitizedString = new( "sanitized-string" );
|
|
|
|
/// <summary>
|
|
/// Important: do not put URL or file path information here, as it will not be
|
|
/// sanitized. Please be careful with including other types of PII here as well.
|
|
/// e.g. "Label: Some String"
|
|
/// </summary>
|
|
public static readonly MarkerSimpleFormatType String = new( "string" );
|
|
|
|
/// <summary>
|
|
/// An index into a (currently) thread-local string table, aka UniqueStringArray.
|
|
/// This is effectively an integer, so wherever we need to display this value, we
|
|
/// must first perform a lookup into the appropriate string table.
|
|
/// </summary>
|
|
public static readonly MarkerSimpleFormatType UniqueString = new( "unique-string" );
|
|
|
|
// ----------------------------------------------------
|
|
// Flow types.
|
|
|
|
/// <summary>
|
|
/// A flow ID is a u64 identifier that's unique across processes. In the current
|
|
/// implementation, we represent them as hex strings, as string table indexes.
|
|
/// </summary>
|
|
public static readonly MarkerSimpleFormatType FlowId = new( "flow-id" );
|
|
|
|
/// <summary>
|
|
/// A terminating flow ID is a flow ID that, when used in a marker with timestamp T,
|
|
/// makes it so that if the same flow ID is used in a marker whose timestamp is
|
|
/// after T, that flow ID is considered to refer to a different flow.
|
|
/// </summary>
|
|
public static readonly MarkerSimpleFormatType TerminatingFlowId = new( "terminating-flow-id" );
|
|
|
|
// ----------------------------------------------------
|
|
// Numeric types
|
|
|
|
// Note: All time and durations are stored as milliseconds.
|
|
|
|
/// <summary>
|
|
/// For time data that represents a duration of time.
|
|
/// e.g. "Label: 5s, 5ms, 5μs"
|
|
/// </summary>
|
|
public static readonly MarkerSimpleFormatType Duration = new( "duration" );
|
|
|
|
/// <summary>
|
|
/// Data that happened at a specific time, relative to the start of
|
|
/// the profile. e.g. "Label: 15.5s, 20.5ms, 30.5μs"
|
|
/// </summary>
|
|
public static readonly MarkerSimpleFormatType Time = new( "time" );
|
|
|
|
// The following are alternatives to display a time only in a specific unit of time.
|
|
|
|
/// <summary> "Label: 5s" </summary>
|
|
public static readonly MarkerSimpleFormatType Seconds = new( "seconds" );
|
|
|
|
/// <summary> "Label: 5ms" </summary>
|
|
public static readonly MarkerSimpleFormatType Milliseconds = new( "milliseconds" );
|
|
|
|
/// <summary> "Label: 5μs" </summary>
|
|
public static readonly MarkerSimpleFormatType Microseconds = new( "microseconds" );
|
|
|
|
/// <summary> "Label: 5ns" </summary>
|
|
public static readonly MarkerSimpleFormatType Nanoseconds = new( "nanoseconds" );
|
|
|
|
/// <summary>
|
|
/// e.g. "Label: 5.55mb, 5 bytes, 312.5kb"
|
|
/// </summary>
|
|
public static readonly MarkerSimpleFormatType Bytes = new( "bytes" );
|
|
|
|
/// <summary>
|
|
/// This should be a value between 0 and 1.
|
|
/// "Label: 50%"
|
|
/// </summary>
|
|
public static readonly MarkerSimpleFormatType Percentage = new( "percentage" );
|
|
|
|
/// <summary>
|
|
/// The integer should be used for generic representations of numbers. Do not
|
|
/// use it for time information.
|
|
/// "Label: 52, 5,323, 1,234,567"
|
|
/// </summary>
|
|
public static readonly MarkerSimpleFormatType Integer = new( "integer" );
|
|
|
|
/// <summary>
|
|
/// The decimal should be used for generic representations of numbers. Do not
|
|
/// use it for time information.
|
|
/// "Label: 52.23, 0.0054, 123,456.78"
|
|
/// </summary>
|
|
public static readonly MarkerSimpleFormatType Decimal = new( "decimal" );
|
|
|
|
public static readonly MarkerSimpleFormatType Pid = new( "pid" );
|
|
public static readonly MarkerSimpleFormatType Tid = new( "tid" );
|
|
public static readonly MarkerSimpleFormatType List = new( "list" );
|
|
|
|
/// <summary>
|
|
/// Represents a table format, with columns of type `TableColumnFormat[]`.
|
|
/// </summary>
|
|
public static MarkerTableFormatType Table( IEnumerable<TableColumnFormat> columns )
|
|
{
|
|
var table = new MarkerTableFormatType();
|
|
table.Columns.AddRange( columns );
|
|
return table;
|
|
}
|
|
}
|
|
|
|
public class MarkerSimpleFormatType( string type ) : MarkerFormatType( type );
|
|
|
|
private sealed class MarkerFormatTypeConverter : JsonConverter<MarkerFormatType>
|
|
{
|
|
public override MarkerFormatType Read( ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options )
|
|
{
|
|
if ( reader.TokenType == JsonTokenType.String )
|
|
{
|
|
string propertyName = reader.GetString() ?? string.Empty;
|
|
|
|
MarkerFormatType? markerFormatType = propertyName switch
|
|
{
|
|
"url" => MarkerFormatType.Url,
|
|
"file-path" => MarkerFormatType.FilePath,
|
|
"sanitized-string" => MarkerFormatType.SanitizedString,
|
|
"string" => MarkerFormatType.String,
|
|
"unique-string" => MarkerFormatType.UniqueString,
|
|
"flow-id" => MarkerFormatType.FlowId,
|
|
"terminating-flow-id" => MarkerFormatType.TerminatingFlowId,
|
|
"duration" => MarkerFormatType.Duration,
|
|
"time" => MarkerFormatType.Time,
|
|
"seconds" => MarkerFormatType.Seconds,
|
|
"milliseconds" => MarkerFormatType.Milliseconds,
|
|
"microseconds" => MarkerFormatType.Microseconds,
|
|
"nanoseconds" => MarkerFormatType.Nanoseconds,
|
|
"bytes" => MarkerFormatType.Bytes,
|
|
"percentage" => MarkerFormatType.Percentage,
|
|
"integer" => MarkerFormatType.Integer,
|
|
"decimal" => MarkerFormatType.Decimal,
|
|
"pid" => MarkerFormatType.Pid,
|
|
"tid" => MarkerFormatType.Tid,
|
|
"list" => MarkerFormatType.List,
|
|
_ => new MarkerSimpleFormatType( propertyName )
|
|
};
|
|
|
|
return markerFormatType;
|
|
}
|
|
|
|
return JsonSerializer.Deserialize( ref reader, JsonProfilerContext.Default.MarkerTableFormatType )!;
|
|
}
|
|
|
|
public override void Write( Utf8JsonWriter writer, MarkerFormatType value, JsonSerializerOptions options )
|
|
{
|
|
if ( value is MarkerSimpleFormatType simpleFormatType )
|
|
{
|
|
writer.WriteStringValue( simpleFormatType.Type );
|
|
}
|
|
else
|
|
{
|
|
JsonSerializer.Serialize( writer, (object?)value, (JsonTypeInfo)JsonProfilerContext.Default.MarkerTableFormatType );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public class MarkerTableFormatType : MarkerFormatType
|
|
{
|
|
public MarkerTableFormatType() : base( "table" )
|
|
{
|
|
Columns = new();
|
|
}
|
|
|
|
public List<TableColumnFormat> Columns { get; set; }
|
|
}
|
|
|
|
public class TableColumnFormat
|
|
{
|
|
public TableColumnFormat()
|
|
{
|
|
Label = string.Empty;
|
|
}
|
|
|
|
[JsonConverter( typeof( MarkerFormatTypeConverter ) )]
|
|
public MarkerFormatType? Type { get; set; }
|
|
|
|
public string Label { get; set; }
|
|
}
|
|
|
|
[JsonConverter( typeof( KebabCaseEnumConverter<MarkerDisplayLocation> ) )]
|
|
public enum MarkerDisplayLocation
|
|
{
|
|
MarkerChart,
|
|
MarkerTable,
|
|
TimelineOverview,
|
|
TimelineMemory,
|
|
TimelineIpc,
|
|
TimelineFileio,
|
|
StackChart
|
|
}
|
|
|
|
private class KebabCaseEnumConverter<TEnum>() :
|
|
JsonStringEnumConverter<TEnum>( JsonNamingPolicy.KebabCaseLower ) where TEnum : struct, Enum;
|
|
|
|
[JsonConverter( typeof( KebabCaseEnumConverter<MarkerGraphType> ) )]
|
|
public enum MarkerGraphType
|
|
{
|
|
Bar,
|
|
Line,
|
|
LineFilled
|
|
}
|
|
|
|
public class MarkerGraph
|
|
{
|
|
public MarkerGraph()
|
|
{
|
|
Key = string.Empty;
|
|
}
|
|
|
|
public string Key { get; set; }
|
|
|
|
public MarkerGraphType Type { get; set; }
|
|
|
|
public ProfileColor? Color { get; set; }
|
|
}
|
|
|
|
[JsonConverter( typeof( ProfileColorEnumConverter ) )]
|
|
public enum ProfileColor
|
|
{
|
|
Blue,
|
|
Green,
|
|
Grey,
|
|
Ink,
|
|
Magenta,
|
|
Orange,
|
|
Purple,
|
|
Red,
|
|
Teal,
|
|
Yellow,
|
|
}
|
|
|
|
private sealed class ProfileColorEnumConverter() : JsonStringEnumConverter<ProfileColor>( JsonNamingPolicy.CamelCase, false );
|
|
|
|
|
|
public class MarkerSchema
|
|
{
|
|
public MarkerSchema()
|
|
{
|
|
Name = string.Empty;
|
|
Display = new List<MarkerDisplayLocation>();
|
|
Data = new List<MarkerDataItem>();
|
|
}
|
|
|
|
public string Name { get; set; }
|
|
|
|
public string? TooltipLabel { get; set; }
|
|
|
|
public string? TableLabel { get; set; }
|
|
|
|
public string? ChartLabel { get; set; }
|
|
|
|
public List<MarkerDisplayLocation> Display { get; set; }
|
|
|
|
public List<MarkerDataItem> Data { get; set; }
|
|
|
|
public List<MarkerGraph>? Graphs { get; set; }
|
|
|
|
public bool? IsStackBased { get; set; }
|
|
}
|
|
|
|
public class MarkerDataItem
|
|
{
|
|
public string? Key { get; set; }
|
|
|
|
public string? Label { get; set; }
|
|
|
|
[JsonConverter( typeof( MarkerFormatTypeConverter ) )]
|
|
public MarkerFormatType? Format { get; set; }
|
|
|
|
public bool? Searchable { get; set; }
|
|
|
|
public string? Value { get; set; }
|
|
}
|
|
|
|
[JsonConverter( typeof( MarkerPayloadConverter ) )]
|
|
public class MarkerPayload
|
|
{
|
|
public string? Type { get; set; }
|
|
|
|
public Dictionary<string, object?>? ExtensionData { get; set; }
|
|
|
|
/// <summary>
|
|
/// Writes the JSON representation of the current object.
|
|
/// </summary>
|
|
/// <param name="writer">The JSON writer.</param>
|
|
/// <param name="payload">The marker payload.</param>
|
|
/// <param name="options">The JSON serializer options.</param>
|
|
protected internal virtual void WriteJson( Utf8JsonWriter writer, MarkerPayload payload, JsonSerializerOptions options )
|
|
{
|
|
}
|
|
}
|
|
|
|
private class MarkerPayloadConverter : JsonConverter<MarkerPayload>
|
|
{
|
|
public override MarkerPayload? Read( ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options )
|
|
{
|
|
if ( reader.TokenType != JsonTokenType.StartObject )
|
|
{
|
|
throw new JsonException( "Expected object start { for MarkerPayload" );
|
|
}
|
|
|
|
var payload = new MarkerPayload();
|
|
|
|
while ( reader.Read() )
|
|
{
|
|
if ( reader.TokenType == JsonTokenType.EndObject )
|
|
{
|
|
return payload;
|
|
}
|
|
if ( reader.TokenType != JsonTokenType.PropertyName )
|
|
{
|
|
throw new JsonException( "Expected property name for MarkerPayload" );
|
|
}
|
|
string propertyName = reader.GetString() ?? string.Empty;
|
|
|
|
if ( propertyName == "type" )
|
|
{
|
|
reader.Read();
|
|
payload.Type = reader.GetString();
|
|
}
|
|
else
|
|
{
|
|
if ( payload.ExtensionData == null )
|
|
{
|
|
payload.ExtensionData = new Dictionary<string, object?>();
|
|
}
|
|
|
|
reader.Read();
|
|
|
|
switch ( reader.TokenType )
|
|
{
|
|
case JsonTokenType.String:
|
|
payload.ExtensionData[propertyName] = reader.GetString();
|
|
break;
|
|
case JsonTokenType.Number:
|
|
payload.ExtensionData[propertyName] = reader.GetDouble();
|
|
break;
|
|
case JsonTokenType.True:
|
|
payload.ExtensionData[propertyName] = true;
|
|
break;
|
|
case JsonTokenType.False:
|
|
payload.ExtensionData[propertyName] = false;
|
|
break;
|
|
case JsonTokenType.Null:
|
|
payload.ExtensionData[propertyName] = null;
|
|
break;
|
|
default:
|
|
#pragma warning disable IL3050
|
|
#pragma warning disable IL2026
|
|
payload.ExtensionData[propertyName] = JsonSerializer.Deserialize<object>( ref reader );
|
|
#pragma warning restore IL2026
|
|
#pragma warning restore IL3050
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return payload;
|
|
}
|
|
|
|
public override void Write( Utf8JsonWriter writer, MarkerPayload payload, JsonSerializerOptions options )
|
|
{
|
|
writer.WriteStartObject();
|
|
|
|
if ( payload.Type != null )
|
|
{
|
|
writer.WriteString( "type", payload.Type );
|
|
}
|
|
|
|
if ( payload.ExtensionData != null )
|
|
{
|
|
foreach ( var (key, value) in payload.ExtensionData )
|
|
{
|
|
writer.WritePropertyName( key );
|
|
switch ( value )
|
|
{
|
|
case string stringValue:
|
|
writer.WriteStringValue( stringValue );
|
|
break;
|
|
case long longValue:
|
|
writer.WriteNumberValue( longValue );
|
|
break;
|
|
case int intValue:
|
|
writer.WriteNumberValue( intValue );
|
|
break;
|
|
case short intValue:
|
|
writer.WriteNumberValue( intValue );
|
|
break;
|
|
case sbyte intValue:
|
|
writer.WriteNumberValue( intValue );
|
|
break;
|
|
case ulong longValue:
|
|
writer.WriteNumberValue( longValue );
|
|
break;
|
|
case uint intValue:
|
|
writer.WriteNumberValue( intValue );
|
|
break;
|
|
case ushort intValue:
|
|
writer.WriteNumberValue( intValue );
|
|
break;
|
|
case byte intValue:
|
|
writer.WriteNumberValue( intValue );
|
|
break;
|
|
case float floatValue:
|
|
writer.WriteNumberValue( floatValue );
|
|
break;
|
|
case double doubleValue:
|
|
writer.WriteNumberValue( doubleValue );
|
|
break;
|
|
case bool boolValue:
|
|
writer.WriteBooleanValue( boolValue );
|
|
break;
|
|
case null:
|
|
writer.WriteNullValue();
|
|
break;
|
|
default:
|
|
#pragma warning disable IL3050
|
|
#pragma warning disable IL2026
|
|
JsonSerializer.Serialize( writer, value );
|
|
#pragma warning restore IL2026
|
|
#pragma warning restore IL3050
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
payload.WriteJson( writer, payload, options );
|
|
|
|
writer.WriteEndObject();
|
|
}
|
|
}
|
|
|
|
}
|