# copyright (c) 2021 PaddlePaddle Authors. All Rights Reserve.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
import paddle.profiler as profiler
# A global variable to record the number of calling times for profiler
# functions. It is used to specify the tracing range of training steps.
_profiler_step_id = 0
# A global variable to avoid parsing from string every time.
_profiler_options = None
_prof = None
[docs]class ProfilerOptions(object):
"""
Use a string to initialize a ProfilerOptions.
The string should be in the format: "key1=value1;key2=value;key3=value3".
For example:
"profile_path=model.profile"
"batch_range=[50, 60]; profile_path=model.profile"
"batch_range=[50, 60]; tracer_option=OpDetail; profile_path=model.profile"
ProfilerOptions supports following key-value pair:
batch_range - a integer list, e.g. [100, 110].
state - a string, the optional values are 'CPU', 'GPU' or 'All'.
sorted_key - a string, the optional values are 'calls', 'total',
'max', 'min' or 'ave.
tracer_option - a string, the optional values are 'Default', 'OpDetail',
'AllOpDetail'.
profile_path - a string, the path to save the serialized profile data,
which can be used to generate a timeline.
exit_on_finished - a boolean.
record_shapes - a boolean.
"""
def __init__(self, options_str):
assert isinstance(options_str, str)
self._options = {
"batch_range": [10, 20],
"state": "All",
"sorted_key": "total",
"tracer_option": "Default",
"profile_path": "/tmp/profile",
"exit_on_finished": True,
"timer_only": True,
"record_shapes": False,
}
self._parse_from_string(options_str)
def _parse_from_string(self, options_str):
for kv in options_str.replace(" ", "").split(";"):
key, value = kv.split("=")
if key == "batch_range":
value_list = value.replace("[", "").replace("]", "").split(",")
value_list = list(map(int, value_list))
if len(value_list) >= 2 and value_list[0] >= 0 and value_list[1] > value_list[0]:
self._options[key] = value_list
elif key == "exit_on_finished":
self._options[key] = value.lower() in ("yes", "true", "t", "1")
elif key in ["state", "sorted_key", "tracer_option", "profile_path"]:
self._options[key] = value
elif key == "timer_only":
self._options[key] = value
elif key == "record_shapes":
self._options[key] = value
def __getitem__(self, name):
if self._options.get(name, None) is None:
raise ValueError("ProfilerOptions does not have an option named %s." % name)
return self._options[name]
[docs]def add_profiler_step(options_str=None):
"""
Enable the operator-level timing using PaddlePaddle's profiler.
The profiler uses a independent variable to count the profiler steps.
One call of this function is treated as a profiler step.
Args:
profiler_options - a string to initialize the ProfilerOptions.
Default is None, and the profiler is disabled.
"""
if options_str is None:
return
global _prof
global _profiler_step_id
global _profiler_options
if _profiler_options is None:
_profiler_options = ProfilerOptions(options_str)
# profile : https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/performance_improving/profiling_model.html#chakanxingnengshujudetongjibiaodan
# timer_only = True only the model's throughput and time overhead are displayed
# timer_only = False calling summary can print a statistical form that presents performance data from different perspectives.
# timer_only = False the output Timeline information can be found in the profiler_log directory
if _prof is None:
_timer_only = str(_profiler_options["timer_only"]) == str(True)
_record_shapes = str(_profiler_options["record_shapes"]) == str(True)
_prof = profiler.Profiler(
scheduler=(_profiler_options["batch_range"][0], _profiler_options["batch_range"][1]),
on_trace_ready=profiler.export_chrome_tracing(_profiler_options["profile_path"]),
timer_only=_timer_only,
record_shapes=_record_shapes,
)
_prof.start()
else:
_prof.step()
if _profiler_step_id == _profiler_options["batch_range"][1]:
_prof.stop()
_prof.summary(op_detail=True, thread_sep=False, time_unit="ms")
_prof = None
if _profiler_options["exit_on_finished"]:
sys.exit(0)
_profiler_step_id += 1