the_profiler.rst 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. .. _doc_the_profiler:
  2. The Profiler
  3. ============
  4. You run your game from Godot and play around. It's fun, it's becoming feature
  5. complete, and you feel it's getting close to release.
  6. But then, you open the skill tree, and it grinds to a halt as something snags in
  7. your code. Watching the skill tree scroll by like it's a slide show is
  8. unacceptable. What went wrong? Is it positioning the skill tree elements, the
  9. UI, or rendering?
  10. You could try to optimize everything and run the game repeatedly, but you can be
  11. smarter about this and narrow down the possibilities. Enter Godot's profiler.
  12. An overview of the profiler
  13. +++++++++++++++++++++++++++
  14. You can open the profiler by opening the **Debugger** panel and clicking on the
  15. **Profiler** tab.
  16. .. image:: img/profiler.png
  17. Godot's profiler does not automatically run because profiling is
  18. performance-intensive. It has to continually measure everything happening in the
  19. game and report back to the debugger, so it's off by default.
  20. To begin profiling, run your game then focus back on the editor. Click on the
  21. **Start** button in the top-left corner of the **Profiler** tab. You can also
  22. check **Autostart**, which will make the profiler automatically start when the
  23. project is run the next time. Note that the **Autostart** checkbox's state is not
  24. preserved across editor sessions.
  25. .. note::
  26. The profiler does not currently support C# scripts. C# scripts can be profiled
  27. using JetBrains Rider and JetBrains dotTrace with the Godot support plugin.
  28. You can clear the data by clicking the **Clear** button anytime. Use the
  29. **Measure** drop-down menu to change the type of data you measure. The
  30. measurements panel and the graph will update accordingly.
  31. The measured data
  32. +++++++++++++++++
  33. The profiler's interface is split into two. There is a list of functions on the
  34. left and the performance graph on the right.
  35. The main measurements are frame time, physics frame, idle time, and physics time.
  36. - The **frame time** is the time it takes Godot to execute all the logic for an
  37. entire image, from physics to rendering.
  38. - **Physics frame** is the time Godot has allocated between physics updates. In
  39. an ideal scenario, the frame time is whatever you chose: 16.66 milliseconds by
  40. default, which corresponds to 60FPS. It's a frame of reference you can use for
  41. everything else around it.
  42. - **Idle time** is the time Godot took to update logic other than physics, such
  43. as code that lives in `_process` or timers and cameras set to update on
  44. **Idle**.
  45. - **Physics time** is the time Godot took to update physics tasks, like
  46. `_physics_process` and built-in nodes set to **Physics** update.
  47. .. note:: **Frame Time** includes rendering time. Say you find a mysterious
  48. spike of lag in your game, but your physics and scripts are
  49. all running fast. The delay could be due to the appearance of
  50. particles or visual effects!
  51. By default, Godot ticks on Frame Time and Physics Time. This gives you an
  52. overview of how long each frame takes relative to the allocated desired physics
  53. FPS. You can toggle functions on and off by clicking the checkboxes on the left.
  54. Other facilities make appearances as you go down the list, like Physics 2D,
  55. Physics, and Audio, before reaching Script functions, where your code appears.
  56. If you click on the graph, you change which frame's information appears on the
  57. left. In the top right, there is also a frame counter where you can manually
  58. adjust the frame you are looking at more granularly.
  59. Scope of measurement and measurement windows
  60. ++++++++++++++++++++++++++++++++++++++++++++
  61. You can change what measurement you are looking at using the **Measure**
  62. drop-down menu. By default, it starts with Frame Time and lists the time it
  63. takes to go through the frame in milliseconds. The average time is the average
  64. time any given function took when called more than once. For example, a function
  65. that took 0.05 milliseconds to run five times should give you an average of 0.01
  66. milliseconds.
  67. If accurate milliseconds count is not important, and you want to see proportions
  68. of time relative to the rest of the frame, use percentage measurements. Frame %
  69. is relative to Frame Time, and Physics % is relative to Physics Time.
  70. The last option is the scope of the time. **Inclusive** measures the time a
  71. function took **with** any nested function calls. For example:
  72. .. image:: img/split_curve.png
  73. `get_neighbors`, `find_nearest_neighbor` and `move_subject` all took a lot of
  74. time. You could be fooled into thinking that this is because all three of them
  75. are slow.
  76. But when changed to **Self**, Godot measures the time spent in the function body
  77. without considering function calls it made itself.
  78. .. image:: img/self_curve.png
  79. You can see that `get_neighbors` and `move_subject` have lost a lot of their
  80. importance. In effect, that means that `get_neighbors` and `move_subject` have
  81. spent more time waiting for some other function call to finish than not, and
  82. `find_nearest_neighbor` is **actually** slow.
  83. Debugging slow code with the profiler
  84. +++++++++++++++++++++++++++++++++++++
  85. Finding slow code with the profiler boils down to running your game and watching
  86. the performance graph as it draws. When an unacceptable spike occurs in the
  87. frame time, you can click on the graph to pause your game and narrow the _Frame
  88. #_ to the spike's start. You may need to jump back and forth between frames and
  89. functions to find the root cause.
  90. Under the Script functions, turn on the checkboxes for some functions to find
  91. which take time. These are the functions you need to review and optimize.
  92. Measuring manually in microseconds
  93. ++++++++++++++++++++++++++++++++++
  94. If your function is complex, it could be challenging to figure out which part
  95. needs optimization. Is it your math or the way you access other pieces of data
  96. to do the math with? Is it the `for` loop? The `if` statements?
  97. You can narrow down the measurement by manually counting ticks as the code runs
  98. with some temporary functions. The two functions are part of the `Time` class
  99. object. They are `get_ticks_msec` and `get_ticks_usec`. The first measures in
  100. milliseconds (1,000 per second), and the second measures in microseconds
  101. (1,000,000 per second).
  102. Either one returns the amount of time since the game engine started in their respective
  103. time frame.
  104. If you wrap a piece of code with a start and end count of microseconds, the
  105. difference between the two is the amount of time it took to run that piece of
  106. code.
  107. .. tabs::
  108. .. code-tab:: gdscript GDScript
  109. # Measuring the time it takes for worker_function() to run
  110. var start = Time.get_ticks_usec()
  111. worker_function()
  112. var end = Time.get_ticks_usec()
  113. var worker_time = (end-start)/1000000.0
  114. # Measuring the time spent running a calculation over each element of an array
  115. start = Time.get_ticks_usec()
  116. for calc in calculations:
  117. result = pow(2, calc.power) * calc.product
  118. end = Time.get_ticks_usec()
  119. var loop_time = (end-start)/1000000.0
  120. print("Worker time: %s\nLoop time: %s" % [worker_time, loop_time])
  121. As you become a more experienced programmer, this technique becomes less
  122. necessary. You begin to learn what parts of a running program are slow. Knowing
  123. that loops and branches can be slow comes from experience, and you gain
  124. experience by measuring and doing research.
  125. But between the profiler and the ticks functions, you should have enough to get
  126. started finding which parts of your code need optimization.