xref: /aosp_15_r20/external/armnn/python/pyarmnn/src/pyarmnn/_utilities/profiling_helper.py (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1# Copyright © 2020 Arm Ltd. All rights reserved.
2# SPDX-License-Identifier: MIT
3"""
4This file contains functions relating to the use of the Arm NN profiler within PyArmNN.
5"""
6import json
7from collections import namedtuple
8
9ProfilerData = namedtuple('ProfilerData', ['inference_data', 'per_workload_execution_data'])
10ProfilerData.__doc__ = """Container to hold the profiling inference data, and the profiling data per workload.
11
12Contains:
13    inference_data (dict): holds end-to-end inference performance data. Keys:
14                           'time_unit' - timer units.
15                           'execution_time' - list of total inference execution times for each inference run.
16    per_workload_execution_data (dict): holds per operation performance data, key is a operation name
17                                        Each operation has
18                                        'time_unit' - timer units.
19                                        'execution_time' - list of total execution times for each inference run.
20                                        'backend' - backend used for this operation.
21
22Examples:
23
24    >>> data = get_profiling_data(profiler)
25    >>> print(data)
26    >>> ProfilerData(inference_data={'time_unit': 'us',
27                                     'execution_time': [8901372.972]},
28                    per_workload_execution_data={'CopyMemGeneric_Execute_#3': {'time_unit': 'us',
29                                                                               'execution_time': [28.941],
30                                                                               'backend': 'Unknown'},
31                                                 'RefConvolution2dWorkload_Execute_#5': {'time_unit': 'us',
32                                                                                         'execution_time': [126838.071],
33                                                                                         'backend': 'CpuRef'},
34                                                 'RefDepthwiseConvolution2dWorkload_Execute_#6': {'time_unit': 'us',
35                                                                                                  'execution_time': [49886.208],
36                                                                                                  'backend': 'CpuRef'}
37                                                 ...etc
38                                                 }
39                    )
40"""
41
42
43def get_profiling_data(profiler: 'IProfiler') -> ProfilerData:
44    """Reads IProfiler object passed in, extracts the relevant data
45        and returns it in a ProfilerData container.
46
47        Args:
48            profiler (IProfiler): The IProfiler object to be parsed.
49
50        Returns:
51            ProfilerData: A container containing the relevant data extracted from the Profiler output.
52    """
53
54    top_level_dict = json.loads(profiler.as_json())
55    armnn_data = top_level_dict["ArmNN"]
56    #Get the inference measurements dict, this will be just one value for key starting with "inference_measurements"
57    inference_measurements = [v for k, v in armnn_data.items() if k.startswith("inference_measurements_")][0]
58
59    #Get the execution data dict, this will be just one value for key starting with "Execute_"
60    execution_data = [v for k, v in inference_measurements.items() if k.startswith("Execute_")][0]
61
62    workload_data = {}
63    inference_data = {}
64    for exec_key, exec_value in execution_data.items():
65        # Check all items with a type.
66        if "type" in exec_value and exec_value["type"] == "Event":
67            for event_key, event_value in exec_value.items():
68                if event_key.startswith("Wall clock time_#") and event_value["type"] == "Measurement":
69                    time_data = __get_wall_clock_times__(event_value)
70                    time_data["backend"] = __get_backend(exec_key)
71                    workload_data[exec_key] = time_data
72        # This is the total inference time map
73        if exec_key.startswith("Wall clock time_#") and exec_value["type"] == "Measurement":
74            time_data = __get_wall_clock_times__(exec_value)
75            inference_data.update(time_data)
76    return ProfilerData(inference_data=inference_data, per_workload_execution_data=workload_data)
77
78
79def __get_wall_clock_times__(wall_clock_item):
80    execution_times = wall_clock_item["raw"]
81    time_data = {}
82    raw_data = []
83    for time in execution_times:
84        raw_data.append(time)
85    time_data["time_unit"] = wall_clock_item["unit"]
86    time_data["execution_time"] = raw_data
87    return time_data
88
89
90def __get_backend(exec_key):
91    if "ref" in exec_key.lower():
92        return "CpuRef"
93    elif "neon" in exec_key.lower():
94        return "CpuAcc"
95    elif "cl" in exec_key.lower():
96        return "GpuAcc"
97    elif "ethos" in exec_key.lower():
98        return "EthosNAcc"
99    else:
100        return "Unknown"