Version: 2019.1
Low-level native plug-in interface
Low-level native plug-in rendering extensions

Low-level native plug-in Profiler API

The Unity Profiler native plug-in enables you to extract data from Unity via script for analysis in an external tool, such as Razor (PS4), PIX (Xbox, Windows), Chrome Tracing, ETW, ITT, Vtune and Telemetry. The Unity Profiler records events, and the Profiler native plug-in API exposes these events to a third-party profiling API, which passes them to the relevant analysis tool.

The following Unity Profiler features help capture instrumentation data for performance analysis:

  • Categories: Unity groups profile data into categories (such as Rendering, Scripting and Animation), and assigns a color to each category. This helps you visually distinguish the types of data in the Profiler window. The Profiler native plug-in API enables you to retrieve these colors so you can use them in an external profiler.

  • Usage flags: The Unity Profiler applies the following usage flags to event markers to help filter the data:

    • Availability flags that describe whether a marker is available in the Unity Editor, or a Development or Release Player.

    • Verbosity levels that correlate to the type of the task you are doing in the Editor, and the level of information that task requires (for example, internal, debug, or user level).

    Usage flags allow you to filter the data before you pass it to an external tool to reduce the amount of generated data, and filter the data in an external tool to reduce noise in the information.

  • Frame events: The Profiler native plug-in API enables you to do frame time analysis in an external profiler.

  • Thread profiling: Unity does a significant amount of work on threads (for example, the main thread, render thread and job system worker thread). You can use the Profiler native plug-in API to enable profiling on any thread.

Plug-in API callbacks

The native Profiler plug-in API provides the interface between Unity’s subsystems and third-party profiling APIs. The API is exposed by the IUnityProfilerCallbacks header, which Unity stores in the <UnityInstallPath>\Editor\Data\PluginAPI folder of your Unity installation.

To use the instrumentation data that the Unity Profiler generates in an external profiler, use this minimal set of callbacks:

  1. RegisterCreateCategoryCallback: Whenever Unity creates a category, the Profiler gets the category name and color, and registers this callback .

  2. RegisterCreateMarkerCallback: Whenever Unity creates a marker, the Profiler gets the marker name, category and usage flags, and registers this callback. UnityProfilerMarkerDesc represents a persistent pointer which you can use to filter markers in RegisterMarkerEventCallback.

  3. RegisterMarkerEventCallback: Tracks the external profiler push/pop markers with the Unity Profiler equivalents, and registers an event callback for the given marker. The Unity Profiler runs the specified callback when a scoped instrumentation event or a single-shot event occurs. You can also track memory allocation and garbage collection events as markers. Unity represents these events as GC.Alloc and GC.Collect respectively.

  4. RegisterFrameCallback: Encapsulates samples into logical frames for use in external profilers that don’t have a concept of frames, and registers a callback that the Unity Profiler runs when Unity starts the next logical CPU frame.

  5. RegisterCreateThreadCallback: Whenever Unity registers a thread for profiling, the Profiler gets the internal thread name, and registers this callback for that thread.

Usage examples

Minimal example

The following example shows you how to send begin and end events to an external profiler:

| #include <IUnityInterface.h>
#include <IUnityProfilerCallbacks.h><br/>
static IUnityProfilerCallbacks* s_UnityProfilerCallbacks = NULL;
static void UNITY_INTERFACE_API MyProfilerEventCallback(
    const UnityProfilerMarkerDesc* markerDesc,
    UnityProfilerMarkerEventType eventType,
    unsigned short eventDataCount,
    const UnityProfilerMarkerData* eventData, void* userData)
{
    switch (eventType)
    {
        case kUnityProfilerMarkerEventTypeBegin:
        {
            MyProfilerPushMarker(markerDesc->name);
            break;
        }
        case kUnityProfilerMarkerEventTypeEnd:
        {
            MyProfilerPopMarker(markerDesc->name);
            break;
        }
    }
}
static void UNITY_INTERFACE_API MyProfilerCreateEventCallback(
    const UnityProfilerMarkerDesc* markerDesc, void* userData)
{
    s_UnityProfilerCallbacks->
      RegisterEventCallback(markerDesc, MyProfilerEventCallback, NULL);
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
{
    s_UnityProfilerCallbacks = unityInterfaces->Get<IUnityProfilerCallbacks>();
    s_UnityProfilerCallbacks->
      RegisterCreateEventCallback(&MyProfilerCreateEventCallback, NULL);
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload()
{
    s_UnityProfilerCallbacks->
      UnregisterCreateEventCallback(&MyProfilerCreateEventCallback, NULL);
    s_UnityProfilerCallbacks->
      UnregisterEventCallback(NULL, &MyProfilerEventCallback, NULL);
}

Note: To unregister the given callback from all markers, run UnregisterEventCallback with the first parameter set to NULL.

UnitySystracePlugin example

You can register and unregister marker callbacks dynamically, once every frame. The following example shows you how to minimize profiling overhead by enabling and disabling callbacks, depending on a third party profile state.

| static void UNITY_INTERFACE_API SystraceFrameCallback(void* userData)
{
    bool isCapturing = ATrace_isEnabled();
    if (isCapturing != s_isCapturing)
    {
        s_isCapturing = isCapturing;
        if (isCapturing)
        {
            s_UnityProfilerCallbacks-><br/>              RegisterCreateMarkerCallback(SystraceCreateEventCallback, NULL);
        }
        else
        {
            s_UnityProfilerCallbacks->
              UnregisterCreateMarkerCallback(SystraceCreateEventCallback, NULL);
            s_UnityProfilerCallbacks->
              UnregisterMarkerEventCallback(NULL, SystraceEventCallback, NULL);
        }
    }
}

Note: To minimize callback overhead, you can register callbacks only for the duration of the capture.

The Systrace API provides the ATrace_isEnabled API, which determines whether capturing is enabled. You can check this on a per-frame basis to enable or disable callbacks dynamically. For a more advanced usage example, see the UnitySystracePlugin repository.

Useful markers

Unity has the following markers that contain useful metadata:

Profiler.DefaultMarker

A marker that Unity reserves for Profiler.BeginSample and Profiler.EndSample events. kUnityProfilerMarkerEventTypeBegin eventType corresponds to the Profiler.BeginSample event and has the following data:

  • Int32: The UnityEngine.Object instance id or 0 if the object is not specified.

  • UInt16 array: The UTF16 string that is passed to Profiler.BeginSample. The size is in bytes.

  • UInt32: The category index.

GC.Alloc

A marker that corresponds to garbage collection allocation. It has the following data:

  • Int64: The size of the allocation.

  • 2019–02–14 Page published with editorial review

  • Low-level Profiler native plug-in added in Unity 2018.3 NewIn20183

Low-level native plug-in interface
Low-level native plug-in rendering extensions