[rtems-central commit] generate_membench.py: New script

Sebastian Huber sebh at rtems.org
Wed Mar 10 09:02:05 UTC 2021


Module:    rtems-central
Branch:    master
Commit:    dba1ebcded914f3439a7241a2319392f58c543b6
Changeset: http://git.rtems.org/rtems-central/commit/?id=dba1ebcded914f3439a7241a2319392f58c543b6

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Fri Mar  5 10:35:30 2021 +0100

generate_membench.py: New script

---

 generate_membench.py | 555 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 555 insertions(+)

diff --git a/generate_membench.py b/generate_membench.py
new file mode 100755
index 0000000..b7ac188
--- /dev/null
+++ b/generate_membench.py
@@ -0,0 +1,555 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: BSD-2-Clause
+""" Generates memory benchmarks. """
+
+# 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 argparse
+import logging
+import os
+import sys
+import textwrap
+from typing import NamedTuple, List, Optional
+
+from rtemsspec.items import ItemCache
+from rtemsspec.membench import generate
+from rtemsspec.sphinxcontent import SphinxContent, SphinxMapper
+from rtemsspec.util import load_config
+
+
+class _Test(NamedTuple):
+    path: str
+    name: str
+    links: List[str]
+    topic: str
+    desc: Optional[str]
+    init: str
+    config: str
+
+
+_CONFIG_DEFAULT = """#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_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"""
+
+_TEXT = ("The system shall provide a benchmark program to show the static "
+         "memory usage of")
+
+_TEST = "This static memory usage benchmark program facilitates"
+
+_LINKS_BASIC = ["../../req/mem-basic"]
+
+_TESTS = [
+    _Test(
+        "rtems",
+        "basic",
+        ["/req/mem-benchmark"],
+        "a basic application configuration",
+        """This resource benchmark is configured for exactly one processor,
+no clock driver, no Newlib reentrancy support, and no file system.""",
+        """/* Nothing to do */""", _CONFIG_DEFAULT),
+    _Test(
+        "rtems",
+        "smp-1",
+        ["mem-basic"],
+        """a basic application configuration with
+${/acfg/if/max-processors:/name} defined to one using the SMP EDF scheduler
+(${/acfg/if/scheduler-edf-smp:/name})""",
+        None,
+        """/* Nothing to do */""",
+        """#define CONFIGURE_MAXIMUM_PROCESSORS 1
+
+#if defined(RTEMS_SMP)
+#define CONFIGURE_SCHEDULER_EDF_SMP
+#endif
+
+""" + _CONFIG_DEFAULT),
+    _Test(
+        "rtems",
+        "smp-global-2",
+        ["mem-smp-1"],
+        """a basic application configuration with
+${/acfg/if/max-processors:/name} defined to two using the global SMP EDF
+scheduler (${/acfg/if/scheduler-edf-smp:/name})""",
+        None,
+        """/* Nothing to do */""",
+        """#define CONFIGURE_MAXIMUM_PROCESSORS 2
+
+#if defined(RTEMS_SMP)
+#define CONFIGURE_SCHEDULER_EDF_SMP
+#endif
+
+""" + _CONFIG_DEFAULT),
+    _Test(
+        "rtems",
+        "smp-global-4",
+        ["mem-smp-1"],
+        """a basic application configuration with
+${/acfg/if/max-processors:/name} defined to four using the global SMP EDF
+scheduler (${/acfg/if/scheduler-edf-smp:/name})""",
+        None,
+        """/* Nothing to do */""",
+        """#define CONFIGURE_MAXIMUM_PROCESSORS 4
+
+#if defined(RTEMS_SMP)
+#define CONFIGURE_SCHEDULER_EDF_SMP
+#endif
+
+""" + _CONFIG_DEFAULT),
+    _Test(
+        "rtems",
+        "smp-part-2",
+        ["mem-smp-1"],
+        """a basic application configuration with
+${/acfg/if/max-processors:/name} defined to two using one SMP EDF scheduler
+for each configured processor (${/acfg/if/scheduler-edf-smp:/name})""",
+        None,
+        """/* Nothing to do */""",
+        """#define CONFIGURE_MAXIMUM_PROCESSORS 2
+
+#if defined(RTEMS_SMP)
+#define CONFIGURE_SCHEDULER_EDF_SMP
+
+#include <rtems/scheduler.h>
+
+RTEMS_SCHEDULER_EDF_SMP( a );
+
+RTEMS_SCHEDULER_EDF_SMP( b );
+
+#define NAME( x ) rtems_build_name( x, ' ', ' ', ' ' )
+
+#define CONFIGURE_SCHEDULER_TABLE_ENTRIES \\
+  RTEMS_SCHEDULER_TABLE_EDF_SMP( a, NAME( 'A' ) ), \\
+  RTEMS_SCHEDULER_TABLE_EDF_SMP( b, NAME( 'B' ) )
+
+#define CONFIGURE_SCHEDULER_ASSIGNMENTS \\
+  RTEMS_SCHEDULER_ASSIGN( 0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY ), \\
+  RTEMS_SCHEDULER_ASSIGN( 1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY )
+#endif
+
+""" + _CONFIG_DEFAULT),
+    _Test(
+        "rtems",
+        "smp-part-4",
+        ["mem-smp-1"],
+        """a basic application configuration with
+${/acfg/if/max-processors:/name} defined to four using one SMP EDF scheduler
+for each configured processor (${/acfg/if/scheduler-edf-smp:/name})""",
+        None,
+        """/* Nothing to do */""",
+        """#define CONFIGURE_MAXIMUM_PROCESSORS 4
+
+#if defined(RTEMS_SMP)
+#define CONFIGURE_SCHEDULER_EDF_SMP
+
+#include <rtems/scheduler.h>
+
+RTEMS_SCHEDULER_EDF_SMP( a );
+
+RTEMS_SCHEDULER_EDF_SMP( b );
+
+RTEMS_SCHEDULER_EDF_SMP( c );
+
+RTEMS_SCHEDULER_EDF_SMP( d );
+
+#define NAME( x ) rtems_build_name( x, ' ', ' ', ' ' )
+
+#define CONFIGURE_SCHEDULER_TABLE_ENTRIES \\
+  RTEMS_SCHEDULER_TABLE_EDF_SMP( a, NAME( 'A' ) ), \\
+  RTEMS_SCHEDULER_TABLE_EDF_SMP( b, NAME( 'B' ) ), \\
+  RTEMS_SCHEDULER_TABLE_EDF_SMP( c, NAME( 'C' ) ), \\
+  RTEMS_SCHEDULER_TABLE_EDF_SMP( d, NAME( 'D' ) )
+
+#define CONFIGURE_SCHEDULER_ASSIGNMENTS \\
+  RTEMS_SCHEDULER_ASSIGN( 0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY ), \\
+  RTEMS_SCHEDULER_ASSIGN( 1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY ), \\
+  RTEMS_SCHEDULER_ASSIGN( 2, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY ), \\
+  RTEMS_SCHEDULER_ASSIGN( 3, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY )
+#endif
+
+""" + _CONFIG_DEFAULT),
+    _Test(
+        "dev/clock",
+        "driver",
+        ["/rtems/req/mem-basic"],
+        """"a basic application configuration with the clock driver enabled
+(${/acfg/if/appl-needs-clock-driver:/name})""",
+        None,
+        """/* Nothing to do */""",
+        _CONFIG_DEFAULT.replace(
+            "CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER",
+            "CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER")),
+    _Test(
+        "rtems/barrier",
+        "wait-rel",
+        _LINKS_BASIC,
+        """a basic application configuration with
+${/acfg/if/max-barriers:/name} defined to one and calls to
+${../if/create:/name}, ${../if/wait:/name}, and ${../if/release:/name}""",
+        None,
+        """(void) rtems_barrier_create( 0, 0, 0, NULL );
+(void) rtems_barrier_wait( 0, 0 );
+(void) rtems_barrier_release( 0, NULL );""",
+        """#define CONFIGURE_MAXIMUM_BARRIERS 1
+
+""" + _CONFIG_DEFAULT),
+    _Test(
+        "rtems/barrier",
+        "wait-rel-del",
+        _LINKS_BASIC,
+        """a basic application configuration
+with ${/acfg/if/max-barriers:/name} defined to one and calls to
+${../if/create:/name}, ${../if/wait:/name}, ${../if/release:/name}, and
+${../if/delete:/name}""",
+        None,
+        """(void) rtems_barrier_create( 0, 0, 0, NULL );
+(void) rtems_barrier_wait( 0, 0 );
+(void) rtems_barrier_release( 0, NULL );
+(void) rtems_barrier_delete( 0 );""",
+        """#define CONFIGURE_MAXIMUM_BARRIERS 1
+
+""" + _CONFIG_DEFAULT),
+    _Test(
+        "rtems/event",
+        "snd-rcv",
+        _LINKS_BASIC,
+        """a basic application configuration with calls to ${../if/send:/name}
+and ${../if/receive:/name}""",
+        None,
+        """(void) rtems_event_send( 0, 0 );
+(void) rtems_event_receive( 0, 0, 0, NULL );""",
+        _CONFIG_DEFAULT),
+    _Test(
+        "rtems/fatal",
+        "fatal",
+        _LINKS_BASIC,
+        """a basic application configuration with a call to
+${../if/fatal:/name}""",
+        None,
+        "rtems_fatal( 0, 0 );",
+        _CONFIG_DEFAULT),
+    _Test(
+        "rtems/part",
+        "get-ret",
+        _LINKS_BASIC,
+        """a basic application configuration with
+${/acfg/if/max-partitions:/name} defined to one and calls to
+${../if/create:/name}, ${../if/get-buffer:/name}, and
+${../if/return-buffer:/name}""",
+        None,
+        """(void) rtems_partition_create( 0, NULL, 0, 0, 0, NULL );
+(void) rtems_partition_get_buffer( 0, NULL );
+(void) rtems_partition_return_buffer( 0, NULL );""",
+        """#define CONFIGURE_MAXIMUM_PARTITIONS 1
+
+""" + _CONFIG_DEFAULT),
+    _Test(
+        "rtems/part",
+        "get-ret-del",
+        _LINKS_BASIC,
+        """a basic application configuration with
+${/acfg/if/max-partitions:/name} defined to one and calls to
+${../if/create:/name}, ${../if/get-buffer:/name}, ${../if/return-buffer:/name},
+and ${../if/delete:/name}""",
+        None,
+        """(void) rtems_partition_create( 0, NULL, 0, 0, 0, NULL );
+(void) rtems_partition_get_buffer( 0, NULL );
+(void) rtems_partition_return_buffer( 0, NULL );
+(void) rtems_partition_delete( 0 );""",
+        """#define CONFIGURE_MAXIMUM_PARTITIONS 1
+
+""" + _CONFIG_DEFAULT),
+    _Test(
+        "rtems/ratemon",
+        "period",
+        _LINKS_BASIC,
+        """a basic application configuration with
+${/acfg/if/max-periods:/name} defined to one and calls to
+${../if/create:/name} and ${../if/period:/name}""",
+        None,
+        """(void) rtems_rate_monotonic_create( 0, NULL );
+(void) rtems_rate_monotonic_period( 0, 0 );""",
+        """#define CONFIGURE_MAXIMUM_PERIODS 1
+
+""" + _CONFIG_DEFAULT),
+    _Test(
+        "rtems/ratemon",
+        "period-del",
+        _LINKS_BASIC,
+        """a basic application configuration with
+${/acfg/if/max-periods:/name} defined to one and calls to
+${../if/create:/name}, ${../if/period:/name}, and
+${../if/delete:/name}""",
+        None,
+        """(void) rtems_rate_monotonic_create( 0, NULL );
+(void) rtems_rate_monotonic_period( 0, 0 );
+(void) rtems_rate_monotonic_delete( 0 );""",
+        """#define CONFIGURE_MAXIMUM_PERIODS 1
+
+""" + _CONFIG_DEFAULT),
+    _Test(
+        "rtems/sem",
+        "obt-rel",
+        _LINKS_BASIC,
+        """a basic application configuration with
+${/acfg/if/max-semaphores:/name} defined to one and calls to
+${../if/create:/name}, ${../if/obtain:/name}, and ${../if/release:/name}""",
+        None,
+        """(void) rtems_semaphore_create( 0, 0, 0, 0, NULL );
+(void) rtems_semaphore_obtain( 0, 0, 0 );
+(void) rtems_semaphore_release( 0 );""",
+        """#define CONFIGURE_MAXIMUM_SEMAPHORES 1
+
+""" + _CONFIG_DEFAULT),
+    _Test(
+        "rtems/sem",
+        "obt-rel-del",
+        _LINKS_BASIC,
+        """a basic application configuration with
+${/acfg/if/max-semaphores:/name} defined to one and calls to
+${../if/create:/name}, ${../if/obtain:/name}, ${../if/release:/name}, and
+${../if/delete:/name}""",
+        None,
+        """(void) rtems_semaphore_create( 0, 0, 0, 0, NULL );
+(void) rtems_semaphore_obtain( 0, 0, 0 );
+(void) rtems_semaphore_release( 0 );
+(void) rtems_semaphore_delete( 0 );""",
+        """#define CONFIGURE_MAXIMUM_SEMAPHORES 1
+
+""" + _CONFIG_DEFAULT),
+    _Test(
+        "rtems/signal",
+        "catch-snd",
+        _LINKS_BASIC,
+        """a basic application configuration with calls to ${../if/catch:/name}
+and ${../if/send:/name}""",
+        None,
+        """(void) rtems_signal_catch( NULL, 0 );
+(void) rtems_signal_send( 0, 0 );""",
+        _CONFIG_DEFAULT),
+    _Test(
+        "rtems/task",
+        "del",
+        _LINKS_BASIC,
+        """a basic application configuration with a
+call to ${../if/delete:/name}""",
+        None,
+        """(void) rtems_task_delete( 0 );
+""",
+        _CONFIG_DEFAULT),
+    _Test(
+        "rtems/task",
+        "exit",
+        _LINKS_BASIC,
+        """a basic application configuration with a
+call to ${../if/exit:/name}""",
+        None,
+        """rtems_task_exit();
+""",
+        _CONFIG_DEFAULT),
+    _Test(
+        "rtems/task",
+        "restart",
+        _LINKS_BASIC,
+        """a basic application configuration with a
+call to ${../if/restart:/name}""",
+        None,
+        """(void) rtems_task_restart( 0, 0 );
+""",
+        _CONFIG_DEFAULT),
+    _Test(
+        "rtems/task",
+        "sus-res",
+        _LINKS_BASIC,
+        """a basic application configuration with
+calls to ${../if/suspend:/name} and ${../if/resume:/name}""",
+        None,
+        """(void) rtems_task_suspend( 0 );
+(void) rtems_task_resume( 0 );
+""",
+        _CONFIG_DEFAULT),
+]  # yapf: disable
+
+
+def _indent(lines: str, level: int = 2) -> str:
+    space = " " * level
+    return lines.replace("\n", f"\n{space}").replace(f"\n{space}\n", "\n\n")
+
+
+def _text(lines: str, level: int = 2) -> str:
+    wrapper = textwrap.TextWrapper()
+    wrapper.break_long_words = False
+    wrapper.break_on_hyphens = False
+    wrapper.width = 79 - level
+    return _indent("\n".join(wrapper.wrap(lines)), level)
+
+
+def _block(lines: Optional[str], level: int = 2) -> str:
+    if lines:
+        return f"""|
+  {_text(lines, level)}"""
+    return "null"
+
+
+def _links(links: List[str]) -> str:
+    text = []  # type: List[str]
+    for link in links:
+        text.append(f"""- role: requirement-refinement
+  uid: {link}""")
+    return "\n".join(text)
+
+
+def _generate_files() -> None:
+    for test in _TESTS:
+        module = os.path.basename(test.path)
+        base = f"testsuites/membench/mem-{module}-{test.name}"
+        source = f"{base}.c"
+        build_spec = f"modules/rtems/spec/build/{base}.yml"
+        with open(build_spec, "w") as out:
+            out.write(f"""SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+build-type: test-program
+cflags: []
+copyrights:
+- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
+cppflags: []
+cxxflags: []
+enabled-by: true
+features: c cprogram
+includes: []
+ldflags: []
+links: []
+source:
+- {source}
+stlib: []
+target: {base}.norun.exe
+type: build
+use-after: []
+use-before: []
+""")
+        req_spec = f"/{test.path}/req/mem-{test.name}"
+        text = _text(f"{_TEXT} {test.topic}.")
+        with open(f"spec{req_spec}.yml", "w") as out:
+            out.write(f"""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:
+{_links(test.links)}
+non-functional-type: quality
+rationale: null
+references: []
+requirement-type: non-functional
+text: |
+  {text}
+type: requirement
+""")
+        val_spec = f"spec/{test.path}/val/mem-{test.name}.yml"
+        brief = _text(f"{_TEST} {test.topic}.")
+        with open(val_spec, "w") as out:
+            out.write(f"""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: validation
+  uid: ../req/mem-{test.name}
+test-brief: |
+  {brief}
+test-code: |
+  static void Init( rtems_task_argument arg )
+  {{
+    (void) arg;
+
+    {_indent(test.init, 4)}
+  }}
+
+  {_indent(test.config)}
+
+  #define CONFIGURE_INIT
+
+  #include <rtems/confdefs.h>
+test-description: {_block(test.desc)}
+test-includes:
+- rtems.h
+test-local-includes: []
+test-target: {source}
+type: test-suite
+""")
+
+
+def _post_process(path: str) -> None:
+    config = load_config("config.yml")
+    item_cache = ItemCache(config["spec"])
+    root = item_cache["/rtems/req/mem-basic"]
+    content = SphinxContent()
+    table_pivots = ["/rtems/req/mem-basic", "/rtems/req/mem-smp-1"]
+    generate(content, root, SphinxMapper(root), table_pivots, path)
+    print(content)
+
+
+def main() -> None:
+    """ Generates memory benchmarks. """
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        '--log-level',
+        choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
+        type=str.upper,
+        default="ERROR",
+        help="log level")
+    parser.add_argument('--log-file',
+                        type=str,
+                        default=None,
+                        help="log to this file")
+    parser.add_argument('--post-process', help="post-process the ELF files")
+    args = parser.parse_args(sys.argv[1:])
+    logging.basicConfig(filename=args.log_file, level=args.log_level)
+    if args.post_process:
+        _post_process(args.post_process)
+    else:
+        _generate_files()
+
+
+if __name__ == "__main__":
+    main()



More information about the vc mailing list