Skip to content

Instantly share code, notes, and snippets.

@MerlinVR
Last active November 20, 2022 11:08
Show Gist options
  • Save MerlinVR/2da80b29361588ddb556fd8d3f3f47b5 to your computer and use it in GitHub Desktop.
Save MerlinVR/2da80b29361588ddb556fd8d3f3f47b5 to your computer and use it in GitHub Desktop.
Basic global profiling scripts for Udon. Throw one of each script on a game object that has a TMP UI text somewhere in its children.
// MIT License
// Copyright (c) 2021 Merlin
using UdonSharp;
using UnityEngine;
[DefaultExecutionOrder(1000000000)]
public class GlobalProfileHandler : UdonSharpBehaviour
{
TMPro.TextMeshProUGUI timeText;
GlobalProfileKickoff kickoff;
private void Start()
{
kickoff = GetComponent<GlobalProfileKickoff>();
timeText = GetComponentInChildren<TMPro.TextMeshProUGUI>();
}
int currentFrame = -1;
float elapsedTime = 0f;
private void FixedUpdate()
{
if (currentFrame != Time.frameCount)
{
elapsedTime = 0f;
currentFrame = Time.frameCount;
}
if (kickoff)
elapsedTime += (float)kickoff.stopwatch.Elapsed.TotalSeconds * 1000f;
}
private void Update()
{
if (currentFrame != Time.frameCount) // FixedUpdate didn't run this frame, so reset the time
elapsedTime = 0f;
elapsedTime += (float)kickoff.stopwatch.Elapsed.TotalSeconds * 1000f;
}
private void LateUpdate()
{
elapsedTime += (float)kickoff.stopwatch.Elapsed.TotalSeconds * 1000f;
timeText.text = $"Update time:\n{elapsedTime:F4}ms";
}
}
// MIT License
// Copyright (c) 2021 Merlin
using UdonSharp;
using UnityEngine;
[DefaultExecutionOrder(-1000000000)]
public class GlobalProfileKickoff : UdonSharpBehaviour
{
[System.NonSerialized]
public System.Diagnostics.Stopwatch stopwatch;
private void Start()
{
stopwatch = new System.Diagnostics.Stopwatch();
}
private void FixedUpdate()
{
stopwatch.Restart();
}
private void Update()
{
stopwatch.Restart();
}
private void LateUpdate()
{
stopwatch.Restart();
}
}
@bdunderscore
Copy link

Here's an update with PostLateUpdate support as well:

// GlobalProfileHandler.cs
#define AVERAGE_OUTPUT

using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
using UdonSharp;
using UnityEngine;

[DefaultExecutionOrder(1000000000)]
public class GlobalProfileHandler : UdonSharpBehaviour
{
    public TMPro.TextMeshPro _timeText;
    private GlobalProfileKickoff _kickoff;

    private void Start()
    {
        _kickoff = GetComponent<GlobalProfileKickoff>();
    }

    private int _currentFrame = -1;
    private float _elapsedTime = 0f;
#if AVERAGE_OUTPUT
    private float _measuredFrametimeTotal = 0f;
    private float _measuredTimeTotal = 0f;
    private int _measuredTimeFrameCount = 0;
    private const int MEASURE_FRAME_AMOUNT = 45;
#endif

    private void FixedUpdate()
    {
        if (_currentFrame != Time.frameCount)
        {
            _elapsedTime = 0f;
            _currentFrame = Time.frameCount;
        }

        if (_kickoff)
            _elapsedTime += (float)_kickoff.stopwatch.Elapsed.TotalSeconds * 1000f;
    }

    private void Update()
    {
        if (_currentFrame != Time.frameCount) // FixedUpdate didn't run this frame, so reset the time
            _elapsedTime = 0f;

        _elapsedTime += (float)_kickoff.stopwatch.Elapsed.TotalSeconds * 1000f;
    }

    private void LateUpdate()
    {
        _elapsedTime += (float)_kickoff.stopwatch.Elapsed.TotalSeconds * 1000f;
    }

    float lastFrame;

    public override void PostLateUpdate()
    {
        _elapsedTime += (float)_kickoff.stopwatch.Elapsed.TotalSeconds * 1000f;
        float now = Time.timeSinceLevelLoad;
        _measuredFrametimeTotal += (now - lastFrame) * 1000f;
        lastFrame = now;

#if AVERAGE_OUTPUT
        if (_measuredTimeFrameCount >= MEASURE_FRAME_AMOUNT)
        {
            _timeText.text = $"Udon: {(_measuredTimeTotal / _measuredTimeFrameCount):F4}ms\nFrametime: {(_measuredFrametimeTotal/_measuredTimeFrameCount):F4}ms";
            _measuredTimeTotal = 0f;
            _measuredFrametimeTotal = 0f;
            _measuredTimeFrameCount = 0;
        }
        _measuredTimeTotal += _elapsedTime;
        _measuredTimeFrameCount += 1;
#else
        _timeText.text = $"Update time:\n{_elapsedTime:F4}ms";
#endif
    }
}

using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;

// MIT License
// Copyright (c) 2021 Merlin

using UdonSharp;
using UnityEngine;

[DefaultExecutionOrder(-1000000000)]
public class GlobalProfileKickoff : UdonSharpBehaviour
{
    [System.NonSerialized]
    public System.Diagnostics.Stopwatch stopwatch;

    private void Start()
    {
        stopwatch = new System.Diagnostics.Stopwatch();
    }

    private void FixedUpdate()
    {
        stopwatch.Restart();
    }

    private void Update()
    {
        stopwatch.Restart();
    }

    private void LateUpdate()
    {
        stopwatch.Restart();
    }

    public override void PostLateUpdate()
    {
        stopwatch.Restart();
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment