-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathLoadingTimeBenchmark.cs
More file actions
142 lines (117 loc) · 4.57 KB
/
Copy pathLoadingTimeBenchmark.cs
File metadata and controls
142 lines (117 loc) · 4.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
using Cysharp.Threading.Tasks;
using DCL.Diagnostics;
using DCL.PerformanceAndDiagnostics.Analytics;
using DCL.RealmNavigation;
using ECS.SceneLifeCycle;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace DCL.LoadingTimes
{
/// <summary>
/// CI-only benchmark of the startup loading stages: reports their durations to analytics and quits the client.
/// </summary>
public sealed class LoadingTimeBenchmark : IDisposable
{
private const string STAGE_PREFIX = "loading_stage_";
private const string START_LABEL = "start_time_s";
private const string STOP_LABEL = "stop_time_s";
private const string DURATION_LABEL = "duration_s";
private const string SCENE_HASH_LABEL = "scene_hash";
// The loading begins with the process, where realtimeSinceStartup is 0.
private const float APP_START_TIME = 0f;
// The analytics service dispatches on a background pump, quitting right away kills the request.
private static readonly TimeSpan ANALYTICS_DELIVERY_GRACE = TimeSpan.FromSeconds(5);
private readonly List<StageMeasure> measures = new ((int)LoadingStatus.LoadingStage.Completed + 1);
private readonly ILoadingStatus loadingStatus;
private readonly IAnalyticsController analytics;
private readonly IScenesCache scenesCache;
private bool reported;
public LoadingTimeBenchmark(ILoadingStatus loadingStatus, IAnalyticsController analytics, IScenesCache scenesCache)
{
this.loadingStatus = loadingStatus;
this.analytics = analytics;
this.scenesCache = scenesCache;
// Init is set before this subscription exists, so it can only be measured from the app start.
measures.Add(new StageMeasure
{
Stage = LoadingStatus.LoadingStage.Init,
StartTime = APP_START_TIME,
StopTime = APP_START_TIME,
});
loadingStatus.CurrentStageMut.OnUpdate += OnStageUpdated;
}
public void Dispose()
{
loadingStatus.CurrentStageMut.OnUpdate -= OnStageUpdated;
}
private void OnStageUpdated(LoadingStatus.LoadingStage stage)
{
if (reported) return;
Sample(stage);
if (stage != LoadingStatus.LoadingStage.Completed) return;
reported = true;
ReportAndQuitAsync().Forget();
}
private void Sample(LoadingStatus.LoadingStage stage)
{
float time = UnityEngine.Time.realtimeSinceStartup;
StageMeasure previous = measures[^1];
previous.StopTime = time;
measures[^1] = previous;
measures.Add(new StageMeasure
{
Stage = stage,
StartTime = time,
StopTime = time,
});
}
private JObject BuildPayload(string? sceneHash)
{
float stopTime = measures[^1].StopTime;
var payload = new JObject
{
{ SCENE_HASH_LABEL, sceneHash },
{ START_LABEL, APP_START_TIME },
{ STOP_LABEL, stopTime },
{ DURATION_LABEL, stopTime - APP_START_TIME },
};
foreach (StageMeasure measure in measures)
payload[$"{STAGE_PREFIX}{measure.Stage.ToString().ToLower()}"] = new JObject
{
{ START_LABEL, measure.StartTime },
{ STOP_LABEL, measure.StopTime },
{ DURATION_LABEL, measure.StopTime - measure.StartTime },
};
return payload;
}
private async UniTaskVoid ReportAndQuitAsync()
{
try
{
JObject payload = BuildPayload(scenesCache.CurrentScene.Value?.Info.Name);
analytics.Track(AnalyticsEvents.Profiling.LOADING_TIMES, payload, true);
#if UNITY_EDITOR
ReportHub.LogProductionInfo(payload.ToString());
#endif
await UniTask.Delay(ANALYTICS_DELIVERY_GRACE);
}
catch (OperationCanceledException) { }
catch (Exception e)
{
ReportHub.LogException(e, ReportCategory.ANALYTICS);
}
finally
{
Application.Quit();
}
}
private struct StageMeasure
{
public LoadingStatus.LoadingStage Stage;
public float StartTime;
public float StopTime;
}
}
}