summaryrefslogtreecommitdiff
path: root/compiler/one-cmds/one-profile
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/one-cmds/one-profile')
-rw-r--r--compiler/one-cmds/one-profile246
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()