From 577769120f4b527e973f248d4641a700125834d4 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 8 Mar 2021 17:23:24 +0100 Subject: membench: New module --- rtemsspec/membench.py | 160 +++++++++++++++++++++++++++ rtemsspec/tests/spec-membench/r0.yml | 13 +++ rtemsspec/tests/spec-membench/r1.yml | 15 +++ rtemsspec/tests/spec-membench/t0.yml | 20 ++++ rtemsspec/tests/spec-membench/t1.yml | 20 ++++ rtemsspec/tests/spec/non-functional-more.yml | 4 + rtemsspec/tests/test_membench.py | 87 +++++++++++++++ 7 files changed, 319 insertions(+) create mode 100644 rtemsspec/membench.py create mode 100644 rtemsspec/tests/spec-membench/r0.yml create mode 100644 rtemsspec/tests/spec-membench/r1.yml create mode 100644 rtemsspec/tests/spec-membench/t0.yml create mode 100644 rtemsspec/tests/spec-membench/t1.yml create mode 100644 rtemsspec/tests/test_membench.py diff --git a/rtemsspec/membench.py b/rtemsspec/membench.py new file mode 100644 index 00000000..a8bc670b --- /dev/null +++ b/rtemsspec/membench.py @@ -0,0 +1,160 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" +This module provides functions for the generation of memory benchmark +documentation. +""" + +# Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import os +import re +from typing import Dict, List, Tuple + +from rtemsspec.items import Item, ItemMapper +from rtemsspec.sphinxcontent import get_label, get_reference, SphinxContent +from rtemsspec.util import run_command + +_SECTION = re.compile( + r"^\s*\d+\s+(\S+)\s+([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s+[0-9a-fA-F]+" + r"\s+[0-9a-fA-F]+\s+.*$") + +_SECTION_MAP = { + ".ARM.attributes": None, + ".ARM.exidx": ".rodata", + ".bss": ".bss", + ".comment": None, + ".data": ".data", + ".debug_abbrev": None, + ".debug_aranges": None, + ".debug_frame": None, + ".debug_info": None, + ".debug_line": None, + ".debug_loc": None, + ".debug_ranges": None, + ".debug_str": None, + ".eh_frame": ".rodata", + ".fini": ".text", + ".fini_array": ".rodata", + ".init": ".text", + ".init_array": ".rodata", + ".nocachenoload": None, + ".robarrier": None, + ".rodata": ".rodata", + ".rtemsroset": ".rodata", + ".rtemsrwset": ".data", + ".rtemsstack": ".rtemsstack", + ".rwbarrier": None, + ".stack": None, + ".start": ".text", + ".text": ".text", + ".vector": ".vector", + ".work": None, + ".xbarrier": None, +} + + +def _do_gather_items(items: List[Item], item: Item) -> None: + if item.type == "test-suite": + items.append(item) + for child in item.children("validation"): + _do_gather_items(items, child) + for child in item.children("requirement-refinement"): + _do_gather_items(items, child) + + +def _gather_items(root: Item) -> List[Item]: + items = [] # type: List[Item] + _do_gather_items(items, root) + return items + + +def _get_sections(item: Item, path: str) -> Dict[str, Tuple[int, int]]: + name = os.path.basename(item.uid).replace("mem-", "") + module = os.path.basename(os.path.dirname(os.path.dirname(item.uid))) + elf = f"{path}/mem-{module}-{name}.norun.exe" + stdout = [] # type: List[str] + status = run_command(["objdump", "-h", elf], stdout=stdout) + assert status == 0 + sections = {} # type: Dict[str, Tuple[int, int]] + for line in stdout: + match = _SECTION.search(line) + if match: + name = match.group(1) + size = int(match.group(2), 16) + section = _SECTION_MAP[name] + if size != 0 and section: + start = int(match.group(3), 16) + end = start + size + info = sections.get(section, (2**64, 0)) + sections[section] = (min(info[0], start), max(info[1], end)) + return sections + + +def _get_label(item: Item) -> str: + return get_label(f"MemBenchmark {item.uid[1:]}") + + +def _generate_table(content: SphinxContent, items: List[Item], + path: str) -> None: + rows = [] # type: List[Tuple[str, ...]] + for index, item in enumerate(items): + sections = _get_sections(item, path) + name = (get_reference(_get_label(item), item.uid), ) + if index == 0: + keys = ("spec", ) + tuple(sections.keys()) + base = {key: info[1] - info[0] for key, info in sections.items()} + rows.append(keys) + rows.append(name + tuple(map(str, base.values()))) + else: + rows.append(name + tuple(f"{info[1] - info[0] - base[key]:+}" + for key, info in sections.items())) + + pivot = items[0] + section = f"Benchmarks Based on: {pivot.spec}" + with content.section(section): + content.wrap(f"""The following memory benchmarks are based on the +memory benchmark defined by {get_reference(_get_label(pivot), pivot.spec)}.""") + content.add_simple_table(rows) + + +def _generate_paragraphs(content: SphinxContent, items: List[Item], + mapper: ItemMapper) -> None: + for item in items: + section = f"Benchmark: {item.spec}" + with content.section(section, label=_get_label(item)): + content.wrap(mapper.substitute(item["test-brief"], item)) + content.wrap(mapper.substitute(item["test-description"], item)) + + +def generate(content: SphinxContent, root: Item, mapper: ItemMapper, + table_pivots: List[str], path: str) -> None: + """ + Generates memory benchmark documentation for items dependent on the root + item and executables in the path. + """ + for pivot in table_pivots: + items = _gather_items(root.map(pivot)) + _generate_table(content, items, path) + items = _gather_items(root) + _generate_paragraphs(content, items, mapper) diff --git a/rtemsspec/tests/spec-membench/r0.yml b/rtemsspec/tests/spec-membench/r0.yml new file mode 100644 index 00000000..763d4982 --- /dev/null +++ b/rtemsspec/tests/spec-membench/r0.yml @@ -0,0 +1,13 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de +enabled-by: true +links: [] +non-functional-type: quality +rationale: null +references: [] +requirement-type: non-functional +text: | + The system shall provide benchmark programs to show the static memory usage + of features. +type: requirement diff --git a/rtemsspec/tests/spec-membench/r1.yml b/rtemsspec/tests/spec-membench/r1.yml new file mode 100644 index 00000000..62ee3440 --- /dev/null +++ b/rtemsspec/tests/spec-membench/r1.yml @@ -0,0 +1,15 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de +enabled-by: true +links: +- role: requirement-refinement + uid: r0 +non-functional-type: quality +rationale: null +references: [] +requirement-type: non-functional +text: | + The system shall provide a benchmark program to show the static memory usage + of a basic application configuration. +type: requirement diff --git a/rtemsspec/tests/spec-membench/t0.yml b/rtemsspec/tests/spec-membench/t0.yml new file mode 100644 index 00000000..e4892555 --- /dev/null +++ b/rtemsspec/tests/spec-membench/t0.yml @@ -0,0 +1,20 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +code: | + /* Blue green code */ +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +description: The Blue Green description. +enabled-by: true +links: +- role: validation + uid: r1 +test-brief: The Blue Green brief description. +test-code: | + /* Blue green code */ +test-description: The Blue Green description. +test-includes: +- blue.h +test-local-includes: +- green.h +test-target: t0.c +type: test-suite diff --git a/rtemsspec/tests/spec-membench/t1.yml b/rtemsspec/tests/spec-membench/t1.yml new file mode 100644 index 00000000..e4892555 --- /dev/null +++ b/rtemsspec/tests/spec-membench/t1.yml @@ -0,0 +1,20 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +code: | + /* Blue green code */ +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +description: The Blue Green description. +enabled-by: true +links: +- role: validation + uid: r1 +test-brief: The Blue Green brief description. +test-code: | + /* Blue green code */ +test-description: The Blue Green description. +test-includes: +- blue.h +test-local-includes: +- green.h +test-target: t0.c +type: test-suite diff --git a/rtemsspec/tests/spec/non-functional-more.yml b/rtemsspec/tests/spec/non-functional-more.yml index ba081e3f..33c5b5d4 100644 --- a/rtemsspec/tests/spec/non-functional-more.yml +++ b/rtemsspec/tests/spec/non-functional-more.yml @@ -9,6 +9,10 @@ links: spec-key: non-functional-type spec-value: performance-runtime uid: non-functional +- role: spec-refinement + spec-key: non-functional-type + spec-value: quality + uid: non-functional spec-description: null spec-example: null spec-info: diff --git a/rtemsspec/tests/test_membench.py b/rtemsspec/tests/test_membench.py new file mode 100644 index 00000000..3bc5ecb5 --- /dev/null +++ b/rtemsspec/tests/test_membench.py @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Unit tests for the rtemsspec.membench module. """ + +# Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from rtemsspec.membench import generate +from rtemsspec.items import ItemCache, ItemMapper +from rtemsspec.sphinxcontent import SphinxContent +from rtemsspec.tests.util import create_item_cache_config_and_copy_spec + + +def run_command(args, cwd=None, stdout=None): + stdout.extend([ + " 0 .start 00000708 00100000 00100000 00010000 2**2", + " CONTENTS, ALLOC, LOAD, READONLY, CODE", + " 2 .text 000090bc 00100740 00100740 00010740 2**6", + " CONTENTS, ALLOC, LOAD, READONLY, CODE", + " 22 .debug_aranges 000011d8 00000000 00000000 000202e8 2**3" + ]) + return 0 + + +def test_membench(tmpdir, monkeypatch): + monkeypatch.setattr("rtemsspec.membench.run_command", run_command) + item_cache_config = create_item_cache_config_and_copy_spec( + tmpdir, "spec-membench", with_spec_types=True) + item_cache = ItemCache(item_cache_config) + root = item_cache["/r0"] + content = SphinxContent() + generate(content, root, ItemMapper(root), ["/r0"], "path") + assert str(content) == """.. _SectionBenchmarksBasedOnSpecT0: + +Benchmarks Based on: spec:/t0 +============================= + +The following memory benchmarks are based on the memory benchmark defined by +:ref:`spec:/t0 `. + +.. table:: + :class: longtable + + =========================== ===== + spec .text + =========================== ===== + :ref:`/t0 ` 38908 + :ref:`/t1 ` +0 + =========================== ===== + +.. _MemBenchmarkT0: + +Benchmark: spec:/t0 +=================== + +The Blue Green brief description. + +The Blue Green description. + +.. _MemBenchmarkT1: + +Benchmark: spec:/t1 +=================== + +The Blue Green brief description. + +The Blue Green description. +""" -- cgit v1.2.3