shecc
shecc copied to clipboard
Introduce generic dynamic array with unit tests
Motivation
- Fixed-size buffers such as
TYPESandPH2_IR_FLATTENare hard to extend. strbuf_tstores bytes only; it cannot handle pointers or large structs (type_t, etc.).- Using a contiguous dynamic array for hash-map buckets improves cache locality and therefore runtime performance.
What’s in this PR
-
Add generic dynamic array
dynarr_tstoressize,capacity,elem_size, and an arena pointer.- Helper APIs:
init,reserve,resize,push_*,extend,get_*,set_raw. - Bounds checks give safety with negligible cost.
-
Add unit tests (
tests/test_dynarr.c)- Cover init, growth, bulk append, random access, mutation and error paths.
- Act as living documentation.
-
Replace
strbuf_t *SOURCEinsrc/global.cwithdynarr_t *- Demonstrates real use and unblocks future clean-ups.
Advantages
- Uniform memory model via the existing arena allocator.
- Built-in range checks catch OOB(Out-Of-Bound) bugs early (temporarily commented in
dynarr_get_byteuntilSOURCEOOB issue is fixed). - API names follow common dynamic-array conventions, easing onboarding.
Known issues
-
test_dynarr.ccurrently#include "src/globals.c", so any change inglobals.crequiresmake update-snapshotsto pass snapshot check -
shecc currently has OOB access on SOURCE bytes.
Next steps
- Migrate all
strbuf_tuseses todynarr_t. - Migrate remaining fixed-size arrays to
dynarr_t. - Re-enable the commented bounds check once the OOB bug is resolved.
- Clean-up codebase, remove redundant function and structures.
Performance impact
benchmark
Benchmark Machine
Benchmark Machine
.-/+oossssoo+/-. alanhacker@alanhacker-ASUS-TUF-Gaming-A15-FA507NV-FA507NV
`:+ssssssssssssssssss+:` ---------------------------------------------------------
-+ssssssssssssssssssyyssss+- OS: Ubuntu 24.04.2 LTS x86_64
.ossssssssssssssssssdMMMNysssso. Host: ASUS TUF Gaming A15 FA507NV_FA507NV 1.0
/ssssssssssshdmmNNmmyNMMMMhssssss/ Kernel: 6.11.0-26-generic
+ssssssssshmydMMMMMMMNddddyssssssss+ Uptime: 9 hours, 38 mins
/sssssssshNMMMyhhyyyyhmNMMMNhssssssss/ Packages: 2345 (dpkg), 10 (flatpak), 14 (snap)
.ssssssssdMMMNhsssssssssshNMMMdssssssss. Shell: bash 5.2.21
+sssshhhyNMMNyssssssssssssyNMMMysssssss+ Resolution: 1920x1080
ossyNMMMNyMMhsssssssssssssshmmmhssssssso DE: GNOME 46.0
ossyNMMMNyMMhsssssssssssssshmmmhssssssso WM: Mutter
+sssshhhyNMMNyssssssssssssyNMMMysssssss+ WM Theme: Adwaita
.ssssssssdMMMNhsssssssssshNMMMdssssssss. Theme: Orchis-Dark-Compact [GTK2/3]
/sssssssshNMMMyhhyyyyhdNMMMNhssssssss/ Icons: Yaru [GTK2/3]
+sssssssssdmydMMMMMMMMddddyssssssss+ Terminal: gnome-terminal
/ssssssssssshdmNNNNmyNMMMMhssssss/ CPU: AMD Ryzen 5 7535HS with Radeon Graphics (12) @ 4.603GHz
.ossssssssssssssssssdMMMNysssso. GPU: NVIDIA GeForce RTX 4060 Max-Q / Mobile
-+sssssssssssssssssyyyssss+- GPU: AMD ATI Radeon 680M
`:+ssssssssssssssssss+:` Memory: 7766MiB / 31328MiB
.-/+oossssoo+/-.
Benchmark Script
Benchmark Script
#!/bin/bash
export LC_ALL=C
n=15
warmup=5
total_user=0
total_sys=0
total_elapsed=0
total_rss=0
tmp_file="$(mktemp)"
echo "Warming up $warmup times..."
for i in $(seq 1 $warmup); do
./out/shecc ./src/main.c >/dev/null 2>&1
done
echo "Running $n benchmarks..."
for i in $(seq 1 $n); do
/usr/bin/time -f "%U %S %e %M" -o "$tmp_file" ./out/shecc ./src/main.c >/dev/null 2>&1
read user sys elapsed rss < "$tmp_file"
echo "Run $i: user=${user}s sys=${sys}s elapsed=${elapsed}s maxrss=${rss}KB"
total_user=$(awk "BEGIN {printf \"%.6f\", $total_user + $user}")
total_sys=$(awk "BEGIN {printf \"%.6f\", $total_sys + $sys}")
total_elapsed=$(awk "BEGIN {printf \"%.6f\", $total_elapsed + $elapsed}")
total_rss=$(awk "BEGIN {print $total_rss + $rss}")
done
rm -f "$tmp_file"
avg_user=$(awk "BEGIN {printf \"%.6f\", $total_user / $n}")
avg_sys=$(awk "BEGIN {printf \"%.6f\", $total_sys / $n}")
avg_elapsed=$(awk "BEGIN {printf \"%.6f\", $total_elapsed / $n}")
avg_rss=$(awk "BEGIN {printf \"%.2f\", $total_rss / $n}")
echo "----------------------------------"
echo "Average user time: ${avg_user}s"
echo "Average system time: ${avg_sys}s"
echo "Average elapsed time: ${avg_elapsed}s"
echo "Average max RSS: ${avg_rss} KB"
Before
Result
Warming up 5 times...
Running 15 benchmarks...
Run 1: user=0.06s sys=0.15s elapsed=0.22s maxrss=294408KB
Run 2: user=0.06s sys=0.15s elapsed=0.21s maxrss=294408KB
Run 3: user=0.06s sys=0.15s elapsed=0.22s maxrss=294216KB
Run 4: user=0.06s sys=0.15s elapsed=0.22s maxrss=294472KB
Run 5: user=0.06s sys=0.15s elapsed=0.22s maxrss=294408KB
Run 6: user=0.05s sys=0.15s elapsed=0.21s maxrss=294472KB
Run 7: user=0.05s sys=0.16s elapsed=0.22s maxrss=294408KB
Run 8: user=0.06s sys=0.15s elapsed=0.22s maxrss=294408KB
Run 9: user=0.06s sys=0.15s elapsed=0.22s maxrss=294408KB
Run 10: user=0.06s sys=0.15s elapsed=0.22s maxrss=294344KB
Run 11: user=0.05s sys=0.16s elapsed=0.22s maxrss=294408KB
Run 12: user=0.06s sys=0.15s elapsed=0.22s maxrss=294344KB
Run 13: user=0.06s sys=0.16s elapsed=0.22s maxrss=294408KB
Run 14: user=0.06s sys=0.15s elapsed=0.22s maxrss=294216KB
Run 15: user=0.06s sys=0.15s elapsed=0.22s maxrss=294280KB
----------------------------------
Average user time: 0.058000s
Average system time: 0.152000s
Average elapsed time: 0.218667s
Average max RSS: 294373.87 KB
After
Result
Warming up 5 times...
Running 15 benchmarks...
Run 1: user=0.06s sys=0.15s elapsed=0.22s maxrss=298248KB
Run 2: user=0.06s sys=0.15s elapsed=0.22s maxrss=298244KB
Run 3: user=0.06s sys=0.15s elapsed=0.22s maxrss=298120KB
Run 4: user=0.07s sys=0.14s elapsed=0.22s maxrss=298120KB
Run 5: user=0.06s sys=0.15s elapsed=0.22s maxrss=297992KB
Run 6: user=0.07s sys=0.15s elapsed=0.22s maxrss=298184KB
Run 7: user=0.07s sys=0.15s elapsed=0.23s maxrss=298120KB
Run 8: user=0.06s sys=0.15s elapsed=0.22s maxrss=298056KB
Run 9: user=0.06s sys=0.15s elapsed=0.22s maxrss=297612KB
Run 10: user=0.07s sys=0.15s elapsed=0.23s maxrss=298056KB
Run 11: user=0.06s sys=0.16s elapsed=0.22s maxrss=298120KB
Run 12: user=0.06s sys=0.15s elapsed=0.22s maxrss=298308KB
Run 13: user=0.06s sys=0.16s elapsed=0.23s maxrss=298052KB
Run 14: user=0.06s sys=0.16s elapsed=0.22s maxrss=297992KB
Run 15: user=0.06s sys=0.17s elapsed=0.23s maxrss=298184KB
----------------------------------
Average user time: 0.062667s
Average system time: 0.152667s
Average elapsed time: 0.222667s
Average max RSS: 298093.87 KB
After benchmark, we observed an average runtime difference of around 15ms in stage-0 compilation. Considering the total build time and the scope of changes, this delta seems reasonable and within acceptable limits.