Skip to content

Commit bdf5920

Browse files
committed
Fix .bin, .hex and .uf2 with new linker sections
Also, format perfbench output in table with reference timing from the host.
1 parent 5bb8a7a commit bdf5920

6 files changed

Lines changed: 110 additions & 48 deletions

File tree

ports/mimxrt10xx/Makefile

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,18 +182,20 @@ $(BUILD)/firmware.elf: $(OBJ) $(LD_FILES)
182182
$(STEPECHO) "LINK $@"
183183
$(Q)$(CC) -o $@ $(LDFLAGS) $(filter-out %.ld, $^) -Wl,--print-memory-usage -Wl,--start-group $(LIBS) -Wl,--end-group
184184

185+
# -R excludes sections from the output files.
185186
$(BUILD)/firmware.bin: $(BUILD)/firmware.elf
186187
$(STEPECHO) "Create $@"
187-
$(Q)$(OBJCOPY) -O binary -j .flash_config -j .ivt -j .text -j .ARM.exidx -j .data -j .itcm -j .dtcm_data $^ $@
188+
$(Q)$(OBJCOPY) -O binary -R .stack -R .dtcm_bss $^ $@
188189

189190
$(BUILD)/firmware.uf2: $(BUILD)/firmware.elf
190191
$(STEPECHO) "Create $@"
191-
$(Q)$(OBJCOPY) -O binary -j .text -j .ARM.exidx -j .data -j .itcm -j .dtcm_data $^ $@-binpart
192+
$(Q)$(OBJCOPY) -O binary -R .stack -R .dtcm_bss -R .ivt -R .flash_config $^ $@-binpart
192193
$(Q)$(PYTHON) $(TOP)/tools/uf2/utils/uf2conv.py -b $(BOOTLOADER_SIZE) -f MIMXRT10XX -c -o $@ $@-binpart
193-
$(Q)rm $@-binpart
194+
195+
# $(Q)rm $@-binpart
194196

195197
$(BUILD)/firmware.hex: $(BUILD)/firmware.elf
196-
$(Q)$(OBJCOPY) -O ihex -j .flash_config -j .ivt -j .text -j .ARM.exidx -j .data -j .itcm -j .dtcm_data $< $@
198+
$(Q)$(OBJCOPY) -O ihex -R .stack -R .dtcm_bss $< $@
197199

198200
include $(TOP)/py/mkrules.mk
199201

ports/mimxrt10xx/linking/common.ld

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Boards can setup reserved flash with _ld_reserved_flash_size in board.ld. */
66

77
ENTRY(Reset_Handler)
88

9-
code_size = 2M;
9+
code_size = _ld_flash_size >= 4M ? 2M : 1M;
1010
_ld_default_stack_size = 20K;
1111

1212
/* Default reserved flash to nothing. */
@@ -52,6 +52,20 @@ SECTIONS
5252
. = ALIGN(4);
5353
} > FLASH_IVT
5454

55+
/* Align for 256 ISR entries and place first in flash. Otherwise the UF2
56+
bootloader can't find it because it uses its own flash_config and ivt. */
57+
.isr_vector : ALIGN(4 * 256)
58+
{
59+
. = ALIGN(4);
60+
KEEP(*(.isr_vector)) /* Startup code */
61+
. = ALIGN(4);
62+
} > ITCM AT> FLASH_FIRMWARE
63+
_ld_isr_destination = ADDR(.isr_vector);
64+
_ld_isr_flash_copy = LOADADDR(.isr_vector);
65+
_ld_isr_size = SIZEOF(.isr_vector);
66+
/* Used by the bootloader to start user code. */
67+
__VECTOR_TABLE = LOADADDR(.isr_vector);
68+
5569
.text :
5670
{
5771
. = ALIGN(4);
@@ -146,19 +160,6 @@ SECTIONS
146160
_ld_itcm_flash_copy = LOADADDR(.itcm);
147161
_ld_itcm_size = SIZEOF(.itcm);
148162

149-
/* Align for 256 ISR entries */
150-
.isr_vector : ALIGN(4 * 256)
151-
{
152-
. = ALIGN(4);
153-
KEEP(*(.isr_vector)) /* Startup code */
154-
. = ALIGN(4);
155-
} > ITCM AT> FLASH_FIRMWARE
156-
_ld_isr_destination = ADDR(.isr_vector);
157-
_ld_isr_flash_copy = LOADADDR(.isr_vector);
158-
_ld_isr_size = SIZEOF(.isr_vector);
159-
/* Used by the bootloader to start user code. */
160-
__VECTOR_TABLE = LOADADDR(.isr_vector);
161-
162163
.dtcm_data :
163164
{
164165
. = ALIGN(4);

supervisor/linker.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
#define PLACE_IN_DTCM_DATA(name) name __attribute__((section(".dtcm_data." #name)))
3434
#define PLACE_IN_DTCM_BSS(name) name __attribute__((section(".dtcm_bss." #name)))
3535
// Don't inline ITCM functions because that may pull them out of ITCM into other sections.
36-
#define PLACE_IN_ITCM(name) __attribute__((section(".itcm." #name),noinline)) name
36+
#define PLACE_IN_ITCM(name) __attribute__((section(".itcm." #name),noinline,aligned(4))) name
3737
#else
3838
#define PLACE_IN_DTCM_DATA(name) name
3939
#define PLACE_IN_DTCM_BSS(name) name

tests/perf_bench/benchrun.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ def bm_run(N, M):
44
except ImportError:
55
import time
66

7-
ticks_us = lambda: int(time.monotonic_ns() / 1000)
7+
ticks_us = lambda: int(time.monotonic_ns() // 1000)
88
ticks_diff = lambda a, b: a - b
99

1010
# Pick sensible parameters given N, M

tests/run-perfbench.py

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@
77
import os
88
import subprocess
99
import sys
10+
import time
1011
import argparse
1112
from glob import glob
13+
from rich.live import Live
14+
from rich.console import Console
15+
from rich.table import Table
1216

1317
sys.path.append("../tools")
1418
import pyboard
@@ -37,58 +41,80 @@ def compute_stats(lst):
3741
return avg, var**0.5
3842

3943

40-
def run_script_on_target(target, script):
44+
def run_script_on_target(target, script, run_command=None):
4145
output = b""
4246
err = None
4347

4448
if isinstance(target, pyboard.Pyboard):
4549
# Run via pyboard interface
4650
try:
4751
target.enter_raw_repl()
52+
start_ts = time.monotonic_ns()
4853
output = target.exec_(script)
54+
if run_command:
55+
start_ts = time.monotonic_ns()
56+
output = target.exec_(run_command)
57+
end_ts = time.monotonic_ns()
4958
except pyboard.PyboardError as er:
59+
end_ts = time.monotonic_ns()
5060
err = er
61+
finally:
62+
target.exit_raw_repl()
5163
else:
5264
# Run local executable
5365
try:
66+
if run_command:
67+
script += run_command
68+
start_ts = time.monotonic_ns()
5469
p = subprocess.run(
5570
target, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, input=script
5671
)
72+
end_ts = time.monotonic_ns()
5773
output = p.stdout
5874
except subprocess.CalledProcessError as er:
75+
end_ts = time.monotonic_ns()
5976
err = er
6077

61-
return str(output.strip(), "ascii"), err
78+
return str(output.strip(), "ascii"), err, (end_ts - start_ts) // 1000
6279

6380

6481
def run_feature_test(target, test):
6582
with open("feature_check/" + test + ".py", "rb") as f:
6683
script = f.read()
67-
output, err = run_script_on_target(target, script)
84+
output, err, _ = run_script_on_target(target, script)
6885
if err is None:
6986
return output
7087
else:
7188
return "CRASH: %r" % err
7289

7390

74-
def run_benchmark_on_target(target, script):
75-
output, err = run_script_on_target(target, script)
91+
def run_benchmark_on_target(target, script, run_command=None):
92+
output, err, runtime_us = run_script_on_target(target, script, run_command)
7693
if err is None:
7794
time, norm, result = output.split(None, 2)
7895
try:
79-
return int(time), int(norm), result
96+
return int(time), int(norm), result, runtime_us
8097
except ValueError:
81-
return -1, -1, "CRASH: %r" % output
98+
return -1, -1, "CRASH: %r" % output, runtime_us
8299
else:
83-
return -1, -1, "CRASH: %r" % err
100+
return -1, -1, "CRASH: %r" % err, runtime_us
84101

85102

86-
def run_benchmarks(target, param_n, param_m, n_average, test_list):
103+
def run_benchmarks(console, target, param_n, param_m, n_average, test_list):
87104
skip_complex = run_feature_test(target, "complex") != "complex"
88105
skip_native = run_feature_test(target, "native_check") != "native"
89106

107+
table = Table(show_header=True)
108+
table.add_column("Test")
109+
table.add_column("Time", justify="right")
110+
table.add_column("Score", justify="right")
111+
table.add_column("Ref Time", justify="right")
112+
113+
live = Live(table, console=console)
114+
live.start()
115+
90116
for test_file in sorted(test_list):
91-
print(test_file + ": ", end="")
117+
# print(test_file + ": ", end="")
92118

93119
# Check if test should be skipped
94120
skip = (
@@ -99,14 +125,15 @@ def run_benchmarks(target, param_n, param_m, n_average, test_list):
99125
)
100126
if skip:
101127
print("skip")
128+
table.add_row(test_file, *(["skip"] * 6))
102129
continue
103130

104131
# Create test script
105132
with open(test_file, "rb") as f:
106133
test_script = f.read()
107134
with open(BENCH_SCRIPT_DIR + "benchrun.py", "rb") as f:
108135
test_script += f.read()
109-
test_script += b"bm_run(%u, %u)\n" % (param_n, param_m)
136+
bm_run = b"bm_run(%u, %u)\n" % (param_n, param_m)
110137

111138
# Write full test script if needed
112139
if 0:
@@ -115,43 +142,59 @@ def run_benchmarks(target, param_n, param_m, n_average, test_list):
115142

116143
# Run MicroPython a given number of times
117144
times = []
145+
runtimes = []
118146
scores = []
119147
error = None
120148
result_out = None
121149
for _ in range(n_average):
122-
time, norm, result = run_benchmark_on_target(target, test_script)
123-
if time < 0 or norm < 0:
150+
self_time, norm, result, runtime_us = run_benchmark_on_target(
151+
target, test_script, bm_run
152+
)
153+
if self_time < 0 or norm < 0:
124154
error = result
125155
break
126156
if result_out is None:
127157
result_out = result
128158
elif result != result_out:
129159
error = "FAIL self"
130160
break
131-
times.append(time)
132-
scores.append(1e6 * norm / time)
161+
times.append(self_time)
162+
runtimes.append(runtime_us)
163+
scores.append(1e6 * norm / self_time)
133164

134165
# Check result against truth if needed
135166
if error is None and result_out != "None":
136-
_, _, result_exp = run_benchmark_on_target(PYTHON_TRUTH, test_script)
167+
_, _, result_exp, _ = run_benchmark_on_target(PYTHON_TRUTH, test_script, bm_run)
137168
if result_out != result_exp:
138169
error = "FAIL truth"
139170

140171
if error is not None:
141-
print(error)
172+
print(test_file, error)
173+
if error == "no matching params":
174+
table.add_row(test_file, *([None] * 3))
175+
else:
176+
table.add_row(test_file, *(["error"] * 3))
142177
else:
143178
t_avg, t_sd = compute_stats(times)
179+
r_avg, r_sd = compute_stats(runtimes)
144180
s_avg, s_sd = compute_stats(scores)
145-
print(
146-
"{:.2f} {:.4f} {:.2f} {:.4f}".format(
147-
t_avg, 100 * t_sd / t_avg, s_avg, 100 * s_sd / s_avg
148-
)
181+
# print(
182+
# "{:.2f} {:.4f} {:.2f} {:.4f} {:.2f} {:.4f}".format(
183+
# t_avg, 100 * t_sd / t_avg, s_avg, 100 * s_sd / s_avg, r_avg, 100 * r_sd / r_avg
184+
# )
185+
# )
186+
table.add_row(
187+
test_file,
188+
f"{t_avg:.2f}±{100 * t_sd / t_avg:.1f}%",
189+
f"{s_avg:.2f}±{100 * s_sd / s_avg:.1f}%",
190+
f"{r_avg:.2f}±{100 * r_sd / r_avg:.1f}%",
149191
)
150192
if 0:
151193
print(" times: ", times)
152194
print(" scores:", scores)
153195

154-
sys.stdout.flush()
196+
live.update(table, refresh=True)
197+
live.stop()
155198

156199

157200
def parse_output(filename):
@@ -268,9 +311,10 @@ def main():
268311
else:
269312
tests = sorted(args.files)
270313

314+
console = Console()
271315
print("N={} M={} n_average={}".format(N, M, n_average))
272316

273-
run_benchmarks(target, N, M, n_average, tests)
317+
run_benchmarks(console, target, N, M, n_average, tests)
274318

275319
if isinstance(target, pyboard.Pyboard):
276320
target.exit_raw_repl()

tools/cpboard.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ def read_until(self, ending, timeout=10):
8181
else:
8282
timeout_count += 1
8383
if timeout is not None and timeout_count >= 100 * timeout:
84+
print("timeout")
8485
raise TimeoutError(110, "timeout waiting for", ending)
8586
time.sleep(0.01)
8687
return data
@@ -164,7 +165,10 @@ def __init__(self, dev):
164165
self._path = mount[0][1]
165166
else:
166167
name = os.path.basename(dev)
167-
sh.pmount("-tvfat", dev, name, _timeout=10)
168+
try:
169+
sh.pmount("-tvfat", dev, name, _timeout=10)
170+
except sh.CommandNotFound:
171+
raise ValueError()
168172
self.mountpoint = "/media/" + name
169173
self._path = self.mountpoint
170174

@@ -516,7 +520,10 @@ def disk(self):
516520
if not part:
517521
return None
518522

519-
return Disk(part[0])
523+
try:
524+
return Disk(part[0])
525+
except ValueError:
526+
return None
520527

521528
@property
522529
def firmware(self):
@@ -555,14 +562,17 @@ def execfile(self, filename, timeout=10):
555562
class Pyboard:
556563
def __init__(self, device, baudrate=115200, user="micro", password="python", wait=0):
557564
self.board = CPboard.from_try_all(device, baudrate=baudrate, wait=wait)
558-
with self.board.disk as disk:
559-
disk.copy("skip_if.py")
565+
disk = self.board.disk
566+
if disk:
567+
with disk as open_disk:
568+
open_disk.copy("skip_if.py")
560569

561570
def close(self):
562571
self.board.close()
563572

564573
def enter_raw_repl(self):
565574
self.board.open()
575+
self.board.repl.reset()
566576

567577
def exit_raw_repl(self):
568578
self.close()
@@ -571,7 +581,12 @@ def execfile(self, filename):
571581
return self.board.execfile(filename)
572582

573583
def exec_(self, command, data_consumer=None):
574-
output = self.board.exec(command, timeout=20000)
584+
try:
585+
output, error = self.board.repl.execute(command, timeout=20000, wait_for_response=True)
586+
except OSError as e:
587+
raise CPboardError("timeout", e)
588+
if error:
589+
raise CPboardError("exception", output, error)
575590
return output
576591

577592

0 commit comments

Comments
 (0)