Skip to content

Track RISC-V64 migration - #1

Draft
siraben wants to merge 40 commits into
masterfrom
riscv-port
Draft

Track RISC-V64 migration#1
siraben wants to merge 40 commits into
masterfrom
riscv-port

Conversation

@siraben

@siraben siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner

Summary

  • Switch the runtime build over to the RISC-V64 guest path and wire the RISC-V emulator, decoder/interpreter, Asbestos scaffolding, syscall dispatch, ELF loading, signals, time/stat layouts, TLS, uname, and proc/cpuinfo handling.
  • Add RISC-V helper tools and selftests (rvdecode, rvrun, rvdecode-selftest, rvinterp-selftest).
  • Keep rootfs handling aligned with the existing iSH project shape: root filesystems are downloaded/created as build or local artifacts, not committed as an expanded roots/ tree. The local .rv64-rootfs-cache/ and roots/ directories are ignored.
  • Add a cross-ISA benchmark harness for i386 vs riscv64 with freestanding C payloads and guest shell/Python/gzip workloads.

Benchmark Figures

Filtered local run:

RUNS=3 WARMUPS=1 \
I386_BUILD=/Users/siraben/Git/ish/build \
RV64_BUILD=/Users/siraben/Git/ish-riscv/build-bench-rv64 \
RV64_FS=/tmp/ish-rv64-testfs \
OUT=/Users/siraben/Git/ish-riscv/e2e_out/bench-compare \
BENCH_FILTER='^(prime_sieve|mandelbrot|file_io|pipe_throughput|gzip_payload)$' \
./benchmarks/hot_paths/compare.sh
benchmark i386 best (s) i386 avg (s) i386 RSD % riscv64 best (s) riscv64 avg (s) riscv64 RSD % riscv64/i386 best
file_io 0.010 0.010 0.0 0.090 0.097 4.9 9.00x
gzip_payload 0.990 1.003 0.9 28.590 28.883 1.2 28.88x
mandelbrot 0.040 0.047 10.1 5.190 5.257 0.9 129.75x
pipe_throughput 0.010 0.010 0.0 0.090 0.090 0.0 9.00x
prime_sieve 0.020 0.020 0.0 2.120 2.150 1.0 106.00x

Note: this is a smoke run. The i386 C benchmarks are short enough that timer resolution dominates several rows, so these figures are useful for tracking large deltas but not publication-grade performance claims.

Validation

  • meson setup build-bench-rv64 . --reconfigure
  • ninja -C build-bench-rv64 ish rvdecode rvdecode-selftest rvinterp-selftest
  • meson test -C build-bench-rv64 --print-errorlogs
  • Compiled freestanding C benchmark payloads for i386 and riscv64 with Homebrew LLVM clang.
  • Ran the filtered 3-sample compare shown above.

Tracking Notes

This is a tracking PR against siraben/ish:master for the RISC-V64 migration branch. Follow-up benchmark runs are posted as PR comments so the body stays stable.

@siraben siraben changed the title Track riscv-port benchmarks Track RISC-V64 migration Apr 27, 2026
@siraben

siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner Author

Follow-up benchmark after ARM64 fiber routing plus core integer lowering (126e82c7). Updated after amending the benchmark harness so C benchmarks time themselves with clock_gettime; gzip_payload is still shell-timed with /usr/bin/time. RUNS=3 WARMUPS=1.

benchmark i386 best i386 avg i386 RSD riscv64 best riscv64 avg riscv64 RSD best ratio
file_io 0.007884s 0.008049s 1.46% 0.014494s 0.014953s 2.30% 1.838x
gzip_payload 0.920000s 0.923333s 0.51% 21.690000s 21.726667s 0.15% 23.576x
mandelbrot 0.042622s 0.043775s 2.18% 3.208335s 3.219829s 0.29% 75.274x
pipe_throughput 0.009748s 0.009911s 1.20% 0.015543s 0.016413s 6.66% 1.594x
prime_sieve 0.016517s 0.016603s 0.52% 0.926400s 0.939972s 1.99% 56.088x

@siraben

siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner Author

Follow-up benchmark after e74a02f0 (Lower RV64 integer ALU ops to ARM64 gadgets). Updated after amending the benchmark harness so C benchmarks time themselves with clock_gettime; gzip_payload is still shell-timed with /usr/bin/time. RUNS=3 WARMUPS=1.

benchmark i386 best i386 avg i386 RSD riscv64 best riscv64 avg riscv64 RSD best ratio
file_io 0.008350s 0.008489s 1.83% 0.012117s 0.012853s 6.24% 1.451x
gzip_payload 0.940000s 0.946667s 0.50% 16.840000s 16.863333s 0.10% 17.915x
mandelbrot 0.045026s 0.046297s 1.94% 1.432628s 1.439321s 0.33% 31.818x
pipe_throughput 0.010125s 0.010269s 1.49% 0.014651s 0.014929s 2.30% 1.447x
prime_sieve 0.017013s 0.017226s 1.64% 0.955603s 0.958939s 0.43% 56.169x

@siraben

siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner Author

Follow-up benchmark after 94823519 (Lower RV64 control flow to ARM64 gadgets). Updated after amending the benchmark harness so C benchmarks time themselves with clock_gettime; gzip_payload is still shell-timed with /usr/bin/time. RUNS=3 WARMUPS=1.

benchmark i386 best i386 avg i386 RSD riscv64 best riscv64 avg riscv64 RSD best ratio
file_io 0.008395s 0.008573s 1.62% 0.010521s 0.010940s 2.75% 1.253x
gzip_payload 0.940000s 0.943333s 0.50% 10.550000s 10.556667s 0.04% 11.223x
mandelbrot 0.043764s 0.044724s 2.22% 0.839010s 0.841588s 0.28% 19.171x
pipe_throughput 0.010258s 0.010447s 1.30% 0.012707s 0.012775s 0.69% 1.239x
prime_sieve 0.017631s 0.017795s 0.78% 0.449544s 0.452858s 0.94% 25.497x

@siraben

siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner Author

Follow-up benchmark after 06bdc445 (Lower RV64 stores to ARM64 TLB gadgets). Updated after amending the benchmark harness so C benchmarks time themselves with clock_gettime; gzip_payload is still shell-timed with /usr/bin/time. RUNS=3 WARMUPS=1.

benchmark i386 best i386 avg i386 RSD riscv64 best riscv64 avg riscv64 RSD best ratio
file_io 0.008280s 0.008493s 2.08% 0.010246s 0.010427s 1.29% 1.237x
gzip_payload 0.970000s 0.990000s 2.18% 7.180000s 7.303333s 1.92% 7.402x
mandelbrot 0.045154s 0.049109s 8.50% 0.839916s 0.842363s 0.23% 18.601x
pipe_throughput 0.009974s 0.010121s 1.05% 0.012116s 0.012436s 1.94% 1.215x
prime_sieve 0.016893s 0.017417s 2.20% 0.198344s 0.201706s 1.52% 11.741x

This checkpoint keeps fast stores enabled. Fast load gadgets are selected in the later load checkpoint.

@siraben

siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner Author

Follow-up benchmark after 8503879b (Lower RV64 multiply and divide ops to ARM64 gadgets). Updated after amending the benchmark harness so C benchmarks time themselves with clock_gettime; RUNS=3 WARMUPS=1.

benchmark i386 best i386 avg i386 RSD riscv64 best riscv64 avg riscv64 RSD best ratio
mandelbrot 0.044716s 0.046076s 2.67% 0.114958s 0.117289s 1.63% 2.571x
prime_sieve 0.017439s 0.017729s 1.39% 0.193336s 0.195130s 0.78% 11.086x

Compared with the store checkpoint, mandelbrot improved from 0.839916s to 0.114958s best. prime_sieve is roughly unchanged because this benchmark is not multiply/divide-heavy.

@siraben

siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner Author

Full benchmark set after 8503879b (Lower RV64 multiply and divide ops to ARM64 gadgets). Updated after amending the benchmark harness so C benchmarks time themselves with clock_gettime; gzip_payload is still shell-timed with /usr/bin/time. RUNS=3 WARMUPS=1.

benchmark i386 best i386 avg i386 RSD riscv64 best riscv64 avg riscv64 RSD best ratio
file_io 0.008684s 0.008781s 0.79% 0.009544s 0.009789s 1.78% 1.099x
gzip_payload 0.950000s 0.976667s 2.10% 7.150000s 7.220000s 1.09% 7.526x
mandelbrot 0.044716s 0.046076s 2.67% 0.114958s 0.117289s 1.63% 2.571x
pipe_throughput 0.010972s 0.011203s 1.50% 0.012366s 0.012589s 2.15% 1.127x
prime_sieve 0.017439s 0.017729s 1.39% 0.193336s 0.195130s 0.78% 11.086x

@siraben

siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner Author

Full benchmark set after ae98c58c (Lower RV64 loads to ARM64 TLB gadgets). Updated after amending the benchmark harness so C benchmarks time themselves with clock_gettime; gzip_payload is still shell-timed with /usr/bin/time. RUNS=3 WARMUPS=1.

benchmark i386 best i386 avg i386 RSD riscv64 best riscv64 avg riscv64 RSD best ratio
file_io 0.008734s 0.009221s 6.00% 0.009273s 0.009407s 1.03% 1.062x
gzip_payload 0.950000s 0.950000s 0.00% 1.630000s 1.643333s 0.76% 1.716x
mandelbrot 0.043968s 0.045213s 2.68% 0.120710s 0.121792s 0.64% 2.745x
pipe_throughput 0.010091s 0.010158s 0.90% 0.010644s 0.011026s 2.80% 1.055x
prime_sieve 0.017066s 0.017416s 1.58% 0.076009s 0.076805s 0.75% 4.454x

The load slow-path bug was INT_NONE == -1 being treated as nonzero failure; after fixing that, the load gadgets are selected for all integer load widths.

@siraben

siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner Author

Full benchmark set after 86e85033 (Lower RV64 FP memory ops to ARM64 gadgets). Updated after amending the benchmark harness so C benchmarks time themselves with clock_gettime; gzip_payload is still shell-timed with /usr/bin/time. RUNS=3 WARMUPS=1.

benchmark i386 best i386 avg i386 RSD riscv64 best riscv64 avg riscv64 RSD best ratio
file_io 0.008546s 0.008644s 0.99% 0.009253s 0.009282s 0.36% 1.083x
gzip_payload 0.930000s 0.943333s 1.32% 1.600000s 1.643333s 2.55% 1.720x
mandelbrot 0.044494s 0.045907s 2.18% 0.120467s 0.121899s 0.84% 2.707x
pipe_throughput 0.010125s 0.010185s 0.82% 0.011163s 0.011645s 3.01% 1.103x
prime_sieve 0.017008s 0.017226s 1.52% 0.075826s 0.076330s 0.65% 4.458x

siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner Author

Full benchmark set after 5a63e240 (Lower RV64 system traps to ARM64 gadgets). C benchmarks are self-timed with clock_gettime; gzip_payload is still shell-timed with /usr/bin/time. RUNS=3 WARMUPS=1.

benchmark i386 best i386 avg i386 RSD riscv64 best riscv64 avg riscv64 RSD best ratio
file_io 0.008745s 0.008975s 2.74% 0.009315s 0.010619s 16.30% 1.065x
gzip_payload 0.940000s 0.966667s 1.95% 1.580000s 1.593333s 0.59% 1.681x
mandelbrot 0.046242s 0.047120s 1.35% 0.118884s 0.124468s 3.44% 2.571x
pipe_throughput 0.010067s 0.010249s 1.56% 0.010798s 0.011505s 4.36% 1.073x
prime_sieve 0.017192s 0.017722s 3.11% 0.077050s 0.077696s 0.77% 4.482x

Validation at this head: rvinterp-selftest passes, and /bin/sh -lc 'echo syscall-ok; uname -m; true' exits 0 and reports riscv64.

siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner Author

Follow-up benchmark after e7aee4eb (Lower RV64 high multiply ops to ARM64 gadgets). C benchmarks are self-timed with clock_gettime; gzip_payload is still shell-timed with /usr/bin/time. RUNS=3 WARMUPS=1.

benchmark i386 best i386 avg i386 RSD riscv64 best riscv64 avg riscv64 RSD best ratio
file_io 0.008027s 0.008192s 1.99% 0.008262s 0.008471s 1.84% 1.029x
gzip_payload 0.930000s 0.933333s 0.51% 1.500000s 1.510000s 0.54% 1.613x
mandelbrot 0.042887s 0.043409s 0.91% 0.107185s 0.108875s 1.50% 2.499x
pipe_throughput 0.010190s 0.010572s 3.68% 0.010444s 0.010483s 0.52% 1.025x
prime_sieve 0.016465s 0.016610s 1.02% 0.073123s 0.073460s 0.37% 4.441x

Validation: rvinterp-selftest passes with explicit mulh, mulhsu, and mulhu coverage; RV64 /bin/sh smoke exits 0.

siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner Author

Follow-up benchmark after b7e36c9e (Lower RV64 fences to ARM64 gadgets). C benchmarks are self-timed with clock_gettime; gzip_payload is still shell-timed with /usr/bin/time. RUNS=3 WARMUPS=1.

benchmark i386 best i386 avg i386 RSD riscv64 best riscv64 avg riscv64 RSD best ratio
file_io 0.008100s 0.008318s 1.98% 0.008364s 0.008575s 2.06% 1.033x
gzip_payload 0.930000s 0.933333s 0.51% 1.510000s 1.516667s 0.31% 1.624x
mandelbrot 0.042662s 0.043384s 2.21% 0.109789s 0.110656s 0.62% 2.573x
pipe_throughput 0.009718s 0.009937s 2.11% 0.010466s 0.011101s 4.16% 1.077x
prime_sieve 0.016289s 0.016850s 3.62% 0.074508s 0.074990s 0.77% 4.574x

This is expected to be mostly neutral on the current suite; it removes fence/fence.i fallback overhead and adds explicit selftest coverage.

siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner Author

Follow-up benchmark after 5c161884 (Lower RV64 CSR ops through ARM64 gadgets). C benchmarks are self-timed with clock_gettime; gzip_payload is still shell-timed with /usr/bin/time. RUNS=3 WARMUPS=1.

benchmark i386 best i386 avg i386 RSD riscv64 best riscv64 avg riscv64 RSD best ratio
file_io 0.008161s 0.008383s 2.41% 0.008836s 0.008876s 0.36% 1.083x
gzip_payload 0.950000s 0.960000s 0.85% 1.500000s 1.533333s 2.22% 1.579x
mandelbrot 0.045695s 0.046493s 1.24% 0.107335s 0.109416s 1.35% 2.349x
pipe_throughput 0.010221s 0.010879s 4.72% 0.010225s 0.010731s 3.62% 1.000x
prime_sieve 0.016651s 0.016949s 1.25% 0.077801s 0.078485s 1.00% 4.672x

Validation: rvinterp-selftest passes with fcsr CSR read/write coverage; RV64 /bin/sh smoke exits 0.

siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner Author

Follow-up benchmark after d3d35888 (Lower RV64 atomics through ARM64 gadgets). C benchmarks are self-timed with clock_gettime; gzip_payload is still shell-timed with /usr/bin/time. RUNS=3 WARMUPS=1.

benchmark i386 best i386 avg i386 RSD riscv64 best riscv64 avg riscv64 RSD best ratio
file_io 0.008168s 0.008357s 1.79% 0.008174s 0.008573s 3.51% 1.001x
gzip_payload 0.940000s 0.950000s 0.86% 1.510000s 1.526667s 0.82% 1.606x
mandelbrot 0.043525s 0.044684s 1.88% 0.102192s 0.104110s 2.28% 2.348x
pipe_throughput 0.009814s 0.010094s 1.97% 0.010010s 0.010270s 2.71% 1.020x
prime_sieve 0.016429s 0.016639s 1.20% 0.074619s 0.076847s 2.34% 4.542x

Validation: rvinterp-selftest passes with amoadd.d coverage; RV64 /bin/sh smoke exits 0.

siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner Author

Follow-up benchmark after 265a7c9e (Lower RV64 FP arithmetic through ARM64 gadgets). This lowers OP-FP and fused multiply-add/subtract via a parameterized helper gadget matching interpreter semantics. C benchmarks are self-timed with clock_gettime; gzip_payload is still shell-timed with /usr/bin/time. RUNS=3 WARMUPS=1.

benchmark i386 best i386 avg i386 RSD riscv64 best riscv64 avg riscv64 RSD best ratio
file_io 0.008180s 0.008247s 1.03% 0.008356s 0.008496s 1.17% 1.022x
gzip_payload 0.930000s 0.933333s 0.51% 1.510000s 1.520000s 0.54% 1.624x
mandelbrot 0.043210s 0.043817s 0.98% 0.105499s 0.107254s 2.13% 2.442x
pipe_throughput 0.009752s 0.009899s 1.59% 0.010509s 0.010688s 1.67% 1.078x
prime_sieve 0.018427s 0.020644s 14.92% 0.073609s 0.074472s 1.09% 3.995x

Validation: rvinterp-selftest passes its fadd.d path through the helper gadget; RV64 /bin/sh smoke exits 0.

siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner Author

Broad benchmark after 265a7c9e with all current lowering batches through FP arithmetic. C benchmarks are self-timed with clock_gettime; shell/gzip rows use /usr/bin/time. RUNS=3 WARMUPS=1.

RV64 rootfs note: /usr/bin/python3 and /bin/bash are not present in /tmp/ish-rv64-testfs, so RV64 skipped python_startup, python_compute, python_imports, and bash_control; those i386-only rows are not in the comparison table below.

benchmark i386 best i386 avg i386 RSD riscv64 best riscv64 avg riscv64 RSD best ratio
file_io 0.009550s 0.009714s 1.65% 0.009052s 0.009410s 3.10% 0.948x
fs_metadata 1.110000s 1.116667s 0.84% 1.380000s 1.393333s 0.68% 1.243x
gzip_payload 0.940000s 0.943333s 0.50% 1.580000s 1.606667s 1.92% 1.681x
mandelbrot 0.043309s 0.044596s 3.29% 0.109954s 0.110777s 0.54% 2.539x
pipe_throughput 0.009952s 0.010222s 1.97% 0.011478s 0.011717s 2.08% 1.153x
prime_sieve 0.016805s 0.017439s 2.82% 0.076001s 0.076842s 0.77% 4.523x
shell_control 1.880000s 1.900000s 1.49% 2.680000s 2.696667s 0.63% 1.426x
shell_pipeline 0.600000s 0.610000s 1.34% 0.860000s 0.880000s 2.45% 1.433x
shell_startup 0.000000s 0.000000s 0.00% 0.010000s 0.010000s 0.00% inf

Coverage status: every decoded RV64 op class now has a lowered path: base integer, branches/jumps, loads/stores, FP memory, M-extension including high multiply, fences, traps/CSR, atomics, OP-FP, and FP fused multiply-add/subtract. Generic rv_exec_one_gadget remains for invalid/unsupported decoded combinations and any future decoder expansion.

siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner Author

Follow-up RV64 lowering/optimization pass using QEMU's RISC-V translator behavior as a reference for direct branch TB chaining and jalr semantics.

Commit pushed: db372fdb (Optimize RV64 block chaining and hot registers)

Changes:

  • pinned RV64 ra, sp, gp, tp, t0-t2, s0, s1 in ARM64 callee-saved host registers
  • synchronized pinned registers around C helper slow paths
  • wired direct jal and conditional branches into asbestos block chaining with RV64 tagged target addresses
  • added a return-cache fast path for normal ret (jalr x0, ra, 0) using the existing fiber return-cache frame storage
  • added targeted C benchmarks: branch_chaining, call_return, hot_regs

Validation:

  • ninja -C build-bench-rv64 ish rvinterp-selftest
  • ./build-bench-rv64/rvinterp-selftest
  • RV64 shell smoke through Alpine rootfs
  • full RUNS=3 WARMUPS=1 ./benchmarks/hot_paths/compare.sh

Full benchmark result, best of 3:

benchmark i386 best s rv64 best s rv64 vs i386
branch_chaining 0.026194 0.055644 2.124x
call_return 0.007880 0.014805 1.879x
file_io 0.008651 0.012534 1.449x
fs_metadata 1.110000 0.870000 0.784x
gzip_payload 0.920000 0.590000 0.641x
hot_regs 0.141409 0.107107 0.757x
mandelbrot 0.044068 0.046357 1.052x
pipe_throughput 0.010004 0.010406 1.040x
prime_sieve 0.016679 0.026040 1.561x
shell_control 1.850000 0.980000 0.530x
shell_pipeline 0.590000 0.340000 0.576x

RV64 still skips Python and bash benchmarks because the current RV64 rootfs does not include /usr/bin/python3 or /bin/bash.

siraben commented Apr 27, 2026

Copy link
Copy Markdown
Owner Author

Follow-up fix for the simulator apk add curl crash path.

Commit pushed: 3cbbde5e (Implement RV64 FP conversions and hwprobe).

What changed:

  • Implemented RV64 FP conversion cases in the interpreter and JIT helper paths, including the fcvt.s.lu instruction that showed up as SIGILL in Alpine Python (d3 77 37 d0, OP-FP funct5=0x1a, rs2=3).
  • Added a conservative riscv_hwprobe syscall implementation for syscall 258. It returns success while marking requested feature keys unsupported, so userspace does not infer unsupported optimized ISA paths from a raw stub.

Validation:

  • ninja -C build-bench-rv64 ish rvinterp-selftest
  • ./build-bench-rv64/rvinterp-selftest
  • Injected Alpine RV64 rootfs with bash and python3 packages: python3 -S, normal python3, and bash all run successfully.
  • Full benchmark matrix with Python and bash present on RV64 completed.

Full benchmark result, best of 3 with Python/bash enabled in the RV64 throwaway rootfs:

benchmark i386 best s rv64 best s rv64 vs i386
bash_control 37.560000 27.320000 0.727x
branch_chaining 0.025849 0.053763 2.080x
call_return 0.007694 0.014739 1.916x
file_io 0.008888 0.011203 1.260x
fs_metadata 1.080000 0.790000 0.731x
gzip_payload 0.930000 0.580000 0.624x
hot_regs 0.145530 0.104777 0.720x
mandelbrot 0.043166 0.045507 1.054x
pipe_throughput 0.010212 0.010109 0.990x
prime_sieve 0.016681 0.026182 1.570x
python_compute 9.040000 0.410000 0.045x
python_imports 2.020000 0.710000 0.351x
python_startup 0.170000 0.150000 0.882x
shell_control 1.840000 0.960000 0.522x
shell_pipeline 0.600000 0.370000 0.617x

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant