Optimizing Debugging and Performance Monitoring in Unity

During the development of our game, we realized that having a centralized debug system would greatly improve our workflow. Instead of scattering debug logs across multiple scripts, we built a Debug Console that not only logs messages but also provides real-time performance metrics. This helps us monitor game performance and quickly identify bottlenecks.

Implementing a Centralized Debug Console

Goals

  1. Replace standard Debug.Log, Debug.LogWarning, and Debug.LogError with our own toggleable logging system.
  2. Display logs in a GUI console within the game.
  3. Integrate performance monitoring for:
    • FPS
    • CPU & GPU usage
    • RAM & VRAM usage
    • Active game objects
    • Draw calls
    • Physics objects
    • Audio sources
    • Network latency (ping)

Refactoring Debug Logging

Instead of using Debug.Log everywhere, we now use our DebugConsole class. The logging system includes two levels of control:

  • Enable/Disable all logging globally
  • Choose whether logs should appear in the on-screen debug console
[SerializeField] bool logEnabled = true;
[SerializeField] bool logToGUI = false;

public static void Log(string message, Object context = default)
{
    if (!instance.logEnabled)
        return;
    Debug.Log(message, context);
    if (instance.logToGUI)
        LogToGUI(message);
}

This allows us to disable logs in production builds while keeping them visible in development.

Displaying Performance Metrics

To better understand how our game performs in real-time, we integrated various performance metrics into the GUI.

Key Features

  • FPS Monitoring:
    Helps track frame rate drops and performance stability.
  • CPU and GPU Time:
    Uses Unity’s Recorder API to measure time per frame.
  • Memory Usage:
    • Profiler.GetTotalAllocatedMemoryLong() for RAM
    • SystemInfo.graphicsMemorySize for VRAM
  • Game Objects & Draw Calls:
    • Object.FindObjectsByType<GameObject>() for active objects
    • UnityEngine.Rendering.OnDemandRendering.effectiveRenderFrameRate for draw calls
  • Physics and Audio Statistics:
    • Object.FindObjectsByType<Rigidbody>() for physics bodies
    • Object.FindObjectsByType<AudioSource>() for active sounds
  • Network Ping:
    Retrieves round-trip time (RTT) from Fusion’s GetPlayerRtt().

Optimized GUI Rendering

Instead of manually positioning each stat with hardcoded y offsets, we use a dynamic spacing system:

float y = Screen.height - 120;
int line = 0; // Line counter for spacing

if (showFPS)
    GUI.Label(new Rect(x, y - lineSpacing * line++, width, height), $"FPS: {Mathf.CeilToInt(1.0f / deltaTime)}", style);
if (showCPUTime)
    GUI.Label(new Rect(x, y - lineSpacing * line++, width, height), $"CPU: {cpuTime:F2} ms", style);
if (showGPUTime)
    GUI.Label(new Rect(x, y - lineSpacing * line++, width, height), $"GPU: {(gpuTime > 0 ? gpuTime.ToString("F2") : "N/A")} ms", style);

This makes it easy to add/remove stats without manually adjusting positions.

With this Debug Console, we now have real-time insights into our game’s performance, reducing debugging time and helping us optimize early. The ability to toggle logging and performance metrics individually ensures flexibility during development.

This system will be continuously improved as we integrate more network-related statistics and potential error tracking.

Schreibe einen Kommentar