using System; using Newtonsoft.Json; using Unity.Pipeline.Commands; using UnityEditor; using UnityEngine; using UnityEngine.Profiling; namespace Unity.Pipeline.Editor.Commands.Observability { /// /// Render statistics for the most recently rendered Editor frame, read from /// . These reflect the last frame the Editor drew (Game/Scene view), not /// an averaged measurement — treat them as a snapshot. /// [Serializable] public class RenderStats { /// Draw calls issued for the last rendered frame. [JsonProperty("drawCalls")] public int DrawCalls { get; set; } /// Total batches (dynamic + static + instanced) for the last rendered frame. [JsonProperty("batches")] public int Batches { get; set; } /// SetPass calls (shader pass switches) for the last rendered frame. [JsonProperty("setPassCalls")] public int SetPassCalls { get; set; } /// Triangles submitted for the last rendered frame. [JsonProperty("triangles")] public int Triangles { get; set; } /// Vertices submitted for the last rendered frame. [JsonProperty("vertices")] public int Vertices { get; set; } } /// /// Process memory usage read from . Values are in bytes and are always /// available at runtime regardless of whether the Profiler window is open. /// [Serializable] public class MemoryStats { /// Total memory currently allocated by Unity (bytes). [JsonProperty("totalAllocatedBytes")] public long TotalAllocatedBytes { get; set; } /// Total memory reserved by Unity (bytes). [JsonProperty("totalReservedBytes")] public long TotalReservedBytes { get; set; } /// Mono managed heap memory in use (bytes). [JsonProperty("monoUsedBytes")] public long MonoUsedBytes { get; set; } /// Mono managed heap size reserved (bytes). [JsonProperty("monoHeapBytes")] public long MonoHeapBytes { get; set; } } /// /// Latest CPU/GPU frame timing from . The Frame Timing Manager /// must have a timing captured for to be true; when unavailable the /// timing fields are left at zero. /// [Serializable] public class FrameTimingStats { /// True when a frame timing was captured and the milliseconds fields are meaningful. [JsonProperty("available")] public bool Available { get; set; } /// Total CPU frame time in milliseconds. [JsonProperty("cpuFrameTimeMs")] public double CpuFrameTimeMs { get; set; } /// Total GPU frame time in milliseconds. [JsonProperty("gpuFrameTimeMs")] public double GpuFrameTimeMs { get; set; } /// CPU main-thread frame time in milliseconds. [JsonProperty("cpuMainThreadFrameTimeMs")] public double CpuMainThreadFrameTimeMs { get; set; } } /// /// Composite performance snapshot returned by get_performance_stats: render counters, /// process memory, and the latest frame timing. /// [Serializable] public class PerformanceStats { /// Render counters for the last rendered Editor frame. [JsonProperty("render")] public RenderStats Render { get; set; } /// Process memory usage at capture time. [JsonProperty("memory")] public MemoryStats Memory { get; set; } /// Latest CPU/GPU frame timing, if one was captured. [JsonProperty("frameTiming")] public FrameTimingStats FrameTiming { get; set; } } /// /// Read-only telemetry command (CLI-198) that snapshots render, memory, and frame-timing stats so /// an agent can reason about Editor performance without opening the Profiler or Stats overlay. /// public static class PerformanceCommands { [CliCommand("get_performance_stats", "Read render, memory, and frame-timing stats (structured, read-only).")] public static PerformanceStats GetPerformanceStats() { return new PerformanceStats { Render = new RenderStats { // UnityStats reflects the last frame rendered by the Editor (Game/Scene view). DrawCalls = UnityStats.drawCalls, Batches = UnityStats.dynamicBatches + UnityStats.staticBatches + UnityStats.instancedBatches, SetPassCalls = UnityStats.setPassCalls, Triangles = UnityStats.triangles, Vertices = UnityStats.vertices }, Memory = new MemoryStats { TotalAllocatedBytes = Profiler.GetTotalAllocatedMemoryLong(), TotalReservedBytes = Profiler.GetTotalReservedMemoryLong(), MonoUsedBytes = Profiler.GetMonoUsedSizeLong(), MonoHeapBytes = Profiler.GetMonoHeapSizeLong() }, FrameTiming = CaptureFrameTiming() }; } /// /// Capture the latest CPU/GPU frame timing. The Frame Timing Manager only yields data once a /// timing has been captured (and platform support exists), so any failure or empty result is /// reported as = false rather than throwing. /// private static FrameTimingStats CaptureFrameTiming() { try { FrameTimingManager.CaptureFrameTimings(); var timings = new FrameTiming[1]; uint received = FrameTimingManager.GetLatestTimings(1, timings); if (received > 0) { return new FrameTimingStats { Available = true, CpuFrameTimeMs = timings[0].cpuFrameTime, GpuFrameTimeMs = timings[0].gpuFrameTime, CpuMainThreadFrameTimeMs = timings[0].cpuMainThreadFrameTime }; } } catch { // Frame timing is platform-dependent and may be unsupported; report as unavailable. } return new FrameTimingStats { Available = false }; } } }