SVE·SME는 명령어뿐 아니라 큰 process 상태다
SVE는 CPU마다 다른 vector length에서도 같은 loop binary가 동작하도록 predicate를 사용한다. SME는 Streaming SVE mode와 matrix accumulator ZA, 일부 확장의 ZT0를 더한다. 문제는 이 register들이 task switch·signal·debugger 때 보존해야 할 process 상태라는 점이다.
Z0~Z31, predicate P0~P15와 FFR을 사용한다.
SME가 사용하는 별도의 vector 실행 mode와 SVL을 갖는다.
SVL × SVL byte 크기의 2차원 accumulator storage다.
VL·SVL, signal context와 ptrace regset 크기가 동적으로 바뀐다.
Linux task가 추적하는 vector 상태
| 상태 | 대표 kernel field | 언제 유효한가 |
|---|---|---|
| FPSIMD | thread.uw.fpsimd_state | NEON/FP 기본 상태와 SVE low 128-bit 연동. |
| SVE | thread.sve_state, sve_vl | SVE 사용 task에 가변 크기 buffer를 할당한다. |
| Streaming SVE | sme_vl, SVCR.SM | SME streaming mode의 vector length와 mode bit. |
| ZA | thread.sme_state, SVCR.ZA | ZA를 사용한 task만 큰 buffer가 필요하다. |
| ZT0 | signal·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_VL과 PR_SME_SET_VL은 CPU가 지원하는 길이 중 하나를 task에 설정한다. 요청값이 그대로 채택된다고 가정하지 말고 반환값에서 실제 길이를 읽어야 한다.
PR_*_VL_LEN_MASK로 길이를 분리한다.PR_*_SET_VL_ONEXEC이면 현재가 아니라 다음execve()에 적용한다.PR_*_VL_INHERIT이면 exec 이후 상속 정책을 유지한다.vec_set_vector_length()가 system 지원 길이로 정규화하고 state buffer를 다시 준비한다.- 길이 변경 시 이전 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 지연 restore | register 소유권 변경. |
| Kernel NEON 사용 | userspace state를 먼저 보존 | kernel 연산이 user vector register를 덮을 수 있음. |
| CPU migration | per-CPU ownership 무효화 | 다른 CPU register에는 state가 없음. |
Signal frame은 고정 크기 구조체가 아니다
signal을 전달할 때 Linux는 FPSIMD 기본 record 뒤에 SVE, ZA, ZT 등의 확장 context를 16-byte 정렬로 배치한다. userspace signal handler나 unwinder는 고정 offset을 가정하지 말고 record header의 magic과 size를 순회해야 한다.
Signal 전달
setup_rt_frame
→ setup_sigframe_layout
→ preserve_sve_context
→ preserve_za_context
→ preserve_zt_context
→ userspace handlersetup_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~Z31 | 32 × VL | 8KB |
| P0~P15 | 16 × VL/8 | 512B |
| FFR | VL/8 | 32B |
| ZA | SVL × SVL | 64KB |
| Header·alignment | ABI 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.c | sve_alloc, sme_alloc, vec_set_vector_length | state allocation과 VL 정책 |
| fpsimd.c | do_sve_acc, do_sme_acc | first-use access trap |
| fpsimd.c | fpsimd_thread_switch | task switch와 lazy restore |
| arch/arm64/kernel/signal.c | preserve_sve_context, preserve_za_context | 가변 signal frame |
| arch/arm64/kernel/ptrace.c | SVE·ZA·ZT regset | debugger와 core dump ABI |
| include/uapi/linux/prctl.h | PR_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-workloadHWCAP, 실제 반환 VL·SVL, binary instruction과 signal/ptrace 동작을 따로 확인한다. sve token 하나만 보고 SVE2·SME·ZA까지 지원한다고 결론 내리지 않는다.
근거 자료
- Local sourceLinux v6.18.37 commit
0c503cf3dde2 - SVEIntroduction to SVE
- SMEScalable Matrix Extension introduction
- LinuxSVE userspace ABI