utils.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. # Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import functools
  15. import sys
  16. from contextlib import ContextDecorator, contextmanager
  17. from typing import Any
  18. from warnings import warn
  19. from paddle.base import core
  20. from paddle.base.core import TracerEventType, _RecordEvent
  21. _is_profiler_used = False
  22. _has_optimizer_wrapped = False
  23. _AllowedEventTypeList = [
  24. TracerEventType.Dataloader,
  25. TracerEventType.ProfileStep,
  26. TracerEventType.Forward,
  27. TracerEventType.Backward,
  28. TracerEventType.Optimization,
  29. TracerEventType.PythonOp,
  30. TracerEventType.PythonUserDefined,
  31. ]
  32. class RecordEvent(ContextDecorator):
  33. r"""
  34. Interface for recording a time range by user defined.
  35. Args:
  36. name (str): Name of the record event.
  37. event_type (TracerEventType, optional): Optional, default value is
  38. `TracerEventType.PythonUserDefined`. It is reserved for internal
  39. purpose, and it is better not to specify this parameter.
  40. Examples:
  41. .. code-block:: python
  42. :name: code-example1
  43. >>> import paddle
  44. >>> import paddle.profiler as profiler
  45. >>> # method1: using context manager
  46. >>> paddle.seed(2023)
  47. >>> with profiler.RecordEvent("record_add"):
  48. ... data1 = paddle.randn(shape=[3])
  49. ... data2 = paddle.randn(shape=[3])
  50. ... result = data1 + data2
  51. >>> # method2: call begin() and end()
  52. >>> record_event = profiler.RecordEvent("record_add")
  53. >>> record_event.begin()
  54. >>> data1 = paddle.randn(shape=[3])
  55. >>> data2 = paddle.randn(shape=[3])
  56. >>> result = data1 + data2
  57. >>> record_event.end()
  58. Note:
  59. RecordEvent will take effect only when :ref:`Profiler <api_paddle_profiler_Profiler>` is on and at the state of `RECORD`.
  60. """
  61. def __init__(
  62. self,
  63. name: str,
  64. event_type: TracerEventType = TracerEventType.PythonUserDefined,
  65. ):
  66. self.name = name
  67. self.event_type = event_type
  68. self.event = None
  69. def __enter__(self):
  70. self.begin()
  71. return self
  72. def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any):
  73. self.end()
  74. def begin(self):
  75. r"""
  76. Record the time of beginning.
  77. Examples:
  78. .. code-block:: python
  79. :name: code-example2
  80. >>> import paddle
  81. >>> import paddle.profiler as profiler
  82. >>> record_event = profiler.RecordEvent("record_sub")
  83. >>> record_event.begin()
  84. >>> paddle.seed(2023)
  85. >>> data1 = paddle.randn(shape=[3])
  86. >>> data2 = paddle.randn(shape=[3])
  87. >>> result = data1 - data2
  88. >>> record_event.end()
  89. """
  90. if not _is_profiler_used:
  91. return
  92. if self.event_type not in _AllowedEventTypeList:
  93. warn(
  94. "Only TracerEvent Type in [{}, {}, {}, {}, {}, {},{}]\
  95. can be recorded.".format(
  96. *_AllowedEventTypeList
  97. )
  98. )
  99. self.event = None
  100. else:
  101. self.event = _RecordEvent(self.name, self.event_type)
  102. def end(self):
  103. r"""
  104. Record the time of ending.
  105. Examples:
  106. .. code-block:: python
  107. :name: code-example3
  108. >>> import paddle
  109. >>> import paddle.profiler as profiler
  110. >>> record_event = profiler.RecordEvent("record_mul")
  111. >>> record_event.begin()
  112. >>> paddle.seed(2023)
  113. >>> data1 = paddle.randn(shape=[3])
  114. >>> data2 = paddle.randn(shape=[3])
  115. >>> result = data1 * data2
  116. >>> record_event.end()
  117. """
  118. if self.event:
  119. self.event.end()
  120. def load_profiler_result(filename: str):
  121. r"""
  122. Load dumped profiler data back to memory.
  123. Args:
  124. filename(str): Name of the exported protobuf file of profiler data.
  125. Returns:
  126. ``ProfilerResult`` object, which stores profiling data.
  127. Examples:
  128. .. code-block:: python
  129. >>> # doctest: +REQUIRES(env:GPU)
  130. >>> import paddle.profiler as profiler
  131. >>> import paddle
  132. >>> paddle.device.set_device('gpu')
  133. >>> with profiler.Profiler(
  134. ... targets=[profiler.ProfilerTarget.CPU, profiler.ProfilerTarget.GPU],
  135. ... scheduler = (3, 10)) as p:
  136. ... for iter in range(10):
  137. ... #train()
  138. ... p.step()
  139. >>> p.export('test_export_protobuf.pb', format='pb')
  140. >>> profiler_result = profiler.load_profiler_result('test_export_protobuf.pb')
  141. """
  142. return core.load_profiler_result(filename)
  143. def in_profiler_mode():
  144. return _is_profiler_used
  145. def wrap_optimizers():
  146. def optimizer_wrapper(func):
  147. @functools.wraps(func)
  148. def wrapper(*args, **kwargs):
  149. if in_profiler_mode():
  150. with RecordEvent(
  151. 'Optimization Step', event_type=TracerEventType.Optimization
  152. ):
  153. return func(*args, **kwargs)
  154. else:
  155. return func(*args, **kwargs)
  156. return wrapper
  157. global _has_optimizer_wrapped
  158. if _has_optimizer_wrapped:
  159. return
  160. from paddle import optimizer
  161. for classname in optimizer.__all__:
  162. if classname != 'Optimizer':
  163. classobject = getattr(optimizer, classname)
  164. if getattr(classobject, 'step', None) is not None:
  165. classobject.step = optimizer_wrapper(classobject.step)
  166. _has_optimizer_wrapped = True
  167. @contextmanager
  168. def _nvprof_range(iter_id, start, end, exit_after_prof=True):
  169. """
  170. A range profiler interface (not public yet).
  171. Examples:
  172. .. code-block:: python
  173. >>> import paddle
  174. >>> model = Model()
  175. >>> for i in range(max_iter):
  176. ... with paddle.profiler.utils._nvprof_range(i, 10, 20):
  177. ... out = model(in)
  178. """
  179. if start >= end:
  180. yield
  181. return
  182. try:
  183. if iter_id == start:
  184. core.nvprof_start()
  185. core.nvprof_enable_record_event()
  186. if iter_id >= start:
  187. core.nvprof_nvtx_push(str(iter_id))
  188. yield
  189. finally:
  190. if iter_id < end:
  191. core.nvprof_nvtx_pop()
  192. if iter_id == end - 1:
  193. core.nvprof_stop()
  194. if exit_after_prof:
  195. sys.exit()
  196. @contextmanager
  197. def job_schedule_profiler_range(iter_id, start, end, exit_after_prof=True):
  198. if start >= end:
  199. yield False
  200. return
  201. try:
  202. if iter_id >= start and iter_id < end:
  203. yield True
  204. else:
  205. yield False
  206. finally:
  207. if iter_id == end - 1:
  208. if exit_after_prof:
  209. sys.exit()
  210. def switch_job_schedule_profiler(
  211. model, iter_id, start, end, exit_after_prof=True
  212. ):
  213. with job_schedule_profiler_range(
  214. iter_id, start, end, exit_after_prof
  215. ) as status:
  216. model._engine.enable_job_schedule_profiler = status