From b2ec2b8f78c52cefea87b20705e1fab02a4eee94 Mon Sep 17 00:00:00 2001 From: vishwaksen-1 Date: Thu, 19 Mar 2026 23:55:11 +0530 Subject: [PATCH] Add benchmarking support for OpenRISC Cores - Update .gitignore to include build and log directories - Fix argument parsing in benchmark_speed.py - Refactor libwikisort.c to use standard boolean types - Add fusesoc configuration for OpenRISC libraries - Implement board support files for mor1kx and maroccino - Introduce run_mor1kx.py for target-specific command execution --- .gitignore | 6 +- benchmark_speed.py | 2 +- examples/openrisc/fusesoc.conf | 36 +++++ examples/openrisc/maroccino/README.md | 22 +++ examples/openrisc/maroccino/boardsupport.c | 41 ++++++ examples/openrisc/maroccino/boardsupport.h | 3 + examples/openrisc/maroccino/linker.ld | 86 +++++++++++ examples/openrisc/mor1kx/README.md | 22 +++ examples/openrisc/mor1kx/boardsupport.c | 43 ++++++ examples/openrisc/mor1kx/boardsupport.h | 3 + examples/openrisc/mor1kx/linker.ld | 86 +++++++++++ pylib/run_mor1kx.py | 162 +++++++++++++++++++++ src/wikisort/libwikisort.c | 8 +- 13 files changed, 512 insertions(+), 8 deletions(-) create mode 100644 examples/openrisc/fusesoc.conf create mode 100644 examples/openrisc/maroccino/README.md create mode 100644 examples/openrisc/maroccino/boardsupport.c create mode 100644 examples/openrisc/maroccino/boardsupport.h create mode 100644 examples/openrisc/maroccino/linker.ld create mode 100644 examples/openrisc/mor1kx/README.md create mode 100644 examples/openrisc/mor1kx/boardsupport.c create mode 100644 examples/openrisc/mor1kx/boardsupport.h create mode 100644 examples/openrisc/mor1kx/linker.ld create mode 100644 pylib/run_mor1kx.py diff --git a/.gitignore b/.gitignore index c90f97ac..48b3c0c3 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,8 @@ __pycache__/ # Default build and log directories bd*/ -logs/ +logs*/ +build/ + +# generated fusesoc libraries +fusesoc_libraries/ diff --git a/benchmark_speed.py b/benchmark_speed.py index be9f5cea..163fdb4d 100755 --- a/benchmark_speed.py +++ b/benchmark_speed.py @@ -359,7 +359,7 @@ def collect_data(benchmarks, args): # Baseline data is held external to the script. Import it here if we are # doing relative output and then generate the relative data if not gp['absolute']: - rel_data = compute_rel(benchmarks, raw_data, args) + rel_data = compute_rel(benchmarks_run, raw_data, args) else: rel_data = {} diff --git a/examples/openrisc/fusesoc.conf b/examples/openrisc/fusesoc.conf new file mode 100644 index 00000000..ec3d89f3 --- /dev/null +++ b/examples/openrisc/fusesoc.conf @@ -0,0 +1,36 @@ +[library.fusesoc-cores] +location = fusesoc_libraries/fusesoc-cores +sync-uri = https://github.com/fusesoc/fusesoc-cores +sync-type = git +auto-sync = true + +[library.intgen] +location = fusesoc_libraries/intgen +sync-uri = https://github.com/stffrdhrn/intgen.git +sync-type = git +auto-sync = true + +[library.elf-loader] +location = fusesoc_libraries/elf-loader +sync-uri = https://github.com/fusesoc/elf-loader.git +sync-type = git +auto-sync = true + +[library.mor1kx-generic] +location = fusesoc_libraries/mor1kx-generic +sync-uri = https://github.com/stffrdhrn/mor1kx-generic.git +sync-type = git +auto-sync = true + +[library.or1k_marocchino] +location = fusesoc_libraries/or1k_marocchino +sync-uri = https://github.com/openrisc/or1k_marocchino.git +sync-type = git +auto-sync = true + +[library.mor1kx] +location = fusesoc_libraries/mor1kx +sync-uri = https://github.com/openrisc/mor1kx.git +sync-type = git +auto-sync = true + diff --git a/examples/openrisc/maroccino/README.md b/examples/openrisc/maroccino/README.md new file mode 100644 index 00000000..d93505d6 --- /dev/null +++ b/examples/openrisc/maroccino/README.md @@ -0,0 +1,22 @@ +build command + +```bash +scons --build-dir=bdMaroccino --config-dir=examples/openrisc/maroccino/ user_libs=-lm \ + cc=or1k-elf-gcc \ + cflags='-c -O3 -fdata-sections -ffunction-sections -mcmov -mhard-float -mror -mrori -msext -msfimm -mshftimm -munordered-float' \ + ldflags='-O3 -Wl,-gc-sections' +``` + +make sure or1k-elf-gcc is in your PATH, or change the cc variable to point to the correct location of the compiler. + +[TODO] Linker is faulty. `linker.ld` includes `generated/output_format.ld` and `generated/regions.ld`, so those files must exist under the selected `--config-dir`-- written by 2024 student. + +Command to for benchmark_size +```bash +python benchmark_size.py --builddir bdMaroccino/ --logdir logsMaroccino --baselinedir baseline-data/ +``` + +Command for speed results +```bash +python benchmark_speed.py --builddir bdMaroccino/ --logdir logsMaroccino --baselinedir baseline-data/ --target-module run_mor1kx --cpu-mhz 1 --timeout 600 --config-path examples/openrisc/fusesoc.conf --tool verilator --system ::mor1kx-generic:1.1 --fusesoc_target marocchino_tb +``` \ No newline at end of file diff --git a/examples/openrisc/maroccino/boardsupport.c b/examples/openrisc/maroccino/boardsupport.c new file mode 100644 index 00000000..abd87fac --- /dev/null +++ b/examples/openrisc/maroccino/boardsupport.c @@ -0,0 +1,41 @@ + +#include +#include +#include +#include +#include +#include + +#define BOARD_CPU_HZ 1000000UL + +uint32_t _or1k_board_uart_base = 0x90000000; +uint32_t _or1k_board_uart_baud = 9600; +uint32_t _or1k_board_clk_freq = BOARD_CPU_HZ; + +static volatile uint32_t start = 0; +static volatile uint32_t end = 0; + +void +initialise_board () +{ + or1k_timer_init (BOARD_CPU_HZ); + /* TTMR[M]=0b11, continuous mode. */ + or1k_timer_set_mode (3u); +} + +void __attribute__ ((noinline)) __attribute__ ((externally_visible)) +start_trigger () +{ + or1k_timer_enable (); + start = or1k_mfspr (OR1K_SPR_TICK_TTCR_ADDR); +} + +void __attribute__ ((noinline)) __attribute__ ((externally_visible)) +stop_trigger () +{ + uint32_t elapsed; + + end = or1k_mfspr (OR1K_SPR_TICK_TTCR_ADDR); + elapsed = end - start; + printf ("End time %" PRIu32 "\n", elapsed); +} diff --git a/examples/openrisc/maroccino/boardsupport.h b/examples/openrisc/maroccino/boardsupport.h new file mode 100644 index 00000000..30cb66fc --- /dev/null +++ b/examples/openrisc/maroccino/boardsupport.h @@ -0,0 +1,3 @@ + + +#define CPU_MHZ 1 diff --git a/examples/openrisc/maroccino/linker.ld b/examples/openrisc/maroccino/linker.ld new file mode 100644 index 00000000..d07ebcd2 --- /dev/null +++ b/examples/openrisc/maroccino/linker.ld @@ -0,0 +1,86 @@ +INCLUDE generated/output_format.ld +INCLUDE generated/regions.ld + +ENTRY(_start) + + +SECTIONS +{ + .text : + { + _ftext = .; + /* Make sure crt0 files come first, and they, and the isr */ + /* don't get disposed of by greedy optimisation */ + *crt0*(.text) + KEEP(*crt0*(.text)) + KEEP(*(.text.isr)) + + *(.text .stub .text.* .gnu.linkonce.t.*) + _etext = .; + } > main_ram + + .rodata : ALIGN(8) + { + _frodata = .; + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.rodata1) + *(.got .got.*) + *(.toc .toc.*) + + /* Make sure the file is aligned on disk as well + as in memory; CRC calculation requires that. */ + FILL(0); + . = ALIGN(8); + _erodata = .; + } > main_ram + + .commands : ALIGN(8) + { + PROVIDE_HIDDEN (__bios_cmd_start = .); + KEEP(*(.bios_cmd)) + PROVIDE_HIDDEN (__bios_cmd_end = .); + } > main_ram + + .data : ALIGN(8) + { + _fdata = .; + *(.data .data.* .gnu.linkonce.d.*) + *(.data1) + *(.sdata .sdata.* .gnu.linkonce.s.*) + + /* Make sure the file is aligned on disk as well + as in memory; CRC calculation requires that. */ + FILL(0); + . = ALIGN(8); + _edata = .; + } > main_ram + + .bss : ALIGN(8) SUBALIGN(8) + { + _fbss = .; + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(8); + _ebss = .; + _end = .; + } > main_ram + . = ALIGN(8); + PROVIDE(__heap_start = . ); + + /DISCARD/ : + { + *(.eh_frame) + *(.comment) + } +} + +PROVIDE(__heap_end = ORIGIN(main_ram) + LENGTH(main_ram)); + +PROVIDE(_fstack = ORIGIN(sram) + LENGTH(sram)); + +PROVIDE(_fdata_rom = LOADADDR(.data)); +PROVIDE(_edata_rom = LOADADDR(.data) + SIZEOF(.data)); diff --git a/examples/openrisc/mor1kx/README.md b/examples/openrisc/mor1kx/README.md new file mode 100644 index 00000000..91950774 --- /dev/null +++ b/examples/openrisc/mor1kx/README.md @@ -0,0 +1,22 @@ +Command to build the benchmarks for the mor1kx configuration: + +```bash +scons --build-dir=bdMor1kx --config-dir=examples/openrisc/mor1kx/ user_libs=-lm \ + cc=or1k-elf-gcc \ + cflags='-c -O3 -fdata-sections -ffunction-sections -mcmov -mhard-float -mror -mrori -msext -msfimm -mshftimm -munordered-float' \ + ldflags='-O3 -Wl,-gc-sections' +``` + +make sure or1k-elf-gcc is in your PATH, or change the cc variable to point to the correct location of the compiler. + +[TODO] Linker is faulty. `linker.ld` includes `generated/output_format.ld` and `generated/regions.ld`, so those files must exist under the selected `--config-dir`-- written by 2024 student. + +Command to for benchmark_size +```bash +python benchmark_size.py --builddir bdMor1kx/ --logdir logsMor1kx --baselinedir baseline-data/ +``` + +command for speed results +```bash +python benchmark_speed.py --builddir bdMor1kx/ --logdir logsMor1kx --baselinedir baseline-data/ --target-module run_mor1kx --cpu-mhz 1 --timeout 600 --config-path examples/openrisc/fusesoc.conf --tool verilator --system ::mor1kx-generic:1.1 --fusesoc_target mor1kx_tb +``` \ No newline at end of file diff --git a/examples/openrisc/mor1kx/boardsupport.c b/examples/openrisc/mor1kx/boardsupport.c new file mode 100644 index 00000000..d53b1b75 --- /dev/null +++ b/examples/openrisc/mor1kx/boardsupport.c @@ -0,0 +1,43 @@ + + +#include +#include +#include +#include +#include +#include + +#define BOARD_CPU_HZ 1000000UL + +uint32_t _or1k_board_uart_base = 0x90000000; +uint32_t _or1k_board_uart_baud = 9600; +uint32_t _or1k_board_clk_freq = BOARD_CPU_HZ; + + +static volatile uint32_t start = 0; +static volatile uint32_t end = 0; + +void +initialise_board () +{ + or1k_timer_init (BOARD_CPU_HZ); + /* TTMR[M]=0b11, continuous mode. */ + or1k_timer_set_mode (3u); +} + +void __attribute__ ((noinline)) __attribute__ ((externally_visible)) +start_trigger () +{ + or1k_timer_enable (); + start = or1k_mfspr (OR1K_SPR_TICK_TTCR_ADDR); +} + +void __attribute__ ((noinline)) __attribute__ ((externally_visible)) +stop_trigger () +{ + uint32_t elapsed; + + end = or1k_mfspr (OR1K_SPR_TICK_TTCR_ADDR); + elapsed = end - start; + printf ("End time %" PRIu32 "\n", elapsed); +} \ No newline at end of file diff --git a/examples/openrisc/mor1kx/boardsupport.h b/examples/openrisc/mor1kx/boardsupport.h new file mode 100644 index 00000000..a7ea198e --- /dev/null +++ b/examples/openrisc/mor1kx/boardsupport.h @@ -0,0 +1,3 @@ + + +#define CPU_MHZ 1 \ No newline at end of file diff --git a/examples/openrisc/mor1kx/linker.ld b/examples/openrisc/mor1kx/linker.ld new file mode 100644 index 00000000..362516a4 --- /dev/null +++ b/examples/openrisc/mor1kx/linker.ld @@ -0,0 +1,86 @@ +INCLUDE generated/output_format.ld +INCLUDE generated/regions.ld + +ENTRY(_start) + + +SECTIONS +{ + .text : + { + _ftext = .; + /* Make sure crt0 files come first, and they, and the isr */ + /* don't get disposed of by greedy optimisation */ + *crt0*(.text) + KEEP(*crt0*(.text)) + KEEP(*(.text.isr)) + + *(.text .stub .text.* .gnu.linkonce.t.*) + _etext = .; + } > main_ram + + .rodata : ALIGN(8) + { + _frodata = .; + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.rodata1) + *(.got .got.*) + *(.toc .toc.*) + + /* Make sure the file is aligned on disk as well + as in memory; CRC calculation requires that. */ + FILL(0); + . = ALIGN(8); + _erodata = .; + } > main_ram + + .commands : ALIGN(8) + { + PROVIDE_HIDDEN (__bios_cmd_start = .); + KEEP(*(.bios_cmd)) + PROVIDE_HIDDEN (__bios_cmd_end = .); + } > main_ram + + .data : ALIGN(8) + { + _fdata = .; + *(.data .data.* .gnu.linkonce.d.*) + *(.data1) + *(.sdata .sdata.* .gnu.linkonce.s.*) + + /* Make sure the file is aligned on disk as well + as in memory; CRC calculation requires that. */ + FILL(0); + . = ALIGN(8); + _edata = .; + } > main_ram + + .bss : ALIGN(8) SUBALIGN(8) + { + _fbss = .; + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(8); + _ebss = .; + _end = .; + } > main_ram + . = ALIGN(8); + PROVIDE(__heap_start = . ); + + /DISCARD/ : + { + *(.eh_frame) + *(.comment) + } +} + +PROVIDE(__heap_end = ORIGIN(main_ram) + LENGTH(main_ram)); + +PROVIDE(_fstack = ORIGIN(sram) + LENGTH(sram)); + +PROVIDE(_fdata_rom = LOADADDR(.data)); +PROVIDE(_edata_rom = LOADADDR(.data) + SIZEOF(.data)); \ No newline at end of file diff --git a/pylib/run_mor1kx.py b/pylib/run_mor1kx.py new file mode 100644 index 00000000..cbf48b36 --- /dev/null +++ b/pylib/run_mor1kx.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python3 + +""" +Target runner for OpenRISC benchmarks via FuseSoC. + +This module is loaded by benchmark_speed.py and provides: +- target-specific CLI argument parsing +- command construction for FuseSoC simulation runs +- result decoding from simulator output +""" + +__all__ = [ + 'get_target_args', + 'build_benchmark_cmd', + 'decode_results', + 'run_benchmark', +] + +import argparse +import subprocess +import re +import os + +from embench_core import log + +cpu_mhz = 1 + +# Default config path computed relative to this file +_DEFAULT_CONFIG = os.path.abspath( + os.path.join(os.path.dirname(__file__), + '..', 'examples', 'openrisc', 'fusesoc.conf') +) + +def get_target_args(remnant): + """Parse target-specific command-line arguments.""" + parser = argparse.ArgumentParser(description='Get target specific args') + + + parser.add_argument( + '--config-path', + type=str, + default=_DEFAULT_CONFIG, + help='path to fusesoc.conf.' + ) + + parser.add_argument( + '--target', + type=str, + default='mor1kx_tb', + help='target to test' + ) + + parser.add_argument( + '--tool', + type=str, + default='verilator', + help='tool to use (verilator highly recommended)' + ) + + parser.add_argument( + '--system', + type=str, + default='::mor1kx-generic:1.1', + help='soc to test' + ) + + parser.add_argument( + '--fusesoc_target', + type=str, + default='mor1kx_tb', + help='soc to test' + ) + + parser.add_argument( + '--ext_args', + type=str, + default='', + help='extra args to pass after all other arguments (i.e. to turn on tracing)' + ) + + return parser.parse_args(remnant) + + +def build_benchmark_cmd(path, args): + """Build the FuseSoC command used to run one benchmark executable.""" + + out = [ + 'fusesoc', '--config', args.config_path, 'run', '--target', + args.fusesoc_target, '--tool', args.tool, args.system, '--elf_load', + path + ] + + return out + + +def decode_results(stdout_str, stderr_str): + """Decode simulator output and return elapsed time in milliseconds. + + Returns 0.0 when the run does not indicate successful completion or when + timing data cannot be found. + """ + + global cpu_mhz + + combined_output = stdout_str + stderr_str + + log.info(stdout_str) + rcstr = re.search(r'Success! Got NOP_EXIT', combined_output, re.S) + if not rcstr: + log.debug('Warning: Failed to find return code') + return 0.0 + + time = re.search(r'End time\s+([0-9A-Fa-fx]+)', combined_output, re.S) + if time: + time_value = time.group(1) + base = 16 if re.search(r'[A-Fa-fx]', time_value) else 10 + ms_elapsed = int(time_value, base) / cpu_mhz / 1000.0 + return max(float(ms_elapsed), 0.001) + + exit_cycles = re.search(r'NOP_EXIT\. Exiting \(([0-9A-Fa-fx]+)\)', + combined_output, re.S) + if exit_cycles: + cycle_value = exit_cycles.group(1) + base = 16 if re.search(r'[A-Fa-fx]', cycle_value) else 10 + ms_elapsed = int(cycle_value, base) / cpu_mhz / 1000.0 + return max(float(ms_elapsed), 0.001) + + log.debug('Warning: Failed to find timing') + return 0.0 + + +def run_benchmark(bench, path, args): + """Run one benchmark executable and return elapsed time in milliseconds. + + Returns None when the process times out or exits with a non-zero code. + """ + global cpu_mhz + cpu_mhz = args.cpu_mhz + + arglist = build_benchmark_cmd(path, args) + try: + res = subprocess.run( + arglist, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + timeout=args.timeout, + ) + except subprocess.TimeoutExpired: + log.warning(f'Warning: Run of {bench} timed out.') + return None + + if res.returncode != 0: + log.warning(f'Warning: Run of {bench} failed with return code {res.returncode}.') + stdout_tail = res.stdout.decode('utf-8', errors='replace')[-800:] + stderr_tail = res.stderr.decode('utf-8', errors='replace')[-800:] + if stderr_tail.strip(): + log.warning(f'Warning: stderr tail for {bench}:\n{stderr_tail}') + elif stdout_tail.strip(): + log.warning(f'Warning: stdout tail for {bench}:\n{stdout_tail}') + return None + + return decode_results(res.stdout.decode('utf-8'), res.stderr.decode('utf-8')) \ No newline at end of file diff --git a/src/wikisort/libwikisort.c b/src/wikisort/libwikisort.c index 6427ec1b..5917e586 100644 --- a/src/wikisort/libwikisort.c +++ b/src/wikisort/libwikisort.c @@ -28,13 +28,9 @@ #include #include #include +#include -/* various #defines for the C code */ -#ifndef true -#define true 1 -#define false 0 -typedef uint8_t bool; -#endif +/* bool/true/false come from */ #define Var(name, value, type) type name = value