summaryrefslogblamecommitdiffstats
path: root/generate_membench.py
blob: 62573eafe72bc80acb55dcafa98c55d876d6af7d (plain) (tree)

































                                                                             
                                           









































                                                                       







                                                         
























                                                                           
                       








































































































                                                                             


                                                      
                                                                          






                                                               



























                                                          









































                                                                              
                                           





                                                           
















































                                                              


























































                                                                               

                          
                                                   







                                                        
                                                   





                                                           








































                                                                               
                 



                                                   
                                         







                                                   
                             







                                                   
                                             








                                                             





































































































                                                          
                         





































                                                           















                                                              












































                                                                  

























                                                                            




                                


















































                                                                               
                                                           


























                                                                               
                                  
                     
                      




































                                                                            
#!/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.content import to_camel_case
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"""

_CONFIG_SMP_1 = """#define CONFIGURE_MAXIMUM_PROCESSORS 1

#if defined(RTEMS_SMP)
#define CONFIGURE_SCHEDULER_EDF_SMP
#endif

""" + _CONFIG_DEFAULT

_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 */""",
        _CONFIG_SMP_1),
    _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(
        "bsp",
        "clock",
        ["../if/group-clock", "/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/clock",
        "set",
        _LINKS_BASIC,
        """a basic application configuration with a
call to ${../if/set:/name}""",
        None,
        "(void) rtems_clock_set( NULL );",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/clock",
        "set-get-tod",
        _LINKS_BASIC,
        """a basic application configuration with calls to
${../if/set:/name} and ${../if/get-tod:/name}""",
        None,
        """(void) rtems_clock_set( NULL );
(void) rtems_clock_get_tod( NULL );""",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/clock",
        "get-uptime",
        _LINKS_BASIC,
        """a basic application configuration with a
call to ${../if/get-uptime:/name}""",
        None,
        "(void) rtems_clock_get_uptime( NULL );",
        _CONFIG_DEFAULT),
    _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",
        ["../../req/group"] + _LINKS_BASIC,
        """a basic application configuration with a call to
${../if/fatal:/name}""",
        None,
        "rtems_fatal( 0, 0 );",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/message",
        "snd-rcv",
        _LINKS_BASIC,
        """a basic application configuration with calls to
${../if/construct:/name}, ${../if/send:/name}, and
${../if/receive:/name}""",
        None,
        """(void) rtems_message_queue_construct( NULL, NULL );
(void) rtems_message_queue_send( 0, NULL, 0 );
(void) rtems_message_queue_receive( 0, NULL, NULL, 0, 0 );""",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/message",
        "ugt-rcv",
        _LINKS_BASIC,
        """a basic application configuration with calls to
${../if/construct:/name}, ${../if/urgent:/name}, and
${../if/receive:/name}""",
        None,
        """(void) rtems_message_queue_construct( NULL, NULL );
(void) rtems_message_queue_urgent( 0, NULL, 0 );
(void) rtems_message_queue_receive( 0, NULL, NULL, 0, 0 );""",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/message",
        "bcst-rcv",
        _LINKS_BASIC,
        """a basic application configuration with calls to
${../if/construct:/name}, ${../if/broadcast:/name}, and
${../if/receive:/name}""",
        None,
        """(void) rtems_message_queue_construct( NULL, NULL );
(void) rtems_message_queue_broadcast( 0, NULL, 0, NULL );
(void) rtems_message_queue_receive( 0, NULL, NULL, 0, 0 );""",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/message",
        "snd-rcv-del",
        _LINKS_BASIC,
        """a basic application configuration with calls to
${../if/construct:/name}, ${../if/send:/name},
${../if/receive:/name}, and ${../if/delete:/name}""",
        None,
        """(void) rtems_message_queue_construct( NULL, NULL );
(void) rtems_message_queue_send( 0, NULL, 0 );
(void) rtems_message_queue_receive( 0, NULL, NULL, 0, 0 );
(void) rtems_message_queue_delete( 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/scheduler",
        "add-cpu",
        ["../../req/group", "../../req/mem-smp-1"],
        """a basic application configuration with a
call to ${../if/add-processor:/name}""",
        None,
        "(void) rtems_scheduler_add_processor( 0, 0 );",
        _CONFIG_SMP_1),
    _Test(
        "rtems/scheduler",
        "rm-cpu",
        ["../../req/group", "../../req/mem-smp-1"],
        """a basic application configuration with a
call to ${../if/remove-processor:/name}""",
        None,
        "(void) rtems_scheduler_remove_processor( 0, 0 );",
        _CONFIG_SMP_1),
    _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",
        "delete",
        _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),
    _Test(
        "rtems/task",
        "set-priority",
        _LINKS_BASIC,
        """a basic application configuration with a
call to ${../if/set-priority:/name}""",
        None,
        "(void) rtems_task_set_priority( 0, 0, NULL );",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/task",
        "get-priority",
        _LINKS_BASIC,
        """a basic application configuration with a
call to ${../if/get-priority:/name}""",
        None,
        "(void) rtems_task_get_priority( 0, 0, NULL );",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/task",
        "mode",
        _LINKS_BASIC,
        """a basic application configuration with a
call to ${../if/mode:/name}""",
        None,
        "(void) rtems_task_mode( 0, 0, 0 );",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/task",
        "wake-after",
        _LINKS_BASIC,
        """a basic application configuration with a
call to ${../if/wake-after:/name}""",
        None,
        "(void) rtems_task_wake_after( 0 );",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/task",
        "wake-when",
        _LINKS_BASIC,
        """a basic application configuration with a
call to ${../if/wake-when:/name}""",
        None,
        "(void) rtems_task_wake_when( NULL );",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/task",
        "set-scheduler",
        _LINKS_BASIC,
        """a basic application configuration with a
call to ${../if/set-scheduler:/name}""",
        None,
        "(void) rtems_task_set_scheduler( 0, 0, 0 );",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/task",
        "get-scheduler",
        _LINKS_BASIC,
        """a basic application configuration with a
call to ${../if/get-scheduler:/name}""",
        None,
        "(void) rtems_task_get_scheduler( 0, NULL );",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/task",
        "set-affinity",
        _LINKS_BASIC,
        """a basic application configuration with a
call to ${../if/set-affinity:/name}""",
        None,
        "(void) rtems_task_set_affinity( 0, 0, NULL );",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/task",
        "get-affinity",
        _LINKS_BASIC,
        """a basic application configuration with a
call to ${../if/get-affinity:/name}""",
        None,
        "(void) rtems_task_get_affinity( 0, 0, NULL );",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/timer",
        "after",
        _LINKS_BASIC,
        """a basic application configuration with calls to
${../if/create:/name} and ${../if/fire-after:/name}""",
        None,
        """(void) rtems_timer_create( 0, NULL );
(void) rtems_timer_fire_after( 0, 0, NULL, NULL );""",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/timer",
        "when",
        _LINKS_BASIC,
        """a basic application configuration with calls to
${../if/create:/name} and ${../if/fire-when:/name}""",
        None,
        """(void) rtems_timer_create( 0, NULL );
(void) rtems_timer_fire_when( 0, NULL, NULL, NULL );""",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/timer",
        "cancel",
        _LINKS_BASIC,
        """a basic application configuration with calls to
${../if/create:/name} and ${../if/cancel:/name}""",
        None,
        """(void) rtems_timer_create( 0, NULL );
(void) rtems_timer_cancel( 0 );""",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/timer",
        "reset",
        _LINKS_BASIC,
        """a basic application configuration with calls to
${../if/create:/name} and ${../if/reset:/name}""",
        None,
        """(void) rtems_timer_create( 0, NULL );
(void) rtems_timer_reset( 0 );""",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/timer",
        "delete",
        _LINKS_BASIC,
        """a basic application configuration with calls to
${../if/create:/name} and ${../if/delete:/name}""",
        None,
        """(void) rtems_timer_create( 0, NULL );
(void) rtems_timer_delete( 0 );""",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/timer",
        "srv-init",
        _LINKS_BASIC,
        """a basic application configuration with a call to
${../if/initiate-server:/name}""",
        None,
        "(void) rtems_timer_initiate_server( 0, 0, 0 );",
        """static void *task_stack_allocate( size_t size )
{
  (void) size;
  return NULL;
}

static void task_stack_deallocate( void *stack )
{
  (void) stack;
}

#define CONFIGURE_TASK_STACK_ALLOCATOR task_stack_allocate

#define CONFIGURE_TASK_STACK_DEALLOCATOR task_stack_deallocate

""" + _CONFIG_DEFAULT),
    _Test(
        "rtems/timer",
        "srv-after",
        _LINKS_BASIC,
        """a basic application configuration with calls to
${../if/create:/name} and ${../if/server-fire-after:/name}""",
        None,
        """(void) rtems_timer_create( 0, NULL );
(void) rtems_timer_server_fire_after( 0, 0, NULL, NULL );""",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/timer",
        "srv-when",
        _LINKS_BASIC,
        """a basic application configuration with calls to
${../if/create:/name} and ${../if/server-fire-when:/name}""",
        None,
        """(void) rtems_timer_create( 0, NULL );
(void) rtems_timer_server_fire_when( 0, NULL, NULL, NULL );""",
        _CONFIG_DEFAULT),
    _Test(
        "rtems/userext",
        "create",
        _LINKS_BASIC,
        """a basic application configuration with
${/acfg/if/max-user-extensions:/name} defined to one and a call to
${../if/create:/name}""",
        None,
        "(void) rtems_extension_create( 0, NULL, NULL );",
        """#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1

""" + _CONFIG_DEFAULT),
    _Test(
        "rtems/userext",
        "delete",
        _LINKS_BASIC,
        """a basic application configuration with
${/acfg/if/max-user-extensions:/name} defined to one and calls to
${../if/create:/name} and ${../if/delete:/name}""",
        None,
        """(void) rtems_extension_create( 0, NULL, NULL );
(void) rtems_extension_delete( 0 );""",
        """#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1

""" + _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:
        if "group" in link:
            break
    else:
        links.insert(0, "group")
    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}.")
        test_suite_name = to_camel_case(f"Mem {test.name}")
        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-suite-name: {test_suite_name}
test-target: {source}
type: memory-benchmark
""")


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()