From a6b9542f0f8cc86d8c835eff54870a094b7f1f38 Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Thu, 31 Jan 2019 11:11:00 +0000 Subject: [PATCH] target: Speed-up read_tree_values() Since target.read_tree_values() has been modified to use tar as a way to fetch the content of files from the target, it is more robust, but also much slower. Since that level of robustness is in practice required only for very specific use-cased, re-introduce the old way of doing read_tree using find and grep. read_tree_values() gains a new parameter to specify how files should be read from the target, with or without tar. It defaults to the old way of doing things. Signed-off-by: Quentin Perret --- devlib/bin/scripts/shutils.in | 25 +++++++++++++++++++++++++ devlib/target.py | 31 ++++++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/devlib/bin/scripts/shutils.in b/devlib/bin/scripts/shutils.in index e230229..0cca5bb 100755 --- a/devlib/bin/scripts/shutils.in +++ b/devlib/bin/scripts/shutils.in @@ -255,6 +255,28 @@ sched_get_kernel_attributes() { # Misc ################################################################################ +read_tree_values() { + BASEPATH=$1 + MAXDEPTH=$2 + + if [ ! -e $BASEPATH ]; then + echo "ERROR: $BASEPATH does not exist" + exit 1 + fi + + PATHS=$($BUSYBOX find $BASEPATH -follow -maxdepth $MAXDEPTH) + i=0 + for path in $PATHS; do + i=$(expr $i + 1) + if [ $i -gt 1 ]; then + break; + fi + done + if [ $i -gt 1 ]; then + $BUSYBOX grep -s '' $PATHS + fi +} + read_tree_tgz_b64() { BASEPATH=$1 MAXDEPTH=$2 @@ -353,6 +375,9 @@ ftrace_get_function_stats) hotplug_online_all) hotplug_online_all ;; +read_tree_values) + read_tree_values $* + ;; read_tree_tgz_b64) read_tree_tgz_b64 $* ;; diff --git a/devlib/target.py b/devlib/target.py index a902917..18fb59c 100644 --- a/devlib/target.py +++ b/devlib/target.py @@ -695,7 +695,7 @@ class Target(object): timeout = duration + 10 self.execute('sleep {}'.format(duration), timeout=timeout) - def read_tree_values_flat(self, path, depth=1, check_exit_code=True, + def read_tree_tar_flat(self, path, depth=1, check_exit_code=True, decode_unicode=True, strip_null_chars=True): command = 'read_tree_tgz_b64 {} {} {}'.format(quote(path), depth, quote(self.working_directory)) @@ -732,8 +732,23 @@ class Target(object): return result + def read_tree_values_flat(self, path, depth=1, check_exit_code=True): + command = 'read_tree_values {} {}'.format(quote(path), depth) + output = self._execute_util(command, as_root=self.is_rooted, + check_exit_code=check_exit_code) + + accumulator = defaultdict(list) + for entry in output.strip().split('\n'): + if ':' not in entry: + continue + path, value = entry.strip().split(':', 1) + accumulator[path].append(value) + + result = {k: '\n'.join(v).strip() for k, v in accumulator.items()} + return result + def read_tree_values(self, path, depth=1, dictcls=dict, - check_exit_code=True, decode_unicode=True, + check_exit_code=True, tar=False, decode_unicode=True, strip_null_chars=True): """ Reads the content of all files under a given tree @@ -742,14 +757,20 @@ class Target(object): :depth: maximum tree depth to read :dictcls: type of the dict used to store the results :check_exit_code: raise an exception if the shutil command fails - :decode_unicode: decode the content of files as utf-8 + :tar: fetch the entire tree using tar rather than just the value (more + robust but slower in some use-cases) + :decode_unicode: decode the content of tar-ed files as utf-8 :strip_null_chars: remove '\x00' chars from the content of utf-8 decoded files :returns: a tree-like dict with the content of files as leafs """ - value_map = self.read_tree_values_flat(path, depth, check_exit_code, - decode_unicode, strip_null_chars) + if not tar: + value_map = self.read_tree_values_flat(path, depth, check_exit_code) + else: + value_map = self.read_tree_tar_flat(path, depth, check_exit_code, + decode_unicode, + strip_null_chars) return _build_path_tree(value_map, path, self.path.sep, dictcls) # internal methods