Imported Upstream version 1.25.0
[platform/core/ml/nnfw.git] / compiler / one-cmds / onecc
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 configparser
24 import os
25 import subprocess
26 import sys
27 from types import SimpleNamespace
28
29 from onelib.CfgRunner import CfgRunner
30 from onelib.WorkflowRunner import WorkflowRunner
31 import onelib.utils as oneutils
32
33 # TODO Find better way to suppress trackback on error
34 sys.tracebacklimit = 0
35
36 subtool_list = {
37     'compile': {
38         'import': 'Convert given model to circle',
39         'optimize': 'Optimize circle model',
40         'quantize': 'Quantize circle model',
41     },
42     'package': {
43         'pack': 'Package circle and metadata into nnpackage',
44     },
45     'backend': {
46         'codegen': 'Code generation tool',
47         'profile': 'Profile backend model file',
48         'infer': 'Infer backend model file'
49     },
50 }
51
52
53 def _call_driver(driver_name, options):
54     dir_path = os.path.dirname(os.path.realpath(__file__))
55     driver_path = os.path.join(dir_path, driver_name)
56     cmd = [driver_path] + options
57     oneutils.run(cmd)
58
59
60 def _check_subtool_exists():
61     """verify given arguments"""
62     subtool_keys = [n for k, v in subtool_list.items() for n in v.keys()]
63     if len(sys.argv) > 1 and sys.argv[1] in subtool_keys:
64         driver_name = 'one-' + sys.argv[1]
65         options = sys.argv[2:]
66         _call_driver(driver_name, options)
67         sys.exit(0)
68
69
70 def _get_parser():
71     onecc_usage = 'onecc [-h] [-v] [-C CONFIG] [-b BACKEND] [-W WORKFLOW] [-O OPTIMIZATION] [COMMAND <args>]'
72     onecc_desc = 'Run ONE driver via several commands or configuration file'
73     parser = argparse.ArgumentParser(description=onecc_desc, usage=onecc_usage)
74
75     oneutils.add_default_arg(parser)
76
77     opt_name_list = oneutils.get_optimization_list(get_name=True)
78     opt_name_list = ['-' + s for s in opt_name_list]
79     if not opt_name_list:
80         opt_help_message = '(No available optimization options)'
81     else:
82         opt_help_message = '(Available optimization options: ' + ', '.join(
83             opt_name_list) + ')'
84     opt_help_message = 'optimization name to use ' + opt_help_message
85     parser.add_argument('-O', type=str, metavar='OPTIMIZATION', help=opt_help_message)
86
87     parser.add_argument(
88         '-W', '--workflow', type=str, metavar='WORKFLOW', help='run with workflow file')
89
90     parser.add_argument(
91         '-b', '--backend', type=str, help='generate code for given backend')
92
93     # just for help message
94     compile_group = parser.add_argument_group('compile to circle model')
95     for tool, desc in subtool_list['compile'].items():
96         compile_group.add_argument(tool, action='store_true', help=desc)
97
98     package_group = parser.add_argument_group('package circle model')
99     for tool, desc in subtool_list['package'].items():
100         package_group.add_argument(tool, action='store_true', help=desc)
101
102     backend_group = parser.add_argument_group('run backend tools')
103     for tool, desc in subtool_list['backend'].items():
104         backend_group.add_argument(tool, action='store_true', help=desc)
105
106     return parser
107
108
109 def _parse_arg(parser):
110     args = parser.parse_args()
111     # print version
112     if args.version:
113         oneutils.print_version_and_exit(__file__)
114
115     return args
116
117
118 def _verify_backend_args(parser, args):
119     """
120     verify one-profile, one-codegen arguments
121
122     This verification logic comes from each drivers' codes.
123     """
124     cfgparser = configparser.ConfigParser()
125     cfgparser.optionxform = str
126     cfgparser.read(args.config)
127
128     for driver in ['one-profile', 'one-codegen']:
129         if not driver in cfgparser:
130             continue
131
132         cfg_args = SimpleNamespace()
133         oneutils.parse_cfg(args.config, driver, cfg_args)
134         cmd_backend_exist = oneutils.is_valid_attr(args, 'backend')
135         cfg_backend_exist = oneutils.is_valid_attr(cfg_args, 'backend')
136         cfg_backends_exist = oneutils.is_valid_attr(cfg_args, 'backends')
137
138         if cfg_backend_exist and cfg_backends_exist:
139             parser.error(
140                 "'backend' option and 'backends' option cannot be used simultaneously.")
141
142         # Check if given backend from command line exists in the configuration file
143         if cmd_backend_exist and cfg_backend_exist:
144             if args.backend != cfg_args.backend:
145                 parser.error('Not found the command of given backend')
146
147         if cfg_backends_exist:
148             cfg_backends = getattr(cfg_args, 'backends').split(',')
149             # check if commands of given backends exist
150             for b in cfg_backends:
151                 if not oneutils.is_valid_attr(cfg_args, b):
152                     parser.error('Not found the command for ' + b)
153
154             # Check if given backend from command line exists in the configuration file
155             if cmd_backend_exist:
156                 if args.backend not in cfg_backends:
157                     parser.error('Not found the command of given backend')
158
159
160 def _verify_arg(parser, args):
161     """verify given arguments"""
162     # check if required arguments is given
163     if not oneutils.is_valid_attr(args, 'config') and not oneutils.is_valid_attr(
164             args, 'workflow'):
165         parser.error('-C/--config or -W/--workflow argument is required')
166     # check if given optimization option exists
167     opt_name_list = oneutils.get_optimization_list(get_name=True)
168     opt_name_list = [oneutils.remove_prefix(s, 'O') for s in opt_name_list]
169     if oneutils.is_valid_attr(args, 'O'):
170         if ' ' in getattr(args, 'O'):
171             parser.error('Not allowed to have space in the optimization name')
172         if not getattr(args, 'O') in opt_name_list:
173             parser.error('Invalid optimization option')
174
175     if oneutils.is_valid_attr(args, 'backend') and oneutils.is_valid_attr(
176             args, 'workflow'):
177         parser.error('\'backend\' option can be used only with \'config\' option')
178
179     if oneutils.is_valid_attr(args, 'backend'):
180         _verify_backend_args(parser, args)
181
182
183 def main():
184     # check if there is subtool argument
185     # if true, it executes subtool with argv
186     # NOTE:
187     # Why call subtool directly without using Argparse?
188     # Because if Argparse is used, options equivalent to onecc including
189     # '--help', '-C' are processed directly onecc itself.
190     # So options cannot be delivered to subtool.
191     _check_subtool_exists()
192
193     # parse arguments
194     # since the configuration file path is required first,
195     # parsing of the configuration file proceeds after this.
196     parser = _get_parser()
197     args = _parse_arg(parser)
198
199     # verify arguments
200     _verify_arg(parser, args)
201
202     bin_dir = os.path.dirname(os.path.realpath(__file__))
203     if oneutils.is_valid_attr(args, 'config'):
204         runner = CfgRunner(args.config)
205         runner.detect_import_drivers(bin_dir)
206         if oneutils.is_valid_attr(args, 'O'):
207             runner.add_opt(getattr(args, 'O'))
208         if oneutils.is_valid_attr(args, 'backend'):
209             runner.set_backend(args.backend)
210         runner.run(bin_dir)
211     elif oneutils.is_valid_attr(args, 'workflow'):
212         runner = WorkflowRunner(args.workflow)
213         runner.run(bin_dir)
214
215
216 if __name__ == '__main__':
217     oneutils.safemain(main, __file__)