It's important to record when your game is performing loading events for
two reasons:

1. To avoid polluting your frame time data while loading.
2. To analyze load times to see when and where load times are longer than acceptable.

A loading event can have associated metadata:  

    public class LoadingTimeMetadata
    {
        public enum LoadingState
        {
            Unknown = 0,

            /// <summary>
            ///     The first time the game is run.
            /// </summary>
            FirstRun = 1,

            /// <summary>
            ///     App is not backgrounded.
            /// </summary>
            ColdStart = 2,

            /// <summary>
            ///     App is backgrounded.
            /// </summary>
            WarmStart = 3,

            /// <summary>
            ///     App is backgrounded, least work needed.
            /// </summary>
            HotStart = 4,

            /// <summary>
            ///     Asset loading between levels.
            /// </summary>
            InterLevel = 5
        }

        public LoadingState state;

        public enum LoadingSource
        {
            UnknownSource = 0,

            /// <summary>
            ///     Uncompressing data.
            /// </summary>
            Memory = 1,

            /// <summary>
            ///     Reading assets from APK bundle.
            /// </summary>
            Apk = 2,

            /// <summary>
            ///     Reading assets from device storage.
            /// </summary>
            DeviceStorage = 3,

            /// <summary>
            ///     Reading assets from external storage, e.g. SD card.
            /// </summary>
            ExternalStorage = 4,

            /// <summary>
            ///     Loading assets from the network.
            /// </summary>
            Network = 5,

            /// <summary>
            ///     Shader compilation.
            /// </summary>
            ShaderCompilation = 6,

            /// <summary>
            ///     Time spent between process starting and onCreate.
            /// </summary>
            PreActivity = 7,

            /// <summary>
            ///     Total time spent between process starting and first render frame.
            /// </summary>
            FirstTouchToFirstFrame = 8,

            /// <summary>
            ///     Time from start to end of a group of events.
            /// </summary>
            TotalUserWaitForGroup = 9
        }

        public LoadingSource source;

        /// <summary>
        ///     0 = no compression, 100 = max compression
        /// </summary>
        public int compression_level;

        public enum NetworkConnectivity
        {
            Unknown = 0,
            Wifi = 1,
            CellularNetwork = 2
        }

        public NetworkConnectivity network_connectivity;

        /// <summary>
        ///     Bandwidth in bits per second.
        /// </summary>
        public ulong network_transfer_speed_bps;

        /// <summary>
        ///     Latency in nanoseconds.
        /// </summary>
        public ulong network_latency_ns;
    }

Any fields that aren't relevant to your needs can be zero.

A loading event can also have an associated annotation. You can define in the
same way as frame time annotations, using one or more fields in the `Annotation`
message.

[`Result<ulong> StartRecordingLoadingTime(LoadingTimeMetadata eventMetadata,
TAnnotation
annotation);`](https://developer.android.com/games/sdk/reference/performance-tuner/unity/class/google/android/performance-tuner/android-performance-tuner-t-fidelity-t-annotation-#startrecordingloadingtime)

This function starts recording a loading time event associated with the given
metadata and annotation, and fills in a `Result<ulong>.value` to be used in the
`StopRecordingLoadingTime()` function.

[`ErrorCode StopRecordingLoadingTime(ulong handle);`](https://developer.android.com/games/sdk/reference/performance-tuner/unity/class/google/android/performance-tuner/android-performance-tuner-t-fidelity-t-annotation-#stoprecordingloadingtime)

This function stops recording an event previously started by
`StartRecordingLoadingTime()`. The event is uploaded at the next session flush.

## Loading group functions

| **Warning:** All loading events must be part of a loading group. See [the code example](https://developer.android.com/games/sdk/performance-tuner/unity/loading-functions#loading-group-function) for loading group functions.

In your game, you may record several loading events for a single loading period
seen by the user. Some examples include [file loading](https://developer.android.com/games/sdk/performance-tuner/unity/loading-functions#file-loading), [scene
loading](https://developer.android.com/games/sdk/performance-tuner/unity/loading-functions#scene-loading), decompression and shader compilation.

It is important to inform Android Performance Tuner that loading events are part
of such a group so that it can provide better insights. Bracket your loading
events with the following start and stop functions in order to do this.
| **Note:** Only one loading group can be active at a time.

[`Result<ulong> StartLoadingGroup(LoadingTimeMetadata eventMetadata, TAnnotation
annotation);`](https://developer.android.com/games/sdk/reference/performance-tuner/unity/class/google/android/performance-tuner/android-performance-tuner-t-fidelity-t-annotation-#startloadinggroup)

This function starts a loading group associated with the given metadata and
annotation, and fills in a `Result<ulong>.value` to be used in the
`StopLoadingGroup()` function. The metadata and annotation are currently not
used by the Play backend but only the annotation can be set to `null`. All subsequent loading events
are tagged by a unique group ID.

[`ErrorCode StopLoadingGroup(ulong handle);`](https://developer.android.com/games/sdk/reference/performance-tuner/unity/class/google/android/performance-tuner/android-performance-tuner-t-fidelity-t-annotation-#stoploadinggroup)

This function stops a loading group previously started by `StartLoadingGroup()`.
Subsequent loading events will not have a group ID until `StartLoadingGroup()`
is called again.

![](https://developer.android.com/static/images/games/performance-tuner/loading-groups.png)
**Figure 1.** Example of the loading group.

## Examples

Here are some examples of how to add loading time functions to your game.

### File loading events

The following code example shows how to record file loading events in your game.  

    public RawImage image;

    IEnumerator LoadImageFromStreamingAssets(string imageName)
    {
        string imagePath = "file://" + Path.Combine(Application.streamingAssetsPath, imageName);
        using (var r = UnityWebRequestTexture.GetTexture(imagePath))
        {
            LoadingTimeMetadata fileLoadingMetadata = new LoadingTimeMetadata()
            {
                state = LoadingTimeMetadata.LoadingState.InterLevel,
                source = LoadingTimeMetadata.LoadingSource.DeviceStorage,
                // Fields are zero by default but they could be set as follows
                compression_level = 0,
                network_connectivity = 0,
                network_transfer_speed_bps = 0,
                network_latency_ns = 0
            };
            Annotation annotation = new Annotation()
            {
                Scene = Scene.MagicalForest
            };
            // Start recording loading time.
            Result<ulong> result = performanceTuner.StartRecordingLoadingTime(fileLoadingMetadata, annotation);
            yield return r.SendWebRequest();
            // Stop recording loading time.
            performanceTuner.StopRecordingLoadingTime(result.value);
            if (r.isNetworkError || r.isHttpError)
            {
                Debug.Log(r.error);
            }
            else
            {
                Texture2D tex = DownloadHandlerTexture.GetContent(r);
                image.texture = tex;
            }
        }
    }

### Scene loading events

The following code example shows how to record scene loading events in your
game.  

    IEnumerator LoadScene(int sceneIndex)
    {
        LoadingTimeMetadata metadata = new LoadingTimeMetadata()
            {state = LoadingTimeMetadata.LoadingState.InterLevel};
        Annotation annotation = new Annotation() {Scene = (Scene) (sceneIndex + 1)};
        Result<ulong> result = performanceTuner.StartRecordingLoadingTime(metadata, annotation);
        AsyncOperation asyncSceneLoad = SceneManager.LoadSceneAsync(sceneIndex, LoadSceneMode.Single);
        while (!asyncSceneLoad.isDone)
        {
            yield return null;
        }

        performanceTuner.StopRecordingLoadingTime(result.value);
    }

### Loading group functions

The following code example shows how to add loading group functions to your
game.  

    IEnumerator LoadImages()
    {
        LoadingTimeMetadata groupMetadata = new LoadingTimeMetadata()
        {
            state = LoadingTimeMetadata.LoadingState.InterLevel,
            source = LoadingTimeMetadata.LoadingSource.DeviceStorage,
        };
        Result<ulong> result = performanceTuner.StartLoadingGroup(groupMetadata, null);
        yield return StartCoroutine(LoadImageFromStreamingAssets("image1.jpeg"));
        yield return StartCoroutine(LoadImageFromStreamingAssets("image2.jpeg"));
        yield return StartCoroutine(LoadImageFromStreamingAssets("image3.jpeg"));
        yield return StartCoroutine(LoadImageFromStreamingAssets("image4.jpeg"));
        var stopErrorCode = performanceTuner.StopLoadingGroup(0);
    }