Dodaj funkcje rejestrowania czasu wczytywania

Rejestrowanie zdarzeń wczytywania w grze jest ważne z 2 powodów:

  1. Aby uniknąć zanieczyszczenia danych o czasie klatki podczas wczytywania.
  2. Analizować czasy wczytywania, aby sprawdzać, kiedy i gdzie są one dłuższe niż akceptowalne.

Z wydarzeniem ładowania mogą być powiązane metadane:

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;
}

Wszystkie pola, które nie są istotne, mogą mieć wartość zero.

Z wydarzeniem wczytywania może być też powiązana adnotacja. Możesz je zdefiniować w taki sam sposób jak adnotacje dotyczące czasu klatki, używając co najmniej jednego pola w Annotationwiadomości.

Result<ulong> StartRecordingLoadingTime(LoadingTimeMetadata eventMetadata, TAnnotation annotation);

Ta funkcja rozpoczyna rejestrowanie zdarzenia czasu wczytywania powiązanego z podanymi metadanymi i adnotacją oraz wypełnia wartość Result<ulong>.value, która będzie używana w funkcji StopRecordingLoadingTime().

ErrorCode StopRecordingLoadingTime(ulong handle);

Ta funkcja zatrzymuje rejestrowanie zdarzenia rozpoczęte wcześniej przez funkcję StartRecordingLoadingTime(). Zdarzenie zostanie przesłane podczas następnego opróżniania sesji.

Wczytuję funkcje grupy

W grze możesz rejestrować kilka zdarzeń wczytywania w jednym okresie wczytywania widocznym dla użytkownika. Obejmują one m.in. wczytywanie plików, wczytywanie scen, dekompresję i kompilację shaderów.

Warto poinformować narzędzie Android Performance Tuner, że zdarzenia wczytywania należą do takiej grupy, aby mogło ono dostarczać lepsze statystyki. Aby to zrobić, umieść zdarzenia ładowania w nawiasach za pomocą tych funkcji rozpoczęcia i zatrzymania.

Result<ulong> StartLoadingGroup(LoadingTimeMetadata eventMetadata, TAnnotation annotation);

Ta funkcja uruchamia grupę wczytywania powiązaną z podanymi metadanymi i adnotacją oraz wypełnia element Result<ulong>.value, który będzie używany w funkcji StopLoadingGroup(). Metadane i adnotacje nie są obecnie używane przez backend Google Play, ale tylko adnotację można ustawić na null. Wszystkie kolejne zdarzenia wczytywania są oznaczane unikalnym identyfikatorem grupy.

ErrorCode StopLoadingGroup(ulong handle);

Ta funkcja zatrzymuje grupę ładowania, która została wcześniej uruchomiona przez StartLoadingGroup(). Kolejne zdarzenia wczytywania nie będą miały identyfikatora grupy, dopóki ponownie nie zostanie wywołana funkcja StartLoadingGroup().

Rysunek 1. Przykład grupy wczytywania

Przykłady

Oto kilka przykładów dodawania do gry funkcji czasu ładowania.

Zdarzenia wczytywania plików

Poniższy przykład kodu pokazuje, jak rejestrować zdarzenia ładowania plików w grze.

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;
        }
    }
}

Zdarzenia wczytywania sceny

Poniższy przykład kodu pokazuje, jak rejestrować zdarzenia wczytywania scen w grze.

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);
}

Wczytuję funkcje grupy

Poniższy przykład kodu pokazuje, jak dodać do gry funkcje grupy wczytywania.

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);
}