Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actionlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ self-hosted-runner:
- pqcp-x64
# RISE RISC-V runner
- ubuntu-24.04-riscv
- self-hosted-nucleo-n657x0
4 changes: 0 additions & 4 deletions .github/actions/bench/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,6 @@ runs:
--ldflags="${{ inputs.ldflags }}" \
--opt=$([[ ${{ inputs.opt }} == "false" ]] && echo "no_opt" || echo "opt") \
-v ${{ inputs.bench_extra_args }}
- name: Check namespace
shell: ${{ env.SHELL }}
run: |
check-namespace
- name: Store benchmark result
uses: benchmark-action/github-action-benchmark@52576c92bccf6ac60c8223ec7eb2565637cae9ba # v1.22.1
with:
Expand Down
28 changes: 28 additions & 0 deletions .github/workflows/bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ jobs:
bench_extra_args: ""
nix_shell: bench
only_no_opt: false
extra_makefile: ""
zephyr_target: ""
- system: rpi5
name: Arm Cortex-A76 (Raspberry Pi 5) benchmarks
bench_pmu: PERF
Expand All @@ -48,6 +50,8 @@ jobs:
nix_shell: bench
only_no_opt: false
cross_prefix: ""
extra_makefile: ""
zephyr_target: ""
- system: a55
name: Arm Cortex-A55 (Snapdragon 888) benchmarks
bench_pmu: PERF
Expand All @@ -57,6 +61,8 @@ jobs:
bench_extra_args: -w exec-on-a55
nix_shell: bench
only_no_opt: false
extra_makefile: ""
zephyr_target: ""
- system: bpi
name: SpacemiT K1 8 (Banana Pi F3) benchmarks
bench_pmu: PERF
Expand All @@ -67,6 +73,8 @@ jobs:
cross_prefix: riscv64-unknown-linux-gnu-
nix_shell: cross-riscv64
only_no_opt: true
extra_makefile: ""
zephyr_target: ""
- system: m1-mac-mini
name: Mac Mini (M1, 2020) benchmarks
bench_pmu: MAC
Expand All @@ -76,12 +84,29 @@ jobs:
bench_extra_args: "-r"
nix_shell: bench
only_no_opt: false
extra_makefile: ""
zephyr_target: ""
- system: nucleo-n657x0
name: Arm Cortex-M55 (NUCLEO-N657X0-Q) benchmarks
bench_pmu: NO
archflags: ""
cflags: ""
ldflags: ""
bench_extra_args: ""
nix_shell: zephyr
only_no_opt: false
cross_prefix: ""
extra_makefile: test/zephyr/platform.mk
zephyr_target: nucleo-n657x0-q
if: github.repository_owner == 'pq-code-package' && !github.event.pull_request.head.repo.fork && (github.event.label.name == 'benchmark' || github.ref == 'refs/heads/main')
runs-on: self-hosted-${{ matrix.target.system }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: ./.github/actions/bench
if: ${{ !matrix.target.only_no_opt }}
env:
EXTRA_MAKEFILE: ${{ matrix.target.extra_makefile }}
ZEPHYR_TARGET: ${{ matrix.target.zephyr_target }}
with:
name: ${{ matrix.target.name }} (opt)
cflags: ${{ matrix.target.cflags }}
Expand All @@ -95,6 +120,9 @@ jobs:
cross_prefix: ${{ matrix.target.cross_prefix }}
opt: true
- uses: ./.github/actions/bench
env:
EXTRA_MAKEFILE: ${{ matrix.target.extra_makefile }}
ZEPHYR_TARGET: ${{ matrix.target.zephyr_target }}
with:
name: ${{ matrix.target.name }} (no-opt)
cflags: ${{ matrix.target.cflags }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/zephyr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,5 @@ jobs:
ZEPHYR_TARGET: ${{ matrix.target.board }}
run: |
opt=${{ matrix.target.opt == 'all' && 'opt' || 'no_opt' }}
nix develop .#zephyr --command ./scripts/tests bench --no-auto -c PMU --opt=$opt
nix develop .#zephyr --command ./scripts/tests bench --no-auto --components -c PMU --opt=$opt
nix develop .#zephyr --command ./scripts/tests bench --no-auto -c NO --opt=$opt
nix develop .#zephyr --command ./scripts/tests bench --no-auto --components -c NO --opt=$opt
3 changes: 3 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,12 @@

# Zephyr build environment (board chosen at make time via EXTRA_MAKEFILE)
packages.zephyr = util.zephyr;
# OpenOCD with STM32N6 support, for the NUCLEO-N657X0-Q hardware target.
packages.openocd = util.openocd;
devShells.zephyr = util.mkShell {
packages = builtins.attrValues
{
inherit (config.packages) openocd;
inherit (util) zephyr;
inherit (pkgs) gcc-arm-embedded qemu cmake ninja dtc gperf coreutils git;
} ++ [ util.zephyrPythonEnv ];
Expand Down
22 changes: 22 additions & 0 deletions nix/openocd/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright (c) The mldsa-native project authors
# Copyright (c) The mlkem-native project authors
# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT

{ fetchFromGitHub
, openocd
, autoreconfHook
}:

openocd.overrideAttrs (old: rec {
pname = "openocd";
version = "unstable-2026-05-01";
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ autoreconfHook ];

src = fetchFromGitHub {
owner = "openocd-org";
repo = "openocd";
rev = "4e9b167e1ae5ccb437eb0538440988b3f0ec53cb";
fetchSubmodules = true;
hash = "sha256-8aYl7JzulPxH6vgSeTKTMIZVH6d55JJlXTBkfgAPTbU=";
};
})
1 change: 1 addition & 0 deletions nix/util.nix
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ rec {
hol_server = pkgs.callPackage ./hol_light/hol_server.nix { inherit hol_light'; };
s2n_bignum = pkgs.callPackage ./s2n_bignum { };
slothy = pkgs.callPackage ./slothy { };
openocd = pkgs.callPackage ./openocd { };
zephyr = pkgs.callPackage ./zephyr { };
zephyrPythonEnv = pkgs.python3.withPackages (ps: with ps; [
pyelftools
Expand Down
16 changes: 13 additions & 3 deletions nix/zephyr/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@

# Board-agnostic Zephyr build environment: a pinned Zephyr tree plus the
# modules needed by the boards we target, exposed via a setup hook so a plain
# `cmake` build works with no west workspace. CMSIS-6 covers the Cortex-M
# boards; add further modules here as more boards are wired up.
# `cmake` build works with no west workspace.
let
zephyr = fetchFromGitHub {
owner = "zephyrproject-rtos";
Expand All @@ -27,6 +26,14 @@ let
rev = "30a859f44ef8ab4dc8f84b03ed586fd16ccf9d74";
hash = "sha256-nTehISN0pu9gnOZMpGaBQ3DFmNxAqAZPGpvbKfEM35o=";
};

# Revision pinned by the Zephyr v4.4.1 manifest (west.yml).
hal_stm32 = fetchFromGitHub {
owner = "zephyrproject-rtos";
repo = "hal_stm32";
rev = "fc11896dd39cfca37bf9b4aeaaa2df8861b81875";
hash = "sha256-AtNq2yTZsTFMTlWn/Ns0wuEiN4Wv/OTV2vWPRu0SnOE=";
};
in
stdenvNoCC.mkDerivation {
pname = "mldsa-native-zephyr";
Expand All @@ -38,11 +45,14 @@ stdenvNoCC.mkDerivation {
mkdir -p $out
ln -s ${zephyr} $out/zephyr
ln -s ${cmsis_6} $out/cmsis_6
ln -s ${hal_stm32} $out/hal_stm32
'';

setupHook = writeText "setup-hook.sh" ''
export ZEPHYR_BASE="$1/zephyr"
export ZEPHYR_MODULES="$1/cmsis_6"
export ZEPHYR_CMSIS_6_MODULE="$1/cmsis_6"
export ZEPHYR_HAL_STM32_MODULE="$1/hal_stm32"
export ZEPHYR_MODULES="$1/cmsis_6;$1/hal_stm32"
export ZEPHYR_TOOLCHAIN_VARIANT=gnuarmemb
export GNUARMEMB_TOOLCHAIN_PATH=${gcc-arm-embedded}
'';
Expand Down
5 changes: 4 additions & 1 deletion scripts/tests
Original file line number Diff line number Diff line change
Expand Up @@ -782,8 +782,11 @@ class Tests:
test_type, self.do_opt(), suppress_output=False
)

if resultss is None:
# Nothing below should write benchmark output unless the run produced
# results and all compile/run steps succeeded.
if resultss is None or len(self.failed) > 0:
self.check_fail()
return

# NOTE: There will only be one items in resultss, as we haven't yet decided how to write both opt/no-opt benchmark results
for k, results in resultss.items():
Expand Down
13 changes: 9 additions & 4 deletions test/bench/bench_mldsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@

static int cmp_uint64_t(const void *a, const void *b)
{
return (int)((*((const uint64_t *)a)) - (*((const uint64_t *)b)));
const uint64_t va = *((const uint64_t *)a);
const uint64_t vb = *((const uint64_t *)b);

/* Avoid subtracting uint64_t values: qsort only needs the sign, and the
* difference may exceed int range after long benchmark runs. */
return (va > vb) - (va < vb);
}

static void print_avg(const char *txt, uint64_t cyc[MLD_BENCHMARK_NTESTS])
Expand All @@ -66,7 +71,7 @@ static void print_percentile_legend(void)
printf("%21s", "percentile");
for (i = 0; i < sizeof(percentiles) / sizeof(percentiles[0]); i++)
{
printf("%9d", percentiles[i]);
printf("%12d", percentiles[i]);
}
printf("\n");
}
Expand All @@ -78,8 +83,8 @@ static void print_percentiles(const char *txt,
printf("%10s percentiles:", txt);
for (i = 0; i < sizeof(percentiles) / sizeof(percentiles[0]); i++)
{
printf("%9" PRIu64, (cyc)[MLD_BENCHMARK_NTESTS * percentiles[i] / 100] /
MLD_BENCHMARK_NITERATIONS);
printf("%12" PRIu64, (cyc)[MLD_BENCHMARK_NTESTS * percentiles[i] / 100] /
MLD_BENCHMARK_NITERATIONS);
}
printf("\n");
}
Expand Down
4 changes: 2 additions & 2 deletions test/hal/hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@

void enable_cyclecounter(void) {}
void disable_cyclecounter(void) {}
uint64_t get_cyclecounter(void) { return k_cycle_get_32(); }
uint64_t get_cyclecounter(void) { return k_cycle_get_64(); }

#elif defined(PMU_CYCLES)

Expand Down Expand Up @@ -125,8 +125,8 @@ uint64_t get_cyclecounter(void) { return DWT->CYCCNT; }
#elif defined(ARMCM55)
/* Cortex-M55: Use dedicated PMU */
#include <ARMCM55.h>
#include <pmu_armv8.h>
#include <system_ARMCM55.h>
#include "pmu_armv8.h"

void enable_cyclecounter(void)
{
Expand Down
3 changes: 3 additions & 0 deletions test/mk/components.mk
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ $(call MAKE_OBJS, $(MLDSA87_DIR), $(EXTRA_SOURCES)): CFLAGS += $(EXTRA_SOURCES_C
endif
else
$(ALL_BINS): $$(TEST_SRCS) $(LIB_SRCS)
# Extra per-binary prerequisites a custom-build platform needs (e.g. Zephyr's
# app inputs and active-target marker, set in test/zephyr/platform.mk).
$(ALL_BINS): $(CUSTOM_BUILD_DEPS)
endif

# ABI checker
Expand Down
22 changes: 12 additions & 10 deletions test/zephyr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

This is a test platform that builds the mldsa-native test applications as
[Zephyr](https://www.zephyrproject.org/) applications, so they can run on
QEMU-emulated Arm MPS boards. It covers Cortex-M3/M4/M7/M33/M55 through a
single platform, without the need for per-board hardware abstraction layers.
QEMU-emulated Arm MPS boards and the NUCLEO-N657X0-Q hardware board. It covers
Cortex-M3/M4/M7/M33/M55 through a single platform, without the need for
per-board hardware abstraction layers.

## Usage

Expand All @@ -23,16 +24,17 @@ nix develop .#zephyr --command ./scripts/tests func --opt=opt

Currently supported targets:

| `ZEPHYR_TARGET` | Zephyr board | QEMU machine | Core |
| --------------- | --------------------- | ------------ | ---------- |
| `mps2-an385` | `mps2/an385` | `mps2-an385` | Cortex-M3 |
| `mps2-an386` | `mps2/an386` | `mps2-an386` | Cortex-M4 |
| `mps2-an500` | `mps2/an500` | `mps2-an500` | Cortex-M7 |
| `mps2-an521` | `mps2/an521/cpu0` | `mps2-an521` | Cortex-M33 |
| `mps3-an547` | `mps3/corstone300/an547` | `mps3-an547` | Cortex-M55 |
| `ZEPHYR_TARGET` | Zephyr board | Runner | Core |
| ------------------- | ------------------------ | -------------- | ---------- |
| `mps2-an385` | `mps2/an385` | `mps2-an385` | Cortex-M3 |
| `mps2-an386` | `mps2/an386` | `mps2-an386` | Cortex-M4 |
| `mps2-an500` | `mps2/an500` | `mps2-an500` | Cortex-M7 |
| `mps2-an521` | `mps2/an521/cpu0` | `mps2-an521` | Cortex-M33 |
| `mps3-an547` | `mps3/corstone300/an547` | `mps3-an547` | Cortex-M55 |
| `nucleo-n657x0-q` | `nucleo_n657x0_q` | OpenOCD + GDB | Cortex-M55 |

The Armv8.1-M MVE FIPS202 backend is an `OPT=1` feature and is built for
`mps3-an547` only (the only listed core with MVE).
`mps3-an547` and `nucleo-n657x0-q`.

## How it works

Expand Down
46 changes: 41 additions & 5 deletions test/zephyr/app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ list(TRANSFORM _test_srcs PREPEND ${R}/)
target_sources(app PRIVATE
${R}/mldsa/mldsa_native.c
${_test_srcs}
${CMAKE_CURRENT_SOURCE_DIR}/shim.c
)

target_include_directories(app PRIVATE
Expand All @@ -30,6 +29,39 @@ target_include_directories(app PRIVATE
${R}/test/hal
)

# The Zephyr shim owns main() (see below). On QEMU targets shim.c stops the
# emulator with the test's exit code; the NUCLEO-N657X0-Q hardware target needs
# its own shim plus libc wrappers that route stdio over ITM/SWO.
if(ZEPHYR_NUCLEO_N657X0_Q)
# The STM32N6 SystemInit() fallback derives VTOR from &g_pfnVectors. With
# Zephyr data in DTCM that symbol lives in RAM, so force VTOR to the ITCM
# vector table instead.
zephyr_compile_definitions(
USER_VECT_TAB_ADDRESS
VECT_TAB_BASE_ADDRESS=0x10000000
VECT_TAB_OFFSET=0x0
)
target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/shim_nucleo_n657x0_q.c)
target_compile_definitions(app PRIVATE
printf=__wrap_printf
fprintf=__wrap_fprintf
puts=__wrap_puts
putchar=__wrap_putchar
fflush=__wrap_fflush
exit=__wrap_exit
)
target_link_options(app PRIVATE
-Wl,--wrap=printf
-Wl,--wrap=fprintf
-Wl,--wrap=puts
-Wl,--wrap=putchar
-Wl,--wrap=fflush
-Wl,--wrap=exit
)
else()
target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/shim.c)
endif()

# The test binary's CFLAGS, forwarded from the build (test/zephyr/platform.mk
# assembles and escapes them) and applied to the mldsa amalgamation and the test
# sources alike, so both honour the project's own warning/opt/std policy and
Expand All @@ -47,6 +79,9 @@ endif()
set_source_files_properties(${R}/test/hal/hal.c
PROPERTIES COMPILE_OPTIONS "-Wno-error")

set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/shim_nucleo_n657x0_q.c
PROPERTIES COMPILE_OPTIONS "-Wno-error")

# Optional native FIPS202 backend (e.g. Armv8.1-M MVE on Cortex-M55). The
# monolithic mldsa_native.c already includes the backend C sources; its
# assembly counterpart comes from mldsa_native_asm.S.
Expand All @@ -57,9 +92,10 @@ if(ZEPHYR_FIPS202_BACKEND)
"MLD_CONFIG_FIPS202_BACKEND_FILE=\"${ZEPHYR_FIPS202_BACKEND}\"")
endif()

# Each test brings its own int main(void); rename it so the Zephyr shim
# (shim.c) owns main() and can stop QEMU with the test's exit code. Only the
# test entrypoint in ZEPHYR_TEST_SRCS defines main(); the support sources
# (notrandombytes, hal) don't, so applying the define to all is harmless.
# Each test brings its own int main(void); rename it so the selected Zephyr
# shim owns main() and can return the test's exit code through the target's
# runner. Only the test entrypoint in ZEPHYR_TEST_SRCS defines main(); the
# support sources (notrandombytes, hal) don't, so applying the define to all is
# harmless.
set_source_files_properties(${_test_srcs}
PROPERTIES COMPILE_DEFINITIONS "main=mld_test_main")
Loading
Loading