profiler.py 4.2 KB
Newer Older
D
dangqingqing 已提交
1
import paddle.v2.fluid.core as core
D
dangqingqing 已提交
2
from contextlib import contextmanager
3
import os
D
dangqingqing 已提交
4

5
__all__ = ['CudaProfiler']
D
dangqingqing 已提交
6

D
dangqingqing 已提交
7
NVPROF_CONFIG = [
8 9 10 11 12 13
    "gpustarttimestamp",
    "gpuendtimestamp",
    "gridsize3d",
    "threadblocksize",
    "streamid",
    "enableonstart 0",
D
dangqingqing 已提交
14
    "conckerneltrace",
15 16 17
]


D
dangqingqing 已提交
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
@contextmanager
def cuda_profiler(output_file, output_mode=None, config=None):
    """The CUDA profiler.
    This fuctions is used to profile CUDA program by CUDA runtime application
    programming interface. The profiling result will be written into
    `output_file` with Key-Value pair format or Comma separated values format.
    The user can set the output mode by `output_mode` argument and set the
    counters/options for profiling by `config` argument. The default config
    is ['gpustarttimestamp', 'gpustarttimestamp', 'gridsize3d',
    'threadblocksize', 'streamid', 'enableonstart 0', 'conckerneltrace'].

    Args:
        output_file (string) : The output file name, the result will be
            written into this file.
        output_mode (string) : The output mode has Key-Value pair format and
            Comma separated values format. It should be 'kvp' or 'csv'.
34 35
        config (list of string) : The profiler options and counters can refer
            to "Compute Command Line Profiler User Guide".
D
dangqingqing 已提交
36 37 38
    """
    if output_mode is None:
        output_mode = 'csv'
D
dangqingqing 已提交
39 40 41
    if output_mode not in ['kvp', 'csv']:
        raise ValueError("The output mode must be 'kvp' or 'csv'.")
    config = NVPROF_CONFIG if config is None else config
42 43 44 45
    config_file = 'nvprof_config_file'
    with open(config_file, 'wb') as fp:
        fp.writelines(["%s\n" % item for item in config])
    core.nvprof_init(output_file, output_mode, config_file)
D
dangqingqing 已提交
46
    # Enables profiler collection by the active CUDA profiling tool.
D
dangqingqing 已提交
47
    core.nvprof_start()
D
dangqingqing 已提交
48 49
    yield
    # Disables profiler collection.
D
dangqingqing 已提交
50
    core.nvprof_stop()
51
    os.remove(config_file)
52 53 54


def reset_profiler():
55 56 57
    """The profiler clear interface.
    reset_profiler will clear the previous time record.
    """
58 59 60 61 62 63
    core.reset_profiler()


@contextmanager
def profiler(state, sorted_key=None):
    """The profiler interface.
64 65 66 67
    Different from cuda_profiler, this profiler can be used to profile both CPU
    and GPU program. By defalut, it records the CPU and GPU operator kernels,
    if you want to profile other program, you can refer the profiling tutorial
    to add more records.
68 69

    Args:
70 71 72 73 74 75 76 77 78
        state (string) : The profiling state, It should be 'CPU' or 'GPU'.
            Although users may define CPUPlace or CUDAPlace when using Fluid,
            the profiler doesn't get the state based on this Place. Since the
            implementation is an independent part from the Fluid.
        sorted_key (string) : If None, the profiling results will be printed
            in the order of first end time of events. Otherwise, the profiling
            results will be sorted by the this flag. This flag should be one
            of 'calls', 'total', 'max', 'min' or 'ave'.
            The `calls` means sorting by the number of calls.
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
            The `total` means sorting by the total execution time.
            The `max` means sorting by the maximum execution time.
            The `min` means sorting by the minimum execution time.
            The `ave` means sorting by the average execution time.
    """

    if state not in ['CPU', 'GPU']:
        raise ValueError("The state must be 'CPU' or 'GPU'.")
    prof_state = core.ProfilerState.kCUDA if state == "GPU" else core.ProfilerState.kCPU
    core.enable_profiler(prof_state)
    yield

    if sorted_key not in ['calls', 'total', 'max', 'min', 'ave']:
        raise ValueError("The state must be in 'calls', 'total', "
                         "'max', 'min', 'ave'")
    sorted_key = 'default' if sorted_key is None else sorted_key
    key_map = {
        'default': core.EventSortingKey.kDefault,
        'calls': core.EventSortingKey.kCalls,
        'total': core.EventSortingKey.kTotal,
        'max': core.EventSortingKey.kMax,
        'min': core.EventSortingKey.kMin,
        'ave': core.EventSortingKey.kAve,
    }
103 104 105
    # TODO(qingqing) : redirect C++ ostream to Python stream.
    # with core.ostream_redirect(stdout=True, stderr=True):
    core.disable_profiler(key_map[sorted_key])