18a0456f44e553d8f74205ee84f35771f62e19c8
[platform/core/ml/nnfw.git] / compiler / one-cmds / one-profile
1 #!/usr/bin/env bash
2 ''''export SCRIPT_PATH="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)" # '''
3 ''''export PY_PATH=${SCRIPT_PATH}/venv/bin/python                                       # '''
4 ''''test -f ${PY_PATH} && exec ${PY_PATH} "$0" "$@"                                     # '''
5 ''''echo "Error: Virtual environment not found. Please run 'one-prepare-venv' command." # '''
6 ''''exit 255                                                                            # '''
7
8 # Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
9 #
10 # Licensed under the Apache License, Version 2.0 (the "License");
11 # you may not use this file except in compliance with the License.
12 # You may obtain a copy of the License at
13 #
14 #    http://www.apache.org/licenses/LICENSE-2.0
15 #
16 # Unless required by applicable law or agreed to in writing, software
17 # distributed under the License is distributed on an "AS IS" BASIS,
18 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 # See the License for the specific language governing permissions and
20 # limitations under the License.
21
22 import argparse
23 import copy
24 import glob
25 import itertools
26 import ntpath
27 import os
28 import sys
29
30 import onelib.utils as oneutils
31
32 # TODO Find better way to suppress trackback on error
33 sys.tracebacklimit = 0
34
35
36 def _get_backends_list():
37     """
38     [one hierarchy]
39     one
40     ├── backends
41     ├── bin
42     ├── doc
43     ├── include
44     ├── lib
45     └── test
46
47     The list where `one-profile` finds its backends
48     - `bin` folder where `one-profile` exists
49     - `backends` folder
50
51     NOTE If there are backends of the same name in different places,
52      the closer to the top in the list, the higher the priority.
53     """
54     dir_path = os.path.dirname(os.path.realpath(__file__))
55     backend_set = set()
56
57     # bin folder
58     files = [f for f in glob.glob(dir_path + '/*-profile')]
59     # backends folder
60     files += [
61         f for f in glob.glob(dir_path + '/../backends/**/*-profile', recursive=True)
62     ]
63     # TODO find backends in `$PATH`
64
65     backends_list = []
66     for cand in files:
67         base = ntpath.basename(cand)
68         if not base in backend_set and os.path.isfile(cand) and os.access(cand, os.X_OK):
69             backend_set.add(base)
70             backends_list.append(cand)
71
72     return backends_list
73
74
75 def _get_parser(backends_list):
76     profile_usage = 'one-profile [-h] [-v] [-C CONFIG] [-b BACKEND] [--] [COMMANDS FOR BACKEND]'
77     parser = argparse.ArgumentParser(
78         description='command line tool for profiling backend model', usage=profile_usage)
79
80     oneutils.add_default_arg(parser)
81
82     # get backend list in the directory
83     backends_name = [ntpath.basename(f) for f in backends_list]
84     if not backends_name:
85         backends_name_message = '(There is no available backend drivers)'
86     else:
87         backends_name_message = '(available backend drivers: ' + ', '.join(
88             backends_name) + ')'
89     backend_help_message = 'backend name to use ' + backends_name_message
90     parser.add_argument('-b', '--backend', type=str, help=backend_help_message)
91
92     return parser
93
94
95 def _verify_arg(parser, args):
96     """verify given arguments"""
97     # check if required arguments is given
98     missing = []
99     if not oneutils.is_valid_attr(args, 'backend'):
100         missing.append('-b/--backend')
101     if len(missing):
102         parser.error('the following arguments are required: ' + ' '.join(missing))
103
104
105 def _parse_arg(parser):
106     profile_args = []
107     backend_args = []
108     unknown_args = []
109     argv = copy.deepcopy(sys.argv)
110     # delete file name
111     del argv[0]
112     # split by '--'
113     args = [list(y) for x, y in itertools.groupby(argv, lambda z: z == '--') if not x]
114     if len(args) == 0:
115         profile_args = parser.parse_args(profile_args)
116     # one-profile has two interfaces
117     # 1. one-profile [-h] [-v] [-C CONFIG] [-b BACKEND] [COMMANDS FOR BACKEND]
118     if len(args) == 1:
119         profile_args = args[0]
120         profile_args, unknown_args = parser.parse_known_args(profile_args)
121     # 2. one-profile [-h] [-v] [-C CONFIG] [-b BACKEND] -- [COMMANDS FOR BACKEND]
122     if len(args) == 2:
123         profile_args = args[0]
124         backend_args = args[1]
125         profile_args = parser.parse_args(profile_args)
126     # print version
127     if len(args) and profile_args.version:
128         oneutils.print_version_and_exit(__file__)
129
130     return profile_args, backend_args, unknown_args
131
132
133 def main():
134     # get backend list
135     backends_list = _get_backends_list()
136
137     # parse arguments
138     parser = _get_parser(backends_list)
139     args, backend_args, unknown_args = _parse_arg(parser)
140
141     # parse configuration file
142     oneutils.parse_cfg(args.config, 'one-profile', args)
143
144     # verify arguments
145     _verify_arg(parser, args)
146
147     # make a command to run given backend driver
148     profile_path = None
149     backend_base = getattr(args, 'backend') + '-profile'
150     for cand in backends_list:
151         if ntpath.basename(cand) == backend_base:
152             profile_path = cand
153     if not profile_path:
154         raise FileNotFoundError(backend_base + ' not found')
155     profile_cmd = [profile_path] + backend_args + unknown_args
156     if oneutils.is_valid_attr(args, 'command'):
157         profile_cmd += getattr(args, 'command').split()
158
159     # run backend driver
160     oneutils.run(profile_cmd, err_prefix=backend_base)
161
162
163 if __name__ == '__main__':
164     main()