DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Mastering Coroutine Execution: Yielding, Flow, and Practical Use Cases in Unity
  • Unity and the Future of Game Development
  • When Airflow Tasks Get Stuck in Queued: A Real-World Debugging Story
  • Creating a Web Project: Key Steps to Identify Issues

Trending

  • Implementing API Design First in .NET for Efficient Development, Testing, and CI/CD
  • Modern Test Automation With AI (LLM) and Playwright MCP
  • Understanding the Shift: Why Companies Are Migrating From MongoDB to Aerospike Database?
  • Software Delivery at Scale: Centralized Jenkins Pipeline for Optimal Efficiency
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Maintenance
  4. How to Debug and Fix Performance Problems in Unity With the Profiler Tool

How to Debug and Fix Performance Problems in Unity With the Profiler Tool

Learn how to debug and fix performance issues with the Unity profiler tool.

By 
Josh Chang user avatar
Josh Chang
·
Apr. 12, 19 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
12.4K Views

Join the DZone community and get the full member experience.

Join For Free

To summarize what I’ve been up to this past month or two, I’ve continued to help out in the TInkerVR project like I’ve talked about in my Post 100 Day Challenge.

You might be thinking: “Josh! What cool VR programming wisdom will you share with us today?” (Hint: it’s in the title). That’s right! Today, it’s all about perf, perf, and even more perf!

Perf is for short for performance in case you’re wondering.

As it turns out, for projects like ours where we have a lot of technologies that are running at the same time (think Leap Motion, ObiSolver, and VRTK among some of the software that we have been using), you run into a whole slew of problems that destroy the performance of your game:

  1. We have too many cameras running from VRTK and Leap Motion, requiring a lot of processing from our computer to render graphics for all of our cameras
  2. Leap Motion and ObiSolver’s physics engine are taking a lot of processing time
  3. Some combination of all this combined with our other software

How did we find this out? We learned all about it through Unity’s profiler tool.

When I first started working with Unity, I never thought there would ever be a day where I would run into performance problems, but here we are talking about performance!

What is the Unity profiler tool? Well, according to the documentation:

“The Unity Profiler Window helps you to optimize your game. It reports for you how much time is spent in the various areas of your game. For example, it can report the percentage of time spent rendering, animating or in your game logic.”

Today, to demonstrate how to use the profiler tool, I’m going to create a new project with hypothetical inefficiencies that will hinder our performance and then use the profiler tool to solve these problems!

Creating an Inefficient Example to Profile

To demonstrate how we might be able to use the profiler tool, we’re going to create an example project to demonstrate how to use the tool.

Unfortunately, I don’t have any concrete examples of a bad performing game for me to release. I imagine that it’ll take a LOT of complex game objects all moving in a scene before we can even get close to seeing problems.

Instead, I decided to write some bad code that I know will affect performance. Here’s what I did so you can follow along.

  1. I created a new project that I just called ProfilerTest
  2. In the new project, I added a Cube into the scene (or really any other game object)
  3. I created a new script calledCubeController that I attached to the cube.

Here’s what the script looks like:

using UnityEngine;
public class CubeController : MonoBehaviour
{

    void Update () {
        RotateGameObject();
        print("a messsage!");
    }

    public void RotateGameObject()
    {
        this.gameObject.transform.Rotate(0, 100 * Time.deltaTime, 0);
        // use a for loop as a bad wait function
        for (int i = 0; i < 1000000; i++) {}
        this.gameObject.transform.Rotate(0, 100 * Time.deltaTime, 0);
    }
}


Looking at this script, we’re doing two bad things:

  1. Printing a message every time in Update(), which happens every frame in our game.
  2. Using a for loop to wait for our variable to become 1,000,000 before we rotate our game object again (and again, once every Update()). I was inspired by this for loop idea from a project where — I’m not joking — used this as a sleep function to wait for some time… Yikes!

Let’s say someone we are working with didn’t know any better and wrote this code. Our game is now showing signs of slowdown and we don’t know what’s causing it; what do we do?

Luckily for us (and you!), we have the Unity profiler tool!

So, we opened it up to see if we can diagnose where our performance problems were coming from.

  1. Open the profiler tool by going to Window > Profiler or hitting Ctrl + 7

It should look something like this:

If you explore the tool, you’ll see that we have a lot of categories we can analyze:

  • CPU Usage
  • Rendering
  • Memory
  • Audio
  • Video
  • Physics
  • …etc.

There are a lot of categories that we can read, but what matters the most is the hierarchy window at the bottom of the Profiler.

Now that we have the profiler tab up, let’s use it!

  1. Run the profiler tool by playing the game
  2. In the Hierarchy window, click the Total tab to organize everything by their Total computation percentage. Note that a high percentage doesn’t mean that we’ll have a high CPU usage. It just means that the category is the most CPU intensive operation out of all your current operation.

Here’s what our profiler looks like:

Immediately after we organized our processes by highest to lowest Total, we can see that  Update.ScriptRunBehaviourUpdate is consuming most of our system resources. Uh oh, this looks like something we did!

Note: the second largest category isEditorOverHead.  EditorOverHead is essentially the profiler tool. If you are experiencing performance problems and turn on the profiler, you’ll see it become even slower. If your tasks are comparable to it, you don’t need to worry too much about your performance. It's only when  EditorOverHead is a small percent of your total resources that you should start getting worried!

If we drill down this specific category, we can see that most likely the problem is something from a script’s Update function. In fact, this is from CubeController.Update().

Unfortunately, aside from telling us which script’s update function is causing our performance problem, we don’t receive any more information, but this is a good start.

Looking at Update() in CubeController, we see that nothing looks wrong, but when we look at  RotateGameObject(), we see that someone (definitely not me!) wrote this:

for (int i = 0; i < 1000000; i++) {}

I don’t know about you, but I don’t think having a for loop going from 0 to 1,000,000 is ever a good idea!

I understand that we want to wait before we execute the code; however, instead of using a blocking for loop, let’s create a coroutine to wait and allow our computer to use its resources for other processing.

Here’s what our script looks like now:

using UnityEngine;
using System.Collections;

public class CubeController : MonoBehaviour
{
    void Update () {
        RotateGameObject();
        print("a messsage!");
    }

    public void RotateGameObject()
    {
        this.gameObject.transform.Rotate(0, 100 * Time.deltaTime, 0);
        StartCoroutine(WaitRotate());
    }

    private IEnumerator WaitRotate()
    {
        yield return new WaitForSeconds(10);
        this.gameObject.transform.Rotate(0, 100 * Time.deltaTime, 0);
    }
}


Now, if we run our game and play the profiler, you’ll see something like this:

Here’s what our profiler looks like after we replaced our CPU blocking for loop with a non-blocking WaitForSecond coroutine.

Wow! It’s significantly faster now running at 3.1 percent of our total resources. This is more than a 90 percent reduction from where it was before at 43.8 percent!

Instead, we now see that we have our  WaitRotate coroutine in our profiler, but that’s okay; it’s barely using any resources at all!

However, before we call it a day, it looks like there are still some resources usages of  Update.ScriptRunBehaviourUpdate that we can try to optimize.

If we keep expanding the hierarchy, you’ll see that 2.8 percent of our resources are being used by  LogStringToConsole.

It sounds like we’re using a print somewhere inside CubeController.Update().

If we go back in look at our Update function, what do we see?

using UnityEngine;
using System.Collections;

public class CubeController : MonoBehaviour
{
    void Update () {
        RotateGameObject();
        print("a messsage!");
    }

    public void RotateGameObject()
    {
        this.gameObject.transform.Rotate(0, 100 * Time.deltaTime, 0);
        StartCoroutine(WaitRotate());
    }

    private IEnumerator WaitRotate()
    {
        yield return new WaitForSeconds(10);
        this.gameObject.transform.Rotate(0, 100 * Time.deltaTime, 0);
    }
}


Hmm, that print statement right there seems suspicious right now. Someone probably left it there when they were debugging something (and once again, it DEFINITELY, wasn’t me!)

While it’s not a bad idea to use print statements to inform yourself and other developers of any warnings or errors, you should never call it every single time in Update().

As mentioned before,  Update() runs every frame of our game. For creating variables, that might be fine, but for printing, we write our message to the console every single time. This action by itself isn’t CPU intensive, but it’s a different story if we do it every frame!

  1. Get rid of the print statement.

This is what you’ll have left:

using UnityEngine;
using System.Collections;

public class CubeController : MonoBehaviour
{
    void Update () {
        RotateGameObject();
    }

    public void RotateGameObject()
    {
        this.gameObject.transform.Rotate(0, 100 * Time.deltaTime, 0);
        StartCoroutine(WaitRotate());
    }

    private IEnumerator WaitRotate()
    {
        yield return new WaitForSeconds(10);
        this.gameObject.transform.Rotate(0, 100 * Time.deltaTime, 0);
    }
}


Now, if we run the profiler tool again, here’s what we get:

Wow, we went from 3.1 percent to 0.1 percent CPU usage. Now, that’s some performance optimization!

Conclusion

By the end of this article, I hope that you can now see that solving performance problems doesn’t have to be a scary or mysterious process with Unity’s profiler tool.

In this article, we took a simple look at how we can begin to use the profiler tool to debug performance problems.

We made a new project with a simple script that was written poorly that we then optimized. Unfortunately, in a real-world scenario, it’ll be far more complex than this.

Chances are, you’ll run into situations where its not an algorithm problem with your scripts but rather because of the following:

  • Large number of assets in a scene taking your GPU
  • Library dependencies that are doing computational-heavy things (like bringing in their own physics engine)
  • Lighting/camera rendering issues
  • Or like us, a combination of all three, plus more!

Either way, after going through a live example of using the Unity tool, you now have a rough idea on the first steps you can take to diagnose performance problems in your game! Stay tuned for what we work on next!

unity Game engine Debug (command)

Published at DZone with permission of Josh Chang, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Mastering Coroutine Execution: Yielding, Flow, and Practical Use Cases in Unity
  • Unity and the Future of Game Development
  • When Airflow Tasks Get Stuck in Queued: A Real-World Debugging Story
  • Creating a Web Project: Key Steps to Identify Issues

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!