InternalProfiler.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. #include "InternalProfiler.h"
  2. #include <stdint.h>
  3. #include <stdio.h>
  4. #include <mach/mach_time.h>
  5. #define ENABLE_DETAILED_GC_STATS 0
  6. #if ENABLE_INTERNAL_PROFILER
  7. namespace
  8. {
  9. enum
  10. {
  11. GpuProfilerBlockEachNthFrame = 4
  12. };
  13. mach_timebase_info_data_t timebaseInfo;
  14. void ProfilerInit()
  15. {
  16. mach_timebase_info(&timebaseInfo);
  17. }
  18. static float MachToMillisecondsDelta(int64_t delta)
  19. {
  20. // Convert to nanoseconds
  21. delta *= timebaseInfo.numer;
  22. delta /= timebaseInfo.denom;
  23. float result = (float)delta / 1000000.0F;
  24. return result;
  25. }
  26. struct ProfilerBlock
  27. {
  28. int64_t maxV, minV, avgV;
  29. };
  30. void ProfilerBlock_Update(struct ProfilerBlock* b, int64_t d, bool reset, bool avoidZero = false)
  31. {
  32. if (reset)
  33. {
  34. b->maxV = b->minV = b->avgV = d;
  35. }
  36. else
  37. {
  38. b->maxV = (d > b->maxV) ? d : b->maxV;
  39. if (avoidZero && (b->minV == 0 || d == 0))
  40. b->minV = (d > b->minV) ? d : b->minV;
  41. else
  42. b->minV = (d < b->minV) ? d : b->minV;
  43. b->avgV += d;
  44. }
  45. }
  46. ProfilerBlock _framePB;
  47. ProfilerBlock _playerPB;
  48. ProfilerBlock _batchCountPB;
  49. ProfilerBlock _drawCallCountPB;
  50. ProfilerBlock _triCountPB;
  51. ProfilerBlock _vertCountPB;
  52. ProfilerBlock _dynamicBatchDtPB;
  53. ProfilerBlock _dynamicBatchCountPB;
  54. ProfilerBlock _dynamicBatchedDrawCallCountPB;
  55. ProfilerBlock _dynamicBatchedTriCountPB;
  56. ProfilerBlock _dynamicBatchedVertCountPB;
  57. ProfilerBlock _staticBatchCountPB;
  58. ProfilerBlock _staticBatchedDrawCallCountPB;
  59. ProfilerBlock _staticBatchedTriCountPB;
  60. ProfilerBlock _staticBatchedVertCountPB;
  61. ProfilerBlock _fixedBehaviourManagerPB;
  62. ProfilerBlock _fixedPhysicsManagerPB;
  63. ProfilerBlock _dynamicBehaviourManagerPB;
  64. ProfilerBlock _coroutinePB;
  65. ProfilerBlock _skinMeshUpdatePB;
  66. ProfilerBlock _animationUpdatePB;
  67. ProfilerBlock _unityRenderLoopPB;
  68. ProfilerBlock _unityCullingPB;
  69. ProfilerBlock _unityMSAAResolvePB;
  70. ProfilerBlock _fixedUpdateCountPB;
  71. ProfilerBlock _GCCountPB;
  72. ProfilerBlock _GCDurationPB;
  73. int _frameId = 0;
  74. // our rendering is dictated by ios display link
  75. // frametime will be time between two frame starts
  76. // unity player time will be time between frame start/end
  77. int64_t _lastFrameStart = -1;
  78. int64_t _frameStart = 0;
  79. int64_t _frameTime = 0;
  80. int64_t _playerTime = 0;
  81. int64_t _msaaResolveStart = 0;
  82. int64_t _msaaResolve = 0;
  83. void* _msaaResolveCounter = 0;
  84. UnityFrameStats _unityFrameStats;
  85. }
  86. extern "C" int64_t UnityScriptingGetUsedSize();
  87. extern "C" int64_t UnityScriptingGetHeapSize();
  88. static void Profiler_SetupScriptingProfile();
  89. void Profiler_InitProfiler()
  90. {
  91. Profiler_SetupScriptingProfile();
  92. ProfilerInit();
  93. if (_msaaResolveCounter == 0)
  94. _msaaResolveCounter = UnityCreateProfilerCounter("iOS.MSAAResolve");
  95. }
  96. void Profiler_UninitProfiler()
  97. {
  98. UnityDestroyProfilerCounter(_msaaResolveCounter);
  99. }
  100. void Profiler_FrameStart()
  101. {
  102. _frameStart = mach_absolute_time();
  103. if (_lastFrameStart < 0)
  104. {
  105. _lastFrameStart = _frameStart; return;
  106. }
  107. _frameTime = _frameStart - _lastFrameStart;
  108. _lastFrameStart = _frameStart;
  109. }
  110. void Profiler_FrameEnd()
  111. {
  112. _playerTime = mach_absolute_time() - _frameStart;
  113. }
  114. void Profiler_FramePresent(const UnityFrameStats* unityFrameStats)
  115. {
  116. if (!unityFrameStats)
  117. return;
  118. _unityFrameStats = *unityFrameStats;
  119. const int EachNthFrame = 32;
  120. if (_frameId == EachNthFrame)
  121. {
  122. _frameId = 0;
  123. ::printf("iPhone Unity internal profiler stats\n");
  124. ::printf("frametime> min: %4.1f max: %4.1f avg: %4.1f\n", MachToMillisecondsDelta(_framePB.minV), MachToMillisecondsDelta(_framePB.maxV), MachToMillisecondsDelta(_framePB.avgV / EachNthFrame));
  125. ::printf("cpu-player> min: %4.1f max: %4.1f avg: %4.1f\n", MachToMillisecondsDelta(_playerPB.minV), MachToMillisecondsDelta(_playerPB.maxV), MachToMillisecondsDelta(_playerPB.avgV / EachNthFrame));
  126. ::printf("batches> min: %3d max: %3d avg: %3d\n", (int)_batchCountPB.minV, (int)_batchCountPB.maxV, (int)(_batchCountPB.avgV / EachNthFrame));
  127. ::printf("draw calls> min: %3d max: %3d avg: %3d\n", (int)_drawCallCountPB.minV, (int)_drawCallCountPB.maxV, (int)(_drawCallCountPB.avgV / EachNthFrame));
  128. ::printf("tris> min: %5d max: %5d avg: %5d\n", (int)_triCountPB.minV, (int)_triCountPB.maxV, (int)(_triCountPB.avgV / EachNthFrame));
  129. ::printf("verts> min: %5d max: %5d avg: %5d\n", (int)_vertCountPB.minV, (int)_vertCountPB.maxV, (int)(_vertCountPB.avgV / EachNthFrame));
  130. ::printf("dynamic batching> batched draw calls: %3d batches: %3d tris: %5d verts: %5d\n",
  131. (int)(_dynamicBatchedDrawCallCountPB.avgV / EachNthFrame),
  132. (int)(_dynamicBatchCountPB.avgV / EachNthFrame),
  133. (int)(_dynamicBatchedTriCountPB.avgV / EachNthFrame),
  134. (int)(_dynamicBatchedVertCountPB.avgV / EachNthFrame));
  135. ::printf("static batching> batched draw calls: %3d batches: %3d tris: %5d verts: %5d\n",
  136. (int)(_staticBatchedDrawCallCountPB.avgV / EachNthFrame),
  137. (int)(_staticBatchCountPB.avgV / EachNthFrame),
  138. (int)(_staticBatchedTriCountPB.avgV / EachNthFrame),
  139. (int)(_staticBatchedVertCountPB.avgV / EachNthFrame));
  140. ::printf("player-detail> physx: %4.1f animation: %4.1f culling %4.1f skinning: %4.1f batching: %4.1f render: %4.1f fixed-update-count: %d .. %d\n",
  141. MachToMillisecondsDelta(_fixedPhysicsManagerPB.avgV / EachNthFrame),
  142. MachToMillisecondsDelta(_animationUpdatePB.avgV / EachNthFrame),
  143. MachToMillisecondsDelta(_unityCullingPB.avgV / EachNthFrame),
  144. MachToMillisecondsDelta(_skinMeshUpdatePB.avgV / EachNthFrame),
  145. MachToMillisecondsDelta(_dynamicBatchDtPB.avgV / EachNthFrame),
  146. MachToMillisecondsDelta((_unityRenderLoopPB.avgV - _dynamicBatchDtPB.avgV - _unityCullingPB.avgV) / EachNthFrame),
  147. (int)_fixedUpdateCountPB.minV, (int)_fixedUpdateCountPB.maxV);
  148. ::printf("scripting-scripts> update: %4.1f fixedUpdate: %4.1f coroutines: %4.1f \n", MachToMillisecondsDelta(_dynamicBehaviourManagerPB.avgV / EachNthFrame), MachToMillisecondsDelta(_fixedBehaviourManagerPB.avgV / EachNthFrame), MachToMillisecondsDelta(_coroutinePB.avgV / EachNthFrame));
  149. #if UNITY_DEVELOPER_BUILD
  150. ::printf("scripting-memory> used heap: %lld allocated heap: %lld max number of collections: %d collection total duration: %4.1f\n", UnityScriptingGetUsedSize(), UnityScriptingGetHeapSize(), (int)_GCCountPB.avgV, MachToMillisecondsDelta(_GCDurationPB.avgV));
  151. #else
  152. ::printf("scripting-memory> information not available on non-development player configuration\n");
  153. #endif
  154. ::printf("----------------------------------------\n");
  155. }
  156. ProfilerBlock_Update(&_framePB, _frameTime, (_frameId == 0));
  157. ProfilerBlock_Update(&_playerPB, _playerTime, (_frameId == 0));
  158. ProfilerBlock_Update(&_batchCountPB, _unityFrameStats.batchCount, (_frameId == 0));
  159. ProfilerBlock_Update(&_drawCallCountPB, _unityFrameStats.drawCallCount, (_frameId == 0));
  160. ProfilerBlock_Update(&_triCountPB, _unityFrameStats.triCount, (_frameId == 0));
  161. ProfilerBlock_Update(&_vertCountPB, _unityFrameStats.vertCount, (_frameId == 0));
  162. ProfilerBlock_Update(&_dynamicBatchDtPB, _unityFrameStats.dynamicBatchDt, (_frameId == 0));
  163. ProfilerBlock_Update(&_dynamicBatchCountPB, _unityFrameStats.dynamicBatchCount, (_frameId == 0));
  164. ProfilerBlock_Update(&_dynamicBatchedDrawCallCountPB, _unityFrameStats.dynamicBatchedDrawCallCount, (_frameId == 0));
  165. ProfilerBlock_Update(&_dynamicBatchedTriCountPB, _unityFrameStats.dynamicBatchedTris, (_frameId == 0));
  166. ProfilerBlock_Update(&_dynamicBatchedVertCountPB, _unityFrameStats.dynamicBatchedVerts, (_frameId == 0));
  167. ProfilerBlock_Update(&_staticBatchCountPB, _unityFrameStats.staticBatchCount, (_frameId == 0));
  168. ProfilerBlock_Update(&_staticBatchedDrawCallCountPB, _unityFrameStats.staticBatchedDrawCallCount, (_frameId == 0));
  169. ProfilerBlock_Update(&_staticBatchedTriCountPB, _unityFrameStats.staticBatchedTris, (_frameId == 0));
  170. ProfilerBlock_Update(&_staticBatchedVertCountPB, _unityFrameStats.staticBatchedVerts, (_frameId == 0));
  171. ProfilerBlock_Update(&_fixedBehaviourManagerPB, _unityFrameStats.fixedBehaviourManagerDt, (_frameId == 0));
  172. ProfilerBlock_Update(&_fixedPhysicsManagerPB, _unityFrameStats.fixedPhysicsManagerDt, (_frameId == 0));
  173. ProfilerBlock_Update(&_dynamicBehaviourManagerPB, _unityFrameStats.dynamicBehaviourManagerDt, (_frameId == 0));
  174. ProfilerBlock_Update(&_coroutinePB, _unityFrameStats.coroutineDt, (_frameId == 0));
  175. ProfilerBlock_Update(&_skinMeshUpdatePB, _unityFrameStats.skinMeshUpdateDt, (_frameId == 0));
  176. ProfilerBlock_Update(&_animationUpdatePB, _unityFrameStats.animationUpdateDt, (_frameId == 0));
  177. ProfilerBlock_Update(&_unityRenderLoopPB, _unityFrameStats.renderDt, (_frameId == 0));
  178. ProfilerBlock_Update(&_unityCullingPB, _unityFrameStats.cullingDt, (_frameId == 0));
  179. ProfilerBlock_Update(&_unityMSAAResolvePB, _msaaResolve, (_frameId == 0));
  180. ProfilerBlock_Update(&_fixedUpdateCountPB, _unityFrameStats.fixedUpdateCount, (_frameId == 0));
  181. ProfilerBlock_Update(&_GCCountPB, 0, (_frameId == 0));
  182. ProfilerBlock_Update(&_GCDurationPB, 0, (_frameId == 0));
  183. _msaaResolve = 0;
  184. ++_frameId;
  185. }
  186. void Profiler_StartMSAAResolve()
  187. {
  188. UnityStartProfilerCounter(_msaaResolveCounter);
  189. _msaaResolveStart = mach_absolute_time();
  190. }
  191. void Profiler_EndMSAAResolve()
  192. {
  193. _msaaResolve += (mach_absolute_time() - _msaaResolveStart);
  194. UnityEndProfilerCounter(_msaaResolveCounter);
  195. }
  196. //
  197. // scriptint memory profiling
  198. //
  199. extern "C"
  200. {
  201. enum ScriptingGCEvent
  202. {
  203. SCRIPTING_GC_EVENT_START,
  204. SCRIPTING_GC_EVENT_MARK_START,
  205. SCRIPTING_GC_EVENT_MARK_END,
  206. SCRIPTING_GC_EVENT_RECLAIM_START,
  207. SCRIPTING_GC_EVENT_RECLAIM_END,
  208. SCRIPTING_GC_EVENT_END,
  209. SCRIPTING_GC_EVENT_PRE_STOP_WORLD,
  210. SCRIPTING_GC_EVENT_POST_STOP_WORLD,
  211. SCRIPTING_GC_EVENT_PRE_START_WORLD,
  212. SCRIPTING_GC_EVENT_POST_START_WORLD
  213. };
  214. enum ScriptingProfileFlags
  215. {
  216. SCRIPTING_PROFILE_NONE = 0,
  217. SCRIPTING_PROFILE_APPDOMAIN_EVENTS = 1 << 0,
  218. SCRIPTING_PROFILE_ASSEMBLY_EVENTS = 1 << 1,
  219. SCRIPTING_PROFILE_MODULE_EVENTS = 1 << 2,
  220. SCRIPTING_PROFILE_CLASS_EVENTS = 1 << 3,
  221. SCRIPTING_PROFILE_JIT_COMPILATION = 1 << 4,
  222. SCRIPTING_PROFILE_INLINING = 1 << 5,
  223. SCRIPTING_PROFILE_EXCEPTIONS = 1 << 6,
  224. SCRIPTING_PROFILE_ALLOCATIONS = 1 << 7,
  225. SCRIPTING_PROFILE_GC = 1 << 8,
  226. SCRIPTING_PROFILE_THREADS = 1 << 9,
  227. SCRIPTING_PROFILE_REMOTING = 1 << 10,
  228. SCRIPTING_PROFILE_TRANSITIONS = 1 << 11,
  229. SCRIPTING_PROFILE_ENTER_LEAVE = 1 << 12,
  230. SCRIPTING_PROFILE_COVERAGE = 1 << 13,
  231. SCRIPTING_PROFILE_INS_COVERAGE = 1 << 14,
  232. SCRIPTING_PROFILE_STATISTICAL = 1 << 15,
  233. SCRIPTING_PROFILE_METHOD_EVENTS = 1 << 16,
  234. SCRIPTING_PROFILE_MONITOR_EVENTS = 1 << 17,
  235. SCRIPTING_PROFILE_IOMAP_EVENTS = 1 << 18, /* this should likely be removed, too */
  236. SCRIPTING_PROFILE_GC_MOVES = 1 << 19,
  237. };
  238. struct MemoryProfiler
  239. {
  240. int64_t gc_total_time;
  241. int64_t gc_mark_time;
  242. int64_t gc_reclaim_time;
  243. int64_t gc_stop_world_time;
  244. int64_t gc_start_world_time;
  245. };
  246. typedef void (*UnityScriptingProfileFunc)(void* /*MemoryProfiler*/ prof);
  247. typedef void (*UnityScriptingProfileGCFunc)(void* /*MemoryProfiler*/ prof, int event, int generation);
  248. typedef void (*UnityScriptingProfileGCResizeFunc)(void* /*MemoryProfiler*/ prof, int64_t new_size);
  249. void UnityScriptingProfilerInstall(void* /*MemoryProfiler*/ prof, UnityScriptingProfileFunc shutdown_callback);
  250. void UnityScriptingProfilerInstallGC(UnityScriptingProfileGCFunc callback, UnityScriptingProfileGCResizeFunc heap_resize_callback);
  251. void UnityScriptingProfilerSetEvents(int /*ScriptingProfileFlags*/ events);
  252. }
  253. static MemoryProfiler _MemoryProfiler;
  254. static void gc_event(void* profiler_, int event, int generation)
  255. {
  256. MemoryProfiler* profiler = (MemoryProfiler*)profiler_;
  257. switch (event)
  258. {
  259. case SCRIPTING_GC_EVENT_START:
  260. profiler->gc_total_time = mach_absolute_time();
  261. break;
  262. case SCRIPTING_GC_EVENT_END:
  263. {
  264. profiler->gc_total_time = mach_absolute_time() - profiler->gc_total_time;
  265. float delta = profiler->gc_total_time;
  266. ProfilerBlock_Update(&_GCDurationPB, delta, false);
  267. ProfilerBlock_Update(&_GCCountPB, 1, false);
  268. break;
  269. }
  270. case SCRIPTING_GC_EVENT_MARK_START:
  271. profiler->gc_mark_time = mach_absolute_time();
  272. break;
  273. case SCRIPTING_GC_EVENT_MARK_END:
  274. profiler->gc_mark_time = mach_absolute_time() - profiler->gc_mark_time;
  275. break;
  276. case SCRIPTING_GC_EVENT_RECLAIM_START:
  277. profiler->gc_reclaim_time = mach_absolute_time();
  278. break;
  279. case SCRIPTING_GC_EVENT_RECLAIM_END:
  280. profiler->gc_reclaim_time = mach_absolute_time() - profiler->gc_reclaim_time;
  281. break;
  282. case SCRIPTING_GC_EVENT_PRE_STOP_WORLD:
  283. profiler->gc_stop_world_time = mach_absolute_time();
  284. break;
  285. case SCRIPTING_GC_EVENT_POST_STOP_WORLD:
  286. profiler->gc_stop_world_time = mach_absolute_time() - profiler->gc_stop_world_time;
  287. break;
  288. case SCRIPTING_GC_EVENT_PRE_START_WORLD:
  289. profiler->gc_start_world_time = mach_absolute_time();
  290. break;
  291. case SCRIPTING_GC_EVENT_POST_START_WORLD:
  292. profiler->gc_start_world_time = mach_absolute_time() - profiler->gc_start_world_time;
  293. break;
  294. default:
  295. break;
  296. }
  297. #if ENABLE_DETAILED_GC_STATS
  298. if (event == SCRIPTING_GC_EVENT_END)
  299. {
  300. ::printf("scripting-gc> stop time: %4.1f mark time: %4.1f reclaim time: %4.1f start time: %4.1f total time: %4.1f \n",
  301. MachToMillisecondsDelta(profiler->gc_stop_world_time),
  302. MachToMillisecondsDelta(profiler->gc_mark_time),
  303. MachToMillisecondsDelta(profiler->gc_reclaim_time),
  304. MachToMillisecondsDelta(profiler->gc_start_world_time),
  305. MachToMillisecondsDelta(profiler->gc_total_time)
  306. );
  307. }
  308. #endif
  309. }
  310. static void gc_resize(void* profiler, int64_t new_size)
  311. {
  312. }
  313. static void profiler_shutdown(void* profiler)
  314. {
  315. }
  316. static void Profiler_SetupScriptingProfile()
  317. {
  318. UnityScriptingProfilerInstall(&_MemoryProfiler, &profiler_shutdown);
  319. UnityScriptingProfilerInstallGC(&gc_event, &gc_resize);
  320. UnityScriptingProfilerSetEvents(SCRIPTING_PROFILE_GC);
  321. }
  322. #endif // ENABLE_INTERNAL_PROFILER