Rasagar/Library/PackageCache/com.unity.burst/Documentation~/debugging-profiling-tools.md
2024-08-26 23:07:20 +03:00

7.3 KiB

Debugging and profiling tools

The following sections describe how to debug and profile your Burst-compiled code in the Editor and in player builds.

Tip

Before attempting to debug Burst-compiled code, enable script debugging for the Editor, or a player build by following the steps in Debug C# code in Unity. Although you can theoretically debug Burst-compiled code even when the script compilation mode is set to Release, in practice it doesn't work reliably. Breakpoints might be skipped, and variables might not appear in the Locals window, for example.

Debugging Burst-compiled code in the Editor

To debug Burst-compiled code in the Editor, you can either use a managed debugger, or a native debugger. This section explains both options.

Attach a managed debugger

You can attach a managed debugger such as Visual Studio, Visual Studio for Mac, or JetBrains Rider. This is the same type of debugger you can use to debug regular managed C# code in your Unity project. The ways of attaching a debugger differ depending on the version of Unity you're using:

  • Unity 2022.2+: When you place a breakpoint inside Burst-compiled code, and you have a managed debugger attached, Unity disables Burst automatically for that code path. This allows you to use a managed debugger to debug the managed version of your code. When you remove all breakpoints from that code path, Unity re-enables Burst for that code path.

  • Unity 2022.1 and older: Disable Burst, either with the global option in the Editor Burst menu (Jobs > Burst > Enable Compilation), or comment out the [BurstCompile] attribute from the specific entry-point that you want to debug.

Attach a native debugger

You can attach a native debugger such as Visual Studio or Xcode. Before doing so, you need to disable Burst optimizations. You can do this in the following ways:

  • Use the Native Debug Mode Compilation setting in the Editor Burst menu (Jobs > Burst > Native Debug Mode Compilation). Important: This setting disables optimizations across all jobs, which impacts the performance of Burst code. If you want to disable optimizations only for a specific job, use the other option in this list.

  • Add the Debug = true flag to your job, which disables optimizations and enables debugging on that specific job:

    [BurstCompile(Debug = true)]
    public struct MyJob : IJob
    {
        // ...
    }
    

    Tip

    Player builds pick up the Debug flag, so you can also use this to debug a player build.

To attach a native debugger to the Unity Editor process, see the native debugging section below.

Debugging Burst-compiled code in a player build

Because of the way that Unity builds the code for a player, you need to tell the debugging tool where to find the symbols. To do this, point the tool to the folder that contains the lib_burst_generated files, which is usually in the Plugins folder.

To debug Burst-compiled code in a player build, you need to attach a native debugger (such as Visual Studio or Xcode) to the player process. Before doing so, you need to:

  • Enable symbol generation. You can do this in either of two ways:

    • Enable the Development Build option before you build the player, or

    • Enable the Force Debug Information option in Burst AOT Player Settings

  • Disable Burst optimizations. You can do this in either of two ways:

    • Disable the Enable Optimizations option in Burst AOT Player Settings. Important: This setting disables optimizations across all jobs, which impacts the performance of Burst code. If you want to disable optimizations only for a specific job, use the other option in this list.

    • Add the Debug = true flag to your job, which disables optimizations and enables debugging on that specific job:

      [BurstCompile(Debug = true)]
      public struct MyJob : IJob
      {
          // ...
      }
      

To attach a native debugger to the player process, see the native debugging section below.

Native debugging

Follow the instructions above to setup native debugging correctly for the Editor or a player build. Then, attach a native debugger such as Visual Studio or Xcode.

Native debugging limitations

  • Native debuggers can't discover lambda captures on Entity.ForEach, so you can't inspect variables originating from these.
  • Structs that use [StructLayout(LayoutKind=Explicit)] and have overlapping fields are represented by a struct that hides one of the overlaps.

Types that are nested, are namespaced in C/C++ style. e.g.

namespace Pillow
{
	public struct Spot
	{
		public struct SubSpot
		{
            public int a;
            public int b;
        }
		public int a;
		public int b;
		public SubSpot sub;
	}

You would refer to SubSpot as Pillow::Spot::SubSpot in this case (for instance if you were trying to cast a pointer in a debugger watch window).

Code-based breakpoints

Burst supports code-based breakpoints through the System.Diagnostics.Debugger.Break method. This method generates a debug trap in your code. You must attach a debugger to your code so that it can intercept the break. Breakpoints trigger whether you've attached a debugger or not.

Burst adds information to track local variables, function parameters and breakpoints. If your debugger supports conditional breakpoints, use these over adding breakpoints in your code, because they only fire when you've attached a debugger.

Profiling Burst-compiled code

Profiling using standalone profiling tools

You can use profiling tools (such as Instruments or Superluminal) to profile Burst-compiled code in a player build. Because of the way that Unity builds the code for a player, you need to tell the profiling tool where to find the symbols. To do this, point the tool to the folder that contains the lib_burst_generated files, which is usually in the Plugins folder.

Unity Profiler markers

To improve the data you get from Unity Profiler (either for Burst-compiled code running in the Editor or in an attached player), you can create Unity Profiler markers from Burst code by calling new ProfilerMarker("MarkerName"):

[BurstCompile]
private static class ProfilerMarkerWrapper
{
    private static readonly ProfilerMarker StaticMarker = new ProfilerMarker("TestStaticBurst");

    [BurstCompile(CompileSynchronously = true)]
    public static int CreateAndUseProfilerMarker(int start)
    {
        using (StaticMarker.Auto())
        {
            var p = new ProfilerMarker("TestBurst");
            p.Begin();
            var result = 0;
            for (var i = start; i < start + 100000; i++)
            {
                result += i;
            }
            p.End();
            return result;
        }
    }
}