한 워크스테이션의 빌드 로그: 이 하드웨어로 실제로 무엇을 할 수 있는지, 측정한 것만 적는다.
순서는 생성 워크로드가 로컬 하드웨어에 들어맞는 대로 — 대규모 언어 모델 먼저, 그 다음 영상·이미지·오디오. 모든 기록에는 실행한 명령줄, 측정한 처리량, 그리고 틀렸던 점이 들어간다. 숫자 하나하나는 이 기계에서, 명시된 날짜에 측정된 것이다. 도출된 값이면 도출됐다고 밝히고, 틀린 기록은 지우지 않고 선을 그어 정정한다. 조용히 고쳐 쓰는 로그는 가치가 없다.
미출시 모델을 맞지 않는 하드웨어에서 돌리면 남의 테스트 안 된 경로를 정면으로 밟는다. 그래서 이 로그의 나머지 절반은 업스트림로 돌려보낸 것이다. 방법과 보낸 기록은 docs/upstream-contributions.md에 있다.
기록은 날짜순으로 log/에 있다. 다른 보기 — 모델·엔진별 속도표는 docs/engine-rates.md에서. 이 리포 안은 한국어로 쓴다. 리포를 나가는 글(업스트림 이슈·PR 본문, 업스트림가 읽을 코드 주석)은 계속 영어다.
Qwen3.8-Flash-Next: 125 B 파라미터에 51 B n-gram 테이블, UD-Q4_K_XL 103.7 GiB, draft 모델 없이 51.0 tok/s — draft를 쓰는 서빙 중인 DeepSeek-V4.1의 두 배를 4분의 1 바이트로 낸다. 카드에는 다 안 들어간다. 3090에 20.5 GiB, A6000에 46.6 GiB, 시스템 RAM에 39.7 GiB — 오른쪽 패널이 동작 중인 그 분할을 보여준다. 전문
같은 상자의 다른 끝. Qwen3-Coder-Next IQ4_XS 39.7 GiB는 A6000 한 장에 컨텍스트 32k와 함께 들어가 133 tok/s로 디코딩한다. 그 프레임에서 3090은 0.0 GiB다. 전문
두 클립 모두 실행의 닫는 구간이다. 프레임 수÷30이 아니라 저장된 프레임별 지연을 합해 잰 길이를 쓴다. 클립을 짧게 할 때는 줄이지 않고 앞에서 잘라낸다. 실행을 짧은 시간에 구겨 넣으면 스톨이 가려져 기계에 대한 거짓말이 된다. toktape 0.2.3-5-g9bf4e52로 녹화·렌더링했고, 파일명이 담는 것은 녹화기 빌드다. 속도와 길이는 정정 가능해야 하니 산문에 둔다.
서빙 프로파일 한 장 요약: 마흔 레이어의 routed expert가 어느 티어에 있는지, 어디에도 안 올라가는 engram 테이블 두 개, 두 번째 카드의 값을 잰 네 갈래 실행. 원본과 재촬영 방법은 assets/placement-sheet.html.
현재 상태. 바뀌기 전 모습과 바꾼 실행 기록은 docs/machine-changes.md에 있다.
| CPU | AMD Ryzen Threadripper PRO 5975WX, 32 cores / 64 threads. Boost disabled, no clock cap |
| Memory | 256 GB DDR4-3600 at DRAM 1.30 V — 32 GB × 8, all 8 channels, Samsung M378A4G43AB2-CWE 2Rx8 UDIMM, non-ECC |
| Measured memory read | 147.7 GB/s (32-thread, 8 GiB read probe); 230.4 GB/s theoretical. A second probe reads 144.8, and that is the one toktape's host percentages are derived against |
| GPU 0 | NVIDIA RTX A6000, 48 GB, bus 61 |
| GPU 1 | NVIDIA GeForce RTX 3090, 24 GB, bus 41 |
| Device order | By UUID, never by slot. Every runner sources configs/gpu-order.env, which pins CUDA_VISIBLE_DEVICES=<A6000 UUID>,<3090 UUID> so CUDA0 is the 48 GB card whatever the bus addresses are. nvidia-smi does not honour that variable and is addressed with -i <UUID> |
| Board | ASUS Pro WS WRX80E-SAGE SE WIFI |
| Storage | Samsung 980 PRO 2 TB NVMe (root) + Phison E18 4 TB NVMe (/models) |
| Case | 3RSYS T840 |
| Power | Super Flower Leadex Platinum SF-2000F14HP, 2000 W |
| Cooling | ARCTIC Freezer 4U-M tower air cooler on CPU_FAN. No chassis fan is on a header — the case fans are wired to the PSU, so all six CHA_FAN channels read Disabled. Fan RPM and per-slot temperature are readable only through the BMC (ipmitool sdr type fan, sdr type temperature; the PCIE0n sensors read when the GPU driver cannot) |
| OS | Ubuntu 24.04, kernel parameter pci=realloc=off |
하루씩 잡아먹고 아직도 유효한 것 네 가지:
pci=realloc=off필수. 없으면 커널이 PCI 리소스를 재배정하면서 칩셋 USB가xhci init -16으로 죽고 10GbE 포트가 내려간다.pci=nocrs는 USB를 살리고 NVIDIA 드라이버를 깨뜨린다.- X550 10GbE 포트는 sustained 부하에서
Tx Unit Hang. GRO·TSO·GSO·LRO를 인터페이스에서 끄기 전에는. - 섀시 팬은 커브 불가. 케이스 팬이 PSU 직결이라 여섯
CHA_FAN채널이 전부Disabled고, 하나가 죽어도 보이지 않는다.지속 부하에서 A6000이 86–87 °C를 유지하고2026-09-16 선 그음: 증인에 팬 속도를 안 넣고 쓴 문장이다. 87 °C는 카드의 95 °C slowdown 근처도 아니고, 자기 목표 84 °C보다 5 °C 위일 뿐이며, 그 이유는 팬 커브가 느려서다. GPU 팬은 NVML로 headless 제어 가능(SW Thermal Slowdown이 약 100% 시간 켜져 있으니, duty cycle 100%인 작업은 시작하기도 전에 스로틀링 상태다.tools/gpu-fan.py, 커브tools/gpu-fan-curve.py) — 램프 안에 끝나는 작업에 16 °C어치, 수렴할 때까지 도는 작업에는 0이다(측정). - PSU 공개 스펙은 ATX12V 2.2 / EPS12V — 네이티브 12V-2x6 커넥터 없음. 벤더 시트에서 읽은 것이지 여기서 측정한 게 아니다. 해당 커넥터를 원하는 카드를 사기 전에 실물 확인.
미해결 질문은 하나로 좁혀졌다. NCCL DDP에서 3090이 버스에서 떨어지는 이유. 2026-09-18에 세 번 재현하고 후보를 걷어냈다. 버스 트래픽 아님 — 핀 메모리 DMA가 15분간 37 GB/s를 유지해도 멀쩡했고, DDP 실제 이동량의 수백 배다. 지속 전력 아님 — 고장은 384 W에서 났고 419 W 15분은 멀쩡했다. 온도 아님(67 °C). 링크 아님 — 전후 에러 레지스터가 동일하고, A6000의 Xid 154는 카드별 고장이 아니라 시스템 전역 플래그다. 남은 것은 집합체만 만드는 것 — 두 카드가 배리어에서 함께 기다렸다가 같이 끌어당기는 동기 transient. 양쪽을 250 W로 묶으면 같은 DDP가 900초 깨끗이 돈다(단일 카드 대비 1.51배, 무제한 1.85배). 동작하는 설정이지 증명은 아니다. 재현, 조사, 확정·미확정.
한 행도 이 박스에서 측정하지 않은 것은 없다. 전체 표는 docs/engine-rates.md.
| 모델 | 조건 | decode | 기록 |
|---|---|---|---|
| DeepSeek-V4.1-Flash, 서빙 프로파일, draft | ik_llama.cpp | 25.05 tok/s, warm | log |
| Qwen3.8-Flash-Next 125B, UD-Q4_K_XL, draft 없음 | 양 카드 + 시스템 RAM | 51.1 tok/s | log |
| Qwen3-Coder-Next, IQ4_XS | A6000 단독, 컨텍스트 32k | 133 tok/s | log |
| Qwen3.6-35B-A3B, UD-Q6_K, 1스트림 | ik 129 / mistral.rs 111 tok/s | 129 / 111 | log |
| 같은 모델, 8스트림 합계 | ik 152 / mistral.rs 324 tok/s | 152 / 324 | log |
| GLM-5.3-Flash, expert 10층 온카드 | ik_llama.cpp | 18.7 tok/s | log |
| GLM-5.3-Flash | ExLlamaV3 -mcs 195 |
22.2 tok/s | log |
| DeepSeek-V4.1-Flash 첫 가동, engram 84 GB 미적재 | mainline llama.cpp, NVMe에서 행 단위 적재 | 20 tok/s | log |
- 347 GB 모델 중 84 GB를 드라이브에 둔 채 20 tok/s. DeepSeek-V4.1-Flash의 engram 테이블은 메모리에 전혀 안 올라가고 NVMe에서 수십 행씩 읽어낸다. 전문
- ik-vs-mainline 20% 격차는 페이지 폴트였다. engram 행을
posix_madvise(WILLNEED)로 예열하자 토큰당 폴트 41–62개→1–11개, 격차는 노이즈로 사라졌다. 전문 - 서빙 프로파일의 프리필은 ubatch가 2.1배, 엔진이 1.15배.
-ub 1024→4096이 11.9k 프리필을 ik에서 236→500 tok/s로 올리고, 디코드는 그대로. 같은 날 서빙에 반영(12k 문서 TTFT 50→25초). 전문 - 3090을 빼는 비용은 디코드의 3% 미만, warm 행에서는 0.3%. 20 GB는 다른 카드가 아니라 호스트가 흡수한다. 전문
- 프롬프트 캐시는 13k 접두사에서 깨진다. Hermes 턴 하나가 13,167 토큰 cold prefill(285초)인데, DeepSeek 파서가 user 구분자를 공개하지 않아 그 앞을 고치면 전체를 다시 읽는다. 9줄 패치로 13,145/13,161 토큰 재사용, 13.8초→0.8초. 전문
- 팬 커브는 3.7분 늦게 도착한다. 카드 자체 커브가 100%에 도달하는 데 그만큼 걸리고, 그 사이 다이는 목표 84 °C보다 최대 5 °C 위에 있다. 처음부터 100%로 고정하면 137초 테이크에서 16 °C, 네 시간짜리에서는 0이다. 전문
- 기계번역은 천 단어당 4.7개 문장의 의미를 바꾼다. 1,711단어 문서에 8건, 전부 유창한 한국어라 구조 게이트는 한 건도 못 잡는다. 번역기는 초안이고, 리드가 읽어야 확정이다. 전문
- 3090 버스 이탈은 133초 만에 재현된다. 드라이버 소스를 읽어 Xid 79·154에 대한 기존 주장 세 개를 정정했고, 남은 것은 동기 transient 가설과 250 W 캡 회피책이다. 전문
실험당 한 파일, 날짜순. 칸 하나는 그날 무엇이 판명됐는지 한 줄과 그것을 대표하는 수치 하나다 — 상세는 항목이 진다. 색인이 항목을 요약하려 들면 색인이 자란다(2026-09-11 47자에서 2026-09-17 2,569자까지 아무도 결정한 적 없이 자랐다).
| 날짜 | 기록 | 무엇이 판명됐나 |
|---|---|---|
| 2026-09-11 | 두 GPU와 256 GB RAM에 걸친 284 B 모델 | routed expert를 층 단위로 두 카드와 호스트에 나눠 29 tok/s |
| 2026-09-12 | 347 GB 모델, 84 GB는 드라이브에 둔 채 | engram 테이블 둘이 RAM에 안 올라가고 NVMe에서 읽혀 20 tok/s, 토큰당 3.3 ms |
| 2026-09-12 | 10분마다 리셋되던 기계 | BIOS가 건 OS Load 워치독을 OS가 인계 안 받아 9분 수명 부팅 넷. 끄지 않고 인계받았다 |
| 2026-09-12 | 캐시만 재던 디스크 벤치 | 버스트는 동일, 갈리는 건 4분 뒤 하한 3.70 대 1.47 GB/s. 벼랑 전에 멈춘 벤치는 캐시 크기를 보고한다 |
| 2026-09-12 | 이사 하나, SSD 하나로 겹친 단절 | 독립된 고장 둘이 각각 네트워크를 막기에 충분했다. 20시간 암전 |
| 2026-09-13 | V4.1을 ik_llama.cpp에 이식 | 빌드 열 개와 틀린 그래프 둘 끝에 PPL 2.2258 대 오라클 2.2438 |
| 2026-09-13 | engram 테이블만 Q8_0으로 되돌리기 | 아무도 안 읽는 125 GB를 더 쓰고 PPL 6% — 안 읽히는 바이트는 품질을 안 산다 |
| 2026-09-14 | AIO가 나가고 공랭이 들어오다 | 냉각수 40도 후반에 warn cpu=89C가 두 번 찍힌 뒤 교체 |
| 2026-09-14 | 메모리 클럭 3200 → 3600 | 읽기 131 → 148 GB/s, 3666 위로는 세 번 다 실패 |
| 2026-09-14 | ik 격차는 페이지 폴트였다 | engram 행 prefetch로 첫 패스 13.6 → 18.4 tok/s, 토큰당 폴트 41–62 → 1–11 |
| 2026-09-15 | 서빙 모델 프리필: ubatch가 2.1배 | -ub 1024 → 4096이 11.9k 프리필을 ik에서 236 → 500 tok/s, 디코드는 불변 |
| 2026-09-15 | 서빙 노브 여섯 개 스위프 | 서는 것은 현재 프로파일 하나뿐 — 나머지 다섯은 대역 안이거나 손해 |
| 2026-09-15 | 한 카드에 통째로 드는 모델 | 132 tok/s, 그리고 어떤 노브로도 안 움직이는 상한 |
| 2026-09-15 | 2.7 GHz 클럭 캡 해제 | AIO 루프용 열 대책이었고 루프가 갔다. 캡 없는 히어로 테이크 |
| 2026-09-15 | GLM-5.3-Flash 첫 숫자 | 디코드가 대역폭-bound가 아니다 — 스레드 스위프가 평탄 |
| 2026-09-15 | llama-server 표면 뒤의 ExLlamaV3 | TabbyAPI time_generate가 무엇을 재는지 확인하고 exl3 베이스라인 확보 |
| 2026-09-15 | V4.1 이식을 PR 둘로 나누다 | 리뷰 가능한 단위로 쪼갠 것이 업스트림 조건이었다 |
| 2026-09-16 | 남긴 모델 전부 재검증 | 1.3 TB를 지우고 슬롯·클럭이 바뀐 상자에서 남긴 파일마다 한 번씩 로드 |
| 2026-09-16 | 석 달 된 Qwen 두 모델 | 125B에 51 tok/s — 활성 6B에 n-gram 테이블 51B라 헤드라인 파라미터가 속도를 안 말한다 |
| 2026-09-16 | 4스트림이 서로 다른 행을 원할 때 | engram 행이 fresh 텍스트에 디코드 6.8%, 토큰당 major fault 22.1개 |
| 2026-09-16 | 열 부팅의 밤, 마진 밖 슬롯 하나 | 3090이 Xid 79로 버스에서 떨어지고 드라이버가 양 카드에 Xid 154를 찍었다 |
| 2026-09-16 | 3090을 빼면 잃는 것 | expert 20 GB어치, 디코드 손실 3% 미만(warm 0.3%) — 호스트가 흡수한다 |
| 2026-09-16 | 24 GB 카드 단독 서빙, 그리고 시트의 결함 | 48 GB 카드를 디퓨전에 비우려고 서빙을 작은 카드로 옮겼다 |
| 2026-09-16 | 같은 크기의 두 거인, 그리지 못한 모델 | 이 기계 첫 이미지 생성. 크기가 같아도 할 수 있는 것이 다르다 |
| 2026-09-16 | 고치지 못한 13.5배, 목표에 닿은 팬 | guidance가 살 수 없던 것과, 팬을 100%로 고정해 얻은 것 |
| 2026-09-16 | 한 카드 세 체제, 3.7분 늦는 팬 | 136초 실행 하나에 체제 셋. 팬 커브 지연이 램프 안 작업에 16 °C |
| 2026-09-17 | 24 GB 카드가 기계에서 나오다 | 마지막 검사가 뭐라 했는지와, 전원이 10초 먼저 나가 못 말한 것 |
| 2026-09-17 | 같은 카드 위의 Rust 엔진 | mistral.rs가 단독은 느리고 4스트림에 두 배 — thinking off가 꺼진 적 없다는 실행 증명 |
| 2026-09-17 | 4스트림 격차의 실제 자리 | 격차는 엔진이 아니라 배치 경로에 있었다 |
| 2026-09-17 | mistral.rs의 오프로드 한계 | 텐서 단위 배치가 아예 없고, MoE 한 층을 호스트에 두면 모든 요청이 실패한다 |
| 2026-09-17 | 엔진마다 오프로드가 무엇을 무는가 | 층·토큰당 ik 0.20 ms 대 mistral.rs 442 ms — 둘 다 호스트 연산이지 GPU 읽기가 아니다 |
| 2026-09-17 | 프롬프트 캐시는 13k 접두사에서 깨진다 | 9줄 패치로 13,145 토큰 재사용, 턴당 13.8 → 0.8초 |
| 2026-09-18 | 24 GB 카드가 같은 슬롯에 돌아오다 | 재장착 검사와 양 카드 상태 복귀 |
| 2026-09-18 | DDP 버스 이탈을 133초에 재현 | 드라이버 소스로 Xid 79·154에 대한 기존 주장 셋을 정정했다 |
| 2026-09-18 | 이 기계가 자기 로그를 번역하다 | 구조 게이트를 통과한 번역에도 천 단어당 4.7건의 의미 변경이 남는다 |
| 2026-09-19 | Rust로 쓴 첫 커널, 두 모델에 같은 스펙 | cuda-oxide Q3_K gemv가 3090에서 ggml mmvq의 1.86배(620 대 333 GB/s, M=8은 1.20배). 네 라운드 열 팔, 하루: 0.40 → 1.05 → 두 팔의 직교 레버를 합쳐 1.86; 4라운드는 CPU AVX2 gemv(ggml의 1.1배 이상, 147.7 GB/s '천장' 정정)와 cuda-oxide ICE 원인 두 줄 |
| 2026-09-19 | 구분자가 콜드 프리필에 물리는 값 | 기본값에서 1.13배, min-step 0에서 3.26배 — 값이 막혀 있던 쪽은 설정이었다 |
| 2026-09-19 | 우리 엔진이 처음으로 토큰을 골랐다 | V2-Lite 전체 순전파, 프롬프트 32개 중 31개가 ik와 같은 토큰. 첫 tok/s 0.0521, 오차는 블록을 따라 누적되지 않는다 |
| 2026-09-19 | 디코드가 평평해졌다 | KV 캐시로 5.26배(0.0519 → 0.2730 tok/s), 스텝 폭 84.5 % → 0.5 %, 로짓은 모든 분할에서 비트 동일 |
| 2026-09-19 | 시간이 어디로 가는지 먼저 잰다 | 디퀀트가 내적보다 크다(56 : 44) — 지렛대는 빠른 f32 내적이 아니라 융합 int8 커널. 토큰과 무관한 가중치 준비가 스텝의 8 %, 병렬화 뒤엔 69 % |
| 2026-09-19 | 15.3배 — 행을 32코어에 나누다 | 0.2730 → 4.1639 tok/s, 스레드 1·3·32의 로짓이 바이트 동일. 스레드 수는 32(물리 코어)로 확정 — SMT 64는 3.7배 느리고 절반이 스핀 탓이다 |
| 2026-09-19 | 융합 커널이 돈다 | 커버리지·커널·배선 세 라운드: 4.1639 → 4.5369 tok/s, Q3_K dequant 0.00. 게이트가 처음으로 바이트가 아니라 밴드를 지킨다 — 융합 경로가 더 정확해서 로짓이 움직인 것을 설계로 받았다. 다음 지렛대는 스텝의 13%를 먹는 디스패치·동기·게더(~28 ms) |
| 2026-09-19 | 합류를 분해한다 | 4.5369 → 4.8046 tok/s, 로짓 비트 불변(재핀 0). 스핀 스윕이 정책을 못박는다 — 파킹은 실제 비용(spin=0 −9.4%)이는데 더 참으면 대역폭을 훔친다. 워커의 out 직접 쓰기로 게더 7.4→2.1 ms, 남은 잔여 41 ms는 디스패치 횟수의 함수 — 다음은 MoE 배칭 |
| 2026-09-19 | 디스패치를 접는다 | 4.8046 → 5.4834 tok/s(+14.1%), 로짓 비트 불변. 전문가당 3번의 풀 디스패치를 층당 2번으로 — 디스패치 1089 → 673/스텝, 배칭 사이트 잔여 3.4 ms로 "잔여는 횟수의 함수"가 측정으로. 관측: 프리필 −27%(원인 미상), 64스레드 6.39(스프레드 53%) |
| 2026-09-19 | 디스패치를 또 접는다 | wv_b 헤드 16콜을 층당 1번으로 — 디스패치 673 → 268/스텝, 어텐션 잔여 13.9 → 2.9 ms, 재핀 0 3연속. 그러나 비프로파일 스텝은 안 움직였다(186.2/186.3 재현) — 워커 파킹 ~930/스텝 불변, 접착부 길이가 파킹을 묶는다. 다음은 Q4_K 융합(17.4 ms) |
| 2026-09-20 | 속성 하나로 73% | 융합 커널이 SSE2로 컴파일되고 있었다 — #[target_feature] 부재, 인트린식은 에러 없이 느려진다. 벤치 0.3 → 10.8 GB/s(코어당 36배), 엔진 5.37 → 9.28 tok/s, 남은 배수 8.9배. T=1 회귀와 프리필 회귀의 정체도 이것. 다음: Q4_K·Q5_0 융합, 이번엔 이식을 넘어서(벤치가 ik 기준률을 이길 때까지) |
| 2026-09-20 | 측정 단위가 먼저 무너졌다 | 스레드 재판정 — 32 유지(열 통제 시 32가 다시 앞서고, 64의 스프레드 44.8%가 우위를 삼킴). 발견: ① 러너 첫 구간이 16~25% 빠르다(부스트/열) — 같은 섹션 안에서만 비교할 것, ② 스텝이 ctx와 선형 증가(ctx 6→101에서 103→285ms) — 실서빙 관문 |
| 2026-09-20 | ctx가 길어도 평탄하다 | flash_attn을 (토큰,헤드) 행 공간으로 풀에 병렬 — 재핀 0. N=96에서 5.74 → 10.10 tok/s(1.76배), 스텝 폭 176.8%→21.2%(기울기 ~1.9→0.21ms/토큰), N=8은 10.61. 사이트 73.8→6.9ms/스텝. 남은 배수 ~7.8배. 다음: **Q4_K 30%·Q5_0 23%**가 스텝의 절반 |
| 2026-09-20 | 진짜 짝을 찾아 배선한다 | Q4_K 융합 — 오라클의 실제 짝 q8_2_x4로(인코더 ik와 2304바이트 비트 동일, 미러는 인트린 에뮬레이터, ik 커널과 1 ULP). 재핀 2, 둘 다 A/B 입증: argmax 31/33→33/33(첫 완전 일치), l_out 꼬리 밴드 2.5e-2→7e-2. N=8 10.61→14.87 tok/s, N=96 10.10→14.06(1.4배), 같은 임대 ik 78.07/83.00 — 남은 배수 5.2/5.9배. Q4_K 스테이지 29.8→3.6ms(8.3배), 프리필 17.63. 커널 단일코어률은 진다: 14.1 vs ik 16.3–17.1(직접 재측정) — 갭은 코드젠, MUL-26 교훈은 피호출 헬퍼에도(누락 시 0.6 GB/s). 새 머리: Q5_0 23.1ms(32.5%) |
| 2026-09-20 | 두 트랙를 같은 날에 깐다 | 첫 서브에이전트 병렬 라운드(worktree+BLOOMERY_REMOTE 두 트랙, 측정·통합은 메인). Q6_K(qY 변형, 재핀 0, 커널률 ik의 95%) · Q5_0(짝=q8_2_x4, k%256이 아닌 사이트의 계약을 타입별로 — 이 조건이 없으면 스테이지 머리가 발화조차 안 함, 발산 집합 {14}로 1핀). 병합 뒤 N=8 14.87 → 24.52 tok/s(1.65배), N=96 22.25, 스텝 67 → 40.8ms, 프리필 32.0 — 남은 배수 3.4배(ik 82.72 같은 임대). 새 머리: q_nope2 11.0ms(26.7%), 부검 완료(셀 병렬 = 비트 동일) |
| 2026-09-20 | flash가 무너지고 직렬이 사라졌다 | 백그라운드 병렬 3트랙 완주(머지 순서: 재핀 없는 것 먼저, flash 재핀 마지막). MUL-36 flash SIMD(kq 8레인 합순서, V는 j축 — 발산 {14}→{24}를 BLOOMERY_FLASH_SIMD=0 한 실행으로 A/B 입증, flash 사이트 6.01→0.40ms/step=15배) · MUL-37 직렬 quant 풀 이양+gate/up 이중양자화 제거(ptr::eq, 비트 불변·재핀 0) · MUL-38 q_nope2 vpsignb 부호접기 maddubs(비트 동일·재핀 0, 벽 −0.07ms는 활용도 25% 사이트라 법칙대로). N=8 37.02, N=96 31.79→39.71(+25%), 스프레드 35.3→6.8%, 프리필 63.65 — ik 82.43/83.27 같은 임대, 잔여 2.10배, 세션 누적 9.55배. 조사 3트랙(Intel·AMD·광역) 동시 완료 → 다음 축 패킹, 그 다음 스펙 디코딩(docs/research/cpu-llm-ideas.md) |
| 2026-09-20 | 사이트 포화도 판정 | 진단 라운드(병렬 3트랙: 원장 분석 · 커널/디스패치 벤치 · GPU 정찰, 임대 창은 메인 단독 — ef9e579 보강의 첫 실전, 사고 없음). 대역폭 벽은 Q6_K(lm_head) 하나(119.3 GB/s = STREAM의 81%), flash 1위 사이트(18.8%)는 스칼라 벽(0.28 GB/s, 스프레드의 전부), 나머지 내적 사이트는 전부 오케스트레이션(풀 평균 가동 9.1워커) — 커널 MT 상한 122–136 GB/s, 디스패치 세금 1.5ms/step, 둘 다 무죄. 예측 변수는 디스패치당 바이트. 다음 축: flash SIMD(재핀) · 직렬 quant 풀 이양(비트 불변) · q_nope2 maddubs(비트 불변) → 유도 ~48 tok/s. MUL-30 판정: GPU는 cuda-oxide 확정(박스 완비, Q4_K CUDA 커널 이미 존재), cutile은 13.3 툴킷 뒤 |
| 2026-09-20 | 스테이지 표가 평탄해졌다 | 병렬 둘째 라운드. Q5_1(마지막 미융합 타입, 커널률 ik의 98-99%, 재핀 0, 사이트 12.6배) · q_nope2 셀 병렬(비트 동일, 8.4배) — 그리고 첫 판의 무한루프가 에이전트 둘을 '무활동'으로 죽였다: 매달린 게이트가 조용한 에이전트의 첫 용의자다. N=8 24.52 → 36.00 tok/s(1.47배), N=96 31.79, 스텝 27.8ms, 프리필 49.3 — 남은 배수 2.30배(ik 82.78 같은 임대). 스테이지 표에 지배 사이트 소멸(최대 22%), 모든 양자화 사이트 융합 완료. 다음: 배칭 사이트 포화도(47 GB/s 대 STREAM 147.7) |
| 2026-09-20 | 빨간 게이트가 0으로 끝나고 있었다 | 하루치 리뷰. 게이트 레시피 13개의 || echo가 4시간 37분 동안 실패를 삼켰다(그 안에 MUL-36/37/38 병합) — 종료 코드 소유자를 tools/gate.sh 하나로, 13게이트 재실행 전부 rc 0(숨은 빨강 없음). 주석 다이어트(qdot 1114→246줄, 이력 주석 137→0을 게이트로) · 디스패치 뼈대 분할. 틀렸던 것: agy 주석 라운드가 수치 계약을 지움(이후 조사 전용), GLM이 완료 마커를 번역, 그리고 뼈대 분할이 swiglu 사이트를 두 배로 만든 회귀 — 같은 임대 3-바이너리 A/B(하드닝 직후 38.49 대 분할 후 37.49)와 프로파일 대조로 찾고, 수정은 별도 같은 임대 A/B로 확인(37.66 → 39.14 tok/s, 네 바퀴 모두 승). 아침의 39.71은 저녁 창에서 같은 커밋으로도 재현 안 됨(37.56), 원인 미측정. 새 기록 없음 |
| 2026-09-20 | 청크 끝마다 락이 하나 있었다 | "ik를 넘을 지렛대"를 찾던 실험 둘은 빈손(n-gram 추측 디코딩: 수용 1.19토큰/스텝 대 손익분기 1.39, 전문가 합집합 k=4에서 0.715 · 거버너 schedutil↔performance 무차이). 세 번째 공짜 실험인 스레드 스윕이 평평했다(8스레드 39.7 = 32스레드 39.7, ik는 60→81) — 원인은 프로파일이 꺼져 있어도 모든 청크가 끝에서 잡던 수집용 Mutex<Vec>, 스텝당 401번의 futex 행렬. N=96 37.79 → 54.40 tok/s(+44%, 같은 임대 A/B 네 바퀴), 잔여 2.19 → 1.52배(ik 82.80). 이어서 mmap 프리폴트 56.05, 활성값 양자화의 rintf libm 호출 제거(perf: 메인 스레드의 10%) 61.48 tok/s — 잔여 1.35배. 프로파일러도 락 없는 슬롯으로(프로파일 실행 40.6 → 52.6) — 포화도 판정의 '디스패치당 바이트' 법칙은 이 락 아래서 잰 것이라 재측정 대상. 기각: 파킹(스핀 400만 무효), 폭 제한 디스패치(좁힐수록 느림), 동적 행 분배(54.4 → 46.5 이하), malloc trim(무변화) |
| 2026-09-20 | 메인 스레드가 곧 스텝이다 | ik를 perf로 보니 커널 스레드시간은 이미 같은 선(ik ~290 ms 대 우리 266 ms/스텝)이고 다른 것은 워커 이용률(75% 대 51%) — 메인 스레드의 직렬 구간이 곧 스텝 길이다. 그 절반이 할당·0 채우기: 스텝당 할당자 호출 14454번(전부 토큰과 무관한 일 — 헤드·전문가 뷰, 메타데이터 키 format!, ok_or가 매번 복제하던 이름). 버퍼 프리리스트로 11463번(속도 무변화), 이어서 그 일 전부를 로드 시점 플랜(Derived)으로 옮겨 1291번, +9.6%(66.11 → 72.48) — 래칫 게이트 gate-alloc. 헤드라인 N=96 72.30 tok/s 대 같은 임대 ik 81.79 → 잔여 1.13배(아침 2.10, 저녁 1.35). 위임 라운드 검수에서 잡은 것 둘: 풀이 블록을 매번 다시 0으로 채움, 무할당 에러 채널의 CAS-후-쓰기 경합. SwiGLU를 ggml_v_expf 포트 8레인으로 +4.0%(62.37 → 64.84), ik와의 argmax 발산 집합 {24} → {}; -C target-cpu=znver3 +4.8%(64.71 → 67.80), 비트 게이트 그대로. 기각: 내용 기반 입력 중복 제거(62.83 → 61.03), fat LTO(무차이). perf 함정 셋: IBS 귀속, -D는 해체 구간을 안 자른다(munmap 6%는 종료 비용이었다), 되돌린 실험의 바이너리를 프로파일함 |
| 2026-09-21 | 스큐 40%는 타이머였다 | N=96 78.80 tok/s 대 같은 임대 ik tg96 82.38 → 잔여 1.045배, 프리필 127.0 tok/s(이종 묶음 디스패치 matmul_q_group으로 층당 디스패치 −5, 디코드 +5.0% — 돌아온 트리는 프리필 −15%였고 레인 셋을 고쳐 +4%: 행 단위 경계 탐색, 열 수를 뺀 비용, 디스패치 단위 블록). 그 전 구간(76.97, 1.075배): "큰 것"이 세 번 연속 작았다: perf가 메인 스레드의 15.5%라던 활성값 양자화를 AVX2로(+0.9%), 풀 벤치 4.56 → 1.61 µs/디스패치(futex notify 생략 + 워커별 완료 표식, 디코드 무차이 — 빈 클로저의 µs는 스텝의 µs가 아니다), 레벨2가 말한 청크 스큐 20–40%에 맞춰 넣은 꼬리 훔치기(디코드 무차이, 프리필 +25%). 행별 타이머 없는 레벨1에서 다시 재니 스큐는 11%(1.06 ms), 장벽 0.58 ms였다 — 타이머 세금은 절대값만이 아니라 청크 길이 분포도 부풀린다. 산수: 계산 바닥은 ik와 같고(9.3 대 9.1 ms) 남은 0.9 ms는 얇게 퍼져 있다 |
| 2026-09-21 | 넘을 선은 기본값이 아니었다 | N=96 84.86 tok/s 대 같은 임대 ik 기본 82.78 ± 0.04, ik 최속 조합 84.19 ± 0.51 — 기본값은 넘었고(+2.5%) 최속 조합(-mla 3 -fa 1 -fmoe 1 -rtr 1, 다른 임대에서 84.55)과는 같은 선. 헤드 체인(q_nope2 → flash → wv_b)을 디스패치 하나로 +4.1%, 라우터 F32 내적과 rms_norm을 ik의 합 순서로 맞추니 빨라지면서 오라클과 비트 동일(3.8e-6·3.4e-5 → 0, 게이트를 0으로 조임). 도구: 비용 두 배 프로브 — perf가 메인의 14%라던 양자화는 1.3%였다 |
| 2026-09-21 | 버스가 곧 스텝이다 | 번갈아 잰 여섯 바퀴 85.96 대 ik 최속 조합 84.13 — 여섯 중 여섯, +2.2%. 16스레드로 줄여도 −5%, 디스패치 안의 버스는 127–147 GB/s로 이미 차 있다: 디코드는 대역폭에 묶여 있다. 활성값 양자화와 MoE swiglu를 행 디스패치 안으로(+1.4%, 레버를 끄면 ik와 같은 84.12). 2 MiB 페이지는 무차이, 익명 복사는 +1%였다가 잡음으로(옵트인). 노는 워커의 프리페치는 wo 스팬 −19%, MoE down +29%로 합계 −9.5% — 기각 |
| 2026-09-21 | 헤드라인은 깊이 0의 문장이었다 | 컨텍스트 깊이 4096에서 39.4 대 ik 64.4 tok/s(−39%) — -c의 +2.2%는 깊이 6–102에서만 참이고 교차점은 256과 512 사이. 새 러너가 깊이마다 두 엔진을 같은 임대에서 잰다: 우리 스텝은 캐시된 키당 3.4 µs, ik는 0.87 µs. 스레드 스윕의 무릎은 14스레드 — 균형점 k* ≈ 2.2로 bloomery 루프라인의 도출값 5.4·10.7에 선을 그었다. A/B의 자도 계산했다: 같은 바이너리 SD 0.6%, 여섯 바퀴 ±0.8%, ±0.5%는 팔당 23바퀴. SMT 48·64스레드는 −7%·−17% |
| 2026-09-21 | 분할은 틀린 축을 잘랐다 | kq 루프에서 다음 KV 행을 프리페치해 깊이 4096에서 39.72 → 42.24 tok/s(+6.3%), 1024 +1.9%, 깊이 0 무차이 — ik의 61%에서 65%로. 헤드 하나를 두 워커에 나누는 분할은 기각: 같은 바이너리 열두 바퀴로 깊이 0 −1.05% ± 0.56%, 깊이 1024 −2.1%, 4096 잡음 안. 분할이 나눈 것은 v_up 행이지 키 축이 아니었다. 전·후 비교는 잇따라 돈 두 실행이고 ik 팔이 공유 대조(0.5% 이내). 3090의 ik 기준선 216.6 / 204.6 / 189.7 tok/s(깊이 0/1024/4096, 유도 천장 700의 31%); CUDA 그래프를 끄면 −10.6% — 코드 독해는 "MoE 디코드에서 그래프가 꺼진다"였고 실측이 뒤집었다 |
| 2026-09-21 | 레이아웃은 힌트를 대신하지 못했다 | KV 캐시를 층당 연속 버퍼 하나로 — 깊이 4096에서 42.28 → 43.37 tok/s(+2.6%), 1024 +2.8%, 한 임대 세 팔 회전(ik의 67%). 같은 바이너리에서 소프트웨어 프리페치만 끄면 4096이 40.51(−3.8%) — 고정 보폭이 됐어도 하드웨어 프리페처가 그 자리를 채우지 못하니 -e의 "행별 Vec이 프리페처를 끊는다" 추측에 선을 그었다. 둘 다 남긴다 |
| 2026-09-21 | 누산기를 레지스터에 두었다 | flash V 누산을 8 ymm 타일로 뒤집어 깊이 4096에서 43.34 → 45.73 tok/s(+5.5%), 1024 +3.8%, 비트 동일을 쌍둥이 게이트로(ik의 71%). GPU 쪽: |
| 2026-09-21 | 트렐리스는 바이트만 샀다 | 3090의 ik CUDA에서 IQ3_KT 혼합은 같은 f16·같은 imatrix의 Q3_K_M보다 4.6% 작고, 2.2–2.6% 느리고(두 실행 같은 방향), PPL이 1.5% 나쁘다(9.231 대 9.098). 더 큰 차이는 묻지 않은 쪽: 기존 정적 파일 → ik 레시피 + imatrix로 PPL −3.6%, 속도는 1% 안(레시피와 imatrix가 섞여 있어 가르지 못함) |
미출시 모델을 맞지 않는 하드웨어에서 돌리면 남의 테스트 안 된 경로를 밟는다. 보낸 것과, 조사하고 일부러 보내지 않은 것의 전체 기록 — 다음 세션에게는 보내지 않은 쪽도 값어치가 있다 — 은 docs/upstream-contributions.md에 있다.
뮤직비디오를 이 기계에서 만드는 것이 다음 과제라, 큐는 그 비용에 대한 질문이 주다. 전부 측정값이 아니라 질문이며, 뒤의 숫자는 이 박스에서 잰 게 아니다. 목록은 docs/v41-experiment-plan.md와 트래커(WKS)에 있고, 여기에는 두지 않는다.
log/ 실험당 한 파일, 날짜순. 측정한 기록
configs/ 기계에서 실제로 돌아가는 스크립트, 그대로 복사
tools/ 기록 수단: VHS 테이프와 구동 스크립트
docs/ 긴 글: 업스트림 버그 서류, 방법, 하드웨어 노트
assets/ 클립과 시트
CLAUDE.md 이 리포에서 일하는 에이전트용 컨텍스트
상세 설명은 각 파일 머리말에 있고, 여기서는 이름만 적는다. 서빙 명령 configs/v41-serve.sh · 구형 V4 서빙 configs/llm-serve.sh · 처리량 측정 configs/tps.py · 모델별 러너 tools/v41/v41-take.sh tools/qwen38/qwen38-take.sh tools/ik/ik-vram-take.sh tools/exl3/exl3serve-take.sh · 모델 내려받기 tools/fetch-gguf.sh configs/hf-fetch/ · 전력 스위프 tools/ik/gpu-power-sweep.sh · 패브릭 부하·판독 tools/mem3600-load.sh tools/pcie-aer-snapshot.sh · GPU 팬 tools/gpu-fan.py tools/gpu-fan-curve.py · CUDA 순서 고정 configs/gpu-order.env · 벤치 서빙 configs/bench-serve.sh · 배치 시트 원본 assets/placement-sheet.html · GGUF 판독 tools/dequant-scan.cpp tools/gguf-region-scan.py · 온도 감시 configs/thermal-guard.sh. 긴 글 세 편: 처리량 모형 · V4.1 서빙 · 도구 인계 · 엔진별 속도 · 조용한 기계 · 보드 펌웨어.
측정하다 도구 부재에 부딪혀 두 번은 도구가 리포지토리까지 됐다. 둘 다 MIT, 포크 아님.
- toktape — 로컬 LLM 서빙용 블랙박스 테이프. 이미 돌아가는
llama-server에 붙어 한 실행을.tape에 담고, 모델 위치·프로세스가 실제 건드린 것·실제 속도를 카드에 찍는다. 이 README의 모든 클립이 이것으로 녹음됐다. 존재 이유: 증인 없는 tok/s는 — 배치, 폴트, 카드가 실제 잡은 클럭 — 누구도 검증 못 하고, 일주일 뒤 저자 본인도 못 한다. 이 리포는 공동 관리자가 아니라 까다로운 하류 사용자다. 손으로 모으는 증인이 필요해지면 로컬 우회가 아니라 toktape에 요구사항으로 보낸다. - exl3-serve — ExLlamaV3용
llama-server호환 HTTP 앞단. ExLlamaV3는 서버를 안 내놓아서llama-server용으로 쓴 것은 아무것도 EXL3 모델을 못 돌렸고, 녹음기도 마찬가지다. 한 EXL3 모델을 그 표면 —/props·/health·/slots·llama-servertimings를 exllamav3 자체 작업 결과로 채운/v1/chat/completions— 으로 서빙한 것이 여기서 엔진을 잴 수 있게 했다. 맞추는 데 든 값: 실모델만 드러낸 결함 네 개, 그리고 속도가 의미를 갖기 전에 먼저 측정해야 했던time_generate.
이 로그가 파일하는 트래커와 위키는 로컬 소프트웨어이기도 하지만, 기계보다 먼저 있던 범용 도구라 여기서가 아니라 CLAUDE.md에 이름을 적는다.


