Profiler
SwiftlyS2's profiler service measures execution time in plugin code and records custom duration metrics.
Access it through Core.Profiler (APIISwiftlyCore.Profiler).
Measuring Code Blocks
Pair APIIContextedProfilerService.StartRecording/APIIContextedProfilerService.StopRecording around the code, wrapped in try/finally so an exception doesn't leave a recording open.
Core.Profiler.StartRecording("Database.PlayerStats.Load");
try
{
LoadPlayerStats();
}
finally
{
Core.Profiler.StopRecording("Database.PlayerStats.Load");
}Recording Precomputed Durations
Use APIIContextedProfilerService.RecordTime for a duration you already measured (double, microseconds).
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
BuildLargeMenu();
stopwatch.Stop();
double durationUs = stopwatch.ElapsedTicks * (1_000_000.0 / System.Diagnostics.Stopwatch.Frequency);
Core.Profiler.RecordTime("Menu.Build", durationUs);Use microseconds consistently so profiler entries stay comparable across the codebase.
Profiling Sub-Operations
Nest start/stop pairs to profile major flow steps separately and find hot spots faster:
Core.Profiler.StartRecording("PlayerData.Process");
try
{
Core.Profiler.StartRecording("PlayerData.Load");
try { LoadPlayerData(player.SteamID); } finally { Core.Profiler.StopRecording("PlayerData.Load"); }
Core.Profiler.StartRecording("PlayerData.Apply");
try { ApplyPlayerData(player); } finally { Core.Profiler.StopRecording("PlayerData.Apply"); }
}
finally { Core.Profiler.StopRecording("PlayerData.Process"); }Naming Strategy
Use clear, hierarchical names so related entries group together:
category.operation.detailExamples: Database.Players.Load, Database.Players.Save, Menu.Main.Build, Menu.Main.Open, Commands.Teleport.Execute, Events.PlayerSpawn.Process.
Avoid generic names like Operation or Process - they make hot spots hard to trace back to real code.
Reference
See APIIContextedProfilerService (APIISwiftlyCore.Profiler) for the full member list - StartRecording, StopRecording, RecordTime.