|
|
|
# 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
|
|
|
|
|
|
|
|
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.
|
|
|
|
'''
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
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
|
|
|
|
|
|
|
|
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]
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
_prof = profiler.Profiler(
|
|
|
|
scheduler = (_profiler_options['batch_range'][0], _profiler_options['batch_range'][1]),
|
|
|
|
on_trace_ready = profiler.export_chrome_tracing('./profiler_log'),
|
|
|
|
timer_only = _timer_only)
|
|
|
|
_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
|