Morse Micro IoT SDK  2.12.3
benchmark_cpu_mem_stack_perf.c
1/*
2 * Copyright 2026 Morse Micro
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6#include "porting_assistant.h"
7
13/* Threshold based on only execution time */
14#define HIGH_PERF_EXECUTION_TIME_THRESHOLD_MS 600
15#define LOW_PERF_EXECUTION_TIME_THRESHOLD_MS 8000
16
17/* Threshold based on only execution time x cpu clock */
18#define HIGH_PERF_EXECUTION_TIME_X_CPU_CLOCK_THRESHOLD 60000
19#define LOW_PERF_EXECUTION_TIME_X_CPU_CLOCK_THRESHOLD 500000
20
22#define LONG_DEEP_FUNC_DEPTH 10
23
26#define LONG_DEEP_FUNC_BODY(a, b, c, d, acc, buf, s) \
27 memcpy(buf, s, sizeof(s)); \
28 acc += buf[0]; \
29 a = a * b + c - d; \
30 b = b ^ (a << 1); \
31 c = c + (b >> 1) - a; \
32 d = d * c ^ b; \
33 acc += a + b - c * d; \
34 acc ^= (acc << 3) | (acc >> 5); \
35 acc += (a * b) ^ (c + d); \
36 acc -= (b ^ c) + (d - a); \
37 acc *= (c | d) ^ (a & b); \
38 { \
39 uint32_t v = acc; \
40 v = v - ((v >> 1) & 0x55555555); \
41 v = (v & 0x33333333) + ((v >> 2) & 0x33333333); \
42 v = (((v + (v >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; \
43 acc += v * a; \
44 }
45
46#define LONG_DEEP_FUNC_BODY10(a, b, c, d, acc, buf, s) \
47 LONG_DEEP_FUNC_BODY(a, b, c, d, acc, buf, s) \
48 LONG_DEEP_FUNC_BODY(a, b, c, d, acc, buf, s) \
49 LONG_DEEP_FUNC_BODY(a, b, c, d, acc, buf, s) \
50 LONG_DEEP_FUNC_BODY(a, b, c, d, acc, buf, s) \
51 LONG_DEEP_FUNC_BODY(a, b, c, d, acc, buf, s) \
52 LONG_DEEP_FUNC_BODY(a, b, c, d, acc, buf, s) \
53 LONG_DEEP_FUNC_BODY(a, b, c, d, acc, buf, s) \
54 LONG_DEEP_FUNC_BODY(a, b, c, d, acc, buf, s) \
55 LONG_DEEP_FUNC_BODY(a, b, c, d, acc, buf, s) \
56 LONG_DEEP_FUNC_BODY(a, b, c, d, acc, buf, s)
57
58#define LONG_DEEP_FUNC_BODY100(a, b, c, d, acc, buf, s) \
59 LONG_DEEP_FUNC_BODY10(a, b, c, d, acc, buf, s) \
60 LONG_DEEP_FUNC_BODY10(a, b, c, d, acc, buf, s) \
61 LONG_DEEP_FUNC_BODY10(a, b, c, d, acc, buf, s) \
62 LONG_DEEP_FUNC_BODY10(a, b, c, d, acc, buf, s) \
63 LONG_DEEP_FUNC_BODY10(a, b, c, d, acc, buf, s) \
64 LONG_DEEP_FUNC_BODY10(a, b, c, d, acc, buf, s) \
65 LONG_DEEP_FUNC_BODY10(a, b, c, d, acc, buf, s) \
66 LONG_DEEP_FUNC_BODY10(a, b, c, d, acc, buf, s) \
67 LONG_DEEP_FUNC_BODY10(a, b, c, d, acc, buf, s) \
68 LONG_DEEP_FUNC_BODY10(a, b, c, d, acc, buf, s)
69
70enum cpu_mem_benchmark_result
71{
72 CPU_MEM_BENCHMARK_GOOD,
73 CPU_MEM_BENCHMARK_MEDIUM,
74 CPU_MEM_BENCHMARK_POOR,
75 CPU_MEM_BENCHMARK_UNKNOWN
76};
77
78static void execute_long_and_deep_func_inner(uint32_t depth)
79{
80 /* Consume stack memory, but not too big to cause stack overflow */
81 static const char description[] = "Simulate computations";
82 char buf[sizeof(description)];
83 /* `volatile` prevents the compiler from hoisting/eliminating these, ensuring
84 * real loads/stores occur each iteration. */
85 volatile uint32_t a = depth, b = depth * 2, c = depth * 3, d = depth * 4;
86 volatile uint32_t acc = 0;
87
88 if (depth == 0)
89 {
90 return;
91 }
92
93 /* Number of iterations and bodies are tuned against running time and accuracy */
94 for (int i = 0; i < 100; i++)
95 {
96 LONG_DEEP_FUNC_BODY100(a, b, c, d, acc, buf, description)
97 LONG_DEEP_FUNC_BODY100(a, b, c, d, acc, buf, description)
98 LONG_DEEP_FUNC_BODY100(a, b, c, d, acc, buf, description)
99 LONG_DEEP_FUNC_BODY100(a, b, c, d, acc, buf, description)
100 LONG_DEEP_FUNC_BODY100(a, b, c, d, acc, buf, description)
101 }
102 /* Deliberately recurse into this function to force multiple
103 * stack frames to stay active. This lowers the possibility
104 * of a caching mechanism artificially speeding up this call,
105 * as this test is trying to pressure any instruction caching
106 * that might help speed this up.
107 */
108 execute_long_and_deep_func_inner(--depth);
109 /* Do one execution after the recursion to ensure the compiler
110 * cannot optimise this away.
111 */
112 LONG_DEEP_FUNC_BODY10(a, b, c, d, acc, buf, description)
113}
114
116static void execute_long_and_deep_func(void)
117{
118 execute_long_and_deep_func_inner(LONG_DEEP_FUNC_DEPTH);
119}
120
121static const char *benchmark_result_to_str(enum cpu_mem_benchmark_result result)
122{
123 switch (result)
124 {
125 case CPU_MEM_BENCHMARK_GOOD:
126 return "Good";
127
128 case CPU_MEM_BENCHMARK_MEDIUM:
129 return "Medium";
130
131 case CPU_MEM_BENCHMARK_POOR:
132 return "Poor";
133
134 default:
135 return "N/A";
136 }
137}
138
139extern const uint32_t mmhal_system_clock;
140
141static enum cpu_mem_benchmark_result evaluate_benchmark_result(uint32_t execution_time)
142{
143 if (execution_time <= HIGH_PERF_EXECUTION_TIME_THRESHOLD_MS)
144 {
145 /* The execution time is small enough to pass regardless of CPU speed */
146 return CPU_MEM_BENCHMARK_GOOD;
147 }
148 else if (execution_time > LOW_PERF_EXECUTION_TIME_THRESHOLD_MS)
149 {
150 /* The execution time is too big. Investigation is needed */
151 return CPU_MEM_BENCHMARK_POOR;
152 }
153
154 /* Let's check whether the execution time is acceptable compared to CPU speed */
155 uint32_t cpu_speed_mhz = mmhal_system_clock / 1000000;
156 if (!cpu_speed_mhz)
157 {
158 return CPU_MEM_BENCHMARK_UNKNOWN;
159 }
160
161 uint32_t execution_time_x_cpu_speed = execution_time * cpu_speed_mhz;
162 if (execution_time_x_cpu_speed <= HIGH_PERF_EXECUTION_TIME_X_CPU_CLOCK_THRESHOLD)
163 {
164 /* The execution time is relatively fine compared to CPU speed */
165 return CPU_MEM_BENCHMARK_GOOD;
166 }
167 else if (execution_time_x_cpu_speed > LOW_PERF_EXECUTION_TIME_X_CPU_CLOCK_THRESHOLD)
168 {
169 /* The execution time is relatively poor compared to CPU speed */
170 return CPU_MEM_BENCHMARK_POOR;
171 }
172
173 /* The execution time is acceptable compared to CPU speed */
174 return CPU_MEM_BENCHMARK_MEDIUM;
175}
176
177TEST_STEP(test_step_benchmark_cpu_mem_stack_perf, "Execute CPU/Memory/Stack benchmark function")
178{
179 uint32_t start_time = mmosal_get_time_ms();
180 execute_long_and_deep_func();
181 uint32_t execution_time = mmosal_get_time_ms() - start_time;
182
183 enum cpu_mem_benchmark_result result = evaluate_benchmark_result(execution_time);
184
185 TEST_LOG_APPEND("\tExecution time: %lu ms\t(%s, mmhal_system_clock = %lu MHz)\n",
186 execution_time,
187 benchmark_result_to_str(result),
188 (mmhal_system_clock / 1000000));
189
190 if (result == CPU_MEM_BENCHMARK_POOR)
191 {
192 TEST_LOG_APPEND("\n\tRelatively slow compared to CPU speed. Please check system bus and "
193 "memory performance.\n");
194 return TEST_FAILED;
195 }
196 else if (result == CPU_MEM_BENCHMARK_UNKNOWN)
197 {
198 TEST_LOG_APPEND("\n\tPlease check whether 'mmhal_system_clock' is valid\n");
199 return TEST_FAILED;
200 }
201
202 return TEST_PASSED;
203}
uint32_t mmosal_get_time_ms(void)
Get the system time in milliseconds.
static unsigned char buf[1024]
Statically allocated buffer for MQTT.
Definition: mqttdemo.c:153
const struct test_step test_step_benchmark_cpu_mem_stack_perf
Test definition.