147 lines
5.9 KiB
Bash
Executable file
147 lines
5.9 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# benchCyclesCalypsi.sh — measure per-call cycles for each benchmark in
|
|
# benchmarks/ compiled with Calypsi cc65816 5.16 (--speed -O 2).
|
|
# Mirrors benchCyclesPrecise.sh but for Calypsi. Output: markdown
|
|
# table; per-call cycles via MAME emu.time().
|
|
|
|
set -euo pipefail
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
BENCH_DIR="$PROJECT_ROOT/benchmarks"
|
|
|
|
CC="$PROJECT_ROOT/tools/calypsi/usr/local/lib/calypsi-65816-5.16/bin/cc65816"
|
|
LN="$PROJECT_ROOT/tools/calypsi/usr/local/lib/calypsi-65816-5.16/bin/ln65816"
|
|
RUNNER="$PROJECT_ROOT/scripts/runInMameCyclesCalypsi.sh"
|
|
|
|
LINKER_SCM=$(mktemp --suffix=.scm)
|
|
trap 'rm -f "$LINKER_SCM"' EXIT
|
|
cat > "$LINKER_SCM" <<EOF
|
|
(define memories
|
|
'((memory IIgsCode (address (#x1000 . #x9FFF))
|
|
(section code farcode cdata idata switch data_init_table))
|
|
(memory IIgsBSS (address (#xA000 . #xBFFF))
|
|
(section stack data zdata heap))
|
|
(memory IIgsNear (address (#x020000 . #x02FFFF))
|
|
(section znear))
|
|
(memory IIgsDP (address (#x0000 . #x00FF))
|
|
(section (registers ztiny)))
|
|
(memory IIgsVec (address (#xFF00 . #xFFFF))
|
|
(section (reset #xFFFC)))
|
|
(block stack (size #x200))
|
|
(block heap (size #x100))
|
|
(base-address _DirectPageStart IIgsDP 0)
|
|
(base-address _NearBaseAddress IIgsNear 0)))
|
|
EOF
|
|
|
|
# Mirror bench definitions from benchCyclesPrecise.sh
|
|
benchInputs() {
|
|
case "$1" in
|
|
sumOfSquares) echo 'sumOfSquares(50)';;
|
|
fib) echo 'fib(10)';;
|
|
strcpy) echo 'mystrcpy(dst, "hello world!")';;
|
|
memcmp) echo 'mymemcmp("hello", "hello", 5)';;
|
|
bsearch) echo 'bsearch(arr, 8, 5)';;
|
|
dotProduct) echo 'dotProduct(va, vb, 4)';;
|
|
popcount) echo 'popcount(0x12345678UL)';;
|
|
crc32) echo 'crc32((const unsigned char *)"hello", 5)';;
|
|
bubbleSort) echo '(bubbleSort(bsBuf, 16), 0)';;
|
|
strLen) echo 'strLen("The quick brown fox jumps over the lazy dog!")';;
|
|
djb2Hash) echo 'djb2Hash("hello world")';;
|
|
*) echo "/* unknown */";;
|
|
esac
|
|
}
|
|
|
|
benchExtern() {
|
|
case "$1" in
|
|
sumOfSquares) echo 'extern unsigned long sumOfSquares(unsigned short n);';;
|
|
fib) echo 'extern unsigned short fib(unsigned short n);';;
|
|
strcpy) echo 'extern char *mystrcpy(char *d, const char *s); static char dst[16];';;
|
|
memcmp) echo 'extern int mymemcmp(const void *a, const void *b, unsigned int n);';;
|
|
bsearch) echo 'extern int bsearch(const int *arr, int n, int key); static const int arr[] = {1,2,3,4,5,6,7,8};';;
|
|
dotProduct) echo 'extern long dotProduct(const short *a, const short *b, unsigned int n); static const short va[] = {1,2,3,4}; static const short vb[] = {5,6,7,8};';;
|
|
popcount) echo 'extern int popcount(unsigned long x);';;
|
|
crc32) echo 'extern unsigned long crc32(const unsigned char *p, unsigned int n);';;
|
|
bubbleSort) echo 'extern void bubbleSort(short *a, unsigned short n); static short bsBuf[16] = {7,3,1,9,4,5,8,2,6,0,15,11,13,10,14,12};';;
|
|
strLen) echo 'extern unsigned short strLen(const char *s);';;
|
|
djb2Hash) echo 'extern unsigned long djb2Hash(const char *s);';;
|
|
*) echo '';;
|
|
esac
|
|
}
|
|
|
|
benchIters() {
|
|
case "$1" in
|
|
sumOfSquares) echo 50;;
|
|
fib) echo 100;;
|
|
strcpy) echo 200;;
|
|
memcmp) echo 500;;
|
|
bsearch) echo 200;;
|
|
dotProduct) echo 200;;
|
|
popcount) echo 100;;
|
|
crc32) echo 100;;
|
|
bubbleSort) echo 10;;
|
|
strLen) echo 200;;
|
|
djb2Hash) echo 200;;
|
|
*) echo 50;;
|
|
esac
|
|
}
|
|
|
|
runOneCalypsiBench() {
|
|
local name="$1"
|
|
local extern_decl call_expr iters
|
|
extern_decl=$(benchExtern "$name")
|
|
call_expr=$(benchInputs "$name")
|
|
iters=$(benchIters "$name")
|
|
[ -z "$extern_decl" ] && { echo "skip"; return; }
|
|
|
|
local cwrap obench bin
|
|
cwrap=$(mktemp --suffix=.c)
|
|
owrap=$(mktemp --suffix=.o)
|
|
obench=$(mktemp --suffix=.o)
|
|
bin=$(mktemp --suffix=.bin)
|
|
bin_raw="${bin%.bin}.raw"
|
|
lst=$(mktemp --suffix=.lst)
|
|
trap 'rm -f "$cwrap" "$owrap" "$obench" "$bin" "$bin_raw" "$lst"' RETURN
|
|
|
|
cat > "$cwrap" <<EOF
|
|
$extern_decl
|
|
volatile unsigned long sink;
|
|
__task int main(void) {
|
|
for (int w = 0; w < 5; w++) sink = (unsigned long)($call_expr);
|
|
*((volatile unsigned long __far *)0x025000) = 0xa1a1UL;
|
|
for (int i = 0; i < $iters; i++) sink = (unsigned long)($call_expr);
|
|
*((volatile unsigned long __far *)0x025002) = 0xa2a2UL;
|
|
while (1) {}
|
|
}
|
|
EOF
|
|
"$CC" -O 2 --speed --code-model=small -c "$cwrap" -o "$owrap" 2>/dev/null \
|
|
|| { echo "compile-fail-wrap"; return; }
|
|
"$CC" -O 2 --speed --code-model=small -c "$BENCH_DIR/$name.c" -o "$obench" 2>/dev/null \
|
|
|| { echo "compile-fail-bench"; return; }
|
|
# ln65816 emits the raw alongside the bin; one per memory
|
|
"$LN" "$LINKER_SCM" "$owrap" "$obench" -o "$bin" \
|
|
--output-format raw --raw-multiple-memories --rtattr exit=simplified \
|
|
--list-file "$lst" clib-sc-sd.a 2>/dev/null \
|
|
|| { echo "link-fail"; return; }
|
|
|
|
local entry
|
|
entry=$(grep "__program_start =" "$lst" | head -1 | awk '{print substr($NF,3)}')
|
|
[ -z "$entry" ] && { echo "no-entry"; return; }
|
|
|
|
local val
|
|
val=$(bash "$RUNNER" "$bin_raw" "$entry" "$iters" 2>&1 | grep -oE 'cyc_per_call=[0-9.]+' | head -1 | sed 's/cyc_per_call=//')
|
|
if [ -z "$val" ]; then
|
|
echo "(no read)"
|
|
else
|
|
printf '%.0f cyc/call' "$val"
|
|
fi
|
|
}
|
|
|
|
printf '| Benchmark | Calypsi (cyc) |\n'
|
|
printf '|-----------|--------------:|\n'
|
|
for src in "$BENCH_DIR"/*.c; do
|
|
name=$(basename "$src" .c)
|
|
extern_decl=$(benchExtern "$name")
|
|
[ -z "$extern_decl" ] && continue
|
|
result=$(runOneCalypsiBench "$name")
|
|
printf '| %s | %s |\n' "$name" "$result"
|
|
done
|