暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AdaptivePerformanceAnalytics.cs 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. #if (UNITY_EDITOR || DEVELOPMENT_BUILD) && UNITY_ANALYTICS
  2. #define ADAPTIVE_PERFORMANCE_ANALYTICS_LOGGING
  3. #endif
  4. using System;
  5. using System.Diagnostics;
  6. using System.Collections.Generic;
  7. using UnityEngine.Assertions;
  8. namespace UnityEngine.AdaptivePerformance
  9. {
  10. internal static class AdaptivePerformanceAnalytics
  11. {
  12. #if UNITY_ANALYTICS
  13. [Serializable]
  14. internal struct ProviderData
  15. {
  16. public bool enabled;
  17. public string id;
  18. public string version;
  19. public string customData;
  20. }
  21. [Serializable]
  22. internal struct FeatureData
  23. {
  24. public bool enabled;
  25. public string id;
  26. public string customData;
  27. }
  28. [Serializable]
  29. internal class AdaptivePerformanceAnalyticsEvent
  30. {
  31. // Is Adaptive Performance enable at all or only added as package and disabled
  32. public bool enabled;
  33. // Is Adaptive Performance active and has at least one provider initialized
  34. public bool initialized;
  35. // Name of the currently active provider
  36. public string activeProvider;
  37. public ProviderData[] providerData = new ProviderData[0];
  38. public string ctrlMode;
  39. public FeatureData[] featureData = new FeatureData[0];
  40. public AdaptivePerformanceAnalyticsEvent()
  41. {
  42. UpdateProviderData();
  43. UpdateFeatureData();
  44. }
  45. void UpdateProviderData()
  46. {
  47. List<Provider.AdaptivePerformanceSubsystemDescriptor> perfDescriptors = Provider.AdaptivePerformanceSubsystemRegistry.GetRegisteredDescriptors();
  48. if (perfDescriptors == null)
  49. return;
  50. if (perfDescriptors.Count == providerData.Length)
  51. return;
  52. Array.Resize<ProviderData>(ref providerData, perfDescriptors.Count);
  53. for (var i = 0; i < providerData.Length; ++i)
  54. {
  55. providerData[i].id = perfDescriptors[i].id;
  56. providerData[i].version = "0.0";
  57. providerData[i].enabled = false;
  58. providerData[i].customData = "";
  59. }
  60. }
  61. public void UpdateFeatureData()
  62. {
  63. if (s_Features.Count == featureData.Length)
  64. return;
  65. featureData = s_Features.ToArray();
  66. }
  67. public void UpdateGeneralEventData()
  68. {
  69. var ap = Holder.Instance;
  70. if (ap == null)
  71. return;
  72. enabled = ap.Active;
  73. if (ap.DevicePerformanceControl != null)
  74. {
  75. ctrlMode = ap.DevicePerformanceControl.PerformanceControlMode.ToString();
  76. }
  77. }
  78. }
  79. [Serializable]
  80. internal struct AdaptivePerformanceThermalAnalyticsEvent
  81. {
  82. public long numThrottlingEventSinceStartup;
  83. public long numThrottlingImminentEventSinceStartup;
  84. public long numNoWarningEventSinceStartup;
  85. public float currentTempTrend;
  86. public float currentTempLevel;
  87. }
  88. enum EventName
  89. {
  90. AdaptivePerformance,
  91. AdaptivePerformanceThermal
  92. }
  93. const string k_VendorKey = "unity.adaptiveperformance";
  94. const int k_MaxEventsPerHour = 100;
  95. const int k_MaxNumberOfElementsInStruct = 10;
  96. static AdaptivePerformanceAnalyticsEvent s_AdaptivePerformanceEvent;
  97. static AdaptivePerformanceThermalAnalyticsEvent s_AdaptivePerformanceThermalEvent;
  98. static List<FeatureData> s_Features = new List<FeatureData>();
  99. static WarningLevel s_LastWarningLevel = WarningLevel.NoWarning;
  100. static bool s_IsRegistered;
  101. #endif
  102. // A feature registers itself with a feature name and once a event is sent, the feature list of the event is updated with this new event
  103. [Conditional("UNITY_ANALYTICS")]
  104. public static void RegisterFeature(string feature, bool status)
  105. {
  106. #if UNITY_ANALYTICS
  107. Assert.IsFalse(feature.Equals(string.Empty));
  108. s_Features.Add(new FeatureData { id = feature, enabled = status, customData = "" });
  109. #endif
  110. }
  111. [Conditional("UNITY_ANALYTICS")]
  112. public static void SendAdaptiveStartupEvent(Provider.AdaptivePerformanceSubsystem subsystem)
  113. {
  114. #if UNITY_ANALYTICS
  115. if (s_AdaptivePerformanceEvent == null)
  116. s_AdaptivePerformanceEvent = new AdaptivePerformanceAnalyticsEvent();
  117. s_AdaptivePerformanceEvent.initialized = subsystem != null ? subsystem.initialized : false;
  118. s_AdaptivePerformanceEvent.activeProvider = subsystem != null ? subsystem.SubsystemDescriptor.id : "NoSubsystemLoaded";
  119. s_AdaptivePerformanceEvent.UpdateGeneralEventData();
  120. var providerData = s_AdaptivePerformanceEvent.providerData;
  121. if (subsystem != null)
  122. {
  123. for (var i = 0; i < providerData.Length; ++i)
  124. {
  125. if (providerData[i].id == subsystem.SubsystemDescriptor.id)
  126. {
  127. providerData[i].version = subsystem.Version.ToString();
  128. providerData[i].enabled = subsystem.initialized;
  129. }
  130. }
  131. }
  132. s_AdaptivePerformanceEvent.UpdateFeatureData();
  133. Send(EventName.AdaptivePerformance, s_AdaptivePerformanceEvent);
  134. #endif
  135. }
  136. // If the status of a feature changes it uses this method to update the AdaptivePerformanceEvent and sends the update. Features should not change often as it has performance implications using string comparison.
  137. [Conditional("UNITY_ANALYTICS")]
  138. public static void SendAdaptiveFeatureUpdateEvent(string feature, bool status)
  139. {
  140. #if UNITY_ANALYTICS
  141. // When features are initialized adaptivePerformanceEvent is not created yet but SendAdaptiveStartupEvent will send a status update for all events during creation of the event.
  142. if (s_AdaptivePerformanceEvent == null)
  143. return;
  144. s_AdaptivePerformanceEvent.UpdateGeneralEventData();
  145. s_AdaptivePerformanceEvent.UpdateFeatureData();
  146. for (var i = 0; i < s_AdaptivePerformanceEvent.featureData.Length; ++i)
  147. {
  148. if (s_AdaptivePerformanceEvent.featureData[i].id.Equals(feature))
  149. {
  150. if (s_AdaptivePerformanceEvent.featureData[i].enabled == status)
  151. return;
  152. s_AdaptivePerformanceEvent.featureData[i].enabled = status;
  153. }
  154. }
  155. Send(EventName.AdaptivePerformance, s_AdaptivePerformanceEvent);
  156. #endif
  157. }
  158. [Conditional("UNITY_ANALYTICS")]
  159. public static void SendAdaptivePerformanceThermalEvent(ThermalMetrics thermalMetrics)
  160. {
  161. #if UNITY_ANALYTICS
  162. // Temperature level and trend will call the method more often but we do not want to send events
  163. if (s_LastWarningLevel == thermalMetrics.WarningLevel)
  164. return;
  165. switch (thermalMetrics.WarningLevel)
  166. {
  167. case WarningLevel.Throttling:
  168. s_AdaptivePerformanceThermalEvent.numThrottlingEventSinceStartup++; break;
  169. case WarningLevel.ThrottlingImminent:
  170. s_AdaptivePerformanceThermalEvent.numThrottlingImminentEventSinceStartup++; break;
  171. case WarningLevel.NoWarning:
  172. s_AdaptivePerformanceThermalEvent.numNoWarningEventSinceStartup++; break;
  173. }
  174. s_AdaptivePerformanceThermalEvent.currentTempLevel = thermalMetrics.TemperatureLevel;
  175. s_AdaptivePerformanceThermalEvent.currentTempTrend = thermalMetrics.TemperatureTrend;
  176. s_LastWarningLevel = thermalMetrics.WarningLevel;
  177. Send(EventName.AdaptivePerformanceThermal, s_AdaptivePerformanceThermalEvent);
  178. #endif
  179. }
  180. #if UNITY_ANALYTICS
  181. static bool RegisterEvents()
  182. {
  183. if (s_IsRegistered)
  184. return true;
  185. var allEventNames = Enum.GetNames(typeof(EventName));
  186. for (var i = 0; i < allEventNames.Length; ++i)
  187. {
  188. if (!RegisterEvent(allEventNames[i]))
  189. return false;
  190. }
  191. s_IsRegistered = true;
  192. return s_IsRegistered;
  193. }
  194. static bool RegisterEvent(string eventName)
  195. {
  196. var result = Analytics.Analytics.RegisterEvent(eventName, k_MaxEventsPerHour, k_MaxNumberOfElementsInStruct, k_VendorKey);
  197. switch (result)
  198. {
  199. case Analytics.AnalyticsResult.Ok:
  200. AnalyticsLog.Debug("Registered event: {0}", eventName);
  201. return true;
  202. case Analytics.AnalyticsResult.TooManyRequests:
  203. // this is fine - event registration survives domain reload (native)
  204. return true;
  205. default:
  206. AnalyticsLog.Debug("Failed to register event {0}. Result: {1}", eventName, result);
  207. return false;
  208. }
  209. }
  210. static void Send(EventName eventName, object eventData)
  211. {
  212. if (!RegisterEvents())
  213. {
  214. AnalyticsLog.Debug("Disabled: event='{0}', time='{1}', payload={2}", eventName, DateTime.Now, JsonUtility.ToJson(eventData));
  215. return;
  216. }
  217. try
  218. {
  219. var result = Analytics.Analytics.SendEvent(eventName.ToString(), eventData);
  220. if (result == Analytics.AnalyticsResult.Ok)
  221. AnalyticsLog.Debug("Event sent: event='{0}', time='{1}', payload={2}", eventName, DateTime.Now, JsonUtility.ToJson(eventData));
  222. else
  223. AnalyticsLog.Debug("Failed to send event {0}. Result: {1}", eventName, result);
  224. }
  225. catch (Exception ex)
  226. {
  227. AnalyticsLog.Debug("Failed to send event {0}. Result: {1}", eventName, ex);
  228. }
  229. }
  230. #endif
  231. internal static class AnalyticsLog
  232. {
  233. [Conditional("ADAPTIVE_PERFORMANCE_ANALYTICS_LOGGING")]
  234. public static void Debug(string format, params object[] args)
  235. {
  236. IAdaptivePerformanceSettings settings = AdaptivePerformanceGeneralSettings.Instance?.Manager.ActiveLoaderAs<AdaptivePerformanceLoader>()?.GetSettings();
  237. if (settings != null && settings.logging)
  238. UnityEngine.Debug.Log(System.String.Format("[Analytics] " + format, args));
  239. }
  240. }
  241. }
  242. }