File size: 13,746 Bytes
18a519f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
using System;
using System.Collections.Generic;
using UnityEditor.Analytics;
using UnityEngine;
using UnityEngine.Analytics;

namespace UnityEditor.Performance.ProfileAnalyzer
{
    class ProfileAnalyzerAnalytics
    {
        const int k_MaxEventsPerHour = 100;
        const int k_MaxEventItems = 1000;
        const string k_VendorKey = "unity.profileanalyzer";
        const string k_EventTopicName = "usability";

        static bool s_EnableAnalytics = false;

        public static void EnableAnalytics()
        {
            AnalyticsResult result = EditorAnalytics.RegisterEventWithLimit(k_EventTopicName, k_MaxEventsPerHour, k_MaxEventItems, k_VendorKey);
            if (result == AnalyticsResult.Ok)
                s_EnableAnalytics = true;
        }

        public enum UIButton
        {
            Pull,
            OpenProfiler,
            CloseProfiler,
            JumpToFrame,
            ExportSingleFrames,
            ExportComparisonFrames,
        };

        public enum UIUsageMode
        {
            Single,
            Comparison,
        };

        public enum UIVisibility
        {
            FrameTimeContextMenu,
            Filters,
            TopTen,
            Frames,
            Threads,
            Markers,
        };

        public enum UIResizeView
        {
            Single,
            Comparison,
        };


        [Serializable]
        struct ProfileAnalyzerUIButtonEventParameters
        {
            public string name;

            public ProfileAnalyzerUIButtonEventParameters(string name)
            {
                this.name = name;
            }
        }

        // camelCase since these events get serialized to Json and naming convention in analytics is camelCase
        [Serializable]
        struct ProfileAnalyzerUIButtonEvent
        {
            public ProfileAnalyzerUIButtonEvent(string name, float durationInTicks)
            {
                subtype = "profileAnalyzerUIButton";

                // ts is auto added so no need to include it here
                //ts = (int)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
                this.duration = durationInTicks;

                parameters = new ProfileAnalyzerUIButtonEventParameters(name);
            }

            public string subtype;
            //public int ts;
            public float duration;  // Duration is in "ticks" 100 nanosecond intervals. I.e. 0.1 microseconds
            public ProfileAnalyzerUIButtonEventParameters parameters;
        }

        [Serializable]
        struct ProfileAnalyzerUIUsageEventParameters
        {
            public string name;

            public ProfileAnalyzerUIUsageEventParameters(string name)
            {
                this.name = name;
            }
        }

        [Serializable]
        struct ProfileAnalyzerUIUsageEvent
        {
            public ProfileAnalyzerUIUsageEvent(string name, float durationInTicks)
            {
                subtype = "profileAnalyzerModeUsage";

                this.duration = durationInTicks;

                parameters = new ProfileAnalyzerUIUsageEventParameters(name);
            }

            public string subtype;
            public float duration;  // Duration is in "ticks" 100 nanosecond intervals. I.e. 0.1 microseconds
            public ProfileAnalyzerUIUsageEventParameters parameters;
        }

        [Serializable]
        struct ProfileAnalyzerUIVisibilityEventParameters
        {
            public string name;
            public bool show;

            public ProfileAnalyzerUIVisibilityEventParameters(string name, bool show)
            {
                this.name = name;
                this.show = show;
            }
        }

        [Serializable]
        struct ProfileAnalyzerUIVisibilityEvent
        {
            public ProfileAnalyzerUIVisibilityEvent(string name, float durationInTicks, bool show)
            {
                subtype = "profileAnalyzerUIVisibility";

                this.duration = durationInTicks;

                parameters = new ProfileAnalyzerUIVisibilityEventParameters(name, show);
            }

            public string subtype;
            public float duration;  // Duration is in "ticks" 100 nanosecond intervals. I.e. 0.1 microseconds
            public ProfileAnalyzerUIVisibilityEventParameters parameters;
        }

        [Serializable]
        struct ProfileAnalyzerUIResizeEventParameters
        {
            public string name;
            public float width;
            public float height;
            public float screenWidth;
            public float screenHeight;
            public bool docked;

            public ProfileAnalyzerUIResizeEventParameters(string name, float width, float height, float screenWidth, float screenHeight, bool isDocked)
            {
                this.name = name;
                this.width = width;
                this.height = height;
                this.screenWidth = screenWidth;
                this.screenHeight = screenHeight;
                docked = isDocked;
            }
        }

        [Serializable]
        struct ProfileAnalyzerUIResizeEvent
        {
            public ProfileAnalyzerUIResizeEvent(string name, float durationInTicks, float width, float height, float screenWidth, float screenHeight, bool isDocked)
            {
                subtype = "profileAnalyzerUIResize";

                this.duration = durationInTicks;

                parameters = new ProfileAnalyzerUIResizeEventParameters(name, width, height, screenWidth, screenHeight, isDocked);
            }

            public string subtype;
            public float duration;  // Duration is in "ticks" 100 nanosecond intervals. I.e. 0.1 microseconds
            public ProfileAnalyzerUIResizeEventParameters parameters;
        }

        static float SecondsToTicks(float durationInSeconds)
        {
            return durationInSeconds * 10000;
        }

        public static bool SendUIButtonEvent(UIButton uiButton, float durationInSeconds)
        {
            if (!s_EnableAnalytics)
                return false;

            // Duration is in "ticks" 100 nanosecond intervals. I.e. 0.1 microseconds
            float durationInTicks = SecondsToTicks(durationInSeconds);

            ProfileAnalyzerUIButtonEvent uiButtonEvent;
            switch (uiButton)
            {
                case UIButton.Pull:
                    uiButtonEvent = new ProfileAnalyzerUIButtonEvent("profilerAnalyzerGrab", durationInTicks);
                    break;
                case UIButton.OpenProfiler:
                    uiButtonEvent = new ProfileAnalyzerUIButtonEvent("profilerAnalyzerOpenProfiler", durationInTicks);
                    break;
                case UIButton.CloseProfiler:
                    uiButtonEvent = new ProfileAnalyzerUIButtonEvent("profilerAnalyzerCloseProfiler", durationInTicks);
                    break;
                case UIButton.JumpToFrame:
                    uiButtonEvent = new ProfileAnalyzerUIButtonEvent("profilerAnalyzerJumpToFrame", durationInTicks);
                    break;
                case UIButton.ExportSingleFrames:
                    uiButtonEvent = new ProfileAnalyzerUIButtonEvent("profilerAnalyzerExportSingleFrames", durationInTicks);
                    break;
                case UIButton.ExportComparisonFrames:
                    uiButtonEvent = new ProfileAnalyzerUIButtonEvent("profilerAnalyzerExportComparisonFrames", durationInTicks);
                    break;
                default:
                    Debug.LogFormat("SendUIButtonEvent: Unsupported button type : {0}", uiButton);
                    return false;
            }


            AnalyticsResult result = EditorAnalytics.SendEventWithLimit(k_EventTopicName, uiButtonEvent);
            if (result != AnalyticsResult.Ok)
                return false;

            return true;
        }

        public static bool SendUIUsageModeEvent(UIUsageMode uiUsageMode, float durationInSeconds)
        {
            if (!s_EnableAnalytics)
                return false;

            // Duration is in "ticks" 100 nanosecond intervals. I.e. 0.1 microseconds
            float durationInTicks = SecondsToTicks(durationInSeconds);

            ProfileAnalyzerUIUsageEvent uiUsageEvent;
            switch (uiUsageMode)
            {
                case UIUsageMode.Single:
                    uiUsageEvent = new ProfileAnalyzerUIUsageEvent("profileAnalyzerSingle", durationInTicks);
                    break;
                case UIUsageMode.Comparison:
                    uiUsageEvent = new ProfileAnalyzerUIUsageEvent("profileAnalyzerCompare", durationInTicks);
                    break;
                default:
                    Debug.LogFormat("SendUsageEvent: Unsupported usage mode : {0}", uiUsageMode);
                    return false;
            }


            AnalyticsResult result = EditorAnalytics.SendEventWithLimit(k_EventTopicName, uiUsageEvent);
            if (result != AnalyticsResult.Ok)
                return false;

            return true;
        }

        public static bool SendUIVisibilityEvent(UIVisibility uiVisibility, float durationInSeconds, bool show)
        {
            if (!s_EnableAnalytics)
                return false;

            // Duration is in "ticks" 100 nanosecond intervals. I.e. 0.1 microseconds
            float durationInTicks = SecondsToTicks(durationInSeconds);

            ProfileAnalyzerUIVisibilityEvent uiUsageEvent;
            switch (uiVisibility)
            {
                case UIVisibility.FrameTimeContextMenu:
                    uiUsageEvent = new ProfileAnalyzerUIVisibilityEvent("profilerAnalyzerFrameTimeContextMenu", durationInTicks, show);
                    break;
                case UIVisibility.Filters:
                    uiUsageEvent = new ProfileAnalyzerUIVisibilityEvent("profilerAnalyzerFilters", durationInTicks, show);
                    break;
                case UIVisibility.TopTen:
                    uiUsageEvent = new ProfileAnalyzerUIVisibilityEvent("profilerAnalyzerTopTen", durationInTicks, show);
                    break;
                case UIVisibility.Frames:
                    uiUsageEvent = new ProfileAnalyzerUIVisibilityEvent("profilerAnalyzerFrames", durationInTicks, show);
                    break;
                case UIVisibility.Threads:
                    uiUsageEvent = new ProfileAnalyzerUIVisibilityEvent("profilerAnalyzerThreads", durationInTicks, show);
                    break;
                case UIVisibility.Markers:
                    uiUsageEvent = new ProfileAnalyzerUIVisibilityEvent("profilerAnalyzerMarkers", durationInTicks, show);
                    break;
                default:
                    Debug.LogFormat("SendUIVisibilityEvent: Unsupported visibililty item : {0}", uiVisibility);
                    return false;
            }

            AnalyticsResult result = EditorAnalytics.SendEventWithLimit(k_EventTopicName, uiUsageEvent);
            if (result != AnalyticsResult.Ok)
                return false;

            return true;
        }

        public static bool SendUIResizeEvent(UIResizeView uiResizeView, float durationInSeconds, float width, float height, bool isDocked)
        {
            if (!s_EnableAnalytics)
                return false;

            // Duration is in "ticks" 100 nanosecond intervals. I.e. 0.1 microseconds
            float durationInTicks = SecondsToTicks(durationInSeconds);

            ProfileAnalyzerUIResizeEvent uiResizeEvent;
            switch (uiResizeView)
            {
                case UIResizeView.Single:
                    // Screen.width, Screen.height is game view size
                    uiResizeEvent = new ProfileAnalyzerUIResizeEvent("profileAnalyzerSingle", durationInTicks, width, height, Screen.currentResolution.width, Screen.currentResolution.height, isDocked);
                    break;
                case UIResizeView.Comparison:
                    uiResizeEvent = new ProfileAnalyzerUIResizeEvent("profileAnalyzerCompare", durationInTicks, width, height, Screen.currentResolution.width, Screen.currentResolution.height, isDocked);
                    break;
                default:
                    Debug.LogFormat("SendUIResizeEvent: Unsupported view : {0}", uiResizeView);
                    return false;
            }

            AnalyticsResult result = EditorAnalytics.SendEventWithLimit(k_EventTopicName, uiResizeEvent);
            if (result != AnalyticsResult.Ok)
                return false;

            return true;
        }

        internal class Analytic
        {
            double m_StartTime;
            float m_DurationInSeconds;

            public Analytic()
            {
                m_StartTime = EditorApplication.timeSinceStartup;
                m_DurationInSeconds = 0;
            }

            public void End()
            {
                m_DurationInSeconds = (float)(EditorApplication.timeSinceStartup - m_StartTime);
            }

            public float GetDurationInSeconds()
            {
                return m_DurationInSeconds;
            }
        }

        static public Analytic BeginAnalytic()
        {
            return new Analytic();
        }

        static public void SendUIButtonEvent(UIButton uiButton, Analytic instance)
        {
            instance.End();
            SendUIButtonEvent(uiButton, instance.GetDurationInSeconds());
        }

        static public void SendUIUsageModeEvent(UIUsageMode uiUsageMode, Analytic instance)
        {
            instance.End();
            SendUIUsageModeEvent(uiUsageMode, instance.GetDurationInSeconds());
        }
    }
}