diff options
Diffstat (limited to 'compiler/one-cmds/one-profile')
-rw-r--r-- | compiler/one-cmds/one-profile | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/compiler/one-cmds/one-profile b/compiler/one-cmds/one-profile new file mode 100644 index 000000000..bc5338dcc --- /dev/null +++ b/compiler/one-cmds/one-profile @@ -0,0 +1,246 @@ +#!/usr/bin/env bash +''''export SCRIPT_PATH="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)" # ''' +''''export PY_PATH=${SCRIPT_PATH}/venv/bin/python # ''' +''''test -f ${PY_PATH} && exec ${PY_PATH} "$0" "$@" # ''' +''''echo "Error: Virtual environment not found. Please run 'one-prepare-venv' command." # ''' +''''exit 255 # ''' + +# Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved +# +# 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 argparse +import copy +import glob +import itertools +import ntpath +import os +import sys +from types import SimpleNamespace + +import onelib.utils as oneutils + +# TODO Find better way to suppress trackback on error +sys.tracebacklimit = 0 + + +def _get_backends_list(): + """ + [one hierarchy] + one + ├── backends + ├── bin + ├── doc + ├── include + ├── lib + └── test + + The list where `one-profile` finds its backends + - `bin` folder where `one-profile` exists + - `backends` folder + + NOTE If there are backends of the same name in different places, + the closer to the top in the list, the higher the priority. + """ + dir_path = os.path.dirname(os.path.realpath(__file__)) + backend_set = set() + + # bin folder + files = [f for f in glob.glob(dir_path + '/*-profile')] + # backends folder + files += [ + f for f in glob.glob(dir_path + '/../backends/**/*-profile', recursive=True) + ] + # TODO find backends in `$PATH` + + backends_list = [] + for cand in files: + base = ntpath.basename(cand) + if not base in backend_set and os.path.isfile(cand) and os.access(cand, os.X_OK): + backend_set.add(base) + backends_list.append(cand) + + return backends_list + + +def _get_parser(backends_list): + profile_usage = 'one-profile [-h] [-v] [-C CONFIG] [-b BACKEND] [--] [COMMANDS FOR BACKEND]' + parser = argparse.ArgumentParser( + description='command line tool for profiling backend model', usage=profile_usage) + + oneutils.add_default_arg(parser) + + # get backend list in the directory + backends_name = [ntpath.basename(f) for f in backends_list] + if not backends_name: + backends_name_message = '(There is no available backend drivers)' + else: + backends_name_message = '(available backend drivers: ' + ', '.join( + backends_name) + ')' + backend_help_message = 'backend name to use ' + backends_name_message + parser.add_argument('-b', '--backend', type=str, help=backend_help_message) + + return parser + + +def _verify_arg(parser, args, cfg_args, backend_args, unknown_args): + """verify given arguments""" + cmd_backend_exist = oneutils.is_valid_attr(args, 'backend') + cfg_backend_exist = oneutils.is_valid_attr(cfg_args, 'backend') + cfg_backends_exist = oneutils.is_valid_attr(cfg_args, 'backends') + + # check if required arguments is given + missing = [] + if not cmd_backend_exist and not cfg_backend_exist and not cfg_backends_exist: + missing.append('-b/--backend') + if len(missing): + parser.error('the following arguments are required: ' + ' '.join(missing)) + + if not oneutils.is_valid_attr(args, 'config'): + if not backend_args and not unknown_args: + parser.error('commands for the backend is missing.') + + if cfg_backend_exist and cfg_backends_exist: + parser.error( + '\'backend\' option and \'backends\' option cannot be used simultaneously.') + + # Check if given backend from command line exists in the configuration file + if cmd_backend_exist and cfg_backend_exist: + if args.backend != cfg_args.backend: + parser.error('Not found the command of given backend') + + if cfg_backend_exist and not oneutils.is_valid_attr(cfg_args, 'command'): + parser.error('\'command\' key is missing in the configuration file.') + + if cfg_backends_exist: + cfg_backends = getattr(cfg_args, 'backends').split(',') + # check if commands of given backends exist + for b in cfg_backends: + if not oneutils.is_valid_attr(cfg_args, b): + parser.error('Not found the command for ' + b) + # Check if given backend from command line exists in the configuration file + if cmd_backend_exist: + if args.backend not in cfg_backends: + parser.error('Not found the command of given backend') + + +def _parse_arg(parser): + profile_args = [] + backend_args = [] + unknown_args = [] + argv = copy.deepcopy(sys.argv) + # delete file name + del argv[0] + # split by '--' + args = [list(y) for x, y in itertools.groupby(argv, lambda z: z == '--') if not x] + if len(args) == 0: + profile_args = parser.parse_args(profile_args) + # one-profile has two interfaces + # 1. one-profile [-h] [-v] [-C CONFIG] [-b BACKEND] [COMMANDS FOR BACKEND] + if len(args) == 1: + profile_args = args[0] + profile_args, unknown_args = parser.parse_known_args(profile_args) + # 2. one-profile [-h] [-v] [-C CONFIG] [-b BACKEND] -- [COMMANDS FOR BACKEND] + if len(args) == 2: + profile_args = args[0] + backend_args = args[1] + profile_args = parser.parse_args(profile_args) + # print version + if len(args) and profile_args.version: + oneutils.print_version_and_exit(__file__) + + return profile_args, backend_args, unknown_args + + +def main(): + # get backend list + backends_list = _get_backends_list() + + # parse arguments + parser = _get_parser(backends_list) + args, backend_args, unknown_args = _parse_arg(parser) + + # parse configuration file + cfg_args = SimpleNamespace() + oneutils.parse_cfg(args.config, 'one-profile', cfg_args) + + # verify arguments + _verify_arg(parser, args, cfg_args, backend_args, unknown_args) + ''' + one-profile defines its behavior for below cases. + + [1] one-profile -h + [2] one-profile -v + [3] one-profile -C ${cfg} (backend, command key in cfg) + [4] one-profile -C ${cfg} (backends key in cfg) + [5] one-profile -b ${backend} ${command} + [6] one-profile -b ${backend} -- ${command} + [7] one-profile -b ${backend} -C {cfg} (backend, command key in cfg) + [8] one-profile -b ${backend} -C {cfg} (backends key in cfg) (Only 'backend' is invoked, + even though cfg file has multiple backends) + [9] one-profile -b ${backend} -C ${cfg} -- ${command} (backend, command key in cfg) + [10] one-profile -b ${backend} -C ${cfg} -- ${command} (backends key in cfg) (Only 'backend' is invoked, + even though cfg file has multiple backends) + + All other cases are not allowed or an undefined behavior. + ''' + cmd_overwrite = False + if oneutils.is_valid_attr(args, 'config'): + # [9], [10] + if backend_args and not unknown_args: + given_backends = [args.backend] + cmd_overwrite = True + else: + # [7], [8] + if oneutils.is_valid_attr(args, 'backend'): + given_backends = [args.backend] + if oneutils.is_valid_attr(cfg_args, 'backend'): + assert (oneutils.is_valid_attr(cfg_args, 'command')) + setattr(cfg_args, args.backend, cfg_args.command) + else: + # [3] + if oneutils.is_valid_attr(cfg_args, 'backend'): + assert (oneutils.is_valid_attr(cfg_args, 'command')) + given_backends = [cfg_args.backend] + setattr(cfg_args, cfg_args.backend, cfg_args.command) + # [4] + if oneutils.is_valid_attr(cfg_args, 'backends'): + given_backends = cfg_args.backends.split(',') + # [5], [6] + else: + assert (backend_args or unknown_args) + given_backends = [args.backend] + + for given_backend in given_backends: + # make a command to run given backend driver + profile_path = None + backend_base = given_backend + '-profile' + for cand in backends_list: + if ntpath.basename(cand) == backend_base: + profile_path = cand + if not profile_path: + raise FileNotFoundError(backend_base + ' not found') + + profile_cmd = [profile_path] + if not cmd_overwrite and oneutils.is_valid_attr(cfg_args, given_backend): + profile_cmd += getattr(cfg_args, given_backend).split() + else: + profile_cmd += backend_args + profile_cmd += unknown_args + + # run backend driver + oneutils.run(profile_cmd, err_prefix=backend_base) + + +if __name__ == '__main__': + main() |