← ARMv9 해설DUJINLABS.COM

Source deep dive 04 · SVE · SME · ZA · signal ABI

ARM SVE·SME Linux 상태 관리 소스 분석

긴 vector를 빠르게 계산한다는 설명을 넘어서, vector length가 task의 저장 공간과 signal frame을 어떻게 키우며 Linux가 first-use trap과 context switch에서 실제로 무엇을 저장하는지 추적한다.

Kernel
Linux v6.18.37
Vector
VL 128–2048
Matrix
ZA · ZT
ABI
prctl · signal

SVE·SME는 명령어뿐 아니라 큰 process 상태다

SVE는 CPU마다 다른 vector length에서도 같은 loop binary가 동작하도록 predicate를 사용한다. SME는 Streaming SVE mode와 matrix accumulator ZA, 일부 확장의 ZT0를 더한다. 문제는 이 register들이 task switch·signal·debugger 때 보존해야 할 process 상태라는 점이다.

SVE

Z0~Z31, predicate P0~P15와 FFR을 사용한다.

Streaming mode

SME가 사용하는 별도의 vector 실행 mode와 SVL을 갖는다.

ZA

SVL × SVL byte 크기의 2차원 accumulator storage다.

Linux ABI

VL·SVL, signal context와 ptrace regset 크기가 동적으로 바뀐다.

Linux task가 추적하는 vector 상태

상태대표 kernel field언제 유효한가
FPSIMDthread.uw.fpsimd_stateNEON/FP 기본 상태와 SVE low 128-bit 연동.
SVEthread.sve_state, sve_vlSVE 사용 task에 가변 크기 buffer를 할당한다.
Streaming SVEsme_vl, SVCR.SMSME streaming mode의 vector length와 mode bit.
ZAthread.sme_state, SVCR.ZAZA를 사용한 task만 큰 buffer가 필요하다.
ZT0signal·ptrace의 ZT record관련 SME extension이 있고 state가 live일 때.

처음 SVE를 실행하면 trap으로 상태를 준비할 수 있다

kernel은 모든 process에 최대 2048-bit SVE와 ZA buffer를 미리 할당하지 않는다. 접근 trap을 이용해 실제 사용 시점에 state를 준비하는 lazy 경로가 있다.

SVE first-use

userspace SVE instruction
→ access trap to EL1
→ do_sve_acc(esr, regs)
→ sve_alloc(current, true)
→ FPSIMD state를 SVE format에 반영
→ CPACR_EL1 access enable
→ instruction 재실행

do_sve_acc()sve_alloc()을 함께 읽는다.

SME first-use

userspace SME instruction
→ do_sme_acc(esr, regs)
→ sve_alloc + sme_alloc
→ streaming/ZA state 초기화
→ SME access enable
→ instruction 재실행

do_sme_acc()는 SVE buffer와 SME buffer가 모두 필요한 경우를 처리한다.

prctl()이 VL·SVL을 process 정책으로 바꾼다

PR_SVE_SET_VLPR_SME_SET_VL은 CPU가 지원하는 길이 중 하나를 task에 설정한다. 요청값이 그대로 채택된다고 가정하지 말고 반환값에서 실제 길이를 읽어야 한다.

  1. PR_*_VL_LEN_MASK로 길이를 분리한다.
  2. PR_*_SET_VL_ONEXEC이면 현재가 아니라 다음 execve()에 적용한다.
  3. PR_*_VL_INHERIT이면 exec 이후 상속 정책을 유지한다.
  4. vec_set_vector_length()가 system 지원 길이로 정규화하고 state buffer를 다시 준비한다.
  5. 길이 변경 시 이전 wider state를 그대로 노출하지 않도록 zeroing과 flush 규칙을 적용한다.

실제 공통 구현은 vec_set_vector_length()이고 UAPI 번호는 include/uapi/linux/prctl.h에 있다.

Context switch는 항상 모든 vector byte를 복사하지 않는다

fpsimd_thread_switch()는 outgoing state가 CPU register에 live한지, memory copy가 최신인지 추적한다. TIF_FOREIGN_FPSTATE 같은 flag를 사용해 다음 userspace 복귀 전 restore가 필요한지 표시한다.

상황필요 작업이유
같은 task의 kernel 진입·복귀가능하면 register state 유지불필요한 대용량 save/restore 방지.
다른 task로 switch필요한 outgoing state 저장, incoming 지연 restoreregister 소유권 변경.
Kernel NEON 사용userspace state를 먼저 보존kernel 연산이 user vector register를 덮을 수 있음.
CPU migrationper-CPU ownership 무효화다른 CPU register에는 state가 없음.

Signal frame은 고정 크기 구조체가 아니다

signal을 전달할 때 Linux는 FPSIMD 기본 record 뒤에 SVE, ZA, ZT 등의 확장 context를 16-byte 정렬로 배치한다. userspace signal handler나 unwinder는 고정 offset을 가정하지 말고 record header의 magicsize를 순회해야 한다.

Signal 전달

setup_rt_frame
→ setup_sigframe_layout
→ preserve_sve_context
→ preserve_za_context
→ preserve_zt_context
→ userspace handler

setup_sigframe_layout()이 필요한 record 공간을 계산하고, 각 preserve 함수가 실제 register data를 userspace frame에 복사한다.

복귀 시에는 userspace가 제공한 size와 VL이 현재 system에서 유효한지 검증한 후 restore한다. 잘못된 context는 kernel memory overwrite가 아니라 잘못된 signal frame으로 거부돼야 한다.

Debugger도 가변 길이 regset을 사용한다

ptrace와 core dump는 NT_ARM_SVE, ZA, ZT regset을 사용한다. debugger가 build한 시점의 최대 VL을 가정하면 newer CPU에서 register를 잘라 읽을 수 있다. 먼저 header를 읽고 실제 payload 크기를 계산해야 한다.

arch/arm64/kernel/ptrace.c의 regset view는 SVE·SME state의 active 여부와 길이를 userspace ABI로 변환한다. signal frame과 ptrace format은 비슷해 보여도 같은 구조로 가정하면 안 된다.

Vector length가 context 비용을 얼마나 키우는가

상태Raw payload 근사식VL/SVL=256 byte
Z0~Z3132 × VL8KB
P0~P1516 × VL/8512B
FFRVL/832B
ZASVL × SVL64KB
Header·alignmentABI record별 추가위 raw 값보다 커짐

성능 해석: 최대 VL이 계산 throughput을 늘릴 수 있지만 signal, context switch, core dump와 debugger transfer 비용도 커진다. workload가 실제로 ZA를 쓰는지와 scheduler 이동 빈도를 함께 측정한다.

Compiler option과 함수 ABI가 mode 전환을 결정한다

확인 순서

clang -march=armv9-a+sve2 -O2 -S demo.c
clang -march=armv9.2-a+sme -O2 -S matrix.c
readelf -A ./demo
objdump -d ./demo | grep -E 'while|ld1|fmopa|smstart'

-march가 instruction 생성을 허용해도 실행 CPU와 kernel HWCAP이 보장되는 것은 아니다. SME 함수의 streaming/ZA interface annotation과 caller/callee save 계약도 ACLE·AAPCS64에서 확인한다.

Linux v6.18.37 소스 지도

파일심볼책임
arch/arm64/kernel/fpsimd.csve_alloc, sme_alloc, vec_set_vector_lengthstate allocation과 VL 정책
fpsimd.cdo_sve_acc, do_sme_accfirst-use access trap
fpsimd.cfpsimd_thread_switchtask switch와 lazy restore
arch/arm64/kernel/signal.cpreserve_sve_context, preserve_za_context가변 signal frame
arch/arm64/kernel/ptrace.cSVE·ZA·ZT regsetdebugger와 core dump ABI
include/uapi/linux/prctl.hPR_SVE_*, PR_SME_*userspace process 정책

실제 시스템에서 state를 검증한다

가용성과 ABI 확인

grep -m1 '^Features' /proc/cpuinfo
getconf GNU_LIBC_VERSION
prctl(PR_SVE_GET_VL)
prctl(PR_SME_GET_VL)
gdb: info all-registers
perf stat ./vector-workload

HWCAP, 실제 반환 VL·SVL, binary instruction과 signal/ptrace 동작을 따로 확인한다. sve token 하나만 보고 SVE2·SME·ZA까지 지원한다고 결론 내리지 않는다.

근거 자료