profiler.py 4.28 KB
Newer Older
wanglch's avatar
wanglch committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# 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

# 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


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,
        }
        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

    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 _profiler_step_id
    global _profiler_options

    if _profiler_options is None:
        _profiler_options = ProfilerOptions(options_str)

    if _profiler_step_id == _profiler_options["batch_range"][0]:
        paddle.utils.profiler.start_profiler(
            _profiler_options["state"], _profiler_options["tracer_option"]
        )
    elif _profiler_step_id == _profiler_options["batch_range"][1]:
        paddle.utils.profiler.stop_profiler(
            _profiler_options["sorted_key"], _profiler_options["profile_path"]
        )
        if _profiler_options["exit_on_finished"]:
            sys.exit(0)

    _profiler_step_id += 1