[libcamera-devel] [PATCH v3 10/12] utils: libtuning: generators: Add yaml output

Paul Elder paul.elder at ideasonboard.com
Thu Nov 10 18:31:52 CET 2022


Add a generator to libtuning for writing tuning output to a yaml file.

Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>

---
Changes in v3:
- add file description
- remove indirection from fake polymorphism

New in 2
---
 utils/tuning/libtuning/generators/__init__.py |   1 +
 .../libtuning/generators/yaml_output.py       | 123 ++++++++++++++++++
 2 files changed, 124 insertions(+)
 create mode 100644 utils/tuning/libtuning/generators/yaml_output.py

diff --git a/utils/tuning/libtuning/generators/__init__.py b/utils/tuning/libtuning/generators/__init__.py
index 937aff30..f28b6149 100644
--- a/utils/tuning/libtuning/generators/__init__.py
+++ b/utils/tuning/libtuning/generators/__init__.py
@@ -3,3 +3,4 @@
 # Copyright (C) 2022, Paul Elder <paul.elder at ideasonboard.com>
 
 from libtuning.generators.raspberrypi_output import RaspberryPiOutput
+from libtuning.generators.yaml_output import YamlOutput
diff --git a/utils/tuning/libtuning/generators/yaml_output.py b/utils/tuning/libtuning/generators/yaml_output.py
new file mode 100644
index 00000000..6398fc59
--- /dev/null
+++ b/utils/tuning/libtuning/generators/yaml_output.py
@@ -0,0 +1,123 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright 2022 Paul Elder <paul.elder at ideasonboard.com>
+#
+# yaml_output.py - Generate tuning file in YAML format
+
+from .generator import Generator
+
+from numbers import Number
+from pathlib import Path
+
+import libtuning.utils as utils
+
+
+class YamlOutput(Generator):
+    def __init__(self):
+        super().__init__()
+
+    def _stringify_number_list(self, listt: list):
+        line_wrap = 80
+
+        line = '[ ' + ', '.join([str(x) for x in listt]) + ' ]'
+        if len(line) <= line_wrap:
+            return [line]
+
+        out_lines = ['[']
+        line = ' '
+        for x in listt:
+            x_str = str(x)
+            # If the first number is longer than line_wrap, it'll add an extra line
+            if len(line) + len(x_str) > line_wrap:
+                out_lines.append(line)
+                line = f'  {x_str},'
+                continue
+            line += f' {x_str},'
+        out_lines.append(line)
+        out_lines.append(']')
+
+        return out_lines
+
+    # @return Array of lines, and boolean of if all elements were numbers
+    def _stringify_list(self, listt: list):
+        out_lines = []
+
+        all_numbers = set([isinstance(x, Number) for x in listt]).issubset({True})
+
+        if all_numbers:
+            return self._stringify_number_list(listt), True
+
+        for value in listt:
+            if isinstance(value, Number):
+                out_lines.append(f'- {str(value)}')
+            elif isinstance(value, str):
+                out_lines.append(f'- "{value}"')
+            elif isinstance(value, list):
+                lines, all_numbers = self._stringify_list(value)
+
+                if all_numbers:
+                    out_lines.append( f'- {lines[0]}')
+                    out_lines +=     [f'  {line}' for line in lines[1:]]
+                else:
+                    out_lines.append( f'-')
+                    out_lines += [f'  {line}' for line in lines]
+            elif isinstance(value, dict):
+                lines = self._stringify_dict(value)
+                out_lines.append( f'- {lines[0]}')
+                out_lines +=     [f'  {line}' for line in lines[1:]]
+
+        return out_lines, False
+
+    def _stringify_dict(self, dictt: dict):
+        out_lines = []
+
+        for key in dictt:
+            value = dictt[key]
+
+            if isinstance(value, Number):
+                out_lines.append(f'{key}: {str(value)}')
+            elif isinstance(value, str):
+                out_lines.append(f'{key}: "{value}"')
+            elif isinstance(value, list):
+                lines, all_numbers = self._stringify_list(value)
+
+                if all_numbers:
+                    out_lines.append( f'{key}: {lines[0]}')
+                    out_lines +=     [f'{" " * (len(key) + 2)}{line}' for line in lines[1:]]
+                else:
+                    out_lines.append( f'{key}:')
+                    out_lines +=     [f'  {line}' for line in lines]
+            elif isinstance(value, dict):
+                lines = self._stringify_dict(value)
+                out_lines.append( f'{key}:')
+                out_lines +=     [f'  {line}' for line in lines]
+
+        return out_lines
+
+    def write(self, output_file: Path, output_dict: dict, output_order: list):
+        out_lines = [
+            '%YAML 1.1',
+            '---',
+            'version: 1',
+            # No need to condition this, as libtuning already guarantees that
+            # we have at least one module. Even if the module has no output,
+            # its prescence is sufficient.
+            'algorithms:'
+        ]
+
+        for module in output_order:
+            out_lines.append(f'  - {module.out_name}:')
+
+            if len(output_dict[module]) == 0:
+                continue
+
+            if not isinstance(output_dict[module], dict):
+                utils.eprint(f'Error: Output of {module.type} is not a dictionary')
+                continue
+
+            lines = self._stringify_dict(output_dict[module])
+            out_lines += [f'      {line}' for line in lines]
+
+        with open(output_file, 'w') as f:
+            for line in out_lines:
+                f.write(f'{line}\n')
-- 
2.35.1



More information about the libcamera-devel mailing list