나는 $130 채굴 카드에서 Qwen3.5-27B를 실행하기 위해 맞춤형 CUDA 추론 엔진을 작성했다

발행: (2026년 5월 3일 PM 01:42 GMT+9)
10 분 소요
원문: Dev.to

Source: Dev.to

Overview

나는 중고 시장에서 NVIDIA CMP 100‑210 카드를 한 장당 약 $130에 네 장 구입했다.
이들은 Volta GV100 다이 기반의 채굴 전용 카드이며, V100과 동일한 실리콘을 사용하고, 각각 16 GB HBM2를 탑재하고 있다. 명세상으로는 네 장을 합쳐 64 GB HBM2를 단일 중고 RTX 3090 한 대 가격에 얻을 수 있다.

실제로 NVIDIA는 하드웨어 수준에서 이들을 제한했다.

스로틀

  • Tensor‑core 스로틀링: 64× 속도 저하.
    • HMMA 지연이 8 cycles → 512 cycles 로 늘어남.
    • cuBLAS WMMA는 ≈ 5 TFLOP per card 로 제한됨.
  • PCIe: Gen1 ×1 로 고정됨.
  • P2P 없음, NVLink 없음.
  • CUPTI: 차단 → NVIDIA 프로파일러 사용 불가.

스루틀은 다이 상의 e‑fuse + PMU 부트‑ROM 이중 잠금으로 강제 적용됩니다 – 펌웨어 스위치가 아닌 하드웨어 수준의 잠금입니다. 소프트웨어 언락은 존재하지 않음 (시도해 봤음).

결과: cuBLAS 텐서 코어를 통하는 모든 작업이 1/64 속도로 실행되거나 즉시 실패합니다. 포함되는 항목:

  • vLLM
  • llama.cpp의 기본 cuBLAS 경로
  • FlashAttention
  • bitsandbytes
  • PyTorch의 기본 matmul

따라서 표준 LLM 추론 스택은 이 하드웨어에서 사용 불가합니다.

우회 방법

Only the tensor cores are throttled. Two other execution paths on the same chip run at full speed:

경로설명성능스로틀
DP4A4‑방향 패킹된 int8 점곱≈ 17 TFLOP없음
HFMA22‑방향 패킹된 fp16 융합 곱셈‑덧셈≈ 24 TFLOP없음

두 경우 모두 정상적인 V100의 텐서 코어와는 일치하지 않지만, 두 경우 모두 5 TFLOP cuBLAS WMMA 한계치를 훨씬 초과합니다. 모든 추론을 이 두 경로로 라우팅함으로써 제한되지 않은 V100 성능의 약 50 %를 회복할 수 있습니다 – 여전히 아무것도 하지 않는 것보다 훨씬 좋습니다.

qengine 소개

qengineQwen 3.5 / Qwen 3.6 하이브리드 모델용 처음부터 만든 CUDA 추론 엔진입니다. (참고: Qwen 3.5/3.6은 dense GDN + Attention 아키텍처를 사용하며, 순수 트랜스포머가 아니기 때문에 커널이 다릅니다.)

특징

  • 프리필을 위한 Hand‑written Q8_0 GEMM 타일 경로전부 DP4A.
  • Fused FlashAttention 커널 (score + softmax + value) – 단일 패스.
  • 긴 컨텍스트를 위한 Split‑K FlashAttention.
  • 3‑bit Walsh‑Hadamard + Lloyd‑Max KV 캐시 → 27 B 모델이 256 K 컨텍스트를 세 개의 16 GB 카드에 맞출 수 있음.
  • OpenAI‑호환 HTTP API (스트리밍, 툴 호출, 비전, 연속 배칭, 슬롯별 프리픽스 캐시 지원).

모든 커널은 sm_70(CMP 제약)용으로 작성되었으며 기존 라이브러리의 포크가 아닙니다.

정직한 벤치마크

Comparison: qengine vs. llama.cpp (빌드 8462, -fa 1, 동일한 Q8_0 GGUFs, 동일한 하드웨어). 숫자가 클수록 좋습니다.

Prefill

모델 / 프리필 길이토큰 / 초 (qengine)토큰 / 초 (llama.cpp)속도 향상
Qwen 3.5‑9B – 297 tokens5941992.99×
Qwen 3.5‑9B – 1.16K tokens6833162.16×
Qwen 3.5‑9B – 4.62K tokens5843611.62×
Qwen 3.5‑9B – 18K tokens3933241.22×

qengine은 처음 세 길이에서 앞서며 18 K에서 동등한 성능을 보입니다.

Generation Throughput

모델토큰 / 초 (qengine)토큰 / 초 (llama.cpp)향상
9 B≈ 7046.6+48 %
27 B26.317.7+51 %

약점: 9 B 듀얼‑GPU에서 18 K는 여전히 llama.cpp보다 뒤처집니다 (~0.48×). 그 이유는 llama.cpp가 활성화 전송을 연산과 겹쳐 수행하는 반면, qengine은 고정된 호스트 메모리를 통해 순차적으로 전송해야 하기 때문입니다 (P2P 없음). 싱글‑GPU 9 B는 이미 듀얼‑GPU 실행보다 빠르므로 차이는 대부분 이론적인 것입니다.

구현 과제

1. Multi‑GPU without P2P

  • CMP 카드들은 peer‑to‑peer와 NVLink를 지원하지 않는다.
  • 숨겨진 상태는 pinned host memory를 통해 GPU 간에 왕복해야 한다.
  • 해결책: 교차‑GPU 엣지당 하나의 pinned‑host 버퍼와 GPU당 하나의 워커 스레드를 배치한다. 작동은 하지만 순차적으로 진행된다.

2. Numerical Drift Killing Korean Output

  • Qwen 3.5‑9B의 한국어 회로는 약해서, 작은 fp16 재정렬 노이즈가 argmax 결정을 뒤바꿔서 한국어가 뒤죽박죽이 된다.
  • 영어 테스트를 통과한 후에 수행한 chunked‑prefill 커널 최적화가 한국어를 깨뜨렸다.
  • 해결책: attention‑reduction 순서를 건드리는 모든 커널이 Korean argmax‑stability check를 수행하도록 하여, 출력을 전송하기 전에 검증한다.

3. Split‑K FlashAttention without Breaking Determinism

  • 기존 64‑block FA 그리드는 긴 컨텍스트에서 SM을 충분히 활용하지 못했다 (3 × 68 SM = 204 중 64 블록만 사용).
  • (kv_head, t_idx)N개의 독립 블록에 매핑하고, 각 블록이 연속 타일 범위를 처리하도록 하는 split‑K 변형을 추가했다.
  • 부분 결과를 log‑sum‑exp 항등식을 이용해 병합한다:
m_global = max_s m_s
l_global = Σ_s exp(m_s − m_global) · l_s
o_global = Σ_s exp(m_s − m_global) · acc_o_s
  • 첫 번째 버전은 부분 o 누산기를 half로 저장했는데, 약 31개의 토큰을 생성한 뒤에 drift가 발생해 (비비트 정확) 결과가 달라졌다.
  • 부분 누산기를 fp32로 저장하면 drift가 fp32‑재정렬 노이즈 수준(~1e‑7 per add)으로 감소해, greedy argmax가 32개 이상의 토큰에서도 안정적으로 유지된다.
  • 결과: 18 K prefill 속도가 270 → 393 t/s (9 B)와 104 → 139 t/s (27 B)로 향상되었다.

4. Speculative Decoding (still broken)

  • 레포에는 미래에 미세 조정된 drafter를 위한 DFlash + DDTree 코드가 포함돼 있다.
  • 사전 학습된 drafter (lucebox‑hub/dflash)는 기본 Qwen 3.5에 대해 학습됐으며, 우리 distill 출력 분포와 불일치해 accept rate가 ≈ 0 %에 머물고 체인이 붕괴된다.
  • README에 broken on purpose라고 명시돼 있다.
  • MTP K=1 단일 토큰 spec은 정상적으로 동작한다.

qengine을(를) 사용해야 하는 경우

상황추천
RTX 30/40‑series, A100, H100vLLM 또는 SGLang을 사용하세요 – 훨씬 더 최적화되어 있고 테스트 커버리지가 광범위합니다.
Ex‑mining cards (CMP 100‑210, ex‑mining V100, P104‑100, 등)qengine이 유용할 수 있습니다.
Older Volta workstations (V100 16/32 GB, Titan V, Quadro GV100)qengine이 작동합니다 (sm_70을 목표로 함).
T4 또는 RTX 20‑series에서 표준 스택이 실망스러울 때qengine이 도움이 될 수 있습니다.
DP4A가 없는 GPU (예: sm_60)지원되지 않음.
AMD / Apple GPU지원되지 않음.

qengine은 **sm_70**을 구체적으로 목표로 합니다. sm_75도 작동할 수 있지만 최적화되지 않았으며, sm_60은 DP4A가 없어 실행할 수 없습니다.

Silicon Definitely Won’t Work

Repo
https://github.com/Haru-neo/qengine — Apache 2.0

이 게시물의 벤치마크는 저장소에 있는 bench_curl.sh 스크립트를 사용하여 재현할 수 있습니다. 27 B 3‑GPU 수치는

  • 내 컴퓨터에서 2026‑05‑03에 측정되었습니다.
  • 하드웨어가 있다면 직접 시도해 보시고, 결과를 알려주시면 감사하겠습니다.

프로젝트 세부 사항

  • 단독 프로젝트.
  • CUDA에 대한 AI 지원이 많이 필요했습니다 — 저는 아키텍처 설계, 프로파일링, 디버깅을 여러 세션에 걸쳐 주도했으며, Claude가 대부분의 커널 구현을 담당했습니다.
  • 저는 한국 고등학생입니다.
  • PR(풀 리퀘스트) 처리 속도가 느립니다.
0 조회
Back to Blog

관련 글

더 보기 »