From 010b732a89352993eda688f2352375464fd712e3 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 21 Nov 2023 11:13:15 +0100 Subject: membench: Support variant comparison --- generate_membench.py | 5 +- membench.py | 43 ++- rtemsspec/membench.py | 367 +++++++++++++++++++-- rtemsspec/tests/spec-membench/r2.yml | 15 + rtemsspec/tests/spec-membench/r3.yml | 15 + rtemsspec/tests/spec-membench/r4.yml | 15 + .../tests/spec-membench/rtems/val/mem-basic.yml | 54 +++ rtemsspec/tests/spec-membench/t1.yml | 2 +- rtemsspec/tests/spec-membench/t2.yml | 20 ++ rtemsspec/tests/spec-membench/t3.yml | 20 ++ rtemsspec/tests/test_membench.py | 194 ++++++++++- 11 files changed, 692 insertions(+), 58 deletions(-) create mode 100644 rtemsspec/tests/spec-membench/r2.yml create mode 100644 rtemsspec/tests/spec-membench/r3.yml create mode 100644 rtemsspec/tests/spec-membench/r4.yml create mode 100644 rtemsspec/tests/spec-membench/rtems/val/mem-basic.yml create mode 100644 rtemsspec/tests/spec-membench/t2.yml create mode 100644 rtemsspec/tests/spec-membench/t3.yml diff --git a/generate_membench.py b/generate_membench.py index 90c2e6e8..73f1c784 100755 --- a/generate_membench.py +++ b/generate_membench.py @@ -31,7 +31,7 @@ import textwrap from typing import NamedTuple, List, Optional from rtemsspec.items import ItemCache -from rtemsspec.membench import generate +from rtemsspec.membench import gather_sections, generate from rtemsspec.sphinxcontent import SphinxContent, SphinxMapper from rtemsspec.util import create_argument_parser, init_logging, load_config @@ -823,9 +823,10 @@ def _post_process(path: str) -> None: config = load_config("config.yml") item_cache = ItemCache(config["spec"]) root = item_cache["/rtems/req/mem-basic"] + sections_by_uid = gather_sections(item_cache, path, "objdump", "gdb") content = SphinxContent() table_pivots = ["/rtems/req/mem-basic", "/rtems/req/mem-smp-1"] - generate(content, root, SphinxMapper(root), table_pivots, path) + generate(content, sections_by_uid, root, table_pivots, SphinxMapper(root)) print(content) diff --git a/membench.py b/membench.py index a8e3b4c0..87a513e6 100755 --- a/membench.py +++ b/membench.py @@ -26,30 +26,57 @@ # POSSIBILITY OF SUCH DAMAGE. import sys +from typing import Dict, List, Optional -from rtemsspec.items import ItemCache, item_is_enabled -from rtemsspec.membench import generate +from rtemsspec.items import ItemCache +from rtemsspec.membench import gather_sections, generate, \ + generate_variants_table, MembenchVariant, SectionsByUID from rtemsspec.sphinxcontent import SphinxContent, SphinxMapper from rtemsspec.util import create_argument_parser, init_logging, load_config +def _split(value: Optional[str]) -> List[str]: + return value.split(",") if value else [] + + def main() -> None: """ Generates a memory benchmark report. """ parser = create_argument_parser() parser.add_argument( "builddir", metavar="BUILDDIR", - nargs=1, + nargs="+", help="the build directory containing the memory benchmark executables") + parser.add_argument( + "--enabled", + help=("a comma separated list of enabled options used to evaluate " + "enabled-by expressions")) + parser.add_argument("--variants", + help="a comma separated list of variant names") args = parser.parse_args(sys.argv[1:]) init_logging(args) - config = load_config("config.yml") - item_cache = ItemCache(config["spec"]) - item_cache.set_enabled([], item_is_enabled) + config = load_config("config.yml")["spec"] + config["enabled"] = _split(args.enabled) + item_cache = ItemCache(config) content = SphinxContent() root = item_cache["/rtems/req/mem-basic"] - table_pivots = ["/rtems/req/mem-basic", "/rtems/req/mem-smp-1"] - generate(content, root, SphinxMapper(root), table_pivots, args.builddir[0]) + table_pivots = ["/rtems/req/mem-smp-1"] + if len(args.builddir) == 1: + sections_by_uid = gather_sections(item_cache, args.builddir[0], + "objdump", "gdb") + generate(content, sections_by_uid, root, table_pivots, + SphinxMapper(root)) + else: + names = _split(args.variants) + assert len(names) == len(args.builddir) + sections_by_build_label: Dict[str, Dict[str, SectionsByUID]] = {} + variants: List[MembenchVariant] = [] + for name, builddir in zip(names, args.builddir): + sections_by_build_label[name]["membench"] = gather_sections( + item_cache, builddir, "objdump", "gdb") + variants.append(MembenchVariant(name, name)) + generate_variants_table(content, sections_by_build_label, root, + variants) print(str(content)) diff --git a/rtemsspec/membench.py b/rtemsspec/membench.py index 6453aad1..b395f728 100644 --- a/rtemsspec/membench.py +++ b/rtemsspec/membench.py @@ -4,7 +4,7 @@ This module provides functions for the generation of memory benchmark documentation. """ -# Copyright (C) 2021 embedded brains GmbH & Co. KG +# Copyright (C) 2021, 2023 embedded brains GmbH & Co. KG # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -29,12 +29,25 @@ documentation. import os import re -from typing import Dict, List, Tuple +from typing import Any, Dict, List, NamedTuple, Tuple -from rtemsspec.items import Item, ItemMapper -from rtemsspec.sphinxcontent import make_label, get_reference, SphinxContent +from rtemsspec.items import Item, ItemCache, ItemMapper +from rtemsspec.sphinxcontent import get_reference, SphinxContent from rtemsspec.util import run_command + +class MembenchVariant(NamedTuple): + """ Represents a static memory benchmark configuration. """ + name: str + build_label: str + + +SectionsByUID = Dict[str, Dict[str, int]] + +_SECTIONS = {".text": 0, ".rodata": 1, ".data": 2, ".bss": 3, ".noinit": 4} + +_SECTION_KEYS = tuple(sorted(_SECTIONS.keys(), key=lambda x: _SECTIONS[x])) + _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+.*$") @@ -53,6 +66,7 @@ _SECTION_MAP = { ".debug_line_str": None, ".debug_loc": None, ".debug_loclists": None, + ".debug_pubnames": None, ".debug_ranges": None, ".debug_rnglists": None, ".debug_str": None, @@ -81,6 +95,184 @@ _SECTION_MAP = { ".xbarrier": None, } +_OBJECT_SIZES = { + "/c/void-pointer": { + "commands": ["sizeof(void *)"], + "uid": "/rtems/val/mem-basic" + }, + "/rtems/barrier/info": { + "commands": ["sizeof(_Barrier_Information)"], + "uid": "/rtems/barrier/val/mem-wait-rel-del" + }, + "/rtems/barrier/obj": { + "commands": ["sizeof(Objects_Control *) + sizeof(Barrier_Control)"], + "uid": "/rtems/barrier/val/mem-wait-rel-del" + }, + "/rtems/message/info": { + "commands": ["sizeof(_Message_queue_Information)"], + "uid": "/rtems/message/val/mem-snd-rcv-del" + }, + "/rtems/message/obj": { + "commands": + ["sizeof(Objects_Control *) + sizeof(Message_queue_Control)"], + "uid": "/rtems/message/val/mem-snd-rcv-del" + }, + "/rtems/part/info": { + "commands": ["sizeof(_Partition_Information)"], + "uid": "/rtems/part/val/mem-get-ret-del" + }, + "/rtems/part/obj": { + "commands": ["sizeof(Objects_Control *) + sizeof(Partition_Control)"], + "uid": "/rtems/part/val/mem-get-ret-del" + }, + "/rtems/priority/control": { + "commands": ["sizeof(Priority_Control)"], + "uid": "/rtems/sem/val/mem-obt-rel-del" + }, + "/rtems/ratemon/info": { + "commands": ["sizeof(_Rate_monotonic_Information)"], + "uid": "/rtems/ratemon/val/mem-period-del" + }, + "/rtems/ratemon/obj": { + "commands": + ["sizeof(Objects_Control *) + sizeof(Rate_monotonic_Control)"], + "uid": "/rtems/ratemon/val/mem-period-del" + }, + "/rtems/sem/info": { + "commands": ["sizeof(_Semaphore_Information)"], + "uid": "/rtems/sem/val/mem-obt-rel-del" + }, + "/rtems/sem/obj": { + "commands": ["sizeof(Objects_Control *) + sizeof(Semaphore_Control)"], + "uid": "/rtems/sem/val/mem-obt-rel-del" + }, + "/rtems/sem/obj-mrsp": { + "commands": [ + "sizeof(Objects_Control *) + sizeof(Objects_Control) + " + "sizeof(MRSP_Control)" + ], + "uid": + "/rtems/sem/val/mem-obt-rel-del" + }, + "/rtems/task/info": { + "commands": ["sizeof(_RTEMS_tasks_Information)"], + "uid": "/rtems/val/mem-basic" + }, + "/rtems/task/obj": { + "commands": [ + "sizeof(Objects_Control *) + sizeof(Thread_Control) + " + "sizeof(RTEMS_API_Control) + sizeof(Thread_queue_Heads)", + "sizeof(Objects_Control *) + sizeof(Thread_Control) + " + "sizeof(RTEMS_API_Control)" + ], + "uid": + "/rtems/val/mem-basic" + }, + "/rtems/timer/info": { + "commands": ["sizeof(_Timer_Information)"], + "uid": "/rtems/timer/val/mem-after" + }, + "/rtems/timer/obj": { + "commands": ["sizeof(Objects_Control *) + sizeof(Timer_Control)"], + "uid": "/rtems/timer/val/mem-after" + }, + "/rtems/userext/info": { + "commands": ["sizeof(_Extension_Information)"], + "uid": "/rtems/userext/val/mem-create" + }, + "/rtems/userext/obj": { + "commands": ["sizeof(Objects_Control *) + sizeof(Extension_Control)"], + "uid": "/rtems/userext/val/mem-create" + }, + "/scheduler/control": { + "commands": ["sizeof(Scheduler_Control)"], + "uid": "/rtems/val/mem-basic" + }, + "/scheduler/priority/context": { + "commands": ["sizeof(Scheduler_priority_Context)"], + "uid": "/rtems/val/mem-basic" + }, + "/scheduler/priority/node": { + "commands": ["sizeof(Scheduler_priority_Node)"], + "uid": "/rtems/val/mem-basic" + }, + "/scheduler/smp/edf/context": { + "commands": [ + "sizeof(Scheduler_EDF_SMP_Context) + " + "sizeof(Scheduler_EDF_SMP_Ready_queue)" + ], + "uid": + "/rtems/val/mem-smp-1" + }, + "/scheduler/smp/edf/node": { + "commands": ["sizeof(Scheduler_EDF_SMP_Node)"], + "uid": "/rtems/val/mem-smp-1" + }, + "/scheduler/smp/edf/ready-queue": { + "commands": ["sizeof(Scheduler_EDF_SMP_Ready_queue)"], + "uid": "/rtems/val/mem-smp-1" + }, + "/score/chain/control": { + "commands": ["sizeof(Chain_Control)"], + "uid": "/rtems/val/mem-basic" + }, + "/score/tq/priority-queue": { + "commands": ["sizeof(Thread_queue_Priority_queue)"], + "uid": "/rtems/val/mem-basic" + }, +} + + +def _section_key(key_value: Tuple[str, Any]) -> int: + return _SECTIONS[key_value[0]] + + +def _get_sections_of_item(sections_by_uid: SectionsByUID, + item: Item) -> Tuple[int, ...]: + return tuple(size for _, size in sorted( + sections_by_uid.get(item.uid, {}).items(), key=_section_key)) + + +def gather_sections(item_cache: ItemCache, path: str, objdump: str, + gdb: str) -> Dict[str, Dict[str, int]]: + """ + Gathers the object sizes for all memory benchmarks of the item cache using + the programs of the path. + """ + sections_by_uid: Dict[str, Dict[str, int]] = {} + for item in item_cache.items_by_type["memory-benchmark"]: + sections = _get_sections(item, path, objdump, gdb) + if sections: + sections_by_uid[item.uid] = sections + return sections_by_uid + + +def gather_object_sizes(item_cache: ItemCache, path: str, + gdb: str) -> Dict[str, int]: + """ + Gathers the object sizes for all memory benchmarks of the item cache using + the programs of the path. + """ + object_sizes: Dict[str, int] = {} + for key, value in _OBJECT_SIZES.items(): + try: + item = item_cache[value["uid"]] + except KeyError: + continue + file = _get_path_to_test_suite_elf_file(item, path) + for command in value["commands"]: + cmd = [gdb, "-ex", f"p {command}", "--batch", ""] + cmd[-1] = file + stdout: List[str] = [] + status = run_command(cmd, stdout=stdout) + if status == 0: + output = " ".join(stdout) + match = re.search(r"\$[0-9]+\s*=\s*([0-9]+)", output) + assert match + object_sizes[key] = int(match.group(1)) + break + return object_sizes + def _do_gather_test_suites(items: List[Item], item: Item) -> None: if item.type == "memory-benchmark": @@ -91,26 +283,64 @@ def _do_gather_test_suites(items: List[Item], item: Item) -> None: _do_gather_test_suites(items, child) -def gather_benchmarks(root: Item) -> List[Item]: +def _gather_benchmarks(root: Item) -> List[Item]: """ Gather all test suite items related to the root item. """ items: List[Item] = [] _do_gather_test_suites(items, root) return items -def get_path_to_test_suite_elf_file(item: Item, path: str) -> str: +def _get_path_to_test_suite_elf_file(item: Item, path: str) -> str: """ Returns the path to the ELF file of the test suite. """ - name = os.path.basename(item.uid).replace("mem-", "") - module = os.path.basename(os.path.dirname(os.path.dirname(item.uid))) - return f"{path}/mem-{module}-{name}.norun.exe" + name = item["test-target"] + return os.path.join(path, f"{name[:name.rfind('.')]}.norun.exe") + + +def _try_add_workspace(gdb: str, elf: str, + section_limits: Dict[str, Tuple[int, int]]) -> None: + if ".noinit" in section_limits: + return + # Maybe an older version of RTEMS + stdout: List[str] = [] + cmd = [gdb, "-ex", "p Configuration.work_space_size", "--batch", elf] + status = run_command(cmd, stdout=stdout) + if status == 0 and stdout[0].startswith("$1 = "): + section_limits[".noinit"] = (0, int(stdout[0][5:])) + + +def _get_size(section_limits: Dict[str, Tuple[int, int]], key: str) -> int: + limits = section_limits.get(key, (0, 0)) + return limits[1] - limits[0] -def _get_sections(item: Item, path: str) -> Dict[str, Tuple[int, int]]: - elf = get_path_to_test_suite_elf_file(item, path) +def _run_objdump(objdump: str, elf: str) -> List[str]: stdout: List[str] = [] - status = run_command(["objdump", "-h", elf], stdout=stdout) - assert status == 0 - sections: Dict[str, Tuple[int, int]] = {} + status = run_command([objdump, "-h", elf], stdout=stdout) + if status != 0: + return [] + return stdout + + +def _make_sections( + section_limits: Dict[str, Tuple[int, int]]) -> Dict[str, int]: + sections: Dict[str, int] = {} + for key in _SECTIONS: + sections[key] = _get_size(section_limits, key) + sections[".noinit"] += _get_size(section_limits, ".vector") + return sections + + +def _get_sections(item: Item, path_to_elf_files: str, objdump: str, + gdb: str) -> Dict[str, int]: + """ + Gets the memory benchmark sections of the program associated with the item + in the path to ELF files. + """ + elf = _get_path_to_test_suite_elf_file(item, path_to_elf_files) + stdout = _run_objdump(objdump, elf) + if not stdout: + return {} + section_limits: Dict[str, Tuple[int, int]] = {} for line in stdout: match = _SECTION.search(line) if match: @@ -120,29 +350,34 @@ def _get_sections(item: Item, path: str) -> Dict[str, Tuple[int, int]]: 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 + limits = section_limits.get(section, (2**64, 0)) + section_limits[section] = (min(limits[0], + start), max(limits[1], end)) + _try_add_workspace(gdb, elf, section_limits) + return _make_sections(section_limits) def _make_label(item: Item) -> str: - return make_label(f"MemBenchmark {item.uid[1:]}") + return f"Membench{item.ident}" -def _generate_table(content: SphinxContent, items: List[Item], - path: str) -> None: +def _generate_table(content: SphinxContent, sections_by_uid: SectionsByUID, + items: List[Item]) -> None: rows: List[Tuple[str, ...]] = [] for index, item in enumerate(items): - sections = _get_sections(item, path) - name = (get_reference(_make_label(item), item.uid), ) + sections = _get_sections_of_item(sections_by_uid, item) + spec = (get_reference(_make_label(item), item.uid), ) if index == 0: - keys = ("spec", ) + tuple(sections.keys()) - base = {key: info[1] - info[0] for key, info in sections.items()} + assert sections + keys = ("Specification", ) + _SECTION_KEYS + base = sections rows.append(keys) - rows.append(name + tuple(map(str, base.values()))) + rows.append(spec + tuple(map(str, sections))) + elif sections: + rows.append(spec + tuple(f"{i - j:+}" + for i, j in zip(sections, base))) else: - rows.append(name + tuple(f"{info[1] - info[0] - base[key]:+}" - for key, info in sections.items())) + rows.append(spec + tuple("?") * len(keys)) pivot = items[0] section = f"Benchmarks Based on: {pivot.spec}" @@ -153,23 +388,83 @@ memory benchmark defined by content.add_simple_table(rows) -def _generate_paragraphs(content: SphinxContent, items: List[Item], - mapper: ItemMapper) -> None: +_WARNING_NO_MEMBENCH = """.. topic:: WARNING + + There are no results available for this static memory usage benchmark. +""" + + +def _generate_paragraphs(content: SphinxContent, + sections_by_uid: SectionsByUID, mapper: ItemMapper, + items: List[Item]) -> None: for item in items: section = f"Benchmark: {item.spec}" with content.section(section, label=_make_label(item)): content.wrap(mapper.substitute(item["test-brief"], item)) content.wrap(mapper.substitute(item["test-description"], item)) + sections = _get_sections_of_item(sections_by_uid, item) + if sections: + content.add_simple_table( + [_SECTION_KEYS, tuple(map(str, sections))]) + else: + content.add(_WARNING_NO_MEMBENCH) + + +def _generate_tables(content: SphinxContent, sections_by_uid: SectionsByUID, + root: Item, table_pivots: List[str]) -> List[Item]: + root_items = _gather_benchmarks(root) + _generate_table(content, sections_by_uid, root_items) + for pivot_uid in table_pivots: + pivot = root.map(pivot_uid) + if not pivot.enabled: + continue + pivot_items = _gather_benchmarks(pivot) + _generate_table(content, sections_by_uid, pivot_items) + return root_items + + +def generate_tables(content: SphinxContent, sections_by_uid: SectionsByUID, + root: Item, table_pivots: List[str]) -> None: + """ Generates memory benchmark tables. """ + _generate_tables(content, sections_by_uid, root, table_pivots) + + +def generate_variants_table(content: SphinxContent, + sections_by_build_label: Dict[str, + Dict[str, + SectionsByUID]], + root: Item, + variants: List[MembenchVariant]) -> None: + """ Generates memory benchmark variant comparison tables. """ + items = _gather_benchmarks(root) + rows: List[Tuple[str, + ...]] = [("Specification", "Variant") + _SECTION_KEYS] + for item in items: + spec = get_reference(_make_label(item), item.uid) + for index, variant in enumerate(variants): + sections = _get_sections_of_item( + sections_by_build_label[variant.build_label]["membench"], item) + what = (spec, variant.name) + if index == 0: + assert sections + base = sections + rows.append(what + tuple(map(str, sections))) + else: + if sections: + rows.append(what + tuple(f"{i - j:+}" + for i, j in zip(sections, base))) + else: + rows.append(what + tuple("?") * len(base)) + spec = "" + with content.latex_tiny("scriptsize"): + content.add_grid_table(rows, [35, 20, 9, 9, 9, 9, 9]) -def generate(content: SphinxContent, root: Item, mapper: ItemMapper, - table_pivots: List[str], path: str) -> None: +def generate(content: SphinxContent, sections_by_uid: SectionsByUID, + root: Item, table_pivots: List[str], mapper: ItemMapper) -> None: """ Generates memory benchmark documentation for items dependent on the root item and executables in the path. """ - for pivot in table_pivots: - items = gather_benchmarks(root.map(pivot)) - _generate_table(content, items, path) - items = gather_benchmarks(root) - _generate_paragraphs(content, items, mapper) + root_items = _generate_tables(content, sections_by_uid, root, table_pivots) + _generate_paragraphs(content, sections_by_uid, mapper, root_items) diff --git a/rtemsspec/tests/spec-membench/r2.yml b/rtemsspec/tests/spec-membench/r2.yml new file mode 100644 index 00000000..2ac74b9d --- /dev/null +++ b/rtemsspec/tests/spec-membench/r2.yml @@ -0,0 +1,15 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2021 embedded brains GmbH & Co. KG +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/r3.yml b/rtemsspec/tests/spec-membench/r3.yml new file mode 100644 index 00000000..2ac74b9d --- /dev/null +++ b/rtemsspec/tests/spec-membench/r3.yml @@ -0,0 +1,15 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2021 embedded brains GmbH & Co. KG +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/r4.yml b/rtemsspec/tests/spec-membench/r4.yml new file mode 100644 index 00000000..6ad6dc06 --- /dev/null +++ b/rtemsspec/tests/spec-membench/r4.yml @@ -0,0 +1,15 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2021 embedded brains GmbH & Co. KG +enabled-by: false +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/rtems/val/mem-basic.yml b/rtemsspec/tests/spec-membench/rtems/val/mem-basic.yml new file mode 100644 index 00000000..8cfcd1cf --- /dev/null +++ b/rtemsspec/tests/spec-membench/rtems/val/mem-basic.yml @@ -0,0 +1,54 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2021 embedded brains GmbH & Co. KG +enabled-by: true +links: [] +test-brief: | + This static memory usage benchmark program facilitates a basic application + configuration. +test-code: | + static void Init( rtems_task_argument arg ) + { + (void) arg; + + /* Nothing to do */ + } + + #define TASK_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES + + #define TASK_STORAGE_SIZE \ + RTEMS_TASK_STORAGE_SIZE( \ + RTEMS_MINIMUM_STACK_SIZE, \ + TASK_ATTRIBUTES ) + + #define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER + + #define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0 + + #define CONFIGURE_DISABLE_NEWLIB_REENTRANCY + + #define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM + + #define CONFIGURE_IDLE_TASK_STORAGE_SIZE RTEMS_MINIMUM_STACK_SIZE + + #define CONFIGURE_MAXIMUM_TASKS 1 + + #define CONFIGURE_RTEMS_INIT_TASKS_TABLE + + #define CONFIGURE_INIT_TASK_ATTRIBUTES TASK_ATTRIBUTES + + #define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + + #define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE TASK_STORAGE_SIZE + + #define CONFIGURE_INIT + + #include +test-description: | + This resource benchmark is configured for exactly one processor, no clock + driver, no Newlib reentrancy support, and no file system. +test-includes: +- rtems.h +test-local-includes: [] +test-target: mem-rtems-basic.c +type: memory-benchmark diff --git a/rtemsspec/tests/spec-membench/t1.yml b/rtemsspec/tests/spec-membench/t1.yml index 1ea13629..b5683255 100644 --- a/rtemsspec/tests/spec-membench/t1.yml +++ b/rtemsspec/tests/spec-membench/t1.yml @@ -16,5 +16,5 @@ test-includes: - blue.h test-local-includes: - green.h -test-target: t0.c +test-target: t1.c type: memory-benchmark diff --git a/rtemsspec/tests/spec-membench/t2.yml b/rtemsspec/tests/spec-membench/t2.yml new file mode 100644 index 00000000..2fff64c4 --- /dev/null +++ b/rtemsspec/tests/spec-membench/t2.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 & Co. KG +description: The Blue Green description. +enabled-by: true +links: +- role: validation + uid: r2 +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: t2.c +type: memory-benchmark diff --git a/rtemsspec/tests/spec-membench/t3.yml b/rtemsspec/tests/spec-membench/t3.yml new file mode 100644 index 00000000..cf20ed3f --- /dev/null +++ b/rtemsspec/tests/spec-membench/t3.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 & Co. KG +description: The Blue Green description. +enabled-by: true +links: +- role: validation + uid: r3 +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: t3.c +type: memory-benchmark diff --git a/rtemsspec/tests/test_membench.py b/rtemsspec/tests/test_membench.py index 76de9180..66ca8c7d 100644 --- a/rtemsspec/tests/test_membench.py +++ b/rtemsspec/tests/test_membench.py @@ -24,13 +24,26 @@ # 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.membench import gather_object_sizes, gather_sections, \ + generate, generate_tables, generate_variants_table, MembenchVariant 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): + if args[0] == "object-sizes": + if "Thread" in args[2]: + stdout.append("$1 = 42") + return 0 + return 1 + if args[0] == "gdb" and "t3" in args[-1]: + stdout.append("$1 = 133") + return 0 + if "t2" in args[-1]: + return 1 + if "t1" in args[-1] and "path-2" in args[-1]: + return 1 stdout.extend([ " 0 .start 00000708 00100000 00100000 00010000 2**2", " CONTENTS, ALLOC, LOAD, READONLY, CODE", @@ -38,6 +51,11 @@ def run_command(args, cwd=None, stdout=None): " CONTENTS, ALLOC, LOAD, READONLY, CODE", " 22 .debug_aranges 000011d8 00000000 00000000 000202e8 2**3" ]) + if "t1" in args[-1]: + stdout.extend([ + " 3 .noinit 00001900 400809e0 400809e0 000909e0 2**3", + " ALLOC" + ]) return 0 @@ -46,28 +64,55 @@ def test_membench(tmpdir, monkeypatch): item_cache_config = create_item_cache_config_and_copy_spec( tmpdir, "spec-membench", with_spec_types=True) item_cache = ItemCache(item_cache_config) + object_sizes = gather_object_sizes(item_cache, "path", "object-sizes") + assert len(object_sizes) == 2 + assert object_sizes["/rtems/task/obj"] == 42 + sections_by_uid = gather_sections(item_cache, "path", "objdump", "gdb") + sections_by_uid_2 = gather_sections(item_cache, "path-2", "objdump", "gdb") root = item_cache["/r0"] content = SphinxContent() - generate(content, root, ItemMapper(root), ["/r0"], "path") + generate(content, sections_by_uid, root, ["r0", "r4"], ItemMapper(root)) assert str(content) == """.. _BenchmarksBasedOnSpecT0: Benchmarks Based on: spec:/t0 ============================= The following memory benchmarks are based on the memory benchmark defined by -:ref:`spec:/t0 `. +:ref:`spec:/t0 `. .. table:: :class: longtable - =========================== ===== - spec .text - =========================== ===== - :ref:`/t0 ` 38908 - :ref:`/t1 ` +0 - =========================== ===== + ======================= ===== ======= ===== ==== ======= + Specification .text .rodata .data .bss .noinit + ======================= ===== ======= ===== ==== ======= + :ref:`/t0 ` 38908 0 0 0 0 + :ref:`/t1 ` +0 +0 +0 +0 +6400 + :ref:`/t2 ` ? ? ? ? ? + :ref:`/t3 ` +0 +0 +0 +0 +133 + ======================= ===== ======= ===== ==== ======= -.. _MemBenchmarkT0: +.. _BenchmarksBasedOnSpecT0: + +Benchmarks Based on: spec:/t0 +============================= + +The following memory benchmarks are based on the memory benchmark defined by +:ref:`spec:/t0 `. + +.. table:: + :class: longtable + + ======================= ===== ======= ===== ==== ======= + Specification .text .rodata .data .bss .noinit + ======================= ===== ======= ===== ==== ======= + :ref:`/t0 ` 38908 0 0 0 0 + :ref:`/t1 ` +0 +0 +0 +0 +6400 + :ref:`/t2 ` ? ? ? ? ? + :ref:`/t3 ` +0 +0 +0 +0 +133 + ======================= ===== ======= ===== ==== ======= + +.. _MembenchT0: Benchmark: spec:/t0 =================== @@ -76,7 +121,16 @@ The Blue Green brief description. The Blue Green description. -.. _MemBenchmarkT1: +.. table:: + :class: longtable + + ===== ======= ===== ==== ======= + .text .rodata .data .bss .noinit + ===== ======= ===== ==== ======= + 38908 0 0 0 0 + ===== ======= ===== ==== ======= + +.. _MembenchT1: Benchmark: spec:/t1 =================== @@ -84,4 +138,122 @@ Benchmark: spec:/t1 The Blue Green brief description. The Blue Green description. + +.. table:: + :class: longtable + + ===== ======= ===== ==== ======= + .text .rodata .data .bss .noinit + ===== ======= ===== ==== ======= + 38908 0 0 0 6400 + ===== ======= ===== ==== ======= + +.. _MembenchT2: + +Benchmark: spec:/t2 +=================== + +The Blue Green brief description. + +The Blue Green description. + +.. topic:: WARNING + + There are no results available for this static memory usage benchmark. + +.. _MembenchT3: + +Benchmark: spec:/t3 +=================== + +The Blue Green brief description. + +The Blue Green description. + +.. table:: + :class: longtable + + ===== ======= ===== ==== ======= + .text .rodata .data .bss .noinit + ===== ======= ===== ==== ======= + 38908 0 0 0 133 + ===== ======= ===== ==== ======= +""" + content = SphinxContent() + generate_tables(content, sections_by_uid, root, ["r0", "r4"]) + assert str(content) == """.. _BenchmarksBasedOnSpecT0: + +Benchmarks Based on: spec:/t0 +============================= + +The following memory benchmarks are based on the memory benchmark defined by +:ref:`spec:/t0 `. + +.. table:: + :class: longtable + + ======================= ===== ======= ===== ==== ======= + Specification .text .rodata .data .bss .noinit + ======================= ===== ======= ===== ==== ======= + :ref:`/t0 ` 38908 0 0 0 0 + :ref:`/t1 ` +0 +0 +0 +0 +6400 + :ref:`/t2 ` ? ? ? ? ? + :ref:`/t3 ` +0 +0 +0 +0 +133 + ======================= ===== ======= ===== ==== ======= + +.. _BenchmarksBasedOnSpecT0: + +Benchmarks Based on: spec:/t0 +============================= + +The following memory benchmarks are based on the memory benchmark defined by +:ref:`spec:/t0 `. + +.. table:: + :class: longtable + + ======================= ===== ======= ===== ==== ======= + Specification .text .rodata .data .bss .noinit + ======================= ===== ======= ===== ==== ======= + :ref:`/t0 ` 38908 0 0 0 0 + :ref:`/t1 ` +0 +0 +0 +0 +6400 + :ref:`/t2 ` ? ? ? ? ? + :ref:`/t3 ` +0 +0 +0 +0 +133 + ======================= ===== ======= ===== ==== ======= +""" + content = SphinxContent() + root_2 = item_cache["/r1"] + generate_variants_table( + content, { + "bla": { + "membench": sections_by_uid + }, + "blb": { + "membench": sections_by_uid_2 + } + }, root_2, [MembenchVariant("a", "bla"), + MembenchVariant("b", "blb")]) + assert str(content) == """.. raw:: latex + + \\begin{scriptsize} + +.. table:: + :class: longtable + :widths: 35,20,9,9,9,9,9 + + +-------------------------+---------+-------+---------+-------+------+---------+ + | Specification | Variant | .text | .rodata | .data | .bss | .noinit | + +=========================+=========+=======+=========+=======+======+=========+ + | :ref:`/t0 ` | a | 38908 | 0 | 0 | 0 | 0 | + + +---------+-------+---------+-------+------+---------+ + | | b | +0 | +0 | +0 | +0 | +0 | + +-------------------------+---------+-------+---------+-------+------+---------+ + | :ref:`/t1 ` | a | 38908 | 0 | 0 | 0 | 6400 | + + +---------+-------+---------+-------+------+---------+ + | | b | ? | ? | ? | ? | ? | + +-------------------------+---------+-------+---------+-------+------+---------+ + +.. raw:: latex + + \\end{scriptsize} """ -- cgit v1.2.3