the symptom, in your words

"FrameStats and PerformanceStats are accessible from game code — no engine benchmark system needed"

✓ verified on engine 26.07.08elane: Making it performposted

▸ SYMPTOM

You want to profile draw calls, triangle counts, GC pressure, or frame pacing from within your game code but assume you need a special engine benchmark system or editor-only API.

▸ CAUSE

The profiling surface is already exposed in the Sandbox.Diagnostics namespace, whitelist-clean, and accessible from any game-assembly Component running in play mode.

▸ FIX

Build a play-mode Component that reads from the available diagnostic APIs each frame:

Frame stats (Sandbox.Diagnostics.FrameStats.Current):

  • DrawCalls — number of draw calls this frame
  • TrianglesRendered — total rendered triangles
  • ObjectsRendered / ObjectsPreCull — visible vs pre-cull object counts
  • ShadowMaps / ShadowedLightsInView — shadow rendering load

Performance stats (Sandbox.Diagnostics.PerformanceStats):

  • Gen0Collections / Gen1Collections / Gen2Collections — GC counts
  • BytesAllocated — allocation pressure

Frame pacing: RealTime.Delta gives per-frame wall time for frame-pacing analysis.

Physics timing: implement IScenePhysicsEvents and use PrePhysicsStep / PostPhysicsStep callbacks with a Stopwatch to time the actual physics solver step — this gives vsync-free CPU cost even when frame fps is capped at 60 in the editor.

Read each stat field inside try/catch so a future engine rename degrades a field to -1 instead of breaking the frame baseline.

What you still can't measure this way: the true GPU ceiling / absolute FPS. Editor play mode is vsync-capped at 60 Hz, so GPU cost below 16.7 ms is invisible. Take absolute numbers from a standalone build.

▸ WHY IT WORKS

These APIs are part of the Sandbox namespace, not the Editor namespace, so they pass the whitelist and run in the game assembly. They give relative numbers sufficient for profiling: frame-time trends, draw-call counts, GC pressure, physics cost. Combined, they cover everything except the absolute GPU ceiling — which requires a standalone build where the engine controls its own swap chain.

Verified on engine 26.07.08e — seen in a real project.
s&box moves fast; an undated fix is a liability. Spot a stale detail?

Want to know when new guides or fixes drop? Join the community to help build this out — report gotchas, flag outdated fixes, or just lurk.

Join the Discord