[{"content":"지피지기면 백전불태 6편 : Agentic AI 시대, CPU의 부활과 CPU 삼국지의 시작 \u0026ldquo;상대를 알고 나를 알면 백 번 싸워도 위태롭지 않다.\u0026rdquo;\n이 시리즈는 AI 가속기 설계를 위해 경쟁사들의 하드웨어를 깊이 이해하는 것을 목표로 합니다.\n여섯 번째 글에서는 Agentic AI 시대에 다시 주목받는 데이터센터 CPU, 그리고 이를 둘러싼 Intel·AMD·NVIDIA 세 벤더의 경쟁에 대해 다룹니다.\n안녕하세요? HyperAccel DV팀 소속 하드웨어 검증 엔지니어 임재원입니다.\n오늘 글은 두 기업의 주가 차트로 시작해 보겠습니다.\n지난 4월 말, Intel이 1분기 실적을 발표하자 다음 날 주가가 하루 만에 24% 뛰었습니다. 1987년 이후 가장 큰 일간 상승폭이었습니다. 2주 뒤 실적을 낸 AMD의 주가도 다음 날 18.6% 올랐습니다. 두 회사의 실적 성장 뒤에는 공통점이 하나 있었습니다. 바로 CPU 였습니다.\nAMD의 데이터센터 매출은 전년 대비 57%, Intel은 22% 늘었고, 두 회사 모두 서버 CPU 수요 급증을 그 배경으로 꼽았습니다. AMD의 리사 수 CEO는 서버 CPU 시장이 2030년까지 1,200억 달러 규모로 커질 것이라 전망하기도 했습니다.\nGPU가 AI의 중심이라고 했는데, 왜 다시 CPU 이야기를 하는 것일까요?\n이 질문이 오늘 글의 출발점입니다. 지금까지 이 시리즈에서 다룬 가속기 구조와 여러 솔루션은 모두 \u0026ldquo;가속기를 AI 연산에 어떻게 최적화하느냐\u0026quot;에 대한 이야기였습니다. 그런데 추론 워크로드가 Agentic AI 로 옮겨가면서, 정작 이 최적화된 가속기가 오히려 일을 못하고 준비 상태로 기다리게 되는 역설이 나타나기 시작했습니다. 그리고 그 병목에는 생각지도 못한 CPU 가 자리잡고 있습니다.\n이번 글에서는 먼저 Agentic AI 시대에 CPU가 다시 병목이 된 이유를 짚어 본 뒤, Intel · AMD · NVIDIA 세 회사의 최신 데이터센터 CPU를 비교해 보며 GPU 전쟁에 이어 앞으로 이어질 CPU 전쟁에 대해 살펴보겠습니다.\nGPU만 늘리면 될까? : 다시 불려 나온 CPU 본격적인 이야기에 앞서, CPU와 GPU의 관계를 잠깐 짚고 가겠습니다. 우리는 흔히 AI 연산의 주인공을 GPU라고 생각하지만, GPU는 혼자서는 한 줄도 실행하지 못합니다. GPU는 본래 화면을 그리는 그래픽 연산을 빠르게 처리하려고 만든 보조 장치였고, 운영체제를 올리고 프로그램을 띄우고 무슨 일을 할지 지시하는 일은 처음부터 CPU의 몫이었습니다. CPU는 혼자서 컴퓨터를 돌릴 수 있지만, GPU는 자신을 먹여 주고 지휘해 줄 호스트 CPU 없이는 아무것도 하지 못합니다. PC에 그래픽카드를 꽂던 시절부터 지금까지 이 종속 관계는 지금도 변하지 않았습니다.\n이후 CUDA로 대표되는 GPGPU(General-Purpose computing on GPU)가 등장하며 GPU는 그래픽을 넘어 범용 연산까지 떠맡았지만, 그것이 CPU를 완전히 대체하려는 것은 아니었습니다. 무겁고 규칙적인 행렬 연산은 GPU가, 분기와 제어가 많은 나머지 일은 여전히 CPU가 맡는 분업이었죠. 그런데 AI 시대에 GPU의 몸값이 폭등하면서, 어느새 CPU는 \u0026lsquo;GPU를 먹여 주는 덜 중요한 부품\u0026rsquo; 정도로 취급되기 시작했습니다. 주연과 조연이 뒤바뀐 것처럼 보였습니다.\n하지만 GPU는 여전히 범용 장치가 아닙니다. 그리고 Agentic AI는 검색 엔진을 두드리고, 샌드박스에서 코드를 실행하고, 여러 도구를 조율하는, 어디에나 필요한 범용적인 일들을 끝없이 요구합니다. 이것은 GPU가 할 수 없고 CPU만이 하는 일입니다. 한동안 조연으로 밀려나 있던 CPU가 다시 무대 중앙으로 불려 나오고, 데이터센터 CPU를 둘러싼 새로운 전쟁이 시작되는 지점입니다.\nAI 연산에 병목이 생길 때 가장 흔하게 떠올릴 수 있는 해결책은 GPU입니다. 더 좋은 성능의 GPU, 더 많은 GPU로 인프라를 확장하는 것입니다. 모델을 한 번 통과시키는 것이 AI 애플리케이션의 전부이던 시절에는 대체로 맞는 처방이었습니다.\n그런데 최근 연구들은 조금 이상한 장면을 보여 줍니다. 한 연구에 따르면, agent가 도구를 호출하고 그 결과를 처리하는 시간이 워크로드에 따라 전체 응답 지연의 최대 88% 까지 차지했습니다. 그리고 이 도구 실행은 거의 전부 CPU에서 일어납니다. 정작 값비싼 GPU는 그 시간 동안 CPU의 실행 결과를 기다리며 놀고 있었던 셈입니다.\n더 흥미로운 것은 이를 해결할 방법을 보여준 또 다른 연구입니다. 여기서는 GPU를 단 한 장도 추가하지 않았습니다. 대신 GPU 하나에 배정된 CPU 코어를 1개에서 8개로 늘렸을 뿐입니다. 그러자 첫 토큰까지 걸리는 시간(TTFT)이 최대 5배 까지 빨라졌습니다.\nGPU를 더 늘리지 않고, CPU 코어 몇 개를 추가하는 것만으로 몇 배의 속도 차이를 보인 것입니다. CPU가 다시 컴퓨팅의 최전선으로 돌아온 것일까요? 다음 섹션에서 그 배경에 대해 알아보겠습니다.\n왜 CPU가 중요해지는가 : 단일 패스에서 agentic 루프로 CPU를 추가하는 것만으로 어떻게 이러한 성능 향상을 이룰 수 있었을까요? 답은 추론의 형태가 진화했다는 데 있습니다.\n지금까지 LLM 추론은 한 번의 경로로 끝납니다. CPU가 입력을 토큰으로 쪼개면, GPU가 모델을 통과시켜 답을 만들고, CPU가 다시 사람이 읽을 글자로 풀어냅니다. 이 구조에서 GPU는 거의 쉴 틈 없이 일합니다. CPU가 맡는 일은 앞뒤로 토큰을 변환하는 가벼운 작업뿐입니다.\nAgentic AI 는 이 그림을 바꿉니다. 에이전트는 모델의 답변을 내놓는 데서 끝나지 않고, 코드·문서·디자인 같은 결과물을 직접 만들어 냅니다. 이를 위해 계획을 세우고, 도구를 부르고, 결과를 본 뒤 다시 판단하는 과정을 여러 번 반복하죠. 이 과정에서 도구 실행과 검색, 코드 실행, 오케스트레이션, 재시도는 모두 CPU의 몫입니다. GPU는 모델을 빠르게 통과시키는 일에만 특화돼 있어, 그 한 순간을 빼면 나머지는 전부 CPU가 떠안기 때문입니다. 결국 GPU는 모델을 통과시키는 순간에만 일하고, CPU가 도구를 돌리는 동안에는 멈춰서 기다립니다.\n그렇다면 CPU가 떠안는 일은 구체적으로 무엇일까요? 크게 세 가지입니다.\n첫째는 정보 검색입니다. RAG(Retrieval-Augmented Generation)나 벡터 DB 조회, 데이터베이스 질의처럼 외부 지식을 찾아오는 작업입니다. 거대한 인덱스를 뒤지고 디스크와 네트워크를 오가는 일이기 때문에 메모리를 많이 소모하고, CPU에서 성능이 더 좋기 때문에 CPU가 주로 진행합니다.\n둘째는 코드 실행입니다. Agentic AI는 코딩 작업에 특히 많이 사용됩니다. 모델이 만든 코드는 사용자에게 전달되기 전에 정상적인 코드인지 확인하는 작업을 거칩니다. 이때 격리된 샌드박스(컨테이너나 별도 프로세스)를 띄워 그 안에서 파이썬이나 shell을 돌립니다. 이 역시 전형적인 CPU·운영체제 작업입니다.\n셋째는 작업과 작업을 연결하는 일입니다. 도구 호출을 준비하고, 돌아온 결과를 파싱하고, 다음 단계를 정하고, 실패하면 재시도하는 오케스트레이션이 CPU 위에서 끊임없이 돌아갑니다.\nIntel 측의 표현을 빌려 말하면, Agentic AI는 추론을 LLM과 같은 하나의 거대한 프로그램이 아니라, 여러 작은 서비스가 협력하는 마이크로서비스에 가깝게 만듭니다. 제어 흐름과 도구 호출, 재시도, 조율 과정이 전부 CPU 위에서 이루어집니다. 그 결과 한 번의 작업이 진행되는 시간의 상당 부분, 측정에 따라서는 30-90% 가 CPU에 머뭅니다.\n비용의 역설 역설적인 것은 비용입니다. 클라우드 인스턴스 가격을 기준으로 보면, GPU 연산은 CPU보다 100배에서 많게는 1,600배까지 비쌉니다. 그런데 이 병목을 풀기 위해 CPU 코어를 더 얹는 비용은 한 서버 기준 약 1.5%에 그쳤습니다. 비싼 GPU를 놀리지 않으려고 값싼 CPU를 조금 더 쓰는 편이 훨씬 남는 장사인 셈입니다.\n아울러 앞선 연구 결과들은 \u0026ldquo;GPU가 좋아질수록 병목은 오히려 CPU로 더 빠르게 옮겨간다\u0026quot;고 말합니다. 차세대 GPU가 모델을 더 빨리 통과시킬수록, 그 사이 다른 작업을 실행하는 CPU의 상대적 부담이 더 커지기 때문입니다. 결국 GPU를 키우는 것만으로는 이 문제가 풀리지 않습니다. 더 좋은 CPU, 더 많은 CPU가 필요해지는 것입니다. 그렇다면 이제 시선을 CPU 자체로, 그리고 CPU를 만드는 회사들로 옮겨 보겠습니다.\n2강 구도에서 3강 구도로 — CPU 경쟁에 뛰어든 NVIDIA 전통적으로 서버 한 대에서 CPU 한 개는 GPU 4-8개를 거느렸습니다. agentic 시대에는 이 비율이 거꾸로 뒤집힙니다. Intel은 차세대 GPU가 더 빨라질수록, GPU 한 개를 제대로 운용하는 데 CPU가 최대 7개까지 필요해질 수 있다고 주장합니다.\n그래서 CPU를 만드는 회사들 모두 \u0026ldquo;이제 다시 CPU의 시대\u0026quot;라고 외칩니다. 그런데 여기서 그동안 보이지 않던 이름이 하나 등장합니다 — 바로 GPU를 만들던 NVIDIA 입니다. NVIDIA가 CPU 경쟁에 직접 뛰어든 것이죠.\n사실 이는 반은 맞고 반은 틀린 이야기입니다. NVIDIA가 데이터센터 CPU 경쟁의 한복판으로 걸어 들어온 것은 분명 새로운 사건이지만, \u0026lsquo;NVIDIA가 CPU를 처음 만든다\u0026rsquo;는 뜻은 아니기 때문입니다. GPU는 혼자서는 아무것도 시작하지 못합니다. 부팅도, 연산할 일을 나눠 던지는 것도 모두 곁에 붙은 CPU(호스트) 가 해 줘야 하죠. 그래서 NVIDIA는 오래전부터 자사 GPU를 거느릴 CPU를 직접 만들어 왔습니다.\n다만 그 무대가 데이터센터는 아니었습니다. 전통적인 데이터센터와 PC 시장은 x86을 쥔 Intel과 AMD 가 단단히 틀어쥐고 있었고, x86 라이선스가 없는 NVIDIA가 비집고 들어갈 자리는 거의 없었습니다. 그래서 NVIDIA의 CPU는 주로 Arm 기반 SoC인 Tegra 의 형태로, 닌텐도 스위치 같은 게임기와 모바일·자동차 임베디드 영역에 자리 잡았죠.\n하지만 NVIDIA는 그 과정에서 쌓은 코어 설계 노하우와 자사 GPU와의 호환성을 발판 삼아, Arm ISA를 중심으로 \u0026lsquo;GPU와 함께 파는\u0026rsquo; 데이터센터 CPU로 무대를 넓혀 왔습니다. Hopper·Blackwell에 짝지은 Grace 가 그 첫 결실이었죠. 그리고 마침내 2026년 6월 GTC Taipei에서, NVIDIA는 Arm 라이선스 코어를 빌려 쓰던 Grace와 달리 직접 설계한 코어로 만든 Vera 를 들고 나와 데이터센터 CPU 시장을 정조준한다고 선언했습니다. 오랫동안 Intel과 AMD의 2강 구도였던 CPU 전쟁이, 비로소 3강 구도 로 바뀌게 된 것입니다. 다음 섹션에서는 세 회사의 CPU 아키텍처를 나란히 뜯어보겠습니다\n3사 CPU 아키텍처 톺아보기 ① x86 vs Arm 세 회사를 가르는 가장 근본적인 선은 코어를 얼마나 크게 키웠느냐가 아니라, 어떤 명령어 집합(ISA) 위에 코어를 세웠느냐입니다 — Intel·AMD는 x86, NVIDIA의 Vera는 Arm 이죠. ISA(Instruction Set Architecture)는 소프트웨어와 하드웨어 사이의 약속, 즉 프로그램이 CPU에게 시킬 수 있는 명령어의 종류와 형식·레지스터 규격을 정해 둔 \u0026lsquo;계약서\u0026rsquo;입니다. 같은 ISA끼리는 한 번 컴파일한 프로그램이 그 위 어떤 칩에서도 돌지만, ISA가 다르면 같은 프로그램도 새로 컴파일해야 합니다.\nx86과 Arm은 이 계약서를 짜는 철학부터 다릅니다. x86은 CISC(Complex Instruction Set Computer) 계열에서 출발해 명령어 하나가 복잡한 일을 처리하고 길이도 제각각(가변 길이)입니다. Arm은 RISC(Reduced Instruction Set Computer) 계열로 명령어를 단순하게 쪼개고 길이를 4바이트로 고정합니다. 오늘날엔 두 진영 모두 내부에서 명령어를 잘게 나눈 마이크로 연산(µop)으로 바꿔 실행해 이 경계가 많이 흐려졌지만, 한 가지 차이는 끝까지 남습니다 — 명령어를 해석(decode)하는 비용 입니다. 길이가 들쭉날쭉한 x86은 명령어의 경계부터 찾아야 해 디코더가 복잡하고 전력을 더 먹는 반면, 길이가 고정된 Arm은 여러 명령어를 한꺼번에 나란히 해석하기 쉬워 디코더를 넓히기에 유리합니다. Arm 아키텍처 기반 프로세서들이 과거 모바일 시대에 AP(application processor)에 많이 사용된 이유가 여기에 있습니다.\n그렇다면 전력이 중요한 AI 연산에서도 효율 좋은 Arm 아키텍처가 유리하지 않을까요? 성능 또한 x86과 비교했을 때 뒤지지 않을 정도로 많이 올라왔지만 현실은 쉽지 않습니다. x86의 진짜 해자는 성능이 아니라 호환성 이기 때문입니다. 수십 년간 쌓인 운영체제와 기업용 소프트웨어, 드라이버가 모두 x86 바이너리로 컴파일돼 있고, 이 자산을 옮기는 데는 막대한 비용이 듭니다. 게다가 x86을 만들 수 있는 회사는 사실상 Intel과 AMD 둘뿐이라, 그 울타리 자체가 진입 장벽입니다.\n반면 Arm의 무기는 효율과 개방성 입니다. 본래 모바일에서 출발해 \u0026lsquo;전력당 성능\u0026rsquo;을 최우선으로 설계됐고, ISA를 라이선스로 개방해 누구나 그 위에 자기만의 코어를 직접 설계할 수 있게 했습니다. Apple의 M 시리즈, 그리고 NVIDIA의 Grace·Vera가 모두 이를 통해 만들어진 것입니다. 전성비와 코어 밀도가 곧 운영비인 데이터센터에서 이 철학은 점점 힘을 받고 있고, NVIDIA가 x86 대신 Arm을 고른 이유도 여기에 있습니다.\n병렬 연산 ISA 확장\n이 기본 ISA 위에, 벡터/행렬 연산을 빠르게 처리하기 위한 확장 명령어 가 올라탑니다. 기본 명령어들은 대부분 연산을 스칼라 단위로 하나씩 처리하기 때문에 여러 개의 데이터를 연산하기 위해서는 그만큼의 명령어가 필요합니다. 이 때문에 병렬화가 가능한 작업은 단일 명령어로 수행하여 처리량을 늘리기 위해 만들어진 것이 SIMD(single instruction, multiple data) 명령어입니다. 이는 지난 GPU편에서도 설명한 개념으로 CPU에서도 성능 향상을 위해 사용하고 있습니다.\nx86 진영(Intel·AMD)은 벡터 길이를 고정하는 AVX(Advanced Vector Extensions) 기반 SIMD 유닛을 공통 토대로 삼고, Arm 진영은 가변 길이 벡터 확장인 SVE(Scalable Vector Extension) 를 씁니다. 여기까지는 ISA가 갈라놓은 차이지만, x86 진영 안에서도 Intel과 AMD의 접근이 나뉩니다.\nIntel 은 AVX 위에 전용 2차원 타일 행렬 엔진 AMX(Advanced Matrix Extensions)를 코어 안에 추가했습니다. AMX는 1차원 벡터가 아니라 행렬 단위로 곱셈-누산을 처리하는 전용 유닛으로, 코어 하나가 한 사이클에 INT8 기준 2,048번, BF16·FP16 기준 1,024번의 곱셈-누산을 처리합니다. 이 전용 행렬 엔진으로 작은 모델(SLM) 정도는 GPU 없이 CPU만으로도 추론이 가능합니다.\nAMD 는 전용 타일 엔진 없이 AVX-512와 VNNI(Vector Neural Network Instructions) 로 행렬 연산을 처리합니다. 전용 2차원 행렬 엔진보다 하드웨어 처리 밀도는 낮지만, 기존 SIMD 유닛으로도 행렬 연산은 충분히 수행할 수 있고 무거운 연산은 GPU에 넘깁니다.\n이에 더해 Intel과 AMD는 x86 생태계에서 CPU 측 AI 행렬 연산 확장을 표준화하기 위한 ACE(AI Compute Extensions) 규격을 공동으로 발표했습니다. 이는 x86 아키텍처에서 AMX와 같은 전용 연산 유닛 없이 범용 연산 유닛으로 AI 연산을 수행할 수 있게 하기 위한 표준입니다.\nNVIDIA Vera는 Arm SVE2 에 네이티브 FP8 을 더한 경로를 씁니다. 전용 타일 엔진은 없지만, 가변 길이 벡터 유닛과 FP8 지원으로 추론 연산 중 일부를 처리하고 무거운 행렬 연산은 GPU에 넘깁니다.\n② 멀티스레딩 — 시간을 쪼갤까, 공간을 가를까 ISA 다음으로 세 회사의 CPU 설계 철학이 가장 뚜렷하게 갈리는 지점이 바로 멀티스레딩입니다. 여기서 NVIDIA가 x86 두 회사와 근본적으로 다른 길을 택합니다.\n멀티스레딩(hardware multithreading) 은 코어 하나에 여러 스레드를 동시에 얹는 기법입니다. 코어가 한 스레드만 돌리면, 그 스레드가 메모리를 기다리며 멈출 때 비싼 실행 유닛이 통째로 놀게 됩니다. 그래서 스레드 두 개를 코어 하나에 같이 얹어, 한쪽이 멈춰 있는 사이 다른 쪽이 빈 유닛을 메우게 하는 것이죠. Intel은 이를 하이퍼스레딩(Hyper-Threading), AMD는 동시 멀티스레딩(Simultaneous Multi-Threading, SMT)이라 부르지만 원리는 같습니다. 관건은 \u0026lsquo;한 코어의 자원을 두 스레드가 어떻게 나눠 쓰느냐\u0026rsquo;이고, 여기서 길이 둘로 갈립니다.\n시분할 SMT (Intel · AMD). 전통적인 2-way SMT는 디코더·실행 포트·레지스터 같은 코어 자원을 두 스레드가 시간 위에서 동적으로 공유합니다. 매 사이클 비어 있는 자원을 그때그때 나눠 갖는 방식이라, 한 스레드만 돌 때는 코어를 통째로 독차지하고 둘이 함께 돌면 서로 경쟁합니다. 평균 처리량은 높지만, 옆 스레드가 자원을 많이 쓰면 내 스레드가 느려지기 때문에 스레드별 성능과 테일 지연(tail latency)이 들쭉날쭉해집니다.\n공간 멀티스레딩 (NVIDIA Vera). Vera의 Olympus 코어는 다른 방향성을 취합니다. 시간을 쪼개 번갈아 쓰는 대신, 코어 자원을 두 스레드에 물리적으로 분할 해 각 스레드가 고정된(그리고 그만큼 축소된) 자원 집합을 받습니다. 88코어가 이렇게 2-way로 갈라져 176스레드가 됩니다. 한 스레드가 낼 수 있는 최고 속도는 시분할 SMT보다 낮을 수 있지만, 옆 스레드가 무엇을 하든 내 스레드의 지연이 흔들리지 않는다는 것이 장점입니다.\n이 차이는 agentic 워크로드에서 의미를 갖습니다. agent의 한 스텝은 수십·수백 개의 도구 호출과 샌드박스 세션을 한꺼번에 펼친 뒤 그 결과가 다 모여야 다음 추론으로 넘어가므로(fan-out·fan-in), 스텝의 완료 시간은 세션들의 평균이 아니라 가장 늦게 끝나는 하나가 결정합니다. 시분할 SMT에서는 이 꼬리가 옆 스레드의 자원 경쟁에 따라 출렁이지만(noisy neighbor), 자원을 물리적으로 분할하면 각 세션의 지연이 이웃과 무관하게 고정돼 테일 지연이 안정됩니다. 결국 한 스레드의 최고 속도보다 모든 세션이 예측 가능한 시간 안에 끝나는 것이 중요해지는 것입니다.\n③ CPU-GPU 링크 마지막은 CPU와 GPU를 잇는 연결부입니다. CPU에서 연산한 결과값을 GPU에 전달해야 할 뿐만 아니라, KV 캐시 용량이 GPU HBM 용량을 초과할 경우 CPU 메모리를 사용해야 하기 때문에 이 연결부는 더욱 중요해집니다.\nIntel과 AMD 는 표준적인 방법을 씁니다. Xeon은 PCIe 5 / CXL로, EPYC은 PCIe 5 / Infinity Fabric으로 CPU와 GPU를 잇습니다. PCIe 5는 x16 레인 기준 방향당 약 64 GB/s, 양방향을 합쳐도 약 128 GB/s 수준입니다.\nNVIDIA 는 독자적인 규격을 사용합니다. Vera는 1.8 TB/s에 이르는 NVLink-C2C 라는 coherent 인터커넥트로 Rubin GPU와 한 몸이 됩니다. 이는 전작 Grace의 900 GB/s를 무려 2배로 끌어올린 수치입니다.\n지금까지 살펴본 세 축을 한 표로 정리하면 다음과 같습니다.\n구분 Intel Xeon AMD EPYC NVIDIA Vera 현세대 대표 Xeon 6980P · Redwood Cove EPYC 9755·9965 · Zen 5 / 5c Vera · Olympus(커스텀 Arm) 명령어 집합 (ISA) x86-64 (CISC 계열) x86-64 (CISC 계열) Arm Armv9.2-A (RISC 계열) 코어 / 스레드 128C / 256T 128C/256T(9755) · 192C/384T(9965) 88C / 176T 행렬 연산 ISA AMX + AVX-512 (전용 타일 행렬엔진) AVX-512 / VNNI (SIMD 기반 행렬연산) SVE2 + FP8 ② 멀티스레딩 2-way 시분할 SMT 2-way 시분할 SMT 2-way 공간 멀티스레딩 (자원 물리분할) ③ CPU-GPU 링크 PCIe 5 / CXL PCIe 5 / Infinity Fabric NVLink-C2C 1.8 TB/s (coherent) 정리 오늘은 Agentic AI 시대에 다시 떠오른 CPU를 살펴봤습니다. 추론이 단일 패스에서 도구를 부르는 루프로 바뀌면서, 제어와 도구 실행이 CPU로 내려왔고, 그 사이 비싼 GPU가 노는 새로운 병목이 생겼습니다. 여러 실험 결과는 이를 분명히 보여 줬습니다. 도구 실행이 응답 지연의 상당 부분을 차지했고, GPU를 늘리는 대신 CPU를 늘리는 것만으로 속도가 빨라졌습니다.\nCPU 수요가 커지는 이러한 상황에서 기존의 Intel과 AMD 두 회사가 양분하고 있던 시장에 NVIDIA가 참전을 선언했습니다. 두 회사와는 매우 다른 접근법과 GPU 인프라 구축 노하우를 기반으로 달성한 높은 성능을 보여주며 고객사들의 기대감을 증폭시키고 있습니다. 세 CPU를 동일한 agentic 워크로드로 직접 비교한 벤치마크는 아직 존재하지 않지만, 발표된 성능만으로는 CPU 시장이 3강 체제로 흘러가지 않을까 생각됩니다.\n흥미로운 점은, 이 흐름이 GPU를 키울수록 더 강해진다는 것입니다. 차세대 GPU가 모델을 더 빨리 통과시킬수록, 그 사이 도구를 돌려서 응답을 보내줘야 하는 CPU의 부담은 오히려 커집니다. AI 가속기를 설계하는 입장에서도, 호스트 CPU를 어떻게 고르고 어떻게 이을 것인가는 점점 더 중요한 질문이 되고 있습니다.\n추신 : HyperAccel은 채용 중입니다. HyperAccel은 데이터센터향 LPU 첫 제품 출시를 목전에 두고 있으며, 하드웨어/소프트웨어 최적화를 통해 LLM 추론의 핵심 병목들을 해소하고 효율적인 서비스를 제공할 수 있는 기술을 개발해 나가고 있습니다.\n저희의 기술적 여정에 흥미가 있으시다면, HyperAccel Career를 통해 지금 바로 지원해 주세요!\nHyperAccel은 여러분의 지원을 기다립니다.\nReference 실적·시장 반응\nAMD Reports First Quarter 2026 Financial Results (공식 IR) Intel Reports First-Quarter 2026 Financial Results (공식 IR) Intel\u0026rsquo;s stock has best day since 1987, soaring 24% — CNBC (2026-04-24) AMD (AMD) Stock Price History — stockanalysis.com Agentic AI와 CPU 병목 (연구·분석)\nRitik Raj et al., \u0026ldquo;Towards Understanding, Analyzing, and Optimizing Agentic AI Execution: A CPU-Centric Perspective\u0026rdquo; (arXiv:2511.00739) Euijun Chung et al., \u0026ldquo;Characterizing CPU-Induced Slowdowns in Multi-GPU LLM Inference\u0026rdquo; (arXiv:2603.22774) The CPU Bottleneck in Agentic AI and Why Server CPUs Matter More Than Ever — viksnewsletter SemiWiki, \u0026ldquo;Agentic AI Demands More Than GPUs\u0026rdquo; (2026-04-08) CPU:GPU 비율 재조정 · 수요/공급\nTrendForce, \u0026ldquo;The Great Rebalance: How Agentic AI Is Reshaping the CPU:GPU Ratio\u0026rdquo; (2026-04) Tom\u0026rsquo;s Hardware, \u0026ldquo;\u0026lsquo;CPUs are cool again\u0026rsquo; — agentic AI로 CPU 수요 급증·공급 부족\u0026rdquo; (2026-04) Tom\u0026rsquo;s Hardware, \u0026ldquo;AI 워크로드 CPU 수요 증가로 공급 부족·가격 인상\u0026rdquo; (2026-04) 벤더 자료\nIntel White Paper, \u0026ldquo;Agentic AI Requires More CPUs\u0026rdquo; (2026) AMD Blog, \u0026ldquo;Agentic AI Changes the CPU/GPU Equation\u0026rdquo; (2026) NVIDIA, \u0026ldquo;NVIDIA Unveils Vera, the CPU for Agents\u0026rdquo; — GTC Taipei 2026 (2026-05-31) NVIDIA Vera CPU 제품 페이지 — \u0026ldquo;The CPU for agents\u0026rdquo; CPU 아키텍처 비교\nBabai Das, \u0026ldquo;Arm vs x86: Why x86 Still Matters in an Arm-Dominated Future\u0026rdquo; — Medium ","permalink":"https://hyper-accel.github.io/posts/cpu-revival/","summary":"Agentic AI 워크로드에서 CPU가 추론 인프라의 병목이 된 원인을 분석하고 CPU 3사의 최신 데이터센터향 CPU 라인업을 분석해보며 Agentic AI 시대에 다시 떠오른 CPU의 중요성에 대해 알아봅니다.","title":"지피지기면 백전불태 6편 : Agentic AI 시대, CPU의 부활과 CPU 삼국지의 시작"},{"content":"Legato: LPU를 위한 프로그래밍 모델 본 글은 HyperAccel의 고객사 및 협력사 개발자를 대상으로, Legato가 무엇이며 무슨 역할을 하고, 왜 만들었으며, 어떻게 설계되었는지를 설명합니다.\n1. Legato는 무엇이며 왜 필요한가? 1.1 소프트웨어 생태계가 승부를 가른다 AI 가속기 시장에서 NVIDIA가 가진 진정한 해자(moat)는 무엇일까요? 흔히 GPU의 연산 성능을 떠올리지만, 실제로 경쟁사와의 하드웨어적 격차는 생각보다 크지 않습니다. 트랜지스터 공정, 메모리 대역폭, 연산 유닛의 설계는 여러 회사가 빠르게 추격하고 있습니다.\n차이를 만드는 것은 결국 소프트웨어 생태계입니다. 수많은 개발자가 CUDA 위에 쌓아 올린 라이브러리, 프레임워크, 노하우, 그리고 \u0026ldquo;어떤 모델이든 일단 NVIDIA에서는 돌아간다\u0026quot;는 신뢰가 진입 장벽을 만듭니다. 하드웨어가 아무리 뛰어나도, 그것을 자유롭고 익숙하게 다룰 수 있는 소프트웨어가 없다면 시장은 움직이지 않습니다.\n1.2 HyperAccel의 LPU가 갖춰야 할 소프트웨어 경쟁력 HyperAccel의 LPU(LLM Processing Unit)가 이 경쟁에서 살아남으려면, 단순히 빠른 칩을 만드는 것을 넘어 두 가지 조건을 충족해야 합니다.\n첫째, 개발자가 사용하면서 위화감을 느껴서는 안 됩니다. 새로운 하드웨어를 쓰기 위해 개발자가 자신의 워크플로를 통째로 갈아엎어야 한다면, 그 하드웨어는 외면받습니다. 현 시점 AI 추론 시장에서 사실상 표준으로 취급받는 torch와 vLLM 기반의 추론 스택과 자연스럽게 호환되어야 합니다.\n둘째, 자유로운 모델을 지원할 수 있어야 합니다. 회사 내부에서 일일이 포팅하고 관리하는 일부 모델만 돌아가는 가속기는 진정한 의미의 플랫폼이 아닙니다. 사용자가 가져오는 임의의 모델을 받아들일 수 있어야 합니다.\n1.3 Legato의 역할 Legato는 이 모든 것을 가능하게 하는, 하드웨어와 소프트웨어 개발자를 이어주는 인터페이스입니다.\nLegato는 하나의 프로그래밍 언어이자, 소프트웨어 개발자에게 프로그래밍 모델 을 제공합니다. 프로그래밍 모델이란 LPU가 소프트웨어 개발자에게 어떻게 보일 것인지를 결정하는 약속입니다.\n이 개념은 CUDA를 떠올리면 명확합니다. 우리는 NVIDIA 칩 내부의 모든 디테일을 알지 못합니다. 그러나 CUDA라는 프로그래밍 모델 하나만 익히면, 어느 세대의 칩이든 프로그래밍할 수 있습니다. CUDA가 칩의 복잡성을 가린 간소화된 프로그래밍 모델 을 제공하기 때문입니다.\nLegato도 마찬가지입니다. 개발자에게 LPU의 간소화된 프로그래밍 모델을 제공하여, 하드웨어의 세부 구현을 몰라도 LPU를 프로그래밍할 수 있게 합니다.\n1.4 스택 안에서 Legato의 위치 Legato가 전체 추론 스택에서 어디에 위치하는지 보면 역할이 분명해집니다.\nLegato는 위로는 기존 생태계(PyTorch/vLLM)와 맞물리고, 아래로는 LPU 하드웨어로 내려가는 다리 역할을 합니다. 개발자는 익숙한 방식 그대로 코드를 작성하고, 복잡한 하드웨어에 관한 처리는 Legato가 흡수합니다.\n2. Legato 한눈에 보기 (Quick Look) 추상적인 설명을 더 하는 대신, 코드를 먼져 보여드리겠습니다. 다음은 행렬 곱(matmul)을 LPU에서 수행하는 간단한 예제입니다.\nimport torch import legato import legato.model.bertha as bertha # Compile target 을 설정합니다. # 이 예시에서는 128GB의 메모리와 32코어를 갖춘 Bertha칩을 컴파일 타깃으로 설정합니다. def get_bertha(ctx): gigabyte = 1024**3 return bertha.Bertha( ctx, \u0026#34;bertha\u0026#34;, 32, # num_cores False, # use_pim 8, # num_memory_channels 128 * gigabyte, # shared_memory_size ) # legato.compile decorator는 이 함수를 더이상 Python 함수가 아닌 Legato 커널로 변환되어 컴파일됩니다. # 이 함수 내에 구현되는 모든 코드는 더 이상 Python이 아닌 Legato 코드가 됩니다. (Triton이나 Mojo등과 같은 개념입니다) @legato.compile( backend=get_bertha ) def simple_matmul( a: legato.get_model().tensor_type( legato.types.float(\u0026#34;bfloat16\u0026#34;), ((-1, 10), 256), \u0026#34;shared_dram\u0026#34; ), b: legato.get_model().tensor_type( legato.types.float(\u0026#34;bfloat16\u0026#34;), [256, 128], \u0026#34;mpu_dram\u0026#34; ), out: legato.get_model().tensor_type( legato.types.float(\u0026#34;bfloat16\u0026#34;), [10, 128], \u0026#34;shared_dram\u0026#34; ) ): # backend에 제공된 device를 불러옵니다 device = legato.get_context().get_device() # Bertha의 Top module 에서 실행되는 코드 with device.get_top(): # a, b 를 0번 코어의 sram 과 mpu_buffer로 복사합니다. legato.tensor.request_load(a, device.get_core(0), \u0026#34;sram\u0026#34;) legato.tensor.request_load(b, device.get_core(0), \u0026#34;mpu_buffer\u0026#34;) # Bertha의 0번 코어에서 실행되는 코드 영역 with device.get_core(0): weight_type = legato.get_model().tensor_type( legato.types.float(\u0026#34;bfloat16\u0026#34;), [256, 128], \u0026#34;mpu_weight\u0026#34; ) # Top module에서 request_load를 통해 전달받은 data를 수신합니다. loaded_a = legato.tensor.receive(a, 0, \u0026#34;sram\u0026#34;) loaded_b = legato.tensor.receive_type(weight_type, 0, None, \u0026#34;mpu_buffer\u0026#34;) # 수신된 데이터로 Matmul 연산을 수행합니다 result = loaded_a @ loaded_b # 연산 결과를 out tensor에 복사합니다. legato.tensor.memcpy(out, result) output = torch.zeros(10, 128, dtype=torch.bfloat16) # legato.session 을 통해 JIT 컴파일 옵션을 지정할 수 있습니다. (출력 포맷, 촐력 directory 등) # simple_matmul 호출 시점에 JIT 컴파일되어 코드가 실행되며, 이미 컴파일된 바이너리가 있다면 코드가 변경되지 않은 이상 캐시된 바이너리를 사용합니다. with legato.session(output_type=legato.OutputType.BINARY, output_path=\u0026#34;simple_matmul\u0026#34;): simple_matmul( torch.randn(10, 256, dtype=torch.bfloat16), torch.randn(256, 128, dtype=torch.bfloat16), output, ) 이 짧은 코드에 Legato의 핵심 개념이 모두 담겨 있습니다.\n@legato.compile — 컴파일 대상이 되는 진입점(entry point)을 정의합니다. with device.get_top() / with device.get_core(0) — 각 연산이 어디서 실행될지(실행 컨텍스트)를 명시합니다. Context의 종류는 칩마다 조금씩 달라질 수 있습니다. 저희사 예제에서 프로그래밍한 HyperAccel LPU는 여러 개의 core로 구성되어 있어, 0번 core에 연산을 할당했습니다. request_load → receive — 데이터가 언제, 어디로 이동하는지를 명시합니다. legato.session(...) — 컴파일 결과물(여기서는 BINARY)을 어떤 형태로, 어디에 만들지 결정합니다. Binary를 선택하면 ELF executable이 출력되며 이외 ASM, CORE_IR, BACKEND_IR 등으로도 출력할 수 있으며, 이는 디버깅 과정에 유용하게 쓰입니다. 3. Legato의 프로그래밍 모델 (핵심 설계 개념) Legato 설계의 핵심은 프로그래밍 모델입니다. 즉, \u0026ldquo;개발자 눈에 LPU가 어떻게 보이는가\u0026quot;입니다.\n3.1 단순화된 가상 하드웨어 모델 중요한 전제가 하나 있습니다. 개발자에게 보여지는 하드웨어 모델은, 실제 하드웨어 구조와 의도적으로 다릅니다. Legato는 복잡한 물리적 디테일을 숨기고, 프로그래머가 이해하기 쉬운 단순화된 가상의 하드웨어를 제시합니다.\n이 가상 하드웨어는 대략 다음과 같이 구성됩니다.\nDRAM + Controller — 모든 코어가 접근할 수 있는 Shared DRAM. 물리적으로는 여러 메모리 모듈로 구성될 수 있지만, 프로그래밍 모델에서는 하나의 큰 메모리로 간주합니다. Virtual DRAM — Shared DRAM처럼 모든 코어가 공유하되, MMU를 통해 접근하는 영역. MMU는 미리 구성되어 있다고 가정합니다. PIM (Processing-in-Memory) — 필요에 따라 선택적으로 사용합니다. Core — 코어의 개수는 하드웨어 구성에 따라 달라집니다. 각 코어는 PC와 레지스터, 여러 실행 유닛(MPU, VPU 등 Executor), 온칩 SRAM(Cache), 그리고 코어가 사적으로 쓰는 Private DRAM을 가집니다. 3.2 메모리 모델 메모리도 소프트웨어 관점에서 세 가지로 단순화됩니다.\nShared Memory — 모든 코어가 공유하는 공간. Bertha에서는 DRAM에 해당합니다. Virtual Shared Memory — MMU가 관리하는 공유 공간. Core Memory — Private DRAM과 SRAM을 합친 코어 전용 공간. 각 core에는 scratchpad memory로 사용할 수 있는 sram 공간이 존재하며, 이 부분은 컴파일러가 planning하여 사용합니다. Private DRAM은 각 core만이 접근할 수 있는 DRAM의 영역으로, Core 내부 scratchpad memory가 부족한 경우 eviction하기 위한 용도로 사용합니다. 여기서 중요한 설계 결정이 드러납니다. 프로그래머가 Core Memory에 데이터를 할당하면, 그것이 SRAM에 놓일지 Private DRAM에 놓일지는 컴파일러의 planning이 결정합니다. 개발자는 \u0026ldquo;이 코어의 메모리\u0026quot;라는 추상적 위치만 다루고, 물리적 배치의 최적화는 컴파일러에 위임합니다.\n3.3 실행 컨텍스트(Executor)와 명시적 데이터 이동 Legato의 연산은 항상 어떤 실행 컨텍스트 아래에서 발생합니다. 컨텍스트는 다음 연산이 어디서 실행될지를 나타냅니다.\ndevice = legato.get_context().get_device() with device.get_top(): legato.tensor.request_load(input_data, device.get_core(0), \u0026#34;sram\u0026#34;) with device.get_core(0): loaded = legato.tensor.receive(input_data, 0, \u0026#34;sram\u0026#34;) result = loaded + loaded device.get_top() — 오케스트레이션과 top 측 로드 요청에 사용합니다. device.get_core(i) — 특정 코어 하나에서 실행합니다. device.get_all_cores() — 모든 코어에서 해당 영역을 실행합니다. LPU는 모듈마다 PC(Program Counter)가 별도로 동작하는 특성이 있습니다. Legato는 이를 ContextOp으로 실행 컨텍스트를 분리하여 자연스럽게 표현합니다.\n또한 데이터 이동은 암묵적이지 않고 명시적입니다. request_load로 소스 컨텍스트에서 로드를 요청하고, receive(또는 receive_type)로 타깃 컨텍스트에서 데이터를 받습니다. 어떤 데이터가 언제 어디로 움직이는지가 코드에 그대로 드러납니다.\nLegato의 스코프는 Python 스코프보다 엄격합니다. 한 영역에서 만든 값을 다음 영역에서 써야 한다면, yield로 명시적으로 넘겨주어야 합니다.\nwith device.get_core(0): q = loaded @ weight yield q with device.get_core(0): legato.tensor.memcpy(output, q) 3.4 미래 하드웨어 호환성 (Forward Compatibility) 이 단순화된 프로그래밍 모델이 주는 가장 큰 보상은 세대 호환성입니다.\n미래의 LPU가 이 프로그래밍 모델과 호환되는 구조를 유지하는 한, 한 번 작성한 프로그램은 코드 수정 없이 다음 세대 하드웨어에서도 실행됩니다. CUDA로 짠 코드가 새 GPU 세대에서도 돌아가는 것과 정확히 같은 약속입니다. \u0026ldquo;하드웨어가 진화해도 코드는 그대로\u0026quot;라는 약속의 근거가 바로 이 프로그래밍 모델의 안정성입니다.\n4. Legato의 설계 철학 4.1 Python embedded DSL Legato는 Python에 내장된 DSL(Domain Specific Language)로 설계되었습니다. 이는 의도적인 선택입니다. 별도의 복잡한 툴체인 설치 없이 pip install 한 번으로 파이썬 환경에서 바로 사용할 수 있어, 진입 장벽을 최대한 낮춥니다. 개발자는 이미 익숙한 파이썬 문법(with, 함수, 데코레이터) 안에서 LPU 프로그래밍을 시작합니다.\n4.2 Python 사용자 친화적 Tensor 추상화 Legato의 연산은 많은 프로그래머들에게 익숙한 tensor 를 기반으로 동작합니다. broadcast, reshape, matmul 등 PyTorch나 NumPy에서 쓰던 것과 유사한 operation들을 제공합니다.\n그 이외에 성능 튜닝이 용이하도록 synchronization (동기화), Metaprogramming (static evaluation) 등 고급 프로그래밍 기능들도 지원합니다.\n각 라이브러리 operation의 의미(semantic)는 LPU 세대가 진화하더라도 코드 변경 없이 쓸 수 있도록 범용적으로 설계되었습니다. 즉, API는 안정적으로 유지되고, 그 아래에서 세대별 최적 구현으로 컴파일됩니다.\n4.3 명시적 제어 vs 자동화의 트레이드오프 Legato는 실행 위치, 데이터 이동, 컴파일타임 파라미터를 개발자가 명시적으로 기술하는, 비교적 로우레벨의 인터페이스입니다. 언뜻 번거로워 보일 수 있지만 이는 의도된 설계입니다. 알고리즘의 데이터 흐름을 명시적으로 표현해야 하는 커널 — 즉 성능이 곧 가치인 코드 — 에서는 이 명시성이 곧 제어력이 됩니다.\n동시에 Legato는 자동화 경로도 제공합니다. 따라서 사용자는 상황에 따라 선택할 수 있습니다.\n완전 자동 — torch.compile 백엔드로 모델 전체를 맡긴다. 완전 수동 — 핵심 커널을 직접 작성해 세밀하게 튜닝한다. 4.4 용이한 확장성 PyTorch 에서 Legato를 활용하는 방법\nLegato는 torch의 backend operation을 구현하여 LPU가 torch와 호환되도록 합니다. 이는 Triton이 GPU 연산을 구현하여 torch를 떠받치는 것과 같은 개념입니다. 구체적으로는 다음 흐름을 따릅니다.\n지원하려는 PyTorch 연산에 대해 Legato 함수를 구현합니다. 하나의 연산에 여러 구현(예: float32용/bfloat16용)이 있을 수 있으므로, resolver 함수가 적절한 구현을 골라 컴파일러에 돌려줍니다. 구현된 모듈을 임포트하거나 legato-library 엔트리포인트로 노출합니다. import torch @torch.compile(backend=\u0026#34;legato\u0026#34;, options={\u0026#34;legato.device\u0026#34;: \u0026#34;bertha\u0026#34;}) def model(x, y): ... 부분 컴파일(Mixed Execution). 모든 연산이 LPU로 내려갈 수 있는 것은 아닙니다. Legato는 모든 그래프를 LegatoGraphWrapper로 감싸, 컴파일 가능한 노드는 Legato 커널로 묶어 내리고, 지원되지 않는 노드는 eager extern으로 실행합니다. resolver가 없거나 특정 dtype/shape 조합에서 AssertionError를 던지면 그 노드는 extern fallback 후보가 됩니다. 덕분에 커스텀 연산이나 미지원 ATen 연산이 섞인 모델도 즉시 실패하지 않고, 컴파일 가능한 영역은 그대로 가속됩니다.\n플랫폼 무관 확장. torch에 국한되지 않습니다. NumPy, CuPy 등 다른 플랫폼으로도 자유롭게 확장 가능합니다. Backend만 Legato로 적절히 구현하면 확장성에 본질적 한계가 없습니다.\n5. Legato의 내부 구조 5.1 컴파일 파이프라인 Legato 프로그램은 다음 단계를 거쳐 하드웨어 산출물로 변환됩니다.\nFrontend — 사용자에게 보여지는 표면을 정의합니다. 파이썬으로 작성된 Legato 코드를 받아 MLIR 기반의 Legato IR로 변환합니다. Core IR / Backend IR — 여러 lowering 패스를 거치며 점점 하드웨어에 가까운 형태로 내려갑니다. Artifact — 최종적으로 Assembly 또는 Binary가 생성됩니다. 5.2 ComputeModel — 하드웨어 정보를 주입하는 단위 파이프라인 전반에는 ComputeModel이 결합되어, 각 하드웨어의 정보를 컴파일러에 제공합니다.\nComputeModel은 하드웨어의 정보를 담은 간소화된 모델로, lowering이나 최적화 결정에서 핵심 역할을 합니다. ComputeModel을 교체하는 것만으로 하드웨어 타깃을 전환할 수 있습니다. 예제에서 보았던 get_bertha처럼, backend 팩토리가 ComputeModel 인스턴스를 만들어 컴파일러에 넘겨줍니다.\nComputeModel은 단순한 정보 제공을 넘어 검증의 기준이 됩니다. 특정 하드웨어에서 실행이 불가능하거나 비효율적인 연산을 사용자가 작성하면, 컴파일러는 가능한 변환을 시도하거나, 그것이 어렵다면 사용자에게 적합한 에러 메시지를 띄워 안내합니다.\n5.3 하드웨어별 Backend Compiler backend는 각 하드웨어마다 별도로 만들어져, 그 하드웨어에 특화된(HW-specific) 변환을 수행합니다. 새로운 LPU를 지원하려면 해당 하드웨어용 backend와 ComputeModel을 구현하면 되며, 상위의 프로그래밍 모델과 사용자 코드는 그대로 재사용됩니다.\n5.4 출력 타깃 — 투명성과 디버깅 Legato는 컴파일의 어느 단계에서든 산출물을 뽑아볼 수 있습니다. legato.session의 output_type으로 다음 중 하나를 선택합니다.\nOutput Type 설명 MLIR 초기 Legato IR (MLIR 형태) CORE_IR Core IR 단계 BACKEND_IR Backend IR 단계 ASM 어셈블리 BINARY 최종 실행 바이너리 with legato.session(output_type=legato.OutputType.MLIR, output_path=\u0026#34;test-output\u0026#34;): kernel(*args) 각 단계의 IR을 직접 확인할 수 있다는 것은, 컴파일 과정이 블랙박스가 아니라는 뜻입니다. 문제가 생겼을 때 어느 단계에서 어떻게 변환되었는지 추적할 수 있어, 디버깅과 검증이 투명합니다.\n5.5 ELF Binary 최종 출력은 ELF binary로 생성됩니다. 이 바이너리는 단순한 명령어 덩어리가 아니라, 하드웨어 정보, 컴파일러 정보, checksum 등 다양한 메타데이터를 함께 담습니다. 런타임은 실행 시 이 정보를 읽어, 해당 바이너리가 지금 이 하드웨어/환경에서 실행하기에 적합한지 검증합니다. 잘못된 바이너리를 잘못된 하드웨어에서 실행하는 사고를 사전에 차단합니다.\n6. 견고성과 검증 (신뢰 신호) 플랫폼을 도입하는 입장에서 가장 중요한 질문은 \u0026ldquo;이것을 믿고 프로덕션에 올릴 수 있는가\u0026quot;입니다. Legato는 여러 층위의 검증으로 이에 답합니다.\n6.1 ComputeModel 기반 검증 앞서 본 것처럼, 사용자가 특정 하드웨어에서 불가능하거나 비효율적인 연산을 작성하면 컴파일러는 자동 변환을 시도하고, 불가능하면 무엇이 왜 안 되는지 알려주는 actionable한 에러 메시지를 제공합니다. 조용히 잘못된 결과를 내는 대신, 컴파일 시점에 문제를 드러냅니다.\n6.2 타입 · 레이아웃 · 동적 shape 검증 Legato는 텐서의 타입과 메모리 레이아웃을 함수 시그니처에서 검증합니다. 특히 동적 차원(dynamic dimension)은 반드시 상한(upper bound)을 가져야 합니다.\nx = torch.zeros(16, 32, 32) torch._dynamo.mark_dynamic(x, 0, max=128) # dim 0은 동적, 상한 128 하드웨어 특성상 텐서가 완전히 동적일 수는 없습니다. 모든 동적 차원은 버퍼 할당과 명령 생성을 위한 최댓값을 가져야 하며, 상한이 없는 동적 차원은 컴파일 시점에 에러를 발생시킵니다. 이는 컴파일러가 컴파일 타임에 tensor allocation을 planning하기 위함입니다.\n6.3 Host-Device ABI (Instruction Table) 호스트와 디바이스 경계에서 인자를 정확히 주고받기 위해, Legato는 Instruction Table이라는 바이너리 ABI를 정의합니다. 64-bit 정렬 규칙을 엄격히 따르며, 스칼라/텐서/튜플 인자를 정해진 규약에 맞춰 패킹합니다. 최대 테이블 크기를 함수 시그니처로부터 컴파일 타임에 계산할 수 있어, 런타임의 인자 전달이 예측 가능하고 안전합니다.\nQ. 그럼 LPU를 쓰려면 Legato를 다 공부해야 하나요? 아니오. 물론 그럴 필요는 없습니다. GPU를 쓰는 모든 AI 개발자들이 모두 CUDA, OpenCL, Vulkan같은 것을 알고 있진 않지요? HyperAccel LPU도 마찬가지입니다.\nLegato는 torch 혹은 여러 library의 backend를 구현하는데 쓰이며, AI 개발자에게 항상 직접적으로 드러나지는 않습니다. torch 나 numpy 등을 LPU에서 사용할 때, 개발자는 평소에 CPU나 GPU에서 하던 것처럼 사용할 수 있습니다. 하지만, 내부적인 연산들은 Legato로 구현됩니다.\n하지만, custom kernel이나 성능 최적화를 극한까지 하고 싶다면, Legato를 직접 사용할 수 있습니다. GPU프로그래밍을 할 때도 성능을 끌어올리거나 이전에 구현되지 않은 연산을 만들고 싶다면 torch에 이미 구현된 것을 사용하는 대신 Triton 혹은 CUDA 등을 이용해서 custom kernel을 만들어 사용하는 경우가 있지요? LPU도 마찬가지입니다. Legato는 언제든지 사용자가 직접 사용할 수 있도록 열려 있으며, 원한다면 torch 로 구현된 모델 중간에 Legato로 직접 구현한 layer를 끼워 넣을 수도 있습니다. 아래처럼요.\n@legato.compile(backend=bertha) def custom_kernel(input: legato.get_model().tensor_type( legato.types.float(\u0026#34;bfloat16\u0026#34;), ((-1, 10), 256), \u0026#34;shared_dram\u0026#34; ), output: legato.get_model().tensor_type( legato.types.float(\u0026#34;bfloat16\u0026#34;), [256, 128], \u0026#34;shared_dram\u0026#34; )): # Some implementation... c = torch.add(a, b) out = torch.zeros(256, 128) # Call legato kernel custom_kernel(c, out) print(f\u0026#34;output from legato kernel : {out}\u0026#34;) # Keep going with torch out_exp = torch.exp(out) 7. 정리 및 다음 단계 7.1 요약 Legato는 LPU의 단순화된 프로그래밍 모델 을 제공하여, 세 가지를 동시에 달성하는 인터페이스입니다.\n생태계 호환성 — torch/vLLM 등 기존 소프트웨어 스택과 자연스럽게 맞물립니다. 세대 호환성 — 프로그래밍 모델이 유지되는 한, 코드 수정 없이 미래 LPU에서 실행됩니다. 확장성 — backend와 ComputeModel만 구현하면 새로운 하드웨어와 플랫폼으로 확장됩니다. CUDA가 NVIDIA 생태계를 떠받치듯, Legato는 HyperAccel LPU 생태계의 토대입니다.\n7.2 지원 타깃과 로드맵 현재 Legato는 Bertha 아키텍처를 타깃으로 합니다(EVT0, EVT1 등 세대별 가이드 제공). ComputeModel 교체를 통한 타깃 전환 구조 덕분에, 향후 LPU 세대로의 확장이 설계 차원에서 준비되어 있습니다.\n추신: HyperAccel은 채용 중입니다! Legato와 LPU 소프트웨어 스택을 함께 만들어갈 동료를 찾고 있습니다. 저희가 다루는 기술들을 보시고 관심이 있으시다면 HyperAccel Career로 지원해 주세요!\n","permalink":"https://hyper-accel.github.io/posts/what-is-legato/","summary":"LPU를 위한 HyperAccel의 프로그래밍 모델이자 컴파일러 스택인 Legato를 소개하며, 이것이 무엇이고 왜 존재하며 어떻게 설계되었는지 다룹니다.","title":"Legato: HyperAccel LPU를 위한 프로그래밍 언어"},{"content":"\n안녕하세요, HyperAccel의 LLMOps 팀 엄태서입니다.\n지난 글에서는 우리가 Copy \u0026amp; Paste 워크플로우에서 코딩 에이전트로 어떻게 넘어왔는지 이야기했습니다. 처음의 AI가 조금 더 똑똑한 검색창 정도로 보였다면, 곧 자동완성이 되었고, 이제는 레포지토리를 직접 읽고, 테스트를 돌리고, 실패를 확인하고, 파일을 고친 뒤 다시 시도하는 데까지 왔습니다.\n이번 글은 그 변화와 함께 조용히 다시 중요해진 도구, 바로 터미널에 관한 이야기입니다. 더 정확히는 그 터미널의 중요성을 만드는 Command Line Interface(CLI) 에 관한 이야기이기도 합니다.\n요즘 들어 달라졌다고 느끼는 점은, 터미널 네이티브 에이전트가 개발과 로컬 Integrated Development Environment(IDE) 세션 사이의 오래된 결속을 느슨하게 풀어놓았다는 것입니다. 이제 일은 제가 닿을 수 있고 신뢰할 수 있는 실행 환경을 따라 움직입니다. 그 환경은 레포지토리가 놓인 워크스테이션일 때도 있고, 서비스에 더 가까운 개발 환경일 때도 있는데, 이때 Secure Shell(SSH) 은 그 환경으로 들어가는 통로일 뿐 그 자체가 목적은 아닙니다.\n이 변화는 하루를 보내는 개발의 감각을, 그리고 어디에서 디버깅할 수 있는지를 바꿔놓았고, 더 나아가 무엇을 진짜 개발 환경이라고 부를 것인지까지 다시 생각하게 만들었습니다.\n터미널이 다시 하나의 장소가 되었다 오랫동안 제게 터미널은 도구 서랍에 가까웠습니다. git, 빌드, 패키지 매니저, 로그 확인, 가끔 손대는 쉘 스크립트 정도가 그 안에 들어 있었죠. 실제 작업은 IDE에서 일어났고, 터미널은 그 작업이 현실을 버텨내는지 확인하는 곳일 뿐이었습니다.\n코딩 에이전트는 터미널을 다시 중심으로 끌어왔습니다.\n이유는 단순합니다. 에이전트가 무언가를 하려면 시스템을 직접 만질 수 있어야 합니다. 파일을 읽고, 코드를 검색하고, 명령을 실행하고, 오류를 관찰하고, 그 흔적을 증거로 남겨야 하는데, CLI는 애초에 바로 그런 loop를 위해 만들어진 인터페이스입니다. 명령도 텍스트, 출력도 텍스트, 실패도 diff도 전부 텍스트이고, 테스트 결과는 사람과 에이전트가 함께 이해할 수 있을 만큼 단순한 신호로 돌아옵니다.\n에이전트가 터미널 안에서 일하면, 시각적인 패널 너머에서 무슨 일이 있었는지 추측할 필요가 줄어듭니다. 제가 실행했을 명령을 그대로 실행하고, 제가 읽었을 로그를 그대로 읽기 때문에, 피드백 loop가 짧고 직접적으로 유지됩니다.\n이 직접성은 생각보다 중요합니다. 채팅 User Interface(UI) 는 친근하게 느껴질 수 있지만, 소프트웨어 작업은 대화만으로 끝나지 않습니다. 결국 제약 안에서 실제 행동이 일어나야 하고, 터미널은 그 행동이 또렷한 흔적을 남기는 장소를 내어줍니다.\n터미널은 또 다른 종류의 기억도 줍니다. 스크롤백에는 일이 어디서 시작됐는지, 어떤 명령이 처음 실패했는지, 어떤 가정이 틀렸는지, 그리고 어떤 테스트가 마지막에 초록불로 바뀌었는지가 고스란히 남습니다. 증거 없는 속도는 늘 불안하기 마련인데, 터미널은 제가 중간에 멈춰 묻고 방향을 바꿀 수 있을 만큼 작업을 충분히 눈에 보이게 해줍니다.\n노트북에 SSH로 들어가 일을 시작했다 이때 처음 생긴 습관은 작고 평범했습니다. 집에 있거나 책상에서 멀지 않을 때조차, 저는 제 노트북에 SSH로 접속해 일을 시작하게 되었습니다.\n에이전트 워크플로우 이전에도 SSH는 유용했지만 어디까지나 제한적이었습니다. 로그를 확인하거나 프로세스를 재시작하거나 아주 작은 수정을 하는 정도는 괜찮았어도, 조금만 큰 일이 되면 불편해졌고, 제대로 된 컨텍스트가 필요할 때면 대개 책상으로 돌아가 IDE를 열 때까지 그냥 기다렸습니다.\n터미널 네이티브 에이전트를 쓰기 시작하면서 그 선이 움직였습니다.\n노트북에 SSH로 접속해 레포지토리를 열고 작업을 설명하면, 이제는 에이전트가 먼저 움직여 코드베이스를 살피고, 계획을 세우고, 테스트를 돌리고, diff를 건네줄 수 있었습니다. 휴대폰이나 원격 쉘을 완벽한 워크스테이션으로 바꾸려던 게 아니라, 이미 믿고 쓰던 워크스테이션에 에이전트가 닿게 해준 것뿐이었습니다.\n원격 디버깅의 감각도 함께 달라졌습니다. 책상에서 멀리 있을 때 문제가 터져도, 더는 그것을 나중에 볼 메모로 줄여 적어둘 필요가 없었습니다. 그 자리에서 곧장 디버깅을 시작할 수 있었으니까요. 제가 다른 곳에서 터미널을 들여다보는 동안, 에이전트는 로그를 모으고, 호출부를 찾고, 실패하는 명령을 재현하면서 문제의 범위를 좁혀갑니다.\n이건 마법이 아니라, 그저 역할 분담이 더 나아진 것입니다. 무엇이 중요한지는 여전히 제가 정하고 패치도 제가 리뷰하지만, 그 지루한 첫 번째 통과만큼은 더 이상 레포지토리가 놓인 바로 그 화면 앞에 앉아서 시작할 필요가 없어졌습니다.\n원격 디버깅에는 나름의 리듬이 있습니다. 저는 먼저 증상을 너무 성급하게 결론으로 몰아가지 않으려 합니다. 요청이 timeout 난다거나, 테스트가 flaky하다거나, 특정 설정 변경 뒤에만 서비스가 죽는다는 식으로 상황만 짚어두는 거죠. 그런 다음 에이전트에게는 수정에 손대기 전에 사실부터 모으라고 부탁합니다. 최근 로그를 확인하고, 코드 경로를 찾고, 재현 명령을 식별하고, 무엇이 바뀌었는지 알려주되 아직 패치는 하지 말라고요.\n이 멈춤이 중요합니다. 원격에서는 혼란을 견딜 여유가 적고, 작은 화면 앞에서는 잘못 든 길 하나하나가 책상에서보다 더 비싸게 느껴지기 때문입니다. 그래서 첫 단계는 triage에 가깝기를 바랍니다. 신호를 모으고, 불확실성을 줄이고, 가장 가능성 높은 문제의 가지에 이름을 붙이는 것까지가 먼저고, 수정은 그다음입니다.\n흥미로운 점은 이런 세션이 의외로 꽤 차분하다는 것입니다. 저는 한 손에 휴대폰을 들고 있을 뿐, 실제 무거운 일은 집에 있는 노트북이 합니다. 레포지토리는 이미 clone되어 있고, 의존성도 설치되어 있고, 테스트 cache까지 따뜻하게 남아 있죠. 저는 휴대폰으로 코딩하는 게 아니라, 그 작업에 훨씬 잘 맞는 곳에서 일어나는 일을 멀리서 조종하고 있는 셈입니다.\n다섯 시간 reset 전략 초기에는, 지금 돌아보면 짧지만 묘했던 한 시절의 스냅사진 같은 습관도 하나 있었습니다.\n에이전트 사용 한도가 지금보다 빡빡하던 시절, 저는 reset window를 기준으로 하루 전체를 계획했습니다. 전날 밤이면 신중하게 prompt를 준비했죠. 컨텍스트를 모으고, 목표를 적고, 관련될 법한 파일을 나열하고, 작업을 최대한 깔끔하게 다듬어두는 일이었습니다.\n그리고 아침 7시 전에 시작했습니다.\n대략의 계획은 단순했습니다. 오전의 reset window를 하나의 긴 uninterrupted run으로 쓰고, 에이전트를 약 다섯 시간 동안 일하게 둔 다음, 점심을 먹고 12시쯤 fresh reset을 받으면 오전에 배운 것을 들고 다시 시작하는 것이었습니다.\n지금 들으면 조금 우스운 루틴이지만, 당시에는 충분히 말이 됐습니다. 부족했던 자원은 모델의 지능만이 아니라 연속성이었기 때문입니다. 첫 한 시간을 레포지토리 설명에 다 써버리면 유용한 window의 큰 부분을 그대로 날리는 셈이었고, 그래서 저는 prompt를 일종의 launch checklist처럼 다루게 되었습니다.\n터미널 네이티브 작업은 이 전략을 한결 낫게 만들어줬습니다. 환경이 이미 코드 바로 옆에 있었던 덕분에, 에이전트가 레포지토리와 테스트, 로그가 함께 있는 곳에서 계획을 그대로 실행할 수 있었기 때문입니다. 그래도 본질적으로는 여전히 scarcity를 전제로 한 전략이었습니다. 열심히 준비하고, 일찍 시작하고, window를 꽉 채워 쓰고, 다음 reset을 기다리는 것이죠.\n이 방식은 제 계획 습관까지 바꿔놓았습니다. 전날 밤의 prompt는 더 이상 단순한 요청이 아니라 압축된 briefing이 되었거든요. 목표와 의심되는 파일, 믿을 수 있는 명령, 중요한 테스트, 그리고 절대 건드리면 안 되는 것들을 적고, 이미 시도해본 것까지 함께 넣어 다음 날 아침 run이 어제의 실수를 되풀이하지 않도록 했습니다. 위험한 길이 보이면 더 안전한 첫걸음도 그 옆에 같이 적어두었고요.\n이 계획은 분명 유용했지만, 동시에 어딘가 의식(儀式)처럼 느껴지기도 했습니다. 비행기가 뜨기 전에 활주로부터 준비해야 했으니까요. 아침 8시에 prompt에서 중요한 제약 하나가 빠졌다는 걸 뒤늦게 알아차리면 run 전체가 흔들릴 수 있었고, 에이전트가 엉뚱한 층을 너무 오래 헤매면 reset window가 눈앞에서 타들어 가는 느낌마저 들었습니다.\n그 시절의 좋은 prompt는 작은 design document에 가까웠습니다. 목표와 범위, 제약, 검증 방법, 그리고 종료 조건까지 담겨 있었죠. 이 습관은 도구가 좋아진 뒤에도 그대로 남았습니다. 이제는 다섯 시간짜리 scarcity window에 맞춰 하루를 짜고 싶지는 않지만, 에이전트에게 선명한 완료의 정의를 건네고 싶은 마음만큼은 여전합니다.\nAndroid와 Termux를 쓰던 시기 한동안 이 워크플로우의 가장 이동성 높은 버전은 Android와 Termux 위에서 돌아갔습니다.\nTermux는 Android용 터미널 환경인데, 바로 이 도구 덕분에 아이디어가 비로소 실제처럼 느껴졌습니다. 처음에는 휴대폰이 주로 제 노트북으로 SSH 접속하는 통로, 그러니까 이미 잘 동작하던 개발 환경에 닿기 위한 길에 가까웠습니다. 제가 믿고 쓰던 머신을 멀리서 조종하는 리모컨에 가까웠을 뿐, 그 자체로 하나의 개발 환경은 아니었던 셈이죠.\n이 설정에는 묘한 매력이 있었지만, 그만큼 마찰도 적지 않았습니다.\n우선 Android 기기가 있어야 했고, 작은 화면에서도 참고 쓸 만한 터미널 emulator와 Virtual Private Network(VPN) 접근이 필요했습니다. 거기에 더해 키, shell 설정, kube config, 폰트, 단축키, 그리고 네트워크가 바뀌어도 무너지지 않을 만큼의 환경 설정까지 갖춰야 했습니다.\n잘 동작할 때는 정말 놀라웠습니다. 책상에서 멀리 떨어져 있어도 의미 있는 조사를 시작할 수 있었으니까요. 훨씬 더 잘 갖춰진 머신이 무거운 일을 도맡는 동안, 저는 그저 작은 화면을 들고 있기만 하면 됐습니다.\n반대로 실패할 때는 아주 평범한 방식으로 실패했습니다. VPN이 붙지 않거나, 키보드가 제가 입력하던 줄을 가리거나, 키 하나가 빠져 있거나, 세션이 툭 끊기는 식이었죠. 터미널 자체는 어디로든 들고 다닐 수 있었지만, 그 터미널까지 가닿는 길은 늘 매끄럽지만은 않았습니다.\n이런 깨짐은 대개 하나의 큰 사고라기보다 작은 모서리들이 한꺼번에 걸리는 연쇄에 가까웠습니다. 모바일 네트워크가 Wi-Fi에서 셀룰러로 넘어가는 사이 VPN 터널이 조용히 죽고, SSH 세션은 잠깐 버티다가 하필 에이전트가 확인을 요청하는 순간 멈췄으며, 휴대폰 키보드는 명령 flag를 멋대로 자동 수정하거나 가장 곤란한 위치에 보이지 않는 줄바꿈을 끼워 넣곤 했습니다.\n환경 drift도 만만치 않은 문제였습니다. 제 노트북 shell에는 몇 년 동안 쌓인 습관이 — alias, 패키지 버전, 기본 editor 설정, SSH config, prompt 동작, 그리고 의존하고 있는 줄도 몰랐던 자잘한 스크립트들이 — 켜켜이 배어 있었습니다. 그중 필요한 만큼만 Android에 다시 옮겨두는 것은 가능했지만, 결코 완전히 같지는 않았고, 빠진 세부 하나하나가 휴대폰은 개발 환경 자체가 아니라 그저 개발 환경으로 들어가는 좁은 문일 뿐이라는 사실을 자꾸 상기시켰습니다. 진짜 환경은 늘 그 문 너머 어딘가에 있었으니까요.\n그래도 이 시기는 제게 중요한 것을 하나 가르쳐줬습니다. 가치는 휴대폰 그 자체에 있던 게 아니라, 살아 있는 개발 표면이 텍스트를 통해 도달 가능해졌다는 사실에 있었다는 점입니다.\n노트북에서 pod 직접 접속으로 Kubernetes가 바꾼 것은 아이디어의 크기보다 접근 경로였습니다.\n예전 경로는 여전히 제 노트북에 기대고 있었습니다. 휴대폰이나 다른 원격 기기에서 먼저 노트북으로 SSH 접속을 한 뒤, 이미 VPN과 kube config, credential, alias, 그리고 손에 익은 습관까지 갖춰진 그 익숙한 shell에서 비로소 Kubernetes pod나 development namespace로 들어가 로그와 설정, 실행 중인 process를 들여다보는 식이었죠. 휴대폰이 pod와 직접 대화하는 구조는 아니었습니다. 노트북은 문제가 사는 곳이라기보다, 그곳으로 건너가기 위한 다리였던 셈입니다.\n직접 접속은 이 경로를 바꿔놓았습니다. 그렇다고 pod가 production이 되거나 조심할 필요가 사라진 건 아니고, 다만 한 단계가 줄었을 뿐입니다. 노트북을 한 번 거친 뒤에야 관련 로그와 config, process에 도착하는 대신, 처음부터 그 자리에서 시작할 수 있게 되었고, 덕분에 디버깅 context도 덜 끊겼습니다.\nAndroid와 Termux 설정은 이 경로를 한층 더 짧게 줄여줬습니다. Termux와 VPN 접근, 그리고 기기 안의 kube config만 충분히 갖춰지면, 노트북을 거치지 않고 Android에서 바로 Kubernetes 환경으로 들어갈 수 있었으니까요. 같은 작은 화면이 이제 서비스가 실제로 살아 있는 곳과 곧바로 이어진 셈입니다.\n여기서 중요한 건 모든 작업을 pod 안에서 해야 한다는 이야기가 아닙니다. 그런 규칙은 오히려 나쁜 규칙이죠. 핵심은 에이전트가 shell의 출처를 거의 신경 쓰지 않는다는 데 있습니다. 그 shell이 노트북에서 왔든, 원격 virtual machine에서 왔든, Android에서 왔든, container에서 왔든, 파일과 명령과 로그와 권한만 갖춰져 있으면 loop는 변함없이 돌아갑니다.\n그 덕분에 이동 중에 pod로 직접 접근하는 일도 제법 쓸모 있어졌습니다. 실행 중인 서비스 가까이에서 동작을 확인해야 할 때면, 알맞은 development 환경에 들어가 에이전트에게 로그를 읽히고, 설정을 확인시키고, 실패 경로를 추적하게 할 수 있습니다. 무언가를 생각하기 시작하려고 온 세상을 로컬에 다시 구축할 필요가 줄어든 거죠.\n이런 설정에서 저는 에이전트가 조심스러운 operator처럼 행동하기를 바랍니다. 바꾸기 전에 먼저 읽고, mutation보다 관찰을 앞세우고, 사실과 추측을 분리하고, 공유 환경에 영향을 줄 수 있는 명령 앞에서는 멈춰 묻기를요. 터미널에서는 이런 경계를 표현하기가 쉽습니다. 작업이 이미 명령 중심으로 흘러가고 있기 때문입니다.\n바로 이 지점에서 생활의 변화와 기술의 요구가 만납니다. 생활의 장점은 책상 밖에서도 얼마든지 조사를 시작할 수 있다는 것이고, 기술적인 조건은 그럼에도 환경을 여전히 조심스럽게 다뤄야 한다는 것입니다. 원격의 편리함은 운영 규율의 필요를 줄여주기는커녕, 오히려 그것을 더 중요하게 만듭니다.\n물론 분명한 경계는 필요합니다. Production 시스템은 보호받아야 하고, credential은 신중히 다뤄야 하며, 어떤 명령은 결코 가볍게 위임해서는 안 됩니다. 하지만 development pod나 통제된 환경에서라면 터미널 에이전트는 자연스럽게 들어맞습니다. Kubernetes 작업 자체가 이미 명령의 형태를 띠고 있기 때문입니다.\n모바일 코드 작업은 더 이상 Android 전용이 아니다 최근의 변화는, 이 모바일 워크플로우가 더 이상 Android와 Termux에만 묶여 있지 않다는 점입니다.\nClaude Code의 remote work 기능은 그 변화를 보여주는 하나의 예입니다. 저는 이것이 이야기의 전부라고 보지도, 어떤 단일 도구가 이 패턴을 독점한다고 생각하지도 않습니다. 다만 워크플로우가 어디로 향하고 있는지는 꽤 잘 보여줍니다. 원격 머신이 개발 환경을 떠안고, 사람은 훨씬 가벼운 client를 통해 그것과 상호작용하는 방향으로요.\n이 점이 중요한 이유는, 예전 설정에 전제 조건이 지나치게 많았기 때문입니다. Android 기기와 terminal emulator, VPN, SSH key, 환경 설정은 물론, 그 모든 것이 일상처럼 익숙해질 때까지 버텨낼 인내심까지 필요했으니까요.\n이제는 같은 기본 아이디어가 Claude app을 통해 펼쳐질 수 있습니다. 책상에서 멀리 떨어져 있어도 app을 열어 원격 머신에서 돌아가는 작업에 닿을 수 있죠. 에이전트에게는 여전히 실제 환경이, 그러니까 파일과 명령과 테스트와 권한이 필요하지만, 사람이 들어가는 입구만큼은 더 이상 손으로 일일이 조립한 모바일 터미널 stack일 필요가 없어졌습니다.\n이것은 생활의 측면에서 꽤 의미 있는 변화입니다. 이제 휴대폰은 워크스테이션인 척할 필요 없이 control surface가 되고, 실제 일은 알맞은 설정을 갖춘 머신에서 일어나면 되니까요.\n진입 장벽도 실질적으로 낮아집니다. 이 기기에 맞는 terminal profile이 있는지, VPN이 지금 멀쩡한지, 모바일 키보드가 필요한 key combination을 제대로 보낼 수 있는지 매번 확인할 필요가 없어지니까요. 그냥 app을 열고, 원격 작업 컨텍스트를 찾아, 하던 일을 이어가면 됩니다.\n그렇다고 책임까지 사라지는 건 아닙니다. 오히려 들어가는 길이 부드러울수록 리뷰 습관은 더 중요해집니다. 일을 시작하기가 쉬워질수록, 어떤 일을 시작할지를 더 의식적으로 골라야 하기 때문입니다. 원격 에이전트는 여전히 계획과 건드린 파일, 실행한 명령, 그리고 그 변경이 동작한다는 증거를 보여줘야 합니다. 편의성이 ownership을 대신해주지는 않습니다.\n그래서 저는 app에서 시작할 때면 작업의 크기를 작게 유지하려고 합니다. 모바일 세션은 조사를 막 시작하거나, 집중된 패치를 요청하거나, 테스트 결과를 확인하거나, 막연한 버그 리포트를 구체적인 계획으로 바꾸기에 좋거든요. 낮은 진입 장벽은 시작을 도와주지만, 그것이 완료의 기준까지 함께 낮추도록 내버려두어서는 안 됩니다.\n바로 그래서, 눈에 보이는 UI가 터미널이 아니더라도 터미널은 여전히 중요합니다. 그 아래의 실행 계층은 변함없이 명령의 형태를 띠고 있기 때문입니다. 에이전트는 app에서 시작될 수 있지만, 정작 쓸모 있는 일은 여전히 shell과 파일, process, 로그, 테스트를 통해 일어납니다.\nIDE는 죽지 않았다 이 글은 IDE가 끝났다는 글이 아닙니다.\n저는 여전히 IDE를 좋아합니다. 낯선 코드를 읽고, debugger로 한 줄씩 따라가고, type을 탐색하고, 조심스러운 refactor를 하기에는 IDE만 한 것이 없죠. 수천 개의 reasoning token을 태울 필요가 없는 마지막 polish와 리뷰에도 잘 맞고요. 원격 에이전트 세션보다 IDE가 훨씬 잘 받쳐주는 종류의 깊은 local attention이 분명히 존재합니다.\n다만 역할은 바뀌고 있습니다.\n요즘 저는 IDE를 깊은 local work와 polish를 위한 장소로 여깁니다. 설계를 살피고, 거친 모서리를 다듬고, 이름을 신중히 바꾸고, 전체 시각적 컨텍스트 안에서 코드를 읽는 곳이죠. 터미널 에이전트는 그와는 완전히 다른 역할을 맡습니다. 그것은 portable execution layer, 그러니까 거의 어디서든 목표가 명령과 패치, 테스트, 로그로 바뀌는 자리입니다.\n이 두 역할은 서로 다투기보다 자연스럽게 맞물립니다. 제가 책상에서 떨어져 있는 동안 에이전트가 첫 pass를 해두면, 나중에 IDE를 열어 더 꼼꼼히 리뷰할 수 있습니다. 반대로 IDE로 까다로운 영역을 먼저 이해한 뒤, 터미널의 에이전트에게 반복적인 변경을 레포지토리 전체에 적용하도록 맡길 수도 있고요.\n흔한 실수는 이 모든 것을 화면과 화면 사이의 싸움으로 바라보는 것입니다. 그보다는 어떤 도구가 어떤 종류의 주의를 잘 받쳐주는지를 묻는 편이 훨씬 유용합니다.\nContext Engineering은 Environment Engineering이 된다 copy and paste 시대의 prompt engineering은 더 좋은 요청을 쓰는 일에 가까웠습니다. 모델에게 역할을 주고, 예시를 더하고, 단계별 답변을 부탁하는 식이었죠. 이런 것들은 지금도 도움이 되지만, 에이전트가 직접 행동할 수 있게 된 순간부터는 그것만으로는 부족해집니다.\n한 걸음 더 들어간 기술이 바로 context engineering입니다. 에이전트가 어떤 파일을 읽어야 하는지, 어떤 테스트가 성공을 정의하는지, 어떤 명령이 안전하고 어떤 directory가 금지 구역인지, 테스트가 실패하면 무엇을 해야 하는지, 그리고 작업이 끝났다고 말할 때 어떤 증거를 남겨야 하는지까지 정해두는 일이죠.\n일이 SSH 세션, Termux, Kubernetes pod, 원격 머신 사이를 오가기 시작하면 context engineering은 environment engineering이 되기도 합니다.\n이제 질문은 더 이상 “모델에게 무엇을 말할까?”에만 머무르지 않습니다. “이 작업은 대체 어디에서 돌아야 할까?” 역시 그만큼 중요해집니다.\n어떤 때는 그 답이 제 노트북입니다. 전체 레포지토리와 로컬 도구가 모두 거기 있으니까요. 또 어떤 때는 development pod인데, 버그가 service mesh나 secret, cluster 설정 근처에서만 모습을 드러내기 때문입니다. 그런가 하면 원격 머신이 답일 때도 있습니다. 휴대폰이 잠기거나 네트워크가 바뀌어도 작업이 계속 이어지기를 바라기 때문이죠.\n에이전트의 품질은 바로 이 환경에 크게 좌우됩니다. 아무리 똑똑한 모델이라도 잘못된 shell 안에서는 시간을 허비할 수 있고, 반대로 알맞은 shell에서 잘 정의된 작업이라면 제가 기차 안에 있든, 커피를 기다리든, 회의 사이를 오가든 그 와중에도 차곡차곡 진전될 수 있습니다.\n그래서 저는 이것을 동료에게 접근 권한을 내어주는 일처럼 생각하게 되었습니다. 중요한 질문은 그 동료가 유능한가에만 있지 않습니다. 그 동료가 맞는 방에 서 있는지, 그리고 맞는 도구를 손에 쥐고 있는지까지 함께 봐야 하죠. prompt가 의도를 정한다면, 환경은 현실을 정합니다.\n일의 질감이 바뀌었다 가장 큰 변화는 제가 타이핑하는 글자 수가 줄었다는 데 있지 않습니다. 그것도 사실이긴 하지만, 정작 핵심은 아니거든요.\n더 큰 변화는 일이 한 의자에 덜 묶이게 됐다는 점입니다.\n출근 전에 디버깅 thread를 미리 시작해둘 수도 있고, 원격 세션에서 실패한 테스트를 확인할 수도 있으며, 노트북에서 멀리 있을 때 development pod를 한번 살펴보라고 에이전트에게 부탁할 수도 있습니다. 복잡한 환경은 원격 머신이 품고 있고, 저는 더 작은 기기를 steering wheel처럼 쥐고 있으면 되는 셈입니다.\n이 변화는 작은 작업이 지니는 감정의 결까지 바꿔놓습니다. 버그 리포트가 더 이상 나중을 위한 reminder로만 남아 있지 않아도 되고, refactor 아이디어가 책상 앞에서 mental stack을 다시 쌓아 올릴 때까지 기다릴 필요도 없어집니다. 컨텍스트가 아직 머릿속에서 신선할 때, 일의 일부를 곧바로 시작할 수 있으니까요.\n물론 여기에는 위험도 따릅니다. 이동성은 자칫 압박으로 바뀔 수 있거든요. 어디서든 일할 수 있다는 말은, 일이 어디로든 침입할 수 있다는 뜻이기도 하니까요. 목적은 가능한 모든 장소에서 코딩하는 것이 아니라, 나쁜 종류의 기다림을 줄이는 데 있습니다. 생각이 필요해서 기다리는 시간이 아니라, 순전히 환경 마찰 때문에 흘려보내는 기다림을 줄이는 것이죠.\n제게 이 워크플로우의 가장 좋은 버전은 끊임없는 constant work가 아니라, 더 부드러운 handoff입니다. 원격으로 일을 시작해 증거를 모으고, 지루한 경로는 에이전트가 먼저 밟아보게 두는 거죠. 그러면 나중에 돌아왔을 때 diff와 로그, 그리고 한층 선명해진 질문을 손에 들고 다시 출발할 수 있습니다.\n이 handoff는 의외로 인간적입니다. 처음에는 그저 어지러운 생각 한 조각에서 출발할 수 있거든요. 이 endpoint가 어딘가 이상하다거나, 이 refactor가 아직 확인하지 못한 경로를 깨뜨렸을 것 같다는 정도의 막연함 말입니다. 제가 이동하는 동안 에이전트는 그 막연함을 첫 pass로 바꿔놓고, 나중에 제가 큰 화면과 full keyboard 앞에 앉았을 때 저는 더 이상 불안에서 시작하지 않습니다. artifact에서 시작합니다.\n검은 화면은 향수가 아니다 터미널이 돌아온 이유는 개발자들이 old school system administrator 흉내를 내고 싶어서가 아닙니다. 터미널이 의도와 실행 사이를 잇는 가장 깨끗한 인터페이스 중 하나이기 때문입니다.\n에이전트가 그 사실을 더 분명하게 만들었습니다.\n에이전트에게는 텍스트 지시가 필요하지만, 그것만으로는 충분하지 않습니다. 행동할 세계가 있어야 하죠. CLI는 그 세계를 읽고 바꿀 수 있는 형태로 건네주고, SSH는 그 세계에 닿게 해주며, Termux는 휴대폰조차 진지한 입구가 될 수 있음을 보여줬습니다. Kubernetes는 같은 패턴을 실제 서비스 가까이에서 쓸모 있게 만들고, Claude Code 같은 도구의 remote work 기능은 그 동일한 loop에 도달하기 위해 필요했던 모바일 설정의 부담을 덜어줍니다.\n그 결과는 모든 개발자가 IDE를 내다 버리는 미래가 아닙니다. 저는 그런 미래를 바라지 않습니다. 결과는 오히려 더 layered한 워크플로우입니다. IDE는 깊은 주의를 위한 든든한 장소로 남고, 터미널은 portable execution layer가 되며, 에이전트는 그 계층 안에서 의도를 관찰 가능한 작업으로 바꿔놓습니다.\n그래서 저는 자꾸만 검은 화면으로 돌아옵니다. 그것이 오래된 물건이어서가 아니라, 어디로든 잘 따라오기 때문입니다.\n마치며 이렇게 정리하고 보니, 결국 이 변화의 핵심은 도구 하나가 아니라 일을 대하는 태도였다는 생각이 듭니다. 터미널이든 IDE든, SSH든 Termux든 Kubernetes든, 중요한 건 \u0026ldquo;이 일을 어디서, 어떤 환경에서 돌릴 것인가\u0026quot;라는 질문을 매번 진지하게 던지게 됐다는 점이거든요. 에이전트는 제 손이 닿는 범위를 넓혀줬지만, 그 손이 무엇을 만질지 정하는 일은 여전히 온전히 제 몫으로 남아 있습니다. 그 균형을 잡아가는 과정 자체가, 요즘 제게는 가장 재미있는 엔지니어링이기도 합니다.\n그리고 이 모든 시도는 혼자 한 게 아닙니다. HyperAccel 안에는 각자의 방식으로 AI를 워크플로우에 녹여내는 동료들이 가득하고, 누군가의 시행착오가 곧 다음 사람의 출발점이 되곤 합니다. 이 글도 그런 공유의 한 조각이라고 생각해 주시면 좋겠습니다.\nUpcoming\u0026hellip; 이번 글이 \u0026ldquo;일을 어디서 돌릴 것인가\u0026quot;에 대한 이야기였다면, 다음 글에서는 한 걸음 더 들어가 그 환경을 실제로 어떻게 설계하는지를 다뤄보려 합니다. 프롬프트가 작은 설계 문서가 되는 과정, 에이전트에게 건네는 가드레일과 검증 단계, 그리고 context engineering이 environment engineering으로 넘어가는 지점을 더 구체적인 사례와 함께 정리해 공유하겠습니다.\nHyperAccel은 AI가 우리의 워크플로우에 자연스럽게 스며드는 방식을 끊임없이 탐색하고 있습니다. 앞으로도 그 시행착오와 인사이트를 계속 나누겠습니다.\nHyperAccel 채용 중! 사실 우리가 이 테크 블로그를 운영하는 큰 이유 중 하나는 최고의 인재를 끌어오기 위해서입니다!\n저희가 다루는 기술에 관심이 있고, 이 혁신의 흐름에 함께하고 싶다면 아래 링크에서 지원해 주세요. HyperAccel Career\nHyperAccel에는 뛰어난 엔지니어들이 가득합니다. 함께할 날을 기다리고 있겠습니다.\n","permalink":"https://hyper-accel.github.io/posts/moving-back-to-terminals/","summary":"AI 코딩 에이전트는 코드를 쓰는 방식만 바꾸지 않았습니다. SSH, Termux, Kubernetes pod, 원격 머신 위에서 일이 시작되는 방식까지 바꾸고 있습니다.","title":"터미널로 돌아가자: 에이전트가 원격 개발을 자연스럽게 만든 방식"},{"content":" 이 글은 AI 시대의 필수 소비재, 메모리 이해하기 시리즈의 4편입니다. 1편, 2편, 3편 에서는 GPU 옆 메모리 계층의 빈 자리를 채우는 High Bandwidth Flash(HBF) 를 다뤘습니다. 이번 편부터는 시점을 GPU 바깥, 시스템 레벨로 옮겨서 Compute Express Link(CXL) 이 메모리 계층의 어디를 채우는지 살펴봅니다.\n들어가며 안녕하세요, HyperAccel에서 RTL Designer로 재직 중인 신승빈입니다.\n지난 1-3편을 통해 우리는 GPU 바로 옆의 메모리 계층 을 깊게 들여다보았습니다. HBM은 DRAM을 쌓아 대역폭을 끌어올렸고, HBF는 NAND에 HBM의 패키징을 입혀 용량을 끌어왔죠.\n그런데 데이터센터 메모리 얘기를 하다 보면 GPU 옆이 아닌 다른 자리에서 자꾸 들리는 이름이 있습니다. 바로 CXL 입니다.\n\u0026ldquo;메모리 풀(pool)을 만든다\u0026rdquo;, \u0026ldquo;VM 사이에 메모리를 공유한다\u0026rdquo;, \u0026ldquo;AI 서버의 hot/warm/cold 데이터를 계층화한다\u0026rdquo; 같은 이야기에 빠지지 않고 등장하는 키워드죠.\n그런데 막상 CXL을 검색해 보면 약자부터 다양합니다. CXL.io, CXL.cache, CXL.mem이 있고, Type 1·2·3 device가 있으며, 버전도 1.1, 2.0, 3.0, 3.1, 3.2까지 등장합니다. 진입 장벽이 꽤 높은 인터페이스입니다.\n그래서 이번 편에서는 한 가지 질문에서 출발하려고 합니다.\n\u0026ldquo;이미 DDR도 있고 PCIe도 있는데, 왜 또 새로운 인터페이스가 필요했을까?\u0026rdquo;\n이 질문에 답해 보면 CXL이 메모리 계층 어디에 자리잡는지, 그리고 메모리 3사(삼성, SK하이닉스, 마이크론)가 일제히 CXL 제품 라인업을 키우는 이유가 자연스럽게 보입니다.\n이 포스팅의 내용은 제가 개인적으로 공부하고, 경험한 내용을 바탕으로 작성되었습니다. 오류가 있다면 언제든지 댓글로 알려주세요.\n왜 또 새로운 인터페이스인가 — DDR과 PCIe 사이의 빈 자리 결론부터 말하면, DDR은 늘릴 수 없고 PCIe는 메모리로 쓰기 어렵기 때문 입니다.\n서버 한 대 안에서 CPU가 데이터를 주고받는 통로는 크게 두 가지입니다.\nDDR 채널: CPU 바로 옆의 DRAM 모듈과 연결되는 메모리 전용 버스 PCIe: GPU, NIC, SSD 같은 주변장치와 연결되는 범용 직렬 버스 이 두 통로는 각자 잘하는 역할이 명확합니다. 그런데 두 통로 모두 한계에 부딪혀 있습니다.\nDDR의 한계: 채널 수가 곧 천장 CPU가 DDR DRAM을 더 붙이려면 메모리 채널을 늘려야 합니다. 그런데 채널을 늘리려면 CPU 패키지의 핀 수가 늘어나고, 메인보드 배선도 같이 복잡해집니다.\n서버용 CPU의 최신 세대도 채널 수는 8-16개 수준에서 멈춰 있고, 채널당 모듈 수도 1-2개로 제한됩니다.\n결과적으로 한 소켓의 DRAM 용량은 수 TB가 천장입니다. 그 이상은 물리적으로 못 붙이는 구조죠.\nLLM 추론이 한 노드에서 다루는 데이터(KV cache, 모델 weight, 임베딩)가 수십 TB로 불어나면서, 이 천장에 닿는 상황이 점점 잦아지고 있습니다.\nPCIe의 한계: 빠르지만 일관성이 없다 그럼 PCIe로 메모리를 붙이면 어떨까요? PCIe Gen5는 16-lane 기준 단방향 약 64 GB/s (양방향 합산 128 GB/s)의 대역폭을 제공합니다. DDR5 채널 하나(약 50 GB/s)와 견줄 만합니다.\n공교롭게도 이 64 GB/s는 3편에도 등장했던 숫자입니다. HBF를 GPU 옆에 붙일 때 \u0026ldquo;대역폭 천장\u0026quot;으로 지목됐던 바로 그 PCIe죠. 그런데 메모리 확장이라는 관점에서 보면 이 대역폭 자체는 그렇게 부족하지 않습니다. 진짜 걸림돌은 다른 데 있습니다.\nPCIe로 메모리를 붙일 때 생기는 문제는 두 가지입니다.\n첫째, 캐시 일관성(cache coherency)이 없습니다. 캐시 일관성이란 여러 주체(CPU 코어, 디바이스)가 같은 메모리 주소를 각자 캐싱하더라도, 한쪽이 값을 바꾸면 나머지도 항상 최신 값을 보도록 보장하는 성질입니다. DDR 메모리는 CPU의 일관성 도메인 안에 있어 CPU의 캐시 계층과 메모리 컨트롤러가 이를 자동으로 보장하지만, PCIe는 그 도메인 바깥에 있습니다. CPU가 PCIe 장치의 메모리를 직접 load/store 하려면 이 일관성이 캐시 라인 단위로 보장되어야 합니다. PCIe는 본래 패킷 기반 I/O 프로토콜이라 이 보장이 없습니다. PCIe 메모리를 메인 메모리처럼 쓰려면 OS가 명시적으로 데이터를 옮겨주는(memcpy 등) 방식이 필요합니다.\n둘째, 메모리 시맨틱이 거칩니다. PCIe는 64B 캐시 라인이 아니라 더 큰 transaction 단위로 동작합니다. 메모리처럼 작은 단위로 fine-grained access를 할 수 없습니다.\nPCIe로 메모리를 붙일 수는 있지만, CPU 입장에서는 그 메모리가 \u0026ldquo;내 메모리\u0026quot;가 아닌 \u0026ldquo;남의 메모리\u0026quot;입니다.\n빈 자리: 캐시 일관성 있는 메모리 인터페이스 지금까지 정리를 한 줄로 묶으면 이렇습니다.\nDDR처럼 일관성 있는 메모리 인터페이스인데, PCIe처럼 시스템 외부로 확장할 수 있는 무언가가 필요하다.\n이 빈 자리를 채우기 위해 등장한 표준이 바로 CXL 입니다.\nCXL은 처음부터 새로 만든 물리 계층이 아닙니다. PCIe의 물리 계층(PHY)을 그대로 빌려 쓰면서, 그 위에 캐시 일관성을 지원하는 새로운 프로토콜을 얹은 표준입니다.\nPCIe 5.0이라는 기성 인프라 위에 캐시 일관성 계약을 추가한 고속 인터커넥트 표준. 이것이 CXL의 핵심 아이디어입니다.\nCXL의 세 얼굴 — CXL.io / CXL.cache / CXL.mem CXL은 하나의 프로토콜이 아니라 세 개의 sub-protocol 묶음입니다. 하나의 PCIe 링크 위에서 셋이 동시에 흐릅니다.\nSub-protocol 역할 모델 CXL.io 디바이스 발견, 설정, DMA PCIe와 동일 CXL.cache 디바이스가 호스트 메모리를 캐싱 디바이스 → 호스트 CXL.mem 호스트가 디바이스 메모리를 직접 접근 호스트 → 디바이스 이름만 봐서는 헷갈리니, 각자의 역할을 풀어 보겠습니다.\nCXL.io — PCIe와 같은 토대 CXL.io는 사실상 PCIe와 동일 합니다. 디바이스를 발견하고(enumeration), 설정 공간을 읽고(configuration), 인터럽트를 전달하고, DMA로 큰 데이터를 옮기는 일을 합니다.\n모든 CXL 디바이스는 반드시 CXL.io를 구현해야 합니다. CXL을 PCIe 위에 얹은 표준으로 만든 이유가 여기 있습니다. 기존 PCIe 인프라(OS 드라이버, BIOS, 컨트롤러 IP)를 그대로 재활용할 수 있도록 한 것이죠.\nCXL.cache — 디바이스가 CPU 메모리를 캐싱 GPU나 가속기 같은 디바이스가 CPU의 메인 메모리를 자주 읽는 경우를 생각해 봅시다.\nPCIe라면 매번 메인 메모리에서 데이터를 가져와야 합니다. 그런데 만약 디바이스 안에 작은 캐시를 두고, 자주 쓰는 데이터를 거기에 저장해 두면 어떨까요? CPU와 디바이스가 같은 데이터를 보고 있다는 보장만 있다면, 통신량을 크게 줄일 수 있을 겁니다.\nCXL.cache 는 정확히 이 일을 합니다. 디바이스가 호스트 메모리를 캐시 라인 단위(64B)로 캐싱 하고, 그 캐시가 CPU 캐시와 일관성을 유지 하도록 합니다.\n내부적으로는 CPU의 캐시 일관성 프로토콜(예: MESI)을 CXL 링크 너머로 확장한 형태입니다. 디바이스가 캐시 라인을 가져갈 때 어떤 상태(Modified/Exclusive/Shared/Invalid)로 가져갈지, 다른 캐싱 에이전트가 그 라인을 가지고 있으면 어떻게 처리할지가 모두 표준화되어 있습니다.\nCXL.mem — CPU가 디바이스 메모리를 메인 메모리처럼 반대 방향도 있습니다. 디바이스에 메모리(DRAM, 또는 그 이상)를 잔뜩 달아 놓고, CPU가 그 메모리를 자신의 메인 메모리처럼 load/store 하고 싶은 경우입니다.\nCXL.mem 이 이 역할을 담당합니다. CPU 입장에서는 디바이스 메모리가 자신의 물리 주소 공간 안의 한 구간으로 보이고, 일반적인 load/store 명령으로 직접 접근할 수 있습니다.\n여기서 중요한 점은 CPU가 일관성을 책임지는 주체(home agent) 역할을 한다 는 것입니다. Type 3처럼 디바이스가 메모리만 들고 있는 경우, 호스트가 단독으로 일관성을 관리하면 충분합니다.\n반면 Type 2처럼 디바이스도 자체 캐시를 가지는 경우 에는 한 캐시 라인의 \u0026ldquo;주인\u0026quot;을 디바이스로 둘지 호스트로 둘지 명시적으로 표시하는 bias-based coherency 가 적용됩니다. 주인이 된 쪽이 그 라인의 일관성을 책임지므로, 양방향 일관성 트래픽을 크게 줄일 수 있습니다.\n복잡하게 들리지만, 실제 구현 부담은 디바이스 쪽에서는 가벼운 편입니다. Type 3의 경우 디바이스는 그저 메모리 컨트롤러처럼 read/write 요청에 응답하면 됩니다.\n세 프로토콜의 조합 CXL 디바이스는 자신이 어떤 일을 하느냐에 따라 세 프로토콜을 골라 구현합니다.\n디바이스에 자체 메모리가 없고 호스트 메모리를 캐싱만 하는 경우: CXL.io + CXL.cache 디바이스에 메모리가 있고 호스트가 그걸 자기 메모리처럼 쓰기만 하면 되는 경우: CXL.io + CXL.mem 디바이스에 메모리도 있고, 그 디바이스가 호스트 메모리도 캐싱해야 하는 경우: CXL.io + CXL.cache + CXL.mem 이 세 가지 조합이 다음 절에서 다룰 Type 1 / Type 2 / Type 3 디바이스 의 기준이 됩니다.\n무엇을 꽂을 것인가 — Type 1 / 2 / 3 디바이스 세 가지 sub-protocol을 어떻게 조합하느냐에 따라 CXL 디바이스는 세 가지 타입으로 나뉩니다.\nType 1 Type 2 Type 3 사용 프로토콜 CXL.io + CXL.cache CXL.io + CXL.cache + CXL.mem CXL.io + CXL.mem 디바이스 자체 메모리 없음 있음 있음 호스트 메모리 캐싱 함 함 안 함 대표 예시 SmartNIC, FPGA 가속기 GPU, AI 가속기 메모리 확장 모듈 각 타입의 역할과 활용처를 풀어 보겠습니다.\nType 1 — 캐싱만 하는 가속기 Type 1 디바이스는 자체 메모리는 없고, 호스트 메모리를 캐싱 합니다.\n대표적인 후보는 SmartNIC 입니다. 네트워크에서 들어오는 패킷을 처리할 때 호스트의 디스크립터 큐나 패킷 버퍼를 빈번하게 읽습니다. 이걸 매번 호스트 메모리까지 다녀오는 대신 NIC 내부 캐시에 보관하고 일관성을 유지하면, 패킷 처리 지연을 크게 줄일 수 있습니다.\nFPGA 가속기처럼 호스트 자료구조를 자주 참조하는 워크로드 에서 Type 1이 가치를 발휘합니다.\nType 2 — 메모리와 캐시를 모두 가진 가속기 Type 2 디바이스는 자체 메모리도 있고, 호스트 메모리도 캐싱 합니다. 세 프로토콜을 모두 씁니다.\n전형적인 예는 CXL을 통해 붙는 GPU나 AI 가속기 입니다. 가속기는 자체 HBM/GDDR을 가지고 있지만, 모델 weight나 입력 데이터를 호스트 메모리에서 가져와 캐싱하기도 합니다. CXL.cache로 호스트 데이터를 가져오고, CXL.mem으로 가속기의 메모리를 호스트에 노출합니다.\n문제는 Type 2가 가장 구현이 복잡한 타입이라는 것입니다. 일관성 관리를 양방향으로 해야 하므로, 디바이스 쪽 컨트롤러 부담이 큽니다. 그래서 실제 양산되는 Type 2 디바이스는 아직 많지 않습니다.\nType 3 — 가장 흔히 보이는 메모리 확장 모듈 Type 3 디바이스는 자체 메모리만 있고, 호스트 메모리는 캐싱하지 않습니다. CXL.io와 CXL.mem만 구현하면 됩니다.\n쉽게 말하면 \u0026ldquo;CXL 인터페이스를 단 메모리 모듈\u0026rdquo; 입니다. 호스트 입장에서는 DDR 모듈을 한 단계 멀리 둔 것처럼 보이고, 일반적인 load/store로 접근할 수 있습니다.\n현재 양산되거나 상용화 직전인 CXL 제품의 대부분은 Type 3 입니다. 이유는 명확합니다.\n구현 복잡도가 가장 낮고 DDR 채널의 천장을 가장 직접적으로 풀어 주며 기존 메모리 사업자의 제품 라인업으로 자연스럽게 이어집니다 뒤에서 살펴볼 메모리 3사의 CXL Memory Module(CMM) 제품군도 모두 Type 3입니다.\n한 디바이스에서 패브릭으로 — CXL 1.1 → 2.0 → 3.x CXL은 2019년에 1.0이 나온 이후로 빠르게 진화하고 있습니다. 버전마다 추가되는 기능은 결국 한 가지 방향을 가리킵니다.\n메모리를 더 멀리, 더 많이, 더 여러 호스트가 공유할 수 있게.\n각 버전의 핵심 변화를 짚어 보겠습니다.\nCXL 1.1 — 한 호스트에 직접 연결 가장 기본 형태입니다. 하나의 호스트 CPU에 하나의 CXL 디바이스를 PCIe 슬롯처럼 직접 연결 합니다.\n이 단계에서 CXL은 \u0026ldquo;DDR 옆에 추가 메모리를 한 단계 멀리 붙이는\u0026rdquo; 도구입니다. 한 노드의 메모리 용량을 늘리는 것이 주된 목적이지, 다른 노드의 메모리까지 확장하는 것은 아닙니다.\nCXL 2.0 — 스위치와 메모리 풀링 2020년에 나온 2.0에서 결정적인 변화가 일어납니다. CXL 스위치 가 도입되어 여러 호스트와 여러 메모리 디바이스를 그물처럼 엮을 수 있게 됩니다.\n가장 인상적인 응용은 메모리 풀링(memory pooling) 입니다. 데이터센터의 메모리 활용률은 평균적으로 40-50% 수준입니다. 어떤 서버는 메모리가 모자라고 어떤 서버는 절반 이상 비어 있는 상황이 흔하죠.\nCXL 2.0에서는 여러 호스트가 하나의 메모리 풀에서 필요한 만큼 동적으로 할당받을 수 있습니다.\n한 가지 주의할 점이 있습니다. 이때의 \u0026ldquo;공유\u0026quot;는 동시 공유가 아니라 동적 할당 입니다.\n거대한 메모리 디바이스는 Multi-Logical Device(MLD) 형태로 여러 chunk로 쪼개집니다. 그리고 Fabric Manager(FM) 라는 컨트롤 플레인이 \u0026ldquo;이 chunk는 호스트 A에게, 저 chunk는 호스트 B에게\u0026rdquo; 식으로 나눠 줍니다. 한 chunk는 한 시점에 한 호스트만 소유합니다. 그래서 캐시 일관성 충돌이 일어날 영역 자체가 없습니다.\n호텔 객실로 비유하면, 한 객실(chunk)은 한 손님(호스트)이 체크인·체크아웃 하면서 회전될 뿐, 두 손님이 같은 객실에 동시에 들어가지 않습니다.\n이 모델만으로도 서버마다 최악의 경우를 가정해 메모리를 과다 구매하는 관행을 줄이는 데에는 충분합니다. 이 단계에서 CXL은 더 이상 단일 노드의 확장 인터페이스가 아닙니다. 랙 단위 메모리 자원 관리의 기반 이 되기 시작합니다.\nCXL 3.x — 패브릭과 멀티 호스트 코히런스 3.0(2022), 3.1(2023), 3.2(2024)까지 이어지는 흐름은 더 야심차게 갑니다.\n핵심은 두 가지입니다.\n첫째, 동적 할당에서 진짜 공유로. 2.0의 풀링이 \u0026ldquo;한 chunk = 한 시점에 한 호스트(번갈아 배정)\u0026ldquo;였다면, 3.x에서는 여러 호스트가 같은 메모리 영역을 동시에 읽고 쓰면서 캐시 일관성을 HW가 유지 합니다. 이를 Global Fabric Attached Memory(GFAM) 라고도 부릅니다. 여기서도 할당(접근 권한 부여)이 사라지는 것은 아닙니다. 2.0이 한 chunk를 한 호스트에게 배타적으로 줬다면, 3.x는 같은 영역을 여러 호스트가 동시에 접근하도록 Fabric Manager가 허용해 준다는 점이 다를 뿐입니다. 이 단계부터 진짜 conflict가 발생할 수 있고, 호스트와 디바이스의 home agent 가 캐시 라인 단위로 이를 해소합니다.\n둘째, 포트 단위 연결에서 패브릭(fabric) 연결로. 3.x는 다수의 CXL 스위치를 엮어 큰 규모의 패브릭을 구성합니다. 여기서 Port-Based Routing(PBR) 은 목적지를 포트 ID 기준으로 라우팅하는 방식인데, 기존 트리 구조의 한계를 넘어 mesh·dragonfly·3D torus 같은 다양한 토폴로지와 대규모 디바이스 배치를 가능하게 합니다.\n이 단계까지 오면 CXL은 사실상 데이터센터 내부의 새로운 인터커넥트 표준 으로 자리잡습니다. NVIDIA의 NVLink, 그리고 UALink(가속기 연결용 오픈 표준) 같은 가속기 인터커넥트와도 비교 대상이 되기 시작하죠.\n지금 2026년 시점에서 양산되는 제품은 대부분 CXL 2.0 을 지원합니다. 3.x는 표준은 나와 있지만 실제 디바이스와 호스트 CPU의 지원이 막 따라잡는 단계입니다.\n메모리 3사가 그리는 CXL 청사진 CXL의 큰 그림을 짚었으니, 실제 제품으로 내려와 보겠습니다.\n흥미로운 점은 표준을 주도하는 곳이 인텔, AMD, 마이크로소프트, 메타 같은 컨소시엄 멤버들임에도 불구하고, 양산 제품 라인업을 가장 공격적으로 펼치고 있는 쪽은 메모리 3사 라는 것입니다. 삼성, SK하이닉스, 마이크론이 거의 같은 시기에 비슷한 형태의 CXL 메모리 모듈을 발표했죠.\n세 회사의 제품군을 정리해 보면 다음과 같습니다.\n회사 대표 제품 폼팩터 핵심 특징 삼성 CMM-D (CXL Memory Module - DRAM) E3.S 단순 메모리 확장, CXL 2.0 삼성 CMM-B (CXL Memory Module - Box) 박스형 어플라이언스 랙 레벨 메모리 풀링 삼성 CMM-H (CXL Memory Module - Hybrid) E3.S DRAM + NAND 하이브리드 SK하이닉스 CMM-DDR5 E3.S DDR5 기반 메모리 확장 SK하이닉스 CMM-Ax E3.S 메모리 + 연산 엔진 통합 마이크론 CZ120 / CZ122 E3.S 메모리 확장 모듈 대부분 폼팩터가 E3.S 인 것이 눈에 띕니다. 서버 스토리지에서 흔히 보이는 핫스왑 가능한 표준 폼팩터로, 이미 데이터센터 배치 노하우가 쌓여 있어 채택 장벽이 낮습니다.\n용량은 모델에 따라 96 GB - 256 GB 수준이고, 인터페이스는 PCIe Gen5 x8을 공통으로 사용합니다. 세 회사 제품의 스펙은 의외로 비슷합니다. 진짜 차이는 \u0026ldquo;메모리 모듈로 끝낼 것이냐, 그 다음 칸까지 갈 것이냐\u0026quot;에서 갈립니다.\n1차 라인: 정직한 메모리 확장 (Type 3 그대로) 가장 기본적인 제품은 그냥 CXL 인터페이스를 단 DDR5 메모리 모듈 입니다.\n삼성 CMM-D, SK하이닉스 CMM-DDR5, 마이크론 CZ120/CZ122 가 모두 이 카테고리에 속합니다. 호스트 입장에서는 \u0026ldquo;조금 멀리 있는 DDR 모듈\u0026quot;처럼 보이고, 일반적인 load/store로 접근합니다. 타깃 워크로드는 명확합니다. 소켓당 DRAM 용량의 천장에 닿은 워크로드 입니다.\nin-memory DB와 대용량 분석 LLM 추론에서 CPU 측에 두는 KV cache, 임베딩 저장소 VM consolidation 환경의 메모리 부족 노드 세 회사가 거의 동일한 스펙으로 경쟁하는 1차 격전지가 여기입니다.\n2차 라인: 풀링과 연산을 모듈 너머로 진짜 흥미로운 쪽은 다음입니다. 메모리 3사는 단순 확장 모듈에서 멈추지 않고, CXL의 후속 기능(풀링, 연산)을 자기 제품으로 끌어오는 시도를 하고 있습니다.\n대표적으로 두 갈래의 방향이 있습니다.\n풀링 박스 형태로 묶기. 삼성의 CMM-B(Box) 는 여러 장의 CMM-D를 하나의 어플라이언스에 담아 랙 레벨의 메모리 풀 을 구성합니다. CXL 2.0 스위치를 내장해, 여러 호스트가 이 박스에서 필요한 만큼 메모리를 할당받습니다.\n메모리 모듈 안에 연산 엔진을 넣기. SK하이닉스의 CMM-Ax 가 대표적이고, 삼성도 CMM-H 와 CXL-PNM 으로 비슷한 그림을 그립니다.\n이 아이디어는 Near-Memory Processing(NMP) 또는 Processing-in-Memory(PIM) 의 한 갈래입니다. 데이터를 가져와서 연산하는 대신, 데이터가 있는 곳에서 직접 연산해 결과만 가져오는 방식 이죠.\n후보 워크로드는 다음과 같은 것들입니다.\n벡터 임베딩 유사도 비교(RAG) 데이터베이스의 필터·집계 LLM 추론의 일부 단계(예: KV cache 압축, top-k 선택) 이 모델이 의미를 가지려면 데이터를 CXL 너머로 옮기는 비용이 연산 비용보다 큰 워크로드 여야 합니다. 여기서 \u0026lsquo;비용\u0026rsquo;이란 데이터 이동에 드는 시간(latency) 과 대역폭·전력 소모 를 의미합니다. 거대한 임베딩 컬렉션을 호스트로 끌어와서 유사도 비교하는 대신, 메모리 모듈 안에서 끝내고 결과만 넘기면 traffic도 줄고 latency도 짧아집니다.\n2편에서 다룬 HBF + HAVEN 조합(거대 vector DB를 HBF에 올려 두고, 그 옆에 search 엔진을 붙여 RAG 유사도 비교를 그 자리에서 끝내는 발상)이 CXL 영역에서는 NMP 통합 모듈로 다시 나타나는 셈입니다.\n패브릭과 IP 진영 — 컨트롤러부터 스위치 실리콘까지 메모리 3사 외에도 CXL 생태계에서 빠지지 않는 플레이어가 있습니다. CXL 컨트롤러·스위치 IP를 공급하거나, 자체 실리콘으로 직접 만드는 회사들입니다.\nAstera Labs: Leo 시리즈 컨트롤러가 Microsoft Azure의 M-series CXL 메모리 등에 쓰이며, CXL 메모리 컨트롤러의 \u0026ldquo;표준 부품\u0026rdquo; 자리를 노리고 있습니다. Marvell, Microchip(구 Microsemi): 컨트롤러 라인업으로 IP 진영의 한 축을 차지합니다. 앞서 본 Micron CZ120도 Microchip의 SMC 2000 컨트롤러를 사용합니다. Panmnesia(파네시아): KAIST CAMELab(Computer Architecture and Memory Systems Laboratory) 에서 나온 한국 fabless 스타트업입니다. 흥미로운 연결고리가 하나 있습니다. 참고 문헌에 인용한 Memory Pooling With CXL 논문의 저자 M. Jung이 바로 이 회사를 창업한 정명수 KAIST 교수 입니다. 단순한 컨트롤러에서 멈추지 않고, CXL 3.2 fabric switch 실리콘(PANSWITCH) 까지 직접 만드는 풀스택 플레이어죠. PBR 과 mesh·dragonfly·3D torus 토폴로지처럼 3.x의 최첨단 기능을 가장 먼저 실리콘으로 구현하고 있습니다. 2026년 4월에는 하반기 양산 계획과 pre-release 실리콘 공급을 발표하며 본격적인 사업화 단계에 들어섰습니다. 메모리 회사가 자체 CXL 컨트롤러를 설계하는 경우도 있지만, 표준이 빠르게 진화하는 만큼 IP·실리콘 공급사에 위탁하거나 협업하는 경우가 흔합니다. 특히 3.x 패브릭처럼 표준 자체가 막 자리잡는 영역 은 Panmnesia 같은 전문 플레이어가 한 발 앞서 가는 모양새인데, 한국 반도체 생태계 입장에서 봐도 꽤 흥미로운 지점이죠.\n메모리 회사들이 일제히 CXL에 들어가는 이유 세 회사가 거의 같은 시기에 같은 카테고리의 제품을 내는 데에는 공통된 동기가 있습니다.\n메모리가 \u0026ldquo;모듈을 끼우는 것\u0026quot;에서 \u0026ldquo;시스템 안에 자리를 차지하는 것\u0026quot;으로 한 단계 올라설 수 있는 기회.\n구체적으로는 세 가지 효과가 있습니다.\n노드당 판매 용량 확대: DDR 채널 천장 너머로 메모리를 더 팔 수 있음 모듈 단가 상승 여지: 풀링·NMP 같은 부가 기능으로 차별화 가능 솔루션 사업 진입: 단순 부품이 아니라 풀링 어플라이언스(예: CMM-B) 단위로도 제안 가능 HBM이 GPU 옆 메모리 비즈니스를 키웠다면, CXL은 CPU 옆 / 시스템 메모리 비즈니스를 다시 키울 수 있는 카드 인 셈입니다. 세 회사가 비슷한 시점에 비슷한 제품군을 내는 것이 이상한 일이 아닌 이유입니다.\n그래서 진짜 쓸 만한가 — 남는 숙제 여기까지 들으면 CXL이 만능처럼 보이지만, 실제 도입 단계에서는 무시 못 할 숙제들이 있습니다.\n지연 비용(Latency Tax) CXL을 통해 붙은 메모리는 DDR 직접 연결 메모리보다 느립니다.\nDDR5 native: 약 80-100 ns CXL 메모리(Type 3): 약 170-300 ns 약 2-3배의 지연 입니다. 이건 PCIe PHY 위에 프로토콜을 얹은 구조에서 오는 본질적인 비용입니다.\n이 비용을 감안하면 CXL 메모리는 메인 메모리 전체를 대체하는 자리가 아니라, \u0026ldquo;가까운 DDR + 한 단계 멀리의 CXL\u0026quot;이라는 2-tier 메모리 구성 의 두 번째 칸으로 들어가는 것이 자연스럽습니다.\n소프트웨어 스택 성숙도 CPU 입장에서 CXL 메모리는 \u0026ldquo;약간 느린 NUMA 노드\u0026quot;처럼 보입니다. 그래서 OS와 런타임이 어떤 데이터를 가까운 DDR에 두고 어떤 데이터를 CXL에 보낼지 결정 해야 합니다.\nLinux 커널은 CXL 드라이버, hot/cold page tracking, transparent page migration 등을 빠르게 정비 중이지만, 워크로드별 최적 튜닝까지는 아직 시간이 필요합니다.\n특히 LLM 추론처럼 메모리 접근 패턴이 결정론적 인 워크로드라면 OS의 자동 tiering보다 애플리케이션이 직접 데이터 배치를 결정하는 편이 더 효율적입니다. 이 부분은 아직 개척의 여지가 많은 영역입니다.\nType 2의 빈 자리, Type 3 위주의 현실 표준상으로는 Type 1·2·3이 모두 정의되어 있지만, 실제 시장은 Type 3 중심으로 굴러가고 있습니다. Type 2가 갖는 양방향 일관성의 복잡도, 그리고 GPU 벤더들이 자체 인터커넥트(NVLink 등)를 밀고 있는 사정이 겹쳐서 그렇습니다.\nCXL이 정말 \u0026ldquo;가속기 인터커넥트의 표준\u0026quot;까지 갈지, 아니면 메모리 확장 + 풀링 표준 으로 자리잡을지는 아직 열려 있는 질문입니다.\n마무리 \u0026amp; 다음 편 예고 이번 글에서는 CXL이 메모리 계층에서 어떤 빈 자리를 채우는지, 어떤 부품들로 구성되어 있는지를 살펴봤습니다.\n정리하면 이렇습니다.\n빈 자리: DDR은 한 노드 안에서 채널 천장이 명확하고, PCIe는 일관성이 없어 메모리로 쓰기 어렵다. 그 사이의 자리. 세 얼굴: CXL.io(PCIe와 동일), CXL.cache(디바이스가 호스트 캐싱), CXL.mem(호스트가 디바이스 메모리 직접 접근). 세 타입: Type 1(캐시만), Type 2(메모리+캐시), Type 3(메모리 확장). 시장은 Type 3 중심. 표준 진화: 1.1(단일 호스트) → 2.0(스위치, 풀링) → 3.x(패브릭, 멀티 호스트 코히런스). 메모리 3사의 CMM: 1차는 정직한 메모리 확장(삼성 CMM-D, SK하이닉스 CMM-DDR5, 마이크론 CZ120). 2차는 풀링 박스(삼성 CMM-B)와 연산 통합(SK하이닉스 CMM-Ax, 삼성 CXL-PNM). 남는 숙제: 2-3배의 latency tax, 소프트웨어 스택의 미성숙, Type 2의 빈 자리. 다만 이 글은 아직 \u0026ldquo;CXL이 무엇인가\u0026quot;에 답한 단계입니다. 진짜 흥미로운 질문은 다음입니다.\nCXL이 실제 LLM 서빙 워크로드에서 어떻게 쓰이고, 어떤 워크로드에 잘 맞는가?\n다음 5편에서는 CXL을 활용한 KV cache offload, 메모리 풀링을 통한 VM 통합, hot/warm/cold tiering 같은 구체적인 활용 사례와, 그 안에서 메모리 3사의 CMM 라인업이 어떻게 자리잡을 수 있는지를 살펴보겠습니다.\n추신 저는 HyperAccel에서 LLM 가속 ASIC 칩 출시를 위해 RTL을 설계하고 있습니다. 메모리 계층을 GPU 옆에서 GPU 바깥, 시스템 레벨까지 확장해 보니 가속기 설계자가 풀어야 할 문제도 한층 다양해집니다. 이 시리즈를 통해 메모리 기술의 흐름을 함께 이해하고, 앞으로의 변화를 함께 지켜볼 수 있으면 좋겠습니다.\nHyperAccel은 HW, SW, AI를 모두 다루는 회사로, 전 방면에 걸쳐 뛰어난 인재들이 모여 있습니다. 폭넓은 지식을 깊게 배우며 함께 성장하고 싶으신 분들은 언제든지 지원해 주세요!\n채용 사이트: https://hyperaccel.career.greetinghr.com/ko/guide\nReference Compute Express Link Consortium — Specifications CXL 3.1 Specification Overview Intel — Compute Express Link Technology Samsung — CXL Memory Module (CMM-D / CMM-B / CMM-H) SK hynix CMM-DDR5 / CMM-Ax Product Briefs Micron CZ120 / CZ122 CXL Memory Expansion Module Astera Labs Leo CXL Smart Memory Controllers Panmnesia — Full Stack CXL Link Solution Panmnesia PANSWITCH — CXL 3.2 / PCIe 6.x Fabric Switch (pre-release silicon Apr 2026, mass production H2 2026) Linux Kernel CXL Documentation D. Gouk, M. Kwon, H. Bae, S. Lee, M. Jung, \u0026ldquo;Memory Pooling With CXL,\u0026rdquo; IEEE Micro, vol. 43, no. 2, pp. 48-57, 2023. DOI: 10.1109/MM.2023.3237491 D. Das Sharma, R. Blankenship, D. S. Berger, \u0026ldquo;An Introduction to the Compute Express Link (CXL) Interconnect,\u0026rdquo; ACM Computing Surveys, vol. 56, no. 11, Article 290, 2024. DOI: 10.1145/3669900 (arXiv:2306.11227) ","permalink":"https://hyper-accel.github.io/posts/what-is-cxl/","summary":"GPU 옆은 HBM과 HBF가 채우지만, CPU 옆에는 또 다른 빈 자리가 있습니다. PCIe와 DDR 사이의 어색한 틈을 메우는 새로운 인터페이스, CXL의 기본 구조와 디바이스 타입, 그리고 메모리 3사가 그리는 CXL 제품 청사진을 살펴봅니다.","title":"AI 시대의 필수 소비재, 메모리 이해하기 4편: CXL 이해하기"},{"content":" 이 글은 AI 시대의 필수 소비재, 메모리 이해하기 시리즈의 3편입니다.\n2편 에서는 HBF가 효과적으로 쓰일 수 있는 자리들(CAG, H³, 그리고 그 너머의 후보 워크로드들)을 정리했습니다.\n이번 편에서는 HBF가 마주해야 할 새로운 워크로드들과 HBF 상용화를 위해 필요한 과제들에 대해 알아보겠습니다.\n들어가며 안녕하세요. HyperAccel DV팀 임재원입니다.\n지난 2편의 결론을 한 문장으로 요약하면 다음과 같습니다.\n워크로드를 잘 고르면 HBF의 약점은 숨길 수 있다.\nHBF가 가진 약점과 이를 극복할 수 있는 워크로드의 조건, 그리고 활용 예시인 SK하이닉스의 H³와 조지아텍의 HAVEN과 같은 아이디어들을 살펴보았습니다.\n하지만 이는 HBF의 약점을 숨길 수 있는 방법이지 완전히 극복할 수 있는 방법은 아닙니다. 여러 가지 가정이 충족된 workload에서 이룰 수 있는 조건부 아이디어입니다. LLM 워크로드가 HBF를 많이 필요로 하지 않는 방향으로 발전한다면 기술이 발전한다고 하더라도 수요는 크지 않을 것입니다. 아울러 HBF의 약점은 NAND Flash 자체의 약점이기도 합니다. HBF는 HBM의 용량 한계를 극복하기 위해 Flash를 기반으로 만들어진 대안입니다. 그리고 LLM 서비스에서는 이미 다양한 형태로 Flash memory가 사용되고 있습니다. 따라서 LLM에서 Flash가 현재 어떻게 사용되고 있는지 먼저 살펴봐야 HBF를 어떻게 활용할 수 있을지에 대한 답을 얻을 수 있습니다.\n이번 편에서는 최신 LLM workload의 추세에 대해 알아보고 Flash memory(SSD)가 LLM 서빙 환경에서 어떻게 사용되는지 살펴본 뒤 HBF가 상용화되기 위해 풀어야 할 과제들을 알아보겠습니다.\n최신 LLM 워크로드 살펴보기 지난 편에서 알아본 HBF의 단점을 숨길 수 있는 워크로드의 조건 중 하나는 워크로드가 deterministic 해야 한다 는 것이었습니다. 워크로드가 deterministic하면 NAND의 긴 latency를 prefetch로 숨길 수 있기 때문입니다. H³의 실험도 정확히 이 가정 위에 서 있습니다. 다음 layer가 어떤 weight와 KV cache를 읽을지 미리 알 수 있다면 HBF의 단점을 숨길 수 있다는 주장입니다.\n하지만 최근 frontier 모델들의 개발 방식은 이 전제를 조금 흔들고 있습니다.\nSparse attention: KV cache의 일부만 연산에 활용하기 Transformer model의 가장 중요한 연산인 attention mechanism의 가장 큰 문제는 입력 길이에 따라 연산량이 입력 길이의 제곱으로 증가한다는 것입니다.\n이를 극복하기 위해 최근 프론티어 연구들은 현재까지 입력된 token으로 만들어진 Key-Value 중 실제 연산에는 일부만 사용하거나 이를 압축한 데이터를 사용하여 연산량과 메모리 통신량을 줄이는 방법을 보여주고 있습니다. Attention mechanism은 근본적으로 모든 단어 간의 맥락을 통해 다음 토큰을 예측하지만, 실제로 중요한 토큰은 일부만 필요하다는 주장에서 비롯된 아이디어입니다. 이를 그림으로 나타내보면 아래와 같습니다.\nKV cache 자체는 연산되고 메모리에 저장되어야 하기 때문에 KV cache를 저장할 용량은 여전히 필요합니다. 이로 인해 용량적인 측면에서는 HBF의 이점을 사용할 수 있습니다. 하지만 sparse attention의 종류에 따라 KV cache를 선택하는 알고리즘이 조금씩 다르며, KV cache를 읽는 패턴도 조금씩 달라집니다.\nStreamingLLM: Attention sink + sliding window attention\n비교적 단순한 형태의 StreamingLLM 은 특정 토큰이 처음 토큰과 현재 위치 기준으로 근접한 몇 개의 토큰과의 attention만 연산합니다. 이 경우 기존의 attention 패턴과 유사하게 필요한 KV cache의 위치를 예측하는 것이 비교적 수월합니다.\n하지만 이 경우 현재 위치한 토큰이 첫 토큰과 인접한 토큰과의 관계만을 파악하여 중간에 위치한 토큰과의 관계는 완전히 무시해버린다는 단점이 있습니다.\nInfLLM \u0026amp; Quest: query-aware sparse attention\n이후에 나온 기법인 InfLLM 과 Quest 는 이를 보완하고자 조금 다른 방식을 사용합니다. 두 방식의 약간의 차이는 있지만 두 방식 모두 현재 처리 중인 토큰으로 만들어진 query와 저장된 KV cache 중 일부를 연산하여 필요한 Key-Value의 idx를 계산합니다. 이후 구해진 idx에 해당하는 Key-Value만을 사용하여 attention 연산을 진행합니다. 앞선 방식과 다른 점은 토큰에 따라 필요한 Key-Value의 위치가 달라지기 때문에 이를 미리 예측하는 것이 어렵다는 점입니다. 추가로 idx를 계산하기 위해 사용되는 Key들도 읽기 패턴이 불규칙합니다.\nCompressed Sparse Attention(CSA) \u0026amp; Heavily Compressed Attention(HCA): KV cache를 압축해서 저장하기\n가장 최근에 발표된 DeepSeek-V4에서는 앞에서 설명한 selection 방식에서 더 나아가 전체 KV cache를 토큰 방향으로 압축합니다. 이를 통해 실제 attention 연산에 사용되는 KV cache를 줄일 수 있습니다. 압축하는 과정에서 전체 KV cache가 projection matrix를 한번 거치기 때문에 read가 최소 한번 일어나고 압축된 KV cache는 이후에도 반복적으로 재사용될 수 있습니다.\n세 기법을 attention 자체의 특성과, HBF 관점에서 중요한 KV cache 접근 패턴(prediction) 두 축으로 정리하면 아래와 같습니다.\n기법 Attention 동작 / 한계 KV cache 접근 패턴 (prediction 관점) StreamingLLM 첫 토큰과 sliding window 안의 최근 토큰만 사용.\n중간 토큰과의 관계는 누락 위치가 규칙적이라 prefetch 친화적 InfLLM / Quest Query 기반으로 필요한 KV idx를 동적으로 선택.\n중간 토큰 정보를 보존 토큰마다 idx가 달라 사전 예측이 어려움 CSA / HCA KV cache를 토큰 방향으로 압축한 뒤 압축본만 attention에 사용.\n단, 압축/재사용 파이프라인이 추가되어 구현 복잡도가 높음 압축본은 위치가 결정론적이어서 예측이 쉬움 Sparse Attention과 같은 새로운 소프트웨어 기법의 등장은 HBF 적용 시 오히려 병목을 만들 수 있습니다. 읽어야 할 주소를 찾는 것이 어려워지게 되면 prefetch를 사용할 경우 miss되는 비율이 올라가거나 불필요한 양의 데이터를 읽어와야 하는 일이 생길 수 있습니다. 이 경우 HBF의 성능을 제대로 발휘하기 어려워집니다. 소프트웨어 최적화를 통해 prefetch hint를 현재 사용한 attention 기법에 맞게 주거나 하드웨어를 고려한 모델 설계가 필요합니다.\n흥미로운 점은 DeepSeek에서 발표한 paper에서는 이렇게 만들어진 KV cache를 메모리에서 어떻게 관리할 것인가에 대한 고민도 담겨 있다는 것입니다. DeepSeek은 모델 추론 서비스 과정에서 이 압축된 KV를 SSD storage에 보관하여 재사용의 이점을 살린다고 소개하고 있습니다. 이러한 방식의 메모리 맞춤형 최적화 방식은 Flash에 기반한 HBF의 활용시에도 큰 이점으로 작용할 것입니다.\n그러면 자연스럽게 LLM 서빙에서 기존의 Flash 기반 SSD storage가 어떻게 사용되고 있는지 살펴보겠습니다.\nLLM 서비스 내에서의 SSD storage 활용처 이전 글에서도 이야기한 바와 같이 증가되는 KV cache size는 앞에서 말한 압축과 희소기법을 적용하더라도 GPU HBM에서 감당하기 힘든 문제입니다. 이로 인해 KV cache를 CPU memory나, 나아가 GPU 밖의 시스템 메모리까지 offloading하여 HBM의 용량 문제를 극복하기 위한 기법들이 많이 사용되고 있습니다. 특히 대용량의 이점을 활용할 수 있는 SSD를 효과적으로 사용하기 위한 기법들이 주목을 받는 추세입니다.\n모델 로딩: Flash storage의 가장 기본적인 활용 가장 보편적인 SSD 사용 사례는 모델 가중치의 보관과 로딩 입니다. DRAM 기반 HBM은 휘발성이라 전원이 꺼지면 데이터가 사라지지만, NAND 기반 SSD는 비휘발성이기 때문에 학습이 끝난 모델 가중치를 지속적으로 보관하는 storage로 사용됩니다. 서비스가 기동될 때 SSD에 저장된 가중치를 읽어 GPU HBM에 로드하는 것이 기본적인 흐름입니다. 특히 여러 GPU 노드가 동일한 모델을 동시에 서빙하는 환경에서는 모든 노드가 접근 가능한 공유 SSD storage가 사실상 필수적입니다.\nKV cache swapping: 비활성 세션은 낮은 티어의 메모리로 vLLM 과 같은 서빙 프레임워크는 GPU HBM의 KV cache 공간이 부족해질 때 비활성 세션의 KV cache를 GPU 밖으로 swap-out 합니다. 여러 명의 사용자를 처리하는 서비스 환경에서는 어느 시점에 어떤 세션이 활성화될지 미리 알 수 없습니다. 사용자가 한참 질문을 하다가도 언제 질문을 중단하거나 다시 시작할지 알기 힘들기 때문이죠. 이러한 경우 잠시 대기 중인 세션의 KV cache가 GPU memory를 계속 점유하게 되면 신규 요청을 받을 여력이 줄어듭니다. 비활성 세션의 KV cache를 CPU DRAM 풀로 swap하거나, context가 큰 세션의 KV cache는 SSD로 swap하는 것으로 이러한 문제를 해결할 수 있습니다.\nGPU memory 자체를 SSD로 확장하기: offloading과 GPU Direct Storage 여기서 한 발 더 나아가 GPU가 사용하는 동적 메모리를 SSD로 확장하는 시도들도 활발히 이루어지고 있습니다. GPU HBM, CPU DRAM, NVMe SSD를 하나의 통합된 메모리 계층으로 다루고, 사용자 환경과 상황에 따라 최적화된 저장소 위치를 파악하고 데이터를 할당하는 것입니다.\n다만 이 접근의 본질적 한계는 데이터 경로에 있습니다. SSD → CPU DRAM → GPU 로 이어지는 긴 경로와 PCIe 대역폭에서 병목을 만들어 latency와 throughput이 크게 감소합니다.\n이 경로를 단축하기 위해 NVIDIA는 GPU Direct Storage(GDS) 기능을 제공합니다. GDS는 PCIe Peer-to-Peer DMA를 활용해 NVMe controller에서 GPU로 데이터를 write/read할 수 있습니다. 호스트 DRAM을 거치지 않으므로 CPU 메모리 대역폭 소비가 사라지고, PCIe 트래픽도 한 번으로 줄어듭니다.\n정리하면 SSD/Flash는 이미 LLM 서빙 스택의 각 계층에서 다양한 역할로 자리잡고 있고, HBM - DRAM - Flash를 하나의 통합된 메모리로서 관리하기 위한 다양한 최적화 기법이 개발되고 있습니다. 하지만 구조적인 한계도 엿볼 수 있습니다. Flash에서 GPU로 데이터를 운반하기 위해서는 구조적으로 PCIe를 활용해야 하는데, PCIe 대역폭이 HBM 대역폭에 비해 낮아 이 구간에서 피할 수 없는 병목이 발생하게 됩니다. SSD의 read latency와 운반 경로에서 더해지는 latency도 병목입니다.\n1편에서 다뤘던 메모리 계층 피라미드를 다시 살펴보겠습니다. HBF가 노리고 있는 자리는 DRAM과 SSD 사이의 자리 입니다. GPU 패키지 가까이에 배치해 access latency를 줄이고, HBM처럼 적층 + 광대역 인터페이스를 사용해 단일 디바이스의 대역폭을 SSD 대비 수십 배 수준으로 끌어올려서 SSD의 두 가지 구조적 약점(거리와 대역폭)을 device 레벨에서 동시에 보완하려는 접근입니다. 만약 이 그림이 실현된다면, 앞서 살펴본 SSD를 활용한 접근법의 문제 상당수가 device 단에서 해소될 수 있습니다.\n문제는 이 청사진이 실현되기 위해 HBF가 NAND 본연의 약점들을 풀어내야 한다는 데 있습니다. 지난 글에서는 NAND의 치명적인 latency 문제와 이를 우회할 수 있는 방안들을 살펴보았고, 이번 글의 앞부분에서는 그 우회를 general하게 적용하기는 쉽지 않다는 한계도 정리해 보았습니다. 하지만 latency 외에도 해결해야 할 문제는 아직 더 있습니다. 이어지는 섹션에서 이에 대해 알아보겠습니다.\n현실적인 문제와 HBF의 남은 과제 GPU / DRAM 수명과 NAND 수명의 mismatch 가장 큰 문제는 NAND의 수명이 일정하지 않고 사용 패턴에 의해 가변적이라는 점입니다. 현재 AI 데이터센터에서 SSD를 활용하는 방식은 write가 드물어 SSD 수명에 큰 부담이 되지 않습니다. 반면 HBF가 HBM과 같이 활용되면서 write가 자주 일어나게 된다면, NAND 특성상 셀이 빠르게 마모되고, 같이 패키징되는 GPU·DRAM의 5~7년 수명보다 메모리가 먼저 죽는 최악의 상황이 발생합니다. 기존의 SSD는 write가 많이 일어나게 된다 해도 교체해버리면 그만입니다. 하지만 HBF는 어떨까요? 이 문제는 아직 공개되지 않은 패키징과 인터페이스 표준과 연결됩니다.\n아직 결정되지 않은 패키징과 인터페이스 표준 HBF 개발에 가장 적극적인 SanDisk는 SK Hynix와 함께 올해 초 HBF 표준 확립을 위한 작업을 시작하였습니다. 하지만 시제품 출시를 앞둔 현재까지 아직 정확한 세부 스펙이 공개되지 않았습니다. 용량과 대역폭보다 제가 더 주목하고 있는 스펙은 패키징과 인터페이스 표준입니다.\n선택지는 크게 두 가지로 나뉩니다. 첫 번째는 PCIe 기반 연결입니다. 이는 운영 환경에서 오랫동안 검증된 안정적인 방식이라 도입 부담이 적고, GPU와 분리된 슬롯 형태로 배치할 수 있어 교체 가능성이라는 이점도 가집니다. 다만 PCIe 한 링크가 낼 수 있는 대역폭은 Gen 5 x16 기준으로도 약 64 GB/s 수준에 머무릅니다. 기존 SSD storage에 비해 GPU와 가까워지기만 할 뿐 HBF가 타겟하는 TB/s 단위의 대역폭은 PCIe 인터페이스만으로는 물리적으로 도달이 불가능 합니다.\n두 번째 선택지는 HBM 스타일 interposer 를 통한 패키지 통합입니다. GPU와 HBM을 interposer를 이용해 패키징한 것과 마찬가지로 GPU - HBF를 연결하거나 GPU - HBM - HBF를 순차적으로 연결하는 방식입니다. 이 방법으로 HBM에 준하는 광대역을 얻을 수 있기 때문에, HBF의 본래 강점을 살릴 수 있는 사실상 유일한 선택지입니다. 다만 GPU·HBM·HBF가 같은 패키지 안에 묶이는 순간 앞 절에서 짚은 수명 mismatch가 부분 교체 불가의 형태로 그대로 따라붙고, 발열과 전력 예산도 같은 패키지 안에서 함께 풀어야 한다는 부담이 동시에 올라옵니다.\n결국 필요한 것은 고도화된 controller와 소프트웨어 최적화 기존 SSD 기반 offloading은 데이터 경로 관리의 상당 부분을 host CPU나 DPU 가 담당해 왔습니다. SSD 내부 controller는 메모리 자체 동작만 책임지면 충분했고, KV cache의 swap 정책이나 prefetch 결정과 같은 운영 정책은 host 측 몫이었습니다. 하지만 HBF는 가속기 구성 안에 직접 들어가는 메모리입니다. 따라서 기존의 CPU/DPU가 처리하던 업무를 HBM/HBF controller 나 base die 에서 직접 처리해야 할 가능성이 높습니다. 단순한 메모리가 아니라 시스템 측 정책의 일부를 흡수한 고도화된 메모리가 필요한 것입니다.\n소프트웨어도 그에 맞춰 진화해야 합니다. HBF를 효과적으로 활용하기 위해서는 application과 framework가 어떤 데이터를 어디에 둘지 controller에 명시적으로 hint를 전달할 수 있어야 합니다. HW와 SW가 같은 가정 위에서 함께 설계되어야 앞에서 본 수명 문제와 대역폭 활용 문제가 해소되고 HBF의 강점이 실제 성능으로 이어질 수 있습니다.\n마무리 오늘 글에서는\n고도화되고 있는 LLM workload의 패턴 LLM 서비스에서 SSD storage의 사용 방식 HBF의 구조적 한계와 남아 있는 과제에 대해 알아보았습니다. 한편으로는 HBF의 위치가 약간 어색하다 는 생각도 듭니다. HBF의 역할이 단순한 메모리 계층구조로 설명하기 어렵기 때문입니다. 단순한 하드웨어 특성으로는 DRAM과 SSD의 중간 역할을 하는 것으로 보이지만, GPU와 물리적으로 가까이 위치한다는 점에서는 HBM과 DRAM의 중간 에 위치한다고 볼 수도 있습니다.\n이러한 어색함이 드는 이유는 AI 시대에 등장한 새로운 형태의 메모리(HBM, HBF)가 근본적으로 기존의 메모리인 DRAM과 NAND Flash를 기초로 만들어졌기 때문일 것입니다. HBM과 HBF 모두 기존에 사용하던 메모리를 적층이라는 공정기술 과 interposer와 CoWoS와 같은 패키징 기술 을 통해 AI 연산에 최적화하고 있습니다. 이러한 현상은 어쩌면 본질적으로 기존의 DRAM과 NAND 메모리가 AI 연산에 온전히 최적화된 메모리가 아니기 때문에 나온 결과는 아닐까요?\nNVIDIA와 기존의 GPU/TPU 회사들은 HBM 을 통한 대역폭 확장으로 메모리 병목을 해결해왔습니다.\nGroq와 Cerebras는 On-chip SRAM 과 본인들의 하드웨어 구조를 통해 새로운 형태의 가속기를 선보였습니다. 저희 HyperAccel도 LPDDR 과 이를 최대한으로 활용할 수 있는 독자적인 하드웨어 최적화 기술로 메모리 문제를 극복하고 있습니다.\n모두 기존의 메모리와 공정기술 / 패키징 기술 / 하드웨어 소프트웨어 최적화 방식으로 AI라는 새로운 형태의 문제를 풀어내고 있습니다. 하지만 근본적인 병목을 해소하기 위해서는 어쩌면 기존의 메모리보다 더 적합한 새로운 형태의 메모리 가 필요할지도 모르겠습니다. 물론 AI에 최적화된 메모리 라는 것이 정답이 있는 문제는 결코 아니고, 새로운 메모리라는 것은 조금 먼 이야기일 수 있습니다. 하지만 이와 관련된 논의도 학계와 산업계에서 조금씩 이루어지고 있습니다. 이에 대해서는 다음에 좀 더 자세히 이야기해보도록 하겠습니다.\n다음 글 예고 메모리 시리즈 1편부터 3편에서는 메모리 용량 병목을 해소하기 위해 등장한 HBF 에 대해 알아보았습니다. 그러나 HBF가 유일한 솔루션은 아닙니다. 다음 편에서는 신승빈님 께서 메모리 문제를 풀 수 있는 또 다른 대안인 CXL(Compute Express Link) 기술에 대해 소개드릴 예정입니다. 많은 관심 부탁드립니다!\n추신: HyperAccel은 채용 중입니다! 메모리 계층이 다양해질수록 가속기 회사는 더 복잡하고 흥미로운 문제를 풀어내야 합니다. 더욱이 메모리와 연산 로직, 소프트웨어와 알고리즘 등 하나의 영역에 국한되지 않고 서로 다른 도메인이 하나로 통합되어야 최적화된 가속기를 개발할 수 있습니다. HyperAccel은 HW, SW, AI를 모두 다루는 회사입니다. 폭넓은 지식을 깊게 배우며 함께 성장하고 싶으신 분들은 언제든지 채용 사이트 에서 지원해 주세요!\nReference Sparse Attention\nR. Child, S. Gray, A. Radford, I. Sutskever (OpenAI), \u0026ldquo;Generating Long Sequences with Sparse Transformers,\u0026rdquo; 2019. arxiv:1904.10509 A. Gu, T. Dao, \u0026ldquo;Mamba: Linear-Time Sequence Modeling with Selective State Spaces,\u0026rdquo; 2023. arxiv:2312.00752 G. Xiao, Y. Tian, B. Chen, S. Han, M. Lewis, \u0026ldquo;Efficient Streaming Language Models with Attention Sinks (StreamingLLM),\u0026rdquo; ICLR 2024. arxiv:2309.17453 C. Xiao et al., \u0026ldquo;InfLLM: Training-Free Long-Context Extrapolation for LLMs with an Efficient Context Memory,\u0026rdquo; NeurIPS 2024. arxiv:2402.04617 J. Tang et al., \u0026ldquo;Quest: Query-Aware Sparsity for Efficient Long-Context LLM Inference,\u0026rdquo; ICML 2024. arxiv:2406.10774 DeepSeek-AI, \u0026ldquo;DeepSeek-V4 Technical Report,\u0026rdquo; 2026. HuggingFace SSD / Flash offloading\nY. Sheng et al., \u0026ldquo;FlexGen: High-Throughput Generative Inference of Large Language Models with a Single GPU,\u0026rdquo; ICML 2023. arxiv:2303.06865 R. Ren et al., \u0026ldquo;An I/O Characterizing Study of Offloading LLM Models and KV Caches to NVMe SSD,\u0026rdquo; CHEOPS \u0026lsquo;25. DOI:10.1145/3719330.3721230 K. Kyung, S. Yun, J. H. Ahn (SNU), \u0026ldquo;SSD Offloading for LLM Mixture-of-Experts Weights Considered Harmful in Energy Efficiency,\u0026rdquo; IEEE Computer Architecture Letters, 2025. arxiv:2508.06978 I. Jeong, S. Woo, S. Namkung, D. Jeon, \u0026ldquo;HiFC: High-efficiency Flash-based KV Cache Swapping for Scaling LLM Inference,\u0026rdquo; 2025. OpenReview NVIDIA technical resources\nNVIDIA GPUDirect Storage Documentation NVIDIA Developer Blog — GPUDirect Storage: A Direct Path Between Storage and GPU Memory NVIDIA Developer Blog — How to Reduce KV Cache Bottlenecks with NVIDIA Dynamo HBF\nKAIST TERALAB, \u0026ldquo;2026 HBF Workload and Roadmap\u0026rdquo; (YouTube) — KAIST TERALAB ","permalink":"https://hyper-accel.github.io/posts/hbf-challenge/","summary":"HBF에게 적합한 자리는 분명히 있습니다. 하지만 memory hierarchy 피라미드에 들어가기 위해서는 아직 부족한 점이 많습니다. 최신 LLM 모델 및 추론 워크로드 트렌드, 그리고 Flash memory의 LLM 사용 방식을 살펴보며 HBF의 남은 과제와 극복 방안에 대해 살펴봅니다.","title":"AI 시대의 필수 소비재, 메모리 이해하기 3편: HBF가 풀어야 할 과제"},{"content":" 이 글은 AI 시대의 필수 소비재, 메모리 이해하기 시리즈의 2편입니다.\n1편: HBF 이해하기 에서는 HBF가 무엇이고 메모리 계층의 어디에 위치하는지를 다뤘습니다.\n이번 편에서는 그 한계를 안고도 HBF가 효과적으로 쓰일 자리는 어디인가 를 묻고, SK하이닉스가 제안한 H³ 아키텍처와 그 너머의 잠재 워크로드까지 살펴봅니다.\n들어가며 안녕하세요? HyperAccel 하드웨어 검증 엔지니어 임재원입니다.\n지난 1편에서는 메모리의 종류와 메모리 계층 구조의 새로운 자리를 차지하려는 HBF(High Bandwidth Flash) 에 대해 알아보았습니다. HBF의 특징을 한 줄로 표현해보면 다음과 같습니다.\n대역폭과 용량은 크지만, 너무 느린 메모리.\n더 정확히 말하면, HBF는 HBM(High Bandwidth Memory) 에 견줄 만한 대역폭에 8-16배 더 큰 용량을 얹은 메모리입니다. 단, 지연시간(latency)은 기존 SSD와 비슷한 수준으로 HBM 대비 약 100배 깁니다. bandwidth와 capacity는 HBM에 비견되거나 오히려 우월한데 latency는 SSD급, 결과적으로 어디에 끼워 넣어야 의미가 있을지 자체가 애매한 스펙입니다. 그래서 HBF가 잘 맞는 워크로드를 따로 발굴하는 과정이 필요합니다.\n1편이 \u0026ldquo;HBF란 무엇인가\u0026quot;에 답했다면, 2편은 그 다음 질문으로 넘어갑니다.\n\u0026ldquo;HBF, 실질적으로 어떻게 쓸 수 있을까?\u0026rdquo;\nHBF는 아직 상용화 전 단계입니다. 시장과 가속기 회사 입장에서는 spec 너머의 그림. 즉, 어떤 워크로드에서 쓰일지, 그 근거가 무엇인지가 분명해져야 비로소 채택 결정이 움직입니다. 그래서 이번 편의 출발점은 이 질문입니다.\nHBF의 잠재 workload를 조사하면서 알게 된 점은, 적절한 워크로드에 약간의 하드웨어 기법을 더하면 HBF의 약점은 숨길 수 있다는 것입니다. 이번 편에서는 SK하이닉스가 IEEE Computer Architecture Letters 2026에 발표한 H³ 아키텍처를 중심으로, HBF가 효과적으로 쓰일 자리들을 찾아봅니다.\nHBF의 한계, 다시 짚기 1편에서 다룬 HBF의 약점을 다시 정리하면 세 가지입니다.\n첫째는 지연시간입니다. HBF는 NAND flash 셀에 패키징을 입혀 만든 메모리입니다. 셀 자체의 읽기 메커니즘이 DRAM보다 본질적으로 느려서, HBM이 수십-수백ns 수준에서 데이터를 읽는 동안 HBF는 약 10-20μs를 필요로 합니다. 약 100배 차이입니다. 이 격차는 패키징을 아무리 잘 해도 셀 차원의 한계라 사라지지 않습니다.\n둘째는 write endurance입니다. NAND flash는 erase/write 사이클에 물리적 수명 제한이 있습니다. 같은 위치에 반복해서 쓰는 워크로드라면 셀이 빠르게 마모됩니다. 학습이나 빈번하게 갱신되는 데이터에는 어울리지 않습니다.\n셋째는 read granularity입니다. HBF는 NAND 기반이라 한 번의 읽기 요청이 page 단위(약 4KB)로 처리됩니다. HBM4가 32B 단위로 fine-grained access가 가능한 것과 대조적이죠. 워크로드가 작은 chunk를 random하게 골라 읽어야 한다면, 매 요청마다 4KB 중 실제로 쓰이는 데이터는 일부에 불과해 effective bandwidth가 급감합니다. 명목 bandwidth가 HBM에 견줄 만해도 실효 bandwidth는 훨씬 낮아질 수 있다는 뜻입니다.\n한계를 비껴가는 워크로드 조건 위 세 약점을 동시에 무력화하려면 워크로드가 아래 조건을 만족해야 합니다.\n한 번 적재하고 여러 번 반복 읽기: write endurance 무력화 데이터 접근이 예측 가능: 접근할 주소를 미리 알 수 있다면 prefetch로 latency를 숨김 큰 단위로 묶어 읽기: 한 번 page를 가져올 때 그 안의 데이터를 충분히 활용해 effective bandwidth를 유지 이 조건이 LLM 워크로드 어디에 들어맞을지 보려면, 가장 먼저 학습(training) 과 추론(inference) 을 비교해 볼 만합니다. 둘은 메모리 입장에서 정반대 성격을 가집니다.\n학습 은 매 step마다 weight를 갱신합니다. backward pass에서 gradient를 계산하고 optimizer state까지 함께 update하기 때문에 메모리 위에서 \u0026ldquo;쓰기\u0026quot;가 끊임없이 일어납니다. 이는 write endurance에 한계가 있는 HBF에는 가장 부적합한 워크로드입니다.\n추론 은 이야기가 다릅니다. 일단 학습이 끝난 뒤의 weight는 추론 내내 웬만해선 갱신되지 않습니다. Llama 3.1 405B를 FP8로 돌린다고 가정하면 weight 한 벌이 약 405GB이고, 이걸 매 batch마다 처음부터 끝까지 읽기만 합니다. HBF가 원하는 read-only 패턴이 여기에 있습니다.\n그런데 추론에서 weight만큼 거대해질 수 있는 데이터가 하나 더 있습니다. KV cache 입니다. 짧은 context에서는 문제가 되지 않지만, 최근 나오는 모델들은 1-10M에 달하는 context window를 지원합니다. 이를 고려한다면 KV cache는 수백 GB - 수 TB까지 부풀어 오릅니다. 이걸 HBF에 올릴 수 있다면 활용 폭이 단번에 넓어집니다. 하지만, 일반적인 KV cache는 write가 빈번하게 일어나기 때문에, 일반적인 상황에서 HBF를 KV cache를 저장하는 주요 공간으로 설정하기에는 무리가 있습니다.\nCAG, 한 번 연산한 KV cache를 여러 번 재사용하기 앞서 설명한 KV cache를 HBF에 올리기가 까다로운 이유를 자세히 설명하면 두 가지입니다.\n매 토큰마다 새로 쓰입니다. decode 단계에서 출력 토큰이 하나씩 생성될 때마다 모든 layer의 KV에 새 entry가 누적됩니다. write 빈도가 무척 높습니다. 요청마다 값이 다릅니다. 사용자 query가 매번 다르니, 같은 모델이라도 KV cache 내용은 매번 새로 계산됩니다. 한 요청을 위한 cache가 다른 요청에서 재사용되지 않습니다. 두 특성은 정확히 HBF가 약한 지점입니다. 잦은 write는 endurance를 깎고, 재사용되지 않는 데이터는 HBF의 거대 capacity를 살릴 명분이 없습니다. 즉, KV cache를 단일 write × 다중 read 형태로 바꿀 수 있다면, 비로소 HBF가 의미를 가집니다.\n그렇다면 실제 LLM 추론에서 사용되는 기법들은 KV cache를 어떻게 다루고 있을까요?\nLLM 응답 품질을 올리는 가장 흔한 기법은 Retrieval-Augmented Generation(RAG) 입니다. 외부 지식 베이스(보통 vector DB)에서 질의에 관련된 문서를 검색해 prompt에 끼워 넣고, 그 위에서 답변을 생성하는 방식이죠. 매 요청마다 retrieve가 일어나고, 가져온 context로 새 KV cache를 만들어 냅니다. 여기까지는 KV cache가 여전히 per-request 단발성이라 위 두 특성을 그대로 안고 있습니다.\n그런데 만약 모델이 참조해야 하는 지식이 요청마다 크게 바뀌지 않는 거대한 공유 자료 라면 어떨까요? 같은 매뉴얼, 같은 코드베이스, 같은 사내 문서를 매번 retrieve \u0026amp; 재계산하는 것은 명백히 낭비입니다.\n2024년 말 발표된 한 논문은 이 낭비를 극복할 수 있는 새로운 패턴을 제안했습니다. 바로 Cache-Augmented Generation(CAG) 입니다.\nCAG의 작동 방식은 단순합니다.\n공유될 만한 거대 지식 자료를 사전에 한 번 모델에 통과시켜 KV cache를 만들어 둡니다. 사용자 질의가 들어오면, 이 사전 KV cache를 prefix처럼 그대로 활용해 답변을 생성합니다. 같은 자료를 다시 계산하지 않습니다. 여러 요청이 들어오면 같은 KV cache를 공유 하면서 각자의 답변을 만들어 냅니다. RAG와 CAG를 한 줄로 비교하면 이렇습니다.\nRAG: retrieve + 매 요청마다 KV cache 재계산 CAG: 사전에 한 번 KV cache 연산, 여러 번 반복 read 메모리 입장에서 보는 차이는 더 극명합니다. RAG의 KV cache는 요청별로 짧고 일회용이지만, CAG의 KV cache는 read-only이며, 여러 요청에서 반복 접근됩니다. CAG로 만들어지는 데이터가 1M context면 수백 GB, 10M context면 수 TB 수준입니다.\n이러한 CAG의 특성을 앞 절에서 정의한 \u0026ldquo;HBF의 약점이 숨겨지는 조건\u0026quot;과 비교해보겠습니다.\nread-only → write endurance 문제 해소 한 번 적재 후 반복 읽기 → 매번 다시 계산하지 않고 한 번 만든 cache를 여러 요청이 나눠 씀 layer 별로 사용되는 KV cache는 예측 가능 → prefetch로 latency 숨김 가능 조건에 적합한 워크로드임을 알 수 있습니다. SK하이닉스가 H³를 정당화하는 핵심 use case로 CAG를 꼽은 이유가 여기 있습니다. 다음으로는 하이닉스가 제시한 하드웨어 아키텍처를 살펴보겠습니다.\nSK하이닉스의 H³: HBM과 HBF의 역할 분담 SK하이닉스 연구진이 발표한 H³ 의 핵심 아이디어는 한 줄로 요약됩니다.\nHBF로 HBM을 대체하지 말고, 거대 read-only 데이터 전용 슬롯으로 옆에 추가하자.\n물리 구조: HBM 뒤에 HBF를 연결 일반적인 GPU에서는 HBM 스택들이 인터포저 위에서 GPU와 나란히 배치되어, GPU shoreline의 한정된 공간을 모두 사용합니다. H³는 이 구조를 건드리지 않습니다. HBM은 그대로 GPU shoreline에 직접 연결합니다.\nHBF는 그 뒷 단에서 연결됩니다. 각 HBM 스택의 base die에 Die-to-Die(D2D) 인터페이스를 추가해, HBM 뒤로 HBF 스택을 한 단계 더 잇습니다. GPU 입장에서는 HBM과 HBF 모두 통합 주소 공간(unified address space) 안의 main memory처럼 보입니다. HBM base die 안의 address decoder \u0026amp; router가 들어온 요청을 HBM으로 보낼지, HBF로 보낼지 판단합니다.\n이 구조의 장점은 GPU shoreline 면적을 더 쓰지 않으면서 HBM 용량의 수십 배를 추가로 끌어다 쓸 수 있다는 점입니다. SK하이닉스의 가정에 따르면 GPU당 HBM3e가 192GB / 8TB/s라면, 같은 GPU 뒤로 붙는 HBF는 GPU당 약 3TB / 8TB/s를 더해 줍니다. 약 16배의 메모리 용량이 추가됩니다.\n데이터 배치 규칙: 누가 어디에 위치하는가 H³의 운영 철학은 데이터의 성격에 따라 두 메모리에 나눠 배치하는 것입니다.\nHBF: 모델 weight, CAG의 사전 계산 공유 KV cache HBM: 생성 중인 KV cache, activation, 그 밖에 자주 갱신되는 데이터 앞서 이야기한 바와 같이 이러한 형식으로 데이터를 용도별로 나눠서 저장하게 된다면 HBF의 약점을 상쇄할 수 있게 됩니다.\nLatency Hiding Buffer 그래도 한 가지 문제는 남습니다. NAND 셀의 약 수십 μs latency입니다. HBM의 ns 단위 응답을 가정하고 동작하던 GPU compute pipeline이 갑자기 μs 단위 메모리를 만나면 거의 멈추게 됩니다.\nSK하이닉스의 해법은 Latency Hiding Buffer(LHB) 입니다. HBM base die 안에 prefetch 전용 SRAM 버퍼를 통합하는 방식입니다.\n작동 원리는 LLM 추론의 한 가지 특성에 기댑니다. 데이터 접근 패턴이 결정론적이다 는 점입니다. 다음 layer에서 어떤 weight와 KV cache가 필요한지 미리 알 수 있다는 뜻이죠. 딥러닝 framework가 이 정보를 prefetch hint로 넘겨주면, LHB는 다음 layer 데이터를 미리 끌어와 두고, 현재 layer 계산이 진행되는 동안 latency를 시간적으로 숨깁니다.\nLHB의 사이즈는 단순한 식으로 정해집니다.\nCapacity_LHB = 2 × BW_HBF × Latency_HBF double buffering을 가정한 식입니다. 논문에서 든 예시 숫자(BW 1 TB/s, latency 20 μs)로 계산하면 약 40MB 가 됩니다. 3nm SRAM 공정 기준으로 따져도 약 8mm² 정도이고, 이는 HBM base die 면적(약 121mm²)의 6.7%에 해당합니다. base die의 여유 공간 안에서 충분히 수용 가능한 오버헤드입니다.\n즉 H³는 \u0026ldquo;HBM의 빈 자리(base die 면적)에 약간의 SRAM을 추가하는\u0026rdquo; 방식으로 latency 문제를 푼 셈입니다.\n시뮬레이션 결과 SK하이닉스 연구진은 H³를 Llama 3.1 405B (FP8, 약 405GB weight) + NVIDIA B200 GPU 셋업으로 시뮬레이션해 평가했습니다. HBM-only 대비 H³가 가지는 강점은 다음과 같습니다.\n지표 (HBM-only 대비 H³ 비율) 1M context 10M context 최대 batch size ~2.6× ~18.8× Throughput (Tokens Per Second / request) ~1.25× ~6.14× Throughput per power (최대) — ~2.69× long-context로 갈수록 이득이 가파르게 커집니다. 또한 단일 GPU로 1M context 추론, GPU 두 장으로 10M context 추론 이 가능했습니다. HBM-only로는 각각 8장, 32장이 필요한 워크로드입니다.\nH³ 너머: HBF가 어울릴 다른 workload H³는 HBF + LLM 추론(특히 CAG)이라는 한 조합을 보여 주었습니다. 그런데 HBF의 \u0026ldquo;약점이 약점 아닌 조건\u0026rdquo;(거대, read-only, deterministic prefetch 가능)을 만족하는 워크로드는 CAG만 있는 것이 아닙니다. 제가 생각하는 HBF 후보지 두 개를 짚어 보겠습니다.\n후보 1. Mixture of Experts(MoE) weight 저장소 최근 frontier LLM의 상당수는 Mixture of Experts(MoE) 구조를 쓰고 있습니다. 모델 안에 수십-수백 개의 expert Feed-Forward Network(FFN) 이 있고, 토큰마다 일부만 활성화됩니다. 활성화되지 않은 expert도 메모리에는 상주해야 하므로 weight 총합이 빠르게 trillion 단위까지 증가합니다.\n이 거대 weight를 HBM 위주로 운영하려면 GPU 여러 장으로 모델을 분산해야 합니다. 이 경우 각 GPU에서 다른 GPU로 weight를 옮겨주거나 중간 연산값을 옮겨주는 과정에서 추가적인 communication overhead가 필요합니다. 그러나 HBF를 통해 메모리 용량을 확장한다면 다른 그림이 가능해집니다. 모든 expert weight를 통째로 HBF에 올려, T급 모델 하나를 단일 칩에서 서빙하는 것 입니다.\nHBF: model weight (read-only) HBM: attention KV cache, activation, hot path 한계: 문제는 각 layer마다 어느 expert가 선택될지 예측하는 것이 힘들다는 것입니다. 입력 token이 attention layer를 거친 뒤에 router에서 어느 expert를 사용할지가 결정되기 때문입니다. expert weight를 불러오기 위한 latency를 숨기기 위해서는 어떤 expert가 선택될지 효과적으로 예측하고 HBF 측에 prefetch hint를 줄 수 있는 추가적인 지원이 필요합니다.\n후보 2. RAG vector DB 저장 앞에서 다뤄본 RAG의 vector DB에서 임베딩 컬렉션은 종종 billion-scale에 달합니다. 용량이 수백 GB - 수 TB 수준이기 때문에, 실제 서비스 환경에서 이 vector DB는 HBM과 같은 memory가 아닌 host 메모리나 별도의 storage에 보관됩니다.\n전형적인 RAG 추론에서는 query encoder가 만든 query embedding이 vector DB의 모든 항목과 유사도 비교를 거쳐 top-k 후보를 추리고, 추려진 top-k 후보의 raw embedding 또는 원문 chunk가 LLM의 prompt에 합쳐집니다.\n이 과정에서 HBF를 활용하면 vector DB를 가속기에 매우 가까이 위치시킬 수 있고, 한 발 더 나아가 HBF와 가속기 사이에 search 전용 엔진을 두는 그림이 가능해집니다. 올해 초 발표된 연구인 HAVEN이 이러한 구조를 채택하고 있습니다. 거대 vector DB는 HBF에 두고, search 엔진을 HBF 인접에 배치해 유사도 비교·top-k 선정을 그 자리에서 처리합니다. 가속기는 좁혀진 top-k의 full payload만 받아 옵니다.\nHBF: vector DB 전체 (raw embedding + 원문 chunk) HBF 인접 search 엔진: 유사도 비교 + top-k 선정 HBM / 가속기: query encoder, LLM 본체 이 구조의 이점은 traffic · latency 측면에서 살펴볼 수 있습니다. search에 따르는 read-access가 여전히 발생하지만, 그 traffic이 HBF ↔ search 엔진 사이의 짧은 경로 안에서만 흘러갑니다. HBF ↔ 가속기 사이에는 좁혀진 top-k 결과만 page 단위로 전달되므로, 가속기 측 메모리 인터페이스가 깨끗하게 유지되고, vector DB가 가속기 가까이 위치한 만큼 search 자체의 속도도 빨라집니다. RAG vector DB가 커질수록 (수십억 문서 규모) HBF의 capacity와 인접 search 엔진의 결합이 cost · throughput 양쪽에서 직접적인 이점이 됩니다.\n한계: 이 구조는 vector DB 옆에 search 엔진을 별도로 둬야 하기 때문에, HBM의 표준 base die에는 없는 search 가속 로직이 추가됩니다. 즉 표준 base die가 아닌 custom base die 를 제작해야 한다는 뜻입니다. 이는 표준 packaging 라인에서 그대로 양산되는 그림이 아니라 vendor·워크로드별 맞춤 base die 제작이 필요함을 의미합니다.\n마무리 이번 글에서는 HBF의 치명적인 약점들을 극복할 수 있는 워크로드의 조건과 그에 부합하는 LLM 워크로드 에 대해 알아보았습니다. 하지만 오늘 알아본 workload들은 전체 LLM 서비스의 일부에 불과합니다. HBM과 비슷한 규모의 시장성을 갖추기 위해서는 조금 더 범용적으로 사용될 수 있는 방안을 찾아야 하지만, HBF에는 극복해야 할 기술적인 과제와 한계가 여전히 존재합니다. 다음 편에서는 기존의 Flash memory가 LLM 서비스에서 어떻게 활용되는지 살펴보면서, HBF가 실질적으로 상용화되기 위해 극복해야 할 숙제들에 대해 알아보겠습니다.\n추신: HyperAccel은 채용 중입니다! 메모리 계층이 다양해질수록 가속기 설계자가 풀어야 할 문제는 더 흥미로워집니다.\n저는 HyperAccel DV팀에서 LLM 가속 ASIC의 하드웨어 검증을 담당하고 있습니다. 단일 칩의 검증을 넘어 메모리 계층, 시스템 통합, 워크로드 매칭까지 함께 고민할 수 있는 자리에서 매일 새로운 문제를 만나고 있습니다.\nHyperAccel은 HW, SW, AI를 모두 다루는 회사입니다. 폭넓은 지식을 깊게 배우며 함께 성장하고 싶으신 분들은 언제든지 채용 사이트 에서 지원해 주세요!\nReference M. Ha, E. Kim, H. Kim, \u0026ldquo;H³: Hybrid Architecture using High Bandwidth Memory and High Bandwidth Flash for Cost-Efficient LLM Inference,\u0026rdquo; IEEE Computer Architecture Letters, 2026. DOI: 10.1109/LCA.2026.3660969 B. J. Chan, C.-T. Chen, J.-H. Cheng, H.-H. Huang, \u0026ldquo;Don\u0026rsquo;t Do RAG: When Cache-Augmented Generation is All You Need for Knowledge Tasks,\u0026rdquo; Proc. The ACM Web Conference (WWW) 2025, 2025. arxiv:2412.15605 SanDisk, \u0026ldquo;Memory-Centric AI: Sandisk\u0026rsquo;s High Bandwidth Flash Will Redefine AI Infrastructure\u0026rdquo; P.-K. Hsu, W. Xu, Q. Liu, T. Rosing, S. Yu, \u0026ldquo;HAVEN: High-Bandwidth Flash Augmented Vector Engine for Large-Scale Approximate Nearest-Neighbor Search Acceleration,\u0026rdquo; 2026. arxiv:2603.01175 ","permalink":"https://hyper-accel.github.io/posts/hbf-workload/","summary":"SK하이닉스의 H³ 아키텍처를 중심으로, HBF의 약점을 극복할 수 있는 워크로드를 탐색합니다.","title":"AI 시대의 필수 소비재, 메모리 이해하기 2편: HBF의 잠재 workload 찾아보기"},{"content":"지피지기면 백전불태 5편: Cerebras와 웨이퍼 스케일 엔진 지피지기면 백전불태(知彼知己 百戰不殆)\n상대를 알고 나를 알면 백 번 싸워도 위태롭지 않다는 뜻입니다.\n이 시리즈는 AI 가속기 설계를 위해 경쟁사들의 하드웨어를 깊이 이해하는 것을 목표로 합니다.\n다섯 번째 글에서는 Cerebras 의 Wafer-Scale Engine(WSE) 을 다룹니다.\n안녕하세요, CL팀 최동현입니다. 웨이퍼 하나를 통째로 칩으로 만드는 회사가 있다는 것, 알고 계셨나요?\n오늘은 Cerebras 의 Wafer-Scale Engine(WSE) 을 다뤄보려고 합니다.\n2026년 1월, Cerebras 는 AI 업계에 큰 소식을 전했습니다. 여러 보도에 따르면 OpenAI 와 100억 달러 규모의 계약을 맺고, 최대 750MW 규모의 연산 용량을 2028년까지 공급한다는 내용이었습니다. AI 가속기 시장에서 NVIDIA 이외의 플레이어가 이렇게 큰 계약의 후보로 언급된 건 이례적입니다.\n이 글에서는 Cerebras 의 핵심 기술인 웨이퍼 스케일 엔진(WSE) 아키텍처가 무엇인지, 왜 수율 문제가 어려웠는지, Cerebras 가 이를 어떻게 풀었는지 정리합니다.\nCerebras, 왜 주목받는가 Cerebras는 2015년 미국 캘리포니아에서 설립된 AI 반도체 스타트업입니다. 창업자 Andrew Feldman 과 Gary Lauterbach 는 2007년 SeaMicro 를 공동 설립했고, 2012년 AMD 에 3억 5,700만 달러에 매각한 경력이 있습니다. 이들은 이런 경험을 바탕으로, AI 시대에는 범용 GPU와 다른 길도 필요하다고 보고 Cerebras를 세웠습니다.\n이들의 문제의식은 비교적 분명했습니다. 통상적인 칩 크기로는 on-chip memory의 크기에 한계가 있고 이에 더해 모델이 커질수록 더 많은 기기간 연결이 필요합니다. 그 결과 메모리 대역폭, 칩 간 통신이 병목이 되기 쉽습니다.\n그래서 Cerebras가 택한 해법은 계산과 데이터 이동을 가능한 한 하나의 웨이퍼 안에 가두는 것이었습니다. 웨이퍼를 잘게 나누지 않고 통째로 하나의 칩처럼 쓰는 웨이퍼 스케일 엔진(WSE) 을 만들어 AI 학습과 추론에 활용한 것이죠. 핵심은 단순히 “칩을 크게 만들자”가 아니라, 칩 밖으로 오가던 데이터를 웨이퍼 내부에서 처리하자는 데 있습니다.\n이 아이디어는 기술적 실험에 그치지 않고 최근 사업적 관심으로도 이어졌습니다. 2025년 8월, Cerebras 는 OpenAI 오픈 모델 gpt-oss-120B 를 초당 3,000토큰 수준으로 구동했다고 발표했습니다. 이어 2026년 1월에는 OpenAI 와 대형 계약을 맺었다는 보도가 나왔고, 2026년 3월에는 AWS 와 함께 Amazon Bedrock 에서 Trainium 기반 prefill과 Cerebras CS-3 기반 decode를 결합하는 추론 협력을 공식 발표했습니다.\n자본시장도 이런 흐름에 반응했습니다. Cerebras는 2024년 한 차례 기업공개를 추진했다가 2025년에 철회한 뒤, 2026년 4월 미국 Securities and Exchange Commission(SEC) 에 S-1 을 다시 제출해 Nasdaq 상장(티커 CBRS)을 추진 중입니다.\n왜 이런 대안이 주목받을까요? 주간 수억 명 규모의 사용자에게 초거대 모델 기반 서비스를 제공하려면 데이터센터 용량을 계속 키워야 합니다. 그러나 NVIDIA GPU에만 의존하면 비용과 공급 모두에서 제약이 생깁니다. 그래서 대형 AI 서비스 사업자는 GPU 클러스터와 다른 구조의 가속기도 검토할 수밖에 없습니다.\n결국 Cerebras는 단순히 “특이한 칩을 만든 회사”를 넘어, 클라우드 사업자와 모델 사업자가 실제 선택지로 검토하는 회사가 됐습니다. 그리고 그 선택지를 가능하게 한 핵심이 바로 WSE 라는 독특한 아키텍처입니다.\n웨이퍼 스케일 엔진이란 일반적으로 반도체 칩은 웨이퍼(wafer)라는 원형 실리콘 판에서 여러 개를 잘라냅니다. 하나의 웨이퍼에서 수십 개에서 수백 개의 작은 칩이 나오고, 각 칩은 따로 패키징되어 GPU, CPU 같은 제품이 됩니다.\nCerebras는 이 방식을 뒤집었습니다. 웨이퍼를 쪼개지 않고 통째로 하나의 칩처럼 사용합니다. 공개 자료 기준 Wafer-Scale Engine 3(WSE-3) 의 면적은 46,225mm² 입니다. 가로세로 약 215mm인 정사각형에 가까운 칩으로, NVIDIA H100 칩(약 814mm²)보다 면적이 50배 이상 큽니다.\n그런데 왜 지금까지 웨이퍼 스케일 칩을 만드는 회사가 거의 없었을까요? 가장 큰 이유는 수율(yield) 입니다. 반도체 제조 과정에서 결함(defect)이 생기는 것은 피할 수 없습니다. 작은 칩은 결함이 들어간 칩만 버리고 나머지를 쓰면 됩니다. 하지만 칩이 커질수록 결함 하나가 들어갈 확률이 높아지고, 결함 때문에 버려지는 면적도 커집니다.\n그림처럼 같은 밀도 의 결함이 있다고 가정해 보겠습니다. 작은 die에서는 결함이 없는 정상 die를 많이 얻을 수 있습니다. 반대로 die 면적이 커지면 정상 die의 비율이 빠르게 낮아집니다. 여기에 원형 웨이퍼에서 사각형 die를 찍어낼 때 가장자리에서 버려지는 면적까지 더해집니다.\n결론적으로 큰 칩은 낮은 수율과 낭비되는 웨이퍼 면적 때문에 제품 단가가 급격히 올라갑니다. 그래서 웨이퍼 스케일 칩은 오랫동안 경제적으로 어렵다고 여겨져 왔습니다.\nCerebras는 이 문제를 아키텍처 설계로 풀었습니다.\nWSE-3 아키텍처 WSE-3 는 2024년 3월에 공개된 3세대 웨이퍼 스케일 칩입니다. TSMC 5nm 공정으로 만들어졌고, 공개 자료 기준 4조 개 이상의 트랜지스터, 90만 개의 활성 AI 코어, 44GB 온칩 SRAM, 21PB/s 메모리 대역폭, 214Pb/s 패브릭 대역폭 을 갖습니다.\nWSE 는 웨이퍼 하나에서 하나의 칩을 찍어내고, 칩 하나는 84개의 서로 연결된 다이(die)를 가지고 있습니다. 일반적인 GPU나 CPU의 경우 이 다이 하나를 잘라내어 칩 하나 판매하지만, WSE의 경우 이 다이들을 서로 연결시켜 하나의 칩으로 사용합니다. 각 다이 내에는 만개 이상의 코어(core)를 가지고 있습니다.\n각 코어 안에는 인접 코어간 연결을 위한 패브릭(fabric), 데이터 저장을 위한 SRAM 48KB와 캐시 512B, 연산 직전에 데이터를 담아두는 레지스터, 그리고 16비트와 8비트 병렬 연산기가 있습니다. 16비트 연산기는 8개 데이터, 8비트 연산기는 16개 데이터에 대해서 동시에 연산할 수 있습니다.\nNvidia의 H100은 칩 밖에 있는 High Bandwidth Memory(HBM) 에서 데이터를 가져옵니다. 물론 그 이름부터가 \u0026ldquo;고대역폭 메모리\u0026quot;이기 때문에 HBM은 굉장히 빠른 메모리이긴 합니다만 어찌되었건 연산이 이루어지는 칩 밖에 존재하는 메모리이기 때문에 연산 유닛과 메모리 사이의 물리적 연결이 병목이 될 수 있습니다. 또한 여러 칩이 연결되기 위해서는 NVLink를 거치고 칩간 연결을 위한 많은 커넥터가 필요합니다. 반면 WSE-3 는 메모리를 칩 위에 다 올려버렸습니다. 각 코어 내에 거대한 Static Random-Access Memory(SRAM) 를 분산 배치합니다. 공개된 WSE-3 자료에 따르면 코어 하나에는 48KB SRAM 이 붙어 있고, 전체 칩으로 따지면 총 44GB 온칩 메모리가 됩니다. HBM에서 SRAM으로 전환하면서 800배가 넘는 메모리 대역폭 이득 을 보는 것이죠.\n여기에 더해 각 die를 별도의 칩으로 자르지 않고, 하나의 칩 위에 모두 같이 올린 형태입니다. 이 덕분에 die 간 통신은 매우 짧은 실리콘 상의 와이어로 연결됩니다. 결과적으로 H100 대비 33배나 더 빠른 통신 속도 를 기대할 수 있습니다.\nCerebras는 웨이퍼 스케일의 수율 문제를 코어를 매우 작게 만드는 방식으로 해결했습니다. 다시말해, “결함이 생겼을 때 잃는 단위”를 아주 작게 만드는 것입니다. 개별 코어의 크기를 매우 작게 만들어 거대한 웨이퍼 전체가 하나의 실패 단위가 아니라, 수십만 개의 작은 코어 중 결함이 생긴 몇개 코어만 잃도록 하는 것이죠. WSE-3 white paper에 따르면 개별 코어 면적은 약 38,000µm², 즉 0.038mm² 수준으로 설명합니다. H100 의 Streaming Multiprocessor(SM) 가 약 6mm² 정도 된다고 하니 개별 코어 면적으로는 백배 이상의 차이가 납니다. 그 결과, 잃게 되는 다이면적(못 쓰는 코어의 개수)가 획기적으로 줄어들게 됩니다.\n못쓰는 코어가 줄어든다고 해도, 웨이퍼레벨이라면 그 못쓰는 칩을 잘라낼 수 없으니 어찌됐건 칩을 못쓰는게 아니냐 라는 의문이 들 수 있습니다. WSE는 이 문제를 해결하기 위해 결함이 생긴 코어를 우회하는 연결 구조를 설계했습니다. 기본적으로 각 코어는 이웃한 코어와의 데이터 전송을 위해 2차원 mesh로 연결됩니다. 다이 안에는 여분의 코어를 만들어 넣어두고, 결함이 발견되면 결함이 발생한 코어를 우회하는 여분의 wire를 활성화시켜 정상 코어와 연결합니다. 즉, 결함이 발생한 코어가 있더라도 논리적인 코어간 연결 구조는 바뀌지 않습니다.\nWSE는 데이터가 도착하면 연산이 발생하는 dataflow 방식으로 동작합니다. MemoryX에서 전송된 weight는 (index, value) 형태의 packet으로 만들어져 필요한 코어로 라우팅됩니다. packet을 받은 코어는 해당 index에 대응하는 activation을 읽고 multiply-add를 수행합니다.\n이처럼 목적지와 연산 대상이 packet 단위로 지정되는 구조 덕분에, WSE는 unstructured sparse pattern에도 효과적으로 대응할 수 있습니다. 핵심은 값이 0인 weight packet을 애초에 MemoryX에서 전송하지 않는다는 점입니다. 따라서 0인 weight는 packet으로 만들어지지 않고, fabric traffic도 만들지 않으며, 대응되는 연산도 발생시키지 않습니다.\n즉 WSE에서 sparsity를 활용한다는 것은 단순히 0을 압축해 저장하는 것이 아니라, 0에 해당하는 데이터 이동과 compute event를 아예 생성하지 않는다는 의미입니다. 이 fine-grained dataflow 실행 방식 덕분에 WSE는 unstructured sparsity에서도 GPU의 dense tile 기반 실행보다 높은 실제 활용률을 기대할 수 있다고 설명합니다.\nSRAM에 모델 올리기 LLM 추론을 단순히 “연산량이 많다”라고만 보면 중요한 병목을 놓치기 쉽습니다. 생성형 모델은 token을 하나 만들 때마다 weight를 읽고, activation과 Key-Value cache를 다루고, 다음 token을 위해 다시 같은 과정을 반복합니다. 이때 많은 경우 병목은 FLOPS 자체보다 weight를 얼마나 빨리 읽어 오느냐에서 생깁니다.\nWSE-3 의 44GB SRAM은 이 지점을 겨냥합니다. 작은 모델이나 일부 layer는 웨이퍼 안에 올려두고, 코어 가까이에서 매우 높은 대역폭으로 읽을 수 있습니다. GPU의 HBM 도 빠르지만, WSE의 SRAM은 더 가까운 위치에 더 촘촘히 분산되어 있습니다. 이 때문에 Cerebras는 추론을 memory bandwidth 문제로 보고, weight와 activation 이동 거리를 줄이는 데 집중합니다.\n그렇다고 모든 모델을 44GB SRAM 안에 넣겠다는 뜻은 아닙니다. 70B급 이상의 모델은 정밀도를 낮춰도 단일 WSE SRAM에 모두 올리기 어렵습니다. 그래서 Cerebras의 시스템은 “모든 것을 칩 안에 넣는다”가 아니라, 올릴 수 있을 만큼 SRAM에 올려 두고, 더 큰 모델은 외부 DRAM/Flash 메모리에 두고 weight streaming을 통해 불러오는 방식을 택합니다.\n따라서 WSE의 성능은 모델을 어디에 배치하느냐와 강하게 연결됩니다. SRAM에 올라가는 부분은 매우 빠르게 접근할 수 있습니다. 반대로 모델이 커져 외부 메모리나 여러 장치 간 streaming에 의존할수록, 웨이퍼 안에서 얻는 locality 이점은 줄어듭니다. 이 trade-off가 뒤에서 볼 MemoryX와 SwarmX가 필요한 이유입니다.\n칩 간 연결성 44GB SRAM에도 다 들어가지 않는 초거대 모델을 지원하려면 단일 WSE만으로는 부족합니다. 그래서 Cerebras는 칩 하나가 아니라 CS-3 시스템, 그리고 여러 CS-3를 묶는 scale-out 구조까지 함께 설계합니다.\n큰 모델 학습에서는 가중치를 웨이퍼 안에 모두 저장하지 않습니다. 외부의 MemoryX 에 모델 weight를 저장한 뒤, layer-by-layer로 CS-3 에 streaming합니다. 여러 CS-3 를 묶을 때는 SwarmX 가 weight broadcast와 gradient reduce를 담당합니다.\n조금 풀어 말하면, MemoryX 는 모델 파라미터 창고에 가깝습니다. WSE의 SRAM은 매우 빠르지만 모든 거대 모델의 weight, gradient, optimizer state를 담기에는 부족합니다. 그래서 큰 상태값은 MemoryX 에 두고, 지금 계산할 layer의 weight만 CS-3 쪽으로 흘려보냅니다. MemoryX는 12개의 100 Gigabit 이더넷 링크로 연결되어있고 이 대역폭을 바이트단위로 환산하면 150GB/s 입니다. 상대적으로 매우 느린 저장공간이라고 할 수 있고, 따라서 WSE는 이 메모리 로드와 이미 불러온 44GB SRAM 상의 데이터에 대한 연산 시간을 겹쳐 메모리 로딩 시간을 감추는 방식을 사용합니다.\n반면 SwarmX 는 여러 CS-3 사이의 분배기이자 합산기입니다. 학습할 때는 같은 weight를 여러 CS-3 에 뿌려야 하고, 각 장비가 계산한 gradient를 다시 모아야 합니다. 반면 추론할 때에는 각 CS-3에 모델 레이어를 분배하여야 하고 한 장비가 계산한 결과물을 다음 레이어를 가진 장비로 넘겨줘야 합니다. SwarmX 는 이 broadcast와 reduce 패턴을 담당해 여러 WSE가 하나의 큰 학습 시스템처럼 움직이도록 돕습니다.\n이 구조의 목표는 사용자가 tensor parallelism이나 pipeline parallelism을 직접 세밀하게 쪼개지 않아도 되게 만드는 것입니다. Cerebras의 표현을 빌리면, 모델 크기를 키워도 프로그래머 입장에서는 데이터 병렬에 가까운 형태로 보이게 만드는 것이 목표입니다. 내부에서는 MemoryX, SwarmX, CS-3가 각각 저장, 통신, compute 역할을 나눠 맡습니다.\nCS-3 시스템의 경우 최대 2,048대 까지 묶어 매우 큰 학습 시스템을 구성할 수 있다고 설명합니다. 이때 중요한 점은 단순히 “많이 연결한다”가 아닙니다. weight broadcast와 gradient reduce가 병목이 되지 않도록 네트워크를 시스템 일부로 함께 설계했다는 점입니다.\n서버에 세로로 넣는다?! 웨이퍼 스케일 칩은 단순히 “큰 silicon die”가 아닙니다. 가로세로 20cm가 넘는 얇은 구조물을 안정적으로 지지하고, 수만 암페어 수준의 전류를 공급하고, 발생하는 열을 빼내야 하는 시스템 문제입니다. 일반 GPU 패키지보다 기계적·열적 제약이 훨씬 까다롭습니다.\n너무 큰 칩을 다룰 때는 중력, 휨, 열팽창, 접촉 압력 같은 물리적 요소가 무시하기 어려워집니다. 웨이퍼가 휘면 전기적 접촉과 냉각 접촉이 불안정해질 수 있습니다. 그래서 WSE는 칩 설계만으로 끝나지 않고, 전용 패키징, 전력 공급, 냉각, 보드 지지 구조가 함께 필요합니다.\nCerebras가 CS-3 같은 완제품 시스템 형태로 판매하는 이유도 여기에 있습니다. WSE만 따로 팔아서 서버 업체가 알아서 꽂는 구조가 아닙니다. 웨이퍼 크기의 chip, 전력 공급 모듈, 냉각 구조, system fabric, MemoryX와 SwarmX까지 묶어 하나의 장비로 제공합니다.\n이 관점에서 보면 Cerebras는 “칩 회사”라기보다 “웨이퍼 스케일 컴퓨터 회사” 에 가깝습니다. WSE의 장점은 silicon 내부에서 나오지만, 그 장점을 실제 데이터센터에서 쓰려면 패키징과 시스템 설계가 반드시 따라와야 합니다.\nCerebras의 강점과 한계 Cerebras의 가장 큰 강점은 메모리 대역폭과 통신 locality 입니다. Large Language Model(LLM) 추론은 흔히 “연산 문제”처럼 보이지만, 실제로는 매 token마다 모델 weight를 반복해서 읽어야 하는 memory bandwidth 문제이기도 합니다. WSE는 거대한 SRAM을 사용하여 bandwidth를 극대화하는 방식으로 이 문제를 해결했습니다. 또한 칩·메모리·연결이 모두 한 웨이퍼 안에 들어가 있어 여러 칩을 이어 붙일 때 생기는 통신 오버헤드 를 줄였습니다.\n한계도 같은 지점에서 나옵니다. 가장 큰 한계는 44GB SRAM은 대단히 빠르지만 용량이 제한적이라는 것입니다. 70B급 이상의 모델은 여러 장치나 외부 weight streaming 구조가 필요합니다.\n짧은 출력 길이(128 prompt tokens, 20 output tokens)에서 Cerebras는 single-user speed를 높게 유지하면서, batch size 증가에 따라 throughput을 함께 끌어올리는 모습을 보여줍니다. 그러나 만약 여러 사용자가 두꺼운 책을 입력하고 그걸 기반으로 장문의 답변을 해야한다면 어떻게 될까요? high batch, long sequence 상황에서 WSE는 44GB로는 model weight와 KV cache를 감당하기 어려울 것이고, 이에 따라 빈번한 MemoryX loading을 필요로 할 것입니다. 즉, 용량이 큰 HBM 대비 직접적인 성능 하락이 보일 수 있다는 것이죠.\n만약 충분한 메모리 공간 확보를 위해 장비를 여러 대 붙인다면 Memory X 접근은 줄겠지만 초기 도입 비용도 함께 커집니다. 공식 단가는 공개되어 있지 않지만, 인터넷상의 공개 정보를 인용하면 규모감을 잡는 데 도움이 됩니다. The Next Platform은 CS-2/CS-3 한 대를 대략 250만~320만 달러로 추정했습니다. MemoryX와 SwarmX까지 포함하면 약 400만 달러 수준에 달합니다. 1달러를 1,500원으로 잡으면 노드당 약 37.5억~60억 원입니다.\n여기에 공개된 미국 증권거래위원회(SEC) 계약 문서에는 CS-3 클러스터 납품 금액이 1.8억~3.5억 달러 규모로 나타납니다. 즉, WSE로의 전환은 칩 하나의 성능만 볼 문제가 아닙니다. CS-3, MemoryX, SwarmX, 네트워크, 전력, 냉각까지 묶인 수십억~수천억 원대 초기 투자 를 함께 요구한다고 볼 수 있습니다.\n정리하자면… 이 글에서는\n① 2026년 Cerebras의 근황과 OpenAI 관련 대형 계약 보도,\n② Cerebras의 창업 배경과 웨이퍼 스케일 도입 이유,\n③ 웨이퍼 스케일 엔진(WSE) 개념과 WSE-3 아키텍처 핵심,\n④ SRAM에 모델을 올리는 방식과 MemoryX/SwarmX 기반 연결성,\n⑤ Cerebras의 강점(대역폭, locality, scale-out 구조)과 한계(긴 출력, 높은 배치에서의 추론, 초기도입 비용 문제)를 살펴봤습니다.\nCerebras의 웨이퍼 스케일 엔진 은 웨이퍼를 통째로 칩으로 쓰는 과감한 설계입니다. 하지만 진짜 핵심은 크기 자체가 아닙니다. 결함이 생겨도 작은 단위로 격리하고, SRAM을 코어 가까이에 두고, 2D mesh fabric으로 데이터 이동을 웨이퍼 안에 가둔다는 점입니다.\nAI 가속기 시장은 이제 NVIDIA 일변도로만 설명하기 어렵습니다. 웨이퍼 스케일, 추론 전용, 메모리 계층 확장, optical interconnect 등 다양한 접근이 공존하는 시대가 됐습니다. 점점 다변화되는 NPU 시장에서 중요한 질문은 “어떤 workload에 최적화된 가속기인가”일 것입니다.\n그럼 지피지기면 백전불태 다음 편에서 다시 뵙겠습니다.\nReference 100x Defect Tolerance: How Cerebras Solved the Yield Problem - Cerebras AWS and Cerebras announce AI inference collaboration - Cerebras AWS and Cerebras bring ultra-fast AI inference to Amazon Bedrock - Amazon Cerebras Systems Form S-1 Registration Statement - SEC EDGAR Cerebras CS-3 Purchase Order #2024-0003 - SEC EDGAR Cerebras MBZUAI CS-3 Purchase Order - SEC EDGAR Cerebras Goes Hyperscale With Third Gen Waferscale Supercomputers - The Next Platform Cerebras WSE-3 Architecture White Paper Hot Chips 2024: Cerebras WSE-3 and Inference IEEE Micro: Cerebras Architecture Deep Dive 추신: HyperAccel은 채용 중입니다! 지피지기면 백전불태라지만 백전백승을 위해서는 훌륭한 인재가 많이 필요합니다!\n저희가 다루는 기술들을 보시고, 관심이 있으시다면 HyperAccel Career로 지원해 주세요!\nHyperAccel에는 정말 훌륭하고 똑똑한 엔지니어분들이 많습니다. 여러분의 지원을 기다립니다.\n","permalink":"https://hyper-accel.github.io/posts/cerebras-wse/","summary":"OpenAI와의 대형 계약 보도로 주목받은 Cerebras의 최근 근황과 WSE-3 아키텍처, 웨이퍼 스케일 칩의 장단점을 비전공자도 이해할 수 있게 정리합니다.","title":"지피지기면 백전불태 5편: Cerebras와 웨이퍼 스케일 엔진"},{"content":" 이 글은 AI 시대의 필수 소비재, 메모리 이해하기 시리즈의 1편입니다.\n들어가며 안녕하세요, HyperAccel에서 RTL Designer로 재직 중인 신승빈입니다.\n최근 주식 시장에서 \u0026ldquo;메모리, 반도체 관련주\u0026quot;가 연일 화제입니다.\n최근에는 \u0026ldquo;HBF\u0026quot;라는 새로운 단어가 들리기 시작하며 \u0026ldquo;그게 뭔데?\u0026rdquo;, \u0026ldquo;그래서 사라고?\u0026rdquo; 이런 이야기가 많이 나오고 있죠.\n그렇다면 여기서 High Bandwidth Flash(HBF) 란 무엇일까요?\nHBF를 이해하려면 먼저 한 가지 질문에 답할 수 있어야 합니다.\n\u0026ldquo;컴퓨터에는 왜 이렇게 많은 종류의 메모리가 있는 걸까?\u0026rdquo;\n우리가 쓰는 컴퓨터 안에는 SRAM, DRAM, HBM, SSD 등 이름부터 복잡한 메모리들이 여러 계층으로 나뉘어 존재합니다. 전부 \u0026ldquo;데이터를 저장하는 것\u0026quot;인데 왜 하나로 통일하지 않을까요?\n이 질문에 답하다 보면, HBF가 왜 등장했고 어디에 위치하는지가 자연스럽게 보이게 됩니다.\n이 포스팅의 내용은 제가 개인적으로 공부하고, 경험한 내용을 바탕으로 작성되었습니다. 오류가 있다면 언제든지 댓글로 알려주세요.\n메모리는 왜 여러 종류인가 — 속도/용량/비용의 트릴레마 결론부터 말하면, 빠른 메모리는 비싸고 작고, 싼 메모리는 느리고 크기 때문 입니다.\n이건 단순히 기술이 덜 발전해서가 아닙니다. 메모리 셀의 물리적 구조 자체가 이 트레이드오프를 결정합니다. 트랜지스터를 많이 써서 셀을 만들면 빠르지만 면적을 많이 차지하고, 셀을 단순하게 만들면 느리지만 같은 면적에 훨씬 많은 데이터를 저장할 수 있습니다.\n컴퓨터는 이 물리적 한계를 우회하기 위해 여러 종류의 메모리를 계층(Hierarchy) 으로 쌓아 사용합니다. 프로세서에 가까울수록 빠르고 작은 메모리를, 멀어질수록 느리지만 큰 메모리를 배치하는 것이죠.\n이제 각 계층의 메모리가 왜 그런 특성을 갖는지, 셀 구조부터 살펴보겠습니다.\nSRAM — 가장 빠르고, 가장 비싼 셀 구조: 트랜지스터 6개로 1비트 Static Random Access Memory(SRAM) 은 하나의 비트를 저장하기 위해 6개의 트랜지스터를 사용합니다. 이를 6T SRAM 셀 이라고 부릅니다.\n6개의 트랜지스터 중 4개는 두 개의 인버터를 구성하여 서로의 출력을 교차 연결(cross-coupled)합니다. 이 구조는 전원이 공급되는 한 자체적으로 상태를 유지하는 래치(latch)를 형성합니다. 나머지 2개의 트랜지스터는 읽기와 쓰기 시 셀에 접근하기 위한 패스 게이트(pass gate) 역할을 합니다.\n왜 빠른가 SRAM이 빠른 이유는 명확합니다.\n래치가 상태를 자체적으로 유지하기 때문에 리프레시(refresh)가 필요 없습니다. \u0026ldquo;Static\u0026quot;이라는 이름이 여기서 옵니다. 읽기 동작은 래치에 저장된 전압 상태를 비트라인으로 전달하는 것이 전부이므로, 접근 지연이 1ns 이하 수준입니다.\n왜 비싼가 문제는 크기입니다. 1비트에 트랜지스터 6개가 필요하니, 셀 하나의 면적이 큽니다. 같은 크기의 실리콘 웨이퍼에서 만들 수 있는 비트 수가 적다는 뜻이고, 이는 곧 비트당 단가가 매우 높다 는 것을 의미합니다.\n그래서 SRAM은 대용량으로 사용하는 것이 물리적으로나 경제적으로나 비현실적입니다. CPU나 GPU 내부의 캐시(L1/L2/L3) 나, AI 가속기의 온칩 메모리 로 수 MB에서 수십 MB 정도만 탑재됩니다.\n빠르지만 비싸고, 용량이 작다. 그래서 프로세서 바로 옆에, 가장 자주 쓰는 데이터만 담아둡니다.\nDRAM — 싸고 크지만, 끊임없이 새로고침 셀 구조: 트랜지스터 1개 + 커패시터 1개 Dynamic Random Access Memory(DRAM) 의 셀 구조는 SRAM과 극적으로 다릅니다. 트랜지스터 1개와 커패시터(축전기) 1개, 단 2개의 소자로 1비트를 저장합니다. 이를 1T1C 구조 라고 합니다.\n커패시터에 전하가 충전되어 있으면 1, 방전되어 있으면 0입니다. 트랜지스터는 이 커패시터에 접근하기 위한 스위치 역할을 합니다.\n왜 싼가 셀에 필요한 소자가 2개뿐이므로, 셀 면적이 SRAM의 1/4에서 1/6 수준 입니다. 같은 웨이퍼에서 훨씬 더 많은 비트를 생산할 수 있으니, 비트당 단가가 크게 낮아집니다. 이 밀도 이점 덕분에 DRAM은 수 GB에서 수십 GB 단위의 메인 메모리로 사용됩니다.\n왜 느린가 (상대적으로) 커패시터는 시간이 지나면 저장된 전하가 조금씩 누설됩니다. 그래서 데이터가 사라지기 전에 주기적으로 전하를 다시 채워주는 리프레시(refresh) 동작이 필요합니다. \u0026ldquo;Dynamic\u0026quot;이라는 이름은 바로 이 특성에서 유래합니다.\n읽기 동작도 SRAM보다 복잡합니다. 커패시터의 전하를 비트라인으로 공유(charge sharing)한 뒤 감지 증폭기(sense amplifier)로 증폭해야 하고, 읽기 과정에서 전하가 소모되므로 읽은 직후 다시 써줘야(restore) 합니다.\n이런 과정들이 추가되기 때문에 접근 지연은 10-100ns 수준 으로, SRAM보다 10배 이상 느립니다.\nDDR: DRAM의 속도를 끌어올리는 인터페이스 DRAM 셀 자체는 느리지만, 외부와 데이터를 주고받는 인터페이스 규격 을 개선하면 실질 전송 속도를 높일 수 있습니다. 그 규격이 바로 Double Data Rate(DDR) 입니다.\nDDR 이전의 SDRAM은 클럭의 상승 엣지(rising edge)에서만 데이터를 전송했습니다. DDR은 이름 그대로 상승 엣지와 하강 엣지 양쪽 모두 에서 데이터를 전송하여, 같은 클럭에서 전송량을 2배로 늘렸습니다.\n이후 세대가 거듭되면서 프리페치(prefetch) 깊이를 늘리는 방식으로 전송 속도를 끌어올렸습니다. 프리페치란 한 번의 내부 메모리 접근으로 여러 비트(beat)를 미리 꺼내두는 기법으로, 내부 클럭보다 외부 전송 속도를 더 빠르게 만들어 줍니다. DDR4는 한 번에 8비트를, DDR5는 16비트를 프리페치합니다. 덕분에 DDR5는 단일 모듈 기준 최대 약 50 GB/s 수준의 대역폭을 제공합니다.\n하지만 이 개선에는 근본적인 천장이 있습니다.\nHBM — DRAM을 쌓아올리다 핀 수의 한계를 패키징으로 돌파하기 DDR의 데이터 버스 폭은 DDR5 기준 64비트 입니다. 프로세서와 메모리를 연결하는 물리적 핀 수에 제한이 있기 때문에, 클럭을 아무리 올려도 한 번에 전송할 수 있는 데이터의 양에는 천장이 존재합니다.\nAI 연산처럼 대규모 데이터를 동시에 읽어야 하는 워크로드에서는 이 병목이 치명적입니다. High Bandwidth Memory(HBM) 는 이 문제를 셀 구조가 아닌 패키징 으로 해결합니다.\n핵심 아이디어는 간단합니다. DRAM 다이를 수직으로 쌓고, 기판 위에서 프로세서 바로 옆에 배치하는 것입니다.\nTSV: 실리콘을 관통하는 수직 배선 일반적인 DRAM 모듈은 PCB 위의 배선으로 프로세서와 연결됩니다. HBM은 다릅니다. 실리콘 다이 자체에 미세한 구멍을 뚫고 구리 배선을 채워 넣어, 위아래 다이를 수직으로 연결합니다. 이것이 Through-Silicon Via(TSV), 실리콘 관통 전극입니다.\nTSV 덕분에 여러 장의 DRAM 다이를 한 스택으로 쌓을 수 있고, 각 다이가 독립적인 데이터 경로를 가지므로 버스 폭을 극적으로 넓힐 수 있습니다. HBM4 기준 데이터 버스 폭은 2048비트 로, DDR5의 32배 입니다.\n인터포저: 프로세서 바로 옆에 붙이다 HBM 스택은 실리콘 인터포저(interposer) 라는 중간 기판 위에 GPU 또는 AI 가속기와 나란히 배치됩니다. 인터포저 내부의 미세 배선이 HBM과 프로세서를 불과 수 mm 거리에서 연결하므로, 기존 DDR 모듈이 PCB를 통해 수십 cm를 이동하던 것과 비교하면 배선 거리가 극적으로 줄어듭니다.\n짧은 배선 = 낮은 지연 + 낮은 소비 전력 + 높은 신호 무결성. 이 조합이 HBM의 대역폭을 가능하게 합니다.\n수치로 보는 HBM 항목 DDR5 HBM3E HBM4 버스 폭 64-bit 1024-bit 2048-bit 스택당 대역폭 ~50 GB/s ~1.2 TB/s ~2 TB/s 이상 스택당 용량 - 24-36 GB 36-48 GB 프로세서와의 거리 수십 cm (PCB) 수 mm (인터포저) 수 mm (인터포저) 2025년 4월 반도체 표준화 기구인 Joint Electron Device Engineering Council(JEDEC) 이 HBM4 표준을 공식 발표했습니다. 이후 2026년 초부터 양산이 시작되었습니다.\nSK하이닉스는 세계 최초로 16층 48GB HBM4 스택을 공개했습니다. NVIDIA의 차세대 GPU인 Vera Rubin은 HBM4 스택 8개를 탑재하여 총 384GB, 약 22 TB/s 의 메모리 대역폭을 목표로 하고 있습니다.\nHBM의 한계: 빠르지만, 여전히 부족한 용량 HBM4까지 오면서 대역폭과 용량 모두 크게 성장했지만, 근본적인 제약은 여전합니다.\n셀 자체는 여전히 DRAM(1T1C)이므로, 비트 밀도의 한계는 그대로입니다. TSV 공정, 인터포저 제조, 다이 적층 시 수율 관리, 열 방출 문제까지 겹치면서 용량 대비 가격이 매우 높습니다.\nHBM4 8스택을 전부 탑재해도 최대 384GB입니다. 그런데 최신 Large Language Model(LLM) 의 파라미터 크기는 수백 GB에서 수 TB에 달합니다. 모델이 커지는 속도를 HBM의 용량 확장이 따라가지 못하고 있는 것이죠.\nNAND Flash — 싸고 크지만, 너무 느린 셀 구조: 전하를 가둬서 비트를 저장하다 NAND Flash 는 SRAM이나 DRAM과는 근본적으로 다른 원리로 데이터를 저장합니다.\nNAND 셀의 핵심은 플로팅 게이트(floating gate) 라는 절연층으로 둘러싸인 전도체입니다. 높은 전압을 가하면 전자가 터널링(tunneling) 현상을 통해 플로팅 게이트에 주입되고, 절연층이 전자의 탈출을 막아 전원이 꺼져도 데이터가 유지 됩니다. 이것이 NAND가 비휘발성(non-volatile) 메모리인 이유입니다.\n왜 싸고 큰가: 극한의 밀도 NAND의 밀도 이점은 두 가지에서 옵니다.\n첫째, 멀티 레벨 셀 입니다. 하나의 셀에 저장하는 전하량을 세밀하게 구분하면 여러 비트를 담을 수 있습니다. Triple-Level Cell(TLC) 는 셀당 3비트, Quad-Level Cell(QLC) 는 셀당 4비트를 저장합니다.\n면적당 집적밀도로 비교하면 그 차이가 더 극적입니다. SRAM은 약 0.04 Gb/mm² 수준인 반면, DRAM은 약 0.2-0.3 Gb/mm², 최신 3D NAND는 약 5-15 Gb/mm² 에 달합니다. 같은 실리콘 면적에서 SRAM 대비 100배 이상, DRAM 대비 20배 이상의 데이터를 저장할 수 있는 셈입니다.\n둘째, 3D 적층 입니다. 현대 NAND는 셀을 평면이 아닌 수직으로 수백 층을 쌓습니다. 삼성의 V-NAND, SanDisk의 BiCS NAND가 대표적이며, 최신 제품은 200층을 넘어섰습니다.\n이 두 가지 덕분에 NAND는 TB 단위의 대용량을 매우 낮은 비트당 단가로 제공합니다.\n왜 느린가: 읽기만 해도 마이크로초 NAND의 읽기 동작은 플로팅 게이트의 전하량에 따라 달라지는 트랜지스터의 문턱 전압(threshold voltage)을 측정하는 과정입니다. 멀티 레벨 셀에서는 여러 단계의 전압을 정밀하게 구분해야 하므로 시간이 더 걸립니다.\n결과적으로 NAND의 랜덤 읽기 지연은 약 50-100us 수준입니다. DRAM의 수십 ns, SRAM의 1ns 이하와 비교하면 1,000배 이상 느린 셈입니다.\n쓰기는 더 느리고, 데이터를 덮어쓰려면 블록 단위로 먼저 지워야(erase) 합니다. 게다가 erase/write 반복 횟수에 물리적 수명 제한(write endurance)이 있습니다.\nAI 서버에서의 현재 역할 현재 AI 서버에서 NAND(SSD)는 모델 저장소 와 체크포인트 저장 역할을 합니다. 학습된 모델 가중치를 보관하고, 필요할 때 HBM으로 로드하는 \u0026ldquo;창고\u0026rdquo; 역할이죠.\n하지만 연산 중에 직접 데이터를 공급하기에는 너무 느립니다. GPU가 데이터를 기다리는 시간이 연산 시간보다 길어지기 때문입니다.\n용량은 넉넉하고 가격도 저렴하지만, 속도가 치명적으로 부족하다. NAND는 이 한계 안에 갇혀 있었습니다.\n빈 자리 — HBM과 SSD 사이의 간극 지금까지 살펴본 메모리 계층을 한눈에 정리해 보겠습니다.\nSRAM DRAM (DDR5) HBM4 ??? NAND (SSD) 셀 구조 6T 1T1C 1T1C (TSV 적층) 플로팅 게이트 접근 지연 ~1 ns ~10-100 ns ~10-100 ns ~50-100 us 대역폭 (스택/모듈) 수 TB/s (온칩) ~50 GB/s ~2 TB/s ~7 GB/s 용량 수 MB-수십 MB 수 GB-수십 GB 36-48 GB 수 TB 비트당 비용 매우 높음 중간 높음 매우 낮음 휘발성 휘발성 휘발성 휘발성 비휘발성 표를 보면 한 가지가 눈에 들어옵니다.\nHBM4는 스택당 최대 48GB, 8스택을 탑재해도 384GB입니다. SSD는 수 TB의 용량을 저렴하게 제공하지만, 대역폭이 7 GB/s 수준에 불과합니다.\nHBM의 대역폭은 좋지만 용량이 부족하고, SSD는 용량은 넉넉하지만 너무 느리다.\n물론 현 시점에 HBM의 용량은 상대적으로 큰 것은 맞지만, 사람들의 기대에 비해 부족하다는 의미입니다.\n이 둘 사이에는 \u0026ldquo;TB 단위의 용량을 TB/s 단위의 대역폭으로 제공하는\u0026rdquo; 메모리가 존재하지 않습니다.\nLLM의 파라미터가 수백 GB에서 수 TB로 커지고 있는 지금, 이 빈 자리를 채울 수 있다면 어떨까요?\nHBF — NAND에 HBM의 옷을 입히다 핵심 아이디어: 익숙한 셀, 새로운 패키징 High Bandwidth Flash(HBF) 는 NAND 셀은 그대로 두고, HBM에서 검증된 패키징 기술을 적용한 새로운 메모리 계층입니다.\n앞서 HBM이 DRAM 셀을 바꾸지 않고 TSV 적층과 인터포저 배치만으로 대역폭을 혁신한 것을 보았습니다. HBF는 정확히 같은 전략을 NAND에 적용합니다.\nNAND 다이를 TSV로 수직 적층하고, 인터포저 위에 GPU나 AI 가속기 바로 옆에 배치합니다. HBM이 DDR의 핀 수 한계를 패키징으로 돌파했듯, HBF는 SSD의 대역폭 한계를 패키징으로 돌파하는 것입니다.\nCBA 아키텍처: NAND를 고대역폭에 최적화하다 HBF의 기술적 핵심은 SanDisk가 개발한 CMOS Bonding Array(CBA) 아키텍처입니다.\n기존 NAND는 하나의 큰 메모리 배열에 순차적으로 접근하는 구조입니다. CBA는 이를 수천 개의 독립적인 스토리지 서브어레이 로 분할합니다. 각 서브어레이가 자체적인 읽기/쓰기 채널을 가지고 동시에 병렬로 작동 하므로, 단일 NAND 다이에서 나올 수 없던 수준의 대역폭을 끌어냅니다.\n여기에 SanDisk의 BiCS NAND (3D 수직 적층 NAND) 기술이 결합됩니다. 수백 층으로 적층된 BiCS NAND 다이들을 TSV로 연결하고, CBA가 이 다이들의 서브어레이를 동시에 구동하는 구조입니다.\n스펙으로 보는 HBF HBM4 HBF Gen 1 HBF Gen 2 HBF Gen 3 읽기 대역폭 ~2 TB/s 1.6 TB/s \u0026gt;2 TB/s \u0026gt;3.2 TB/s 스택 용량 36-48 GB 512 GB 1 TB 1.5 TB 접근 지연 ~10-100 ns ~10 us - - 셀 구조 1T1C DRAM 플로팅 게이트 NAND 플로팅 게이트 NAND 플로팅 게이트 NAND 주목할 숫자가 있습니다.\nHBF Gen 1의 읽기 대역폭은 1.6 TB/s로, HBM4에 근접합니다. 그런데 용량은 512GB로, HBM4 스택(48GB)의 10배 가 넘습니다. HBM 대비 8-16배의 용량을 유사한 대역폭과 유사한 비용 으로 제공하는 것이 HBF의 핵심 가치입니다.\nHBM 컨트롤러와의 호환성 HBF의 또 다른 강점은 물리적 footprint와 전기적 인터페이스(PHY 레벨)가 HBM과 호환 된다는 점입니다.\n핀 배치, 패키지 크기, 전력 프로파일, 스택 높이까지 HBM4와 거의 동일하므로, 기존 HBM용 인터포저와 패키징 인프라를 그대로 재활용할 수 있습니다.\n다만, HBF가 HBM의 drop-in 대체품은 아니라는 점 은 분명히 해둘 필요가 있습니다. NAND는 DRAM과 접근 단위(페이지 vs. 워드), 소거 사이클, wear-leveling 등의 특성이 다르기 때문에, 호스트 측 컨트롤러에는 최소한의 프로토콜 변경이 필요 합니다. SanDisk와 SK하이닉스가 추진 중인 오픈 표준도 \u0026ldquo;동일한 전기 인터페이스 + 최소한의 프로토콜 변경\u0026quot;을 지향점으로 두고 있습니다.\n즉, 새로운 메모리 컨트롤러를 처음부터 설계할 필요는 없지만, 기존 HBM 컨트롤러를 그대로 쓸 수는 없습니다. 그래도 가속기 설계자 입장에서 채택 장벽이 크게 낮아진다는 점은 여전히 유효합니다.\nHBF의 한계: 만능은 아니다 HBF는 빈 자리를 채우는 강력한 후보이지만, 한계도 명확합니다.\n지연시간: 약 10us로, HBM의 수십-수백 ns 대비 약 100배 느립니다. NAND 셀의 읽기 메커니즘 자체가 DRAM보다 본질적으로 느리기 때문에, 패키징만으로는 이 격차를 완전히 해소할 수 없습니다.\n쓰기 속도와 수명: NAND 특유의 느린 쓰기와 제한된 erase/write 사이클은 그대로 남아 있습니다. 이 때문에 HBF는 빈번한 쓰기가 필요한 AI 학습(training) 에는 적합하지 않습니다.\n반대로, 한 번 로드한 모델 가중치를 반복적으로 읽기만 하는 AI 추론(inference) 워크로드에는 이러한 한계가 큰 문제가 되지 않습니다. HBF가 \u0026ldquo;AI 추론 시대의 메모리\u0026quot;로 주목받는 이유가 바로 여기에 있습니다.\n마무리 \u0026amp; 다음 편 예고 이번 글에서는 메모리가 왜 여러 종류로 나뉘는지, 각 메모리의 셀 구조가 어떻게 속도/용량/비용의 트릴레마를 결정하는지를 살펴보았습니다.\n정리하면 이렇습니다.\nSRAM: 6T 셀, 가장 빠르지만 가장 비싸고 작다 DRAM: 1T1C 셀, 밀도 이점으로 메인 메모리를 담당하지만 대역폭에 한계가 있다 HBM: DRAM 셀에 TSV + 인터포저 패키징을 적용하여 대역폭을 혁신했지만, 용량 확장이 어렵다 NAND: 극한의 밀도와 낮은 가격이지만, 너무 느려서 연산에 직접 참여하지 못한다 HBF: NAND 셀에 HBM의 패키징을 적용하여, HBM과 SSD 사이의 빈 자리를 채우는 새로운 계층 그런데 빈 자리를 채울 수 있다는 것만으로는 이야기가 완성되지 않습니다.\nHBF는 HBM 대비 약 100배 긴 지연시간(약 10us)이라는 약점을 가지고 있습니다. 그렇다면 이 약점을 어떻게 극복하고, HBF를 실제 LLM 워크로드에 활용할 수 있을까요?\n다음 편에서는 HBF가 LLM에서 어떻게 활용될 수 있을지, 그리고 SK하이닉스가 제안한 long latency 극복 방안을 중심으로 알아보겠습니다.\n다음 편은 HyperAccel의 Jaewon Lim 님이 작성해 주실 예정입니다. 많은 관심 부탁드립니다!\n추신 저는 HyperAccel에서 LLM 가속 ASIC 칩 출시를 위해 RTL을 설계하고 있습니다. 메모리 대역폭이라는 한정된 자원을 최대한 활용해서 최고의 성능을 내기 위해서 많은 사람들이 함께 머리를 맞대고 더 효율적인 활용법을 고민하고 있습니다. 이 시리즈를 통해 메모리 기술의 흐름을 함께 이해하고, 앞으로의 변화를 함께 지켜볼 수 있으면 좋겠습니다.\nHyperAccel은 HW, SW, AI를 모두 다루는 회사로, 전 방면에 걸쳐 뛰어난 인재들이 모여 있습니다. 폭넓은 지식을 깊게 배우며 함께 성장하고 싶으신 분들은 언제든지 지원해 주세요!\n채용 사이트: https://hyperaccel.career.greetinghr.com/ko/guide\nReference SanDisk HBF Fact Sheet Scaling the Memory Wall: Behind Sandisk\u0026rsquo;s High Bandwidth Flash for AI Inferencing SK hynix and Sandisk Begin Global Standardization of Next-Generation Memory \u0026lsquo;HBF\u0026rsquo; SK Hynix Unveils AI Chip Architecture with HBF HBM VS HBF VS HBS: Building the Memory Hierarchy for AI High Bandwidth Flash: NAND\u0026rsquo;s Bid for AI Memory HBF: A High-Bandwidth Flash New Star Breaking the \u0026ldquo;Memory Wall\u0026rdquo; for AI High Bandwidth Flash is years away despite its promise SK hynix and SanDisk announce new High Bandwidth Flash — Tom\u0026rsquo;s Hardware HBM roadmaps for Micron, Samsung, and SK hynix: To HBM4 and beyond The State of HBM4 Chronicled at CES 2026 ","permalink":"https://hyper-accel.github.io/posts/what-is-hbf/","summary":"메모리는 왜 여러 종류이고, HBF는 어디에 위치하는가? SRAM부터 HBF까지, 메모리 계층의 물리적 원리와 HBF의 기술 구조를 알아봅니다.","title":"AI 시대의 필수 소비재, 메모리 이해하기 1편: HBF 이해하기"},{"content":"Project Glasswing: Claude Mythos Preview 안녕하세요. HyperAccel CL(Compute Library)팀 박현준입니다.\n2026년 4월 초, Anthropic은 Project Glasswing 이라는 산업 연대와 함께 Claude Mythos Preview 라는 미공개 프론티어 모델을 공개했습니다. 최신 모델 소식은 보통 “벤치마크가 올랐다” 정도로 끝나는데, 이번에는 Frontier Red Team 블로그 에서 한 달간의 내부 평가와 취약점 사례를 아주 길게 풀었습니다. Mythos Preview 수준의 코딩·추론이 기존 벤치가 가리키던 범위를 넘어서 취약점 탐지 와 공격 코드 작성 까지 한 번에 끌고 올라왔기 때문이죠. 솔직히 처음엔 단순한 마케팅 전략인가 싶었는데, 읽다 보니 이번만큼은 숫자 너머 이야기가 꽤 크다는 느낌이 들었습니다.\nMythos Preview란 무엇인가 Project Glasswing Glasswing은 AWS, Apple, Google, Microsoft, Linux Foundation 등이 참여한 방어 우선(defense-first) 협력 프로그램입니다. 핵심은 모델의 성능을 빠르게 넓게 푸는 것보다, 고위험 역량을 먼저 방어 커뮤니티에 연결해 실제 대응력을 올리는 데 있습니다. 다시 말해, 모델을 \u0026ldquo;공개한다/안 한다\u0026quot;의 이분법으로 보기보다, 누구에게 어떤 통제 아래 먼저 접근권을 줄 것인지까지 포함해 배포 전략을 설계한 프로젝트라고 볼 수 있습니다. Anthropic은 Mythos Preview에 대해 일반 공개(GA) 계획이 없다 고 명시했습니다. 이 결정은 강한 사이버 역량이 무분별하게 확산될 때 생길 수 있는 부작용을 통제하려는 선택인 것 같습니다.\nRed Team 글에 따르면 Mythos Preview는 사용자의 지시가 주어졌을 때 주요 운영체제와 주요 웹 브라우저 에서 제로데이(zero-day) , 즉 아직 공개되지 않은 취약점을 찾아내고 공격 코드까지 만들 수 있는 수준입니다. 이런 능력은 방어 효율을 크게 높일 수 있지만, 동시에 악용 속도도 끌어올릴 수 있기에 Anthropic이 제한 공개를 택한 배경이 됩니다.\n새로운 차원의 가치를 창출하는 LLM의 등장 Mythos가 기존 모델들과 차별화되는 지점은 \u0026ldquo;정답을 얼마나 잘 맞히는가\u0026quot;보다 \u0026ldquo;학습되지 않은 문제를 어디까지 해결하는가\u0026quot;에 있습니다. 과거 모델들은 학습된 패턴을 기억하여 사람이 직접 만든 시험에 대한 점수를 높여왔다면, Mythos는 학습되지 않은 취약점 탐지 에서도 새로운 차원의 가치를 창출하고 있습니다.\n여기서 말하는 새로운 가치는 단순히 벤치마크 점수를 높이는 데 있지 않고, 실제 운영 환경에서 오랫동안 드러나지 않았던 치명적 시스템 결함을 찾아내 방어 의사결정에 바로 연결할 수 있다는 점을 의미합니다. 그리고 이 가치는 Red Team 보고서에서 공개된 OpenBSD, FFmpeg, FreeBSD 사례처럼, 장기간 누락되어 있던 결함이 실제로 식별된 결과를 통해 증명됩니다.\nMythos Preview는 무엇이 다른가 벤치마크의 발전 프론티어 모델이 출시될 때마다 사용되는 벤치마크는 해당 모델의 강점이 잘 드러나는 축 으로 조금씩 기울거나, 새 지표가 덧붙는 경향이 있습니다.\nLLM 등장 이래 벤치마크의 변화를 크게 네 단계로 나누어 보면 다음과 같습니다.\n패턴 맞추기에 가까운 시험 — 초기 벤치마크. 짧은 지식 문제, 작은 함수 하나 고치기 정도가 가능한지 평가합니다. 실제 코드베이스 단위의 코딩 — 파일 한 조각이 아니라 프로젝트 전체 문맥을 보고 문제를 푸는지 체크합니다. 장기 에이전틱 실행 — 한 번의 답을 맞추는 것이 아니라 시도·실패·재시도 를 포함해 더 고수준의 문제를 해결할 수 있는지 확인합니다. 실전 결과 중심 평가 — 공개 벤치에 없는 제로데이 (아직 공개되지 않은 취약점)를 찾게 하여 “외워서 푼 것”이 아니라는 것을 검증합니다. 이 과정에서 기존 공개 벤치는 점수가 한계에 닿으면서 포화(saturate) 되고, 측정은 자연스럽게 다음 질문으로 넘어갑니다. “더 큰 덩어리의 작업을 끝까지 밀어붙일 수 있는가”, “특정 도메인의 문맥을 이해하고 손댈 수 있는가”처럼 대규모 업무 와 도메인에 특화된 업무 를 얼마나 잘 처리하는지를 가리키는 쪽으로 무게중심이 옮겨갑니다.\nAnthropic이 Claude Opus 4.7 을 내놓으면서 함께 실은 평가 표에도, 코딩 에이전트·터미널·긴 맥락·도구 사용·금융·문서 등 도메인 벤치 가 나란히 올라와 있는 것이 그 연장선에 있습니다.\nMythos의 벤치마크 성능 Glasswing 페이지와 Red Team 글에는 여러 벤치마크 성능 표가 실려 있습니다. 제시된 항목에서는 Mythos Preview가 Opus 4.6보다 높은 점수를 보인다고 적혀 있고, 그 중 일부만 가져왔습니다.\n벤치마크 Mythos Preview Opus 4.6 CyberGym 83.1% 66.6% SWE-bench Verified 93.9% 80.8% Terminal-Bench 2.0 82.0% 65.4% 숫자만 봐도 개선 폭이 크다는 인상은 받았지만, 저는 낯선 벤치마크보다 Red Team 글 에 담긴 구체적인 사례가 더 많이 와닿았습니다. 이를테면 오랜 기간 안정적으로 서비스 해왔던 여러 프로그램들에게서 취약점을 발견한 것인데요, 제세한 내용은 다음 장에 정리했습니다.\n방어적 활용에 성공한 사례 OpenBSD, TCP SACK (27년 된 취약점) 첫 번째로는 27년 동안 남아 있던 OS의 버그를 발견한 사례입니다. Selective Acknowledgment(SACK) 는 TCP에서 “중간에 빠진 조각만 다시 보내자”고 알려 주는 기능입니다. Red Team 글에 따르면, Mythos Preview는 OpenBSD가 이 기능을 처리하는 코드에서 확인해야 할 범위의 시작과 끝을 제대로 검사하지 못하는 틈 과, 시퀀스 번호를 비교하는 방식의 정수 연산 오버플로 가 겹치는 조합을 찾았습니다. 평소에는 동시에 성립하지 않아야 할 조건이 한꺼번에 참이 되면서, 커널이 잘못된 주소에 쓰기를 시도하고 원격에서 기계가 멈추는(Denial of Service, DoS) 상황으로 이어진다고 설명합니다.\nFFmpeg, H.264 디코더 (16년 된 취약점) 16년 넘게 사용되던 동영상 디코더에서도 버그를 찾았습니다. H.264 디코더는 화면을 잘게 나누어 슬라이스 단위로 디코딩합니다. 여기서 “슬라이스 번호는 32비트까지 올라갈 수 있는데, 각 블록이 어느 슬라이스에 속하는지 기록하는 표는 16비트만 쓴다”는 자릿수가 맞지 않는 구조 가 문제입니다. 이 표에는 ‘비어 있음’을 뜻하는 값으로 65535 를 채워 두는데, 슬라이스를 극단적으로 많이 넣으면 실제 슬라이스 번호 65535 와 이 ‘비어 있음’ 표시가 겹쳐 버립니다. 그러면 엉뚱한 칸을 참조하게 되어 힙 메모리를 조금 넘겨 쓰는 상황 이 발생하게 된다는 점을 발견하였습니다.\nFreeBSD NFS, Remote Code Execution(RCE) (17년 된 취약점) Mythos는 17년 된 파일 공유 프로그램에서도 보안 상 취약점을 발견하였습니다. NFS는 파일을 네트워크로 공유할 때 쓰는 서비스입니다. Red Team 글에 따르면 Mythos Preview가 로그인 없이도 서버에 접근해 root 권한을 얻는 경로를, 버그 탐지부터 공격코드 작성까지 사람 개입 없이 끝냈다고 합니다. Remote Procedure Call(RPC) 의 RPCSEC_GSS 처리에서 길이 검사가 느슨해 커널 스택 오버플로가 가능했고, 이를 Return Oriented Programming(ROP) 으로 이어 authorized_keys 에 공격자 키를 추가하였습니다.\n개발자: 에이전트 시대에 우리는 어떻게 일해야 하는가 예시를 통해 LLM은 점점 기존 벤치마크의 점수를 높게 받는 단계를 넘어서 실제 가치를 창출하는 단계에 도달하고 있다는 점을 확인할 수 있었습니다. 에이전트의 능력이 한 단계 오를 때마다 개발자가 직접 코드를 작성하는 일 이 줄어들고, 설계하고 검증하고 책임지는 쪽으로 역할이 옮겨가고 있습니다. 보안 사례는 하나의 케이스일 뿐, 일상 개발도 같은 방향의 압력을 받고 있다고 느낍니다. 2달 전에 작성한 에이전트 도입기 글에서 에이전트로 코드 생산성이 오름에 따라 병목이 되는 곳은 리뷰라고 언급했었는데요, 리뷰가 바로 검증하고 책임지는 작업에 해당합니다.\n사람이 코드를 줄 단위로 읽는 방식은 속도에 한계가 있어서, 일부 변화가 빠른 팀에게는 plan.md 를 리뷰해보려는 움직임도 보이고 있습니다. 다만 이 분야는 변화 속도가 너무 빠르기에 “어떤 방식이 정답이다”라고 지금 단정하기는 어렵습니다. 제가 생각했을 때 중요한 점은 하나의 고정된 프로세스를 선언하는 것이 아니라, 모델이 다음 점프를 할 때마다 개발자도 변화에 맞춰 유기적으로 작업 프로세스를 갱신할 준비 를 갖추는 일이라고 생각합니다.\n저희 팀은 이미 플랜 리뷰를 적극 권장하고 있고, 앞으로 출시될 에이전트 역량에 맞춰 프롬프트, 하네스, 검증 장치를 유기적으로 바꿔 가보려고 합니다. 예를 들면 에이전트가 무한 루프나 공회전에 빠지지 않도록 가드레일 및 표지판을 설계하고, 작업마다 서로 다른 모델을 사용하고, 스스로 공격을 시도하도록 하여 보안을 강화하는 식으로 하네스를 설계하려고 합니다. 앞으로도 여러 시행착오를 겪으며 인사이트를 공유드리겠습니다.\n참고 링크 Project Glasswing Assessing Claude Mythos Preview’s cybersecurity capabilities (Red Team) Claude Mythos Preview System Card (PDF) Introducing Claude Opus 4.7 HyperAccel 채용 중! ChatGPT가 출시된 지 3년 반이 지났는데요, 이순신의 스마트폰에 대해 구구절절 이야기하던 LLM은 어느덧 장기간 널리 신뢰받고 있는 프로그램들의 보안 체계까지 위협하고 있습니다. HyperAccel은 빠르게 발전하는 최신 에이전트 사용을 주저하지 않고, 최소한의 보안 아래 회사의 적극적인 지원 및 사내 스터디를 통해 적극적으로 실무에 사용하고 있습니다.\n또한 에이전트가 더 많은 업무 환경에 퍼질수록 추론에 필요한 연산·메모리·전력 수요도 함께 커집니다. HyperAccel은 이러한 시장의 흐름에 맞춰 지속 가능한 가속 인프라를 공급하는 목표를 갖고 있습니다.\n저희가 다루는 기술에 관심이 있으시다면 HyperAccel Career 로 지원해 주세요. 긴 글 읽어 주셔서 감사합니다.\n","permalink":"https://hyper-accel.github.io/posts/project-glasswing-mythos-preview/","summary":"Anthropic의 Project Glasswing과 Claude Mythos Preview를 중심으로, 모델의 사이버보안 역량이 왜 도약했는지, 벤치마크가 어떻게 바뀌었는지, 실제 방어 사례를 정리하고, 개발자가 에이전트와 소통하는 방식이 어디로 가야 하는지까지 짚습니다.","title":"Project Glasswing: Claude Mythos Preview"},{"content":"Kubernetes 기반 사내 개발 환경 구축기 3편: LPU를 위한 Kubernetes Device Plugin 안녕하세요! 저는 HyperAccel ML팀에서 DevOps Engineer로 근무하고 있는 전영훈입니다.\n이번 포스팅은 Kubernetes 기반 사내 개발 환경 구축기 시리즈의 3번째 글입니다!\n1편에서는 Kubernetes를 기반으로 하는 개발 환경 구축의 배경과 전체적인 설계 및 방향에 대해서 살펴보았고, 2편에서는 기존 Self-Hosted Runner의 구조적인 한계를 뛰어넘기 위한 ARC 기반 CI/CD 인프라 설계 전략 수립 및 구축 과정에 대해 소개하였습니다. 3번째 글에서는 Kubernetes 환경 위에서 Custom Resource 활용 시에 필요한 Device Plugin 에 관련된 내용을 전달하고자 합니다.\n하이퍼엑셀은 LLM 추론에 특화된 LPU(LLM Processing Unit) device를 만드는 회사입니다. Kubernetes 환경 위에서 LPU라는 custom resource를 인식하게 하고 원활한 스케줄링을 돕기 위해서는 LPU를 위해 개발된 Device Plugin이 필요합니다.\n이번 글에서는 LPU Device Plugin이라는 키워드를 주제로 아래 내용들에 대해 이야기해보려고 합니다!\n우선, Kubernetes Device Plugin의 동작 원리와 구체적인 동작 방식에 대해 설명합니다. 이후에 하이퍼엑셀의 1세대 FPGA 기반 LPU를 위한 device plugin의 개발 과정 및 어떠한 방식으로 제공되고 있는지에 대해 소개합니다. 이어서 곧 출시를 앞둔 ASIC 기반 LPU인 Bertha 를 위한 device plugin의 개발 과정에 대해 간략하게 소개하겠습니다. 마지막으로는 현재 각광받고 있는 기술인 DRA(Dynamic Resource Allocation) 를 소개하고, DRA가 Kubernetes에서 스케줄러 및 Device Plugin과 어떤 연관성이 있는지 설명하겠습니다.\nKubernetes Device Plugin Kubernetes Device Plugin 프레임워크는 GPU, FPGA, NIC과 같은 custom device들을 Kubernetes 클러스터에 노출하고 관리할 수 있게 해주는 표준 인터페이스 입니다.\n기본적으로 Kubernetes는 CPU와 메모리 리소스만 인식할 수 있습니다. 따라서 Device Plugin을 적용하지 않는다면 Kubernetes에서 custom device들에 대한 정보가 전혀 없기 때문에 하드웨어 간 구분이 어렵고, device의 상태 체크 혹은 Pod을 스케줄링할 때 기준으로 삼는 것과 같은 동작이 어렵습니다. Device Plugin을 통해 Vendor들이 Kubernetes 코드를 직접 수정하지 않고도 자신들의 하드웨어를 지원할 수 있게 되었습니다.\n왜 Device Plugin이 필요한가? Device Plugin이 제공되기 이전에는 새로운 하드웨어를 지원하기 위해서는 Kubernetes 자체의 소스 코드를 직접 수정해야 했습니다. 이러한 방식은 방대한 양의 Kubernetes 소스 코드의 파악이 필요하기 때문에 유지보수가 어렵고, 새로운 하드웨어에 대해서 매번 코드를 수정해야 하기 때문에 확장성이 떨어지는 방식이었습니다.\n정리해보자면,\n유지보수 용이성 및 확장성 증가: Kubernetes는 컨테이너 오케스트레이션에만 집중 하고, 하드웨어 제어 로직은 제조사(NVIDIA, AMD, HyperAccel 등)가 만든 Device Plugin이 담당합니다.\n다양한 하드웨어 지원: GPU 뿐만 아니라 고성능 네트워크(SR-IOV), 암호화 가속기(QAT) 등 다양한 자원을 동일한 방식으로 관리할 수 있습니다.\nDevice Plugin의 작동 원리 \u0026amp; 워크플로우 Device Plugin은 일반적으로 DaemonSet으로 실행되며, 각 노드에서 gRPC 서비스를 통해 Kubelet과 통신합니다. Kubelet과 Device Plugin의 통신을 통해 device를 인식하게 하는 과정은 아래와 같습니다.\n등록 단계 (Registration)\nPlugin이 시작되면 노드의 특정 경로(/var/lib/kubelet/device-plugins/kubelet.sock)를 통해 Kubelet에 자신을 등록합니다.\n\u0026ldquo;나는 hyperaccel.ai/lpu라는 리소스를 관리하는 plugin이다!\u0026rdquo; 라고 Kubelet에게 알리는 과정입니다.\n목록 확인 및 모니터링 단계 (ListAndWatch)\nKubelet은 주기적으로 plugin에게 사용 가능한 디바이스 목록을 요청합니다.\nPlugin은 ListAndWatch 메서드를 통해 디바이스의 상태(Healthy/Unhealthy)를 실시간으로 모니터링하여 Kubelet에 보고합니다.\n할당 단계 (Allocate)\n노드 레벨에서는, 사용자가 Pod 스펙에 resources.limits.hyperaccel.ai/lpu: 1을 명시하면, 스케줄러는 해당 리소스가 여유 있는 노드에 Pod를 배치합니다. 스케줄러는 Pod이 할당될 노드를 선택하는 역할 을 합니다.\n스케줄러를 통해 Pod이 노드에 배치되면, Kubelet은 plugin의 Allocate 메서드를 호출합니다. Plugin은 해당 컨테이너가 장치에 접근할 수 있도록 필요한 설정(환경 변수, 장치 노드 경로, 볼륨 마운트 등)을 응답합니다.\nDevice Plugin은 노드 내부에서 어떠한 디바이스를 할당할지 선택하는 역할 을 합니다.\n지금까지 Device Plugin이 Kubernetes가 디바이스를 인식하도록 Kubelet과 통신을 주고 받는 과정에 대해 살펴보았습니다. 그렇다면 두 컴포넌트가 서로 통신할 때 어떤 인터페이스가 필요할까요? Device Plugin이 Kubelet과 통신할 때 필요한 gRPC 인터페이스를 살펴보겠습니다.\n주요 gRPC 인터페이스 메서드 이름 역할 GetDevicePluginOptions Plugin의 옵션(정기적인 체크포인트 등)을 확인 ListAndWatch 디바이스 목록을 반환하고 상태 변경을 스트리밍 GetPreferredAllocation 선호 조건을 통해 특정 하드웨어가 선택되게끔 유도하는 기능 제공 Allocate 컨테이너 생성 시 특정 하드웨어를 사용하기 위한 설정 제공 PreStartContainer 컨테이너가 시작되기 전 장치를 초기화 (optional) 다음으로는 실제 pod이 디바이스를 요청하는 과정에서 Device Plugin을 비롯한 Kubernetes 내부 컴포넌트들이 어떤 과정을 통해 디바이스를 pod에게 할당하는지 설명하겠습니다.\nPod에게 디바이스가 할당되는 과정 하이퍼엑셀의 LPU를 예시로 설명하겠습니다.\n노드에서 사용 가능한 LPU 탐지 우선, Kubernetes 레벨에서 Device Plugin과 상호작용하여 API Server와 Kubelet이 어떻게 새로운 디바이스를 탐지하고 모니터링하는지에 대해 설명하겠습니다.\nRegisterRequest (디바이스 등록 요청)\nDevice Plugin이 실행되면 Unix Domain Socket을 통해 Kubelet의 Device Plugin Manager에게 plugin을 등록합니다.\n\u0026ldquo;이 노드에는 hyperaccel.ai/lpu라는 자원이 있으니 내가 관리하겠다\u0026rdquo; 라고 알리는 과정입니다.\nStart gRPC server (통신 서버 시작)\nDevice Plugin은 Kubelet과 통신하기 위해 gRPC 서버를 구동합니다. 이를 통해 Kubelet은 장치의 상태를 묻거나 장치를 할당(Allocate) 해달라는 요청을 보낼 수 있게 됩니다. ListAndWatch (장치 목록 확인 및 감시)\nKubelet은 Device Plugin의 ListAndWatch() 함수를 호출합니다.\n이 과정에서 Device Plugin은 하단에 연결된 LPU를 탐지하고, 이들의 상태(Healthy/Unhealthy)를 Kubelet에 보고합니다. 해당 연결은 계속 유지되어 장치에 문제가 생기면 즉시 알립니다.\nUpdate node status (노드 상태 업데이트)\nKubelet은 확인된 LPU 자원 정보(예: hyperaccel.ai/lpu: 4)를 API Server에 전달합니다.\nAPI Server는 이 정보를 etcd에 기록합니다.\n이제 클러스터 전체가 \u0026ldquo;해당 노드에서 LPU 4개를 사용할 수 있다\u0026rdquo; 는 사실을 알게 됩니다.\n이제 사용자가 pod를 생성할 때 YAML 파일에 아래와 같이 요청하면, Kubernetes Scheduler가 해당 노드로 pod를 배치할 수 있게 됩니다.\n# User Pod YAML file resources: limits: hyperaccel.ai/lpu: 1 # LPU 1개 요청 Pod의 요청에 맞는 적절한 LPU 선택 및 할당 위 과정을 통해 Kubernetes 레벨에서 LPU라는 새로운 디바이스를 사용할 준비가 완료되었다면, 이제 실제 할당 과정에 대해 살펴볼 필요가 있습니다. 사용자가 YAML 파일에 \u0026ldquo;LPU 1개가 필요해\u0026rdquo; 라고 선언했을 때, Kubernetes 내부적으로 어떤 동작이 일어나는지 단계별로 설명하겠습니다.\nBind(pod, node) - Pod 스케줄링\n사용자가 PodSpec에 hyperaccel.ai/lpu: 1을 요청합니다.\nKubernetes Scheduler 는 전체 노드 중 IDLE 상태인 LPU가 있는 노드를 탐색합니다.\n조건에 맞는 worker node를 선택하고, \u0026ldquo;해당 pod을 지정된 노드에 배치해!\u0026rdquo; 라고 명령(Bind)합니다.\nAllocateRequest (할당 요청)\nKubelet은 자신에게 배정된 pod을 실행하는데 LPU가 필요함을 확인합니다.\nKubelet 내부의 Device Plugin Manager가 Device Plugin에게 \u0026ldquo;LPU 1개가 필요하니 쓸 수 있게 준비해줘\u0026rdquo; 라고 요청합니다. 이때 사용할 특정 LPU의 ID(예: LPU 0)를 함께 전달합니다.\nAllocateResponse (할당 응답)\nDevice Plugin은 해당 LPU를 컨테이너에서 사용할 수 있도록 필요한 설정 정보들을 Kubelet에 응답합니다.\nEnvs: 컨테이너 안에서 참조할 환경 변수 Devices: 컨테이너가 접근해야 할 장치 경로 (예: /dev/lpu0) Mount: 필요한 라이브러리나 드라이버 파일의 마운트 경로 CreateContainer (컨테이너 생성)\nKubelet은 받은 정보를 바탕으로 컨테이너 런타임(containerd)에 컨테이너 생성을 요청합니다.\n이때 containerd는 설정된 대로 호스트의 /dev/lpu0 디바이스를 컨테이너 내부로 연결하여, 최종적으로 실행된 pod이 LPU 하드웨어에 직접 접근할 수 있게 됩니다.\n결과적으로 사용자는 복잡한 하드웨어 설정 과정을 몰라도, 단지 YAML 파일에 limits: hyperaccel.ai/lpu: 1이라는 한 줄만 추가함으로써 새로운 디바이스인 LPU를 안전하고 격리된 환경에서 사용할 수 있게 되는 것입니다!\n그런데, 위 과정의 4단계에서 한 가지 의문이 생길 수 있습니다. Device Plugin이 AllocateResponse로 반환한 장치 경로, 환경 변수, 마운트 정보를 컨테이너 런타임(containerd)은 어떻게 해석하고 주입하는 걸까요? 이러한 과정을 표준화한 것이 바로 CDI(Container Device Interface) 입니다.\nCDI: 디바이스 주입의 표준화 CDI가 등장하기 전의 문제 Device Plugin이 AllocateResponse를 통해 컨테이너에 필요한 설정 정보를 Kubelet에 전달하면, 최종적으로 컨테이너 런타임이 이를 해석하여 컨테이너를 생성합니다. 그런데 이 과정에서 벤더마다 디바이스를 컨테이너에 주입하는 방식이 제각각 이었습니다.\n예를 들어, NVIDIA GPU를 컨테이너에서 사용하려면 단순히 /dev/nvidia0 장치 파일만 마운트하는 것으로는 부족합니다. GPU 드라이버 라이브러리(libcuda.so, libnvidia-ml.so 등), 관련 유틸리티 바이너리, 그리고 이들의 정확한 버전에 맞는 경로까지 모두 컨테이너 내부에 올바르게 주입되어야 합니다. 이를 위해 NVIDIA는 자체적인 컨테이너 런타임 Hook인 nvidia-container-runtime-hook을 개발하여 사용해왔습니다.\nFPGA, 네트워크 가속기(SR-IOV), 암호화 가속기(QAT) 등 다른 벤더의 디바이스들도 각자 고유한 방식으로 장치 노드, 드라이버 라이브러리, 설정 파일을 컨테이너에 주입해야 합니다. 이로 인해 다음과 같은 문제가 발생하였습니다.\n런타임 의존성: 벤더마다 자체 컨테이너 런타임 혹은 런타임 Hook을 개발해야 했습니다. NVIDIA의 nvidia-container-runtime, AMD의 xilinx-container-runtime 등 각각의 런타임이 필요했고, 이들은 서로 호환되지 않았습니다.\n복잡한 설정 관리: 하나의 노드에서 GPU와 FPGA를 동시에 사용하려면 여러 런타임 Hook을 조합해야 하는 등 운영 복잡도가 증가하였습니다.\n이식성 부족: Docker에서 동작하던 디바이스 설정이 containerd나 CRI-O에서는 동작하지 않는 경우가 발생하였습니다. 컨테이너 런타임마다 디바이스 주입 방식이 달랐기 때문입니다.\nCDI란? CDI(Container Device Interface)는 이러한 문제를 해결하기 위해 등장한 컨테이너 런타임 수준의 표준 스펙 입니다. CDI는 디바이스를 컨테이너에 주입하는 방식을 하나의 JSON 스펙 파일 로 선언적으로 정의합니다. 컨테이너 런타임(containerd, CRI-O, Podman 등)이 이 스펙을 읽고 디바이스를 컨테이너에 주입하는 방식입니다.\n쉽게 말해, CDI 이전에는 벤더마다 \u0026ldquo;내 디바이스를 컨테이너에 넣으려면 이런 특수한 런타임을 설치해야 해\u0026rdquo; 라고 했다면, CDI 이후에는 \u0026ldquo;이 JSON 파일만 있으면 어떤 런타임이든 내 디바이스를 주입할 수 있어\u0026rdquo; 로 바뀐 것입니다.\nCDI 스펙 파일의 구조 CDI 스펙 파일은 /etc/cdi/ 또는 /var/run/cdi/ 경로에 위치하며, 다음과 같은 구조를 가집니다.\n{ \u0026#34;cdiVersion\u0026#34;: \u0026#34;0.6.0\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;hyperaccel.ai/lpu\u0026#34;, \u0026#34;devices\u0026#34;: [ { \u0026#34;name\u0026#34;: \u0026#34;lpu0\u0026#34;, \u0026#34;containerEdits\u0026#34;: { \u0026#34;deviceNodes\u0026#34;: [ { \u0026#34;path\u0026#34;: \u0026#34;/dev/lpu0\u0026#34;, \u0026#34;hostPath\u0026#34;: \u0026#34;/dev/lpu0\u0026#34;, \u0026#34;permissions\u0026#34;: \u0026#34;rw\u0026#34; } ], \u0026#34;mounts\u0026#34;: [ { \u0026#34;hostPath\u0026#34;: \u0026#34;/opt/hyperaccel/lib\u0026#34;, \u0026#34;containerPath\u0026#34;: \u0026#34;/usr/lib/hyperaccel\u0026#34;, \u0026#34;options\u0026#34;: [\u0026#34;ro\u0026#34;, \u0026#34;nosuid\u0026#34;, \u0026#34;nodev\u0026#34;, \u0026#34;bind\u0026#34;] } ], \u0026#34;env\u0026#34;: [ \u0026#34;LPU_DEVICE_INDEX=0\u0026#34;, \u0026#34;LPU_VISIBLE_DEVICES=0\u0026#34; ] } } ], \u0026#34;containerEdits\u0026#34;: { \u0026#34;env\u0026#34;: [ \u0026#34;LPU_DRIVER_VERSION=1.0.0\u0026#34; ] } } 위 스펙 파일의 주요 구성 요소를 살펴보면 다음과 같습니다.\n필드 설명 kind 디바이스의 종류를 식별하는 벤더 도메인 기반 이름 (예: hyperaccel.ai/lpu) devices 개별 디바이스 단위의 정의 목록. 각 디바이스는 고유한 name을 가짐 containerEdits 컨테이너에 적용할 변경 사항을 선언적으로 정의 deviceNodes 컨테이너 내부에 노출할 장치 파일 경로 및 권한 mounts 드라이버 라이브러리, 펌웨어 등 필요한 파일의 마운트 설정 env 컨테이너 내부에 주입할 환경 변수 디바이스 수준의 containerEdits는 해당 디바이스가 요청될 때만 적용되고, 최상위 containerEdits는 해당 kind의 디바이스가 하나라도 요청되면 공통으로 적용됩니다.\nCDI의 동작 흐름 CDI를 적용한 디바이스 할당 과정은 다음과 같습니다.\nCDI 스펙 생성: Device Plugin(혹은 DRA Driver)이 노드의 디바이스를 탐지하고, 각 디바이스에 대한 CDI 스펙 파일을 생성하여 /etc/cdi/ 경로에 저장합니다.\nCDI 디바이스 이름 전달: Pod에 디바이스를 할당할 때, Device Plugin은 AllocateResponse에 CDI 디바이스 이름(예: hyperaccel.ai/lpu=lpu0)을 포함하여 Kubelet에 전달합니다.\n컨테이너 런타임의 CDI 해석: Kubelet이 컨테이너 런타임(containerd)에 컨테이너 생성을 요청할 때 CDI 디바이스 이름을 함께 전달합니다. 컨테이너 런타임은 /etc/cdi/ 경로에서 해당 스펙 파일을 찾아 읽고, containerEdits에 정의된 장치 노드, 마운트, 환경 변수를 자동으로 컨테이너에 주입합니다.\n컨테이너 실행: 모든 디바이스 설정이 적용된 상태로 컨테이너가 실행되며, Pod 내부에서 디바이스에 직접 접근할 수 있습니다.\n이전에 살펴본 AllocateResponse 기반의 흐름과 비교하면, 디바이스를 컨테이너에 주입하는 복잡한 로직이 Device Plugin에서 CDI 스펙 파일로 분리 되었다는 것이 핵심입니다. Device Plugin은 더 이상 장치 경로, 마운트, 환경 변수를 직접 AllocateResponse에 담아 반환할 필요 없이, CDI 디바이스 이름만 전달하면 됩니다. 나머지는 컨테이너 런타임이 CDI 스펙을 통해 처리합니다.\ncontainerd 버전별 CDI 설정 CDI를 사용하려면 컨테이너 런타임에서 CDI 지원이 활성화되어 있어야 합니다. containerd의 경우 버전에 따라 CDI 지원 상태가 다릅니다.\ncontainerd 버전 CDI 지원 상태 설정 필요 여부 1.7 미만 CDI 미지원 사용 불가 1.7 ~ 1.x CDI 지원 (기본값: 비활성화) 수동 활성화 필요 2.0 이상 CDI 지원 (기본값: 활성화) 별도 설정 불필요 containerd 1.7 이상 ~ 2.0 미만 버전에서는 /etc/containerd/config.toml에서 CDI를 명시적으로 활성화해야 합니다.\n[plugins.\u0026#34;io.containerd.grpc.v1.cri\u0026#34;] enable_cdi = true cdi_spec_dirs = [\u0026#34;/etc/cdi\u0026#34;, \u0026#34;/var/run/cdi\u0026#34;] 설정 변경 후 containerd를 재시작하면 CDI가 활성화됩니다.\nsudo systemctl restart containerd containerd 2.0부터는 enable_cdi가 기본적으로 true이므로 별도의 설정 없이 CDI를 바로 사용할 수 있습니다.\nCDI와 DRA의 관계 CDI는 이후에 소개할 DRA(Dynamic Resource Allocation)와도 밀접한 관계가 있습니다. DRA Driver는 디바이스를 컨테이너에 주입할 때 CDI를 표준 인터페이스로 사용합니다. 즉, CDI는 Device Plugin 시대의 디바이스 주입 방식을 표준화하는 데서 출발하여, DRA 시대에도 핵심적인 역할을 수행하는 기반 기술 입니다. DRA에 대해서는 이후 섹션에서 자세히 다루겠습니다.\nDevice Plugin Examples 지금까지 Kubernetes Device Plugin이 무엇이고, 왜 필요하고, 어떤 과정을 통해 디바이스를 감지하고 할당하는지 와 더불어 디바이스 주입의 표준화 기술인 CDI에 대해서 살펴보았습니다. 본격적으로 LPU를 위한 Device Plugin을 살펴보기 전에, 대표적인 vendor인 NVIDIA와 AMD에서 제공하는 Device Plugin을 예시로 살펴보겠습니다.\nNVIDIA GPU Device Plugin NVIDIA Cloud-Native Toolkit Stack Layer에서 볼 수 있듯이, NVIDIA는 GPU 활용을 위해 계층화된 구조를 제시합니다.\nLinux Distribution: 호스트 OS 레벨\nContainer Engine (Docker/containerd): 컨테이너 실행 환경\nKubernetes: Pod 스케줄링 및 관리\nGPU Operator (Top Layer): 이 모든 과정을 자동화하는 운영 도구로, 그 핵심 구성 요소 중 하나가 바로 NVIDIA Device Plugin 입니다.\nNVIDIA GPU Operator는 자원 노출(Expose Resources), 상태 모니터링(Health Check), 장치 할당 및 격리(Device Allocation \u0026amp; Isolation) 와 같은 Device Plugin의 기본 기능을 전부 지원하면서도 다음과 같은 확장성을 가집니다.\n특징 설명 MIG(Multi-Instance GPU) 지원 MIG 기능을 통해 하나의 물리 GPU를 여러 개의 가상 GPU로 나누어 관리할 수 있음 생태계 통합 Prometheus(모니터링), Grafana(시각화)와 연동되는 dcgm-exporter와 긴밀하게 작동 운영 자동화 GPU Operator를 통해 드라이버 설치부터 플러그인 배포까지 한 번에 관리하는 현대적인 패턴으로 제공 AMD Xilinx Device Plugin Xilinx는 제공하는 디바이스인 FPGA를 Kubernetes 환경에서 원활하게 사용할 수 있도록 지원하기 위해 Node Feature Discovery(NFD)와 FPGA Operator를 융합 하여 활용합니다.\nNFD는 각 노드를 스캔하여 \u0026ldquo;이 노드에는 어떤 Xilinx 카드가 꽂혀 있는가?\u0026rdquo; 를 파악하고, 노드에 label을 생성합니다. FPGA는 모델명뿐만 아니라 장착된 Shell 버전, PCIe 정보 등이 매우 중요하기 때문에, 스케줄러가 FPGA 모델이나 특정 기능 지원 여부를 보고 pod를 배치할 수 있도록 기초 데이터를 제공합니다.\nNFD가 노드에 label을 생성했다면, FPGA Operator는 이를 기반으로 노드를 READY 상태로 만듭니다.\n컴포넌트 설명 Host Setup 각 노드에 XRT(Xilinx Runtime) 드라이버와 펌웨어를 자동으로 설치 Container Runtime 컨테이너 내에서 xbutil 같은 도구를 사용하거나 FPGA 자원에 접근할 수 있도록 전용 런타임 엔진을 구성 Device Plugin 최종적으로 xilinx.com/fpga와 같은 가상 자원을 API Server에 보고 하이퍼엑셀의 1세대 LPU는 Xilinx의 FPGA를 기반으로 합니다. 즉, 전술한 Xilinx Device Plugin을 적용해야만 Kubernetes 환경에서 LPU를 활용할 수 있습니다.\n하지만, Xilinx Device Plugin을 그대로 적용하여 실제 서버 환경에서 사용하기는 기능적인 한계가 있기 때문에 어렵습니다. 어떤 한계점이 있고 저희는 어떻게 이를 극복했을까요? 이제 본격적으로 저희가 어떻게 LPU를 위한 Device Plugin을 구현했는지 설명해보겠습니다.\nHyperAccel LPU를 위한 Kubernetes Device Plugin 하이퍼엑셀의 1세대 LPU는 FPGA(Field-Programmable Gate Array) 위에 설계되었고, Xilinx Alveo U55C 디바이스를 기반으로 하고 있습니다.\nXilinx에서 Xilinx FPGA Device Plugin을 오픈소스로 제공하고 있습니다. 이를 활용하여 클러스터에 Daemonset 형태로 plugin을 배포하면, Kubernetes에서 FPGA를 리소스 하드웨어로 인식하고 스케줄링의 대상을 선택할 수 있습니다. FPGA는 amd.com/xilinx_u55c_gen3x16_xdma_base_3-0와 같은 이름을 가지고 인식됩니다.\n기존 Xilinx Device Plugin 적용의 어려움 현재 하이퍼엑셀은 FPGA 기반 LPU를 탑재한 오리온(Orion) 서버를 제공하며, 오리온 서버 하나에는 8개의 LPU 디바이스가 장착됩니다.\n이때 8개의 LPU는 Ring-Topology 형태로 연결됩니다.\n기존 Xilinx FPGA Device Plugin에서는 단순하게 \u0026ldquo;현재 노드에 IDLE 디바이스의 개수가 현재 pod이 요청하는 디바이스 개수보다 많은가?\u0026rdquo; 의 정보만 전달할 수 있기 때문에 스케줄러는 이를 기준으로 pod이 할당될 노드를 선택하게 됩니다. 이때 device topology를 고려하지 않고 할당해준다면, 연결성 문제가 발생할 수 있습니다.\n예시와 함께 살펴보겠습니다. Pod이 요청하는 오리온 서버 내부 LPU 개수가 4개라고 가정해보겠습니다. 디바이스 할당 요청이 오면 Device Plugin은 Kubelet에게 IDLE한 디바이스 목록을 전달하고, Kubelet에서는 이를 기반으로 랜덤하게 디바이스를 선택 하게 됩니다.\n이러한 상황에서 위 예시처럼 연결성이 고려되지 않고 디바이스가 선택된다면,\n4개의 LPU가 서로 연결되어 있지 않기 때문에 분산 추론과 같은 동작이 어렵습니다. (Parallel 통신 및 LPU 간 activation 동기화 불가)\n향후에 4개의 LPU를 가진 pod이 스케줄링을 요청하는 상황이 발생하는 경우, 똑같은 문제가 발생합니다. (IDLE 디바이스 개수는 만족되어 스케줄링되지만, 디바이스 간 연결성이 없음)\n이렇게 된다면 물론 여러 LPU를 활용하는 분산 작업이 어려울 뿐만 아니라 오리온 서버 내부에 자원 파편화가 발생하기 때문에 서버 차원에서 utilization이 감소하게 됩니다.\n이러한 한계점으로 인해 오리온 서버를 활용한 내부 개발 및 테스트 환경과 외부 PoC 환경에서는 LPU를 1개 혹은 전부 할당해주는 방법만 적용할 수 있었습니다. 이렇듯 1 or ALL 방식으로 할당하게 되면, Kubernetes 환경 위에서 멀티 디바이스로 개발 혹은 테스트가 필요한 상황에서 오리온 서버 하나에서 개발자 여러 명이 작업하기 어려운 상황에 봉착하게 됩니다. 해당 문제를 극복하여 Kubernetes 기반 개발 환경에서 보다 유연한 디바이스 활용을 위해 자체적으로 Orion Device Plugin을 개발 하였습니다.\nOrion Device Plugin Orion Device Plugin은 기존 Xilinx Device Plugin의 기능에 Topology-Aware 할당 기능 을 추가한 컴포넌트입니다.\n사내에서 개발한 HyperDex-Toolchain을 활용하면 오리온 서버 내 LPU의 연결성을 보여주는 network table 을 추출할 수 있습니다. Pod에서 요청한 LPU의 개수와 network table에서 추출한 오리온 서버의 IDLE 상태인 LPU의 연결성을 기반으로 최적의 디바이스 할당 조합을 결정합니다. Device Plugin에서 앞서 설명한 GetPreferredAllocation 함수를 통해 해당 목록을 Kubelet으로 전달하면, Kubelet은 이를 기반으로 Pod에게 LPU를 할당합니다.\n개발한 컴포넌트를 활용해서 현재 아래와 같은 경로에서 오리온 서버를 다양하게 사용하고 있습니다.\nKubernetes 기반 사내 개발 환경에서 FPGA 개발자에게 완전 격리된 오리온 서버 내부 LPU를 제공합니다. 즉, 오리온 서버 하나에서 여러 명의 개발자가 디바이스 간섭 없이 동시에 작업 할 수 있습니다.\n오리온 서버를 기반으로 실행되는 하이퍼엑셀 Chat Demo 시에 여러 모델을 같은 오리온 서버에서 동시에 서빙할 수 있습니다.\n고객사 PoC를 진행할 때, 만약 Kubernetes 환경 위에서 테스트 해보고 싶은 니즈가 있다면 Device Plugin을 함께 제공합니다.\nBertha Device Plugin 하이퍼엑셀의 차세대 ASIC chip인 Bertha가 곧 시장에 공개될 예정입니다!\nBertha는 완전히 새로운 하이퍼엑셀의 독자적인 ASIC chip이기 때문에 Kubernetes 환경에서 활용하기 위해서는 Device Plugin을 비롯한 NFD, Metric Exporter와 같은 컴포넌트들이 모두 포함된 Bertha Operator의 개발이 필요합니다. 현재 Bertha를 위한 Cloud-Native Software Stack에 대해 ML팀 김남윤(Author, LinkedIn)님 과 함께 개발을 진행하고 있습니다.\nDRA in Kubernetes 지금까지 Kubernetes에서 새로운 디바이스를 활용하기 위해 꼭 필요한 컴포넌트인 Device Plugin에 대해 소개하고, 현재 하이퍼엑셀 개발 환경에서 이를 어떻게 활용하고 있는지 살펴보았습니다. 하지만, Device Plugin에도 일부 한계점이 존재합니다.\nKubernetes Device Plugin의 한계점 Device Plugin을 통한 하드웨어 관리는 다음과 같은 한계점이 있습니다.\n정적 할당: 리소스 할당 방식이 단순히 요청하는 디바이스의 개수 기반입니다.\n복잡한 설정 부족: 하드웨어의 세부 설정(예: GPU 분할, 메모리 대역폭 설정 등)을 pod 요청 시점에 동적으로 반영하기 어렵습니다.\n리소스 공유의 어려움: 여러 pod이 하나의 자원을 유연하게 나누어서 사용하는 시나리오 구현이 복잡합니다.\nDRA(Dynamic Resource Allocation) 기존 Device Plugin 한계점을 극복하고 GPU, FPGA와 같은 커스텀 하드웨어 자원을 기존보다 훨씬 유연하고 세밀하게 관리하기 위해 새로 도입된 프레임워크인 Kubernetes DRA가 활발하게 활용되고 있습니다.\nDRA는 마치 스토리지(PVC/PV)를 사용하는 것과 유사한 방식으로 하드웨어 자원을 요청하고 할당받을 수 있게 설계 되었습니다. 쉽게 말해, 과거에는 \u0026ldquo;LPU 1개 주세요\u0026rdquo; 라고만 할 수 있었다면, DRA를 통해서는 \u0026ldquo;특정 모델 추론에 최적화된 설정의 LPU를 동적으로 할당해주세요\u0026rdquo; 와 같은 훨씬 복잡한 요청을 할 수 있게 된 것입니다.\nDRA의 핵심 구성 요소 DRA는 리소스를 정의하고 요청하는 방식을 자원 할당(Allocation) 과 사용(Usage) 으로 명확히 분리합니다.\n구성 요소 설명 ResourceClaim 사용자가 필요한 자원(예: \u0026ldquo;16GB 이상의 GPU 1개\u0026rdquo;)을 정의하고 요청하는 객체 (PVC와 유사) ResourceClass 자원의 종류와 이를 처리할 드라이버를 정의 (StorageClass와 유사) ResourceSlice 각 노드에 실제 존재하는 디바이스의 세부 정보(모델, 용량, 상태 등)를 담고 있는 데이터 단위 DRA Driver 특정 하드웨어 Vendor가 제공하는 플러그인으로, 실제 하드웨어 준비 및 할당을 담당 Device Plugin vs DRA 특징 Device Plugin DRA 리소스 모델 정수 기반 (예: hyperaccel.ai/lpu: 1) 객체 기반 (ResourceClaim) 파라미터 전달 매우 제한적 (Annotation 활용 등) 매우 자유로움 (Custom 파라미터 지원) 스케줄링 단순 개수 체크 복잡한 제약 조건 반영 가능 라이프사이클 Pod 실행 시점에 고정 Pod와 독립적으로 할당/해제 가능 2025년 하반기 출시된 Kubernetes v1.34를 기점으로 DRA의 주요 기능들이 정식 버전(GA, General Availability)으로 전환되었습니다. 이에 따라 최신 클라우드 환경(GKE, EKS 등)이나 온프레미스 AI 클러스터에서 NVIDIA GPU 등의 가속기 관리를 위해 표준적으로 채택되고 있는 추세입니다.\n하이퍼엑셀에서도 이에 발 맞추어 Kubernetes 환경에서 DRA를 활용한 Bertha의 사용을 지원할 수 있도록 준비하고 있습니다!\n정리하자면\u0026hellip; 이번 글에서는 Kubernetes 기반 개발 환경 구축기 시리즈 중 3번째 내용인 Kubernetes Device Plugin이 무엇인지, CDI는 어떤 기술인지, 하이퍼엑셀의 LPU를 Kubernetes 환경에서 활용하기 위한 Device Plugin의 개발 과정, 그리고 보다 유연하게 자원을 할당하는 기술인 DRA에 대해 소개드렸습니다.\n시장 경쟁력이 있는 LPU를 위해서는 HW 레벨에서 잘 설계하는 것도 중요하지만, 최적화된 SW 스택이 반드시 동반되어야 합니다. 가장 보편적으로 사용되고 있는 Kubernetes 환경 위에서 LPU의 원활한 사용을 지원하는 것은 chip 성공의 중요한 과제입니다!\n저희 ML팀의 DevOps 파트에서는 하이퍼엑셀 LPU의 잠재적인 고객분들을 위한 Cloud-Native Toolkit 소프트웨어를 개발하고 있습니다. 이러한 소프트웨어의 기반이 되는 Device Plugin, DRA와 같은 컴포넌트를 통해 컴퓨팅 노드 내부에서 원활하게 LPU를 사용할 수 있게 됩니다.\n끝까지 읽어주셔서 감사합니다!\n추신: HyperAccel은 채용 중입니다! HyperAccel은 LLM 가속 ASIC 칩 출시를 위해 모든 구성원들이 열심히 달리고 있습니다! HW, SW뿐만 아니라 추론 AI 기술을 전체적으로 다루는 회사로, 모든 방면에 걸쳐 뛰어난 인재들이 함께 일하고 있습니다. 멋진 동료들과 같이 일하며 한 분야에 국한된 것이 아닌 폭넓은 지식을, 심지어 깊게 배우며 지식을 공유하고 빠른 속도로 함께 성장하고 있습니다!\n저희 ML팀의 DevOps 파트 는 사내 개발자들의 생산성 증대를 위한 개발 환경 제공 및 관리 업무와 함께 LPU chip의 클라우드 레벨 활용을 효과적으로 지원하기 위한 Cloud-Native Toolkit을 개발하고 있습니다.\nHyperAccel에서 다루는 기술들을 보시고, 관심이 있으시다면 HyperAccel Career를 통해 지원해 주세요!\nReference Kubernetes 1.26: Device Manager graduates to GA CDI - Container Device Interface containerd CRI Plugin Configuration NVIDIA Device Plugin AMD Xilinx Device Plugin Dynamic Resource Allocation ","permalink":"https://hyper-accel.github.io/posts/k8s-device-plugin/","summary":"\u003ch1 id=\"kubernetes-기반-사내-개발-환경-구축기-3편-lpu를-위한-kubernetes-device-plugin\"\u003eKubernetes 기반 사내 개발 환경 구축기 3편: LPU를 위한 Kubernetes Device Plugin\u003c/h1\u003e\n\u003cp\u003e안녕하세요! 저는 HyperAccel ML팀에서 DevOps Engineer로 근무하고 있는 전영훈입니다.\u003c/p\u003e\n\u003cp\u003e이번 포스팅은 \u003cstrong\u003eKubernetes 기반 사내 개발 환경 구축기\u003c/strong\u003e 시리즈의 3번째 글입니다!\u003c/p\u003e\n\u003cp\u003e1편에서는 Kubernetes를 기반으로 하는 개발 환경 구축의 배경과 전체적인 설계 및 방향에 대해서 살펴보았고, 2편에서는 기존 Self-Hosted Runner의 구조적인 한계를 뛰어넘기 위한 ARC 기반 CI/CD 인프라 설계 전략 수립 및 구축 과정에 대해 소개하였습니다. 3번째 글에서는 \u003cstrong\u003eKubernetes 환경 위에서 Custom Resource 활용 시에 필요한 Device Plugin\u003c/strong\u003e 에 관련된 내용을 전달하고자 합니다.\u003c/p\u003e","title":"Kubernetes 기반 사내 개발 환경 구축기 3편: LPU를 위한 Kubernetes Device Plugin"},{"content":"AITER 분석: AMD가 ROCm inference 성능을 2배로 올린 방법 안녕하세요? HyperAccel ML팀 소속 박민호입니다.\nSemi Analysis 는 반도체 업계에서 유명한 리서치 기관입니다. 이 기관은 주요 GPU 의 inference 성능을 실측 비교하는 InferenceX 벤치마크를 운영하고 있습니다.\n2026년 2월에 공개된 InferenceX v2 보고서에 따르면, AMD MI300X 의 SGLang throughput 성능이 2025년 12월에서 2026년 1월 사이 거의 2배 가까이 향상되었다고 합니다. 이 성능 향상의 중심에 AI Tensor Engine for ROCm(AITER) 이라는 커널 라이브러리가 있었습니다.\n저는 이 소식을 접하고 궁금해졌습니다. 도대체 AITER 가 뭐길래, 소프트웨어 최적화만으로 하드웨어의 성능을 2배나 끌어올릴 수 있었을까? 이번 포스트에서는 AITER 의 아키텍처, 커널 백엔드 전략, 그리고 성능 향상의 원리를 정리해 봤습니다. 아래 목록에 해당되는 분들께 도움이 될 것 같습니다:\nAMD GPU 의 inference 성능 현황이 궁금하신 분 GPU 커널 최적화 기법에 관심이 있으신 분 NVIDIA 외의 AI 가속기 생태계가 궁금하신 분 AITER란 무엇인가? AI Tensor Engine for ROCm(AITER) 는 AMD 가 공개한 고성능 AI operator 통합 저장소입니다. 한 마디로 요약하면 AMD GPU 에서 AI 워크로드를 가속하기 위한 커널 모음집 입니다. NVIDIA 생태계에서 cuDNN 이 하는 역할을 ROCm 생태계에서 AITER 가 수행한다고 보면 됩니다.\n항목 내용 저장소 ROCm/aiter 라이선스 MIT 언어 구성 Python (63.6%), CUDA/HIP (25.8%), C++ (9.7%) 지원 GPU AMD Instinct MI300X, MI325X, MI350 Inference Framework vLLM, SGLang AITER 의 핵심 가치는 드롭인 교체 에 있습니다. vLLM 이나 SGLang 같은 inference framework에서 환경 변수 하나만 켜면 기존 operator가 AITER 의 최적화된 커널로 자동 교체됩니다. 코드 수정 없이 성능 향상을 얻을 수 있다는 뜻입니다.\n어떤 operation을 지원하는가? AITER 는 Large Language Model(LLM) inference 의 핵심 operation을 폭넓게 지원합니다.\n카테고리 operation 백엔드 Attention Flash Attention, Multi-head Latent Attention(MLA), Paged Attention CK, ASM, Triton Fused MoE Top-K routing, MoE sorting, BlockScale FP8 FFN HIP, CK, ASM GEMM FP8 per-token/channel, block-scale FP8, INT8, pre-shuffle CK, ASM Normalization RMSNorm, LayerNorm (fused quantization 포함) Triton, CK Embedding Rotary Position Embedding(RoPE) forward/backward Triton Quantization BF16/FP16 → FP8/INT4 변환 CK, Triton Communication AllReduce, reduce-scatter, all-gather Triton, HIP 여기서 눈에 띄는 것은 백엔드 열입니다. 하나의 operation에도 CK, ASM, Triton 등 여러 백엔드가 병기되어 있습니다. 이것이 AITER 의 핵심 설계 철학인 멀티 백엔드 전략 입니다. 이에 대해서는 뒤에서 자세히 다루겠습니다.\n성능 벤치마크: 숫자로 보는 AITER 백문이 불여일견이라고 하죠. AITER 가 MI300X 에서 달성한 성능 향상 수치를 먼저 보겠습니다.\n커널/워크로드 Throughput 향상 Block-scale General Matrix Multiplication(GEMM) 2배 Block-scale Fused Mixture of Experts(MoE) 3배 MLA Decode 17배 Multi-Head Attention(MHA) Prefill 14배 DeepSeek V3/R1 throughput (SGLang 기준) 2배 (6,485 → 13,704 tok/s) DeepSeek R1 prefill latency ↓52% (3.13s → 1.51s) DeepSeek R1 decode latency ↓47% (0.053s → 0.028s) NVIDIA H200 대비 (DeepSeek R1) 동일 latency에서 2-5배 높은 throughput MLA Decode 17배, MHA Prefill 14배는 단순한 튜닝으로 나올 수 있는 수치가 아닙니다. AITER 가 어셈블리 수준까지 내려가서 커널을 직접 작성했기 때문에 가능한 결과입니다.\n아키텍처 구조 상위 레벨 아키텍처 AITER 의 아키텍처는 크게 5개 계층으로 구성됩니다.\n사용자 API: Python(torch 호환) 및 C++ API 상위 레벨 operator: tuned_gemm.py, fused_moe.py, mla.py 등 operator 오케스트레이터 operator 래퍼: @compile_ops 데코레이터 기반의 operator 래핑 계층 JIT 컴파일: 첫 호출 시 커널을 컴파일하고 .so 파일로 캐시 커널 백엔드: Triton, Composable Kernel(CK), HIP, ASM 4가지 백엔드 사용자 입장에서는 import aiter 로 PyTorch 호환 함수를 호출하면 됩니다. 나머지는 AITER 가 알아서 최적의 커널을 선택하고, 컴파일하고, 캐싱합니다.\nJIT 컴파일 파이프라인 AITER 의 모든 operator는 @compile_ops 데코레이터 패턴을 따릅니다.\n@compile_ops(\u0026#34;module_gemm_a8w8\u0026#34;, fc_name=\u0026#34;gemm_a8w8\u0026#34;, gen_func=cmdGenFunc, gen_fake=fake_shape_fn) def gemm_a8w8(XQ, WQ, x_scale, w_scale, Out): ... # 본문은 실행되지 않음 — 런타임에 컴파일된 C++로 대체 이 패턴의 동작 원리는 다음과 같습니다.\nPython 코드에서 데코레이터 함수를 호출합니다 모듈 캐시에서 이미 컴파일된 .so 파일이 있는지 확인합니다 없으면 optCompilerConfig.json 에서 모듈 설정을 로드합니다 hipcc 로 컴파일하고 Ninja 빌드 시스템으로 .so 를 생성합니다 importlib.import_module() 로 로드하여 캐시에 저장합니다 이후 호출에서는 캐시된 커널을 바로 사용합니다 첫 실행 시에만 컴파일 비용이 발생하고, 이후에는 네이티브 수준의 성능을 얻습니다. 84개의 컴파일 모듈이 이 방식으로 관리됩니다.\n4가지 커널 백엔드 AITER 의 특징은 하나의 커널 언어를 고집하지 않는다 는 점입니다. operator 특성에 따라 4가지 백엔드를 골라 씁니다.\nTriton Triton 은 OpenAI 가 개발하고 AMD 가 ROCm 용으로 포팅한 Python 기반 GPU 프로그래밍 Domain-Specific Language(DSL) 입니다. 블록 단위 프로그래밍 모델로, 개발자가 타일 수준에서 알고리즘을 작성하면 컴파일러가 자동으로 최적화합니다.\nAITER 에서 가장 많은 커널(100개 이상) 이 Triton 으로 작성되었습니다. RMSNorm, RoPE, quantization, MoE sorting 등 유틸리티성 operation에 주로 사용됩니다.\n# Triton RMSNorm 커널 예시 @triton.jit def _rms_norm_fwd_kernel( X_ptr, W_ptr, Out_ptr, stride_x_row, N, eps, BLOCK_N: tl.constexpr, ): row_idx = tl.program_id(0) # 각 프로그램이 하나의 행 처리 cols = tl.arange(0, BLOCK_N) mask = cols \u0026lt; N x = tl.load(X_ptr + row_idx * stride_x_row + cols, mask=mask, other=0.0) x_sq = x * x mean_sq = tl.sum(x_sq, axis=0) / N rrms = tl.rsqrt(mean_sq + eps) # reciprocal square root w = tl.load(W_ptr + cols, mask=mask) out = x * rrms * w tl.store(Out_ptr + row_idx * stride_x_row + cols, out, mask=mask) Triton 의 강점은 개발 속도입니다. Python 문법으로 GPU 커널을 작성할 수 있고, 메모리 coalescing 이나 shared memory 관리를 컴파일러가 자동 처리합니다. 반면 컴파일러의 한계로 이론 대역폭의 95% 이상에 도달하기는 어렵습니다.\nComposable Kernel(CK) CK 는 AMD 가 개발한 C++ 템플릿 기반 고성능 커널 라이브러리입니다. NVIDIA 의 CUTLASS 와 유사한 위치에 있습니다. \u0026ldquo;조합 가능한 커널\u0026rdquo; 이라는 이름처럼, 재사용 가능한 타일 operation 빌딩 블록을 조합하여 복잡한 operator를 만듭니다.\nCK 의 핵심은 operation fusion 입니다. 예를 들어 GEMM 결과에 스케일링을 별도 커널 없이 인라인으로 fusion할 수 있습니다.\n// GEMM 결과에 dequantization를 인라인으로 fusion template \u0026lt;typename AccDataType, typename DDataType, typename EDataType\u0026gt; struct RowwiseScale { __host__ __device__ constexpr void operator()( EDataType \u0026amp;e, const AccDataType \u0026amp;c, const DDataType \u0026amp;d0, // weight 스케일 const DDataType \u0026amp;d1 // activation scale ) const { const F32 x = ck::type_convert\u0026lt;F32\u0026gt;(c) * ck::type_convert\u0026lt;F32\u0026gt;(d0) * ck::type_convert\u0026lt;F32\u0026gt;(d1); e = ck::type_convert\u0026lt;EDataType\u0026gt;(x); } }; // → GEMM 계산 + dequantization가 하나의 커널에서 수행됩니다 AITER 에서는 GEMM(A8W8, A4W4, block-scale), MoE 2-stage, 일부 Attention 등 matrix operation 중심 커널에 CK 를 사용합니다. M, N, K 형상에 따라 100개 이상의 pre-tuned된 인스턴스 중 최적의 것을 선택하는 휴리스틱 디스패치도 구현되어 있습니다.\nHIP Heterogeneous-computing Interface for Portability(HIP) 는 AMD 의 C++ 런타임 API 이자 커널 언어입니다. CUDA 의 AMD 대응물로, 대부분의 CUDA 커널 코드가 이름만 바꾸면 HIP 에서 동작합니다.\nCUDA 개념 → HIP 대응물 ───────────────────────────────────────── cudaMalloc() → hipMalloc() cudaMemcpy() → hipMemcpy() __global__ void kernel → __global__ void kernel (동일!) __shared__ → __shared__ (동일!) cudaStream_t → hipStream_t nvcc → hipcc AITER 에서는 Paged Attention, KV 캐시, TopK, AllReduce 등 general-purpose operation에 HIP 를 사용합니다. csrc/kernels/ 디렉토리에 34개의 .cu 파일이 이 방식으로 작성되어 있습니다.\nAssembly(ASM) ASM 백엔드는 AMD GPU 의 machine code인 AMDGCN Instruction Set Architecture(ISA) 로 직접 작성된 커널입니다. 컴파일러의 모든 추상화를 우회하고 GPU 레지스터, instruction scheduling, 메모리 접근 패턴을 개발자가 100% 제어합니다.\n왜 여기까지 내려가야 할까요? 고수준 컴파일러는 안전한 코드를 생성하는 대신 최적화 기회를 놓칩니다. ASM 은 GPU 의 Matrix Fused Multiply-Add(MFMA) instruction, 특수 레지스터, instruction pipelining을 100% 활용할 수 있습니다. 그 결과가 MLA Decode 17배, MHA Prefill 14배 향상입니다.\n레지스터 타입: SGPR (Scalar GPR) — control flow, constant (모든 스레드 공유) VGPR (Vector GPR) — 데이터 operation (각 스레드별 독립 값) AccVGPR — MFMA accumulator (matrix multiplication 결과 저장) 핵심 instruction: v_mfma_f32_32x32x8_f16 — 32×32 matrix multiplication (FP16→FP32) v_mfma_f32_16x16x32_fp8 — 16×16 matrix multiplication (FP8→FP32) buffer_load_dwordx4 — Global 메모리에서 128비트 로드 ds_read_b128 — LDS에서 128비트 로드 AITER 의 hsa/ 디렉토리에는 354개 이상의 사전 컴파일된 ASM 커널(.co 파일) 이 있습니다. 이렇게 많은 인스턴스가 필요한 이유는 ASM 커널은 컴파일 타임에 모든 파라미터가 고정되기 때문입니다. 런타임 분기 없이 모든 가능한 조합을 사전 컴파일합니다.\nhead_dim: {64, 128, 256} → 3가지 dtype: {fp16, bf16, fp8} → 3가지 causal: {true, false} → 2가지 → 조합 폭발 → 162개+ FMHA 인스턴스 백엔드 선택 기준 AITER 가 각 operation에 특정 백엔드를 선택하는 기준을 정리하면 다음과 같습니다.\n기준 Triton CK HIP ASM 개발 속도 ★★★★★ ★★☆☆☆ ★★★☆☆ ★☆☆☆☆ 최대 성능 ★★★☆☆ ★★★★☆ ★★★☆☆ ★★★★★ 이식성 ★★★★★ ★★★☆☆ ★★★★☆ ★☆☆☆☆ 유지보수 ★★★★★ ★★★☆☆ ★★★★☆ ★☆☆☆☆ 커널 수 100+ ~20 34 354+ (.co) \u0026ldquo;그러면 다 ASM 으로 짜면 되지 않나?\u0026rdquo; 라고 생각할 수 있는데, ASM 은 개발 난이도가 매우 높고 GPU 아키텍처가 바뀌면 처음부터 다시 작성해야 합니다. AITER 는 성능이 가장 중요한 핫 패스에만 ASM 을 쓰고, 나머지는 Triton 이나 CK 로 개발 효율을 확보합니다.\nFramework Integration: 환경 변수 하나로 활성화 AITER 는 기존 코드를 건드리지 않고 통합할 수 있습니다. 환경 변수만 설정하면 됩니다.\n# Enable AITER in vLLM VLLM_USE_AITER_MOE=1 VLLM_USE_AITER_BLOCK_GEMM=1 \\ vllm serve deepseek-ai/DeepSeek-V3 --tensor-parallel-size 8 # Enable AITER in SGLang CK_BLOCK_GEMM=1 SGLANG_ROCM_AITER_BLOCK_MOE=1 \\ python3 -m sglang.launch_server --model deepseek-ai/DeepSeek-V3 --tp 8 프레임워크가 환경 변수를 확인하고 조건부로 AITER operator로 디스패치합니다. 덕분에 A/B 테스트도 간단합니다. 환경 변수를 켜고 끄는 것만으로 AITER 적용 전후 성능을 비교할 수 있습니다.\n첫 실행 시에는 JIT 컴파일이 트리거되어 ~/.cache/aiter/ 에 .so 파일이 생성됩니다. 이후 실행에서는 캐시된 커널을 재사용하므로 추가 비용이 없습니다.\n핵심 설계 패턴 정리 AITER 를 살펴보면서 눈에 띄었던 설계 패턴들을 정리합니다.\n멀티 백엔드 커널 디스패치 하나의 커널 언어를 고집하지 않습니다. decode attention 에는 ASM, GEMM 에는 CK, MoE sorting 에는 Triton 을 사용합니다. unified compiler 전략과는 다른 접근입니다.\nFP8 Block-scale Quantization 토큰별 (1x128) activation scale + weight별 (128x128) 스케일로 효율적인 mixed precision operation을 가능하게 합니다. 특히 DeepSeek 과 같은 MoE 아키텍처에서 큰 효과를 발휘합니다.\nCSV 기반 auto-tuning 커널 파라미터가 (M, N, K, cu_num) 형상별로 CSV 파일에 저장됩니다. 재컴파일 없이 모델별 튜닝이 가능합니다. DeepSeek V3, Qwen3, LLaMA 405B 등 21개 모델 설정이 pre-tuned되어 있습니다.\n하드웨어 특화 최적화 MI300X 인터 GPU 토폴로지에 특화된 커스텀 AllReduce, 최적 메모리 접근 패턴을 위한 weight pre-shuffling(16x16 레이아웃) 등 하드웨어 수준의 최적화가 포함되어 있습니다.\n결론 AITER 는 AMD 가 NVIDIA 와의 AI inference 성능 격차를 줄이기 위해 만든 커널 라이브러리입니다. 단일 커널 언어에 의존하지 않고 Triton, CK, HIP, ASM 4가지 백엔드를 operator별로 골라 쓰는 구조가 특징입니다.\nSemi Analysis 의 InferenceX v2 보고서에서도 언급되었듯이, AITER 의 최적화는 MI300X 의 SGLang 성능을 거의 2배로 끌어올렸습니다. 다만 Semi Analysis 가 지적한 것처럼, 개별 커널 성능은 뛰어나지만 FP4, disaggregated serving, expert parallelism 등 여러 최적화를 동시에 조합 했을 때의 성능(composability)은 아직 NVIDIA 대비 부족한 부분이 있습니다.\n그래도 AITER 가 보여준 것은 분명합니다. 소프트웨어 최적화만으로 같은 하드웨어에서 2배 성능을 뽑아낼 수 있다는 사실입니다. NPU 를 개발하고 있는 저희 입장에서도, 하드웨어의 이론적 성능을 실제 성능으로 전환하는 것이 얼마나 중요한지 다시 한번 느끼게 되었습니다.\n참고 자료 GitHub: ROCm/aiter Semi Analysis: InferenceX v2 — NVIDIA Blackwell Vs AMD vs Hopper Semi Analysis: AMD 2.0 — New Sense of Urgency AMD 블로그: AITER — AI Tensor Engine For ROCm AMD 블로그: Accelerate DeepSeek-R1 with AITER + SGLang 추신 HyperAccel 채용 안내 AITER 를 분석하면서 커널 레벨 최적화가 얼마나 큰 차이를 만드는지 체감했습니다. NPU 회사인 저희도 하드웨어 성능을 제대로 끌어내는 소프트웨어 스택을 만들어가고 있습니다. LPU 의 ASIC 출시를 앞두고, 커널 최적화부터 inference framework integration까지 함께할 팀원을 기다리고 있습니다.\n채용 사이트: https://hyperaccel.career.greetinghr.com/ko/guide\n혹시 관심이 있으시다면 언제든지 연락 주세요!\n","permalink":"https://hyper-accel.github.io/posts/rocm-aiter/","summary":"AMD GPU의 inference 성능을 끌어올린 AITER(AI Tensor Engine for ROCm)를 분석합니다.","title":"AITER 분석: AMD가 ROCm inference 성능을 2배로 올린 방법"},{"content":"안녕하세요? HyperAccel ML팀 소속 박현준입니다. 2022년 11월 ChatGPT가 출시된 이래 AI 기술들이 기하급수적으로 빠르게 발전하며 하루가 멀다하고 새로운 AI tools가 출시되고 있습니다.\n하드웨어에는 반도체 칩의 집적도가 2년마다 2배씩 증가한다는 무어의 법칙이 있다면, 최근에는 LLM의 자율 작업 수행 능력이 7개월마다 2배씩 증가한다는 연구 결과가 발표되고 있습니다. 초기 서비스가 이순신의 스마트폰에 대해 장황하게 설명하여 비웃음을 샀다면, 최근 서비스는 자연어는 물론이고 사진, 동영상, 오디오 등 거의 모든 입력을 높은 완성도로 처리해내고 있습니다. 이러한 기술 개발의 중심에 있는 아키텍처가 Transformer 입니다.\n어떤 도구라도 잘 쓰기 위해서는 도구가 어떻게 생겼는지 자세하게 알아야 한다고 생각합니다. 따라서 이번 글에서는 Transformer 연산이 어떤 배경에서 등장하게 되었는지 먼저 알아봅니다. 그다음으로 연산이 어떻게 생겼는지 이해하고, 마지막으로 연산의 병목과 이를 해결하기 위한 기초적인 최적화 기법 몇 가지를 살펴보겠습니다.\nPart 1: 등장 배경 세상을 바꾼 아키텍처, Transformer 2017년 Google 연구팀은 \u0026ldquo;Attention Is All You Need\u0026rdquo; 라는 논문을 발표하였습니다. 해당 논문은 문장을 한꺼번에 행렬로 처리하는 방식으로 기존 모델인 RNN/LSTM에 있었던 속도 한계를 해결하였을 뿐만 아니라 인간이 시퀀스를 이해하는 방법을 모방한 \u0026ldquo;Attention\u0026quot;이라는 기법으로 성능도 크게 향상시켰습니다. 요즘 핫한 Gemini , ChatGPT 를 비롯한 오늘날 대부분의 LLM이 이 논문에서 제시한 Transformer 구조를 기반으로 하고 있습니다.\nLLM이 하는 일: 다음 단어 예측 Large Language Model(LLM) 의 동작 방식을 수학적으로 표현하면 \u0026ldquo;주어진 텍스트에 이어질 다음 단어를 예측하는 정교한 수학 함수\u0026quot;입니다. 단, 한 단어를 확정적으로 고르는 것이 아니라, 가능한 모든 다음 단어에 확률 을 부여합니다. 그 확률 분포에서 매번 하나를 샘플링하기 때문에, 같은 질문을 해도 실행할 때마다 다른 답이 나올 수 있습니다. 학습은 엄청난 양의 텍스트를 처리하면서 이 예측을 점점 정확하게 만드는 과정입니다. 실 사용에서 LLM은 \u0026ldquo;어떤 문장이든 넣으면 그다음에 올 단어를 그럴듯하게 예측해 주는 마법의 기계\u0026quot;입니다. 사람이 LLM에게 짧은 영화 대본을 물어보는 장면으로 예시를 들어보겠습니다. 사용자는 LLM에게 대본을 입력하면, 이 마법의 기계는 예측된 단어를 이어 붙이고, 다시 넣는 과정을 반복해 대본을 완성합니다. 이것이 바로 우리가 채팅봇과 대화할 때 실제로 일어나는 일입니다.\nPart 2: Transformer 기본 구조 쪼개보기 전체 구조 개관 모델마다 세부 사항은 다르지만, 이번 글에서는 가장 간단한 모델인 GPT-2를 기준으로 작성하겠습니다. Transformer는 크게 Token Embedding, Decoder Block, LM Head 세 단계로 나눌 수 있으며, 이때 Decoder Block은 일반적으로 동일한 n개(GPT-2의 경우 24개)의 블록이 쌓여 있습니다. 하나의 블록은 또 다음과 같이 여섯 단계로 나눌 수 있습니다. 이를 그림으로 표현하면 다음과 같습니다.\nToken \u0026amp; Positional Embedding Transformer의 첫 단계는 사람의 언어를 컴퓨터가 이해할 수 있는 언어로 바꾸는 것입니다. 이를 Token Embedding 이라고 부르며, 각 토큰(token) 을 긴 숫자 리스트, 즉 벡터로 바꿉니다. (실제로는 한 단어가 한 토큰으로 1:1 대응되지는 않습니다만, 이해의 편의를 위해 1:1 대응된다고 가정하겠습니다.) 이렇게 변환을 하게 되면 각 단어가 긴 숫자 리스트로 변환되고, 이를 벡터라고 부르며, 이 벡터가 대응되는 단어의 의미를 갖게 됩니다. 같은 단어라도 문장 안에서 어디에 있느냐에 따라 의미가 달라지기 때문에 Positional Embedding 이라는 작업도 수행합니다.\n여기서도 역시 GPT-2 Medium의 예시를 보겠습니다. 이 모델이 인식할 수 있는 토큰의 갯수(Vocab size)는 50,287개이고, 각 토큰은 크기가 1024인 벡터(embedding dimension)로 인코딩 됩니다. (이를 우리는 1024차원이라고도 부릅니다.) 이 역할을 수행하는 Word Token Embedding Table(WTE) 는 크기가 [50287, 1024]로, 각 토큰을 1,024차원 벡터로 매핑합니다.\nWord Positional Embedding Table(WPE) 는 [1024, 1024]로 시퀀스 내 해당 단어의 위치를 1,024차원 벡터로 매핑합니다. 토큰 ID 시퀀스를 WTE에 넣어 [seq_len, 1024]를 얻고, 위치 인덱스를 WPE에 넣어 [seq_len, 1024]를 얻은 뒤, 두 행렬을 더하면 Decoder Block으로 들어갈 준비가 끝이 납니다.\nLayer Normalization Layer Normalization(LayerNorm) 은 Decoder Block의 첫 단계로, 각 토큰마다 평균과 분산을 맞춰 주는 정규화입니다. 저희가 중고등학교 수학시간에 배웠던 정규화(Normalization)와 같은 개념입니다. 입력 분포가 레이어마다 크게 달라지면 학습이 불안정해지고, 기울기 폭주나 소실이 생기기 쉽기 때문에 LayerNorm을 통해 각 위치의 벡터를 \u0026ldquo;적당한 스케일과 분포\u0026quot;로 맞춰 학습을 안정시키고, 깊은 네트워크에서도 층을 많이 쌓을 수 있게 합니다.\nSelf-Attention: Query, Key, Value의 의미 Attention이 해결하는 문제: 문맥에 따른 의미 결정 tower 로 예시를 들어보겠습니다. 처음에는 임베딩을 수행하면 \u0026ldquo;높은 구조물\u0026quot;이라는 일반적인 의미 방향으로 1024차원의 벡터가 생성됩니다. 이때 바로 앞에 Eiffel 이 오면, 그 벡터가 tower 쪽으로 정보를 보내 \u0026ldquo;에펠 탑\u0026quot;에 가까운 방향으로 갱신됩니다. 앞에 miniature 까지 있으면 \u0026ldquo;큰 것\u0026quot;과의 연관이 줄어들고 더 구체적인 의미로 바뀝니다. 한 토큰에서 다른 토큰으로의 정보 전달은 단어 하나를 넘어 긴 거리, 풍부한 문맥까지 포함할 수 있습니다. 추리 소설 끝부분 \u0026ldquo;Therefore the murderer was\u0026hellip;\u0026ldquo;에서 다음 단어를 맞추려면, 마지막 벡터 was 가 앞선 전체 문맥의 정보를 흡수해야 합니다. Attention이 바로 그 \u0026ldquo;어떤 토큰이 어떤 토큰을 얼마나 참조할지\u0026quot;를 계산합니다.\nQ, K, V 생성과 직관적 의미 GPT-2 Medium의 입력토큰은 1024개를 넘을 수 없습니다. 각 토큰은 크기가 1024인 벡터로 변환되므로, 해당 모델의 Attention Input은 최대 [1024, 1024](=[seq_len, N_embed])가 됩니다. 여기에 서로 다른 가중치 행렬 W_Q, W_K, W_V를 곱해 Query(Q) , Key(K) , Value(V) 라는 행렬을 만듭니다. 임베딩 차원(N_embed=1024)은 헤드 수(N_head=16)와 헤드당 차원(head_dim=64)로 나눠져 최종적으로 Q·K·V 행렬은 각각 [seq_len, N_head, head_dim] 형태가 됩니다.\n직관을 위해 \u0026ldquo;Hello, my name is ____\u0026rdquo; 라는 문장에서 마지막 빈칸을 예측하는 상황을 생각해 보겠습니다. Part 1에서 LLM은 다음 단어를 예측하는 기계라고 했습니다. 빈칸을 채우려면 마지막 위치의 토큰 is 가 앞선 단어들의 정보를 끌어모아야 합니다. 이때 Q, K, V가 각각 다음 역할을 합니다.\nQuery(Q) — is가 던지는 질문입니다. \u0026ldquo;다음에 올 단어를 맞추려면, 앞 문맥에서 어떤 정보를 가져와야 할까?\u0026rdquo; 이 질문이 is의 Q 벡터에 인코딩됩니다. Key(K) — 앞선 각 단어가 내미는 명찰입니다. Hello는 \u0026ldquo;나는 인사말이야\u0026rdquo;, my는 \u0026ldquo;나는 소유격이야\u0026rdquo;, name은 \u0026ldquo;나는 이름에 관한 단어야\u0026rdquo; 같은 태그를 K 벡터에 담고 있습니다. is의 Q와 각 단어의 K를 비교(내적)하면, name 의 점수가 가장 높게 나옵니다. \u0026ldquo;이름이 뭔지\u0026quot;를 맞춰야 하니까요. Value(V) — 점수가 높은 단어가 실제로 전달하는 내용입니다. name의 V에는 \u0026ldquo;이름\u0026quot;이라는 의미가 담겨 있고, 이 정보가 점수 비중대로 합쳐져서 is의 벡터를 갱신합니다. 이렇게 갱신된 is 벡터에는 \u0026ldquo;인사 + 나의 + 이름 + ~이다\u0026quot;라는 문맥이 응축되어 있고, 이 벡터가 LM Head를 거치면 빈칸에 John 같은 사람 이름이 높은 확률로 나오게 됩니다. 요약하면 Q는 \u0026ldquo;다음 단어를 맞추기 위해 무엇이 필요한가(질문)\u0026rdquo;, K는 \u0026ldquo;나는 어떤 종류의 단서를 갖고 있는가(명찰)\u0026rdquo;, V는 \u0026ldquo;내가 실제로 넘겨줄 의미(내용)\u0026ldquo;입니다.\nQuery · Keyᵀ: 유사도 Score와 마스킹 아까 N_head개만큼 헤드가 있다고 말씀드렸는데요, 하나의 헤드 안에서 Q와 K의 크기는 [N_position, head_dim] 입니다. K를 전치해 Kᵀ [head_dim, N_position]로 두고 Score = Q · Kᵀ 를 계산하면 [N_position, N_position] 행렬이 나옵니다. 행은 \u0026ldquo;현재 Query를 가진 토큰\u0026rdquo;, 열은 \u0026ldquo;참조 가능한 모든 위치\u0026quot;이고, (i, j) 원소는 i번째 토큰이 j번째 토큰을 얼마나 중요하게 보는지에 대한 스코어입니다. Query와 Key 벡터가 가까울수록(정렬될수록) 내적이 커집니다.\n사람도 왼쪽에서 오른쪽으로 글을 읽듯, Attention 연산에서도 과거 토큰이 미래 토큰을 알 수 없도록 해야 하고, 이를 위해 마스킹 기법을 사용합니다. \u0026ldquo;나보다 뒤에 있는 위치\u0026quot;의 Score를 Softmax 전에 −∞로 두면, Softmax 후에는 0이 되어, 뒤쪽 토큰은 앞쪽 토큰에 영향을 주지 않습니다. 즉 \u0026ldquo;뒤 토큰이 앞 토큰을 바꾸는 것\u0026quot;을 막는 것입니다.\nSoftmax \u0026amp; Value 가중합 거의 다 왔습니다 조금만 더 힘을 내볼까요! Score 행렬의 각 행 (각 Query 위치)에 Softmax 를 적용합니다. softmax 연산 특성으로 인해 한 행의 합이 1이 됩니다. 그리고 이 값들은 \u0026ldquo;다른 토큰들을 얼마나 비중 두고 볼지\u0026quot;에 대한 확률 분포를 의미하게 됩니다. 예를 들어 \u0026ldquo;헬스 2, 테니스 1, 침대 0.1\u0026rdquo; 같은 점수를 \u0026ldquo;헬스 0.7, 테니스 0.2, 침대 0.1\u0026quot;로 바꾼다면, 각 숫자는 값에서 확률값이 됩니다. 각 Query 위치에서, 모든 위치의 Value 벡터에 위에서 구한 가중치를 곱해 가중합 하면, 그 위치에 더해 줄 갱신 벡터(ΔE)가 나옵니다.\nMulti-Head Attention과 Output Projection Attention Layer에 들어갈 때 [seq_len, N_embed]를 [seq_len, N_head, head_dim]으로 쪼갰었습니다. 헤드라는 개념은 모델 성능을 향상시키기 위해 채택되었습니다. 한 head는 \u0026ldquo;형용사–명사\u0026rdquo; 같은 한 종류의 관계에 특화될 수 있지만, 언어에서 문맥이 바뀌는 방식은 매우 다양합니다. 그래서 서로 다른 Q·K·V 행렬을 가진 여러 head로 분할하고, 각 head를 병렬로 처리함으로써 문맥 이해 능력을 향상시킨 것입니다. 각 head는 서로 다른 서브스페이스에서 [N_position, head_dim] 출력을 만든 뒤, 이들을 concatenate 하여 [N_position, N_embed]로 만듭니다.\n마지막으로 Output Projection(FC): ConcatenatedAttention · W_O + b_O 로 [N_embed, N_embed] 가중치를 적용해, 여러 head에서 나온 정보를 하나의 표현 공간으로 다시 묶습니다. 이것이 한 블록의 Multi-Head Attention 최종 출력입니다. 이제 어려운 부분은 다 끝났습니다!\nResidual Connection Self-Attention 출력과 원래 입력을 더하는 연결을 Residual Connection(skip connection) 이라고 합니다. y = x + AttentionOutput 형태로, 이름은 거창하지만 본질은 행렬 덧셈입니다. 원래 정보 x를 유지한 채 Attention이 포착한 변화분 만 더하는 구조이기 때문에, 깊은 네트워크에서도 기울기가 잘 전달되고 학습이 안정적입니다.\nFeed-Forward Network (FFN) 이쯤되서 다시 리마인드해보면, 하나의 디코더 레이어는 총 6단계(Layernorm-Attention-Residual-Layernorm-FFN-Residual)로 이루어져 있습니다. Layernorm과 Residual은 중복이므로 Feed-Forward Network(FFN) 을 마지막으로 살펴보겠습니다. FFN은 두 개의 Linear 레이어와 그 사이의 Activation Function 로 구성됩니다. 입력 [N_position, N_embed]에 첫 번째 Linear로 차원을 확장 하고, 활성화(예: GeLU)를 거친 뒤, 두 번째 Linear로 다시 차원을 축소 하여 [N_position, N_embed]를 만듭니다. 각 위치마다 독립적으로 같은 MLP가 적용된다고 보시면 되고(position-wise FFN), 이 연산은 Attention에서 모인 정보를 비선형 변환으로 더 복잡한 특징 공간에 매핑하는 역할을 합니다. 앞에서 말했던 6단계를 모두 수행하면 하나의 디코더 블록 연산이 끝이 나고, 동일 과정을 N번(GPT-2의 경우 24번) 반복하면 Decoder Block 연산이 모두 끝이 나게 됩니다.\nLM Head: 다음 토큰 예측 마지막 단계인 LM Head는 벡터를 다시 인간이 이해할 수 있는 단어로 변환하는 단계입니다. 보통 Token Embedding Table(WTE) 의 전치(transpose)를 사용해 logit 을 계산합니다. 이 logit에 Softmax 를 적용하면 다음 토큰으로 어떤 토큰을 출력하면 좋을지에 대한 확률 분포가 나오게 됩니다.\n물론 확률이 가장 높은 토큰을 출력하는 방식도 있지만, 일반적으로 sampling 을 사용하여 확률에 따라 하나를 뽑아 다음 토큰으로 씁니다. 이때 샘플링 범위를 조절하는 대표적인 파라미터가 top_k 와 top_p 인데, 두 파라미터를 함께 쓰면 \u0026ldquo;너무 엉뚱한 단어가 뽑히는 것\u0026quot;을 막으면서도 자연스러운 다양성을 유지할 수 있습니다.\n축하드립니다! 여기까지 이해하셨다면 Transformer의 기본 구조를 모두 파악하신 겁니다. 한 번에 모든 내용이 와닿지 않더라도 괜찮습니다. Transformer는 최근 아키텍처인 만큼 결코 쉬운 주제가 아닙니다. 이 글에서는 구체적인 수치와 연산의 의미를 중심으로 설명드렸지만, 다양한 관점의 글들을 꾸준히 접하시다 보면 점점 익숙해지실 겁니다. 이제 마지막 파트로 가서 대표적인 최적화 기법에 대해 다뤄보겠습니다.\nPart 3: 최적화 기법 KV Cache와 메모리·대역폭 이슈 Part 2에서 가장 중요한 연산은 단연 Attention인데요, Query와 Key를 곱하여 나오는 Score 행렬의 크기는 context size의 제곱 입니다. 토큰이 N개면 N×N 행렬이므로, 문맥이 길어질수록 연산량과 메모리가 빠르게 늘어납니다. 추론 시에는 이전 스텝에서 계산한 Key 와 Value 를 다시 쓰기 위해 KV cache 에 저장하지만, 문맥이 길수록 이 캐시가 너무나 커져서 문맥 길이·메모리·대역폭이 큰 병목이 됩니다.\n예를 들어 LLaMA-3-70B 를 bfloat16(bf16) 기준으로 100만 토큰 문맥으로 돌린다고 하겠습니다. 모델 파라미터 70B × 2 byte ≈ 140GB입니다. KV cache는 2(K,V) × 배치 1 × 레이어 80 × KV head 8 × head 차원 128 × 시퀀스 1M × 2 byte 식으로 잡으면 약 328GB 수준이 될 수 있습니다. 한 토큰을 생성할 때 읽어야 할 메모리가 모델 + KV cache로 약 468GB이고, 초당 20 토큰을 만들려면 이론상 10TB/s급 메모리 대역폭이 필요하다는 식으로 이해하시면 됩니다. 최신 GPU인 NVIDIA B100의 메모리 대역폭이 최대 8TB/s이며 메모리 용량은 192GB에 불과하다는 것을 생각하면 어느정도 수준인지 감이 오실 겁니다.\nKV Cache Architecture 비교 (MHA, MQA, GQA, MLA) KV를 어떻게 저장·공유하느냐에 따라 크게 4가지 방식(MHA, MQA, GQA, MLA)으로 나눌 수 있습니다. 핵심 trade-off는 정확도(표현력) 와 KV cache 크기(메모리·대역폭) 사이의 균형이며, 이 차이를 시각적으로 잘 풀어준 논문이 있어 사진자료 첨부드립니다.\nMulti-Head Attention (MHA) 원래 Transformer 논문에서 제안된 구조입니다. Query head마다 자기 전용 K, V head가 있어 1 Query : 1 KV 관계입니다. GPT-3, LLaMA 1/2 등이 이 방식을 씁니다.\n장점: head마다 독립적인 K, V를 가지므로 표현력이 가장 높고, 다양한 패턴을 동시에 포착할 수 있습니다. 정확도 면에서 가장 유리합니다. 단점: KV cache를 head 수만큼 전부 저장해야 하므로, 문맥이 길어지면 메모리 사용량과 대역폭 요구가 급격히 커집니다. Multi-Query Attention (MQA) 모든 Query head가 하나의 K, V head를 공유합니다. N Query : 1 KV 관계이며 PaLM, Falcon, StarCoder 등에서 사용합니다.\n장점: KV cache 크기가 MHA의 1/N_head 수준으로 줄어들어, 추론 시 메모리·대역폭 부담이 크게 감소합니다. 배치 크기를 늘리거나 긴 문맥을 처리하기 훨씬 유리합니다. 단점: 모든 head가 같은 K, V를 보기 때문에, head별로 서로 다른 관계를 포착하는 능력이 떨어집니다. MHA 대비 정확도가 다소 하락하는 trade-off가 있습니다. Grouped-Query Attention (GQA) Query head를 여러 그룹 으로 나누고, 그룹마다 하나의 KV 쌍을 공유합니다. MHA(1:1)와 MQA(N:1)의 중간으로, N Query : M KV 관계입니다. 예를 들어 Query head 32개, KV head 8개면 Query 4개가 KV 1개를 공유합니다. LLaMA-2-70B, LLaMA-3, Mistral 등이 GQA를 씁니다.\n장점: MQA보다 KV head가 많아 표현력이 높으면서, MHA보다 KV cache가 작습니다. 정확도와 효율 사이에서 실전적으로 가장 균형 잡힌 선택지로 평가받고 있습니다. 단점: MHA에 비하면 여전히 head 간 KV를 공유하므로 표현력이 제한되고, MQA만큼 메모리를 줄이지는 못합니다. Multi-Head Latent Attention (MLA) K, V를 저차원 latent 벡터로 압축(projection)한 뒤, 그 latent 공간에서 Attention을 수행합니다. KV cache에는 원래 K, V 대신 이 작은 latent 벡터만 저장하면 됩니다. DeepSeek-V2/V3 등에서 사용합니다.\n장점: KV cache를 원래 차원보다 훨씬 작은 latent 차원으로 압축하므로, GQA보다도 메모리 효율이 좋습니다. 동시에 head마다 독립적인 Q를 유지해 표현력을 크게 희생하지 않습니다. 단점: latent projection을 위한 추가 연산(압축·복원 행렬곱)이 필요하고, 구현 복잡도가 높습니다. 압축 과정에서 정보 손실이 발생할 수 있어, 압축 비율을 잘 조절해야 합니다. 언제 무엇을 쓸까? (상황별 선택 가이드) 위 네 가지 방식은 “항상 이것이 정답”이라기보다(물론 대세는 있지만) 문맥 길이·메모리·품질 요구·구현 환경에 따라 선택이 달라집니다. 빠르게 변하는 LLM 생태계에서는 예전에 쓰이던 조합이 지금은 잘 언급되지 않기도 하고, 반대로 “지금은 GQA가 대세”라고만 알고 있으면 왜 MHA나 MQA를 쓸 때가 있는지 헷갈리기 쉽습니다. 아래는 각 방식을 어떤 상황에서 고려할 수 있는지 정리한 가이드입니다.\nMHA — 문맥이 짧고(예: 수백~수천 토큰), 정확도·표현력을 최우선으로 할 때. 연구·실험용 소형 모델, 또는 KV cache 부담이 상대적으로 작은 서비스에서 여전히 의미 있습니다. 초기 Transformer·GPT-3·LLaMA 1/2 시절의 기본 선택이었고, “head마다 독립적인 K·V”라는 원론적 구조를 유지하고 싶을 때 참고할 수 있습니다. MQA — 메모리·대역폭이 극한이고, 문맥이 매우 길거나 배치 크기를 크게 잡아야 할 때. PaLM·Falcon·StarCoder처럼 “KV를 하나만 두고 모든 Query가 공유”하는 구조라 cache가 가장 작습니다. 표현력은 MHA·GQA보다 떨어질 수 있으므로, 품질보다 처리량·규모 확장이 더 중요한 배포 환경에서 고려합니다. GQA — 일반적인 프로덕션에서 정확도와 효율의 균형이 필요할 때. LLaMA-2-70B·LLaMA-3·Mistral 등 대부분의 최신 오픈 LLM이 채택한 방식으로, “어떤 걸 쓸지 모르겠다”면 GQA를 기본으로 두고, 문맥이 극단적으로 길거나 메모리가 극히 부족한 경우에만 MQA·MLA를 검토하는 식으로 쓰면 됩니다. MLA — 긴 문맥 + 메모리 효율을 동시에 요구하되, GQA보다 더 aggressive한 cache 절감이 필요할 때. DeepSeek-V2/V3처럼 latent로 K·V를 압축하는 방식이라 구현·튜닝 난이도는 있지만, “head별 Q는 유지하면서 cache만 줄이고 싶다”는 요구에 잘 맞습니다. 인프라와 실험 리소스가 충분한 팀에서 도입을 검토하기 좋습니다. 정리하면, 모든 튜닝이 항상 맞는 것은 아니고 적절한 상황에 맞게 선택해야 의미가 있습니다. 짧은 대화 위주 서비스와 100만 토큰급 문서 서비스는 같은 “Attention 최적화”라도 다른 구조가 어울릴 수 있다는 점만 기억해 두면 도움이 됩니다.\n정리 이 글에서는 LLM의 동작 원리부터 LLM을 구성하는 각 연산의 의미를 적절한 비유와 함께 살펴보았습니다. 다시 한번 요약하자면, Transformer architecture는 크게 Token Embedding, Decoder Block, LM Head 세 단계로 구성되어 있고, Decoder Block은 다시 LayerNorm, Attention, Residual, LayerNorm, FFN, Residual로 쪼개서 살펴볼 수 있습니다. 마지막으로 문맥 길이에 따른 O(N²) 비용과 KV cache 메모리·대역폭 이슈, 그리고 이를 해결하기 위한 MHA·MQA·GQA·MLA 같은 KV Cache 관련 기본적인 구조 변형을 비교해보았습니다.\nReference https://arxiv.org/pdf/2209.10797\nhttps://arxiv.org/pdf/2503.11486\nhttps://metr.org/blog/2025-03-19-measuring-ai-ability-to-complete-long-tasks/\nHyperAccel 채용 중! 저희는 LLM 추론 최적화의 최전선에서 성장하고 있는 NPU 설계 스타트업입니다. 이번 글은 하이퍼엑셀 내부 교육자료를 바탕으로 작성되었는데요, 이처럼 서로의 전문성을 공유하며 함께 성장하는 문화가 저희의 강점입니다.\n저희가 다루는 기술에 관심이 있고, 이 흐름에 함께하고 싶다면 아래 링크에서 지원해 주세요. HyperAccel Career\n","permalink":"https://hyper-accel.github.io/posts/what-is-the-transformers/","summary":"Transformer 기반 LLM의 내부 구조를 하나하나 뜯어보며, 각 모듈이 갖는 의미와 최적화 기법까지 정리합니다.","title":"Transformer World: LLM의 기본 구조 뜯어보기"},{"content":"지피지기면 백전불태 번외편: Pallas Programming Model 지피지기면 백전불태(知彼知己 百戰不殆)\n상대를 알고 나를 알면 백 번 싸워도 위태롭지 않다는 뜻입니다.\n이 시리즈는 AI 가속기 설계를 위해 경쟁사들의 하드웨어를 깊이 이해하는 것을 목표로 합니다.\n이번 글에서는 TPU에서 커스텀 커널을 작성할 수 있게 해주는 Pallas 프로그래밍 모델에 대해 다룹니다.\n안녕하세요, HyperAccel ML팀 엔지니어 최동현입니다.\n지난 2편에서 부상하고 있는 TPU의 하드웨어 아키텍처와 소프트웨어 스택에 대해 살펴봤습니다. 이번 글에서는 2편에 이어 TPU 소프트웨어 스택 중 Pallas에 대해 더 자세히 알아보려고 합니다.\n최신 TPU 세대인 Ironwood에서는 Pallas 라는 프로그래밍 모델이 성능 최적화의 핵심 역할을 하고 있습니다. Pallas는 TPU에서 CUDA나 Triton처럼 커스텀 커널을 작성할 수 있게 해주는 도구로, 하드웨어의 세부 구조를 직접 제어할 수 있으면서도 Python 환경에서 비교적 쉽게 사용할 수 있다는 점이 특징입니다.\n2편에서 XLA 컴파일러의 한계를 언급했듯이, 자동 컴파일러만으로는 최신 알고리즘들을 최적화하기 어려운 경우가 많습니다. Pallas는 바로 이런 한계를 넘어서기 위해 구글이 만든 커널 언어입니다. Ironwood와 함께 공개되면서 \u0026ldquo;Extreme performance: Custom kernels via Pallas\u0026quot;라는 슬로건으로 강조되고 있습니다. TPU의 성능을 극대화하는 데 중요한 역할을 합니다.\n따라서 본 시리즈의 번외로 Pallas 프로그래밍 모델을 한번 짚고 넘어가겠습니다. 이번 글에서는 Pallas가 무엇인지, 왜 필요한지, 그리고 어떻게 TPU의 성능을 끌어올리는지 알아봅니다.\nBackground: TPU 아키텍처와 Pallas의 필요성 Pallas를 이해하기 위해서는 먼저 TPU가 CPU나 GPU와 어떻게 다른지 알아야 합니다.\n전통적인 구조 vs TPU의 Systolic Array 전통적인 CPU나 GPU 아키텍처는 연산을 위해 SRAM에서 레지스터 파일로 데이터를 매번 가져오고 저장하는 과정을 반복합니다. 행렬곱처럼 동일한 데이터를 반복해서 사용하는 연산에서는 이 방식이 막대한 메모리 대역폭 낭비 를 초래합니다.\nTPU는 이를 해결하기 위해 한 번 로드된 데이터가 연산기 사이를 흐르며 연속적으로 계산되는 구조 를 채택했습니다. 이것이 바로 2편에서 설명한 Systolic Array 구조입니다.\nTPU 내에서의 연산은 다음과 같은 흐름을 가집니다:\nWeight 공급: DRAM에 저장된 가중치 데이터가 Weight FIFO를 거쳐 Matrix Multiply Unit(MXU)로 로드됩니다. Activation 공급: Unified Buffer(UB)에 저장된 입력 데이터가 MXU로 전달됩니다. 행렬 연산 수행: MXU 내부의 Systolic Array 구조를 통해 곱셈과 누적(Multiply-Accumulate) 연산이 동시다발적으로 일어납니다. 후처리 파이프라인: MXU의 출력값은 Accumulator, Activation Unit(ReLU 등), Normalize/Pool Unit을 차례로 통과하며 AI 모델에 필요한 추가 연산을 수행합니다. 결과 저장: 모든 연산 플로우를 마친 최종 출력은 다시 Unified Buffer로 돌아와 저장됩니다. GPU와의 핵심 차이점: 실행 단위의 변화 이러한 구조적 차이는 프로그래밍 모델의 관점에서 매우 큰 차이를 만듭니다.\nGPU (Single Instruction Multiple Thread, SIMT): 수많은 스레드가 독립적으로 계산을 수행하며, 32개의 스레드를 워프(Warp) 단위로 묶어 관리합니다. 데이터 하나하나에 집중하는 세밀한 병렬 처리가 특징입니다. TPU (Single Program Multiple Data, SPMD): 한 번의 데이터 로드로 전체 연산 시퀀스를 끝내버립니다. 즉, 개별 스레드가 아닌 \u0026lsquo;텐서(또는 타일) 하나에 대한 전체 프로그램\u0026rsquo;을 하나의 최소 실행 단위 로 간주합니다. Why Pallas? Pallas는 TPU의 하드웨어적 특성(Unified Buffer 직접 제어, MXU 스케줄링 등)을 추상화하면서도, 개발자가 직접 \u0026lsquo;텐서 단위의 흐름\u0026rsquo;을 최적화할 수 있도록 설계된 언어입니다.\nTPU는 세대를 거듭하며 벡터 연산 유닛을 강화하고, 대규모 모델 대응을 위한 스케일업 기술을 발전시켜 왔습니다. 최신 아키텍처인 Ironwood에 이르러서는 칩렛(Chiplet) 구조를 채택한 거대한 패키지 위에 256x256 크기의 Systolic Array(MXU)를 총 4개 나 탑재한 \u0026ldquo;괴물 연산기\u0026quot;가 되었습니다.\n하지만 하드웨어의 체급이 비약적으로 커졌음에도 불구하고, 한 번의 데이터 로드를 통해 최대한 많은 연산을 수행한다 는 핵심 설계 기조는 변함없이 유지되고 있습니다.\n왜 Pallas가 필요한가? 2편에서 XLA 컴파일러에 대해 다뤘을 때, XLA는 강력한 최적화 컴파일러지만 한계가 있다고 했습니다. 새로운 연산 알고리즘이 등장하면 어떻게 될까요? 컴파일러가 이를 최적화할 수 있는 버전으로 업데이트되기 전까지는 수동으로 만든 커스텀 커널의 성능을 따라잡기 어렵습니다.\n예를 들어 Flash Attention이나 MoE(Mixture of Experts) 같은 최신 알고리즘들은 메모리 접근 패턴이 복잡하거나 데이터 의존성이 높아 자동 컴파일러가 최적화하기 어려운 경우가 많습니다. 이런 경우에는 개발자가 직접 메모리 계층 구조를 이해하고, 데이터를 어떻게 타일링할지, 언제 메모리 간 데이터 이동을 할지 등을 세밀하게 제어해야 합니다.\nGPU에서는 이런 문제를 CUDA나 Triton으로 해결했습니다. CUDA는 하드웨어를 직접 제어할 수 있지만 진입장벽이 높습니다. Triton은 CUDA보다 추상화 수준이 높아서 비교적 쉽게 사용할 수 있습니다. 하지만 둘 다 GPU에서만 작동합니다.\nTPU에서는 어떻게 할까요? 구글은 2023년 무렵부터 JAX의 실험적인 확장 기능으로 Pallas 라는 커널 언어 API를 제공하기 시작했습니다. Pallas는 Triton과 비슷한 철학을 가지고 있지만, GPU와 TPU 양쪽을 모두 지원한다는 점이 큰 차이입니다.\nPallas란 무엇인가? Pallas는 JAX 생태계 내에서 커스텀 커널을 작성할 수 있게 해주는 커널 언어입니다. GPU와 TPU 양쪽에서 작동하며, 하드웨어의 메모리 계층 구조, 데이터 타일링, 블록 단위 병렬성 등을 직접 제어할 수 있게 해줍니다.\nPallas의 핵심 아이디어는 간단합니다. 높은 수준의 자동화된 컴파일러가 처리하기 어려운 연산을 개발자가 하드웨어에 가까운 수준에서 직접 제어할 수 있게 해줍니다. CUDA처럼 완전히 낮은 수준으로 내려가는 것은 아니고, Python 환경에서 비교적 쉽게 사용할 수 있도록 추상화되어 있습니다. 자동 컴파일러의 편의성과 수동 최적화의 제어력을 모두 제공하는 균형점을 찾은 것입니다.\n핵심 추상화: Grid, BlockSpec, Ref Pallas는 세 가지 핵심 추상화를 통해 하드웨어를 제어합니다: Grid, BlockSpec, 그리고 Ref 입니다.\nGrid: 병렬 실행 추상화\nPallas는 Grid 라는 추상화를 통해 커널의 반복 실행 공간을 정의합니다. Grid는 커널 함수가 몇 번, 어떤 구조로 호출될지를 지정하는 launch configuration입니다. Grid의 각 점은 고유한 program_id를 가진 하나의 프로그램 인스턴스에 대응되며, 이 프로그램 인스턴스가 실제로 어떤 하드웨어 단위에서 실행되는지는 백엔드에 따라 달라집니다.\ndef kernel(o_ref): i = pl.program_id(0) # 현재 프로그램의 ID o_ref[i] = i # Grid 크기 지정: (8,) = 8개의 병렬 프로그램 result = pl.pallas_call( kernel, out_shape=jax.ShapeDtypeStruct((8,), jnp.int32), grid=(8,), # 8개의 병렬 인스턴스 )() 즉 grid=(8,)이면 커널 함수가 8개의 프로그램 인스턴스로 실행되고(program_id: 0~7), grid=(4, 4)이면 16개(4×4)의 인스턴스로 실행됩니다. CUDA에서 \u0026lt;\u0026lt;\u0026lt;gridDim, blockDim\u0026gt;\u0026gt;\u0026gt;으로 론칭 크기를 지정하는 것과 유사한 개념입니다. 다만 각 프로그램 인스턴스가 하드웨어의 어떤 단위에 매핑되는지는 아키텍처에 따라 근본적인 차이가 있습니다.\nGPU에서의 Grid\nGPU 백엔드(Triton/Mosaic)에서 Grid는 하드웨어 스케줄러에 의한 완전 병렬 실행 을 전제로 합니다. 각 프로그램 인스턴스(Grid의 각 점)는 하나의 스레드 블록(Thread Block) 에 매핑되어 개별 Streaming Multiprocessor(SM) 에서 독립적으로 실행됩니다. 예를 들어 grid=(8,)이면 8개의 스레드 블록이 생성되어, GPU의 SM들에 분산 배치됩니다.\n하드웨어가 비결정적으로 스레드를 스케줄링하므로 프로그램 인스턴스 간의 실행 순서가 보장되지 않습니다. 따라서 개발 시 BlockSpec의 index_map 설계에서 서로 다른 프로그램이 동일한 High Bandwidth Memory(HBM) 위치에 쓰지 않도록 경쟁 조건(Race condition)을 엄격히 관리해야 합니다.\nTPU에서의 Grid\nTPU 백엔드에서 Grid는 다중 코어 간의 병렬성과 단일 코어 내의 순차적 파이프라이닝 을 조합한 모델입니다. Grid 차원은 두 종류로 나뉩니다:\nParallel 차원: 프로그램 인스턴스가 여러 TensorCore에 분산되어 물리적으로 동시에 실행됩니다. 예를 들어 grid=(2, 8) 에서 첫 번째 차원이 Parallel이면, 2개의 TensorCore가 각각 독립적으로 작업을 처리합니다. Sequential 차원: 하나의 TensorCore 내에서 프로그램 인스턴스가 순차적으로 루프를 돌며 실행됩니다. 위 예시에서 두 번째 차원이 Sequential이면, 각 TensorCore가 8번의 반복을 직렬로 수행합니다. TPU는 매우 넓은 SIMD 머신이지만, 소프트웨어적으로는 단일 스레드 프로세서 처럼 코딩할 수 있습니다. Tensor Control System(TCS)이 Sequential 차원의 루프를 돌며 전체 연산을 제어하는 직관적인 흐름을 제공합니다.\nSequential 차원은 단순히 느리게 실행하는 것이 목적이 아닙니다. 세마포어(Semaphore) 를 통해 현재 연산과 다음 데이터의 로드를 중첩(Overlap)시켜 메모리 레이턴시를 숨기기 위한 전략적 수단 으로 사용됩니다.\nBlockSpec: 메모리 레이아웃 추상화\nPallas는 BlockSpec 을 통해 거대한 데이터를 하드웨어가 소화할 수 있는 크기(Chunk)로 쪼개는 과정을 추상화합니다. 이는 단순히 데이터를 자르는 것을 넘어, HBM(Remote)과 SRAM(Local) 사이의 데이터 전송 방식 설정 입니다.\nBlockSpec은 세 가지 구성 요소로 이루어져 있습니다:\nblock_shape: 각 프로그램 인스턴스가 Local Memory(SRAM) 작업대 위에 올려둘 데이터의 크기입니다. 하드웨어의 SRAM 용량을 초과하지 않도록 설계하는 것이 성능 최적화의 핵심입니다. index_map 함수: grid 인덱스(i, j)를 입력받아 HBM 상의 블록 시작 위치를 반환합니다. 이 함수는 컴파일 시점에 분석되어 하드웨어의 Direct Memory Access(DMA) 주소 계산 로직으로 변환됩니다. memory_space: 조각난 데이터가 머물 물리적 그릇을 지정합니다. 지정하지 않을 경우 백엔드 설정에 따라 기본 공간(pl.SRAM)으로 할당됩니다. Ref: 메모리 참조 추상화\nPallas는 Ref 객체를 통해 복잡한 하드웨어 메모리 주소 체계를 추상화합니다. 이는 단순히 데이터를 가리키는 포인터를 넘어, SRAM(Local Memory) 상의 특정 데이터 블록에 대한 논리적 뷰 를 제공합니다.\nRef의 핵심 특징은 다음과 같습니다:\nLocal Memory 참조: Ref는 HBM이 아닌, 하드웨어의 가장 빠른 작업대인 SRAM(TPU의 Vector MEM/Scalar MEM, GPU의 Shared Memory) 에 올라온 데이터를 가리킵니다. Dereferencing (역참조): x_ref[...]와 같이 대괄호를 사용하는 시점에 비로소 SRAM → Register File 로의 실제 데이터 로드가 발생하며, 값(Value)으로 변환됩니다. 하드웨어 추상화: 동일한 Ref 인터페이스를 사용하더라도 백엔드에 따라 TPU의 Vector/Scalar 메모리나 GPU의 Shared Memory 접근으로 자동 변환됩니다. 명확한 최적화를 위해 직접 설정할 수도 있습니다. Pallas Hardware Modeling Pallas는 TPU와 GPU 각각에 대하여 하드웨어 모델을 제공합니다. 큰 그림은 같으나 세부적으로는 다르므로, 먼저 공통적으로 구조화되어 있는 전체 구조를 살펴봅시다.\nPallas가 추상화하는 공통 하드웨어 모델은 다음과 같은 계층 구조를 가집니다:\nRemote Memory (HBM): 고대역폭 메모리(High Bandwidth Memory)로, 가장 느리지만 용량이 큰 메모리 공간입니다. pltpu.HBM 등을 통해 명시적으로 지정하거나 pl.ANY를 통해 자동으로 지정할 때 주로 사용됩니다. Multiple \u0026ldquo;Core\u0026rdquo; structure: 그리드를 병렬적으로 처리하기 위한 독립적 연산 유닛들의 집합입니다. 각 코어는 독립적으로 연산을 수행할 수 있습니다. Local Memory (SRAM 혹은 Cache): 코어 내부에 위치한 빠른 메모리입니다. Remote Memory보다 훨씬 빠르지만 용량은 제한적입니다. HBM 상의 데이터와 일치성을 위해 READ용 변수와 WRITE용 변수를 분리하는 것을 권장합니다. Register Files in Execution Units: 연산 유닛과 직접적으로 데이터를 주고 받을 수 있는 가장 빠른 메모리입니다. 연산에 필요한 데이터를 즉시 제공합니다. 일반적으로 Local Memory는 Register File의 10배, Remote Memory는 Local Memory의 10배 레이턴시가 소요됩니다. 그러나 Chiplet 구조를 채택한 TPU v7 Ironwood에서는 하나의 칩 안에 HBM까지 모두 가지고 있어, Remote Memory 통신이 기존 10배에서 2~5배로 빨라질 수 있습니다.\nPallas의 TPU 하드웨어 모델\nTPU의 하드웨어 모델은 공통 모델을 기반으로 하되, TPU만의 특수한 구조를 가집니다:\n메모리 계층 구조:\nLocal Memory 는 Vector Memory와 Scalar Memory로 분리되어 있습니다:\nVector Memory(VMEM): Vector 및 Matrix 관련 연산을 위한 데이터를 저장하는 메모리입니다. 동일 텐서 코어 내의 Vector/Matrix Unit (VPU/MXU/XLU)에서 접근 가능합니다. Scalar Memory(SMEM): Logic flow(loop, condition 등)를 위한 scalar 연산 관련 데이터를 저장하는 메모리입니다. 동일 텐서 코어 내의 Scalar Unit (TCS)에서 접근 가능합니다. TCS에서 생성하는 고수준의 명령을 통해 SMEM 상에 저장된 데이터를 벡터 연산에 직접 사용할 수도 있습니다. 예를 들어, SMEM에 저장된 스케일링 팩터 같은 scalar 값을 TCS가 벡터 파이프라인에 브로드캐스트하여, VMEM으로 별도 복제 없이 벡터 전체에 곱셈을 수행할 수 있습니다. 각 VMEM과 SMEM에는 READ/WRITE를 위한 영역을 따로 배치하여 HBM과의 data sync를 확보합니다. READ로 불러와진 데이터를 수정 시 다시 write-back을 안 하기 때문에 HBM과의 데이터 불일치가 발생할 수 있어서입니다.\n데이터 흐름과 파이프라이닝:\n커널 호출 시 Remote Memory(HBM)에서 Local Memory(VMEM/SMEM)로 지정된 BlockSpec에 맞추어 데이터를 로드합니다. 이때 설정된 Grid 번호에 맞추어 해당하는 데이터를 자동으로 가져옵니다.\n커널 내에서 Ref 데이터 호출 시 Local Memory에서 Register File로 데이터를 가져가 연산을 진행합니다. Local Memory ↔ Register File 간 이동 및 연산 작업 수행 중 다음 Grid에 대한 Remote Memory → Local Memory 데이터 로드가 자동으로 겹쳐져 진행됩니다. 이를 통해 메모리 레이턴시를 상당량 감출 수 있습니다.\n커널에서 설정된 출력 Ref 데이터에 결과 데이터를 쓰면 Local Memory로 write-back되며, 이후 해당 그리드에 대한 모든 프로그램 종료 시에 출력 Ref 데이터가 Remote Memory에 write-back됩니다.\nPallas의 GPU 하드웨어 모델\nGPU 또한 하드웨어 모델은 공통 모델을 기반으로 하되, GPU만의 구조를 가집니다:\n메모리 계층 구조:\nLocal Memory는 Shared Memory(SMEM): 각 Streaming Multiprocessor(SM)별로 독립적인 Shared Memory/L1 Cache 공간을 가집니다. TPU와 달리 Scalar/Vector 구분이 없는 통합된 작업 공간이며, 수많은 스레드가 이 공간에 동시 접근하여 병렬 연산합니다. 데이터 흐름과 파이프라이닝:\n단순히 하드웨어 스케줄링에만 의존하는 기존 방식과 달리 Pallas GPU는 HBM(Remote) → SMEM(Local) 데이터 로드와 TensorCore 연산을 명시적으로 중첩(Overlap) 합니다. plgpu.emit_pipeline 등을 통해 연산 유닛이 현재 데이터를 처리하는 동안 비동기적으로 다음 그리드의 데이터를 미리 가져와 메모리 레이턴시를 감춥니다. 커널 내부의 Ref 변수는 HBM이 아닌, Local Memory(SMEM)에 올라왔거나 올라올 예정인 데이터 조각의 주소를 가리킵니다. memory_space=plgpu.GPUMemorySpace.GMEM 설정을 통해 HBM(Remote) 공간을 명시하고 copy_gmem_to_smem으로 직접 제어할 수 있습니다. 메모리 파이프라이닝과 세마포어 TPU 아키텍처에서 HBM(Remote Memory)과 VMEM(Local Memory) 간의 데이터 이동은 수백 사이클의 레이턴시를 발생시킵니다. MXU가 아무리 빠르게 행렬 연산을 수행해도, 데이터가 도착할 때까지 기다려야 한다면 전체 성능은 메모리 병목에 갇히게 됩니다.\nPallas는 이 문제를 하드웨어 수준의 세마포어(Semaphore) 를 활용한 파이프라이닝으로 해결합니다.\nPallas의 동기화 메커니즘: Semaphore 기반의 비동기 제어\nPallas에서 DMA와 연산 유닛은 서로 독립적으로 작동하며, 이들의 속도 차이를 조율하기 위해 세마포어(Semaphore) 를 사용합니다. 동작 원리는 다음과 같이 상호 신호 체계로 이루어집니다.\nData Load (Producer): DMA가 외부 메모리(HBM)에서 로컬 메모리(VMEM/SMEM)로 데이터 로드를 완료하면, 세마포어 값을 증가(Signal)시켜 데이터가 준비되었음을 알립니다. Compute (Consumer): 연산 유닛은 세마포어 값을 확인하며 데이터가 로드될 때까지 대기(Wait)합니다. 값이 충족되면 즉시 연산을 시작합니다. Feedback Loop: 연산이 완료되면 연산 유닛은 다시 세마포어를 Signal하여 DMA에게 버퍼가 비었음을 알리고, 다음 데이터를 로드할 수 있도록 허용합니다. 이러한 Wait-Signal 구조를 통해 데이터 로드와 연산을 겹쳐서 실행(Overlapping)함으로써 하드웨어 가동률을 극대화합니다.\nDouble Buffering: 레이턴시를 숨기는 핵심 기법\n세마포어를 활용한 가장 기본적인 파이프라이닝 기법이 Double Buffering입니다. 우선 Local Memory(TPU에서는 주로 VMEM) 내에 두 개의 버퍼(Buffer 0, Buffer 1)를 서로 다른 SRAM 주소에 독립적으로 할당합니다. 동작 예시를 들자면 할당한 두개의 버퍼 중 한쪽 영역에는 DMA가 접근하여 버퍼 쓰기 동작 등을 수행하고, 다른 한쪽에는 Compute가 각각 접근하여 연산을 수행하는 등의 방식으로 동작하며, Pallas 컴파일러가 루프 인덱스에 따라 DMA와 Compute 연산이 향하는 포인터를 교대로 스위칭합니다.\n초기화: DMA가 첫 번째 데이터를 Buffer 0에 로드 루프 시작: VPU가 Buffer 0을 연산하는 동시에, DMA는 다음 데이터를 Buffer 1에 로드 버퍼 교체: 연산과 로드가 모두 완료되면 역할 교대 - VPU는 Buffer 1을, DMA는 Buffer 0에 로드 반복: 이 과정을 데이터가 끝날 때까지 반복 결과적으로 메모리 로드 시간이 연산 시간 뒤로 완전히 숨겨집니다. 연산이 데이터 로드보다 오래 걸리는 compute-bound 워크로드에서 특히 효과적입니다.\nPallas에서는 pltpu.semaphore를 통해 이러한 동기화를 명시적으로 제어할 수 있습니다. \u0026lsquo;Read-before-ready(데이터 도착 전 읽기)\u0026lsquo;와 \u0026lsquo;Write-over-active(연산 중 덮어쓰기)\u0026rsquo; 같은 위험한 상황을 하드웨어 수준에서 방지하며, 컴파일러가 자동으로 Prefetch와 Overlap을 최적화 합니다.\nBackend Lowering과 JAX 통합 Pallas로 작성된 커널은 최종적으로 하드웨어 코드로 변환됩니다. GPU에서는 Triton 또는 Mosaic GPU 백엔드를 통해, TPU에서는 Mosaic 컴파일러를 통해 MLIR 형태로 낮춰지고 최종적으로 하드웨어 코드로 변환됩니다. 이 과정에서 연산자 fusion, 타일링 자동화, 데이터 전송과 계산의 오버랩(overlap) 등이 최적화됩니다. 개발자가 작성한 고수준 코드가 하드웨어에 최적화된 코드로 변환되는 것입니다.\n또한 Pallas 커널은 JAX의 jit, vmap, grad 같은 변환(Transform)과 호환됩니다. 따라서 고성능 커널을 작성하면서도 자동 미분, 매핑, 컴파일 등의 기능을 여전히 활용할 수 있다는 것이 큰 장점입니다. 이는 Pallas가 단순한 커널 언어를 넘어 JAX 생태계와 완전히 통합된 도구임을 보여줍니다.\nCUDA vs Pallas: 프로그래밍 모델 비교 1편에서 살펴본 CUDA와 Pallas를 비교해봅니다.\n핵심 비교 구분 CUDA Pallas 추상화 스레드 중심 (Thread → Warp → Block → Grid) 데이터 중심 (Grid + BlockSpec + Ref) 메모리 제어 명시적 (__shared__, __global__) 선언적 (memory_space, 자동 매핑) 동기화 수동 (__syncthreads()) 자동 (세마포어 기반 파이프라이닝) 하드웨어 NVIDIA GPU 전용 GPU + TPU 지원 생태계 성숙 (Nsight, cuBLAS, cuDNN) 실험적 (JAX 통합) 언어 C/C++ Python 코드 비교: 벡터 덧셈 CUDA - 스레드 ID 직접 계산, 경계 체크 필요:\n__global__ void vector_add(float *A, float *B, float *C, int N) { int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx \u0026lt; N) C[idx] = A[idx] + B[idx]; } Pallas - 데이터 블록 단위 추상화:\ndef vector_add_kernel(a_ref, b_ref, c_ref): c_ref[...] = a_ref[...] + b_ref[...] result = pl.pallas_call(vector_add_kernel, out_shape=..., grid=(N,))(a, b) 위 코드는 개념적 예시이며, 실제 동작을 위해서는 out_shape와 BlockSpec 등을 완성해야 합니다.\n선택 가이드 CUDA 선택 Pallas 선택 NVIDIA GPU 최대 성능 필요 GPU/TPU 이식성 필요 프로덕션 안정성 중요 빠른 프로토타이핑 기존 CUDA 코드베이스 활용 JAX 생태계 (jit, vmap, grad) 활용 성숙한 디버깅/프로파일링 도구 필요 TPU 커스텀 커널 작성 TPU에서 Pallas가 어떻게 활용되는가 최신 TPU 세대인 Ironwood에서는 Pallas를 중심에 두고 \u0026ldquo;Extreme performance: Custom kernels via Pallas\u0026quot;라는 슬로건으로 강조하고 있습니다. Ironwood 스택에서는 Pallas 정의를 통해 개발자가 Python 속에서 메모리 타일링, 데이터 이동, MXU 활용에 대한 전략을 직접 기술할 수 있습니다. Mosaic 컴파일러가 이를 TPU 코드로 낮춰 구현합니다.\n이 조합을 통해 데이터 고착(input stationary), 가중치 고착(weight stationary), 출력 고착(output stationary) 등의 타일링 전략과 스트라이드, 배치(batch) 단위의 분산 처리가 효율적으로 설계됩니다. 또한 HBM ↔ 온칩 메모리 데이터 전송과 MXU 계산을 동시에 겹치게 하면서 전체 파이프라인의 스케줄링 병목을 최소화하는 설계가 가능해졌습니다.\n최대 성능 잠재력 실현: 자동 컴파일러가 발견하기 힘든 메모리 액세스 패턴, 타일링 전략 등을 명시적으로 조정할 수 있기 때문에, 매우 빠른 커널을 만들 수 있습니다.\n하드웨어 추상화 유지: 여전히 Python 언어, JAX 생태계 내에서 작업하며, jit, grad 등의 기능을 그대로 사용할 수 있습니다.\n다중 백엔드 대응: GPU와 TPU 양쪽을 지원하며, 동일한 커널 정의로 여러 하드웨어에서 동작하게 할 수 있는 유연성이 있습니다.\n고려해야 할 사항 실험 단계: Pallas는 아직 자주 변경되는 실험적 단계에 있습니다. 버전 업에 따라 breaking changes가 있을 수 있고, 일부 기능이 완전하지 않거나 \u0026ldquo;미구현(unimplemented)\u0026rdquo; 에러가 나올 수 있습니다.\n실질적 이식성: Pallas가 GPU와 TPU 플랫폼 모두를 위한 backend를 가지고 있긴 하지만, 동일 코드가 두 시스템에서 최적으로 돌아간다는 것은 아닙니다. 현재 Pallas의 이식성은 동작 가능성에 가깝습니다.\n디버깅 및 최적화 도구 필요성: MXU utilization, memory bandwidth utilization 등을 세밀하게 보는 도구가 CUDA ecosystem보다 부족합니다.\n채택 장벽: TPU 없이 GPU만 있는 상황이라면 PyTorch 기반의 Triton을 사용하는 것이 더 합리적입니다. 일반적인 ML스택(PyTorch + AWS 혹은 온프레미스 서버)에서 JAX 기반이며 대체로 GCP 기반으로 TPU를 사용해야하는 Pallas는 채택되기 어렵습니다.\n마치며 이번 글에서는 TPU에서 커스텀 커널을 작성할 수 있게 해주는 Pallas 프로그래밍 모델에 대해 살펴봤습니다.\n먼저 TPU의 Systolic Array 구조가 CPU/GPU와 어떻게 다른지, 그리고 이러한 하드웨어적 특성이 프로그래밍 모델에 어떤 영향을 미치는지 확인했습니다. TPU는 텐서 단위의 실행 모델을 채택하여, 한 번의 데이터 로드로 전체 연산 시퀀스를 수행하는 구조적 특징을 가지고 있습니다.\nXLA 컴파일러가 자동으로 최적화하기 어려운 영역을 위해 등장한 Pallas는 Grid, BlockSpec, Ref라는 핵심 추상화를 통해 하드웨어의 메모리 계층 구조와 데이터 타일링을 직접 제어할 수 있게 해줍니다. TPU의 VMEM/SMEM, GPU의 Shared Memory처럼 각 하드웨어에 맞춘 메모리 모델을 제공하면서도 Python 환경에서 비교적 쉽게 사용할 수 있는 추상화 수준을 유지합니다.\nCUDA와의 비교를 통해 Pallas가 더 높은 추상화 수준을 제공하면서도 하드웨어 제어력을 유지한다는 점을 확인했고, Ironwood 세대에서 Pallas가 \u0026ldquo;Extreme performance\u0026quot;를 위한 핵심 도구로 자리잡고 있음을 살펴봤습니다.\nPallas는 자동화된 컴파일러와 수동 최적화 사이의 간극을 메우는 중요한 도구로, 최신 알고리즘들이 요구하는 복잡한 메모리 접근 패턴을 효율적으로 처리할 수 있게 해줍니다. Flash Attention, MoE, Sparse 연산처럼 비표준적인 연산 패턴이 중요해질수록 Pallas와 같은 커스텀 커널 도구의 역할은 더욱 커질 것입니다.\nReference Pallas Documentation Pallas TPU Details Inside the Ironwood TPU codesigned AI stack PyTorch/XLA 2.4 improves Pallas and adds eager mode TPU Architecture (qsysarch.com) TPU v7 Documentation 추신: HyperAccel은 채용 중입니다! 지피지기면 백전불태라지만 백전백승을 위해서는 훌륭한 인재가 많이 필요합니다!\n저희가 다루는 기술들을 보시고, 관심이 있으시다면 HyperAccel Career로 지원해 주세요!\nHyperAccel에는 정말 훌륭하고 똑똑한 엔지니어분들이 많습니다. 여러분의 지원을 기다립니다.\n","permalink":"https://hyper-accel.github.io/posts/pallas-programming-model/","summary":"TPU에서 커스텀 커널을 작성할 수 있게 해주는 Pallas 프로그래밍 모델에 대해 알아봅니다.","title":"지피지기면 백전불태 번외편: Pallas Programming Model"},{"content":"지피지기면 백전불태 4편 : 메모리 용량 병목과 NVIDIA ICMS \u0026ldquo;상대를 알고 나를 알면 백 번 싸워도 위태롭지 않다.\u0026rdquo;\n이 시리즈는 AI 가속기 설계를 위해 경쟁사들의 하드웨어를 깊이 이해하는 것을 목표로 합니다.\n네 번째 글에서는 올해 초 NVIDIA 젠슨황 CEO가 CES 키노트 세션에서 발표한 ICMS(Inference Context Memory Storage)와 이를 관리하는 프로세서인 DPU(Data Processing Unit)에 대해 다룹니다.\n안녕하세요? HyperAccel DV팀 소속 하드웨어 검증 엔지니어 임재원입니다.\n오늘 글은 지난달 CES 2026에서 있었던 NVIDIA CEO 젠슨황의 키노트 세션으로 시작을 해보겠습니다. 오늘 소개드릴 내용의 대부분이 이 키노트 영상 후반부에 담겨 있습니다. reference에 링크를 남겨두었으니 키노트 내용에 대해 더 자세히 알고 싶게 된 분들은 아래 링크의 풀 영상을 참조하시기 바랍니다.\nRubin 플랫폼 매해 젠슨황 키노트는 AI의 발전 방향과 반도체가 해야 할 일에 대해 알 수 있는 중요한 지표입니다. 특히 당해에 출시될 NVIDIA의 최신 라인업 GPU와 GPU pod을 구성하는 다양한 구성 요소들의 발전이 함께 소개됩니다.\n올해 젠슨황 CEO가 키노트에서 강조한 것은 올해 하반기에 정식 출시될 Rubin GPU로 구성될 데이터센터향 제품인 Rubin 플랫폼입니다.\n위 이미지에서 사각형으로 표시한 부분이 Vera CPU 36개, Rubin GPU 72개가 탑재된 NVL72 랙입니다. 이 랙에는 18개의 연산용 트레이가 층층히 들어있고, 각 연산 트레이마다 CPU 2개, GPU 4개가 장착됩니다. 추가로 이 트레이에는 CPU와 GPU뿐만 아니라 다른 트레이, 혹은 스토리지와 같은 다른 장치들과 통신하기 위한 또 다른 칩들이 들어있습니다.\n결과적으로 Vera Rubin 플랫폼을 구성하는 칩들을 모아보면 아래 이미지와 같습니다. CPU와 GPU의 성능 향상도 물론 괄목할 만한 부분이지만 오늘 우리가 주목할 것은 CPU와 GPU가 아닌 아래 그림의 5번째 위치한 칩인 Bluefield-4 DPU입니다. DPU에 주목해야 할 이유를 알기 위해서는 Rubin 플랫폼 소개 이후 젠슨황이 새롭게 던진 화두인 AI의 새로운 병목 지점에 대해 알아 보아야 할 필요가 있습니다.\nContext is the new bottleneck : 메모리 용량 자체가 병목이 되다 메모리 대역폭만이 병목이 아닙니다. 메모리 용량 그 자체가 새로운 병목이 되었습니다. 지난 글에서 LLM 연산 특성을 통해 LLM 연산이 memory-bound인 이유와 HBM 수요가 증가하게 된 배경에 대해 설명드린 바 있습니다. 매 토큰을 생성할 때마다 메모리에서 KV cache를 가져오기 때문에 메모리 대역폭이 병목이 되었습니다.\n하지만 최근 발생한 새로운 문제는 KV cache를 GPU 메모리에 올릴 수 없을 정도로 KV cache 자체에 필요한 용량이 많아졌다는 것입니다. 이는 최근 LLM 모델 발전이 context 길이를 늘리는 방향으로 이뤄지고 있기 때문입니다.\nOpenAI가 2024년 말 공개한 reasoning model과 claude cowork와 같은 agentic AI가 그 대표적인 예시입니다.\nReasoning model OpenAI의 o1, o3를 필두로 뛰어난 성능 향상으로 각광을 받은 Reasoning 모델들은 복잡한 문제를 해결하기 위해 \u0026lsquo;생각하는 시간\u0026rsquo;을 길게 갖습니다. 이 과정에서 모델은 최종 답변을 내놓기 전 내부적으로 수많은 \u0026lsquo;생각 토큰\u0026rsquo;들을 생성합니다.\n내부 추론 토큰: 겉으로 드러나지 않더라도 모델이 논리적 단계를 밟기 위해 생성하는 \u0026lsquo;생각\u0026rsquo; 토큰들이 전체 문맥의 상당 부분을 차지하게 됩니다. 자가 교정(Self-correction): 추론 과정 중에 오류를 발견하고 이를 수정하는 과정이 반복되면서, 수백개 정도의 토큰으로 이뤄진 질문에도 수천 토큰 이상의 문맥이 순식간에 쌓이게 됩니다. Agentic AI 에이전트형 AI는 단순히 질문에 답하는 것을 넘어, 스스로 계획을 세우고 도구를 사용하며 환경과 상호작용합니다. 이 과정은 \u0026lsquo;관찰-판단-행동\u0026rsquo;의 루프를 반복하며 이뤄집니다.\n상호작용 이력 유지: 에이전트가 어떤 도구를 썼고, 그 결과가 어떠했으며, 다음 계획은 무엇인지에 대한 모든 기록을 컨텍스트에 유지해야 일관된 동작이 가능합니다. 대량의 환경 데이터: 웹 페이지 스크린샷, 전체 코드베이스, 방대한 문서 등 에이전트가 처리해야 할 데이터 자체가 크기 때문에 컨텍스트 윈도우의 요구치가 급격히 상승합니다. 반복적 정교화: 한 번에 성공하지 못할 경우 실패 원인을 분석하고 다시 시도하는 과정이 누적되면서 일반적인 챗봇 대비 수십 배 이상의 토큰을 소모하게 됩니다. 용량에 대한 감이 안오시는 분들을 위해 숫자를 통한 예시를 보여드리겠습니다.\nTransformer 구조에서 토큰당 필요한 KV cache 용량 계산식은 아래와 같습니다.\n$$\\text{Total KV Cache Memory} = 2 \\times B \\times S \\times L \\times H_{kv} \\times D_h \\times P$$\n$$B : batch\\ size$$ $$S : sequence\\ length$$ $$L : num\\ layer$$ $$H_{kv} : num\\ head$$ $$D_{h} : head\\ dimension$$ $$P : precision(BF16: 2B,\\ FP8: 1B)$$\nmodel config가 공개된 Llama 3.1 405B 모델에 이 계산식을 적용해보면 토큰 1개당 약 516KB의 KV cache size가 사용됩니다. 여기서 사용자당 10만정도의 context length를 사용한다고 가정한다면 사용자당 필요한 KV cache 크기는 48GB, 128명의 사용자가 동시에 사용한다면 순간적으로 필요한 KV cache 크기는 6TB까지 커집니다.\n모델 parameter를 제외한 KV cache 에만 6TB의 메모리가 필요하게 됩니다. 아직 출시되지 않은 Rubin GPU 기준으로도 약 20개의 GPU에 해당하는 HBM이 필요한 수준입니다. 실제로 이러한 문제로 인해 GPU와 함께 탑재된 CPU의 DRAM에 KV cache를 저장하거나 다른 GPU의 HBM을 사용하는 식으로 저장고를 확장시키는 memory-offloading이 사용되고 있습니다.\n그렇다면 NVLink로 연결된 위 아래의 compute tray GPU로 KV cache를 넘기면 되지 않을까요? 랙하나에 72개 GPU가 들어가니 이론상으로 20TB 이상의 HBM memory를 공유할 수 있을 것입니다. 이는 언뜻 가장 빠른 방법처럼 보이지만, 데이터센터 스케일의 서빙에서는 몇 가지 문제가 있습니다.\nHBM의 기회비용: HBM은 단순 저장소로 쓰기에는 너무 비싸고 희귀한 자원입니다. 다른 GPU의 HBM에 내 KV cache를 넘기는 순간, 그 GPU는 자신이 처리해야 할 새로운 요청을 받을 공간을 잃게 됩니다. 자신이 저장할 수 있는 KV cache 용량을 뺏긴 셈이기 때문이죠. 데이터센터 운영자 입장에서 GPU의 연산 가동률을 높여야 수익이 나는데, HBM을 단순 스토리지로 쓰는 것은 비효율적인 선택입니다. NVLink 트래픽 혼잡: NVLink는 이미 모델 연산을 위한 병렬처리(Model Parallelism)를 위한 통신이 대부분의 트래픽을 차지하고 있습니다. 여기에 GPU 간 KV cache 공유가 빈번해지면 실질 모델 연산에 필요한 통신 대역폭까지 잠식하는 트래픽 혼잡이 발생합니다. 장애 전파 위험: 내 KV cache를 들고 있는 옆 GPU 노드에 문제가 생기면 내 추론 작업까지 함께 멈춰버리는 의존성 문제가 발생합니다. 한편, NVLink 기반 공유 이외에도 또 다른 문제가 있습니다. 지금까지는 사용자가 하나의 request를 보냈을 때의 상황만을 고려했습니다. 하지만 사용자들은 하나의 request만 보내지 않습니다. 여러 번의 request를 보낸다면 상황은 어떻게 될까요? 그중에서 과거에 보냈던 요청과 동일한 KV cache를 필요로 한다면? 메모리 용량 문제로 이전에 생성한 KV cache를 이미 지워버렸다면, GPU는 수십~수백 GB에 달하는 KV cache를 처음부터 다시 연산해야 합니다. 지난 시간에 말씀드렸듯 이 정도의 데이터를 다시 연산하는 것은 엄청난 연산량 낭비이자 시간 낭비입니다.\nKV cache를 위한 스토리지의 필요 결국 데이터센터 환경에서는 각 GPU가 연산에만 집중할 수 있도록 하면서, 동시에 대량의 KV cache를 지우지 않고 보관할 수 있는 별도의 공유 저장소가 필요합니다.\n이를 위해 우리는 memory hierarchy의 더 하위 계층의 메모리를 활용해야 할 수 밖에 없게 된 것입니다. 가장 먼저 떠오르는 것은 각 서버 트레이 내부에 장착된 로컬 SSD에 KV cache를 저장하는 방법입니다. 하지만 로컬 SSD에는 두 가지 근본적인 한계점이 있습니다.\n용량 한계: 한 서버 트레이 안에 넣을 수 있는 SSD 개수는 공간과 전력 문제로 매우 제한적입니다. 공유 문제: 한 서버의 로컬 SSD에 저장된 KV cache는 다른 서버가 직접 읽을 수 없습니다. 네트워크를 타고 CPU가 관여하여 넘겨줘야 하는데 이는 너무 느립니다. 그렇다고 데이터센터 저 멀리의 범용 네트워크 스토리지(NAS 등)를 쓰자니, 용량은 충분하지만 네트워크 지연이 너무 커서 LLM 서빙의 대역폭 요구를 감당할 수 없습니다. 로컬 SSD는 빠르지만 너무 작고 공유가 안 되며, 네트워크 스토리지는 크지만 너무 느립니다.\nNVIDIA가 DPU를 통해 해결하려고 하는 문제가 바로 여기에 있습니다.\nNVIDIA의 해결책: ICMS (Inference Context Memory Storage) NVIDIA는 이 문제를 해결하기 위해 로컬 SSD(G3 계층)와 네트워크 스토리지(G4 계층) 사이에 G3.5 계층이라고 불리는 ICMS를 도입했습니다. 로컬 SSD의 빠른 대역폭과 네트워크 스토리지의 거대한 공유 능력을 결합한 것입니다.\nICMS는 별도의 전용 랙에 존재하지만, BlueField-4 DPU와 PCIe Gen 6로 직결되어 로컬 SSD를 읽는 것과 거의 차이 없는 속도를 내면서도, 모든 GPU가 DPU를 통해 자신의 로컬 메모리처럼 접근할 수 있는 거대한 공유 메모리 풀 역할을 합니다. NVIDIA의 목적은 ICMS를 통해 GPU가 추론 연산에서 활용할 수 있는 메모리를 HBM과 DRAM에서 SSD(NAND Flash)까지 확장하는 것입니다. 아까 보여드렸던 Rubin 플랫폼 랙 중 표시한 부분이 이 ICMS용 랙입니다. 이를 통해 Rubin 플랫폼의 각 GPU는 기존 HBM 1TB + 추가 16TB 스토리지를 자신의 HBM 메모리처럼 활용할 수 있습니다. compute tray에 GPU와 같이 꽂혀있는 Bluefield-4 DPU가 GPU ↔ ICMS 간 데이터 통신을 관리해주는 역할을 하게 됩니다.\n대역폭의 한계를 극복하기 위한 소프트웨어 최적화 그러나 DPU의 스펙 문서를 보게 되면 한가지 의문점이 듭니다. HBM 대역폭은 2.2TBps인 반면에, DPU 대역폭은 100GBps로 대략 1/20 수준이기 때문입니다. 개별 GPU에서 활용할 수 있는 메모리 용량이 늘어났더라도 그 메모리에서 데이터가 오는 속도가 HBM과 차이가 난다면 메모리 대역폭에서 병목이 발생하지 않을까요?\n충분히 합리적인 의문입니다. 하지만 ICMS가 타겟팅하는 메모리인 KV cache의 사용 특성을 이용하면 이 한계를 극복할 수 있습니다. KV cache는 decode 단계에서 이전에 생성된 KV cache를 반복해서 재사용하는 특성을 갖고 있습니다. 그렇다면 다음 토큰 연산을 위해 필요한 KV cache는 미리 GPU로 가져오더라도 큰 문제가 없습니다. 이는 소프트웨어적으로 예측 가능한 영역입니다.\n추론 최적화를 위한 프레임워크 : vLLM과 SGLang, 그리고 LMCache 앞서 설명드린 KV cache의 특성을 활용하여 추론 연산을 최적화하기 위한 다양한 프레임워크들이 개발되어왔습니다. 지난번에 김재우님(Author, LinkedIn)이 소개해주신 SGLang도 그 중 하나입니다.\nvLLM \u0026amp; SGLang vLLM과 SGLang은 추론 연산 가속을 위한 엔진으로 GPU 메모리 안에서 KV cache를 효율적으로 관리하기 위한 기능을 제공합니다. 그중 하나가 prefix caching인데요. 특정 request에서 입력된 sequence의 앞부분(prefix)과 다음 request에서 입력된 sequence의 앞부분이 겹치는 경우 해당 부분에 대해서 이전 request에서 생성된 KV cache를 그대로 재사용할 수 있는 기능입니다. 같은 request 내에서 decoding 작업 시 매 토큰 생성마다 해당 request 내에서 생성된 KV cache를 재사용하는 것은 기본적으로 가능하였습니다. 이 기능은 거기서 한발 더 나아가 서로 다른 request에서도 입력토큰만 같다면 생성되는 KV cache는 같을 것이기 때문에 추가적인 연산 필요 없이 KV cache를 재사용할 수 있는 것입니다.\n다만 vLLM과 SGLang의 한계는 KV cache 관리 영역이 GPU memory (+CPU host memory)로 한정되어 있고, 입력 토큰이 처음부터 같을 때에만 prefix caching을 사용할 수 있다는 점입니다. 같은 sub sequence가 중간에 있더라도 앞선 prefix들이 다르면 KV cache를 재사용할 수 없습니다. 이는 causal attention 구조의 특성 상 현재 토큰으로 생성되는 KV cache가 자신보다 앞에 있는 모든 토큰에 영향을 받기 때문입니다. 이 기능이 \u0026ldquo;prefix\u0026rdquo; caching이라 불리는 이유도 여기에 있습니다.\nLMCache LMCache는 이러한 한계를 극복하기 위해 탄생한 KV cache 전용 분산 캐시 관리 프레임워크입니다. 앞서 언급한 기능인 현재 연산 중에 다음에 필요한 KV cache를 디바이스의 메모리에서 동시에 prefetch를 진행할 수 있는 기능을 제공합니다.\n아울러 prefix-caching의 한계를 극복한 CacheBlend 기법을 사용하여 토큰 위치가 다른 곳에서 생성된 KV cache에 토큰 위치와 이전 맥락에 대한 추가적인 연산을 통해 KV cache를 그대로 다시 계산하는 것보다 훨씬 적은 연산량으로 KV cache를 계산할 수 있는 non-prefix cache reuse를 지원합니다.\nNVIDIA의 추론 프레임워크 Dynamo에도 LMCache가 통합되어 있으며, ICMS에서 이 LMCache 기능이 탑재된 Dynamo가 활용됩니다. 아울러 HyperAccel에서도 LPU에서 LMCache를 지원할 수 있도록 소프트웨어를 개발중에 있습니다.\nBluefield-4 DPU의 역할 DPU는 이러한 소프트웨어를 사용하여 GPU와 다른 디바이스 간 데이터 전송과 memory offload를 위한 연산을 수행하고 데이터 이동을 효율적으로 관리하기 위한 보조 프로세서입니다. DPU 내부에도 Vera CPU 이전 버전인 Grace CPU가 탑재되어 있어 앞서 설명한 스토리지 관리를 위한 소프트웨어를 구동할 수 있습니다. 기존에는 이러한 역할을 CPU에서 대부분 진행하였지만, DPU가 데이터 이동에 관한 연산을 수행하게 되면 기존 CPU는 연산에 대한 부담을 줄이고 LLM 연산을 위한 스케줄링이나 다른 연산에 자원을 집중할 수 있습니다. 이외에도 AI 네오 클라우드에서 필수적인 데이터 암호화 기능도 DPU에서 가속하여 confidential computing 환경을 구축하는데 도움을 줍니다.\n정리 오늘은 LLM의 새로운 병목인 저장소 문제와 함께 이를 해결하기 위한 NVIDIA의 새로운 플랫폼 ICMS, 이를 관리하는 새로운 프로세서인 DPU와 DPU에서 구동하는 소프트웨어 프레임워크들에 대해 알아보았습니다. 이를 통해 NVIDIA가 GPU에서 활용하는 메모리를 플래시 메모리까지 확장하기 위해 사용한 하드웨어/소프트웨어적 기술들을 엿볼 수 있었습니다.\n그런데, 이 플래시 메모리를 칩 바로 옆에 두면 더 빠르게 쓸 수 있지 않을까요? 최근 부상하고 있는 HBF(High Bandwidth Flash)가 이를 가능하게 하는 기술입니다. HBF는 신기술 트렌드를 다루는 다른 시리즈에서 다뤄보겠습니다.\n다음 글에서는 주제를 가속기로 다시 가져가 보겠습니다. OpenAI의 코드 생성 모델 Codex-Spark를 서비스하며 주목받은 기업이죠. 웨이퍼 한 장 크기의 거대한 칩을 만드는 AI 가속기 스타트업 Cerebras와 Wafer Scale Engine에 대해 알아보겠습니다.\n추신 : HyperAccel은 채용 중입니다. HyperAccel은 데이터센터향 LPU 첫 제품 출시를 목전에 두고 있으며, 하드웨어/소프트웨어 최적화를 통해 LLM 추론의 핵심 병목들을 해소할 수 있는 솔루션을 개발해 나가고 있습니다.\n저희의 기술적 여정에 흥미가 있으시다면, HyperAccel Career를 통해 지금 바로 지원해 주세요!\nHyperAccel은 여러분의 지원을 기다립니다.\nReference CES 2026 Jensen Huang Keynote LMCache KV Cache Calculator Inside the NVIDIA Rubin Platform Introducing Bluefield-4 powered ICMS LMCache: An Efficient KV Cache Layer for Enterprise-Scale LLM Inference CacheBlend: Fast Large Language Model Serving for RAG with Cached Knowledge Fusion NVIDIA Dynamo LMCache integration ","permalink":"https://hyper-accel.github.io/posts/nvidia-icms-dpu/","summary":"LLM의 새로운 병목인 KV 캐시 용량 문제를 해결하기 위해 NVIDIA가 제시한 새로운 계층의 스토리지인 ICMS와 이를 관리하는 Bluefield-4 DPU의 기술적 원리를 살펴봅니다.","title":"지피지기면 백전불태 4편 : 메모리 용량 병목과 NVIDIA ICMS"},{"content":"Copy \u0026amp; Paste에서 자율 코딩 에이전트까지: 조용한 변화의 시작 안녕하세요, 하이퍼엑셀 ML 팀 엔지니어 엄태서입니다.\n개발자들 사이에는 이런 농담이 있습니다. “우리 일은 결국 문제를 구글에 검색하고, 첫 번째로 뜨는 링크를 눌러서, Stack Overflow에서 답을 복사해 붙여넣는 거 아니냐?” 어떤 면에서는 AI 코딩 도구의 등장이 우리가 하는 일을 완전히 바꾼 건 아닙니다. 다만 그 일을 훨씬 더 잘, 훨씬 더 빠르게 하게 만들었죠. 지난 몇 달 동안 우리 팀은 AI 보조 개발의 거의 모든 물결을 직접 타 봤습니다. 초기의 단발성 상호작용부터, 지금은 사실상 일상적으로 의존하는 자율 에이전트까지요. 이 글에서는 그 여정이 어떤 모습이었는지, 무엇을 배웠는지, 그리고 앞으로 어디로 향하고 있다고 생각하는지 정리해 보려고 합니다.\n초창기: AI는 더 똑똑한 검색 엔진이었다 대형 언어 모델(LLM)이 처음 대중에게 열렸을 때, 특히 개발자들에게는 “정답”이나 “정석”이 없었습니다. 대부분 사람들은 LLM을 친구, 선생님, 개인 상담가, 혹은 그냥 새로운 검색 엔진처럼 다양하게 사용했죠. 그럼 개발자들은 어땠을까요? 초창기 사용 사례는 솔직히 말해 조금 민망할 정도로 단순했습니다. 에러 메시지를 복사해서 ChatGPT에 붙여넣고, 유용한 답이 나오길 기대하는 것 이였죠.\n그 경험은 “대화형 Stack Overflow”에 가까웠지만, 놀랍게도 꽤 잘 작동했습니다. 예전에는 forum thread를 한참 스크롤하면서 “내 Python 버전과 정확히 맞는 답” 하나를 찾기 위해 시간을 썼다면, 이제는 몇 초 만에 상황에 맞춘 설명을 받을 수 있으니까요.\n그 다음부터는 사용경험이 자연스럽게 확장됐습니다. 개발자들은 문법 질문을 하고, 코드 snippet을 요청하고, 익숙하지 않은 API에 대한 설명을 받기 시작했습니다. 이때의 멘탈 모델은 여전히 “내가 특정 질문을 하면, 내 상황에 맞는 답을 준다”에 가까웠습니다. 하지만 미묘한 변화가 이미 진행되고 있었죠. 모델이 컨텍스트를 유지할 수 있다는 걸 깨닫자, 더 큰 코드 덩어리(때로는 파일 전체)를 넣고 아키텍처, 디자인 패턴, 디버깅 전략 같은 상위 레벨의 질문을 하기 시작했습니다. 아직 AI가 모든 코드를 쓰는 단계는 아니었지만, 점점 꽤 유능한 페어 프로그래밍 파트너가 되어가고 있었습니다. (무엇보다… 어떠한 질문을 해도 덜 민망한 상대였죠.)\n탭 자동완성이 모든 것을 바꿨다 진짜 변곡점은 GitHub Copilot, Cursor 같은 도구들이 등장하면서였습니다. IDE 자동완성은 수십 년 전부터 존재했지만, 이건 근본적으로 달랐습니다. 변수명이나 메서드 시그니처를 제안하는 수준이 아니라, 코드 logic 전체를 예측하기 시작했으니까요. 뭔가를 조금 입력하거나, 심지어 주석 한 줄만 적어도 나머지가 마치 마법처럼 나타났습니다. Tab을 누르고, 수락하고, 넘어갑니다. (가끔은 “잊어버리고” 계속 진행하죠.)\n이 변화가 코딩의 리듬을 얼마나 바꿨는지는 과장하기 어렵습니다. 보일러플레이트, 반복 패턴, 표준 구현을 작성하는 시간이 분 단위에서 초 단위로 줄었습니다. 개발자들은 더 빨라졌고, 더 중요한 변화는 플로우(flow) 상태를 더 오래 유지하게 되었다는 점입니다. 문서나 검색 엔진으로 이동하며 컨텍스트가 끊기던 마찰이 거의 사라졌습니다.\n그리고 그 다음은 “에이전트적인 경험(agentic experience)”의 등장입니다. Cursor 같은 도구들은 단순 자동완성을 넘어 더 야심찬 방향으로 진화했습니다. 자연어로 문제를 설명하면 LLM/IDE가 코드베이스를 훑고, 관련 파일을 찾아내고, 여러 곳에 걸친 변경을 제안한 뒤, 내가 검토하고 수락하길 요청합니다. 개발자의 역할은 “코드를 작성하는 사람”에서 “코드를 지시하고 검토하는 사람”으로 이동하기 시작했습니다. 마치 레포지토리를 밀리초 단위로 읽고 (거의) 전부 다 이해해버리는 주니어 엔지니어가 생긴 느낌이랄까요.\nCLI 에이전트와 구조화된 AI 워크플로우의 부상 IDE 통합 도구들이 강력하긴 했지만, 우리는 곧 한계를 느꼈습니다. 구조(Structure)가 부족했던 겁니다. Cursor가 rules(룰)이라는 개념—코딩 표준, 코멘팅 컨벤션, 일반 정보 등을 정의하는 마크다운 파일—을 도입했을 때 우리 팀도 바로 도입했습니다. 거의 모든 레포지토리에 룰 파일을 추가해, AI 보조 도구를 사용하더라도 최소한 팀 표준을 따르는 코드가 나오게 만들었죠. 단순한 아이디어였지만 효과는 상당했습니다.\n다음 도약은 MCP(Model Context Protocols)였습니다. MCP는 AI 도구가 외부 데이터 소스에 연결될 수 있게 해줍니다. 갑자기 에이전트가 Confluence 문서에서 컨텍스트를 가져오고, 내부 문서를 이해하고, 코드 밖에 있던 설계 의사결정까지 참조할 수 있게 된 겁니다. AI는 이제 코드만 읽는 게 아니라 조직의 지식(기관 기억, institutional knowledge) 을 읽기 시작했습니다.\n하지만 “AI로 생산성을 올려보자”라는 우리 팀의 엔진에 진짜 로켓 부스터를 단 건 Claude Code였습니다. Claude Code는 skills(스킬)이라는 개념을 도입했는데, 이는 정적인 rules를 훨씬 뛰어넘는 구조화된 다단계 워크플로우입니다. 저희 팀 레포 중 하나에서는 이제 .claude 디렉토리를 두고, 계획 수립, 기능 구현, 테스트 작성, PR 오픈, PR 리뷰 코멘트 가져와 반영하기 같은 스킬들을 관리하고 있습니다. 또한 플랫폼에 특화된 하드웨어 제약, 팀이 trial and error로 배운 안티패턴, SDK별 컨벤션 같은 것도 스킬 또는 Claude Code rules로 녹여두었습니다.\n저희가 사용해 온 Claude Code skills 파일을 어떻게 만들었는지, 그리고 기타 Claude Code 활용 사례를 어떻게 최적화했는지에 대한 자세한 내용은 향후 블로그 게시물에서 심도 있게 다룰 예정입니다.\n룰 파일과 스킬의 차이는, 스타일 가이드와 “훈련된 동료”의 차이에 가깝습니다. 룰은 “pytest를 써라, unittest는 쓰지 마라”라고 말합니다. 스킬은 “이 유형의 모듈에 맞는 테스트 스위트를 작성하고, 실행하고, 실패하면 최대 다섯 번까지 자동 수정하고, 결과를 요약 보고하라”라고 말합니다.\n/implement-tested, /pr-review, /open-pr 같은 스킬은 과거에 몇 시간이 걸리던 작업들을, 인간의 감독 하에 몇 분 단위의 작업으로 바꿔놓았습니다.\n기존에도 LLM을 활용해 코드 생성을 시도해 왔지만, 대부분은 “한 번의 요청–한 번의 응답” 구조에 머물러 있었습니다. Claude Code의 skills는 계획 → 구현 → 테스트 → 수정 → 보고까지 이어지는 실행 흐름 전체를 하나의 재사용 가능한 단위로 구조화할 수 있었고, 특히 반복적이지만 인지 부하가 큰 작업을 안정적으로 압축해 주었다는 점에서 체감 생산성에 큰 차이를 만들었습니다.\n코드 리뷰 병목: 아무도 경고해주지 않았던 부분 아무도 미리 말해주지 않았던 문제가 있습니다. AI와 에이전트 도구들이 개발자를 엄청나게 빠르게 만들었습니다. 하루 걸리던 PR이 한 시간 만에 열리기 시작했죠. 그런데 코드 리뷰—사람이 꼼꼼히 읽고 이해하고 검증해야 하는 단계—는 빨라지지 않았습니다. 오히려 병목은 더 심해졌습니다. 코드 생산 속도가 빨라질수록 리뷰 대기열이 길어지고, 진짜 개발 속도는 저희가 기대한 만큼 늘지 않았습니다.\nGitHub PR에서 AI를 활용해 surface-level 문제들을 잡는 데 도움을 받았지만, 더 근본적인 질문은 남았습니다. 더 높은 속도에서 품질을 어떻게 유지할 것인가?\n그 질문에 대한 답은 계속 진화 중이지만, 최근에는 이런 workflow 모델로 움직이고 있습니다. AI 에이전트가 코드를 작성하기 전에 먼저 plan.md 파일을 생성합니다. 이는 접근 방식, 변경할 파일들, 각 결정의 이유를 구조적으로 담은 문서입니다. 이후 사람 리뷰어는 구현 코드의 모든 라인을 샅샅이 보는 대신 계획(plan)을 리뷰합니다. 핵심 제약은 변경된 코드가 포괄적인 test suite를 통과해야 한다는 점입니다. 이렇게 하면 정확성의 부담이 라인 단위 리뷰에서 테스트 커버리지로 이동하고, 결과적으로 “좋은 테스트”의 중요성이 그 어느 때보다 커집니다.\n다만 여기에는 결정적인 단서가 있습니다. 새 테스트를 만들거나 기존 테스트 코드를 수정하는 작업은 반드시 사람이 리뷰해야 합니다. 테스트는 plan 기반 리뷰 모델을 신뢰할 수 있게 만드는 계약(Contract)입니다. 테스트가 약하거나 잘못되면 워크플로우 전체가 무너집니다. 그래서 구현 코드에 대해서는 점진적으로 더 ‘가벼운’ 리뷰 전략을 도입하려고 하지만, 테스트 코드는 여전히 신중한 인간 판단의 영역으로 남겨두고 있습니다.\n미래는 어떻게 될까? 저희 팀, 저희 회사뿐만 아니라, 저는 전 세계가 아직도 초기 단계에 있다고 믿습니다. 도구는 매달 좋아집니다. 아니, 솔직히 말해 매일 좋아집니다. AI 워크플로우가 안정화되는 것 같다가도, 언제나 또 다른 변화가 찾아옵니다. 개발자로서 중요한 건 이 변화들을 계속 주시하고, 계속 적응하는 것입니다. 적응할 준비가 되어 있지 않다면, 뒤처지게 됩니다. 세상에서 가장 뛰어난 프로그래머일지라도, AI 도구를 “어떻게 활용해야 하는지”를 아는 사람이 훨씬 빠르게 앞질러갈 수도 있습니다. 우리 팀은 AI 도구가 현재이자 미래라는 점을 이해하고 매우 열린 태도를 갖고 있고, 그 공통된 믿음 덕분에 팀의 개발 속도는 실제로 가속되고 있습니다.\n우리가 보는 미래는 이렇습니다. AI 에이전트가 점점 더 복잡한 일을 처리하고, 우리는 그저 “빨리 되는 것”이 아니라 빠르게 진행되면서도 제대로 되고 있는지를 확인하는 역할에 더 집중하게 될 겁니다. 사람들은 항상 “이 모델의 컨텍스트 길이”를 이야기합니다. 물론 중요합니다. 하지만 현장에서 이 도구들을 활용해 ‘더러운 일’을 맡기는 개발자 입장에서는 우리가 컨텍스트 마스터가 되어야 합니다. 큰 그림을 완전히 이해하고, 가장 작은 디테일까지 놓치지 않으며, 무엇을 해야 하는지 의도를 정의하고, 아키텍처를 검증하고, 테스트 스위트를 큐레이션하며, 빠르고 중요한 판단을 내리는 사람 말이죠.\n결국 인간의 역할은 코드를 쓰고 검토하는 것에서, 의도를 정의하고, 아키텍처를 검증하고, 테스트를 관리하고, 중요한 판단을 빠르게 내리는 것으로 계속 이동할 것입니다.\n앞으로 성공할 팀은 지금부터 이런 기반에 투자하는 팀입니다. 잘 구조화된 스킬 정의, 포괄적인 테스트 커버리지, 명확한 아키텍처 문서화, 그리고 AI 툴을 지름길이 아니라 새로운 규율을 요구하는 증폭기 (force multiplier)로 받아들이는 문화요.\n우리는 개발자를 대체하는 게 아닙니다. 개발자라는 직업의 의미를 다시 정의하고 있을 뿐입니다.\nUpcoming\u0026hellip; 이번 글은 전체적인 방향성과 문제의식을 공유하는 인트로 성격의 글로 생각하며 공유드렸습니다. 이후에는 Skills, Kernel Agent, 그리고 기타 AI 도구 활용 사례에 대해 각각 별도의 글로 나누어, 사용 방법뿐 아니라 내부적으로 어떻게 설계하고 최적화했는지까지 상세히 정리해 글을 올리도록 하겠습니다.\nHyperAccel 내부적으로 AI가 워크플로우에 자연스럽게 통합되는 방식을 끊임없이 탐색하고 있습니다. 그 과정에서 우리는 “코드를 개발하는 방식”이 근본적으로 변화하고 있는 이 새로운 패러다임 속을 항해하고 있습니다. 앞으로도 그 시행착오와 인사이트를 계속 공유하겠습니다.\nHyperAccel 채용 중! 사실 우리가 이 테크 블로그를 운영하는 큰 이유 중 하나는 최고의 인재를 끌어오기 위해서입니다!\n저희가 다루는 기술에 관심이 있고, 이 혁신의 흐름에 함께하고 싶다면 아래 링크에서 지원해 주세요. HyperAccel Career\nHyperAccel에는 뛰어난 엔지니어들이 가득합니다. 함께할 날을 기다리고 있겠습니다.\n","permalink":"https://hyper-accel.github.io/posts/how-we-use-ai/","summary":"\u003ch1 id=\"copy--paste에서-자율-코딩-에이전트까지-조용한-변화의-시작\"\u003eCopy \u0026amp; Paste에서 자율 코딩 에이전트까지: 조용한 변화의 시작\u003c/h1\u003e\n\u003cp\u003e안녕하세요, 하이퍼엑셀 ML 팀 엔지니어 엄태서입니다.\u003c/p\u003e\n\u003cp\u003e개발자들 사이에는 이런 농담이 있습니다. “우리 일은 결국 문제를 구글에 검색하고, 첫 번째로 뜨는 링크를 눌러서, Stack Overflow에서 답을 복사해 붙여넣는 거 아니냐?”\n어떤 면에서는 AI 코딩 도구의 등장이 우리가 하는 일을 완전히 바꾼 건 아닙니다. 다만 \u003cstrong\u003e그 일을 훨씬 더 잘, 훨씬 더 빠르게\u003c/strong\u003e 하게 만들었죠. 지난 몇 달 동안 우리 팀은 AI 보조 개발의 거의 모든 물결을 직접 타 봤습니다. 초기의 단발성 상호작용부터, 지금은 사실상 일상적으로 의존하는 \u003cstrong\u003e자율 에이전트\u003c/strong\u003e까지요. 이 글에서는 그 여정이 어떤 모습이었는지, 무엇을 배웠는지, 그리고 앞으로 어디로 향하고 있다고 생각하는지 정리해 보려고 합니다.\u003c/p\u003e","title":"Copy \u0026 Paste에서 코딩 에이전트까지: 조용한 변화의 시작"},{"content":"안녕하세요. HyperAccel ML팀에서 재직중인 김남윤입니다.\n1편에서 Kubernetes 기반 개발 환경 구축의 배경과 전체적인 설계 방향을 다루었습니다. 이번 글에서는 그 연장선에서 CI/CD 인프라를 어떻게 재설계했는지에 대해 이야기합니다.\n개발 환경이 Kubernetes 위로 올라간 이상, CI/CD 파이프라인 역시 같은 환경 위에서 운영하는 것이 아키텍처적으로 일관된 선택입니다. 이 글에서는 기존 Self-hosted Runner가 왜 장기적으로 지속 불가능했는지를 구조적으로 분석하고, ARC(Actions Runner Controller)를 도입하면서 내린 핵심 기술적 의사결정들 — DinD 모드와 Kubernetes 모드의 선택 기준, Rook-Ceph 기반 Ephemeral PVC 전략, Vault를 통한 Secret 생명주기 관리, 그리고 자체 개발한 GitHub Actions Exporter를 통한 파이프라인 관측성(Observability) 확보까지를 다룹니다.\nSelf-hosted Runner의 구조적 한계 기존에는 서버에 Docker 컨테이너로 Self-hosted Runner를 직접 설치하여 운영했습니다. 러너의 라벨은 호스트명(예: ha-xxx)으로 지정하고, GPU 테스트 워크플로우에서는 --all-gpu 플래그를 통해 해당 서버의 GPU 전체를 사용하는 방식이었습니다.\nGitHub의 Hosted Runner(ubuntu-latest 등)를 사용하지 않은 이유는 다음과 같습니다.\n하드웨어 종속성: FPGA 및 GPU 기반 테스트는 해당 디바이스가 물리적으로 장착된 노드에서만 실행 가능 네트워크 격리: 사내 Harbor 레지스트리, Vault 서버 등 내부 인프라에 외부 Runner에서 접근 불가 이미지 전송 비용: 수 GB 단위 Docker 이미지의 외부 build/push/pull 순환은 네트워크 대역폭과 시간 양쪽에서 비효율적 Self-hosted Runner로 이러한 제약은 해결했지만, 시간이 지나면서 이 구조 자체의 근본적인 문제가 드러났습니다.\n첫째, 서버와 워크플로우의 강결합. 러너 라벨이 호스트명에 종속되어 있으므로, 서버 교체나 이름 변경 시 해당 서버를 참조하는 모든 워크플로우를 수정해야 합니다. 또한 --all-gpu와 같은 플래그 방식은 동시에 두 개의 Job이 같은 서버에 스케줄링될 때 GPU 자원 경합을 제어할 수 없어, 한쪽 Job이 예측 불가능하게 실패하는 문제가 있었습니다.\n둘째, 실행 환경의 오염. Runner 프로세스가 호스트 OS 위에서 직접 실행되므로, 빌드 A에서 설치한 패키지나 변경한 시스템 설정이 빌드 B의 동작에 영향을 미칩니다. 이는 빌드 결과의 재현성을 보장할 수 없다는 의미이며, CI 파이프라인의 근본적인 목적을 훼손합니다.\n셋째, 탄력적 스케일링의 부재. 동시 실행이 필요한 워크플로우 수는 시간대별로 크게 변동하지만, 서버에 고정 설치된 Runner 수는 정적입니다. Runner를 과소 프로비저닝하면 큐 대기 시간이 증가하고, 과다 프로비저닝하면 유휴 자원이 낭비됩니다.\n이 세 가지 문제는 모두 Runner가 Kubernetes의 스케줄링 및 라이프사이클 관리 체계 밖에 존재하기 때문에 발생합니다. Kubernetes 클러스터가 이미 구축되어 있는 환경에서, Runner를 Pod으로 전환하여 클러스터의 제어 하에 두는 것이 논리적으로 맞다고 판단했습니다.\nARC(Actions Runner Controller)의 아키텍처 ARC는 GitHub이 공식으로 지원하는 Kubernetes Operator로, Self-hosted Runner의 전체 라이프사이클을 Kubernetes 위에서 관리합니다. ARC의 아키텍처를 이해하기 위해서는 AutoScalingRunnerSet CRD(Custom Resource Definition)를 중심으로 살펴볼 필요가 있습니다. 이 리소스가 Runner의 생성, 스케일링, 삭제를 제어하는 핵심입니다.\n동작 흐름 Listener Pod이 GitHub Actions Service와 HTTPS Long Poll 연결을 유지하며 새로운 Job을 감시합니다. 이 연결은 Webhook이 아닌 Polling 방식이므로, 별도의 인바운드 네트워크 설정이 불필요합니다.\nJob이 감지되면 Listener는 Kubernetes API를 통해 EphemeralRunnerSet의 replica count를 patch하여 스케일 업을 요청합니다.\nEphemeralRunner Controller가 JIT(Just-in-Time) 구성 토큰을 발급받아 Runner Pod을 생성하고, 해당 Pod은 GitHub Actions Service에 자신을 등록합니다.\nJob 실행이 완료되면 EphemeralRunner Controller가 GitHub API를 확인한 후 파드를 삭제합니다. 이 일회성(ephemeral) 실행 모델은 이전 빌드의 잔여물이 다음 빌드에 영향을 미치는 문제를 원천적으로 차단합니다.\n용도별 AutoScalingRunnerSet 설계 HyperAccel의 CI 워크로드는 범용 빌드, FPGA 합성, GPU 테스트 등 필요 자원의 스펙트럼이 넓습니다. 이를 반영하여 용도별로 7개의 AutoScalingRunnerSet을 배포하고 있습니다.\n$ kubectl get autoscalingrunnerset -n arc-systems NAME MIN MAX CURRENT RUNNING runner-base 1 10 1 1 # DinD 모드 runner-cpu 1 10 3 3 # Kubernetes 모드 runner-cpu-largememory 1 10 1 1 # Kubernetes 모드 runner-fpga 1 3 1 1 # Kubernetes 모드 runner-gpu 1 3 1 1 # Kubernetes 모드 runner-highcpu 1 10 1 1 # Kubernetes 모드 runner-hybrid 1 4 1 1 # Kubernetes 모드 각 Scale Set은 nodeAffinity 또는 tolerations를 통해 적합한 노드에만 스케줄링됩니다.\nrunner-gpu: nvidia.com/gpu.present=true 라벨이 있는 GPU 노드에 배치 runner-fpga: FPGA가 장착된 특정 노드에만 배치 runner-cpu / runner-cpu-largememory: ci=large-memory 라벨 노드에 배치 워크플로우에서는 runs-on 키에 Scale Set 이름을 지정하여 원하는 Runner를 선택합니다.\njobs: gpu-test: runs-on: runner-gpu # GPU Runner 선택 fpga-synth: runs-on: runner-fpga # FPGA Runner 선택 build: runs-on: runner-cpu # 범용 CPU Runner 선택 주목할 점은 runner-base만 DinD 모드를 사용하고, 나머지 6개는 모두 Kubernetes 모드를 사용한다는 것입니다. 이 두 모드의 차이는 ARC 운영에서 가장 중요한 아키텍처적 결정 중 하나입니다.\nDinD 모드 vs Kubernetes 모드: 아키텍처적 차이 ARC에서 Runner Pod이 컨테이너를 실행해야 하는 경우(워크플로우의 container: 키 또는 컨테이너 액션), DinD(Docker-in-Docker) 모드와 Kubernetes 모드 두 가지 방식을 제공합니다. 이 두 모드는 컨테이너 실행의 메커니즘, 볼륨 관리, 보안 모델이 근본적으로 다릅니다.\nDinD 모드 (runner-base) Runner Pod 내부에 Docker 데몬을 Sidecar 컨테이너로 실행하는 방식입니다. HyperAccel에서는 runner-base가 이 모드로 운영됩니다.\n# runner-base의 핵심 설정 (DinD 모드) spec: containers: - name: runner env: - name: DOCKER_HOST value: unix:///var/run/docker.sock - name: RUNNER_WAIT_FOR_DOCKER_IN_SECONDS value: \u0026#34;120\u0026#34; volumeMounts: - mountPath: /var/run name: dind-sock # Docker 소켓 공유 - mountPath: /home/runner/_work name: work initContainers: - name: init-dind-externals # Runner externals 복사 command: [\u0026#34;cp\u0026#34;] args: [\u0026#34;-r\u0026#34;, \u0026#34;/home/runner/externals/.\u0026#34;, \u0026#34;/home/runner/tmpDir/\u0026#34;] - name: dind # Docker 데몬 (Sidecar) image: docker:dind securityContext: privileged: true # ⚠️ Privileged 필수 restartPolicy: Always args: [\u0026#34;dockerd\u0026#34;, \u0026#34;--host=unix:///var/run/docker.sock\u0026#34;] volumeMounts: - mountPath: /var/run name: dind-sock - mountPath: /home/runner/externals name: dind-externals volumes: - name: dind-sock emptyDir: {} # 휘발성 볼륨 - name: dind-externals emptyDir: {} - name: work emptyDir: {} DinD 모드의 구조적 특징은 다음과 같습니다.\n첫째, docker:dind 이미지가 initContainers에서 restartPolicy: Always로 실행되어 Sidecar 패턴으로 동작합니다. Runner 컨테이너는 DOCKER_HOST 환경변수를 통해 이 Docker 데몬의 Unix 소켓에 접근합니다.\n둘째, Docker 데몬이 컨테이너 레이어 관리, 이미지 pull, 네트워크 생성을 모두 Pod 내부에서 수행하므로, 노드의 containerd 이미지 캐시를 활용하지 못합니다. 이미 노드에 캐시된 이미지라 하더라도 DinD 데몬이 별도로 다시 pull해야 합니다.\n셋째, Docker 데몬 실행을 위해 privileged: true가 필수입니다. 이는 Pod에게 호스트의 거의 모든 커널 기능에 대한 접근 권한을 부여하므로, 보안 정책이 엄격한 환경에서는 신중한 판단이 필요합니다.\n넷째, 모든 볼륨이 emptyDir로 구성되어 있어 Pod이 삭제되면 데이터가 함께 사라집니다. Docker 빌드 캐시 역시 보존되지 않습니다.\nKubernetes 모드 (runner-cpu, runner-gpu, runner-fpga 등) Runner Pod이 Kubernetes API를 호출하여 워크플로우의 컨테이너 Step을 별도의 Pod으로 생성하는 방식입니다. ARC의 Container Hook(runner-container-hooks)이 이 과정을 중개합니다.\n# runner-cpu의 핵심 설정 (Kubernetes 모드) spec: containers: - name: runner env: - name: ACTIONS_RUNNER_CONTAINER_HOOKS value: /home/runner/k8s/index.js - name: ACTIONS_RUNNER_CONTAINER_HOOK_TEMPLATE value: /home/runner/k8s/worker-podspec.yaml - name: ACTIONS_RUNNER_REQUIRE_JOB_CONTAINER value: \u0026#34;true\u0026#34; volumeMounts: - mountPath: /home/runner/_work name: work - mountPath: /home/runner/k8s/worker-podspec.yaml name: hook-template subPath: worker-podspec.yaml volumes: - name: work ephemeral: volumeClaimTemplate: # Ephemeral PVC spec: accessModes: [\u0026#34;ReadWriteOnce\u0026#34;] storageClassName: rook-ceph-block resources: requests: storage: 15Gi - name: hook-template configMap: name: arc-hook-cpu # worker-podspec ConfigMap Kubernetes 모드의 핵심 메커니즘은 다음과 같습니다.\nACTIONS_RUNNER_CONTAINER_HOOKS는 Container Hook의 진입점(index.js)을 지정합니다. 워크플로우에서 container: 키를 사용하면, Runner가 직접 실행하는 대신 이 Hook이 Kubernetes API를 호출하여 별도의 Workflow Pod을 생성합니다.\nACTIONS_RUNNER_CONTAINER_HOOK_TEMPLATE는 생성될 Workflow Pod의 스펙 템플릿(worker-podspec.yaml)을 지정합니다. 이 템플릿은 ConfigMap으로 관리되며, Runner 유형별로 다른 ConfigMap을 참조합니다(arc-hook-cpu, arc-hook-gpu, arc-hook-fpga 등).\nACTIONS_RUNNER_REQUIRE_JOB_CONTAINER=true는 모든 Job이 반드시 container: 키를 통해 컨테이너 내에서 실행되도록 강제합니다. 이를 통해 Runner Pod 자체에서 직접 작업이 실행되는 것을 방지합니다.\n실제로 Job이 실행되면 Runner Pod 외에 별도의 Workflow Pod이 생성됩니다.\n$ kubectl get pods -n arc-systems | grep runner-cpu-hh7xv runner-cpu-hh7xv-runner-4tvrs 1/1 Running 0 9h # Runner Pod runner-cpu-hh7xv-runner-4tvrs-workflow 1/1 Running 0 4m # Workflow Pod (Container Hook) 두 모드의 구조적 비교 항목 DinD 모드 (runner-base) Kubernetes 모드 (runner-cpu 등) 컨테이너 실행 Pod 내부 Docker 데몬 Kubernetes API로 별도 Pod 생성 Privileged 모드 필수 (Docker 데몬) 선택적 (worker-podspec에서 결정) 이미지 캐시 DinD 내부에 격리 (노드 캐시 미활용) 노드의 containerd 캐시 공유 작업 볼륨 emptyDir (휘발성) Ephemeral PVC (rook-ceph-block, 15Gi) Step 격리 동일 Docker 네트워크 Step별 독립 Pod 가능 Docker CLI 완전 호환 비호환 (Container Hook 경유) 설정 복잡도 낮음 높음 (worker-podspec, RBAC 등) 적합한 워크로드 Docker build/push 필요 시 컨테이너 내 빌드/테스트 runner-base를 DinD 모드로 유지하는 이유는, Docker CLI를 직접 사용해야 하는 워크플로우(이미지 빌드, 레지스트리 push 등)가 존재하기 때문입니다. Kubernetes 모드에서는 Docker 데몬이 없으므로 docker build를 직접 실행할 수 없습니다.\n볼륨 전략: Ephemeral PVC와 캐시 계층 Runner의 볼륨 설계는 빌드 성능과 안정성에 직접적인 영향을 미칩니다. DinD 모드와 Kubernetes 모드에서 볼륨 전략이 질적으로 다릅니다.\nDinD 모드의 볼륨: emptyDir # runner-base의 볼륨 (DinD 모드) volumes: - name: dind-sock # Docker 소켓 공유 (Runner ↔ DinD 데몬) emptyDir: {} - name: dind-externals # Runner externals 복사본 emptyDir: {} - name: work # 워크스페이스 (checkout, 빌드 산출물) emptyDir: {} - name: harbor-ca # Harbor CA 인증서 configMap: name: harbor-ca 모든 작업 볼륨이 emptyDir이므로 Pod 삭제 시 데이터가 소멸합니다. Docker 빌드 캐시도 유지되지 않기 때문에, 이전 빌드에서 캐시된 레이어를 재사용할 수 없습니다 — 이는 대규모 이미지 빌드에서 불리한 구조입니다.\nKubernetes 모드의 볼륨: Ephemeral PVC + 캐시 계층 # runner-cpu의 볼륨 (Kubernetes 모드) volumes: - name: work ephemeral: volumeClaimTemplate: spec: accessModes: [\u0026#34;ReadWriteOnce\u0026#34;] storageClassName: rook-ceph-block # Ceph 블록 스토리지 resources: requests: storage: 15Gi # Runner당 15Gi - name: hook-template configMap: name: arc-hook-cpu # worker-podspec 템플릿 Kubernetes 모드에서는 작업 디렉토리(/home/runner/_work)에 Ephemeral PVC를 사용합니다. emptyDir과 달리 Rook-Ceph 블록 스토리지를 백엔드로 하므로 노드 로컬 디스크 상태에 무관하게 안정적인 I/O를 제공하며, Runner당 15Gi의 전용 볼륨이 할당됩니다. Ephemeral PVC는 Runner Pod의 라이프사이클에 종속되어 Pod 삭제 시 함께 삭제되므로, 스토리지 누수 없이 일관된 운영이 가능합니다.\nworker-podspec의 캐시 볼륨 전략 Container Hook이 생성하는 Workflow Pod에는 추가적인 캐시 볼륨이 마운트됩니다. 이 설정은 각 Runner 유형별 ConfigMap(arc-hook-cpu, arc-hook-gpu 등)의 worker-podspec.yaml에 정의됩니다.\n# arc-hook-cpu ConfigMap (worker-podspec.yaml) — 일부 발췌 spec: containers: - name: \u0026#34;$job\u0026#34; env: - name: HF_HOME value: /mnt/cache/huggingface - name: CCACHE_DIR value: /mnt/cache/ccache - name: UV_CACHE_DIR value: /mnt/cache/uv resources: limits: cpu: \u0026#34;32\u0026#34; memory: \u0026#34;128Gi\u0026#34; volumeMounts: - name: huggingface-cache mountPath: /mnt/cache/huggingface - name: ccache-cache mountPath: /mnt/cache/ccache - name: uv-cache mountPath: /mnt/cache/uv volumes: - name: huggingface-cache persistentVolumeClaim: claimName: huggingface-runner-pvc # NFS (모든 Runner 공유) - name: ccache-cache hostPath: path: /tmp/ccache # 노드 로컬 캐시 - name: uv-cache hostPath: path: /tmp/uv # 노드 로컬 캐시 볼륨 전략을 계층별로 정리하면 다음과 같습니다.\n계층 볼륨 유형 용량 생명주기 용도 작업 디렉토리 Ephemeral PVC (rook-ceph-block) 15Gi / Runner Pod 종속 checkout, 빌드 산출물 모델 캐시 PVC (huggingface-runner-pvc) 영구 (모든 Runner 공유) HuggingFace 모델, 데이터셋 빌드 캐시 hostPath 노드 디스크 노드 종속 ccache, uv 패키지 캐시 특히 huggingface-runner-pvc는 모든 Runner가 공유하는 PVC로, 수 GB 단위의 LLM 모델을 매 빌드마다 다운로드하는 것을 방지합니다. ccache와 uv 캐시는 hostPath를 사용하여 같은 노드에 스케줄링된 Runner 간에 공유됩니다.\n단, hostPath 캐시는 동일 노드에 복수의 Runner가 동시 실행될 경우 lock 경합이 발생할 수 있습니다. 실제로 uv 캐시에서 이 문제를 경험했으며, UV_CACHE_DIR 환경변수로 Runner별 캐시 경로를 분리하여 해결했습니다.\nVault: Secret 생명주기 관리 CI/CD 파이프라인에서 Secret(Registry 인증 정보, API 키, 서명 키 등)의 관리는 보안과 운영 양쪽에서 중요한 문제입니다.\nGitHub Secrets의 한계 GitHub의 Repository Secrets, Organization Secrets는 소규모 환경에서는 충분합니다. 그러나 레포지터리가 수십 개로 확장되면 다음과 같은 문제가 발생합니다.\n중복 관리: 동일 Secret을 여러 레포지터리에 각각 등록 → 로테이션 시 전수 업데이트 필요 이력 추적 부재: Secret의 마지막 갱신 시점, 변경 주체를 확인할 수 없음 권한 분리 불가: Secret 접근에 레포지터리 Admin 권한이 요구됨 Vault를 도입해야겠다고 생각한 가장 중요한 계기는 devcontainer 이미지 태그 관리였습니다. 기존에는 devcontainer 이미지 태그를 GitHub Repository Variables(vars.DEVCONTAINER_IMAGE_AIDA_CU126 등)로 관리했습니다. 새 이미지가 빌드될 때마다 담당 개발자가 수동으로 변수를 업데이트해야 했고, 이 과정에서 누락이 빈번하게 발생하여 오래된 이미지로 워크플로우가 실행되는 문제가 있었습니다. Vault 도입 후에는 CI 파이프라인이 빌드 완료 시 최신 이미지 태그를 Vault에 자동으로 기록하고, 후속 워크플로우와 Developer Portal이 needs.fetch-secrets.outputs를 통해 항상 최신 값을 참조하는 구조로 전환했습니다. 이미지 버전 정보를 사람이 관리/수정하는 과정이 완전히 제거됩니다.\nVault 도입과 인증 전략 HashiCorp Vault를 Kubernetes 클러스터에 배포하고, 접근 주체에 따라 서로 다른 Auth Method를 적용했습니다.\nARC Runner는 JWT Auth Method를 사용합니다. GitHub Actions의 OIDC provider가 발급하는 ID Token을 Vault에 제출하여 인증하는 방식입니다. 워크플로우에 permissions: id-token: write를 선언하면 GitHub이 OIDC 토큰을 자동으로 발급하고, hashicorp/vault-action이 이를 Vault에 전달합니다.\n# 워크플로우에서 Vault Secret 주입 (JWT Auth) permissions: id-token: write # GitHub OIDC 토큰 발급 허용 contents: read steps: - name: Import Secrets from Vault uses: hashicorp/vault-action@v3 with: url: ${{ secrets.VAULT_ACTION_URL }} method: jwt # GitHub OIDC JWT role: ${{ secrets.VAULT_ACTION_ROLE }} exportToken: true secrets: | secret/data/harbor username | HARBOR_USERNAME ; secret/data/harbor password | HARBOR_PASSWORD 반면 Developer Portal은 Kubernetes 클러스터 내부에서 직접 실행되는 Pod이므로, Kubernetes Auth Method를 통해 ServiceAccount 토큰으로 인증합니다. 이렇게 접근 주체의 특성에 맞는 Auth Method를 분리 적용함으로써, 각 경로의 보안 모델을 최적화할 수 있습니다.\n이 구조의 핵심적인 이점은 두 가지입니다.\n단일 관리 지점: Secret 로테이션 시 Vault에서 한 번만 변경하면 모든 파이프라인에 즉시 반영됩니다.\n감사 로그(Audit Log): 모든 Secret 접근에 대해 who, when, what이 기록되어 보안 감사 요구사항을 충족합니다.\nfetch-secrets: 재사용 워크플로우를 통한 Secret 중앙화 Vault를 도입했더라도, 각 워크플로우가 개별적으로 Vault 인증과 Secret 조회 로직을 구현한다면 중복 코드가 확산됩니다. 이를 방지하기 위해 fetch-secrets라는 재사용 워크플로우(GitHub Actions의 workflow_call)를 설계했습니다. Vault 인증(JWT)과 Secret 조회 로직을 이 워크플로우 한 곳에 캡슐화하고, 호출 측에서는 출력값만 참조하는 구조입니다.\n# docker-build-push.yml — 호출 측 jobs: fetch-secrets: uses: ./.github/workflows/fetch-secrets.yml # Vault 인증/조회를 위임 secrets: inherit build: needs: [fetch-secrets] steps: - name: Log in to Harbor uses: docker/login-action@v3 with: registry: ${{ needs.fetch-secrets.outputs.harbor_registry_url }} username: ${{ needs.fetch-secrets.outputs.harbor_username }} password: ${{ needs.fetch-secrets.outputs.harbor_password }} 빌드 워크플로우는 Vault의 존재조차 알 필요 없이, needs.fetch-secrets.outputs에서 필요한 값을 가져오기만 하면 됩니다. Vault의 Secret path가 변경되더라도 fetch-secrets.yml 한 곳만 수정하면 전체 파이프라인에 반영됩니다.\nGitHub Actions Exporter: 파이프라인 관측성 확보 CI/CD 인프라의 운영 성숙도를 높이기 위해서는 관측성(Observability)이 필수적입니다. GitHub Actions 웹 UI는 개별 워크플로우의 상태 확인에는 적합하지만, 여러 레포지터리에 걸친 전체적인 추세, 병목 지점, 이상 징후를 실시간으로 파악하기에는 한계가 있습니다.\n이를 해결하기 위해 GitHub Actions Exporter를 Go 언어로 자체 개발했습니다.\n개발 배경 기존 오픈소스 Exporter들이 제공하지 않았던 세 가지 메트릭이 필요했습니다.\n러너 레이블별 큐 대기 시간: ARC Runner와 Hosted Runner를 혼용하는 환경에서 병목 지점을 식별하기 위함 연속 실패 추적: 특정 워크플로우의 연속 실패를 실시간으로 감지하여 조기에 대응하기 위함 브랜치별 분석: main과 feature 브랜치의 빌드 패턴이 다르므로 분리된 분석이 필요 아키텍처와 주요 메트릭 GitHub REST API ──→ Collector ──→ /metrics endpoint │ Prometheus 스크랩 │ Grafana 대시보드 + AlertManager 메트릭 설명 활용 workflow_runs_total 워크플로우 총 실행 횟수 사용량 추이 분석 workflow_failure_rate 실패율 (0.0 ~ 1.0) 품질 모니터링 workflow_duration_seconds 실행 시간 히스토그램 성능 회귀 감지 workflow_queue_time_seconds 큐 대기 시간 Runner 부족 감지 workflow_consecutive_failures 연속 실패 횟수 즉각 알림 트리거 workflow_runs_in_progress 현재 실행 중 워크플로우 실시간 상태 파악 workflow_runs_by_branch_total 브랜치별 실행 횟수 브랜치 전략 분석 Kubernetes Deployment로 배포하고 Prometheus ServiceMonitor로 스크랩합니다. ARC의 Listener Pod에도 Prometheus 메트릭 annotation이 설정되어 있어, Runner 스케일링 관련 메트릭도 함께 수집됩니다.\n관측성을 통한 의사결정 대시보드를 통해 실제로 감지하고 대응한 사례들입니다.\n큐 대기 시간 급증: 특정 시간대에 동시 Job이 몰리면서 maxRunners 한도에 도달 → Scale Set의 최대 Runner 수를 조정 특정 워크플로우 실패율 50% 돌파: Docker 레이어 캐시 만료로 인한 빌드 실패 패턴 식별 → 캐시 전략 수정 빌드 시간의 점진적 증가: 테스트 케이스 증가로 30분 → 45분 소요 → 테스트 병렬화 적용 # 실패율 20% 초과 워크플로우 식별 github_actions_workflow_failure_rate \u0026gt; 0.2 # 큐 대기 60초 초과 — Runner 부족 징후 github_actions_workflow_queue_time_seconds_avg \u0026gt; 60 # 연속 실패 3회 이상 — 즉각 대응 필요 github_actions_workflow_consecutive_failures \u0026gt;= 3 인프라 운영 및 유지보수 자동화 구축된 인프라의 안정성과 최신성을 유지하기 위해 운영 작업을 자동화했습니다.\nVault 데이터 백업 Vault에 저장된 Secret과 정책(Policy)은 클러스터 장애 시 복구를 위해 필수적인 데이터입니다. 매주 일요일 오전, Raft 스냅샷을 생성하여 두 곳의 저장소(AWS S3, 사내 MinIO)에 이중으로 백업합니다. 오래된 백업은 Retention Policy(기본 6일)에 따라 자동으로 정리됩니다.\nARC 및 Runner 버전 추적 GitHub Actions Runner와 Container Hook은 지속적으로 업데이트됩니다. 매주 월요일, 최신 릴리스 버전을 확인하고 현재 버전을 비교하는 버전 추적 워크플로우가 실행됩니다. 새로운 버전이 감지되면 자동으로 PR을 생성하여 관리자에게 알림을 보내며, 이를 통해 Runner 환경을 항상 최신 상태로 유지할 수 있습니다. 전체 아키텍처 지금까지 소개한 모든 컴포넌트를 하나로 구성하면 다음과 같은 아키텍처가 됩니다.\n컴포넌트 역할 AutoScalingRunnerSet (x7) 용도별 Runner 스케일링 정책 (DinD 1 + K8s 모드 6) Listener Pod GitHub Long Poll로 Job 감지, Prometheus 메트릭 노출 EphemeralRunner JIT 토큰 등록 → Job 실행 → 자동 삭제 Container Hook + worker-podspec Kubernetes 모드에서 Workflow Pod 생성 및 볼륨/리소스 주입 Vault Secret 중앙 관리, JWT(ARC) / K8s Auth(Portal) 이중 인증 Rook-Ceph Ephemeral PVC 백엔드 (Runner 작업 디렉토리) GitHub Actions Exporter 워크플로우 메트릭 수집, Prometheus에 노출 도입 후 정량적 변화 항목 전환 전 전환 후 빌드 큐 대기 시간 평균 3분 이상 15초 이내 Secret 관리 레포지터리별 수동 Vault 단일 관리 장애 인지 소요 시간 문의 후 확인 Grafana 대시보드 실시간 감지 하드웨어 자원 관리 수동 서버 배치 nodeAffinity 자동 스케줄링 빌드 재현성 비결정적 Ephemeral Pod으로 보장 GPU와 FPGA처럼 가용 자원이 제한된 하드웨어의 경우, maxRunners(각각 3)를 통해 동시 실행 Job 수를 해당 하드웨어의 가용 수량에 맞추어 자원 경합을 방지하고 있습니다.\n마치며 이 글에서는 Self-hosted Runner의 구조적 한계에서 출발하여, ARC 기반으로 CI/CD 인프라를 전면 재설계한 과정을 다루었습니다. 특히 DinD 모드와 Kubernetes 모드의 아키텍처적 차이, Rook-Ceph 기반 Ephemeral PVC와 다층 캐시 전략, Vault를 통한 Secret 생명주기 관리, 그리고 자체 개발한 Exporter를 통한 파이프라인 관측성 확보까지 — 단순히 도구를 도입하는 것을 넘어, 왜 이러한 설계를 선택했는지의 기술적 근거를 공유하고자 했습니다.\n읽어주셔서 감사합니다!\n추신: HyperAccel은 채용 중입니다! Vault는 secret을 관리하고, ARC는 워크로드를 스케줄링하고, Rook은 스토리지를 추상화하고, Prometheus는 모든 것을 관측합니다. 각자 다른 역할이지만, 하나의 클러스터 안에서 조합될 때 비로소 완성된 시스템이 됩니다. HyperAccel도 마찬가지입니다 — HW, SW, AI 각 분야의 전문가들이 모여 하나의 목표를 향해 움직이고 있습니다. 이 조합에 함께하고 싶으시다면, HyperAccel Career에서 지원해 주세요.\nReference Actions Runner Controller (ARC) Documentation Runner Container Hooks (GitHub) HashiCorp Vault — JWT/OIDC Auth Method GitHub Actions — OIDC Token for Vault Rook-Ceph Documentation Kubernetes 기반 사내 개발 환경 구축기 1편 ","permalink":"https://hyper-accel.github.io/posts/arc-setup-guide/","summary":"HyperAccel의 CI/CD 인프라를 Actions Runner Controller(ARC) 기반으로 전면 재설계한 기술적 여정과 Vault JWT/Kubernetes Auth 이중 연동, 그리고 자체 개발한 Go 기반 Prometheus Exporter를 통한 파이프라인 관측성(Observability) 확보까지의 전 과정을 다룹니다.","title":"Kubernetes 기반 사내 개발 환경 구축기 2편: ARC와 CI/CD 인프라 고도화"},{"content":"Kubernetes 기반 사내 개발 환경 구축기 1편: 왜 Kubernetes인가? 안녕하세요! 저는 HyperAccel ML팀에서 DevOps Engineer로 근무하고 있는 전영훈입니다.\n이 글을 보시는 분들 중에서 개발자 여러분들은 어떤 환경에서 개발하고 계신가요? 로컬 환경, SSH 서버 접속, 클라우드 서비스를 비롯한 다양한 환경 위에서 개발을 진행하고 계실 것이라고 생각됩니다.\nHyperAccel은 Kubernetes 클러스터를 기반으로 구축된 환경 위에서 개발을 진행하고 있습니다. 개발 진행 시에 필요한 패키지들을 기반으로 제작된 devcontainer를 기반으로 Pod을 띄우고, container 내부에 접속해서 작업을 진행하는 구조입니다. 사내 개발자분들의 보다 편리한 사용을 위해서 Devcontainer Portal을 만들어서 제공하고 있습니다.\n하지만, 처음부터 Kubernetes 환경에서 개발이 진행되었던 것은 아닙니다. Kubernetes 기반 사내 개발 환경 구축기에서는 사내 개발자들의 불편함을 해소하고 효율적인 개발 프로세스 제공을 위해 어떻게 Kubernetes 기반 개발 환경을 구축하였는지에 대한 여정을 소개하고자 합니다.\n해당 시리즈의 첫 번째 글인 이번 포스팅에서는 Kubernetes 도입 이전 기존 개발 환경의 한계점에서부터 Kubernetes를 도입하기까지 과정에 대해 소개합니다.\nContainer 기반 개발 환경이 도입되기 이전 HyperAccel은 KAIST CAST Lab 구성원들이 힘을 합쳐 작은 규모에서부터 시작된 스타트업입니다.\n초기 스타트업의 특성 상 굉장히 빠른 템포로 개발을 진행했었고, 체계적인 개발 환경을 구축하기 어려운 상황이었습니다. 해당 시점에는 제가 HyperAccel에 합류하기 이전이기 때문에, 초창기 멤버이신 ML팀 박현준(Author, LinkedIn)님과 대화를 통해 당시 개발 환경에 대해 전해들을 수 있었습니다.\n당시 저희는 10명 정도 규모의 굉장히 작은 조직이었고, 타이트한 기간 내에 목표를 달성하기 위해 개발 환경에는 크게 신경쓰지 못했었습니다. 사내 서버에 각자 계정을 만들고 접속해서 사용했고, 누군가 서버의 자원을 많이 사용하고 있다면 직접 자리로 찾아가서 언제 작업이 끝나는지 독촉하곤 했었죠. (웃음)\n공통된 개발 환경이 없는 경우에 발생하는 어려움에 대해서 조금 더 구체적으로 살펴보겠습니다.\n서버 관리의 어려움 만약 서버가 10대 있고 개발자가 총 10명 있다면, 모든 개발자가 서버 전체에 접근하기 위해서는 총 100개의 계정이 필요합니다. 물론 계정 생성 정도는 자동화 스크립트를 사용한다면 크게 어렵지 않다고 생각하실 수 있습니다. 하지만, 이러한 환경에서 개발을 진행한다면 개발자는 서버마다 본인의 작업물이 같은 상태인지 추적하기 굉장히 어렵습니다. (Github을 활용한다고 해도 매우 불편합니다.)\n보안 및 서버 안정성 문제도 함께 고려해야 합니다. 예를 들면, sudo 권한 부여에 대해서도 추가로 정책을 정할 필요가 있습니다. 추가로 개발 도중 실수(sudo rm -rf /와 같은 폭력적인 예시를 생각해볼 수 있습니다\u0026hellip;)로 인해 서버가 망가지게 되면 복구하는데 비용이 들게 됩니다.\n패키지 버전 통일의 어려움 여러 명이서 함께 코드를 구현하는 것에 있어서 각자 코드의 통합은 필수 항목입니다. 개인별로 독립된 환경에서 개발을 진행한다면, 향후에 이를 통합할 때 버전 문제가 발생할 수 있습니다. Torch 버전 충돌, Clang 버전 불일치와 같은 문제가 발생할 수 있는 것이죠. 소위 말하는 It Works on my Machine을 서로 주장하게 되는 것입니다.\n자원 사용의 어려움 HyperAccel의 1세대 chip은 FPGA를 기반으로 제작되었습니다. FPGA 서버는 ring topology 형태로 연결되어 있기 때문에 서버 내부에서 완전 격리로 사용하기 위해서는 1대만 사용하거나 혹은 전부 다 사용하는 방식 중 하나로 활용해야만 했습니다.\n이러한 이유로 추가 설정 없이는 개발자 여러 명이 동시에 사용하기 어려운 구조입니다. (현재는 Kubernetes 환경 위에서 원활하게 사용되고 있습니다. 해당 내용에 대해서는 향후 작성될 글에서 Kubernetes Device Plugin이라는 주제로 자세히 알아보도록 하겠습니다.)\n추가로 GPU 같은 경우에도 점유 여부를 확인하기 위해서는 nvidia-smi와 같은 명령어를 통해 실행 중인 프로세스를 확인하거나, dashboard를 직접 참고해야하는 불편한 점이 있습니다.\nDevcontainer의 도입 회사의 규모가 커지고 개발자의 수가 늘어남에 따라서 체계적인 개발 환경 구축이 필요한 상황이 되었습니다. 이를 위해 ML팀 Lead이신 박민호(Author, LinkedIn)님께서 HyperAccel-Devcontainer라는 컨테이너화 된 개발 환경(편의상 이번 글에서는 devcontainer라고 지칭하겠습니다)을 구축하셨습니다.\n현재 devcontainer는 2가지 버전으로 제공합니다. 개발자분들이 필요로 하시는 설정이 다르기 때문에 이러한 니즈를 반영하기 위함입니다. 각 버전들은 공통으로 필요한 사항들이 설치된 base 이미지를 기반으로, 각 버전마다 필요한 패키지와 환경을 세팅하였습니다. 이를 통해 기존에 문제가 되었던 clang, torch 버전 충돌 이슈와 같은 문제들을 해결할 수 있었습니다.\n이렇듯 container 기반으로 개발 환경을 제공하는 경우에는 개발 인원 모두가 같은 환경 위에서 개발을 진행할 수 있다는 장점이 있습니다. It Works on my Machine을 피할 수 있는 것이죠. 또한 격리된 환경에서 개발을 진행하기 때문에 개인의 실수로 인해 서버가 망가지는 상황을 최대한 피할 수 있습니다.\n하지만, 이러한 container 개발 환경에도 명확한 한계점이 있습니다.\n개인별 서버 접속 계정의 필요성 개인별로 서버에 접속할 수 있는 계정은 여전히 제공해야 합니다. 개발자의 입장에서는 개발을 위해서는 서버 계정의 존재 여부에 의존해야 하고, 관리자의 입장에서는 개발 팀의 인원이 변동될 때마다 계정 관리를 해주어야 하는 업무 지점이 하나 늘어나게 됩니다.\n또한, 개인에게 서버 접속을 허용해주기 때문에 위에서 말씀드린 실수로 인한 서버 고장의 가능성도 여전히 존재합니다.\n개발 환경에 대한 유연성 부족 우선, 개발자는 서버마다 자신의 디렉토리를 관리해야 하기 때문에 여전히 서버 환경에 종속되어 있습니다. 만약 특정 서버가 다운된다면, 해당 서버를 쓰고 있던 개발자들은 (백업이 없다면) 자신의 결과물에 대한 추적이 어려운 경우 업무에 지장을 받을 수 있습니다. 현재 저희 회사에서는 외부 IDC의 서버도 함께 사용하기 때문에 관리자가 출장을 가서 서버를 고쳐야하는 상황이 된다면 업무가 더 오랜 시간 지연될 수 있습니다.\n추가로 개발자 입장에서 container 환경 사용에 대해 익히기까지 시간과 노력이 필요합니다. Container에 대한 기본 지식부터 실행 과정 및 주의사항까지 DevOps에 친숙하지 않은 개발자의 입장에서는 어려운 지점이 될 수 있습니다.\n해결하지 못한 자원 사용의 어려움 FPGA와 GPU 사용에는 여전히 제약이 발생합니다. 앞서 설명드린 문제점이 container 환경에서도 동일하게 발생할 수 있습니다.\n이러한 한계점을 극복하고 보다 쾌적한 개발 환경 제공을 위해 Kubernetes를 도입하기로 결정하게 되었습니다.\nKubernetes 기반 devcontainer 개발 환경 도입 여기까지 글을 읽으셨을 때 독자분들께서는 이러한 의문점이 생기실 수 있습니다.\n\u0026ldquo;Kubernetes는 도대체 어떤 tool이고, 왜 사용해야 하는거지?\u0026rdquo;\n본격적으로 Kubernetes를 기반으로 한 개발 환경에 대해 설명드리기 전에, Kubernetes란 어떠한 tool이고 이를 기반으로 개발 환경을 구축했을 때 어떠한 이점을 얻을 수 있는지에 대해 소개하도록 하겠습니다.\nContainer Orchestration Kubernetes는 Container Orchestration Tool입니다. Container를 쉽고 빠르게 배포 및 확장하고, 관리를 자동화해주는 오픈소스 플랫폼이죠. 단순한 container 플랫폼을 넘어 마이크로서비스 및 클라우드 플랫폼을 지향하고, container로 이루어진 것들을 손쉽게 담고 관리할 수 있는 그릇 역할을 합니다. 이렇게 설명하면 와닿지 않으실 수 있는데, 한 문장으로 정리해보자면 이렇게 표현해볼 수 있겠네요.\n복잡한 인프라 운영을 코드화 및 자동화하여, 누구나 일관되게 서비스를 배포, 확장, 운영할 수 있게 해주는 도구\nContainer Orchestration이라는 개념에 대해서 좀 더 설명해보겠습니다. Container를 기반으로 운영되는 환경에서 서비스는 container의 형태로 사용자들에게 제공됩니다. 이때 관리해야 할 container의 개수가 적다면 담당자 한 명이서도 충분히 문제 상황에 대한 대응이 가능하지만, 조직의 규모가 커진다면 담당자 한 명이 이슈에 대응하는 것은 불가능합니다. 규모가 큰 환경에서는 아래와 같은 운영 기법이 필요합니다.\n모든 서비스가 정상적으로 동작하고 있는지를 계속해서 모니터링하는 시스템 제공 특정 클러스터나 특정 컨테이너에 작업이 몰리지 않도록 스케줄링, 로드 밸런싱, 스케일링 수많은 container의 상태를 지속해서 관리하고 운영하는 과정을 조금이나마 쉽게, 자동으로 할 수 있는 기능을 제공해주는 시스템이 바로 Container Orchestration입니다.\nAbout Kubernetes 지금까지 Kubernetes와 Container Orchestration이 무엇인지에 대해 살펴보았습니다. 다음으로는 Kubernetes 컴포넌트에 대해서 간단히 알아보도록 하겠습니다. 아래 그림을 통해 Kubernetes 클러스터를 구성하는 필수 컴포넌트들에 대한 개요를 확인하실 수 있습니다.\nKubernetes 클러스터는 Control Plane과 하나 이상의 Worker Node로 구성됩니다.\nControl Plane 컴포넌트 Kubernetes 클러스터 전체 상태를 관리하는 역할을 합니다. 요청받은 작업의 자원 요구사항을 분석하여 최적의 노드에 배치하는 스케줄링 프로세스와, 클러스터의 전반적인 가용성 및 보안 정책을 집행함으로써 시스템의 안정성을 보장합니다.\n아래 소개하는 컴포넌트들을 통해 클러스터의 전체적인 상태(Desired State)를 정의하고 관리하는 중추적인 논리 계층 역할을 수행합니다.\nkube-apiserver\nKubernetes HTTP API를 노출하는 핵심 서버 컴포넌트 etcd\n모든 API 서버 데이터를 위한 일관성과 고가용성을 갖춘 key-value 저장소 kube-scheduler\n노드에 할당되지 않은 pod을 찾아 적절한 노드에 할당 kube-controller-manager\n컨트롤러를 실행하여 쿠버네티스 API 동작을 구현 Worker Node 컴포넌트 Worker Node는 Control Plane으로부터 할당받은 작업(pod 실행)을 실제로 수행하는 물리적(혹은 가상) 서버입니다. 간단하게 소개하자면 실제로 pod이 실행되는 서버라고 할 수 있습니다.\n아래 소개하는 컴포넌트들은 모든 노드에서 실행되며, 실행 중인 pod를 유지하고 Kubernetes runtime 환경을 제공합니다.\nkubelet\n노드 에이전트, Pod와 그 안의 container가 실행 중임을 보장 kube-proxy (Optional)\n노드에서 네트워크 규칙을 유지하여 서비스를 구현 container-runtime\nContainer 실행을 담당하는 소프트웨어 지금까지 Kubernetes와 클러스터 레벨에서 Kubernetes가 어떠한 역할을 하는지에 대해 살펴보았습니다. 그렇다면 사내 개발 환경 구축을 Kubernetes 기반으로 진행했던 이유는 어떤 것일까요? 다음으로는 Kubernetes 클러스터 형태로 개발 환경을 관리하는 것의 장점을 기반으로 선택 이유에 대해 설명하겠습니다.\nKubernetes 기반 개발 환경의 장점 Kubernetes를 기반으로 개발 환경을 제공한다면 어떠한 장점을 얻을 수 있을까요? 앞서 제시한 container 기반 개발 환경의 한계점을 어떻게 극복할 수 있는지에 초점을 맞추어 설명하도록 하겠습니다.\n완전한 격리 개발 환경 구축 Kubernetes 클러스터가 도입되며 더 이상 개발자가 서버에 접속할 필요가 없어졌습니다. 개발자분들은 Kubernetes 환경에서 devcontainer를 실행하고, container 내부에 접속하여 개발을 진행하기만 하시면 됩니다! 노드 선택, 자원 관리 등 인프라 측면에서 신경써야할 부분은 모두 클러스터 레벨에서 관리되기 때문이죠.\n또한, 클러스터 레벨에서 노드 사용 정책을 지정하여 사용자의 접근 권한 및 자원 사용에 대해 지정할 수 있습니다. 클러스터 내부 노드를 용도에 맞게 분리하여 사용자 입장에서 불편함을 느낄 요소가 많이 제거되고, 비정상적인 자원 사용을 통제하여 노드가 다운되는 상황도 막을 수 있습니다.\n유연한 개발 환경 운용 더 이상 개발 환경이 특정 노드에 종속되지 않습니다! 일부 노드가 다운되어도 클러스터 내부 다른 노드로 pod을 스케줄링할 수 있기 때문입니다. 개발자 home 같은 경우에도 NAS에 nfs provisioner 형태로 제공하기 때문에 안심하고 다른 노드에 뜬 pod 위에서 개발을 진행할 수 있습니다.\n추가로 portal 형태로 사용자에게 제공(아래에서 구체적으로 설명드리겠습니다)하기 때문에, 사용자에게 클러스터 접근 권한만 부여한다면 초기 진입장벽 없이 사용 가능합니다.\n자원 관리 용이 FPGA, GPU와 같은 custom 자원을 container 단위로 독점적으로 사용할 수 있습니다. Kubernetes는 기본적으로 CPU, Memory 이외의 자원은 custom 자원으로 간주합니다. 이러한 자원들을 Kubernetes 위에서 활용하기 위해서는 Device Plugin이 필요합니다.\n현재 저희 클러스터에는 Device Plugin이 세팅되어 있고, 이를 기반으로 container에 해당 자원들을 할당하여 사용한다면 다른 container의 개입 없이 격리하여 활용할 수 있습니다.\nKubernetes 클러스터 구축 및 개발 환경 도입 결과적으로 Kubernetes 클러스터를 구축하고, 이를 기반으로 사내 개발 환경을 도입하였습니다!!\n현재 저희 Kubernetes 클러스터에 적용되어 있는 컴포넌트 중에서 개발 환경의 편의성 증대를 목적으로 하는 일부에 대해 간략하게 소개해보겠습니다.\n고가용성(High Availability)\nKubernetes에서 Control Plane을 하나로 유지한다면 SPOF(Single Point Of Failure)가 생깁니다. 클러스터가 다운되면 개발자분들의 작업이 전부 중단되는 불상사가 발생하게 됩니다. 이를 방지하기 위해 3개 노드를 Control Plane으로 지정하였고, KeepAlived와 HAProxy를 적용하여 특정 노드가 다운되어도 클러스터가 정상 운영되도록 하였습니다.\n저장소 관리\n관리 편의성 증대 및 네트워크 지연 최소화를 위해 Rook-Ceph과 Harbor를 도입하여 내부 OCI Registry를 운영하고 있습니다. 사내 PyPi 서버 환경 제공을 위해 Nexus를 도입하여 운영하고 있습니다. CI/CD 고도화\nGithub 환경에서 CI/CD를 진행할 때 기존에는 컴퓨팅 노드에 Github Action Runner를 직접 띄워 쓰는 방식이었습니다. Kubernetes 클러스터가 구축되며 보다 안정적인 runner 실행을 위해 ARC(Actions Runner Controller)를 도입하였습니다.\nSecret 관리의 중앙화 및 개발자들의 secret 접근성 증대를 위해 Vault을 도입하여 운영하고 있습니다.\nPortal 제공\nDevcontainer Portal을 만들어서 개발자분들에게 제공하고 있습니다. Devcontainer Portal의 기능에 대해 좀 더 설명해보겠습니다.\nContainer 생성 및 삭제\n버튼 클릭 한 번만으로 container의 생성, 재시작, 삭제를 손쉽게 컨트롤할 수 있습니다. 에러 로그 확인\nPortal에서는 container 내부 terminal 접근 및 Logs 확인을 허용합니다. 이를 통해 에러가 발생했을 때 바로 확인이 가능합니다. Kubernetes 클러스터 노드 모니터링\n노드의 하드웨어 자원 사용량 및 잉여 자원 여부에 대한 정보를 제공하므로, 개발에 필요한 자원에 대한 정보를 확인할 수 있습니다. HyperAccel은 HW chip을 만드는 회사이므로, 개발 시에 device가 꼭 필요하고 이를 잘 모니터링하는 것이 중요합니다. Portal을 제공하기 전에는 Makefile 및 .env 파일을 활용하여 pod을 실행하도록 하였습니다. 이러한 방식은 사용자들에게 초기 진입 장벽과 불편함을 야기합니다. 이를 해결하고자 Portal을 통해 pod 실행 환경을 GUI로 제공하는 방식을 적용하였고, 필요한 명세들은 go-template와 ConfigMap을 활용하여 제공합니다. 개발자들은 편하게 개발 환경 인프라를 실행하고 모니터링을 통해 log 확인이 용이해졌기 때문에 개발에 더욱 집중할 수 있는 환경이 되었습니다.\n저는 석사과정 당시 분산학습 환경에서 효율적인 GPU 사용을 위한 스케줄링 연구를 진행했었습니다. 연구 진행을 위해 Kubernetes scheduler를 직접 수정해보며 Kubernetes의 제한적인 기능만을 활용했었는데요, 이번 구축 과정을 통해 클러스터 구축부터 운영까지 전체 과정을 진행해보는 소중한 경험을 했습니다.\n개발 환경 제공을 위해 Kubernetes 클러스터를 구축하고 어떻게 하면 사내 개발자 여러분들의 생산성을 높이고 편의성을 증대할 수 있는지 고민하는 과정이 어렵기도 했지만 정말 보람차고 즐거웠습니다.\n정리하자면\u0026hellip; 이번 글에서는 Kubernetes 기반 개발 환경 구축기 시리즈 중 첫 번째 내용인 기존 개발 환경의 한계점과 Kubernetes 도입 계기 및 과정에 대해 소개드렸습니다.\n공통된 조건을 기반으로 격리된 개발 환경을 제공하기 위해서 container 기반 환경을 제공하고, 이를 관리하기 위해 Kubernetes를 도입하였습니다. 개발자 입장에서는 인프라에 대해 신경써야 하는 부분이 최소화되기 때문에 편리하게 개발에만 집중할 수 있고, 관리자 입장에서는 규모가 커지는 환경에서도 안정적으로 관리 및 이슈를 대응할 수 있게 되어 업무 효율성이 크게 증가하였습니다.\n앞으로 전개될 시리즈 글에서는 개발 환경을 고도화하고 생산성을 높이기 위해 Kubernetes 클러스터 위에 어떠한 프레임워크를 추가했는지에 대해 소개하도록 하겠습니다!\n나아가 저희 ML팀에서는 HyperAccel에서 출시될 ASIC chip을 Kubernetes 위에서 활용할 수 있도록 지원하는 소프트웨어 스택 개발을 진행하고 있습니다. Kubernetes는 개발 환경 이외에도 현재 가장 주목받고 있는 기술인 LLM(Large Language Model) Serving의 기반 인프라로써 중요한 역할을 합니다. 해당 내용에 관련해서도 글을 통해 소개하도록 하겠습니다!\n향후 업로드되는 글에 대해서도 많은 관심 부탁드리며, 끝까지 읽어주셔서 감사드립니다!\n추신: HyperAccel은 채용 중입니다! HyperAccel은 LLM 가속 ASIC 칩 출시를 위해 HW, SW, AI를 모두 다루는 회사로 전 방면에 걸쳐 뛰어난 인재들이 모여있고, 이런 환경에서 한 분야에 국한된 것이 아닌 폭넓은 지식을, 심지어 깊게 배우며 지식을 공유하고 빠른 속도로 함께 성장하고 있습니다!\n저희 ML팀의 DevOps 파트는 사내 개발자들의 생산성 증대를 위한 개발 환경 제공 및 관리, LPU chip을 클라우드 레벨에서의 활용을 효과적으로 지원하기 위한 소프트웨어 스택을 개발하고 있습니다.\nHyperAccel에서 다루는 기술들을 보시고, 관심이 있으시다면 HyperAccel Career로 지원해 주세요!\nReference Kubernetes Docs What is Kubernetes? Why Kubernetes? 하이퍼엑셀(HyperAccel), Amazon EC2 F2 Instance 기반 LPU로 고효율 LLM 추론 서비스 구축 Hyperdex Toolchain Software Stack Actions Runner Controller ","permalink":"https://hyper-accel.github.io/posts/development-environment-with-k8s-ch1/","summary":"\u003ch1 id=\"kubernetes-기반-사내-개발-환경-구축기-1편-왜-kubernetes인가\"\u003eKubernetes 기반 사내 개발 환경 구축기 1편: 왜 Kubernetes인가?\u003c/h1\u003e\n\u003cp\u003e안녕하세요! 저는 HyperAccel ML팀에서 DevOps Engineer로 근무하고 있는 전영훈입니다.\u003c/p\u003e\n\u003cp\u003e이 글을 보시는 분들 중에서 개발자 여러분들은 어떤 환경에서 개발하고 계신가요? 로컬 환경, SSH 서버 접속, 클라우드 서비스를 비롯한 다양한 환경 위에서 개발을 진행하고 계실 것이라고 생각됩니다.\u003c/p\u003e\n\u003cp\u003eHyperAccel은 \u003cstrong\u003eKubernetes 클러스터를 기반으로 구축된 환경\u003c/strong\u003e 위에서 개발을 진행하고 있습니다. 개발 진행 시에 필요한 패키지들을 기반으로 제작된 \u003ccode\u003edevcontainer\u003c/code\u003e를 기반으로 Pod을 띄우고, container 내부에 접속해서 작업을 진행하는 구조입니다. 사내 개발자분들의 보다 편리한 사용을 위해서 \u003ccode\u003eDevcontainer Portal\u003c/code\u003e을 만들어서 제공하고 있습니다.\u003c/p\u003e","title":"Kubernetes 기반 사내 개발 환경 구축기 1편: 왜 Kubernetes인가?"},{"content":"지피지기면 백전불태 3편 : 엔비디아가 200억 달러에 인수한 그록의 LPU \u0026ldquo;상대를 알고 나를 알면 백 번 싸워도 위태롭지 않다.\u0026rdquo;\n이 시리즈는 AI 가속기 설계를 위해 경쟁사들의 하드웨어를 깊이 이해하는 것을 목표로 합니다.\n세 번째 글에서는 작년 말 엔비디아에 약 200억달러로 인수된 미국의 스타트업 그록(groq)의 LPU(Language Processing Unit)에 대해 다룹니다.\n구글을 박차고 나온 엔지니어의 과감한 도전 그록의 탄생 배경에 대해 알기 위해서는 창업자인 조나단 로스(Jonathan Ross)에 대해 알아봐야 할 필요가 있습니다. 그는 구글에서 TPU(Tensor Processing Unit) 프로젝트를 처음 시작했던 핵심 멤버였습니다. TPU 개발팀에서 근무하던 그는 향후 AI 추론 시장의 성장 가능성을 직감하고 구글을 박차고 나와 그록을 창업합니다. 그리고 독자적인 추론 전용 칩인 LPU(Language Processing Unit)을 세상에 내놓았습니다.\n이들이 목표로 한 시장은 저희 HyperAccel이 지향하는 지점과 매우 유사합니다.\nGPU / TPU: 학습(Training)과 추론(Inference)을 모두 지원하지만, 태생적으로 대규모 연산 집중적인 학습에 최적화 LPU: 학습은 과감히 버리고, 오직 거대언어모델(LLM)의 추론 최적화에만 올인 학습과 추론의 개념에 대해 생소한 분들은 여기서 이러한 의문이 들 수 있을 것입니다.\n??? : 학습? 추론? 다 같은 AI 연산아닌가? GPU는 다 잘하는거 아닌가? 추론 특화 칩이 필요한 이유가 뭐지?\n그런 분들을 위해 AI 연산에서 학습과 추론의 차이에 대해 잠시 짚고 가도록 하겠습니다.\n학습과 추론 : 범용칩의 한계와 전용칩의 기회 AI workload는 크게 가중치를 업데이트하는 학습과, 고정된 가중치를 사용하는 추론으로 나누어 볼 수 있습니다.\n주어진 이미지를 보고 어떤 이미지인지 구분하는 AI 모델을 개발한다고 가정해봅시다. 이를 위해서는 먼저 다량의 이미지 데이터를 통해 모델을 훈련시키는 과정이 필요합니다. 훈련 과정에서 모델은 이미지를 보고 현재 가중치를 바탕으로 정답을 내놓은 뒤(Forward path), 정의된 학습 메커니즘에 따라 실제 정답과의 오차를 비교하고 이를 바탕으로 현재 가중치를 업데이트합니다(Backward path). 이를 반복하면 모델의 가중치는 계속해서 업데이트되고, 충분한 시간이 지나면 이 모델은 오차가 줄어들고 이미지를 잘 구분할 수 있게 됩니다. 학습이 어느정도 진행되었다면 이 모델을 실제로 사용해야 하겠죠? 이 추론 과정에서는 학습과 달리 가중치를 업데이트할 필요가 없습니다. 이미 학습을 마친 모델의 가중치를 업데이트 하는 과정은 실제 사용 단계에선 불필요한 연산이기 때문이죠. 따라서 추론 과정에서는 Forward path만 존재합니다.\n이를 통해 알 수 있는 사실은 추론은 학습만큼의 엄청난 연산량을 필요로 하지 않는다는 점입니다.\n하지만 이것만으로 전용칩의 타당성을 입증하기엔 부족합니다. 단순히 추론의 연산량이 적다면, 오버 스펙이더라도 GPU나 TPU와 같은 엄청난 연산량을 지원하는 하드웨어로 많은 추론연산을 진행하면 그만이기 때문이죠. 실제로 AI 기업에서는 학습에는 최고사양의 GPU 라인업(B200 등)을, 추론에는 상대적으로 낮은 라인업의 GPU(H200 등)을 사용하고 있습니다. 현재 LLM이 이끌고 있는 생성형 AI 시장에서 추론 칩의 필요성을 알기 위해서는 현재 사용되는 LLM의 구조적 한계에 대해 살펴보아야 합니다.\nLLM의 구조적 한계 : 병목은 컴퓨팅이 아닌 메모리에 있다 현재 GPT, Gemini, Grok 등 LLM 모델의 근간이 되는 Transformer 아키텍쳐의 근본적인 특징은 결과값을 한번에 문장으로 생성하는 것이 아닌, 단어(이하 토큰) 하나씩 순차적으로 생성한다는 것입니다. 이를 자기회귀적(auto-regressive) 특성을 가진다고 표현합니다. 이는 Transformer 모델이 입력값을 통해서만 결과값을 생성하지 않는 것이 아니라, 출력 토큰이 생성될 때마다 입력 토큰들과 지금까지 생성된 출력 토큰들과의 관계를 다시 계산해서 다음 출력 토큰을 생성하기 때문입니다. 이렇게 되면 연산이 엄청나게 많이 필요하겠지요. 하지만 문제는 연산량 뿐만이 아닙니다. 매번 토큰을 생성할 때마다 모든 값들을 다시 계산하게 되면 연산 비효율이 높아지기 때문에 재사용이 가능한 중간 값(KV cache)들은 메모리에 넣어두고 다음 토큰을 연산할 때 메모리에서 이를 읽어와서 다시 계산하게 됩니다. 문제는 이로 인해 토큰을 매번 생성할 때마다 과거의 데이터들을 메모리에서 다시 불러와야 하기 때문에 토큰을 많이 생성할수록 메모리 이동량이 증가하게 되는 것입니다.\n컴퓨터 구조에서는 하드웨어 성능의 한계를 진단하기 위해 Roofline Model이라는 측정 기법을 사용합니다. 하드웨어에서 사용되는 소프트웨어의 연산 특성과 하드웨어 스펙을 통해 해당 연산의 가능한 최대의 성능을 확인하는 것입니다.\nRoofline Model 그래프는 두 개의 축으로 구성됩니다. x축은 연산강도(Operational Intensity)입니다. 한번 가져온 데이터로 얼마 만큼의 연산을 수행하느냐를 나타내는 지표이며, 데이터 재사용성이 높아질수록 증가합니다. y축은 성능(Performance)으로, 일반적으로 초당 부동소수점 연산 횟수(FLOPS/s, FLOPS : Floating Point Operations)로 표현됩니다.\n그래프 위의 각 선들은 하드웨어의 성능 한계를 나타냅니다. 기울기가 있는 선은 메모리 대역폭에 의한 성능 한계를 나타내며, 연산강도가 낮을 때(초록 점선 기준 왼쪽 영역) 이 선을 따라 최대 성능이 결정됩니다. 이 영역에서는 하드웨어의 연산 능력이 아무리 뛰어나도 메모리에서 데이터를 가져오는 속도에 제한받아 메모리 대역폭에 비례한 성능만 얻을 수 있습니다.(Memory bound). 이 직선의 기울기는 성능(FLOPS/s) / 연산 강도(FLOPS/BYTE)이므로 하드웨어의 메모리 대역폭 (BYTE/s)와 같습니다.\n반면 수평선은 하드웨어의 최대 연산 성능 한계를 나타냅니다. 연산강도가 충분히 높아서(초록 점선 기준 오른쪽 영역) 이 수평선에 도달하게 되면, 해당 연산의 성능은 하드웨어가 낼 수 있는 최대 연산 성능과 같아집니다.(Compute bound) 두 선이 만나는 지점을 Ridge Point라고 하며, 이 지점에서 메모리와 연산 성능이 균형을 이룹니다. 이 지점 이후로는 연산 강도가 높아져도 하드웨어적 한계에 막혀서 최대 성능이 더이상 증가하지 못합니다.\nCompute Bound : 하드웨어 스펙에 비해 필요로 하는 연산량이 너무 많아 칩의 계산 속도의 물리적 한계로 병목 발생 Memory Bound : 연산기는 충분한데, 메모리에서 데이터를 가져오는 속도가 그에 비해 느려서 병목 발생 학습 과정은 연산량도 많이 필요하며, 병렬화가 가능하기 때문에 compute bound에 가깝습니다. 하지만 LLM 추론 과정, 특히 첫 입력 토큰들에 대한 첫 출력 토큰을 계산(Prefill Stage)한 이후에 출력 토큰을 하나씩 뽑아내는 과정(Decoding Stage)에서는 개별 토큰을 출력하기 위해 매번 메모리에서 과거 데이터를 읽어와야 합니다. 아울러 이 데이터의 크기는 출력 토큰 길이가 길어질수록 증가합니다. 이는 연산 강도를 낮추기 때문에 추론 연산은 memory bound에 가깝습니다.\nGPU와 다른 데이터센터향 칩들이 비싼 HBM(고대역폭 메모리)을 사용해야만 하는 이유가 바로 여기에 있습니다. 아무리 칩의 연산 속도가 빨라도, 메모리 벽(Memory Wall)을 넘지 못하면 무용지물이기 때문입니다. 앞서 언급했듯, memory-bound 영역에서 그래프의 기울기는 메모리 대역폭과 같기 때문에 HBM을 사용하여 대역폭을 늘리게 되면 아래 그래프와 같이 같은 연산 강도에서도 높은 성능을 뽑아낼 수 있습니다.\n추론 칩은 LLM의 이러한 병목지점을 타겟팅합니다. 아무리 연산 성능이 높아도 memory bound로 인해 성능 한계에 도달할 수밖에 없다면, LLM 구조에 맞는 아키텍쳐나 memory bandwidth를 극대화할 수 있는 칩으로 승부를 보는 것입니다. GPU와 같은 범용칩도 이러한 움직임을 보이고는 있지만, 과감한 하드웨어적 혁신과 구조 개선을 하기엔 무리가 있습니다. 현재는 LLM 연산에 GPU가 많이 사용되고 있지만 GPU는 LLM 뿐만 아니라 다양한 구조의 AI 모델 학습과 연산에 사용되고 있으며, AI 연산 뿐만 아니라 이미지 렌더링과 같은 다양한 작업에 활용되는 범용칩이 되었기 때문입니다. 필요 없는 부분을 덜어내고 특수한 workload를 타겟팅한 전용칩이 강점을 보일 수 있는 이유가 바로 여기에 있습니다.\n다음으로는 그록이 하드웨어 시장에 이 전용칩을 통해 보여준 과감한 시도들에 대해 알아보겠습니다.\n그록의 과감한 도박 : Memory Hierarchy의 고정관념을 붕괴시켜라 그록 LPU의 가장 큰 특징은 메모리 구조입니다. 조금 전 memory bandwidth가 매우 중요하다고 말씀드렸는데요. A100 GPU의 메모리 구조를 살펴보면 아래 그림과 같습니다.\n개별 GPU의 메모리 hierarchy는 GPU 칩 내부의 on-chip SRAM, GPU 칩과 붙어 있는 off-chip 메모리(HBM) 그리고 GPU 서버에서 구동 시 개별 노드에 할당된 시스템 메모리(DRAM)로 구성되어 있습니다. memory hierarchy에서 아래로 내려갈 수록 용량은 커지고 대역폭은 작아지며, 용량당 가격은 저렴해집니다. LLM 연산 진행시 가중치나 중간 연산값들은 대부분 HBM에 저장된 후 다시 읽어가며, HBM에서 읽은 데이터는 연산기와 가까이 있는 GPU SRAM에 cache 형태로 보관하여 재사용시 메모리 효율을 늘리는 형식으로 연산이 이루어집니다. 이는 CPU나 다른 전통적인 컴퓨터 구조에서도 채택해왔던 형식입니다.\n엔비디아를 비롯한 대기업들과 많은 추론 칩 스타트업들이 HBM과 메모리를 더 효율적으로 쓸 수 있는 방법을 고민하였지만, 그록은 이러한 memory hierarchy에 의문을 품고 판을 뒤집는 질문을 던집니다.\n??? : 모든 데이터를 칩 내부(On-chip)에 넣어버리면 안되나?\n단순히 SRAM 용량을 늘리겠다는 것이 아닙니다. Off-chip 메모리를 사용하지 않겠다는 것입니다. 그록은 본인들의 칩에서 과감하게 위 계층구조의 가운데에 해당하는 HBM을 제거했습니다. 대신 칩 내부의 캐시 메모리로 쓰이는 SRAM을 메인 메모리로 사용합니다.\nHBM 대역폭 : B200 기준 8 TB/s LPU SRAM 대역폭 : 80 TB/s 이상 (최소 10배~20배 차이) 이 압도적인 대역폭을 활용하여 그록은 2020년 ISCA(컴퓨터 아키텍처 국제 학회)에서 ResNet 등의 이미지 분류 모델에서 GPU보다 뛰어난 성능을 증명했습니다.\n문제 : 가격과 용량 하지만 on chip memory만 사용한다고 모든 문제가 해결되는 것은 아닙니다. SRAM만 사용해서 모든 문제가 해결된다면 이미 많은 하드웨어 기업들이 그 방법을 채택했을 겁니다. 문제는 비용입니다. SRAM과 DRAM 모두 같은 메모리처럼 보이지만, 그 구조를 보면 매우 다릅니다.\n전자공학을 전공하신 분들이라면 한번쯤 보셨을 만한 이미지입니다. 간단하게 숫자로 설명하면 DRAM은 비트 하나를 저장하는 개별 cell당 1개의 트랜지스터와 1개의 캐패시터가 필요한 반면, SRAM은 cell당 6개의 트랜지스터가 필요합니다. 단순 부품 개수만 3배 차이이며, 배선 복잡도를 생각하면 차지하는 면적은 수십배까지 차이가 납니다. 때문에 SRAM 용량을 늘리게 되면 칩 사이즈가 커지게 되며, 이전 글에서 말씀드린 레티클 한계(Reticle limit)로 인해 용량을 늘리는데는 한계가 있습니다. 더군다나 SRAM 용량을 늘린다는 것은 칩 안에 SRAM이 차지하는 비율이 증가한다는 것입니다. 그만큼 연산에 필요한 로직들이 들어갈 자리가 줄어드는 것이죠. 메모리가 중요하다 한들 메모리만 있으면 연산을 할 수 없습니다. 이러한 한계로 개별 칩에는 SRAM을 많아야 HBM 용량의 1/10정도(수백MB)로 밖에 담지 못하는 것이 현실입니다.\n최신 LLM 모델들은 기본적으로 수십억 규모의 parameter를 가집니다. 압축이 되어 있지 않다고 가정하고 간단히 계산해도 가중치를 저장하는데에만 수십GB 정도의 메모리가 필요하니 SRAM만 사용한다면 칩 하나에 모델 하나를 올리는 것 조차 불가능합니다.\n해결책 : 쪼개서 저장하고, 컨베이어 벨트처럼 돌린다 그록은 이 문제를 Scale-out으로 해결했습니다. 칩 하나에 모델을 못 담으니, 수백 개의 칩에 모델의 가중치를 쪼개서(Sharding) 저장하는 것입니다. 여기서 AI 병렬화 기법이 등장합니다.\nTensor Parallelism (TP) : 하나의 큰 행렬 연산을 여러개의 작은 행렬 연산으로 분해. 부분적 행렬 연산에 필요한 가중치를 여러 칩의 메인 메모리에 나눠서 저장하고 각 칩이 부분적 행렬 연산 수행. Pipeline Parallelism (PP) : 모델의 레이어(Layer)를 그룹 별로 나누어 처리. 연산 순서 별로 각 칩은 이전 칩에서 연산된 결과를 받아서 다음 레이어에 대한 연산 수행 그록은 이 병렬화 기법을 적용한 그들의 시스템을 거대한 컨베이어 벨트에 비유합니다. 입력 데이터가 첫 번째 칩(벨트의 시작)에 들어가면, 각 칩은 본인이 맡은 연산만 수행하고 옆 칩으로 데이터를 넘깁니다. 마지막 칩에서 최종 토큰이 튀어나오는 구조입니다. 이를 애니메이션으로 나타내면 아래와 같습니다.\n반면 GPU의 단일 칩에서 같은 작업을 수행하려 한다면\nHBM에서 memory load -\u0026gt; 연산 -\u0026gt; 다시 HBM에서 memory load -\u0026gt; 연산\n이 과정을 반복해야 합니다. HBM에 연산에 필요한 데이터들은 저장하고 있지만, 연산기 근처(SRAM)에 load할 수 있는 데이터의 용량에는 마찬가지로 한계가 있기 때문입니다. 이로 인해 반복적으로 memory load가 이뤄지는 과정에서 병목이 발생하는 것이 그록의 주장입니다. 이를 애니메이션으로 나타내보면 아래와 같습니다.\n그록의 시스템이 성공적으로 동작하기 위해서는 칩 간 통신(Chip-to-Chip, C2C) 속도가 생명입니다. 컨베이어 벨트 중간이 끊기면 공장 전체가 멈추니까요. 그록은 독자적인 C2C 인터커넥트 기술(RealScale)과 Dragonfly Topology를 통해 8개 이상의 칩을 하나의 거대한 노드처럼 묶었습니다. 여러 개의 칩이 서로의 SRAM을 공유하는 거대한 단일 칩처럼 보이게 하여 통신 오버헤드(Communication Overhead)를 거의 0에 수렴하게 만든 것입니다.\nGPU도 이러한 방식을 사용하지 못하는 것은 아닙니다. 앞서 설명드린 TP와 PP는 GPU를 이용한 분산 학습에서 널리 사용되는 병렬화 방식입니다. 다만 GPU에서는 이러한 기법(특히 TP)를 사용할 때 device간 data sync를 맞추기 위한 작업이 필요합니다. GPU는 런타임 라이브러리인 NCCL(Nvidia collective communication library)를 통해 GPU간 통신을 지원합니다. 앞서 말씀드린 TP를 사용하는 과정에서는 각 GPU에서 연산된 행렬 곱셈 결과를 다른 GPU들과 공유하여서 summation을 구하는 과정, all-reduce가 필요합니다.\n하지만 그록의 LPU에서는 엔비디아에서 사용하는 NCCL과 같은 런타임 라이브러리가 불필요합니다. LPU에서는 device간 통신이 NCCL과 같은 런타임 라이브러리에서 이뤄지는 것이 아닌 컴파일 타임에서 예측 가능하기 때문인데요. 어떻게 가능한 것인지 그록의 또다른 아키텍쳐 철학을 통해 알아보도록 하겠습니다.\nSoftware-defined Hardware : 컴파일러가 모든 것을 결정한다 그록 LPU의 또 다른 특징은 하드웨어 설계보다 소프트웨어(특히 컴파일러)가 우선한다는 점입니다. 실제로 LPU의 설계 철학을 담은 공식 문서를 보면 컴파일러 아키텍쳐가 디자인 되기 전에 칩 디자인은 건들지조차 하지 않았다고 합니다. 이는 컴파일러가 모든 하드웨어를 컨트롤 가능하고 개별 하드웨어 동작들이 컴파일러 레벨에서 예측가능하도록 하기 위함입니다.\nDeterministic Execution (결정론적 실행) CPU나 GPU는 언제 어떤 데이터가 들어올지 모르기 때문에, 하드웨어 레벨에서 복잡한 스케줄러(Branch Prediction, Cache Managing, Warp Scheduling 등)를 사용합니다. 이는 유연하지만, 예측 불가능한 지연(Tail Latency)을 만듭니다.\n잠시 1편에서 등장한 GPU의 warp scheduling 예시를 다시 보겠습니다.\n(본 예시는 단순한 설명을 위한 것이며, 실제 하드웨어 동작과는 다를 수 있습니다.)\n이전에 소개드린 warp scheduling에서 메모리에 데이터를 읽고 쓰는 load/store 명령은 비동기적으로 일어납니다. 이는 근본적으로 메모리 load/store 명령이 언제 완료될지 모르기 때문입니다. 그 동안 프로세서는 어쩔 수 없이 비동기적 명령이 완료될 때까지 기다려야 하는 것이죠. 하지만, 이 명령이 완료되는 시점을 알 수 있다면, stall해야 하는 시간을 정확히 예측할 수 있다면? 프로세서는 그 시간 동안 할 수 있는 일을 계산하여 다른 일을 하면서 idle한 프로세스를 최소화하고 시스템을 최적화할 수 있을 것입니다.\nLPU의 정적 스케줄링(static scheduling)은 바로 딥러닝과 LLM, 그중에서도 추론 연산에 이를 적용하는 것을 목적으로 합니다. 앞서 언급드렸듯이 추론 연산은 고정된 가중치를 통해서 최종 결과값(LLM에서는 output token)을 계산하는 과정입니다. 이 과정에서 모델이 고정되어 있다면 연산 순서는 대체로 고정되어 있습니다. 고정된 연산 순서는 정적 스케줄링을 적용하기 위한 최적의 조건 중 하나입니다. 연산 중간에 발생할 수 있는 스케줄링을 걷어낼 수 있기 때문입니다. 이렇게 되면 한정된 하드웨어 자원을 스케줄링이 아닌, 연산 유닛이나 메모리 등 다른 유닛으로 활용할 수 있기 때문에 하드웨어 효용성도 증가합니다.\n이러한 정적 스케줄링의 효과는 칩 여러개를 동시에 사용하는 상황에서 더 빛을 발휘합니다.\n직전에 이야기한 엔비디아의 NCCL 라이브러리를 통해 all-reduce/all-gather를 사용하는 과정에서는 장치간 동기화(synchronization)이 필요합니다. 이는 모든 장치에서 작업이 끝나야 다음 작업을 수행할 수 있지만, 각 장치에서 언제 작업이 끝날 지 모르기 때문입니다.\n하지만 컴파일러가 각 장치에서 작업이 완료되는 시점까지 알 수 있다면 어떨까요? NCCL에서 작업 중 필요한 동기화 작업은 물론 NCCL에서 필요한 작업까지 컴파일러 단에서 수행할 수 있을 것입니다.\n이러한 이유로 그록은 하드웨어의 \u0026lsquo;뇌\u0026rsquo;에 해당하는 스케줄링 기능을 최소한으로 남기고, 이 기능을 컴파일러에게 위임했습니다. 지금까지 설명한 그록 LPU의 정적 스케줄링을 요약해보면 아래와 같습니다.\n컴파일러는 컴파일 시점에 칩 내부, 나아가 사용할 모든 칩간의 데이터 흐름을 하드웨어 시간 단위(clock cycle)로 미리 계산합니다. 데이터가 언제, 어느 칩의, 어느 메모리 주소에 도착할지 100% 예측 가능합니다(Deterministic). 하드웨어는 복잡한 고민 없이 컴파일러가 시키는 대로만 실행합니다. LPU는 실행 시간의 예측 가능성을 확보하고, 스케줄링에 해당하는 하드웨어 자원을 연산에 집중시킬 수 있게 되었습니다. 엔비디아는 왜 그록을 인수했을까? 그록의 LPU는 기술적으로는 혁신적이고 뚜렷한 강점을 갖고 있었지만, 비즈니스적으로는 난관이 있었습니다. 고객사 입장에서 LPU로 LLM 모델 하나만 돌린다 하더라도 수백 개의 칩(Rack 단위)이 필요하므로 초기 도입 비용이 수십~수백억 원에 달했기 때문입니다. 이러한 문제 때문인지 그록은 사업 초기에는 칩(GroqChip) 판매를 진행했지만, 이후 사업 다각화를 통해 GroqCloud를 통해 클라우드 API 임대 사업을 해왔습니다. 본인들이 그록칩을 통해 직접 구축한 서버나 랙을 사용할 수 있는 API를 제공하는 것입니다.\n그렇다면 엔비디아가 이 그록을 인수한 배경은 무엇일까요? 일반적인 경제 기사에서는 추론 시장 지배력 확대를 위한 기술 라이선싱이라는 의견이 지배적입니다. 하지만 저는 엔지니어로서 기술적 상상력을 조금 가미하여 그록 인수 이후 펼쳐질만한 몇 가지 기술적 시나리오에 대해 이야기해보며 오늘 글을 마무리하도록 하겠습니다.\n가설1 : 새로운 이종 컴퓨팅(Heterogeneous Computing) 플랫폼 구축 최근 AI 추론 연산 트렌드 중 하나는 Prefill과 Decoding의 연산 분리(prefill-decode disaggregation)입니다. 이는 추론 연산 안에서도 특성이 다른 작업이 혼재되어 있기 때문입니다.\nPrefill(Context) phase : 입력 프롬프트를 한 번에 집어넣어서 많은 연산 필요 → Compute Bound Decoding(Generation) phase : 첫 토큰 생성 이후 생성되는 토큰을 하나씩 순차적으로 입력 → Memory Bound 엔비디아는 작년말 prefill과 decode별로 다른 연산기를 사용하는 이종 하드웨어 플랫폼을 공개한 바 있습니다. 차세대 GPU 아키텍쳐인 Rubin 아키텍쳐를 기반으로 context-phase에 특화하여 제작한 Rubin CPX를 공개하며 이것이 탑재된 플랫폼을 같이 공개하였습니다. 해당 플랫폼의 아이디어를 요약하면 Prefill stage는 Rubin CPX → Decoding stage는 Rubin GPU에서 실행하는 것입니다. 이 플랫폼에 그록의 LPU 아키텍쳐를 활용한다면 아래와 같은 2가지 방식의 새로운 플랫폼을 상상해볼 수 있습니다.\n현재 플랫폼에 Rubin GPU 대신 GPU + LPU 혼합 하드웨어(Rubin LPU) 장착 Rubin CPX → Prefill Rubin LPU → Decoding 현재 플랫폼에 1에서 언급한 하드웨어 추가 Rubin CPX → Prefill Rubin LPU → Decoding Rubin GPU → Prefill + Decoding 하지만 현실적으로 위와 같은 플랫폼 구축을 위해서는 어려움이 많을 것으로 예상됩니다. LPU와 GPU의 하드웨어 아키텍쳐간 차이가 크기 때문에 단일 플랫폼 내 통합이 쉽지 않기 때문입니다. 따라서 저는 이 시나리오보다는 다음에 소개할 시나리오가 더 가능성이 높다고 생각합니다.\n가설2 : 하이브리드 AI 기가 팩토리 구축 엔비디아는 단순 하드웨어 기업에서 나아가 직접 데이터센터를 구축하고 있습니다. 엔비디아가 준비중인 이른바 AI 기가 팩토리는 그들의 하이퍼스케일러(Meta, Google, Amazon)들이 구축하는 데이터센터를 본인들이 직접 구축하여 다른 고객들에게 제공하기 위한 플랫폼입니다. 그록이 제공한 GroqCloud API의 확장된 버전이라고 생각하시면 되겠습니다.\n데이터센터 구축은 단순 하드웨어 지식을 넘어 시스템 전반에 대한 이해, 고객사 경험 등 다양한 유/무형 자산을 필요로 하기 때문에 이를 할 수 있는 기술력을 갖춘 회사들은(특히 하드웨어 회사들 중에서는) 많지 않습니다. 보통 하이퍼스케일러들이 데이터센터를 구축하면서 본인들의 노하우나 기술력을 구축한 경우가 대부분입니다. 그록은 실제로 본인들의 추론 칩으로 데이터센터를 구축하고 실제 API를 제공한 하드웨어 기업입니다. 엔비디아 입장에서 그록을 인수하게 된다면 본인들의 기가 팩토리에 들어갈 하드웨어 라인업을 확장할 수 있습니다.\n앞서 말한 이종 컴퓨팅을 서버나 노드 단위가 아닌 데이터센터 단위로 확장해본다면\n학습을 비롯한 GPU 특화된 작업은 GPU 클러스터에서 연산 LPU에서 더 빠르게 진행할 수 있는 작업은 LPU 클러스터에서 연산 그러면 LPU가 더 빠르게 진행할 수 있는 작업은 무엇이 있을까요? 이전에 이야기한 LLM 추론 연산 자체의 관점에서 본다면 추론 과정 중 Prefill/Decoding 작업을 GPU와 LPU 클러스터가 분리해서 진행하는 것을 생각해볼 수 있습니다. 이번에는 추가로 작업 단위의 관점에서 LPU가 강점을 지닐만한 workload 몇개를 소개해볼까 합니다.\n(여기부터는 제 사견이 많이 반영되어 있습니다.)\nSpeculative Decoding\n최근 LLM 서빙의 트렌드 중 하나는 Speculative Decoding(추측 디코딩)입니다. 모델 사이즈가 커지면서 연산 시간이 오래 걸리다보니 기존 모델(Target Model)을 증류하거나 비슷한 동작을 하도록 훈련된 작고 빠른 모델(Draft Model)이 문장의 뒷부분을 미리 빠르게 생성하면, Target Model이 이를 병렬로 검증하는 방식입니다. 그록의 LPU 클러스터는 여기서 작은 사이즈의 Draft Model 연산에 사용될 수 있습니다. LPU는 작은 사이즈의 모델에서 압도적인 토큰 생성 속도를 자랑하기 때문입니다. 전체적인 관점에서 LPU/GPU 클러스터의 역할을 구분해보면 아래와 같습니다.\nLPU : 빠른 속도로 후보 토큰들을 생성 GPU : LPU에서 던져준 토큰들이 맞는지 한 번에 검증 다만 이러한 시스템은 근본적으로 한계가 있습니다. GPU - LPU 클러스터간 통신 오버헤드 때문이데요. LPU가 생성한 토큰들만 GPU로 던져주면 오버헤드가 크지 않겠지만, Speculative decoding의 Target Model은 토큰 검증을 위해 Draft Model에서 생성된 데이터(KV cache)들을 필요로 합니다. 하나의 칩이나 노드 안에서 통신이 이뤄진다면 오버헤드가 상대적으로 적겠지만, 클러스터끼리 통신에서 대용량의 KV cache 이동이 필요하다면 오버헤드가 커지는 것은 큰 문제입니다. 서비스 자체의 성능을 오히려 저하시킬 수 있기 때문입니다. 이는 speculative decoding 뿐만 아니라 prefill-decode disaggregation을 클러스터 단위로 수행하는 경우에 공통적으로 고민해야 하는 문제이기도 합니다.\n더욱이 최근 speculative decoding은 위에서 설명한 target-draft 방식으로 모델을 분리하지 않고 단일 모델에서 내부 최적화를 통해 이를 적용하는 방식으로 변모하면서 이종 컴퓨팅을 사용하기 어려운 환경으로 변화하고 있습니다.\nAgentic AI\n또 다른 시나리오는 Agentic AI입니다. AI는 단순히 답변만 하는 챗봇을 넘어, 스스로 계획을 세우고 도구를 사용하며 여러 단계의 추론을 거치는 에이전트 형태로 진화하고 있습니다. 계획을 세우고, 도구를 사용하는 각각의 단계에서 크고 작은 모델들이 각자 생성한 데이터를 주고받는 최종 결과물을 생성하게 됩니다. 다양한 모델이 사용된다는 관점에서 직전에 언급한 Speculative Decoding과 비슷하게 이종 컴퓨팅을 사용하는 시나리오를 생각해볼 수 있습니다.\nLPU : 단순한 판단, 도구 선택, 반복적인 루틴 작업, 라우팅(Routing) 등 빠른 반응이 필요한 가벼운 에이전트 작업(Worker)을 담당 GPU : 복잡한 논리 추론, 코드 생성, 이미지 렌더링 등 막대한 연산이 필요한 무거운 작업 담당 Agentic AI 시스템은 KV cache와 같은 텐서 형태가 아닌 텍스트(JSON) 기반으로 통신하기 때문에 물리적인 하드웨어 분리가 자유롭습니다. Speculative decoding에서 이야기한 병목인 통신 오버헤드에 대한 우려가 적기 때문입니다. 때문에 LPU + GPU 클러스터를 결합한다면 Agentic AI 서빙에 최적화된 데이터센터 플랫폼을 구성할 수 있을 것으로 생각됩니다.\n정리 이번 글에서는\nLPU의 등장 배경과 범용칩/전용칩의 차이 그록의 하드웨어/소프트웨어 설계 철학 엔비디아의 그록 인수 이후 예상되는 몇가지 기술적 시나리오 위 3가지에 대해 알아보았습니다.\n개인적으로 이번 인수건은 엔비디아가 자본력으로 하드웨어 시장에서 독점적 지위를 유지하기 위한 움직임으로 보여 무서운 감정이 들면서도, 저희 회사에서도 사용하는 LPU라는 용어가 시장과 대중들에게 한번 더 알려지는 계기가 된 듯 하여 양가적인 감정이 들게 하는 뉴스였습니다. 시장에서 저희 제품을 증명하게 된다면 저희 회사에게도 큰 기회가 많이 열릴 것이라는 기대감도 들었습니다.\n총 3편에 걸쳐 엔비디아의 GPU, 구글의 TPU, 그리고 그록의 LPU까지 다양한 AI 가속기에 대해 살펴보았습니다. 지금까지는 가속기의 아키텍쳐와 연산 구조에 중점을 두었지만, 다음 글에서는 연산 바깥에서 가속기만큼 중요한 역할을 하는 스토리지로 주제를 확장해보고자 합니다. 다음 편에서는 올해 CES에서 주목을 받은 엔비디아의 BlueField를 중심으로, AI 데이터센터에서 중요한 역할을 담당하는 스토리지와 DPU(Data Processing Unit)에 대해 알아보겠습니다.\n추신 : HyperAccel은 채용 중입니다. 저희 HyperAccel은 LPU 첫 제품 출시를 목전에 두고 있습니다. 이번 제품뿐만 아니라 앞으로 나올 다른 제품 개발을 위해서도 HyperAccel은 더 많은 훌륭한 엔지니어를 필요로 하고 있습니다.\n저희가 다루는 기술들을 보시고, 관심이 있으시다면 HyperAccel Career로 지원해 주세요!\nHyperAccel에는 정말 훌륭하고 똑똑한 엔지니어분들이 많습니다. 여러분의 지원을 기다립니다.\nReference Jonathan Ross Interview\nThink Fast: A Tensor Streaming Processor (TSP) for Accelerating Deep Learning Workloads, ISCA 2020\nA Software-defined Tensor Streaming Multiprocessor for Large-scale Machine Learning, ISCA 2022\nWhat is Language Processing Unit? - groq blog\ngroq whitepapers\nSpeculative Decoding - Nvidia blog\nRubin CPX platform - Nvidia blog\nNCCL Collective Operations\n","permalink":"https://hyper-accel.github.io/posts/lpu-deep-dive/","summary":"그록과 LPU의 탄생 배경과 그들의 하드웨어 / 소프트웨어 설계 철학에 대해 알아보고 엔비디아가 그록을 인수한 의도에 대해 분석해봅니다.","title":"지피지기면 백전불태 3편 : 엔비디아가 200억 달러에 인수한 그록의 LPU"},{"content":"SDD, 일의 의미가 변하는 시대에 적응하기 위하여 들어가며 안녕하세요, 저는 HyperAccel에서 RTL Designer로 재직중인 신승빈입니다.\n저는 일을 잘 하고 싶지만, 그렇다고 시간을 필요 이상으로 투자해서 그 목표를 달성하고 싶지는 않습니다.\n즉 \u0026ldquo;어떻게 하면 일의 가성비를 더 높일지\u0026rdquo; 항상 궁리하고 있습니다. 동일 시간동안 업무 퀄리티는 높이고 더 많은 일을 하면 저에게나 회사에게나 이득이니까요.\n2025년은 23년, 24년보다 더 활발했던 생성형 AI의 개발, 발전과 함께 소프트웨어 개발 업계는 이 글을 읽는 많은 분들께서 체감하실 정도로 그 형태가 많이 바뀐 한 해였다고 생각합니다.\n소프트웨어 개발 관련 지식이 전무한 하드웨어쟁이인 저도 몇 번의 대화를 거치면 제가 원하는 형태의 앱을 만들 수 있게 되었고, 홈페이지도 뚝딱하고 만들 수 있었죠.\n하지만 앱에 제가 원하는 기능을 하나씩 더 추가하고, 디자인도 보기 좋게 수정하려고 몇 번의 대화를 거치면 이전에 해결했던 버그가 새로 등장하거나, 버튼을 자기 마음대로 배치하는 등 엉뚱한 행동을 하기 십상이었습니다.\n결국 \u0026ldquo;제가 원하는 형태의 무언가\u0026quot;에는 도달할 수 있었지만, 2%, 아니 10%정도 부족한 수준에서 더 개선하기 어렵고 saturate되는 상황을 많이 직면할 수 있었습니다.\n이런 상황이 발생했을 경우 저는 해당 언어의 전문가가 아니기 때문에 그 코드셋을 바탕으로 수정할 수도 없었고, 만약 전문가였다고 해도 여러 번의 대화로 인해 뒤엉켜버린 스파게티 코드를 이해하기엔 시간이 많이 소요되었을 것입니다.\n저 혼자서는 그런대로 타협해서 쓸 수 있었지만, 이걸 실제로 사람들에게 서비스한다거나 판매한다고 생각하면 절대 관리할 수 없을 것이라고 생각했고, 결국 이런 형태의 개발은 한계가 명확하다고 느꼈습니다.\n물론 제가 전문가가 아니기 때문에 발생한 문제일 수 있지만, 오히려 전문가에게도 이런 형태의 업무 프로세스는 코드 리뷰, 리팩토링, 룰 준수, 테스트 생성 등의 과정이 더 많은 시간을 잡아먹고 결론적으로는 생산성 향상이 아닌 하락으로 이어질 수 있는 가능성이 훨씬 높을 것입니다.\n실제로 내가 많은 일을 하고 있는 것 처럼 보이지만, 쓸데없는 코드를 많이 생산하고, 유지보수에 많은 시간을 쏟고있는 것일 뿐, 시간 대비 생산하는 가치는 더 낮아질 수 있는 것이죠.\n이 글을 읽고 계신 분들 중에서도 이런 경험을 하신 분들이 적지 않을 것이라고 생각합니다.\n이런 악순환을 피하고, 최대한 효율적이면서도 빠르게, 양질의 토큰을 LLM들로부터 뽑아내서 저희가 원하는 결과물을 얻기 위한 방법론, SDD에 대해서 함께 알아봅시다.\n이 포스팅의 내용은 제가 개인적으로 공부하고, 경험한 내용을 바탕으로 작성되었습니다. 오류가 있다면 언제든지 댓글로 알려주세요.\nSDD? BDD, TDD, RDD와는 무엇이 다른가? 과거에, 어쩌면 지금도 여전히 많은 개발자들은 사람들끼리 업무를 할 때 과정과 품질을 높이면서도 협업 효율을 높이기 위해서 다양한 방법론을 사용하고 있습니다. 대중적인 방법론 몇 가지를 소개해 드리겠습니다.\nBDD(Behavior-Driven Development) BDD(Behavior-Driven Development)는 사용자의 행위(Behavior)를 자연어로 정의한 시나리오를 먼저 쓰고, 이를 테스트 코드로 변환하여 개발하는 방법론입니다. 예를 들면 \u0026ldquo;로그인 기능 구현\u0026rdquo; 이라고 하지 않고, \u0026ldquo;사용자는 아이디를 입력하고, 비밀번호를 입력한다. 이후 로그인 버튼을 클릭하면 비밀번호를 확인하고, 맞으면 메인 페이지로 이동하고, 틀리면 에러 메시지를 보여주고 메인 페이지로 이동하지 않는다.\u0026rdquo; 와 같이 구체적인 사용자의 행위를 기반으로 한 요구사항 명세서를 작성하는 것이지요.\nTDD(Test-Driven Development) TDD(Test-Driven Development)는 최소한의 테스트부터 작성하고, 이를 통과하는 코드를 작성하며 끊임없이 리팩토링하며 개발하는 방법론입니다. 마찬가지로 로그인 기능을 구현해야 했다면, \u0026ldquo;아이디가 비어있을 때 false를 뱉는 함수\u0026rdquo;, \u0026ldquo;비밀번호가 틀리면 예외처리를 하는 함수\u0026rdquo; 부터 시작하여 점차 복잡한 기능을 구현해 나가는 방향으로 개발이 진행됩니다.\nRDD(README Driven Development) RDD(README Driven Developement)는 코드를 짜기 전에, 소프트웨어 설명서를 가장 완벽하게 작성하고, 사용자가 어떻게 설치하고 사용할지를 상상하며 개발합니다. 특히 오픈소스 프로젝트에서 중요한데, 이 기능을 가져다 쓸 다른 개발자를 위한 안내서를 쓴 다음에 구현이 이루어진다는 점이 포인트입니다.\n앞서 설명한 3가지 방법론과, SDD(Spec-Driven Development)의 가장 큰 차이점은 \u0026ldquo;누구를 위한 약속인가\u0026quot;에 있습니다.\n기본적으로 지금까지의 방법론들은 \u0026ldquo;내가\u0026quot;혹은 \u0026ldquo;우리 팀이\u0026rdquo; 일을 잘 하기 위한 도구였습니다. 문서를 작성하다 보면 기업의 문화나 내부적인 성격이 녹아들어 다른 팀이 이해하기 어려운 경우가 발생할 수도 있죠. 하지만 애초에 내부 품질 향상을 위한 목적을 가지고 있기 때문에, 큰 문제가 되지 않습니다.\n이제 저희는 사람들과 한 코드를 가지고 씨름하는 시간보다도, LLM과 대화하며 결과물을 만들어내는 시간이 훨씬 많아졌습니다. 그런데 cursor나 antigravity와 같은 코딩 IDE 속에서도 코드 생성 모델을 바꾸기도 하고, 다른 세션에서 시작하기도 하고, 간혹 코드를 긁어서 다른 웹페이지의 모델에게 질문하기도 하죠. 이럴 때마다 확률형 생성 모델인 LLM은 조금씩 다른 결과물을 만들어 낼 수 밖에 없습니다. 그리고 가장 큰 문제는, LLM은 \u0026ldquo;기업 문화\u0026quot;라는 것에 관심이 없죠. 우리의 개발 환경과 스타일에 대한 \u0026ldquo;맥락 이해\u0026rdquo; 자체가 부족합니다.\nSDD는 \u0026ldquo;나\u0026quot;와 \u0026ldquo;LLM(AI Agent)\u0026rdquo; 사이의 엄격한 약속입니다. 그 어떤 모델이 오더라도 반드시 따라야 하는 룰로써 작동하고, 생성된 코드들의 연결과 호환성을 보장하는 역할을 합니다. 기존에 LLM을 마법 지팡이처럼 다루던 시대는 금세 지나가고, 이제는 LLM을 잘 다루기 위한 방법론이 필요한 시대가 온 것입니다. 물론 SDD가 만능은 아닙니다. 하지만 적어도 하나의 문서를 가지고 지속적으로 검증을 거치고, 최대한 원하는 형태에 가까운 결과물을 얻을 수 있다는 점에서 생산성 향상에 직접적인 도움을 주는 것이죠.\n간단하게 SDD가 어떤 느낌인지에 대해서 알아보았는데요, 그렇다고 TDD는 이제 죽은 방법론이고, SDD만 쓰면 되는 것일까요? 그렇지 않습니다. SDD는 TDD를 대체하는 방법론이 아니라, LLM을 더 효율적으로 쓰면서, TDD가 채워주지 못하는 부분을 보완하는 방법론입니다.\n여전히 SDD가 왜 필요한지, 설명서를 읽고 코드를 생성한다는 것 같은데, 애초에 원론적으로 이것이 왜 필요한지 의문이 드실 수도 있습니다. 다음 섹션부터 SDD의 등장 배경부터 이론적인 부분들까지 더 자세히 알아보도록 하겠습니다.\n알아보기도 전에 끝나버린 바이브 코딩의 시대, 다시 돌아온 엔지니어링 \u0026ldquo;어? 이게 되네?\u0026rdquo;\n제가 학부생활을 하던 시절, 처음으로 Chat GPT 3에게 코드를 짜 달라고 했을 때의 전율을 기억합니다.\n대충 말해도 찰떡같이 알아듣고 코드를 뱉어내는 경험은 정말 새로웠죠. 업계에서는 이걸 바이브 코딩(Vibe Coding)이라고 부르더라구요. AI와의 소통으로, 느낌(Vibe)만 가지고 결과물을 만들 수 있었으니까요.\n하지만 이 시기는 짧았습니다.\n앞서 제가 겪었던 것처럼, 프로젝트 규모가 조금만 커져도, 혹은 몇 번의 대화를 거칠수록 AI는 급속도로 멍청해지기 시작했습니다.\n변수명을 까먹고, 아까 고친 버그를 다시 만들어내고, 결국엔 \u0026ldquo;그냥 내가 짜고 말지\u0026quot;라는 생각이 들게 만드는 수정의 늪-Doom Loop에 빠지게 되죠.\n심지어 이미 뭔가 잘못됐다는 생각이 들었을 때는 코드가 너무 지저분하고 꼬여 있어 리팩토링을 한다거나, 수정한다는 것은 거의 불가능하기 일쑤였습니다.\n바이브 코딩의 실패는 단순히 AI 모델의 성능 문제가 아닙니다.\n이건 확률론적 생성에 의존하는 LLM의 본질적인 한계와, 엔지니어링의 부재가 만났을 때 필연적으로 발생하는 사고였습니다.\n이제 우리는 \u0026ldquo;마법\u0026quot;이 아니라 \u0026ldquo;공학\u0026quot;의 관점에서 AI를 바라봐야 할 때가 되었습니다.\nLLM 맛보기: Context Window와 Attention이란? 왜 AI는 대화가 길어지면 멍청해질까요? 이걸 이해하려면 LLM의 두뇌 구조인 Context Window와 Attention 메커니즘을 이해해야 합니다.\nContext Window: 창문을 통해 보는 영화 LLM의 기억력은 무한하지 않습니다. 가끔 채팅 모델을 사용하다 보면 \u0026ldquo;이걸 까먹었다고?\u0026rdquo; 라는 생각이 들 때가 있으셨을겁니다.\n이런 장난감을 보신 적 있나요? 저는 어릴 때 가지고 놀아 본 기억이 있는데요, 빙글빙글 돌리면 구멍을 통해서 말이 달리는 모습을 볼 수 있는, 잔상효과를 이용한 장난감입니다.\nLLM의 Context Window는 이 장난감의 구멍과 비슷하게 생각할 수 있습니다. 한번에 볼 수 있는 정보의 양이 제한적인 특징이 있죠.\n심지어 그 정보를 저장하는 메모리 또한 유한하기 때문에, 무한하게 늘릴 수도 없습니다. 결국 창 밖으로 벗어나버린 정보는 처리되지 않거나 잊혀지게 됩니다.\nAttention Mechanism: 칵테일 파티 효과 위에서 말한 창문이 정말 넓어져서 무한해졌다고 해도, 또 다른 문제가 있습니다. 바로 뭐가 중요한지 선택하기가 매우 어려워진다는 것입니다.\n우리는 친구가 열 명일때는 얼굴과 이름, 성격, 어쩌면 생년월일과 전화번호까지도 기억할 수 있습니다.\n게다가 열 명의 친구들은 모두 소중하죠. 하지만 친구가 만 명이 됐다면? 십만 명이 됐다면? 이름을 기억하는 것 조차 어려워집니다.\n칵테일 파티 효과는 파티의 참석자들이 시끄러운 주변 소음이 있는 방에 있음에도 불구하고 대화자와의 이야기를 선택적으로 집중하여 잘 받아들이는 현상에서 유래한 말이다. 이와 같이 주변 환경에 개의치 않고 자신에게 의미 있는 정보만을 선택적으로 받아들이는 것을 \u0026lsquo;선택적 지각(selective perception)\u0026lsquo;또는 \u0026lsquo;선택적 주의\u0026rsquo;라고 하는데, 이런 선택적 지각이나 주의가 나타나는 심리적 현상을 일컫는다. \u0026lsquo;자기 관련 효과(self-referential effect)\u0026rsquo;, \u0026lsquo;연회장 효과, 잔치집 효과\u0026rsquo;라고도 한다.\n어텐션 메커니즘은 칵테일 파티 효과와 참 비슷합니다.\n소란스러운 대화 속에서 중요한 한 줄, 사용자가 진짜 원하는 것을 찾아내야 하기 때문입니다.\nLLM도 수만 줄의 코드와 대화 로그에서 중요한 내용, 즉 핵심 요구 사항을 찾아내기 위한 수학적 메커니즘이 존재하는데요, 그것이 바로 Attention Mechanism입니다. 한 번쯤 들어보시거나 읽어보셨을 유명한 논문, \u0026ldquo;Attention is all you need\u0026quot;에서 제시한 개념이기도 하죠. 수학적인 설명은 생략하고, 전체를 다 기억하는 대신, 중요한 것만 골라보는 방법이라고 생각하시면 됩니다.\n대화가 짧을 때는 AI가 정확히 중요한 구간을 찾아냅니다. 하지만 대화가 수백 턴 이어지면 파티장은 아수라장이 되고, AI는 느려지고, 틀리고, 엉뚱한 답을 내뱉게 되는 것입니다. 마치 우리 저 식당 갔었지? 라고 말하는 상황처럼요..\n왜 SDD인가: 채팅 기반 코딩의 구조적 한계와 붕괴 이런 기술적 배경을 알고 나면, 왜 우리가 채팅창에서 코드를 짤 때 고통받았는지 명확해집니다.\n중간 소실 (Lost in the Middle) 현상: 연구에 따르면 LLM은 텍스트의 처음과 끝은 잘 기억하지만, 중간에 있는 내용은 기가 막히게 잘 까먹습니다. 채팅 초반에 정의한 데이터 구조나 유틸리티 함수들이 대화 중반부에 묻혀버리면, AI는 엉뚱하게도 이미 있는 함수를 새로 만들거나(중복 코드), 엉뚱한 변수를 가져다 쓰기 시작합니다.\n어텐션 희석 (Attention Dilution): 대화가 길어질수록 AI가 정보 하나하나에 쏟을 수 있는 \u0026lsquo;집중력\u0026rsquo;이 줄어듭니다. 중요한 요구사항이 잡담이나 에러 로그 사이에 섞여 희석되어 버리는 것이죠. 단순히 \u0026ldquo;아니 그게 아니라\u0026rdquo; 라고 치는 행동이 저희의 LLM을 더 힘들게 만들고 있던 것이죠. 감정적으로나 메모리적으로나 말입니다\u0026hellip;\n둠 루프 (Doom Loop): 에러가 나서 로그를 주면, 보통은 AI가 수정 코드를 줍니다. 근데 똑같은 에러가 또 납니다. AI의 컨텍스트 윈도우가 \u0026lsquo;실패한 시도\u0026rsquo;와 \u0026lsquo;에러 로그\u0026rsquo;로 가득 차버려서, 정답을 찾기보다 오답 패턴을 학습해버린 상태가 되는 겁니다. 실제로 학습해서 평생 그 답을 내는 일은 드물겠지만, 적어도 정답도 아닌 오답으로 가득찬 창문에서는 질문을 찾는 것 조차 어려워질 것입니다.\n결국 \u0026ldquo;채팅 로그를 스펙으로 삼는 것\u0026rdquo; 자체가 구조적으로 실패할 수밖에 없는 게임이었던 겁니다. 그래서 우리는 SDD로, 채팅을 최소화하고, 정제된 문서를 던져주는 방식으로 전환해야 합니다. 채팅 로그는 최소화하고, 필요한 내용들을 문서로 정리하고, 문서를 바탕으로 AI가 코드를 작성하는 방식으로 전환해야 합니다.\nSDD 워크플로우의 등장과 표준화 SDD의 핵심은 간단합니다. 코드는 휘발적이고, 스펙은 영구적이다라는 철학입니다. 코드는 스펙에서 언제든 다시 뽑아낼 수 있는 \u0026lsquo;부산물(Artifact)\u0026lsquo;로 취급하고, 우리가 관리해야 할 원본(Source of Truth)은 \u0026lsquo;자연어 명세서\u0026rsquo;가 됩니다. 특히 LLM 모델들의 성능이 기하급수적으로 좋아지면서, 오히려 \u0026ldquo;코드 품질\u0026quot;을 걱정하기 보다 내가 작성하는 \u0026ldquo;스펙 문서의 품질\u0026quot;을 더욱 중요하게 생각해야 합니다. 저에게 가장 부족한 문과적 소양이 다시 필요해지고 있는 것이죠\u0026hellip;\n일반적인 SDD 워크플로우는 다음과 같습니다.\nIntent (의도 설정): \u0026ldquo;무엇을 만들고 싶은가?\u0026ldquo;를 정의합니다.\nSpec Writing (명세 작성): AI와 대화하며 spec.md나 PRD.md 파일을 작성합니다. 여기에 기능, 데이터 모델, 제약 사항을 꽉 채워 넣습니다. 이 파일은 지속적으로 LLM이 참조하고, 상호 수정하고, 계속해서 업데이트되고 보존됩니다.\nGeneration (생성): \u0026ldquo;이 스펙대로 구현해\u0026quot;라고 명령합니다. AI는 스펙을 보고 구현 계획(Plan)을 세우고 코드를 짭니다. 이 부분은 특히 Antigravity가 잘 하는 것 같더라구요.\nVerification (검증): 결과물이 이상한가요? 코드를 고치지 마세요. 스펙을 고치고 다시 생성하거나, 테스트를 위한 문서를 작성하세요.\n이 과정은 마치 컴파일러에게 소스코드를 주고 실행 파일을 뽑는 것과 비슷합니다. 여기서 \u0026lsquo;소스코드\u0026rsquo;는 \u0026lsquo;자연어 스펙\u0026rsquo;이고, \u0026lsquo;컴파일러\u0026rsquo;는 \u0026lsquo;AI 에이전트\u0026rsquo;가 되는 셈이죠. 잠깐, 컴파일러가 무엇인지 궁금하신가요? 그렇다면 이 글을 읽어보세요.\nSDD를 위한 차세대 도구들 SDD가 무엇이고, 왜 등장했고, 사용해야 될 것 같다는 생각은 드셨을 것 같습니다. 간단하게 SDD를 사용해보실 수 있는 코딩 IDE를 소개합니다. 다행히 2025년과 2026년을 기점으로 SDD를 지원하는 강력한 도구들이 많이 쏟아져 나오고 있습니다.\nCursor \u0026amp; .cursorrules: 가장 접근하기 쉬운 도구입니다. 프로젝트 최상단에 .cursorrules 파일을 만들면 어떤 모델이든지 실행될 때 마다 이 규칙을 참조하게 됩니다. 이 파일이 LLM에게는 일종의 prefix처럼 작동하는 것이죠. 저는 보통 RTL Design이나, C++ 코딩에 관련된 rule들을 세팅하고 사용했는데요, example_cursorrules.txt는 제가 실제로 사용했던 rule 파일입니다. 당시엔 잘 몰라서 https://cursorrules.org/category 사이트에서 찾아 붙여넣는 형태로 작성했습니다. 엄밀하게는 SDD 라기보단 전체적인 코드 생성 스타일을 통일하는 목적으로 사용할 수 있습니다. 넓은 의미의 Spec 정의인 것이죠.\nGoogle Antigravity 구글이 내놓은 \u0026lsquo;에이전트 우선(Agent-First)\u0026rsquo; IDE입니다. 여기서는 AI가 단순히 코딩만 하는 게 아니라, 먼저 Implementation Plan이나 할 일 목록(Task List) 같은 문서를(Artifact) 먼저 만들어 결재를 받습니다. \u0026ldquo;코딩하기 전에 계획부터\u0026quot;라는 사수의 멘토링을 시스템화한 느낌이죠. 실제로 spec 문서를 작성하기가 어렵다면 이 implementation plan 문서를 바탕으로 시작해도 괜찮을 것 같습니다.\nOh-My-OpenCode (OpenCode) 오픈소스 진영의 반격입니다. oh-my-zsh처럼 플러그인 형태로 동작하는데, 재미있는 건 \u0026lsquo;Ultrawork\u0026rsquo; 모드입니다. \u0026ldquo;이거 될 때까지 집에 가지 마\u0026rdquo; 모드랄까요. 에러가 나면 AI 에이전트(Sisyphus)가 스스로 문서를 찾아보고, 디버깅하고, 재시도합니다. 특히 다양한 모델을 사용할 수 있고, 좀 더 \u0026ldquo;스스로 작동하는\u0026rdquo; 형태에 가까운 AI Agent를 엿볼 수 있다고 생각합니다. 제가 업무하는 형태와는 좀 방향이 달라서 저는 잘 사용하지 않지만, 최근에 굉장히 주목받고 있습니다.\n이 모든 게 가능한 이유는 SGLang이나 Guidance 같은 기술들이 AI가 뱉는 결과물을 강제로 JSON이나 특정 포맷으로 고정해주기 때문입니다. 덕분에 AI의 환각을 억제하고, 시스템끼리 대화할 수 있는 구조가 만들어진 것이죠. SGLang에 대해서는 이전 글에서 자세히 다루고 있으니, 궁금하신 분들은 참고해보시면 좋을 것 같습니다.\n결론: 우리는 어디로 가야하는가? SDD는 단순히 개발 방법론의 변화라기보단, 개발자의 정체성이 바뀌는 지점이 아닐까 생각하고 있습니다. 물론 전 일반적으로 개발자라고 불리우는 SW 개발자는 아니지만, HW 개발(RTL Design)에 있어서도 무언가 변하고 있다 내지는 가능성이 보인다고 체감하고 있습니다.\n이제 코딩을 하는 우리 모두는 똑똑한 AI 인부들을 지휘하는 작은 PM로 변모해야 합니다.\n코드를 빨리 치는 능력보다, 모호한 생각을 명확한 글로 정리하는 능력이 훨씬 중요한 시대가 다가올 것입니다.\n공학을 하기 위해 문학을 해야 하는 시대가 개화하고 있는 것이죠.\n게다가 대다수의 LLM들은 영어 입력에 대한 학습이 더 많이 이루어져 있기 때문에, 영어로 문서를 작성하는 것이 더욱 좋은 결과를 가져올 것은 거의 당연해 보입니다.\n혹자는 이를 두고 \u0026lsquo;1인 유니콘(1-Person Unicorn)\u0026rsquo; 기업이 탄생할 기반이 마련되었다고 합니다. 혼자서 기획, 디자인, 개발, 배포를 수십 명의 AI 에이전트에게 위임하며 운영하는 미래죠. 물론 바이브코딩만으로는 절대 달성할 수 없는 미래이고, 스펙 작성에 있어서도 너무 많은 문서작업이 수반되지 않으면서도 최고의 효율을, 내가 원하는 목적을 달성할 수 있도록 고민해야 합니다.\n엔비디아의 젠슨황은 최근의 많은 인터뷰에서 \u0026lsquo;가능한 한 AI를 최대한 활용하라\u0026rsquo; 라고 말했습니다. 최근 AI 버블이나, 일자리 감소에 대한 우려등이 많이 대두되고 있는 것과는 상반되는 인터뷰입니다.\n개인적으로 저 또한 RTL이지만 코딩을 하는 입장으로 이런 인터뷰가 반가우면서도, 마냥 낙관적으로만 바라볼 것이 아니라 각자의 입장에 맞춘 해석이 필요하다고 생각하고 있습니다.\n계산기가 처음 등장했을 때, 주산을 하던 사람들은 대부분 일자리를 잃었을 것입니다. 그러나 \u0026ldquo;계산\u0026quot;이라는 근본 자체가 사라진 것이 아니니, 결국 그 사람들은 남들보다 적어도 한 스텝 앞선 위치에서 계산기를 사용할 수 있었겠죠.\n현 상황도 저는 크게 다르지 않다고 생각합니다. 코딩에 대한 진입 장벽은 많이 낮아진 것이 맞습니다. 그렇지만 코딩을 단 한번도 해 보지 않은 사람이 구글, 아마존, 유튜브처럼 초거대 서비스를 만들 수 있을까요? 무한한 시간을 가정해도 결국엔 잔뜩 뒤엉킨 스파게티만 남고 실패할 것이라고 저는 자신있게 말씀드릴 수 있습니다. 이에 대해 더 하고 싶은 말이 많지만, 요약하면 \u0026ldquo;제대로 아는 사람이 더 잘 하게 되는, 빈익빈 부익부와 닮은 무언가의\u0026rdquo; 세상이 이미 오고 있다고 생각합니다. 그런 세상이 다가오는 지금, 저희는 한 발짝 앞서 있는 이점을 최대한 활용할 수 있어야 합니다.\n어쩌면 우리는 개발자로서 매우 중요한 시기를 지나고 있는지도 모릅니다. 인간과 AI가 함께 시스템을 만들어가는 새로운 프로토콜, 그 시작점에 SDD가 있습니다. 이 글을 읽으시는 분들은 지금 어떤 기능을, 서비스를 개발하고 계신가요? 마크다운 파일을 열고, 상상하고 계신 내용을 스펙으로 정의하는 순간, 새로운 엔지니어링이 시작될 것입니다.\n추신 저는 \u0026ldquo;어떤 엔지니어로 성장해야 하는가?\u0026ldquo;에 대한 고민을 계속 이어나가고 있고, 그 과정에서 SDD를 알게 되었습니다. 개인적으로 SDD는 가까운 시일 내에 주류가 될 개발 방법론이며, 스펙 문서를 작성하는 능력 자체도 경쟁력이 될 수 있다고 생각합니다. 결국 언젠가 사람들은 이 스펙 문서의 작성조차 생성형 AI 모델에게 요청하겠지만, 그 또한 \u0026ldquo;스펙 문서를 위한 스펙 문서\u0026quot;를 잘 작성할 수 있어야 최고의 스펙 문서를 얻을 수 있을 것입니다. 내가 뭘 하고 있는지는 당연히 잘 설명할 수 있어야 하지만, 이 개발의 Context를 알지 못하는 LLM에게 내가 원하는 바를 정확히 전달하는 능력이 중요해질 것입니다.\n순수하게 비어있는 main.cpp에서부터 코드를 작성하는 시대는 지나갔습니다. 이제는 어디서 내 경쟁력을 찾아야 할 지 고민이 필요한 시점이고, 저는 그 시작이 바로 스펙 문서를 작성하는 능력을 키우는 것이라고 생각합니다. 여러분은 어떻게 생각하시나요?\n개인의 성장을 위해서는 스펙 문서를 잘 쓰는 것도 중요하지만 \u0026ldquo;누구와 함께\u0026rdquo; 일하는지도 매우 중요합니다.. 이런 점에서 저희 HyperAccel은 이런 부분에서 최고의 회사라고 자부합니다. LLM이 되었든 사람이 되었든 업무를 지시하기 위해서는 다방면으로 지식이 필요하게 됩니다. 저희는 LLM 가속 ASIC 칩 출시를 위해 HW, SW, AI를 모두 다루는 회사로 전 방면에 걸쳐 뛰어난 인재들이 모여있고, 이런 환경에서 한 분야에 국한된 것이 아닌 폭넓은 지식을, 심지어 깊게 배우며 지식을 공유하고 함께 성장하고 싶으신 분들은 언제든지 저희 HyperAccel에 지원해주세요!\n채용 사이트: https://hyperaccel.career.greetinghr.com/ko/guide\nReference 칵테일 파티 효과 조이트로프 Why Your AI Coding Agent Keeps Making Bad Decisions(And How To Fix It) Spec-Driven Development: Building Better Software, Faster with Kiro Lost in the Middle: How Language Models Use Long Contexts Attention Dilution Reasons I Found Why AIs Struggle With Coding introducing-google-antigravity The Ultimate Guide to AI-Powered Development with Cursor: From Chaos to Clean Code Oh-My-OpenCode The Rise of the “Zero-Employee” Unicorn: The Comprehensive Guide to the Post-Labor Startup Extract, Edit, Apply – a design pattern for AI ‘Are you insane?’: Billionaire CEO Jensen Huang blasts Nvidia managers who are ‘telling their people to use less AI’ ","permalink":"https://hyper-accel.github.io/posts/what-is-sdd/","summary":"AI 시대의 새로운 개발 방법론, Spec-Driven Development에 대해 알아보고, 프롬프트 엔지니어링을 넘어 스펙(Spec) 엔지니어링으로 나아가는 방향을 제시합니다.","title":"Specs are All You Need: Spec-Driven Development (SDD)란 무엇인가?"},{"content":"오늘은 조금은 색다른 주제를 가지고 왔습니다. 컴파일러를 사용하다가, 자동으로 컴파일러가 loop을 변형하여 최적화해주거나, 병렬화를 해 주면 좋겠다고 생각한 적이 있지 않은가요? 컴파일러 엔지니어들도 이러한 고민들을 해왔습니다. 그 중 하나의 방법으로 등장한 것이 polyhedral compiler 인데요, LLVM Polly 프로젝트, MLIR affine dialect가 사용하는 방법이기도 합니다. 오늘은 이 방법에 대해 소개해 보겠습니다.\n기본 개념 먼저, 자세히 설명하기 전에 기본적인 개념을 짚고 넘어가고자 합니다. 대부분의 개념들은 선형대수학을 조금만 알고 있다면 쉽게 접할 수 있는 것들입니다.\nAffine function (아핀 함수) Affine 함수는 선형 변환 + 평행이동 으로 정의 가능한 함수를 의미합니다. Affine 변환을 하게 되면, 원래 선을 이루던 점들은 같은 선으로 이동하고, 두 선분의 중앙에 있던 점은 변환 후에도 여전히 중앙에 있지요. 즉, 일차 변환에서 상수합을 가능하도록 한 것을 affine 변환이라고 생각하시면 됩니다.\n$f(\\vec{v})=M_f\\vec{v}+\\vec{f}_0$\nM은 행렬을 의미하며 $\\vec{f}_0$ 는 상수 행렬을 의미합니다.\nAffine hyperplane (아핀 초평면) n 차원 공간에서 n-1 차원인 affine subspace를 affine hyperplane 이라고 합니다.\nhyperplane은 다음을 만족하는 벡터 ( $\\vec{v}$) 의 집합입니다.\n$k = h\\vec{v}$ (k는 상수)\n즉, n이 3차원이라면, hyperplane은 2차원 면이 됩니다.\nPolyhedron Polyhedron이란, 유한 개의 Affine hyperplane으로 인해 나눠진 공간 (half-space) 의 교집합입니다. 그리고, bounded된 polyhedron을 polytope이라고 부릅니다. (닫힌 공간이라는 의미입니다)\n아래 그림에서는, 4개의 1D hyperplane (2D space 이므로 hyperplane은 1D) 가 존재하며, 이로 인해 polytope를 정의할 수 있습니다. 즉, 다음 식에서 정의한 $\\vec{x}$의 집합이라 할 수 있지요.\n${\\vec{x} \\in \\mathbb{R} | A\\vec{x} + \\vec{b} \\ge 0 }$\n$A \\in \\mathbb{R}^{m \\times n}, \\vec{b} \\in \\mathbb{R}^m$ (n 차원에서 m개의 hyperplane으로 인해 bound된 polyhedron일 때)\nFarkas Lemma 도메인 $D$ 를 half-space들로 정의되는 polyhedron이라고 할 때,\nFarkas lemma는 도메인 D 안에서 affine form (아핀 함수)을 도메인 D를 정의하는 half-space 들의 선형 식으로 표현 가능함을 의미합니다.\n다시 말해, half space들이 다음과 같이 정의될 때,\n$a_k\\vec{x} + b_k ≥ 0, k = 1,p$\naffine function (아핀 함수) $\\psi(\\vec{x})$ 가 D 안에서 non-negative인 것과 $\\psi(\\vec{x})$ 가 non-negative인 half space들의 선형 결합으로 표현 가능하다는것은 동치입니다.\n$\\psi(\\vec{x}) = \\lambda_0 + \\sum_{k=1}^{p}\\lambda_k(a_k\\vec{x} + b_k)\\ where \\ \\lambda_0, \\lambda_1, \u0026hellip;, \\lambda_p \\ge 0$\n조금 더 풀어서 설명하자면 우리가 어떤 아핀 함수를 정의했고, 이것이 domain D 안에 있다고 하겠습니다. 만약 이 함수가 비음수 (non-negative)라면, 그 함수는 domain D를 정의하는 half-space들의 선형 식으로 표현이 가능하며, 또한 그 반대(역) 도 성립합니다.\n이 Lemma를 이용하여 Affine 함수로 정의된 schedule을 변환할 때, half-space들의 선형 결합으로 변환하여 ILP를 이용해 문제를 더 쉽게 풀 수 있도록 해 줍니다.\n프로그램의 구성 요소의 해석 이제 기본이 되는 개념들을 소개했으니, 어떻게 우리가 프로그램을 표현할 수 있는지 살펴보도록 합시다.\n간단한 프로그램을 하나 가져와 보겠습니다\nfor(int i = 0; i \u0026lt; N; ++i){ for(int j = 0; j \u0026lt; N; ++j){ x[i] = x[j]*2 + y[j]; // Statement 1, iteration vector : (i, j) } for(int k = 0; k \u0026lt; N; ++k){ y[i] = y[i]*2; // Statement 2, iteration vector : (i, k) } } 이 프로그램은 3개의 loop과 2개의 statement로 이루어져 있습니다. 각 statement 는 iteration vector를 가지는데, iteration vector란, 각 statement가 영향을 받는 loop induction variable (Loop에서 변하는 index variable. 위 예시에서는 i, j, k)들을 벡터 형태로 표현한 것입니다.\n즉, Statement 1 x[i] = x[j]*2 + y[j] 의 iteration vector는 (i, j) 가,\nStatement2 y[i] = y[i]*2 의 iteration vector는 (i, k) 가 됩니다.\nSchedule vector Schedule vector란 각 statement가 언제 실행될지 나타내는 vector입니다. schedule vector에는 statement가 속한 위치와 감싸고 있는 loop들에 대한 정보가 들어 있습니다.\nSchedule vector는 statement의 실행 시점을 나타내며, polyhedral analysis에서는 이를 이용하여 statement의 조건을 검사하거나, transformation을 수행하게 됩니다.\n위 예시에서, Statement 1의 schedule vector는 (i, 0, j) 가, Statement 2는 (i, 1, k) 가 됩니다.\nSchedule vector를 설정하는 방법은 다음과 같습니다.\nOutermost scope부터 기술 loop이 존재한다면, 그 loop의 induction variable을 넣는다 한 scope안에 여러 statement (loop 포함) 이 존재한다면, scalar 값을 넣어 분리합니다 (이를 scalar dimension이라 부릅니다) 위 예시에서는 loop i 내부에 loop이 2개가 있으므로, 이를 scalar dimension으로 분리했습니다. 1,2,3 에 의해, 가능한 schedule vector의 최대 길이는 nested loop이 m개 있다 할 때, 2m + 1개가 됩니다. \u0026lt;가장 바깥쪽 scope의 scalar dimension\u0026gt; + \u0026lt;각 loop의 iteration vector\u0026gt;*m + \u0026lt;각 loop 내부의 scalar dimension\u0026gt; = 2m + 1 일반적으로, scalar dimension이 필요 없는 경우 (즉, scope내부에 statement가 1개인 경우) 는 scalar dimension을 생략합니다. 또 다른 예시를 들어 볼까요?\n아래와 같은 코드가 있다고 합시다.\nfor (int i = 0; i \u0026lt; N; ++i) { for (int j = 0; j \u0026lt; N; ++j) { A[i][j] = A[i][j] + u[i] * v[j] + u2[i] * v2[j]; // S0 } B[i] = A[i][0]; // S1 } for (int k = 0; k \u0026lt; N; ++k) { for (int l = 0; l \u0026lt; N; ++l) { x[k] = x[k] + beta * A[l][k] * y[l]; // S2 } } 그렇다면, 각 Statement는 다음과 같은 schedule vector를 가지게 됩니다\nS0 : $\\begin{pmatrix}0\u0026amp;i\u0026amp;0\u0026amp;j\\end{pmatrix}$ → 0 번째 loop i 내부 0번째 loop j의 유일한 statement\nS1 : $\\begin{pmatrix}0\u0026amp;i\u0026amp;1\\end{pmatrix}$ → 0번째 loop i 내부 1번째 statement\nS2 : $\\begin{pmatrix}1\u0026amp;k\u0026amp;l\\end{pmatrix}$ → 1번째 loop k의 내부 유일한 loop l 의 유일한 statement\nPolyhedral analysis 이제 Polyhedral analysis를 수행해 봅시다. 가장 먼저, loop이 병렬화가 가능한지 분석을 해 보겠습니다.\nParallelism analysis 다음 코드를 생각해보죠. 아래 코드는 병렬화가 가능할까요?\n// Q. loop i 와 loop j 는 병렬화가 가능한가? for(int i = 0; i \u0026lt; N; ++i){ for(int j = 0; j \u0026lt; N; ++j){ if(i \u0026gt; j) b[i][j] = b[j][i]; // S0 } } 우선 병렬화가 가능하려면 어떤 조건이 필요할까요? loop i 혹은 loop j를 병렬화 하려면, 각 iteration사이에 아무런 연관성이 없어야 합니다. 각 iteration이 독립적으로 실행된다면 상관 없지만, 한 iteration에서 쓴 것을 이후의 다른 iteration에서 읽어야 한다면 (혹은 그 반대가 된다면) loop을 병렬화할 수 없겠지요. 그렇다면 위의 예시 코드는 어떤가요?\n이 코드는 matrix B를 transpose하고 있습니다. 상삼각 matrix (upper-triangular matrix)를 하삼각 matrix (lower-triangular matrix) 로 옮겨 쓰고 있지요. 따라서, 각 loop iteration 사이에 아무런 관계가 없으므로 (dependency가 없으므로) 병렬화가 가능합니다.\n그러면 이것을 Polyhedral analysis로 어떻게 알 수 있을까요? 우리는 몇 가지 과정을 거쳐서 이를 알아낼 수 있습니다.\n각 statement의 iteration vector를 구합니다. iteration vector를 바탕으로, Domain을 나타냅니다. Domain이 비어있는지 확인합니다. S0의 iteration vector는 (i, j)가 됩니다. 그리고, S0에는 읽기와 쓰기, 두 개의 동작이 있지요.\n그럼 S0를 읽기와 쓰기 관점에서 보게 되면,\nRead_s0(i, j) = (j, i)\nWrite_s0(i, j) = (i, j)\n그리고, S0의 polyhedron (Domain $D_{s0}$)은 다음과 같이 정의됩니다.\ni ≥ 0 \u0026amp;\u0026amp; i \u0026lt; N j ≥ 0 \u0026amp;\u0026amp; j \u0026lt; N i \u0026gt; j Memory dependency가 있으려면, 다음을 만족해야 합니다.\n$$ \\exists(\\vec{s}, \\vec{t}) : \\begin{cases} \\vec{s} \\in D_{s0} \\newline \\vec{t}\\in D_{s0} \\newline W(\\vec{s}) = R(\\vec{t})\\end{cases} $$\n이때 $\\vec{s}$ 와 $\\vec{t}$ 는 서로 다른 임의의 iteration vector 이며, 각 iteration에서 statement S0를 read 및 write관점으로 해석합니다. 즉, 각 loop에서 병렬화가 가능하려면 서로 다른 iteration vector를 넣었을 때, $R(\\vec{t})$(READ_s0(i, j)) 와 $W(\\vec{s})$(WRITE_s0(i, j)))가 같으면 안 되겠지요?\n자 이제, $\\vec{s} = (i, j), \\vec{t} = (i\u0026rsquo; ,j\u0026rsquo;)$ 으로 표현하여 그대로 대입해보겠습니다.\n$W(\\vec{s}) = R(\\vec{t})$ 를 풀어 쓰면, $(i\u0026rsquo;, j\u0026rsquo;) = (j, i)$ 이고, 이를 Read시의 조건에 대입하면, $i\u0026rsquo; \u0026gt; j\u0026rsquo; \\implies j \u0026gt; i$ 이며, Write시 조건은 $i \u0026gt; j$ 가 되지요.\n그런데, $i \u0026gt; j$ 과 $j \u0026gt; i$ 는 당연히 동시에 만족될 수 없겠지요?\n따라서, dependence polyhedron은 공집합이 되어 아무런 iteration간 아무런 dependency가 없으므로, loop i 및 loop j가 모두 병렬화 가능하다는 결론에 이르게 됩니다. (애초에 domain이 공집합이니, Schedule vector를 만들 필요가 없지요)\n하나의 예시를 더 들어 보겠습니다.\nfor(int i = 0; i \u0026lt; N; ++i){ for(int j = 0; j \u0026lt; M; ++j){ a[i][j] = a[i][j-1]; // S0 } } 이 경우 코드는 어떻게 병렬화가 가능할까요?\niteration domain\ni ≥ 0 \u0026amp;\u0026amp; i \u0026lt; N j ≥ 0 \u0026amp;\u0026amp; j \u0026lt; M iteration vector\n$$ \\exists(s, t) : \\begin{cases} \\vec{s} \\in D_{s0} \\newline \\vec{t}\\in D_{s0} \\newline W(\\vec{s}) = R(\\vec{t})\\end{cases} $$\n이를 통해 Schedule vector를 만들어 봅시다. Parallel 하다는 것은, 각 Schedule 사이의 dependency가 없어야 한다는 의미이므로, 모든 loop이 병렬화가 가능하려면, 아래와 같은 조건을 만족해야 합니다. (일부만 0이라면 해당 dimension에 해당하는 loop만 병렬화가능)\n($\\phi(\\vec{s}), \\phi(\\vec{t})$ 는 각 iteration에서의 schedule vector라 합시다.)\n$$ \\phi_{s0}(\\vec{t}) - \\phi_{s0}(\\vec{s}) =\\vec{0} $$\nScalar dimension을 생략한다면,\n$$ \\begin{pmatrix}i \\newline j \\end{pmatrix} - \\begin{pmatrix} i\u0026rsquo; = i \\newline j\u0026rsquo; = j-1 \\end{pmatrix} = \\begin{pmatrix}0 \\newline 1 \\end{pmatrix} $$\n즉, loop i는 0, loop j는 1이 나왔으므로, loop j에만 dependency가 존재함을 알 수 있습니다. 따라서, 위 예제는 loop i만 병렬화가 가능합니다.\n이렇게 schedule vector를 만들어서 병렬성을 분석하는 예시도 만들어 보았습니다.\nPolyhedral transformation 이제, polyhedral transformation에 대해 알아봅시다. polyhedral transformation은 분석한 code를 더 효율적으로 바꾸는 과정인데요, llvm-polly같은 라이브러리에서 최적화를 위해 실행합니다.\n핵심은, 코드의 correctness를 유지하면서, cost function을 만들어, cost를 줄이는 방향으로 코드를 변환하는 것입니다.\nStatement $S^k$의 $i$ 번째 dimension에 관하여 schedule vector의 일부를 다음과 같이 쓸 수 있습니다.\n$$ \\phi_{S_i^k}(\\vec{t})=\\begin{pmatrix}c_0^i\u0026amp;c_1^i\u0026amp;\\cdots\u0026amp;c_n^i\\end{pmatrix}\\begin{pmatrix}i_0\\newline i_1\\newline i_2\\newline \\cdots\\newline i_{n-1}\\newline 1\\end{pmatrix} $$\n$c_0^i \u0026hellip;c_n^i$ 은 polyhedral optimization을 통해 찾는 transformation parameter 들입니다. $c_n^i$는 scalar dimension을 나타낼 때 사용됩니다.\n이를 모든 dimension에 관해 표현할 경우 다음과 같이 쓸 수 있습니다.\n$$ \\tau_s \\vec{t}=\\begin{pmatrix}\\phi_{S_i^0}(\\vec{t}) \\newline\\phi_{S_i^1}(\\vec{t}) \\newline\\vdots \\newline\\phi_{S_i^{k-1}}(\\vec{t})\\end{pmatrix}=\\begin{pmatrix}c_1^0 \u0026amp; c_2^0 \u0026amp; \\cdots \u0026amp; c_n^0 \\newline c_1^1 \u0026amp; c_2^1 \u0026amp; \\cdots \u0026amp; c_n^1 \\newline\\vdots \u0026amp; \\vdots \u0026amp; \\ddots \u0026amp; \\vdots \\newline c_1^{k-1} \u0026amp; c_2^{k-1} \u0026amp; \\cdots \u0026amp; c_n^{k-1}\\end{pmatrix}\\vec{t}+\\begin{pmatrix}c_0^0 \\newline c_0^1 \\newline \\vdots \\newline c_0^{k-1}\\end{pmatrix} $$\n이때 $\\vec{t}$는 iteration vector를 의미합니다.\nTransformation matrix 내부의 parameter들을 정하게 되면, 새로운 schedule vector가 나오겠지요? 그럼 우리가 이전에 정한 constraint들을 유지한 채로, transformation matrix를 적용해서 나온 schedule vector대로 프로그램을 만들면, 그 프로그램은 모습이 조금 바뀌겠지만, (Loop 의 구조나 statement들의 index가 바뀌겠지만) 변환 이후에도 정상적인 동작을 할 것입니다. 어쩌면 새로운 구조에서는 병렬화가 가능해지거나, temporary variable이 필요하지 않을수도 있지요.\nTransformation parameter는 일반적으로는 ILP를 통해 cost function을 최소화시키는 방향으로 찾으나 genetic algorithm, bayesian optimization, RL 등등의 다양한 방법을 생각해볼 수 있습니다.\n이 역시 예시를 통해 자세히 생각해 봅시다.\nfor(i = 0; i \u0026lt; N; ++i){ for(j = 0; j \u0026lt; N; ++j){ for(k = 0; k \u0026lt; N; ++k){ c[i][j] = c[i][j] + a[i][k] * b[k][j]; // S1 } } } for(i = 0; i \u0026lt; N; ++i){ for(j = 0; j \u0026lt; N; ++j){ for(k = 0; k \u0026lt; N; ++k){ d[i][j] = d[i][j] + e[i][k]*c[k][j]; // S2 } } } 자 그럼 이 코드를 간단히 transformation 하는 예시를 봅시다.\nStatement S1의 변환:\n$$ \\tau_{s_1}(\\vec{i}_{s_1}) = \\begin{pmatrix} 0 \u0026amp; 1 \u0026amp; 0 \\newline 1 \u0026amp; 0 \u0026amp; 0 \\newline 0 \u0026amp; 0 \u0026amp; 0 \\newline 0 \u0026amp; 0 \u0026amp; 1\\end{pmatrix}\\begin{pmatrix}i \\newline j \\newline k \\end{pmatrix} + \\begin{pmatrix} 0 \\newline 0 \\newline 0 \\newline 0\\end{pmatrix} $$\n따라서 각 dimension의 schedule은:\n$$ (\\phi_{S_1}^1, \\phi_{S_1}^2, \\phi_{S_1}^3, \\phi_{S_1}^4) = (j, i, 0, k) $$\nStatement S2의 변환:\n$$ \\tau_{s_2}(\\vec{i}_{s_2}) = \\begin{pmatrix} 0 \u0026amp; 1 \u0026amp; 0 \\newline 0 \u0026amp; 0 \u0026amp; 1 \\newline 0 \u0026amp; 0 \u0026amp; 0 \\newline 1 \u0026amp; 0 \u0026amp; 0\\end{pmatrix}\\begin{pmatrix}i \\newline j \\newline k \\end{pmatrix} + \\begin{pmatrix} 0 \\newline 0 \\newline 1 \\newline 0\\end{pmatrix} $$\n따라서 각 dimension의 schedule은:\n$$ (\\phi_{S_2}^1, \\phi_{S_2}^2, \\phi_{S_2}^3, \\phi_{S_2}^4) = (j, k, 1, i) $$\n이것은 새로운 schedule vector입니다. vector의 각 loop을 순서대로 t0, t1, t3 라 하고 새로운 loop을 만들어 보면 아래와 같은 코드를 얻을 수 있습니다.\nfor(t0 = 0; t0 \u0026lt; N; ++t0){ for(t1 = 0; t1 \u0026lt; N; ++t1){ for(t3 = 0; t3 \u0026lt; N; ++t3){ // i -\u0026gt; t1, j -\u0026gt; t0, k -\u0026gt; t3 c[t1][t0] = c[t1][t0] + a[t1][t3]*b[t3][t0]; // S1 } for(t3=0; t3 \u0026lt; N; ++t3){ // i -\u0026gt; t3, j -\u0026gt; t0, k -\u0026gt; t1 d[t3][t0] = d[t3][t0] + e[t3][t1]*c[t1][t0]; // S2 } } } 이 코드는 원래 코드와 같은 동작을 하지만, loop의 구조가 조금 달라졌습니다 (맨 바깥쪽 loop이 하나로 합쳐졌지요). 이 프로그램이 기존과 똑같은 결과를 낸다는 것은 우리가 transformation matrix의 파라미터를 이전 프로그램의 constraint (dependency 등) 를 만족한다는 가정을 미리 넣고 찾았기 때문에 보장된다고 할 수 있습니다.\n결국 핵심은, domain constraint들을 모두 만족하면서 가장 cost function을 작게 만드는 transformation matrix $\\tau_s$를 찾는 것인데요, 보통은 ILP를 통해 찾습니다. 예를 들어, 위 예시에서는 statement S2 에서 C를 read하는 부분이 statement S1 에서 C를 write하는 부분보다 나중에 실행되어야 한다는 constraint와, i, j, k의 loop 범위에 관한 constraint들을 추가할 수 있겠지요? 이러한 constraint를 추가한 다음 ILP를 푸는 식이지요.\n보다 구체적으로 optimal transformation matrix를 어떻게 찾는지에 관한 알고리즘은 다음 글에서 설명드리도록 하겠습니다.\n참고 문헌 Effective Automatic Parallelization AND Locality Optimization Using The Polyhedral Model (Uday, 2008)\n","permalink":"https://hyper-accel.github.io/posts/polyhedral-compiler-analysis/","summary":"\u003cp\u003e오늘은 조금은 색다른 주제를 가지고 왔습니다. 컴파일러를 사용하다가, 자동으로 컴파일러가 loop을 변형하여 최적화해주거나, 병렬화를 해 주면 좋겠다고 생각한 적이 있지 않은가요? 컴파일러 엔지니어들도 이러한 고민들을 해왔습니다. 그 중 하나의 방법으로 등장한 것이 \u003cstrong\u003epolyhedral compiler\u003c/strong\u003e 인데요, \u003cstrong\u003eLLVM Polly\u003c/strong\u003e 프로젝트, \u003cstrong\u003eMLIR affine dialect\u003c/strong\u003e가 사용하는 방법이기도 합니다. 오늘은 이 방법에 대해 소개해 보겠습니다.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"기본-개념\"\u003e기본 개념\u003c/h2\u003e\n\u003cp\u003e먼저, 자세히 설명하기 전에 기본적인 개념을 짚고 넘어가고자 합니다. 대부분의 개념들은 선형대수학을 조금만 알고 있다면 쉽게 접할 수 있는 것들입니다.\u003c/p\u003e","title":"Polyhedral Analysis"},{"content":"2025년에 바라보는 CES 2026 핵심 정리 (feat. SAMSUNG, SK, LG) 안녕하세요? HyperAccel ML팀 소속 박현준입니다.\n1월 6일에 라스베가스에서 시작한 CES가 1월 9일 성황리에 종료되었습니다. 우선 저는 작년(2025년) CES에 참여하여 하이퍼엑셀 부스를 운영했었고, 해당 경험을 바탕으로 올해(2026년) CES를 리뷰해보려고 합니다. 혹자는 왜 작년에 안 올리고 이제서야 올리는지 의문을 가질 수 있는데요,\n이유는 간단합니다. 작년에는 테크 블로그가 없었기 때문입니다. 작년에 참여한 입장으로서 CES 2026에 대한 기사를 보니 올해는 어땠을지 궁금해졌고, 테크 블로그에 글을 쓰겠다는 명분 덕분에 올해 CES에 대해 알아보는 시간을 가질 수 있었습니다. 아래 목록에 해당되는 분들께는 이번 포스트가 도움이 될 것 같습니다:\nCES 관련 통계 및 핵심 정리가 궁금하신 분 CES 부스 준비 및 운영 후기가 궁금하신 분 한국의 대기업(LG, SAMSUNG, SK)의 전시품 및 컨셉이 궁금하신 분 CES 관련 통계 및 핵심 정리 CES는 1967년을 시작으로 매년 열리는 세계 최대 규모의 소비자 가전 전시회입니다. 기업 입장에서는 자사의 기술을 뽐내며 마케팅 및 브랜딩을 할 수 있으며, 관람객 입장에서는 최신 기술 동향을 파악할 수 있습니다. 우리나라는 미국과 중국에 이어 3번째로 많은 기업이 참여하고 있으며, 혁신상 수상 개수는 세계 1위를 기록하며 국내 기술력을 전 세계에 뽐내고 있습니다.\n2025 2026 슬로건 DIVE IN - Connect. Solve. Discover innovators show up 키워드 AI\u0026amp;로보틱스, 모빌리티, 확장현실, 스마트홈, 디지털 헬스케어 피지컬 AI, 공간 컴퓨팅, 디지털 헬스, 모빌리티, 스마트홈 참여 국가 및 기업 160여 개국 4800+ 기업 150여 개국 4500+ 기업 참여 국내 기업 1000+ 기업 1000+ 기업 국내 기업 최고혁신상 34개 중 15개 (44%) 30개 중 15개 (50%) 국내 기업 혁신상 458개 혁신상 중 219개 수상 (47.8%) 367개 혁신상 중 222개 수상 (60.5%) 일단 CES의 첫 인상을 말씀드리자면 제 예상보다 훨씬 더 컸습니다. 흡사 대학교 캠퍼스를 돌아보는 듯한 느낌을 받았습니다. 사전에 가보고 싶은 부스들을 정리해두고 참여했음에도 불구하고 원하는 부스들을 찾기가 어려웠고, 다른 캠퍼스로 이동하려면 셔틀 버스를 타야 했는데, 대기 줄이 길어서 동선을 짜기도 쉽지 않았습니다.\n저는 이러한 고민을 하던 찰나에 K-STARTUP 통합관에서 운영하는 부스 투어를 현장 신청하여 주목받는 글로벌 기업들의 부스를 최적화된 동선으로 볼 수 있었습니다. 편하게 글로벌 기업의 부스를 전체적으로 둘러볼 수 있어서 좋았지만, 한편으로는 제가 보고 싶은 부스를 집중해서 보지 못했다는 아쉬움도 남았습니다. 저는 만약 특별한 니즈가 없으시다면 부스 투어를 찾아서 이용하는 방식을 추천드리고, 특별한 니즈가 있으시다면 동선까지 꼼꼼하게 짜오시기를 추천드립니다.\n관람 포인트나 동선 관련 분석은 KOTRA라는 기업에서 매년 작성해주고 있는데요, 제가 쓴 글은 아니지만 잘 쓰여진 글이라고 생각되어 추천하고 공유드립니다.\nCES 2025 가이드: https://dl.kotra.or.kr/pyxis-api/2/digital-files/51efe51a-718d-4f3a-9182-12c424384f7b\nCES 2026 가이드: https://dl.kotra.or.kr/pyxis-api/2/digital-files/719ffe16-6ece-4214-969f-b663985315d3\nCES 2025 참가 후기 중소벤처기업부에서는 스타트업 육성을 위한 \u0026ldquo;초격차 스타트업 1000+\u0026rdquo; 프로젝트를 진행하고 있고, 프로젝트 중 일부로 한국 스타트업들을 모아 매년 CES 전시관을 운영하고 있습니다. 규모가 작은 스타트업도 편하게 참여할 수 있도록 잘 짜여 있었습니다.\n이렇게 CES 진입장벽을 낮춰주신 덕분에 작년에도 올해도 K-STARTUP 통합관에 많은 기업이 참여하고 있고, 올해 기준으로는 무려 38개 기관에서 470개 사가 참여하였습니다. 한국 전체로 봤을 때는 1000여 개의 회사가 참가하였습니다. 이러한 지원이 한국이 CES 혁신상을 가장 많이 받도록 하는 강력한 원동력 중 하나가 아닐까 생각이 들었습니다.\n참가사 입장에서도 K-STARTUP 문구 덕분에 다양한 국적, 다양한 분야의 분들께서 부스를 방문해주셨는데요, 고객사/투자자/협업사 등 수많은 분들과 이야기를 나눌 수 있었습니다. 회사 차원에서는 파트너들과 관계를 쌓을 수 있을 뿐만 아니라 고객사에게 브랜딩을 할 수 있는 소중한 자리였고, 개인 입장에서도 인사이트를 키울 수 있는 좋은 기회였습니다.\n잘 도와주신 덕분에 저희도 처음임에도 불구하고 \u0026ldquo;참여\u0026quot;보다 \u0026ldquo;전시\u0026quot;에 집중할 수 있었고, 성공적으로 CES 부스 운영을 마칠 수 있었습니다. 작년에 전시했던 저희 부스 모습입니다. 사진에 보이는 서버는 FPGA 기반 1세대 서버로, LLM 추론을 위한 차세대 AI 칩 개발의 첫 단계였습니다.\n한국 대기업의 CES 전시 동향 처음 보는 신기술로 모두를 놀라게 한 글로벌 기업들도 많이 있었습니다만, 아무래도 실제 현장에 갔을 때는 세계 무대에서 글로벌 기업들과 당당히 어깨를 나란히 하고 있는 한국 기업을 볼 때 더 가슴이 뛰었습니다.(국뽕맞음) 따라서 이번 목차에서는 한국의 대기업인 삼성, LG, SK가 CES 전시를 어떻게 운영하는지 2025년과 2026년을 비교해 보며 알아보고자 합니다.\n회사 구분 2025년 2026년 LG 혁신상 LG OLED TV 등 24개 제품 webOS 플랫폼 등 18개 제품 관전 포인트 28개의 OLED TV로 구성된 구조물 집안일 도와주는 홈 로봇, 클로이드 삼성 혁신상 갤럭시 버즈3 프로 등 29개 제품 양자보안 칩 등 27개 제품 관전 포인트 모든 가전이 연결된 스마트홈 세계 최초 130형 마이크로 RGB TV SK 혁신상 HBM3E 등 HBM4 등 관전 포인트 메모리 분야 유일무이 최고혁신상 세계 최초 HBM4 16단 48GB 공개 LG in CES LG는 관객에게 시각적인 인상을 주기 위해 노력한다고 느꼈습니다. 작년에 제가 본 전시 통틀어서도 LG의 전시가 가장 인상 깊었는데요,\n작년에 LG는 투명/무선 OLED 28대를 둥글게 전시하여 하나의 구조물을 형성하여 기술력을 뽐냈습니다. 이러한 LG의 차력쇼는 주변 공간을 압도하는 것을 넘어 CES 공식 매거진 1면까지 장식하였습니다.\n부스 안으로 들어가면 실물을 가까이서 볼 수 있었으며, 마치 TV가 아니라 창문에 상이 맺히는 것처럼 보여 미적으로도 뛰어났습니다. 참고로 LG signature OLED TV는 2023년부터 2026년까지 총 4년 연속 최고혁신상을 수상하고 있습니다.\n올해 LG는 가사 도우미 클로이드를 출시하며 또 한번 언론을 뜨겁게 달궜습니다.\n실제 데모에서 냉장고에서 우유를 꺼내고, 수건을 접고, 세탁물을 넣는 등 다양한 데모를 선보였습니다. 개인적으로 아직 실제로 상용화할 만큼 높은 완성도는 아니었지만 가정 로봇의 초기 버전이라는 점에서 큰 의미가 있고, AI의 발전 속도를 봤을 때 내년에는 얼마나 더 완성도 있는 모습을 보여줄지 정말 기대가 되는 데모였습니다.\nSAMSUNG in CES 삼성은 작년과 올해 모두 CES에서 박물관 컨셉으로 스마트홈에 대한 이야기를 풀어냈습니다.\n작년에는 AI가 어떻게 가전을 서로 연결하고 생산성을 높여주고 에너지를 효율적으로 사용할 수 있는지를 담백하게 전시하였습니다. 특히 SmartThings 플랫폼을 중심으로 냉장고, 세탁기, 에어컨 등 모든 가전이 하나로 연결되는 스마트홈 생태계를 강조하였습니다.\n올해는 AI가 일상에서 어떻게 즐거움, 편리함, 돌봄을 제공할 수 있는지를 전시하였습니다.\n메인홀에 전시된 세계 최초 130형 마이크로 RGB TV는 관객의 이목을 잡기에 충분하였으며, 이 밖에도 구글 제미나이가 탑재된 비스포크 AI 냉장고, 웨어러블 기반 건강 관리 솔루션 등 AI가 일상에 스며드는 비전을 선보였습니다. 디스플레이부터 가전, 헬스케어까지 전 영역에서 AI를 접목하는 삼성의 행보가 인상적이었습니다.\nSK in CES SK는 작년에도 올해도 HBM을 주력 기술로 선보였습니다. 개인적인 생각을 조심히 말씀드리면 SK의 HBM은 전시회 환경에서 데모를 통해 보여주기 어려운 기술이라고 생각합니다. 왜냐하면 메모리 반도체 특성상 핵심 기술을 시각적으로 보여주기가 쉽지 않기 때문입니다.\n하지만 작년 SK 전시관의 입구는 폭포 속 동굴에 들어가는 듯한 느낌을 주어 사람들의 발걸음을 멈추고 이목을 끌기에 충분하였습니다. 찾아보니 bit를 파도처럼 형상화한 그래픽을 구현하여 메모리 회사임을 나타내었다고 합니다. 그리고 HBM 존재만으로도 이미 세계에서 가장 핫한 주제이기에 정말 많은 사람이 방문하였습니다.\n저는 아무래도 반도체 회사에 종사하고 있는 만큼 더 많은 관심이 갔는데요, HBM을 비롯한 다양한 메모리 반도체들의 실물 및 스펙을 볼 수 있어서 좋았습니다. 젠슨 황의 사랑을 독차지하고 있는 HBM에 대한 설명을 간단히 드리자면, HBM(High Bandwidth Memory)은 여러 개의 DRAM을 수직으로 연결하여 대역폭을 키운 제품으로, 기존 DRAM보다 데이터 전송 속도가 혁신적으로 빠르다는 점이 특징입니다. 그중 상단에 전시된 HBM3E는 HBM3의 Extension 버전이라는 뜻으로 2026년 기준 HBM 출하량의 절반 이상이 HBM3E로 예상될 만큼 핫한 모델입니다.\n올해는 HBM4 16단을 최초로 공개하였습니다. HBM4는 단순 성능 개선을 넘어 전체적인 아키텍처를 변경하였습니다. 대역폭을 2배로 넓혔고, 메모리 맨 아랫층에 로직 공정을 넣어 메모리 근처에서 연산 기능까지 수행할 수 있다고 합니다.\nAI 시대의 핵심 부품인 HBM을 선도하고 있는 SK하이닉스가 CES에서도 세계의 주목을 받는 모습이 인상적이었습니다. 앞으로도 메모리 반도체 분야에서 SK하이닉스의 활약을 기대해봅니다. (메모리 싸게 주세요 흑흑)\n결론 CES는 올해도 역시 규모와 많은 회사들의 노력, 그리고 전 세계의 엄청난 관심으로 World Best Show임을 다시 한번 증명했습니다.\nCES 2025에서 NVIDIA의 CEO, 젠슨황이 말했습니다. AI의 다음 개척 분야는 Physical AI라고. 1년이 지나 CES 2026을 바라보는 지금, AI가 단순히 소프트웨어에 머무르지 않고 물리적인 세계로 확장되고 있다는 점이 가장 눈에 띄었습니다. 대표적으로 LG의 클로이드가 실제 가정에서 활용되는 모습을 보여주었고, 이번 포스트에서는 다루지 않았지만 여러 부스에서 춤을 추거나 일을 하는 로봇을 어렵지 않게 찾아볼 수 있었습니다.\n그리고 CES 2026에서 AMD의 CEO, 리사 수가 말했습니다. 전 인류를 위해 수십억 개의 AI 에이전트가 24시간 백그라운드에서 돌아가는 세상이 올 것이라고. 이처럼 AI는 점점 더 인류의 삶에 깊숙이 침투하고 있고, 이러한 수요를 뒷받침하기 위해 NVIDIA의 GPU는 물론이고 SAMSUNG, SK의 HBM4 같은 하드웨어의 발전도 빠르게 이루어지고 있습니다. 이러한 흐름은 앞으로 더 가속화될 것으로 보입니다.\n회사가 성공하기(=큰 매출을 올리기) 위해서는 \u0026ldquo;명확한 시장\u0026rdquo;, \u0026ldquo;혁신적인 아이템\u0026rdquo;, \u0026ldquo;훌륭한 팀\u0026rdquo; 3가지 요소가 필요하다고 생각합니다. 그리고 이번 CES를 보면서 현재 AI 시장은 전례 없이 빠르게 성장하고 있고, 한국의 많은 회사들이 이러한 환경 속에서 세계의 주목을 받고 있다고 느꼈습니다. 1년 사이에 눈부신 기술 발전을 이루어낸 많은 회사들에 대한 리스펙을 보내며, CES 2027에서의 한국 기업들의 활약을 기대해봅니다.\n추신 HyperAccel 채용 안내 이번 기회는 하이퍼엑셀을 되돌아보는 계기가 되기도 하였습니다. NPU 회사인 저희에게 \u0026ldquo;명확한 시장\u0026quot;은 이보다 더 좋을 수가 없어 보이고, \u0026ldquo;혁신적인 아이템\u0026quot;인 LPU는 이미 FPGA로 기능(Functionality)과 경쟁력(Performance) 검증이 끝나 ASIC 칩의 출시를 기다리고 있는 상황입니다. 저희는 마지막 요소인 \u0026ldquo;훌륭한 팀\u0026quot;을 함께 만들어갈 여러분을 기다리고 있습니다.\n채용 사이트: https://hyperaccel.career.greetinghr.com/ko/guide\n혹시 관심이 있으시다면 언제든지 연락 주세요!\n","permalink":"https://hyper-accel.github.io/posts/ces2026-report/","summary":"\u003ch1 id=\"2025년에-바라보는-ces-2026-핵심-정리-feat-samsung-sk-lg\"\u003e2025년에 바라보는 CES 2026 핵심 정리 (feat. SAMSUNG, SK, LG)\u003c/h1\u003e\n\u003cp\u003e안녕하세요? HyperAccel ML팀 소속 박현준입니다.\u003c/p\u003e\n\u003cp\u003e1월 6일에 라스베가스에서 시작한 CES가 1월 9일 성황리에 종료되었습니다. 우선 저는 작년(2025년) CES에 참여하여 하이퍼엑셀 부스를 운영했었고, 해당 경험을 바탕으로 올해(2026년) CES를 리뷰해보려고 합니다. 혹자는 왜 작년에 안 올리고 이제서야 올리는지 의문을 가질 수 있는데요,\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"뒷북\" loading=\"lazy\" src=\"/posts/ces2026-report/images/back_book.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e이유는 간단합니다. 작년에는 테크 블로그가 없었기 때문입니다. 작년에 참여한 입장으로서 CES 2026에 대한 기사를 보니 올해는 어땠을지 궁금해졌고, 테크 블로그에 글을 쓰겠다는 명분 덕분에 올해 CES에 대해 알아보는 시간을 가질 수 있었습니다. 아래 목록에 해당되는 분들께는 이번 포스트가 도움이 될 것 같습니다:\u003c/p\u003e","title":"2025년에 바라보는 CES 2026 핵심 정리 (feat. SAMSUNG, SK, LG)"},{"content":"지피지기면 백전불태 2편: TPU의 등장과 부상 지피지기면 백전불태 1편: GPU의 역사와 기초\n지피지기면 백전불태(知彼知己 百戰不殆)\n상대를 알고 나를 알면 백 번 싸워도 위태롭지 않다는 뜻입니다.\n이 시리즈는 AI 가속기 설계를 위해 경쟁사들의 하드웨어를 깊이 이해하는 것을 목표로 합니다.\n두 번째 글에서는 최근 AI 가속기 시장에 참전을 선언한 Google의 TPU(Tensor Processing Unit)에 대해 다룹니다.\nTPU? 최근 AI 가속기 시장에서 가장 핫하게 떠오른 키워드 중 하나는 바로 TPU일 것입니다. 지난 11월 구글은 7세대 TPU 아키텍쳐인 아이언우드(Ironwood)를 소개하면서 이전 세대에 비해 향상된 학습 및 추론 성능과 클러스터 확장성, 그리고 AI 스타트업인 앤트로픽(Anthropic)과의 협업 등을 발표하였습니다. 국내/외 언론에서도 이를 관심 있게 다루면서 일반 대중들에게도 TPU라는 용어가 알려지게 되었고, 이 뉴스 이후 구글과 엔비디아의 주가에도 적지 않은 영향을 주었습니다.\n하지만 TPU는 갑자기 등장한 제품은 아닙니다. 이번에 발표된 TPU는 무려 7세대 TPU입니다. 구글은 2016년부터 지금까지 매년 새로운 세대의 TPU를 발표하였습니다. 초기에는 AlphaGo 등 내부 모델 개발 및 연구용으로만 사용하였지만, 구글 클라우드를 통해 다른 기업이나 연구기관에서 TPU를 사용할 수 있는 서비스도 판매해왔습니다.\n그런데 생각해보면 이상합니다. 구글은 분명 소프트웨어 기업인데 왜 GPU 대신 본인들만의 칩을 만들게 되었을까요? 거기에 더해 하드웨어 시장까지 진출하려고 하는 자신감은 어디서 나온 것일까요? 오늘은 TPU의 기원과 최신 세대 TPU인 Ironwood에 대해 파헤쳐보며 구글의 AI 반도체 시장에 대한 \u0026lsquo;근거 있는 자신감\u0026rsquo;에 대해 알아보고자 합니다.\nTPU의 등장 TPU 구조를 이해하기 위해서는 먼저 TPU가 개발된 배경에 대해 알아야 할 필요가 있습니다. 이는 TPU 1세대 백서에 자세히 기술되어 있는데요.\n2000년대에 구글에서 제공하던 서비스들은 특수한 형태의 연산이 필요한 작업들도 custom ASIC이 필요 없이 기존의 데이터센터 내의 유휴 자원으로 돌릴 수 있는 수준이었습니다. 2010년대에 접어들어 인공지능 기술이 구글 서비스에 본격적으로 도입되면서 그 사정이 달라지게 됩니다. 사람들이 하루에 딱 3분씩만 음성 검색을 이용한다고 가정했을 때, 음성 인식 심층 신경망(DNN, Deep Neural Network)을 구동하기 위해서는 기존 데이터센터의 규모를 두 배로 늘려야 한다는 예측이 나왔기 때문입니다. 일반적인 CPU로는 이를 감당하기 어려워지자 구글 내부에서는 이를 위한 맞춤형 ASIC 프로젝트, TPU 프로젝트가 시작됩니다. 놀라운 점은 설계, 검증, 제작, 배포까지 15개월 만에 이루어졌다는 점입니다. 당시 제작된 TPU는 구글 내부에서만 사용되다가 2016년, 이세돌과 알파고의 대국에 TPU가 사용되었음이 공개되면서 TPU가 처음으로 외부에 알려지게 됩니다.\nTPU 하드웨어 아키텍쳐 그럼 본격적으로 TPU 아키텍쳐에 대해 살펴보겠습니다.\nSystolic array 앞서 말씀드렸듯이 TPU는 AI 연산에 특화되어 제작되었습니다. AI 연산 중 가장 큰 특징은 대규모의 행렬 곱셈을 수행한다는 점인데요. 이는 모델 종류(CNN, RNN, Transformer)와 학습/추론 과정에 관계 없이 볼 수 있는 공통적인 특징입니다. 이 특징은 인공 신경망의 가중치를 사용하고 기타 다른 값들을 연산하는 과정에서 나타납니다.\nTPU에서는 이 행렬 곱셈을 효율적으로 실행할 수 있도록 일반적인 프로세서(CPU)에서는 볼 수 없는 Systolic array라는 특별한 유닛을 사용합니다. \u0026ldquo;Systolic\u0026quot;은 심장의 수축 운동인 \u0026lsquo;수축기(systole)\u0026lsquo;에서 유래한 단어입니다. 마치 심장이 규칙적으로 박동하며 혈액을 신체의 각 부분으로 보내는 것처럼, 배열 구조 내에서 데이터가 연산 유닛 사이를 리듬감 있고 규칙적으로 이동하며 연산이 수행되는 모습에서 착안된 이름입니다. Systolic array는 데이터 흐름을 최적화하고 병렬 처리를 극대화하여 행렬 곱셈과 같은 대규모 연산에 효율적입니다. Systolic array가 행렬 곱셈을 진행하는 과정을 애니메이션으로 나타내보면 아래와 같습니다.\n브라우저가 비디오 재생을 지원하지 않습니다. 다음으로는 Systolic array의 효과를 더 구체적으로 설명하기 위해 일반적인 프로세서의 연산 방식과 TPU의 systolic array를 사용한 연산 방식을 비교해보겠습니다.\n일반적인 프로세서에서 덧셈이나 곱셈과 같은 산술 연산을 수행하는 과정은 아래와 같습니다.\nregister에 데이터를 로드 컨트롤러에서 ALU(Arithmetic Logic Unit)에 명령을 전송 ALU가 register에서 데이터를 읽어가서 연산을 수행한 후 결과값을 register에 다시 씀 즉, ALU가 개별 연산을 수행할 때마다 register에 데이터를 읽고 수행하는 과정이 필요한 것입니다. AI 연산에서 사용되는 대규모 행렬 연산은 일반적인 연산보다 월등히 많은 연산량을 필요로 합니다. 때문에 이 과정을 생략할 수 있다면\n필요한 register의 용량을 줄임으로써 면적 효율을 증대시키고 register ↔ ALU간 데이터 이동횟수를 줄임으로써 전력 소모를 줄일 수 있을 것입니다. Systolic array는 이 과정을 생략할 수 있는 대안 중 하나인데요. 개별 ALU에서 연산된 결과를 register에 저장하는 것이 아니라 다른 ALU로 넘겨주는 것입니다. 이를 통해 앞서 말한 효과를 얻을 수 있는 것이죠.\n하지만 Systolic array를 효과적으로 사용하기 위해서는 몇 가지 조건을 충족해야 합니다.\nALU → ALU 간에 데이터를 넘겨주는 타이밍을 정확히 맞춰줘야 하고 개별 ALU에서 연산된 결과가 다음 ALU에서 사용되어야 하는 보장이 필요합니다. 첫번째 조건은 하드웨어적으로 적절히 조절한다 치더라고, 두번째 조건은 연산 자체의 특성이 이를 만족해야 합니다. 행렬 곱셈은 이 두번째 조건을 만족하기 때문에 Systolic array를 가장 효율적으로 사용할 수 있습니다.\n행렬 곱셈을 작은 단위로 분해하면 여러 개의 벡터 내적으로 나타낼 수 있습니다. 벡터 내적은 개별 element의 곱셈결과의 누산값인데요. 개별 ALU에 입력으로 들어가는 element들의 타이밍을 정확하게 맞춰주고 element의 곱셈 값을 다음 ALU로 넘기면서 순차적으로 누산하게 되면 register와의 통신 없이 행렬 곱셈을 수행할 수 있게 됩니다.\n이러한 Systolic array는 TPU에서 사용한 대표적인 특징으로 AI 연산을 수행하는 GPU나 다른 AI 가속기(NPU, LPU) 아키텍쳐에도 큰 영향을 미치게 됩니다.\nTPU Building Block 다음으로는 TPU 개별 칩에서 사용하는 연산 단위에 대해 알아보겠습니다. 앞서 살펴본 GPU는 수백 개의 **SM(Streaming Multiprocessor)**으로 구성되어 있습니다. 하드웨어 스케줄러가 32개 스레드 묶음인 \u0026lsquo;워프(Warp)\u0026rsquo; 중 실행 준비가 된 것을 실시간으로 선택해 연산 자원에 투입하는데, 이는 명령어를 무작위로 실행하는 것이 아니라 **대기 시간을 다른 작업으로 메워 효율을 극대화(Latency Hiding)**하는 방식입니다. 즉, GPU는 수많은 작은 연산 단위를 촘촘하게 관리하며 전체 처리량을 높이는 데 최적화되어 있습니다.\n반면, **TPU(Tensor Processing Unit)**는 이와 대조적인 접근 방식을 취합니다. 잘게 쪼개진 수많은 유닛 대신, 거대한 행렬 연산을 한 번에 처리할 수 있는 소수의 강력한 전용 코어를 탑재하고 있습니다. 아울러 여러 인스트럭션을 합쳐둔 더 고수준의 명령어(VLIW, Very Long Instruction Word)를 통해 다량의 데이터를 연산 블록에 한번에 밀어넣는 방식으로 동작합니다. 복잡한 동적 스케줄링의 비중을 줄이는 대신, 인공지능 연산의 핵심인 대규모 행렬 곱셈을 마치 거대한 파이프라인이 흐르듯 단번에 수행하도록 설계된 것이 TPU 아키텍처의 핵심입니다.\nTPU의 개별 칩에 사용되는 코어는 선형 대수 연산에 특화된 TensorCore와 임베딩 연산에 특화된 SparseCore로 나뉩니다. (GPU에서 사용하는 Tensor Core와 용어는 같지만 역할의 차이가 있습니다.)\nTensorCore\nTensorCore는 Systolic array와 DMA(Direct Memory Access) 유닛 등을 통해 전달된 데이터에 대한 연산을 수행하는 연산 파이프라인입니다. GPU의 CUDA core나 Tensor core와 유사한 역할을 하며, GPU에서는 정확히 어떤 시점에 어떤 코어를 사용하겠다고 지정할 수 없지만(빈 실행 장치에 자동으로 채워넣음), TPU의 TensorCore는 컴파일 타임에 최적화된 데이터플로우에 따라 정적으로 할당됩니다. 앞서 말씀드린 행렬 연산을 위한 MXU(Matrix Multiplication Unit)이 가장 대표적이고, 행렬 연산 뿐만 아니라 스칼라, 벡터 연산을 위한 연산기도 포함되어 있습니다. 세대에 따라 다르지만 칩별로 1~2개의 TensorCore가 탑재됩니다.\nSparseCore\nSparseCore는 4세대 TPU부터 적용된 core 아키텍쳐입니다. SparseCore는 AI에서 행렬 연산 이외에 사용되는 연산 중 하나인 임베딩 연산에 특화된 유닛입니다. LLM 등에서 사용하는 임베딩 연산은 테이블 크기가 비교적 작기 때문에 연산 오버헤드가 과하지 않지만, DLRM(Deep Learning Recommendation Model)과 같은 추천 시스템에서는 임베딩 테이블 크기가 전체 파라미터의 대부분에 달할 정도로 오버헤드가 크기 때문에 임베딩 연산에서 연산 병목이 발생할 확률이 매우 높습니다.\nTPU에서 SparseCore가 차지하는 비중은 (4세대 기준) 5%정도로 Tensor core에 비해 작지만, 이 유닛으로 기존 대비 5~7배의 성능 향상을 이루어냈습니다. 세대에 따라 다르지만 칩별로 2개 혹은 4개의 SparseCore가 탑재됩니다.\nScale-up/Scale-out System TPU는 칩별로 1~2개의 적은 수의 거대한 코어로 연산을 수행합니다. 거대한 코어를 사용해 1개의 칩으로도 연산을 수행할 수도 있지만, 더 큰 연산을 위해서는 여러개의 칩을 연결하고 이를 병렬적으로 사용하는 것이 필요합니다. TPU는 이를 위해 아래와 같은 네트워크 기술을 사용합니다.\nTorus topology\n여러 개의 칩을 연결하여 하나의 거대한 서버를 구축하는 scale-up을 위해 TPU는 torus topology를 사용합니다. 여러 개의 칩을 연결한 모습을 떠올려보면 일반적으로 첫번째 그림과 같은 바둑판 모양의 격자 구조 (mesh topology)를 생각해볼 수 있는데요. 이 구조의 단점은 양끝에 있는 노드들끼리 연결이 안되어 있기 때문에 노드간 최대 거리가 길어진다는 점입니다. torus 구조에서는 양 끝에 있는 node들을 wrap-around link로 연결하여 배선 복잡도는 높아지지만 노드간 최대 거리를 N → N/2로 줄일 수 있습니다. 4세대 TPU에서는 이 torus 구조를 3D로 확장하여 노드간 통신 범위와 하나로 묶이는 TPU 개수를 확장하였습니다. 4 * 4 * 4(=64)개의 TPU 묶음을 cube라고 부르고 이 cube가 여러 개 모인 클러스터를 pod이라고 부릅니다.\nOptical Circuit Switch(OCS)\n이러한 칩 간 통신을 중재 하기 위해서는 네트워크 스위치가 필요한데요. TPU는 광학 스위치인 OCS를 도입하여 torus 간의 연결 구조를 소프트웨어에서 재구성할 수 있도록 하였습니다. 연산 특성에 따라 최적화된 연결 구조를 소프트웨어에서 결정할 수 있도록 한 것입니다.\nTPU 소프트웨어 스택 다음으로는 TPU에서 사용하는 소프트웨어에 대해 알아보겠습니다.\nTensorFlow 지난 포스팅에서 GPU는 CUDA라는 프로그래밍 모델로 제어할 수 있다고 말씀드린 바가 있는데요. 구글은 CUDA와 같은 kernel language를 개발하는 대신, GPU와 TPU 상관없이 사용할 수 있는 TensorFlow라는 딥러닝 프레임워크를 개발해왔습니다. TensorFlow와 PyTorch와 같은 프레임워크의 특징은, CUDA와 달리 개발자가 하드웨어의 세부 구조를 이해하지 않아도 동일한 코드로 GPU와 TPU 같은 다양한 가속기에서 바로 실행할 수 있다는 점입니다. 구글은 생태계 확장을 위해 동일한 TensorFlow 소스코드를 사용하더라도 CPU, GPU, TPU 등 다양한 하드웨어 플랫폼에서 동작하고 모바일 기기부터 대규모 분산 시스템까지 어디에나 배포할 수 있도록 강력한 유연성을 제공했습니다. 이로 인해 산업/배포용으로는 TensorFlow가 강력한 도구로 자리잡게 되었습니다. 하지만 하드웨어에 대한 정밀한 제어가 어렵다보니 최적화 입장에서 한계가 있습니다.\nJAX 하지만 TPU 하드웨어를 소프트웨어 단에서 최적화 할 수 있는 방법이 없는 것은 아닙니다. JAX라는 python library를 활용하면 가능한데요. 이는 TPU를 적극적으로 활용하는 구글 내부 개발자들이 TPU를 보다 더 효율적으로 사용하기 위해 개발한 python library입니다. TPU에서는 직후에 설명할 머신러닝 가속형 컴파일러인 XLA를 사용할 수 있는데요. XLA는 TensorFlow와 JAX 모두에서 사용할 수 있는 컴파일러입니다. JAX는 이 XLA를 소프트웨어 개발자들이 더 직접적이고 유연하게 활용할 수 있도록 만들어진 일종의 python interface입니다. GPU/TPU 구분 없이 사용가능하며, 함수형 프로그래밍 패러다임과 자동 미분 기능을 제공하여 연구와 실험에 더 적합한 설계를 가지고 있습니다. 구글 AI 팀에서는 연구와 모델 학습에 적극적으로 이를 활용하고 있지만, 소프트웨어 레벨에서 연산 최적화를 진행해야 하기 때문에 진입장벽이 다소 높다는 것이 특징입니다.\nXLA(Accelerated Linear Algebra) 구글은 앞서 설명한 TensorFlow의 한계를 극복하고 머신러닝에서 TensorFlow의 성능을 한단계 더 향상시키기 위한 방법을 고민하게 됩니다. 구글에게는 크게 두 가지 방향의 선택지가 있었을 것으로 생각됩니다.\nCUDA와 비슷하게 하드웨어를 직접적으로 제어할 수 있는 별도의 low-level 언어(가령, TPU-C)를 만들고, 최적화된 커널을 만들어 TensorFlow와 같은 high-level language에서 해당 커널을 호출 머신러닝에 특화된 컴파일러를 사용하여 컴파일러가 해당 하드웨어에 최적화된 기계어를 생성 전자의 방식은 개발자들이 직접 하드웨어를 제어할 수 있기 때문에 높은 자유도를 가집니다. 아울러 하드웨어에 새로운 기능이 추가되거나 새로운 알고리즘(FlashAttention, Mixture-of-Expert(MoE))이 개발될 때마다 개발자들은 최적화를 위해 새로운 CUDA kernel을 짜게 됩니다. 최적화의 요구는 항상 존재하며, 그럴 때마다 CUDA 생태계는 확장됩니다. 이는 다른 하드웨어 회사들의 시장진입을 어렵게 하는 CUDA 생태계의 거대한 기술적 해자로 작용하고 있습니다.\n구글은 머신러닝 연산의 핵심이 되는 선형 대수 연산에 특화된 XLA 컴파일러를 만드는 후자의 방식을 선택해왔습니다. CUDA 생태계에 전면적으로 도전하는 것은 우회했지만, 어떻게 보면 새로운 언어를 배워야 하는 개발자들의 짐을 컴파일러에게 넘겨줬다고 볼 수 있습니다. AI 연산 중 일부를 통해 XLA 컴파일러의 연산 최적화 방식에 대해 알아보겠습니다.\n(* 본 설명은 XLA 컴파일러의 최적 방식을 설명하기 위한 예시로 실제 동작과 일치하지 않습니다.)\nimport math # 1. Linear: z = weight * x + bias def linear_op(x, weights, bias): # write result to main memory z = [sum(xj * wj for xj, wj in zip(x, weights[i])) + bias[i] for i in range(len(weights))] return z # 2. Activation: ReLU def relu_op(z): # Read z value from main memory -\u0026gt; write back result to main memory a = [max(0, val) for val in z] return a # 3. Softmax def softmax_op(a): # read a from main memory -\u0026gt; find max -\u0026gt; summation -\u0026gt; div -\u0026gt; write back result to main memory max_val = max(a) exp_vals = [math.exp(val - max_val) for val in a] sum_exp = sum(exp_vals) return [ev / sum_exp for ev in exp_vals] 단순히 위의 3개의 function을 순차적으로 실행하게 되면 각 function들의 중간 결과를 메인 메모리에 쓰고 다시 읽는 과정이 필요합니다. XLA 컴파일러의 핵심은 이 operation을 통합하여 불필요한 연산이나 메모리 할당을 제거하고 빠른 속도와 적은 메모리 사용으로 연산을 수행할 수 있도록 하는 것입니다.\nGPU에서도 kernel fusion을 통해 여러 개의 연산 kernel을 통합할 수 있습니다. GPU에서는 통합된 CUDA kernel 수동으로 만드는 방법과 PyTorch나 TensorRT 내부 기능을 이용하여 커널을 자동으로 융합시키는 두 가지 방법이 있다면, XLA는 컴파일 단계에서 개별 operation을 분석하여 각 하드웨어(CPU/GPU/TPU)에 최적화된 기계어를 만들어낸다는 것에서 차이가 있습니다.\nXLA는 TensorFlow와 JAX에서 지원되다가 최근에는 PyTorch에서도 pytorch/xla를 통해 XLA를 사용할 수 있도록 지원되면서 그 저변을 확대하고 있습니다.\nPallas XLA는 강력한 최적화 컴파일러로 동작하지만 한계도 존재합니다. 새로운 연산 알고리즘이 등장할 경우 컴파일러가 이를 최적화할 수 있는 버전으로 업데이트 되기 전까지 수동으로 생성한 custom kernel의 성능을 따라잡기 힘들다는 것입니다.\n이를 위해 구글은 2023년 무렵부터 JAX의 실험적인 확장 기능으로 Pallas(jax.experimental.pallas)라는 kernel language API를 제공해왔습니다. 이는 앞서 언급한 성능 향상을 위한 두 가지 방법 중 첫번째 방법에 해당합니다. Pallas는 2021년 탄생한 GPU용 고수준 kernel language인 Triton과 비교해볼 수 있습니다.\nTriton은 2021년에 OpenAI에서 제작된 오픈소스 GPU 프로그래밍 언어입니다. 강력하지만 진입장벽이 높고 하드웨어 구조를 이해해야 한다는 CUDA의 한계점을 극복하기 위해 CUDA 보다 한단계 더 추상화된 인터페이스를 제공하여 머신러닝 개발자들이 다양한 연산과 알고리즘을 GPU에서 더 쉽게 최적화할 수 있도록 한 것이 특징입니다. Hopper/Blackwell 등 아키텍쳐의 구애 받지 않도록 추상화를 진행하여 개발자 편의성을 증대시켰으며, 높은 추상화 단계에도 불구하고 Triton으로 만들어진 프로그램들이 수동으로 만들어진 CUDA kernel과 성능 면에서 비슷한 수준에 도달한 벤치마크도 존재합니다.\nJAX에서도 Triton 언어를 사용할 수 있도록 통합이 진행되었지만 Triton은 GPU에서만 작동하기 때문에 TPU에서는 이러한 최적화를 진행하기가 힘든 부분이 있었습니다. Pallas는 이를 극복하기 위한 TPU용 kernel-language API로 Triton과 달리 GPU와 TPU를 모두 지원하는 공통 커널 언어를 제공하는 것이 큰 특징입니다. Pallas는 JAX뿐만아니라 PyTorch/XLA에서도 사용가능하도록 통합이 진행되었습니다.\nIronwood 출시, 구글의 참전 선언 4세대 TPU 이후로는 기술적인 내용을 상세하게 기술한 자료가 많이 없어 기존에 비해 7세대 TPU에서 달라진 점과 AI 반도체 업계에 시사하는 점들에 대해 기술적인 관점에서 이야기해보겠습니다.\n하드웨어 관점 chiplet architecture\nIronwood는 TPU 아키텍쳐 중 최초로 chiplet 구조를 채택하였습니다. chiplet 구조는 레티클 한계라고 불리는 반도체 제조 공정의 한계를 극복하기 위해 도입된 공정 기술입니다.\n레티클 한계: 반도체 업계 표준으로 고정되어 사용하는 포토마스크(reticle)의 크기 회로를 그릴 때 사용되는 노광기의 렌즈의 축소 배율로 인해 단일 노광으로 찍어낼 수 있는 개별 다이의 크기를 레티클 한계라고 부릅니다. 이 한계 (현재는 약 858mm²)을 넘어가게 되면 단일 노광이 불가능하여 여러 노광 패턴을 이어붙이는 스티칭(Stitching) 기법이 필요합니다. 하지만 이 경우 불량률이 급격히 상승하여 제조 비용이 증가합니다. 이런 경제적인 이유로 기존 칩들은 프로세서 영역(메모리 이외의 영역)이 이 크기를 넘어가지 않도록 제작되었습니다.\n하지만 데이터센터에서 사용되는 칩들의 수요 스펙이 증가하게 되면서 더 큰 칩들이 필요하게 되었고, 단일 칩 사이즈를 키우는 대신 이를 동일한 구조의 칩으로 여러개로 쪼개어서 만든 뒤 패키징 단계에서 이를 연결하는 chiplet 구조가 도입되었습니다. 이렇게 되면 개별 칩의 크기를 키울 수 있게 되면서 개별 제품들의 성능이 증가할 수 있습니다.\nNvidia GPU는 2024년에 출시한 Blackwell 아키텍쳐인 B100/B200 제품군부터 이 기술을 도입하였고 데이터센터향 가속기를 만드는 다른 가속기 회사들도 이 구조를 도입하고 있습니다. TPU는 이번세대 제품군부터 chiplet 구조를 적용하였고, 이로 인해 이전 제품군 단일 제품 성능(peak Compute, memory bandwidth 등)이 월등히 높은 것을 볼 수 있습니다.\n이 chiplet 구조에서 2개의 개별 die는 이전 제품의 개별 chip 이상의 성능을 보이기 때문에 Ironwood에서는 개별 die를 torus topology의 하나의 node로 보고 개별 제어가 가능하도록 합니다. 이를 위해 3D torus에서 축을 하나 더 추가한 4D torus topology를 도입하였습니다.\n소프트웨어 관점 vLLM 지원과 tpu-inference의 등장\n구글은 지난 10월 tpu-inference 라는 새로운 하드웨어 플러그인을 vLLM에 통합했습니다. 이 플러그인은 JAX와 PyTorch를 단일 로어링 경로(Single Lowering Path)로 통일하여, 프레임워크에 상관없이 최적화된 TPU 기계어를 생성합니다. 이 플러그인의 가장 큰 장점은 GPU에서 쓰던 vLLM 인터페이스 그대로 TPU 위에서 LLM 모델을 고성능으로 서빙할 수 있게 된 것입니다.\nTensorFlow 지원 중단\n구글은 이번세대 TPU부터 과감하게 TensorFlow 지원을 중단했습니다. 이는 PyTorch의 생태계 지배력을 인정하면서 PyTorch 생태계 내에서(PyTorch/XLA) TPU의 성능을 최적화 할 수 있도록 기존 생태계에 XLA를 통합하고, 독자적인 framework 개발은 TensorFlow보다 성능 향상에 더 최적화된 JAX framework에 더 집중하겠다는 두 가지 의미로 해석됩니다.\nPallas의 소프트웨어 생태계 안착\nJAX 공식문서에는 아직 pallas가 experimental 기능으로 기술되어 있지만, 블로그에서도 pallas를 TPU 성능 극대화를 위한 수단으로 공식적으로 소개하고 있습니다. 이는 XLA 컴파일러 업데이트를 기다리지 않고 개발자가 직접 최적화 커널을 짜는 것을 권장한 것으로 풀이됩니다. CUDA/Triton에 있던 커널 최적화의 자유도를 TPU에서도 누릴 수 있게 된 것입니다.\n구글의 AI 반도체 시장 야욕 이러한 소프트웨어 생태계 확장과 하드웨어 성능의 비약적 향상은 단순한 기술 개선을 넘어 구글의 전략적 전환을 의미합니다. 이는 엔비디아가 독점해온 AI 반도체 시장에 본격적으로 진입하기 위한 움직임입니다. 구글의 시장 진입 전략을 살펴보자면 아래와 같습니다.\nTPU 직접 판매 가능성\n그동안 TPU는 구글 클라우드(GCP)를 통해서만 임대할 수 있었습니다. 보안상의 이유로 하드웨어 기술문서를 상세하게 공개하지 않는 편이었으며, 직접 판매도 진행하지 않아 TPU는 구글 내부 데이터센터에만 존재했습니다. 하지만 최근 구글은 TPU를 타사 데이터센터에 직접 공급하거나 하드웨어 자체를 판매하는 전략을 검토 중인 것으로 알려졌습니다. 이는 폐쇄적인 구글 전용 칩 이미지를 벗고, 독립적인 AI 반도체 벤더로서 엔비디아와 정면 승부를 벌이겠다는 선언입니다.\n소프트웨어 개방과 수직 계열화의 완성\n엔비디아의 강력함은 하드웨어뿐만 아니라 CUDA라는 소프트웨어 생태계에서 나옵니다. 구글은 이에 맞서 XLA라는 자동화와 Pallas라는 개방성을 무기로 삼고 있습니다. \u0026ldquo;GPU는 수동으로 최적화된 커널에서 최고의 성능이 나오지만, TPU는 컴파일러가 자동으로 최적화하고 필요하면 개발자가 직접 튜닝할 수도 있다\u0026quot;라는 메시지를 던지고 있는 것입니다. 더불어 구글의 소프트웨어 스택은 CUDA와 달리 특정 하드웨어에 국한되지 않아 최근 떠오르는 이종 컴퓨팅 시장에서도 경쟁력을 확보할 수 있습니다.\n거기에 더해 구글은 모델(Gemini), 프레임워크(JAX), 컴파일러(XLA), 그리고 하드웨어(TPU)까지 AI의 모든 스택을 수직 계열화한 유일한 기업입니다. 소프트웨어와 하드웨어의 융합이 필수적인 AI 반도체 시장에서 구글은 이러한 수직 계열화를 통해 유리한 고지를 선점하고 있습니다.\n정리 본 글에서는\nTPU의 등장 배경 TPU의 하드웨어/소프트웨어 아키텍쳐 최신 TPU 제품인 Ironwood의 특징 구글의 반도체 시장 전략에 대해 알아보았습니다. 이를 통해 내릴 수 있는 결론을 요약하면 아래와 같습니다.\n구글은 10년 전부터 AI workload에 최적화된 ASIC인 TPU를 개발해왔습니다. GPU와 CUDA의 기술적 해자를 허물고 하드웨어 종속적이지 않은 소프트웨어 생태계 구축을 위한 기술적 노력을 이어가고 있습니다. 단순 클라우드 사업을 넘어 AI 반도체 시장에 직접 진출하여 엔비디아와 동등한 지위를 구축하고자 합니다. 그런데, 최초 TPU 프로젝트에 참여했던 인원이 또다른 반도체 스타트업을 설립했었다는 사실, 알고 계셨나요? 얼마 전 엔비디아와 한화 약 30조원 규모의 계약을 체결한 AI 반도체 스타트업 Groq이 바로 그 주인공인데요. 엔비디아가 어마어마한 규모의 돈을 주고 구매한 Groq의 기술은 무엇일까요? 다음 글에서는 저희와 같은 용어를 사용하는 Groq의 LPU에 대해 알아보겠습니다.\nReference An in-depth look at Google’s first Tensor Processing Unit (TPU) From silicon to softmax: Inside the Ironwood AI stack Announcing Ironwood TPUs General Availability and new Axion VMs to power the age of inference In-Datacenter Performance Analysis of a Tensor Processing Unit TPU v4: An Optically Reconfigurable Supercomputer for Machine Learning with Hardware Support for Embeddings 추신: HyperAccel은 채용 중입니다! 지피지기면 백전불태라지만 백전백승을 위해서는 훌륭한 인재가 많이 필요합니다!\n저희가 다루는 기술들을 보시고, 관심이 있으시다면 HyperAccel Career로 지원해 주세요!\nHyperAccel에는 정말 훌륭하고 똑똑한 엔지니어분들이 많습니다. 여러분의 지원을 기다립니다.\n","permalink":"https://hyper-accel.github.io/posts/tpu-deep-dive/","summary":"TPU의 등장 배경에 대해 알아보고 하드웨어/소프트웨어 구조를 파헤쳐보면서 구글의 AI 반도체 전략에 대해 분석해봅니다.","title":"지피지기면 백전불태 2편: TPU의 등장과 부상"},{"content":"지피지기면 백전불태 1편: GPU의 역사와 기초 지피지기면 백전불태(知彼知己 百戰不殆)\n상대를 알고 나를 알면 백 번 싸워도 위태롭지 않다는 뜻입니다.\n이 시리즈는 AI 가속기 설계를 위해 경쟁사들의 하드웨어를 깊이 이해하는 것을 목표로 합니다.\n첫 번째 글에서는 가장 강력한 경쟁자인 NVIDIA GPU를 다룹니다.\n2020년대 핫 이슈를 이야기할 때 NVIDIA GPU를 빼놓을 수 없습니다.\nAI 반도체 설계 회사로서 NVIDIA와 경쟁하려면,\n먼저 NVIDIA가 어떻게 여기까지 왔는지, 그리고 GPU가 어떤 장치인지를 이해해야 합니다.\n이 첫 번째 글에서는 NVIDIA GPU가 어떻게 탄생했고, 어떤 아키텍처 선택이 오늘의 위치를 만들었는지 살펴보고,\n하드웨어 엔지니어 관점에서 이 설계의 강점과 구조적 특성을 정리합니다.\nNVIDIA는 1993년 설립되어 1995년 NV1로 그래픽 시장에 진입했습니다.\nRIVA 128(1997)과 GeForce 256(1999)으로 PC 그래픽 카드 시장에 자리를 잡았지만,\nGeForce FX 시리즈 실패로 큰 위기를 맞았습니다.\n이 실패를 딛고 NVIDIA는 GPU 아키텍처를 재구축하며 G80 Tesla 아키텍처와 CUDA를 선보였습니다.\n이 전환으로 GPU는 \u0026ldquo;그냥\u0026rdquo; 그래픽 칩에서 벗어나 HPC와 GPGPU 시장까지 지배할 수 있는 플랫폼이 되었습니다.\n2012년, GPU로 훈련한 AlexNet이 ImageNet Large Scale Visual Recognition Challenge(ILSVRC)에서 우승하며\nGPU는 딥러닝과 떼려야 뗄 수 없는 관계가 되었습니다.\n2022년 ChatGPT 출시로 생성형 AI가 대중화되면서, AI 하드웨어 시장이 사실상 NVIDIA 중심으로 통합되었고,\nNVIDIA는 세계 시가총액 1위 기업으로 올라섰습니다.\n오늘날 NVIDIA GPU는 더 이상 \u0026ldquo;그냥 그래픽 가속기\u0026quot;가 아닙니다.\nAI 인프라 레이어를 사실상 지배하는 범용 병렬 컴퓨팅 플랫폼 이며,\n우리 관점에서는 새로운 가속기가 반드시 넘어야 할 기준점(baseline) 입니다.\n그렇다면 GPU는 어떻게 탄생했고, 어떻게 확산되면서 AI 시장까지 진입하게 되었을까요?\n그래픽 카드의 탄생 초창기 대중화된 컴퓨터는 CLI(Command Line Interface) 방식을 사용했습니다.\n화면은 대부분 초록색 글자와 검은색 배경이었고, 그래픽 작업은 거의 없었죠.\n그래서 CPU가 다른 작업을 처리하면서 화면 업데이트까지 함께 할 수 있었습니다.\n하지만 CLI는 사용자가 명령어를 외워야 해서 진입장벽이 높았고, 대중적 매력이 부족했습니다.\nXerox의 Alto, Apple의 Lisa 같은 시스템이 윈도우, 아이콘, 마우스를 갖춘 GUI(Graphic User Interface) 시대를 열었습니다.\nGUI는 사용성을 크게 개선했지만, CPU 부담이 늘어났습니다.\n이에 발맞춰 IBM 같은 제조사들이 메인보드의 그래픽 회로를 점점 강화해 나갔고,\nVGA(Video Graphics Array)에 이르러서는 그래픽이 PC의 핵심 구성 요소가 되었습니다.\n1990년대부터 3D 그래픽 게임에 대한 수요가 폭증하면서 그래픽 연산 능력에 대한 필요성도 급증했습니다.\n1993년도에 출시한 DOOM은 3D 그래픽 게임에 혁신을 가져왔는데, 플레이 시 초당 약 1000만 번의 연산이 필요했습니다.\n비디오게임에 필요한 연산은 초당 프레임 수 × 해상도 × 물리 시뮬레이션 × 텍스처 효과로 여러 방면 기술이 혼합되어 있고, 각 분야가 발전하면서 필요한 연산의 횟수는 기하급수적으로 늘어났습니다.\n게임별로 필요한 연산량을 살펴보면:\nDOOM (1993): 초당 약 1000만 번 Super Mario 64 (1996): 초당 1억(100M) 번 Half-Life (1998): 초당 5억 번 World of Warcraft (2004): 초당 22억 번 Minecraft (2011): 초당 1000억(100G) 번 Call of Duty: Modern Warfare III (2023): 초당 30~40조 번 30년 만에 연산량이 약 3~4백만 배 증가한 셈입니다.\n여기서 말하는 그래픽 연산은 어떻게 진행될까요?\nCPU가 먼저 가상 3D 공간의 기하학적 정보인 정점(vertex)들을 전송합니다.\nGPU는 이 정점들을 화면상의 최종 픽셀 색상으로 변환하기 위해 셰이더(shader) 를 실행합니다.\n셰이더는 렌더링 파이프라인의 각 단계를 프로그래밍 가능하게 제어하는 작은 프로그램으로,\n정점이나 픽셀에 대한 변환, 조명, 색상 계산 등의 연산을 수행합니다.\n먼저 vertex shader 가 정점들을 화면 좌표에 배치합니다.\n이어서 primitive generation과 rasterization을 거쳐 픽셀로 매핑되고,\n각 픽셀마다 fragment shader 가 최종 색상을 계산합니다.\n이렇게 계산된 픽셀 색상들이 framebuffer에 저장되어 화면에 표시됩니다.\n이러한 기본 그래픽 파이프라인 위에,\n더 현실적인 표현을 위해 anti-aliasing, blending, transparency, shadow mapping 같은 추가 효과가 적용되었습니다.\nNVIDIA FX 그래픽 카드를 보면, 초기 GPU는 이 그래픽 파이프라인을 하드웨어로 그대로 옮겨놓았습니다.\nvertex shading을 위한 vertex shader 회로가 따로 있고, fragment shading을 위한 fragment shader 회로가 따로 있었죠.\n즉, 그래픽을 위해 고정된 가속장치(fixed-function accelerator) 였습니다.\n이런 일방향 파이프라인 구조에는 큰 문제가 있었습니다.\n중간 단계가 오래 걸리면 앞단계가 stall되어 버블이 생기고 하드웨어 활용률이 떨어집니다.\n이 문제는 Programmable Shader 가 등장하면서 더욱 심해졌습니다.\n커스텀 shader 함수는 연산 시간이 더 오래 걸리는 경우가 많아서 전체 하드웨어 활용률을 저해했고,\n파이프라인이 길어지면서 병목이 어디서 발생하는지 파악하기 어려워졌습니다.\n이런 상황에서 NVIDIA는 혁신적인 해결책을 내놓았습니다. 바로 Unified Shader를 도입한 G80 Tesla 아키텍처였죠.\n별도의 vertex shader와 fragment shader 하드웨어 대신, 모든 shader 작업을 하나의 코어 풀에서 처리할 수 있게 했습니다.\n기존에 몇 픽셀씩 벡터로 묶어서 처리하던 방식을 개별 픽셀 단위로 분해하고,\n여러 픽셀에 대한 연산을 묶어서 스케줄링하는 방식으로 패러다임을 전환했습니다.\n이런 아키텍처 전환 덕분에 특정 shader 연산이 오래 걸리더라도,\n같은 코어에서 다른 shader 작업을 계속 진행할 수 있게 되었습니다.\n일방향 파이프라인에서 발생하던 병목 현상이 혁신적으로 개선되었고,\n이를 통해 GPU를 바라보는 새로운 관점이 열렸습니다: HPC(High Performance Computing)를 위한 GPGPU 입니다.\nGPGPU와 CUDA의 등장 그래픽 처리 장치로서 발전을 거듭한 GPU가 연구자들의 눈에 띄게 됩니다.\n2003년 두 연구팀이 각자 독립적으로 연구한 결과,\n\u0026ldquo;GPU로 일반 선형대수학 문제를 풀면 기존 고성능 CPU보다 빠르다\u0026rdquo; 는 사실이 밝혀지면서\n본격적으로 GPGPU 바람이 불기 시작했습니다.\nGPU는 초당 연산량이 높다. 그럼 다른 데 쓰면 어떨까?\n배경을 살펴보면, 그래픽 발전을 위해 DirectX 8(2000)이 Programmable Shader 개념을 도입하여\n개발자가 전용 셰이더 하드웨어에서 실행되는 커스텀 셰이더 프로그램을 만들 수 있게 했습니다.\nDirectX 9(2002)에서는 셰이더 언어 HLSL(High-Level Shader Language)을 추가하여\nProgrammable Shader를 본격적으로 실용화했습니다.\n이때 GPU의 특성인 \u0026ldquo;다수 픽셀에 대한 동일 연산\u0026rdquo; 이\n행렬 곱셈 같은 선형 대수학 문제의 \u0026ldquo;다중 데이터에 대한 동일 연산 실행\u0026rdquo; 과 매우 유사하다는 점에 착안하여,\n입력 정점(input vertex)을 함수 입력으로, 프레임 버퍼(frame buffer)를 함수 출력으로 해석하는 방식으로\n\u0026ldquo;범용 GPU(GPGPU)\u0026rdquo; 개념이 정립되었습니다.\n다만 당시 하드웨어는 여전히 그래픽 파이프라인으로 만들어져 있었습니다.\n그래서 당시 GPGPU는 일종의 \u0026ldquo;해킹\u0026rdquo; 과 같은 방식이었습니다.\n선형 대수학 문제를 그래픽 문제로 재해석하고, 그래픽 파이프라인에 맞춰야 했으며,\n기존 C 코드를 HLSL이나 GLSL(OpenGL Shader Language) 같은 셰이더 언어로 다시 작성해야 했죠.\n강력했지만 매우 번거로웠습니다.\n이 문제는 Tesla 아키텍처(2006)와 뒤이어 나온 CUDA(Compute Unified Device Architecture)(2007)를 통해 완벽히 해결됩니다.\nCUDA는 태생부터 그래픽이 아닌 병렬 연산에 초점을 맞추어 설계되었는데, Tesla의 Unified Shader 구조에 맞추어\n하나의 데이터 포인트에 대한 작업을 thread 한 하드웨어 SM에 배정되는 thread 묶음을 block 함수 실행 시 생성되는 전체 thread를 grid 로 정의하여 C언어의 개념체계를 그대로 사용하여 커널 함수를 구현할 수 있도록 하였습니다.\nTesla 아키텍처와 CUDA 프로그래밍 모델을 통해 GPU는 진정한 GPGPU의 세계로 들어갈 수 있었습니다.\n이제 현대 GPU인 Hopper 아키텍처를 기준으로 과연 GPU는 어떤 식으로 만들어졌는지 살펴봅시다.\n현대 GPU 구조 GPU (Device) 아래와 같은 구성 요소를 포함하는 전체 Device 입니다. 여러 GPC(Graphics Processing Cluster) 메모리(HBM(High Bandwidth Memory) 혹은 GDDR(Graphics Double Data Rate)) 메모리 컨트롤러 L2(Level 2) 캐시 PCIe(Peripheral Component Interconnect Express)/NVLink(NVIDIA NVLink) 인터페이스 GigaThread Engine: GPU 최상단에서 커널 실행 요청을 받아, 수천 개의 스레드 블록을 각 GPC와 SM으로 분배하는 전역 스케줄러 역할을 수행합니다. GPC (Graphics Processing Cluster) 여러 개의 SM을 묶어 관리하는 상위 하드웨어 단위입니다. 래스터화 엔진(Raster Engine) 등 그래픽 처리를 위한 공통 자원을 공유합니다. Hopper 아키텍처에서는 스레드 블록 클러스터(Cluster)가 실행되는 경계가 됩니다. GPC 내부에는 SM 간의 초고속 연결망이 있어 Distributed Shared Memory(DSMEM) 접근이 가능합니다.(Hopper 이상) SM (Streaming Multiprocessor) GPU의 핵심 연산 블록(Building Block)이자, 스레드 블록(Block)이 실행되는 물리적 공간입니다.\nCPU의 코어(Core)와 유사한 개념이지만 훨씬 더 많은 스레드를 동시에 처리합니다.\n하나의 SM은 동시에 수십 개의 워프(Warp)를 활성화 상태로 유지하며(Active Warps), 메모리 대기 시간이 발생하면 즉시 다른 워프로 전환하여 파이프라인을 꽉 채웁니다(Latency Hiding).\n주요 구성 요소:\n4개의 SM Sub-partition: 연산 유닛들의 집합. Unified Shared Memory / L1(Level 1) Cache: 데이터 공유와 캐싱을 위한 고속 메모리. (Hopper 기준 256KB) TMA (Tensor Memory Accelerator): Hopper 아키텍처에서 도입된 연속된 메모리(주로 텐서) 복사를 전담하는 비동기 복사 엔진. SM Sub-partition (Processing Block / SMSP) SM 내부를 4개로 쪼갠 구획입니다. (현대 NVIDIA GPU의 표준 구조) 각 파티션은 자체적인 Warp Scheduler (1개), Dispatch Unit, Register File (64KB), 그리고 할당된 CUDA Cores 및 Tensor Cores 세트를 가집니다. SM 하나를 통째로 관리하는 복잡도를 줄이고, 4개의 파티션이 독립적으로 워프를 스케줄링하여 병렬성을 극대화합니다. 그럼 이 하드웨어 위에서 작업은 어떻게 구조화될까요? CUDA 프로그래밍 모델을 조금 더 살펴봅시다.\nCUDA 프로그래밍 모델의 구조 이러한 하드웨어 아키텍처 상에서 GPU는 병렬 작업을 총 5단계로 Thread를 묶어서 관리합니다.\n스레드 (Thread) 병렬 처리의 최소 단위\nCUDA 연산의 가장 작은 논리적 단위입니다. 개발자가 작성한 커널(Kernel) 코드는 SPMD (Single Program Multiple Data) 방식에 따라 모든 스레드에 복제되어 실행됩니다. 각 스레드는 고유한 thread ID를 부여받으므로, 이를 이용해 서로 다른 메모리 주소에 접근하거나 각기 다른 제어 흐름을 가질 수 있습니다. 물리적으로는 CUDA Core 파이프라인을 점유하며 실행됩니다. 워프 (Warp) 하드웨어 실행의 최소 단위\n워프는 32개의 연속된 스레드를 묶은 집합이며, 실질적인 명령어 실행(Instruction Issue) 단위입니다. 한 워프 내의 모든 스레드는 Instruction Cache 내의 명령줄을 가리키는 Program Counter(PC)를 공유합니다. (동일 명령, 동시 issue) 워프가 실행(issue)되면, PC가 가리키는 명령줄이 Dispatch Unit으로 전송되어 실행되고, 명령 실행이 종료되면 워프가 release되면서 PC가 증가합니다. 만약 워프 내 스레드들이 if-else문 등으로 서로 다른 실행 경로로 갈라진다면(Branch Divergence), 하드웨어는 모든 경로를 순차적으로 처리(Serialization)한 뒤 다시 합류시킵니다. 따라서 동일 워프 내 스레드들의 실행 경로를 일치시키는 것이 성능의 핵심입니다. SM 내부의 Warp Scheduler는 실행 가능한 상태의 워프를 빠르게 교체(Context Switching)하며 메모리 대기 시간(Latency)을 숨깁니다. 스레드 블록 (Thread Block / Cooperative Thread Association) 협력과 공유의 단위\n서로 긴밀하게 협력할 수 있는 스레드들의 그룹(최대 1024 스레드) 입니다. 같은 블록 내의 스레드들은 Shared Memory를 공유하고, __syncthreads() 배리어(Barrier)를 통해 실행 단계를 동기화할 수 있습니다. 하나의 블록은 물리적으로 반드시 하나의 SM (Streaming Multiprocessor)에 할당되어 생애주기를 마칩니다. SM의 자원(Register, Shared Memory 용량) 한계가 곧 블록 크기의 제약이 됩니다. 1차원~3차원(Block(x,y,z))으로 구성 가능하여, 이미지나 볼륨 데이터 같은 다차원 문제를 직관적으로 맵핑할 수 있습니다. 스레드 블록 클러스터 (Thread Block Cluster) 블록 간 고속 통신을 위한 상위 계층 (Hopper 이상)\nHopper 아키텍처에서 도입된 상위 계층으로, 여러 개의 스레드 블록을 묶은 단위입니다. 기존에는 블록 간 통신이 매우 제한적이었습니다 (Global Memory 경유). 클러스터는 물리적으로 GPC (Graphics Processing Cluster)에 매핑됩니다. 클러스터 내의 블록들은 DSMEM 기술을 통해, L2 캐시를 거치지 않고 서로의 Shared Memory에 직접 접근(P2P, Peer-to-Peer)할 수 있습니다. 그리드 (Grid) 커널 실행의 전체 단위\n커널이 호출(Launch)될 때 생성되는 모든 스레드 블록의 집합입니다. 커널 호출 한 번이 곧 하나의 그리드입니다. 그리드 내의 블록들은 서로 독립적입니다. 실행 순서가 보장되지 않습니다. 서로 다른 SM에서 병렬로 실행될 수도, 하나의 SM에서 순차적으로 실행될 수도 있습니다. 이 독립성 덕분에 동일한 코드가 SM이 10개인 보급형 GPU에서도, SM이 144개인 H100에서도 수정 없이 동작하는 확장성(Scalability) 이 보장됩니다. GPU는 어떻게 동작하는가? 그렇다면 코드를 넣었을 때 GPU는 도대체 어떻게 동작하는 것일까요? Scheduling 예시를 통해 차근차근 알아보겠습니다.\n간단한 fp32(32-bit floating-point) 덧셈 커널을 예시로 살펴봅시다.\n그리드를 블록 1개, 각 블록은 96개의 스레드로 구성하여 커널을 실행합니다.\n실제로는 커널이 머신 코드(SASS, Shader Assembly)로 컴파일되지만, 편의상 4단계의 논리적 과정으로 생각해볼 수 있습니다:\n오퍼랜드 A를 메모리(SMEM/Shared Memory, L1, L2, global)에서 레지스터 파일로 불러오기 (LD, Load) 오퍼랜드 B를 레지스터로 불러오기 (LD) 레지스터에 있는 오퍼랜드로 FADD(Floating-Point Add) R3, R1, R2 연산을 수행하여 결과를 레지스터에 저장 계산 결과를 다시 메모리(SMEM/L1/L2/global)에 저장하기 (ST, Store) LD와 ST 연산은 연산 파이프라인 관점에서 비동기적으로 동작 합니다.\nLD/ST 유닛은 메모리 주소를 계산하여 메모리 서브시스템에 요청을 보내고,\n메모리 서브시스템이 나중에 이를 완료합니다.\n만들어진 총 96개의 스레드는 3개의 warp로 나뉘고, 1개의 block에 배정되어 있으므로 1개의 SM에 할당됩니다.\n이때 scheduling 예시 편의를 위해 모두 같은 SMSP에 할당된다고 가정합시다.\nHopper에서의 Warp 스케줄링 하드웨어 본격적인 스케줄링 예시로 들어가기 전에, Hopper 기준으로 Warp Scheduler와 Dispatch Unit이 어떤 역할을 하는지를 먼저 짚고 가겠습니다.\nWarp Scheduler는 scoreboard를 이용해 각 warp의 의존성 상태를 추적하면서,\n지금 당장 실행 가능한(eligible) warp를 고르는 역할을 합니다.\n이때 Dispatch Unit의 처리 능력, 예를 들어 Hopper에서 대략 32 threads/clk 수준의 issue 폭을 고려해,\n해당 사이클에 자원이 부족한 warp는 나중에 issue하도록 뒤로 미룹니다.\nDispatch Unit은 이렇게 선택된 warp의 명령을 실제 실행 파이프라인에 태우는 모듈입니다.\nWarp Scheduler는 warp 단위로 issue하지만, Dispatch Unit은 32개의 스레드를 여러 사이클에 나누어 보내거나,\nLD/ST·INT(Integer)·FP(Floating-Point) 같은 서로 다른 타입의 파이프라인에 적절히 섞어서(co-issue) 보내\nGPU의 자원을 최대한 채우려고 합니다.\n이제 이 하드웨어 위에서, 첫 번째 warp인 Warp A가 어떻게 스케줄되는지를 단계별로 살펴보겠습니다.\nSingle Warp Scheduling Warp A는 Warp Scheduler(WS)에 의해 issue됩니다.\nPC(Program Counter) 값에 따라 첫 번째 명령어인 LD R1, [A+tid]가 Dispatch Unit으로 전송됩니다.\nDispatch Unit은 현재 SMSP에서 사용 가능한 자원을 스캔하여 8개의 LD/ST 유닛이 사용 가능함을 확인합니다.\n이후 issue된 32개의 스레드를 8개씩 4 사이클에 걸쳐 LD/ST 유닛에 할당합니다.\n각 유닛은 할당받은 명령어를 기반으로 메모리 주소를 계산하여 메모리 서브시스템에 로드 요청을 보냅니다.\n이러한 로드 명령은 비동기적으로 처리됩니다.\n5번째 사이클에 LD/ST 동작이 끝나면, WS는 Warp A를 release하면서 PC 값을 증가시킵니다.\n다음 사이클에 WS는 release된 Warp A를 다시 issue하여 같은 방식으로 두 번째 LD 명령을 수행합니다.\n두 번의 LD가 모두 issue된 후, Warp A는 바로 FADD R3, R1, R2를 실행할 수 없습니다.\nR1과 R2가 아직 비동기 로드에 의해 채워지는 중이기 때문입니다.\n워프는 두 오퍼랜드가 모두 준비될 때까지 기다려야 합니다.\n이 대기 시간 동안 FP 유닛은 유휴 상태가 되며, stall이 발생합니다.\n메모리 로드 시간은 대략적으로 다음과 같습니다:\nL1(Level 1) cache: ~20 사이클 L2(Level 2) cache: ~100 사이클 HBM(High Bandwidth Memory): 수백 사이클 (300~800) 메모리 로드가 완료되고 의존성(Dependency)이 해결되면, Warp A는 다시 eligible 상태가 되어 WS에 의해 issue됩니다.\nFADD 명령은 FP32(32-bit Floating-Point) 파이프라인으로 전송됩니다.\nHopper에서는 SMSP당 32개의 FP32 유닛이 존재하므로, 워프 내 32개 스레드를 한 번에 처리할 수 있습니다.\nFADD 연산이 완료되면 워프가 다시 release되고, 마지막 ST 명령은 LD와 유사한 방식으로 동작합니다.\nDouble Warp Scheduling 이제 Warp B를 추가해봅시다.\nSingle warp 시나리오에서는 첫 번째 LD가 끝났을 때, Warp A의 PC(Program Counter)가 아직 완전히 이동하지 않은 상태라서\nWS가 즉시 Warp A를 다시 issue할 수 없어 한 사이클의 유휴 상태가 발생했습니다.\n하지만 Warp B가 있으면 이 유휴 슬롯을 활용할 수 있습니다.\nWarp A가 모든 LD/ST 유닛을 사용 중일 때는 Warp B를 실행할 수 없습니다.\n하지만 A의 LD가 모두 dispatch되면, WS는 Warp B를 issue하여 같은 방식으로 LD를 수행합니다.\n이렇게 A와 B를 번갈아가며 총 네 번의 LD 명령을 issue합니다 (워프당 두 번씩).\n그 후 두 워프 모두 FADD를 수행하기 전에 로드가 완료되기를 기다립니다.\nSingle warp 케이스와 비교했을 때 핵심 차이점은 Warp A의 메모리 레이턴시가 Warp B의 로드와 오버랩된다는 것입니다.\n이로 인해 보이는 stall 시간이 줄어듭니다.\nWarp A의 두 번째 LD 이후 Warp B의 LD가 바로 이어지기 때문에, Warp A의 비동기 메모리 로드 시간이 오버랩되어 stall 시간이 감소합니다.\nWarp A의 메모리 로드가 완료되면 즉시 FADD가 issue 및 dispatch됩니다.\n예시에서는 Warp B의 의존성도 곧바로 해결되어 다음 사이클에 FADD가 연달아 수행됩니다.\n연산기가 파이프라인 구조로 되어 있기 때문에, 각 스테이지별 유휴 상태가 독립적으로 관리되며\n레이턴시를 효과적으로 숨길 수 있습니다.\nMultiple Warp Scheduling 마지막으로 Warp C를 추가합니다.\n세 개의 워프가 동시에 실행되면, GPU는 메모리 연산과 계산을 더욱 효과적으로 오버랩할 수 있습니다.\n이를 통해 발생할 수 있는 대부분의 stall이 사라집니다.\n결론적으로, Hopper에서의 CUDA 프로그래밍은 SMSP 파이프라인에 충분한 독립적인 작업을 채우는 것이 핵심입니다.\n여러 워프에서 로드, 산술 연산, 스토어를 issue하여 비동기 메모리 통신 시간을 효과적으로 오버랩하는 방식으로 동작합니다.\n정리하자면… 이 글에서는\n① 그래픽 카드에서 출발한 NVIDIA의 역사,\n② Tesla·CUDA를 거치며 GPGPU 플랫폼으로 확장된 과정,\n③ Hopper 세대 기준의 하드웨어 구조와 스케줄링 예시를 살펴보며,\n궁극적으로\n\u0026ldquo;GPU는 느린 메모리를, 많은 워프 간의 빠른 컨텍스트 전환과 여러 연산의 동시 실행으로 가리는 장치\u0026rdquo;\n라는 결론에 도달했습니다.\n결국 메모리 계층, 스케줄러 정책, 실행 파이프라인까지 GPU의 모든 설계 요소가 이 목표를 중심으로 짜여 있다는 점이 핵심입니다.\n다음 글에서는 최근 무섭게 AI 하드웨어 시장을 뺏어가고 있는 Google의 TPU에 대해서 살펴보겠습니다. TPU의 역사와 최신 TPU 아키텍처인 Ironwood에 대한 분석을 진행할 예정이니 많은 관심 부탁드립니다.\n그럼 지피지기면 백전불태 2편: TPU의 등장과 부상 에서 다시 뵙겠습니다.\n추신: HyperAccel은 채용 중입니다! 지피지기면 백전불태라지만 백전백승을 위해서는 훌륭한 인재가 많이 필요합니다!\n저희가 다루는 기술들을 보시고, 관심이 있으시다면 HyperAccel Career로 지원해 주세요!\nHyperAccel에는 정말 훌륭하고 똑똑한 엔지니어분들이 많습니다. 여러분의 지원을 기다립니다.\n","permalink":"https://hyper-accel.github.io/posts/how-gpu-works/","summary":"NVIDIA GPU의 역사와 Hopper 아키텍처를 통해, 어떻게 GPU가 메모리 레이턴시를 숨기는지 정리한 글입니다.","title":"지피지기면 백전불태 1편: GPU의 역사와 기초"},{"content":"Tech Blog를 시작하게 된 계기 저희 회사 SW group에는 김재우(Author, LinkedIn)님이라는 개발자가 계십니다. 재우님께서는 저희 HW kernel 개발을 위한 언어인 legato를 개발해주고 계신데요. 재우님께서 몇 달 전부터 꾸준히 요청해주신 것이 있습니다.\n저희 회사 기술 블로그 하면 안되나요? (from 재우)\n재우님께서는 이전 직장에서 진행하셨던 프로젝트를 기술 블로그에 올렸던 경험이 있으셨고, 그 포스트 덕분에 여러 실력 있는 개발자분들께서 회사에 관심을 가지게 되어 입사까지 하셨던 경험이 있다고 하셨습니다.\n그리고 저도 저희 회사가 고성능의 LLM Inference Chip을 만들기 위해 고민하는 내용, 그 Chip을 잘 지원하기 위한 Software Stack을 만들기 위해 고민하는 바가 엄청나게 많은데, 그것을 외부 개발자분들께 전달드리고 싶다는 생각을 많이 하였습니다.\n그런데\u0026hellip;. 누가 만들고 운영하지?\n블로그에 올릴 글들은 저희 회사의 Wiki (confluence로 운영 중)에 아주 풍부하게 있다는 것은 알고 있었습니다. 하지만 올릴 글이 많다는 것과, 블로그를 만들어서 운영한다는 것은 또 다른 차원의 문제였죠.\nHyperAccel의 LLM Inference Engine 지원을 위한 오픈소스 분석 (Coming Soon\u0026hellip;)\n재우님께서 기술 블로그를 운영하면 좋겠다는 말씀을 하신지도 몇 개월이 지났지만, 아직 아무도 엄두를 내지 못하였습니다. 왜냐하면 아무도 운영을 해본 적이 없으니까요!\n그런데 저는 사실 저는 해본 적이 있었습니다\u0026hellip; 저의 개인 블로그에 몇 년간 글을 올린 적이 있었기 때문이죠.\n하지만 누군가는 나서서 하지 않을까? 라는 막연한 기대감과, \u0026ldquo;난 지금도 너무 바쁜데\u0026hellip;\u0026rdquo; 라는 생각으로 인해 애써 모른 척을 하고 있었습니다.\n그런데 올해 10월에 재우님과 PyTorch Conference를 같이 다녀올 일이 생겼습니다(이전 포스트 참고).\n그때 재우님께서 미국 출장 중에도 한국 시간에 계속 팀원들과 논의하면서 컴파일러를 개발하는 것을 보고, 내가 바빠서 못하는 것은 핑계가 아닐까? 라는 생각을 하게 됐습니다.\n그리고 제가 팀장으로서 팀원들에게 언제나 하는 이야기가 있었어요.\n\u0026ldquo;나다 싶으면 해라\u0026rdquo; 라는 마인드 셋입니다.\n그래서 결정했습니다. 내가 하기로\n기술 블로그 플랫폼 선정 기술 블로그를 만들 때는 여러 가지 선택지가 있습니다.\n블로그 플랫폼 이용 Velog Medium Tistory \u0026hellip; 자체 구축 (Static Site Generator + github pages 이용) Jekyll Hugo \u0026hellip; 물론 제일 간편한 것은 블로그 플랫폼을 이용하는 것이겠지요. 간단하게 회원가입 후 블로그를 만들면 되니까요.\n하지만 제가 생각했던 기술 블로그 운영 시에 중요한 요소들이 몇 가지 있었습니다.\n댓글 기능이 있어야 함 Google Analytics를 붙일 수 있어야 함 SEO가 잘 되어야 함 유지 보수가 편리해야 함 여러 사용자가 쉽게 본인 글을 투고할 수 있어야 함 다른 요소들은 블로그 플랫폼을 이용하여도 충분히 지원이 가능했지만, 유지 보수가 편리해야 함과 여러 사용자가 쉽게 본인 글을 투고할 수 있어야 함은 블로그 플랫폼을 활용해서는 달성하기가 어려워보였습니다.\n어 그런데 블로그 플랫폼을 사용해야 유지 보수가 편리하지 않나요?\n그렇습니다. 개인 블로그를 운영할때는 아마 블로그 플랫폼을 사용하는 것이 훨씬 편할 겁니다. 하지만 저희가 반드시 고려해야하는 점이 있었습니다.\n\u0026ldquo;저희 기술블로그는 직원 한명이 운영하는 것이 아닌 Editor Group이 운영해야 한다\u0026rdquo; 입니다.\n저는 Software Engineering at Google이라는 책을 굉장히 좋아하고, 이 책에서 배운 것들을 팀 운영시에 많이 적용을 하고 있는데요. 이 책에 Bus Factor라는 용어가 나옵니다.\nBus Factor : 프로젝트를 진행하는 팀원 중 몇 명이 제대로 된 인수인계 등의 절차 없이 갑작스럽게 빠지게 되었을 때 프로젝트가 중단 내지는 그에 준하는 심각한 상황에 놓이는지를 나타내는 지수\nBus Factor가 높을수록 프로젝트의 안정성이 높아지는데요, 만약 블로그 플랫폼을 이용하여 블로그 운영을 한다면 블로그 운영자(아마도 저겠죠?)가 블로그 운영을 할 수 없는 상황에 빠진다면, 저희 기술블로그는 유령블로그가 될 것입니다.\n하지만 자체 구축을 Github을 이용해서 한다면, 블로그 구축 자체는 제가 대부분 해야하지만 운영은 Editor Group에서 할 수 있습니다.\n그래서 시작되었습니다. Hugo를 이용한 기술 블로그 구축\n기술 블로그 구축! 기존에 제가 운영하던 블로그는 Jekyll로 만들었습니다. 하지만 Jekyll은 테마 수정이 어렵고, Ruby 기반이기 때문에 가끔 dependency 문제를 일으키는 경우가 있었습니다. 저는 Ruby를 사용해 본적이 없어서, dependency 문제가 발생해도 흐린눈 뜨고 그냥 무시를 했었죠\n그런데, 최신 SSG (Static Site Generator)를 찾아보니 Go 언어로 된 Hugo라는 녀석이 보였고, 테마도 다양하고, 커뮤니티도 많이 활성화 되어있어, 이를 기반으로 블로그 구축을 시작했습니다.\n그리고 Editor Group으로 참여하고 싶은 사람도 모집을 하였지요.\n무려 9명이나 지원자가!\n그리고 댓글 기능, 다국어 지원 (한국어, 영어), 검색 기능, Google Search 등록, Google Analytics 등록, Author 기능\u0026hellip; 도 모두 구현을 완료하였습니다!\n기술 블로그 운영 저희 기술 블로그에 글을 작성하고 싶으면 Github Pull Request를 통해서 진행이 가능합니다. Github PR로 진행되기 때문에, 특정 관리자가 아닌, 글을 작성하고 싶은 사람이 자유롭게 투고를 할 수 있는 시스템으로 운영이 됩니다.\n그리고, Editor Group은 PR에서 자유롭게 글에 대한 의견을 댓글로 남길 수 있습니다.\nEditor Group의 아주 중요한 역할이 하나 있습니다. 바로 개발자 분들께 기술 블로그 포스트 작성을 독려 하는 것이죠.\n저는 2018년경에 BERT라는 논문을 읽고 BERT 논문정리라는 블로그 글을 포스팅한 적이 있었는데요. 감사하게도 이 글을 굉장히 많은 분들이 읽어주셔서 한동안 Google 검색 결과 최상단에 노출이 되었습니다.\n자신이 공부하고 조사한 내용을 외부에 알리는 것은 회사의 기술력을 홍보하기에도 좋지만, 개인에 대한 홍보도 되고 또 되어야 한다고 믿기 때문에, 개발자 분들께 사내 wiki에 정리한 내용 중 외부에 공개해도 좋은 글들이 있다면 적극적으로 블로그 포스팅해주시는 것을 독려하고 있습니다.\n추후 올라갈 글들\u0026hellip; 저희 HyperAccel에서는 LLM Inference를 위한 HW 설계와 그것을 위한 Software Stack 전체를 다 개발하는 회사입니다.\n그렇기 때문에 정말 넓은 범위의 기술을 한 회사 내에서 다루고 있는데요. 그래서 기술 블로그에 올리게 될 글들도 정말 다양한 topic을 다룰 것입니다.\nCompiler는 어떻게 만드는 것인지? GPU의 특성 (지피지기면 백전백승) LLM Inference Framework (vLLM, SGLang, \u0026hellip;) 오픈소스 분석 Cluster 환경에서 Hardware 지원을 위한 Kubernetes Components 개발기 Kubernetes 기반 사내 개발 환경 구축기 \u0026hellip; 정말 다양하고 퀄리티 높은 글들을 공유할 예정이니, 많이 관심 가져 주세요!\nHyperAccel은 채용 중 입니다! 저희가 이 기술 블로그를 운영하는 목적 중 가장 큰 것은, 인재 영입 입니다!\n저희가 다루는 기술들을 보시고, 관심이 있으시다면 HyperAccel Career로 지원해주세요!\nHyperAccel에는 정말 훌륭하고 똑똑한 엔지니어분들이 많습니다. 여러분의 지원을 기다립니다.\n","permalink":"https://hyper-accel.github.io/posts/tech-blog-operation/","summary":"\u003ch2 id=\"tech-blog를-시작하게-된-계기\"\u003eTech Blog를 시작하게 된 계기\u003c/h2\u003e\n\u003cp\u003e저희 회사 SW group에는 김재우(\u003ca href=\"https://hyper-accel.github.io/authors/jaewoo-kim/\"\u003eAuthor\u003c/a\u003e, \u003ca href=\"https://www.linkedin.com/in/jaewoo-kim-b38325237/\"\u003eLinkedIn\u003c/a\u003e)님이라는 개발자가 계십니다. 재우님께서는 저희 HW kernel 개발을 위한 언어인 \u003ccode\u003elegato\u003c/code\u003e를 개발해주고 계신데요. 재우님께서 몇 달 전부터 꾸준히 요청해주신 것이 있습니다.\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"jaewoo-teams\" loading=\"lazy\" src=\"/posts/tech-blog-operation/jaewoo-teams.png\"\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e저희 회사 기술 블로그 하면 안되나요?\u003c/strong\u003e                   (from 재우)\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e재우님께서는 이전 직장에서 진행하셨던 프로젝트를 기술 블로그에 올렸던 경험이 있으셨고, 그 포스트 덕분에 여러 실력 있는 개발자분들께서 회사에 관심을 가지게 되어 입사까지 하셨던 경험이 있다고 하셨습니다.\u003c/p\u003e\n\u003cp\u003e그리고 저도 저희 회사가 \u003cstrong\u003e고성능의 LLM Inference Chip을 만들기 위해 고민\u003c/strong\u003e하는 내용, 그 \u003cstrong\u003eChip을 잘 지원하기 위한 Software Stack을 만들기 위해 고민\u003c/strong\u003e하는 바가 엄청나게 많은데, 그것을 외부 개발자분들께 전달드리고 싶다는 생각을 많이 하였습니다.\u003c/p\u003e","title":"기술 블로그 시작기"},{"content":"프로그래밍 언어 만들기 컴파일러를 만들기 전에, 우리는 먼저 언어를 정의해야 합니다. 프로그래밍 언어는 단순히 구문으로 정의되는 것이 아닙니다. 사실 프로그래밍 언어는 인간과 컴퓨터 사이의 사용자 인터페이스입니다.\n프로그래밍 언어란 무엇인가? 추상화는 컴퓨터 과학의 핵심 개념 중 하나입니다. 추상화가 없다면, 컴퓨터로 무언가를 하기 위해서는 전기 신호, 메모리 레이아웃, 레지스터, 그리고 수많은 하드웨어의 특징을 고려해야 할 것입니다.\n프로그래밍 언어는 이러한 복잡성을 단순화합니다. 그것은 아이디어를 표현하는 인간 친화적인 방법을 제공하면서, 그것들을 작동하게 만드는 low-level 메커니즘을 숨깁니다. 이런 의미에서, programming language는 computing을 위한 UI로 기능합니다—하드웨어를 수동으로 조작하는 대신, 로직, 애플리케이션, 그리고 시스템을 구축하는 데 집중할 수 있게 해주는 계층입니다.\nPython, Rust, C++, Go, 또는 완전히 새로운 언어를 선택하든 목적은 동일합니다: 인간의 명령을 기계의 행동으로 바꾸는 것입니다. 먼저 프로그래밍 언어가 어떤 방식으로 디자인될 수 있는지 함께 살펴봅시다.\n컴파일러(Compiled) vs 인터프리터(Interpreter) Programming language 구현은 종종 코드를 실행하는 방식에 따라 분류됩니다:\nCompiled language Interpreted language 컴파일 언어는 실행 전에 전체 소스 코드를 machine instruction으로 변환합니다. 일단 컴파일되면, 프로그램은 하드웨어에서 직접 실행될 수 있으며, 높은 성능과 효율적인 CPU 사용을 제공합니다.\n반면에 인터프리터 언어는 코드를 단계별로 실행합니다. 인터프리터는 각 명령어를 읽고 즉시 수행하며, 독립적인 machine binary를 생성하지 않습니다.\n간단한 비유를 해봅시다:\n프랑스어로 작성된 요리책이 있다고 상상해보세요.\n인터프리터를 사용하면, 요리책 한 줄을 읽고, 그것을 한국어로 번역한 다음, 번역된 내용대로 그대로 따릅니다. 그리고, 다음 한 줄을 또 읽고, 번역한 다음 그대로 하기를 또 반복합니다. 컴파일러를 사용하면, 프랑스어에 능통한 친구를 데려와 책을 끝까지 한국어로 번역한 다음 (이래서 마음씨 좋은 친구가 필요하겠지요?), 여러분은 한국어 책을 보며 멈추지 않고 원활하게 요리합니다. 컴파일 언어(C, C++, 또는 Rust 같은)는 일반적으로 속도, 안전성 분석, 그리고 최적화를 제공하지만, 코드가 변경되면 다시 컴파일 해야합니다. 인터프리터 언어(Python, Ruby, 또는 Perl 같은)는 편의성, 상호작용성, 그리고 유연성을 우선시합니다 (특히 초기 개발 단계에서 유용하지요) 하지만 \u0026ldquo;일반적으로\u0026rdquo; 더 느리게 실행됩니다. 이것이 C가 일반적으로 Python보다 빠른 이유입니다. C도 REPL(Read Eval Print Loop 의 약자로, 사용자와 곧바로 상호작용하면서 프로그램을 실행할 수 있는 환경)과 같은 환경을 가질 수 있지만, 잘 쓰이지 않고 표준 toolchain의 일부가 아닙니다.\nLanguage는 동시에 컴파일(Compiled) 되거나 인터프리트(Interpreted) 될 수 있습니다\n실제로, \u0026ldquo;컴파일 언어\u0026rdquo; 또는 \u0026ldquo;인터프리터 언어\u0026rdquo; 라는 것은 언어 자체의 속성이 아니며, 이러한 구분을 언어 자체보다는 언어 구현의 속성으로 보는 것이 더 정확합니다.\n한 가지 예로, JVM(Java Virtual Machine 자바 가상머신) 기반 언어는 \u0026ldquo;compiled\u0026quot;와 \u0026ldquo;interpreted\u0026rdquo; 둘 다 될 수 있습니다. 즉, runtime에 Just-In-Time compiler를 사용하여 즉석에서 기계어로 컴파일되거나, 실행 (interpret) 될 수 있습니다. 일반적으로 Java(또는 다른 JVM 기반 언어) 프로그램은 먼저 \u0026ldquo;bytecode\u0026quot;라고 불리는 것으로 compile됩니다. 이것은 JVM을 위한 instruction이지만, 하드웨어의 종류에 영향을 받지 않습니다. 이 bytecode는 JVM이 실행되는 어디든 배포될 수 있으며, target 특정 코드로 컴파일하거나 bytecode를 실행하는 것은 JVM의 구현 방식에 따라 달라집니다.\nPython 또한 종종 인터프리터 언어로 설명되지만, 실제로는 소스 코드가 먼저 Python bytecode(.pyc 파일)로 컴파일된 다음, PVM(Python Virtual Machine)에 의해 실행됩니다. PyPy와 같은 일부 파이썬 구현은 JVM이 하는 것처럼 Python을 기계어로 컴파일할 수도 있습니다.\nManaged vs. Unmanaged 프로그래밍 언어의 특성을 구분하는 또 다른 유용한 방법은 메모리를 관리하는 방식입니다.\n프로그램이 실행되려면 메모리가 필요합니다. 프로그램은 운영 체제로부터 메모리를 요청하고 완료되면 반환해야 합니다. 그렇게 하지 않으면 문제가 발생합니다:\n프로그램이 소유하지 않은 메모리에 접근할 때 Segmentation fault 사용하지 않는 메모리가 절대 반환되지 않을 때 Memory leak Managed language는 메모리 처리를 자동화하며, 종종 garbage collection이나 runtime 분석을 사용합니다. 이것은 메모리 관련 실수의 가능성을 줄이고 개발을 단순화합니다. 그들은 일반적으로 \u0026ldquo;Garbage Collector (GC)\u0026ldquo;라고 불리는 프로그램을 사용하는데, GC는 자동으로 도달할 수 없는 메모리 영역을 감지하고 해제하므로, 운영 체제가 다른 프로그램(process)을 위해 그 메모리를 할당할 수 있습니다. 일부 garbage collector는 특정 단계에서 전체 프로그램을 중지할 수 있지만(stop-the-world), 현대의 collector들은 다양한 기법들을 사용하여 긴 일시 중지를 줄이거나 피합니다. Garbage collector는 편리하지만 프로그램을 더 느리게 만들 수 있다는 단점이 있습니다.\nManaged programming language 예시 (Python)\n# my_list is internally allocated size = input() # Python internally allocates memory space for storing list. my_list = [x for x in range(0, int(size))] # Do some work using my_list # my_list is automatically deallocated after use Unmanaged language (C/C++)는 개발자에게 직접적인 제어권을 줍니다. 그들은 malloc과 free와 같은 API를 제공하며, 이것은 궁극적으로 lower-level system call을 통해 운영 체제로부터 메모리를 요청합니다. 프로그래머는 메모리가 올바르게 할당되고 해제되는지 확인하고, 잘못되지 않도록 직접 관리해야 합니다. Unmanaged language는 garbage collector에 의존하지 않기 때문에, stop-the-world event(GC를 돌리기 위해 프로그램을 일시정지 하는 것) 와 같은 GC 관련 일시 중지를 피하지만, 정확성과 안전성의 책임을 프로그래머에게로 넘깁니다. 프로그래머가 언제 메모리를 할당하고 해제할지 수동으로 최적화할 수 있기 때문에 더 많은 최적화를 진행할 수도 있죠. 하지만 이것을 프로그래머가 직접 관리해야 하므로, 프로그램을 더 복잡하게 만들고, 깨지기 쉽게 만듭니다. (Rust는 garbage collection 없이 메모리 안전성을 달성하기 위해 컴파일러가 강제하는 정적 ownership 및 borrowing 시스템을 사용합니다.)\nUnmanaged programming language 예시 (C)\n#include \u0026lt;stdio.h\u0026gt; #include \u0026lt;stdlib.h\u0026gt; int main(){ int size; scanf(\u0026#34;%d\u0026#34;, \u0026amp;size); // Explicitly allocate aray int* my_list = malloc(size * sizeof(int)); for(int i = 0; i \u0026lt; size; ++i){ my_list[i] = i; } // Do some work with my_list // my_list has to be explicitly freed, or memory would leak. free(my_list); return 0; } 함수형 프로그래밍 (Functional Programming) 마지막으로, 프로그래밍 언어의 또 다른 패러다임 중 하나인 함수형 프로그래밍에 관해 간단히 소개하고자 합니다. 일반적인 언어보다는 조금 덜 사용되지만, 그만큼 장점이 많은 프로그래밍 패러다임이기 때문에 소개하고자 합니다. 함수형 프로그래밍을 하면 훨씬 버그를 적게 발생시키는 프로그램을 작성할 수 있거든요. 여러분이 함수형 프로그래밍을 실제로 하고 있지 않더라도, 프로그래머로써 알아두면 더 안정적인 프로그램을 만드는 데 도움이 됩니다.\n함수형 프로그래밍 언어는 프로그램을 수학적인 함수로 구성함으로써 함수의 순수성, 값의 불변성, 그리고 함수들이 합성되는 방식을 강조하는 프로그래밍 언어입니다. 함수형 언어는 computation이 표현식(expression)의 평가(evaluation)로 표현됩니다. 우리가 수학에서 정의하는 함수는, 입력이 같을 경우 결과가 절대 달라질 수 없지요? 함수형 프로그래밍에서는 이 사고방식을 따릅니다.\n다음은 list의 모든 숫자를 더하는 간단한 예시입니다\nPython으로 list의 값들을 모두 더하는 예시\nmy_list = [1,2,3,4,5] sum = 0 for elem in my_list: sum += elem print(f\u0026#34;Sum : {sum}\u0026#34;) # Prints \u0026#34;Sum : 15\u0026#34; 함수형 언어의 예시 (F#)\nlet my_list = [1;2;3;4;5] let sum = List.fold (fun acc elem -\u0026gt; acc + elem) 0 my_list printfn \u0026#34;Sum : %A\u0026#34; sum // Prints \u0026#34;Sum : 15\u0026#34; 둘 다 같은 일을 하지만, 작성되는 방식이 조금 다르지요?\nPure functional language는 다른 언어들이 갖지 않는 제약사항이 있습니다.\n모든 값(let binding)은 불변 (immutable) 입니다. for loop가 없습니다 (모든 iteration은 recursion으로 수행됩니다) 그러나, compiler는 함수가 \u0026ldquo;tail-recursive\u0026quot;이면 최적화를 위해 recursion을 loop로 변환할 수 있습니다 (이것에 대해서는 나중에 더 설명하겠습니다) 순수 함수형 언어가 아닌 함수형을 지향하는 멀티 패러다임(multi-paradigm) 언어들은, for loop을 제공하기도 합니다. 함수가 \u0026ldquo;순수(Pure)\u0026rdquo; 합니다 \u0026ldquo;순수(Pure)\u0026ldquo;하다는 것은 함수가 프로그래머가 모르는 side-effect가 들어있는 동작을 하지 않는다는 것을 의미합니다. Side-effect라 함은, 겉으로 들어나지 않는 내부적인 동작을 의미합니다 예를 들면 파일 입출력 등이 있지요. Side-effect가 없으므로, 결과가 사용되지 않으면 함수를 제거해도 안전합니다 (Compiler는 더 공격적으로 dead code elimination을 할 수 있습니다) Function은 동일한 입력이 주어지면 항상 같은 결과를 제공합니다 Functional programming language는 일반적으로 더 가파른 학습 곡선을 가지며, 많은 프로그래머들이 functional language에 익숙하지 않습니다. 그러나 몇 가지 명확한 장점이 있습니다.\n함수형 프로그래밍의 장점\nSide-effect가 없기 때문에, 프로그램이 더 안전하고, 안정성 분석이 쉽습니다. 컴파일러가 잠재적인 오류를 감지하기 쉽게 만듭니다. 프로그램을 더 명확하게 표현할 수 있습니다. 실행 자체보다 \u0026ldquo;무엇을 계산할지\u0026quot;에 초점을 맞춥니다. (조금 잘 안 와닿을 수 있지만, 함수형 언어의 구현들을 보면 보다 쉽게 이해하실 겁니다) Purity(순수 함수)와 immutability(값의 불변성)는 안전한 concurrent 프로그램을 작성하기 쉽게 만듭니다. 위에 나열된 이유들을 모두 설명하는 것은 이 장의 범위를 벗어나지만, programming language를 만들어가다 보면, 왜 이러한 문제가 중요한지, 그리고 함수형 언어가 일반적인 프로그래밍 언어와 비교해 가지는 장점들을 이해할 수 있을 것입니다. 물론, 함수형 언어는 만능 해결책이 아닙니다. 특정 작업, 특히 복잡한 side effect가 필요하거나, 성능이 중요한 작업의 경우, 함수형 스타일로 만들지 않는 것이 더 자연스럽거나 효율적일 수 있습니다.\nProgramming language를 만들어봅시다! 그래서, 우리는 어떤 종류의 언어를 만들게 될까요?\n우리는 GC를 사용하지 않는 (즉 컴파일러나 사용자가 메모리를 관리하는), 함수형 스타일 (100% 함수형으로는 만들지 않을 것입니다) 언어와, 컴파일러를 만들 것입니다. 하지만 우리는 ownership control(Rust처럼!)을 구현할 것이므로 프로그래머가 데이터의 lifetime을 수동으로 관리할 필요가 없습니다. 왜 이렇게 하냐고요? Compiler 자체에 집중하기 더욱 쉽고(interpreter나 garbage collector를 만들 필요가 없습니다!), 그리고 이미 interpreter를 구현하는 것에 대해서는 좋은 글들이 많기 때문에, 여기서는 컴파일러에 더 집중해 보고자 합니다.\n왜 함수형 언어인가?\n함수형 언어는 대부분의 사람들에게 배우기 더 어렵고, 많은 프로그래머들이 익숙하지 않은 유형의 언어입니다. 그런데 왜 함수형 언어를 만들고자 할까요? 첫째, language designer의 관점에서, 정의하기 더 쉽고 명확합니다. 둘째, 대부분의 프로그래머들이 함수형 프로그래밍에 익숙하지 않기 때문에, 함수형 프로그래밍에 대해 소개해주고 싶었습니다. 우리는 그것이 일반적인 프로그래밍 언어와 어떻게 다르게 행동하는지 보고, 어떤 장점과 단점이 있는지 볼 것입니다. 그러나, 함수형 언어를 만들지 않더라도 여기서 설명된 개념들을 이용하면 도움이 될 것입니다.\nHoya Language. 우리의 언어는 \u0026ldquo;Hoya\u0026quot;라고 이름을 붙여 보았습니다. 이 글의 나머지 부분은 Hoya를 구현하는 것을 중심으로 진행될 것입니다. 하지만 키보드를 치기 전에, 먼저 Hoya가 어떻게 생겼는지 살펴봐야겠지요? 만들기 전에, 먼저 우리가 뭘 만들지 정의하고 시작합시다.\nHello world! Hoya가 \u0026ldquo;Hello world!\u0026ldquo;를 출력하게 해 봅시다. 다음은 Hoya language의 가장 간단한 예시입니다.\nfunc main(){ print(\u0026#34;Hello world!\u0026#34;) 0 } 이 프로그램은 간단한 트리(tree) 형태로 표현해볼 수 있습니다.\n이것은 우리의 프로그램이 어떻게 보이는지입니다 (접미사 \u0026ldquo;E\u0026quot;는 \u0026ldquo;Expression\u0026quot;을 나타냅니다).\nCallE (call expression)는 세 개의 자식으로 구성됩니다. 첫 번째는 callee(호출되는 함수)를 나타냅니다. 두 번째는 인수인 \u0026ldquo;Hello world\u0026quot;이며, string을 나타냅니다. 마지막은 NextE이며, 실행할 다음 expression을 나타냅니다. 여기서, 다음 expression은 상수 0입니다.\n프로그램을 tree와 같은 형식으로 표현함으로써, 컴파일러나 인터프리터는 그것을 순회하고 컴파일하거나 실행할 수 있습니다. 이러한 종류의 트리를 AST(Abstract Syntax Tree의 약자)라고 합니다. 프로그램—컴퓨터의 관점에서는 단순한 문자열을 AST로 변환하는 것은 일반적으로 compiler가 수행하는 첫 번째 과정입니다. 프로그램이 AST로 변환되면, 컴파일러가 기계어로 번역하거나, 인터프리터로 직접 실행할 시작할 수 있습니다.\n다음 장부터, Hoya의 모든 부분을 설계하기 시작할 것입니다. 언어가 어떻게 정의될 수 있는지, 그리고 각 표현식(expression) 이 평가될 때 동작을 어떻게 정의하는지 살펴봅시다.\n","permalink":"https://hyper-accel.github.io/posts/crafting-compilers-ch1-1/","summary":"\u003ch1 id=\"프로그래밍-언어-만들기\"\u003e\u003cstrong\u003e프로그래밍 언어 만들기\u003c/strong\u003e\u003c/h1\u003e\n\u003cp\u003e컴파일러를 만들기 전에, 우리는 먼저 언어를 정의해야 합니다. 프로그래밍 언어는 단순히 구문으로 정의되는 것이 아닙니다. 사실 프로그래밍 언어는 인간과 컴퓨터 사이의 사용자 인터페이스입니다.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"프로그래밍-언어란-무엇인가\"\u003e\u003cstrong\u003e프로그래밍 언어란 무엇인가?\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e추상화는 컴퓨터 과학의 핵심 개념 중 하나입니다. 추상화가 없다면, 컴퓨터로 무언가를 하기 위해서는 전기 신호, 메모리 레이아웃, 레지스터, 그리고 수많은 하드웨어의 특징을 고려해야 할 것입니다.\u003c/p\u003e\n\u003cp\u003e프로그래밍 언어는 이러한 복잡성을 단순화합니다. 그것은 아이디어를 표현하는 인간 친화적인 방법을 제공하면서, 그것들을 작동하게 만드는 low-level 메커니즘을 숨깁니다. 이런 의미에서, programming language는 \u003cstrong\u003ecomputing을 위한 UI\u003c/strong\u003e로 기능합니다—하드웨어를 수동으로 조작하는 대신, 로직, 애플리케이션, 그리고 시스템을 구축하는 데 집중할 수 있게 해주는 계층입니다.\u003c/p\u003e","title":"Crafting Compilers (Chapter 1.1) : 프로그래밍 언어 만들기"},{"content":"NAVER DAN 2025 참관기 Introduction 안녕하세요? HyperAccel ML팀 박신현입니다. 2025년 11월 6~7일 양일간 코엑스에서 열렸던 NAVER DAN 2025에 다녀와서 느낀 점을 공유하려고 합니다.\n참관 동기 이번 컨퍼런스 참관의 주요 목적은 다음과 같습니다:\n확장 가능한 스토리지 인프라 인사이트 확보: 컴퓨팅 클러스터 내 노드끼리 데이터를 공유하는 것을 넘어, 서로 다른 클러스터 간 데이터를 주고 받을 수 있는 스토리지 인프라 구축을 위한 기술적 인사이트를 얻고자 했습니다.\nAI 클러스터 자원의 효율적 활용 방식 학습: HyperAccel에서는 AI 워크로드를 수행하기 위해 GPU, FPGA로 구성된 AI 클러스터를 운영하고 있습니다. 이러한 AI 클러스터 내 자원을 효율적으로 활용하기 위해, 다른 기업에서는 AI 클러스터를 어떻게 운영하고 있는지 학습하고자 했습니다.\nNAVER DAN 2025 주요 사항 IDC Seamless HDFS 분산 스토리지 인프라 인사이트를 얻기 위해 들었던 세션인 IDC Seamless HDFS 내용을 공유합니다. NAVER 검색 플랫폼에서 거대한 데이터와 트래픽을 처리하며 겪었던 멀티 IDC 환경의 한계와, 이를 극복하기 위해 자체 구축한 분산 스토리지 기술에 대한 이야기입니다.\n문제: 데이터 고립과 데이터 복구 NAVER는 평촌, 판교, 세종 등 여러 IDC에 걸쳐 대규모 Hadoop 클러스터(C3)를 운영 중인데, IDC 간 물리적 거리로 인해 다음과 같은 한계에 봉착했습니다.\n데이터 고립(Data Silo) 클러스터가 IDC별로 독립적으로 구성되어 있어, 타 IDC에 있는 데이터에 접근하려면 IDC 간 네트워크(DCI)를 타야 합니다. 이때 발생하는 트래픽이 DCI 대역폭을 초과하면, 해당 회선을 쓰는 다른 모든 서비스에 장애를 유발할 수 있어 매우 위험합니다. 데이터 복구(Data Recovery) 데이터가 특정 IDC에만 고립되어 저장되므로, 화재 등으로 해당 IDC가 전소될 경우 데이터가 영구 소실될 위험이 있습니다. 솔루션: IDC Seamless HDFS NAVER는 이러한 문제를 해결하기 위해 IDC Seamless HDFS라는 새로운 아키텍처를 도입했습니다.\nLogical Single Namespace 다른 IDC에 위치한 DataNode들을 논리적으로 하나의 HDFS Namespace로 묶었습니다. 사용자 입장에서는 데이터가 어느 IDC에 있는지 신경 쓸 필요 없이, 마치 하나의 로컬 스토리지처럼 편리하게 사용할 수 있습니다. 한 IDC에 장애가 발생하더라도, 다른 IDC를 통해 서비스와 데이터 접근이 중단 없이 유지됩니다. Replica 배치 전략 (2+2 구조) 기본 복제본(Replica) 수를 4개로 설정하고, 각 IDC에 2개씩 강제로 배치되도록 BlockPlacementPolicy를 새로 개발했습니다. Rack 정보를 IDC 코드 + Rack 형태로 2 depth로 구성하여 NameNode가 물리적 위치를 인지하게 했습니다. Read Operation 최적화 클라이언트가 데이터를 읽을 때는 항상 자신이 위치한 IDC 내의 Replica(2개 중 하나)를 우선적으로 읽도록 유도합니다. 이를 통해 Read 작업 시에는 IDC 간 트래픽이 전혀 발생하지 않으며, 성능 저하도 없습니다. Write Operation 최적화 Sync Write: 데이터 안전성이 중요할 때 사용합니다. 양쪽 IDC에 동시에 쓰기를 수행하며, 즉시 동기화됩니다. Async Write: 성능이 중요할 때 사용합니다. 로컬 IDC에만 먼저 쓰고, 반대편 IDC로는 백그라운드에서 복제합니다. MLXP - GPU 효율화를 선도하는 대규모 MLOps 플랫폼 다음으로는 NAVER의 MLOps 플랫폼, MLXP에 대해 다룹니다. 수천 대의 GPU를 운영하는 NAVER가 어떻게 자원 효율성을 극대화하고, 대규모 학습/서빙 워크로드를 안정적으로 처리하는지 2가지 핵심 파트로 나누어 정리했습니다.\n전사 GPU 자원 통합 및 쿼터 시스템 구축 NAVER는 물리적 노드들을 각 조직에게 할당하는 Private Zone 방식으로 GPU 클러스터를 운영하고 있었습니다.\n특정 팀은 GPU가 남아서 놀고(유휴 자원), 특정 팀은 부족해서 대기하는 불균형이 발생했습니다. 또한, A100, H100 등 이기종 GPU가 섞이면서 자원 파편화가 심화되었습니다. 물리적 독점 구조를 타파하고, 모든 GPU를 하나의 공유 리소스 풀(Public Zone)로 통합하여 유휴 자원을 최소화했습니다. Priority Class: 단순히 합치는 것을 넘어, 체계적인 쿼터 시스템을 개발하여 적용했습니다. Provisioning Type: 워크로드 성격에 따라 Reserved(보장형), Spot(저가형/축출가능) 등으로 구분합니다. Category \u0026amp; Purpose: Serving(고가용성), Training(배치), Interactive(개발) 등 목적에 따라 우선순위를 세분화하여 스케줄링의 공정성을 확보했습니다. AI 워크로드 특성에 최적화된 네트워크 토폴로지 인지 스케줄링 Kubernetes의 기본 스케줄러는 AI 워크로드(Batch, Gang Scheduling) 에 최적화되어 있지 않아 성능 저하를 유발했습니다. 이를 해결하기 위해 Volcano 스케줄러를 기반으로 기능을 고도화했습니다.\nGang Scheduling: 학습에 필요한 모든 Pod이 준비되었을 때만(All-or-Nothing) 자원을 할당하여 교착 상태(Deadlock)를 방지했습니다. 분산 학습 시 노드 간 통신 속도가 전체 학습 속도를 좌우합니다. 하지만 기본 스케줄러는 물리적 네트워크 구조(InfiniBand Switch 연결 등)를 모른 채 Pod을 무작위로 배치하여 심각한 성능 저하를 초래했습니다.\nHyperNode CRD: 스케줄러가 물리적 네트워크 토폴로지를 인지하고, 고속 통신이 가능한 같은 스위치 하위 노드들에 Pod을 묶어서 배치하도록 HyperNode CRD를 구현했습니다. HyperNode: 네트워크 토폴로지 정보를 담은 CRD(Custom Resource Definition)를 정의하여 스케줄러가 이를 참조하게 했습니다 참관 후기 기술적 인사이트 이번 컨퍼런스에서 가장 인상 깊었던 부분은 IDC Seamless HDFS였습니다. 현재 HyperAccel의 개발 환경 역시 여러 클러스터로 분산되어 있어, 물리적 위치에 구애받지 않고 데이터를 공유할 수 있는 스토리지 인프라 구축이 중요한 과제입니다. NAVER의 2+2 Replica 배치 전략과 Read/Write 최적화 방식은 향후 우리 인프라 설계에 좋은 참고가 될 것입니다.\nMLXP 세션에서는 대규모 AI 클러스터 운영에 대한 실질적인 인사이트를 얻을 수 있었습니다. 특히, InfiniBand 등 네트워크 토폴로지를 인지한 스케줄링은 분산 학습 성능에 직접적인 영향을 미치는 핵심 요소입니다. 대규모 LLM을 실행하려면 자사 칩을 장착한 노드들이 고속 네트워크로 연결되어야 하므로, 토폴로지를 무시한 무작위 배치는 심각한 성능 저하를 초래합니다.\n결국, 좋은 AI 칩을 만드는 것만으로는 충분하지 않습니다. 스케줄러를 비롯한 SW 스택까지 함께 개발해야 자사 칩을 효율적으로 활용할 수 있다는 점을 다시 한번 확인할 수 있었습니다.\nReference IDC Seamless HDFS: IDC의 한계를 넘어 도달한 데이터 통합의 세계\nMLXP: GPU 효율화를 선도하는 대규모 MLOps 플랫폼\n추신 HyperAccel 채용 안내 HyperAccel은 LLM 추론을 위한 차세대 AI 칩을 개발하고 있습니다. FPGA 검증을 완료했으며, 곧 ASIC 칩과 서버 솔루션을 출시할 예정입니다. PyTorch 생태계와의 통합을 통해 개발자들이 쉽게 사용할 수 있는 솔루션을 만들어가고 있습니다.\n채용 사이트: https://hyperaccel.career.greetinghr.com/ko/guide\n혹시 관심이 있으시다면 언제든지 연락 주세요!\n","permalink":"https://hyper-accel.github.io/posts/naverdan2025-report/","summary":"\u003ch1 id=\"naver-dan-2025-참관기\"\u003eNAVER DAN 2025 참관기\u003c/h1\u003e\n\u003ch2 id=\"introduction\"\u003eIntroduction\u003c/h2\u003e\n\u003cp\u003e안녕하세요? HyperAccel ML팀 박신현입니다. 2025년 11월 6~7일 양일간 코엑스에서 열렸던 NAVER DAN 2025에 다녀와서 느낀 점을 공유하려고 합니다.\u003c/p\u003e\n\u003ch3 id=\"참관-동기\"\u003e참관 동기\u003c/h3\u003e\n\u003cp\u003e이번 컨퍼런스 참관의 주요 목적은 다음과 같습니다:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e확장 가능한 스토리지 인프라 인사이트 확보\u003c/strong\u003e: 컴퓨팅 클러스터 내 노드끼리 데이터를 공유하는 것을 넘어, 서로 다른 클러스터 간 데이터를 주고 받을 수 있는 스토리지 인프라 구축을 위한 기술적 인사이트를 얻고자 했습니다.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eAI 클러스터 자원의 효율적 활용 방식 학습\u003c/strong\u003e: HyperAccel에서는 AI 워크로드를 수행하기 위해 GPU, FPGA로 구성된 AI 클러스터를 운영하고 있습니다. 이러한 AI 클러스터 내 자원을 효율적으로 활용하기 위해, 다른 기업에서는 AI 클러스터를 어떻게 운영하고 있는지 학습하고자 했습니다.\u003c/p\u003e","title":"NAVER DAN 2025 참관기"},{"content":"SGLang의 철학 LLM이 도입된 이후, LLM은 문제 해결, 코드 작성, 질문 답변 등 다양한 분야에서 복잡한 작업을 해결하는 데 사용되어 왔습니다. 오늘날 LLM은 에이전트 능력을 확장하여 인간의 개입 없이 사용자가 요청한 작업을 완료하고 있습니다.\n이를 위해서는 skeleton of thought나 tree of thought와 같은 다양한 프롬프팅 기법이 필요합니다. 즉, 우리는 LLM이 특정 패턴을 따르도록 구조화하여 우리의 요구에 맞추고, 요구사항을 충족하도록 제어하고 안내하기 위한 프로그래밍 가능성을 필요로 합니다.\n저자들은 현재 솔루션에서 이 과정이 비효율적이었다고 주장하며, 그 이유는 다음과 같습니다:\nLLM이 non-deterministic 하기 때문에 LM(Language Model) 프로그램을 프로그래밍하기 어렵습니다. 명령을 실행하기 전에 LLM이 무엇을 출력할지 예측할 수 없습니다. 이는 LLM 출력의 가독성을 떨어뜨립니다. 중복된 계산과 메모리 사용으로 인해 LM 프로그램 실행이 비효율적입니다. 현재 솔루션 (논문 작성 당시 TGI, vLLM등을 의미)은 KV-cache를 재사용하는 효과적인 메커니즘이 부족합니다. 출력 형식이 고정되어 있거나 특정 문법 규칙을 따를 때, 현재 솔루션은 항상 토큰을 하나씩 출력하기 때문에 이를 효과적으로 활용할 수 없습니다. SGLang의 핵심 아이디어는 컴파일 가능한 새로운 python DSL(Python-embedded DSL)을 개발하여 AI 프로그램을 구조로 단순화하는 것입니다.\nSGLang DSL 논문에서 가져온 SGLang DSL 예제입니다.\n이미지에 대한 에세이를 평가하는 AI 프로그램을 만들고 싶다고 가정해봅시다.\n우리 시스템이 수행해야 할 작업은 다음과 같습니다:\n에세이와 이미지를 읽고, 에세이가 이미지에 관한 것인지 판단합니다. 그렇지 않으면 종료합니다. 에세이가 이미지와 일치하는 경우, 여러 차원(명확성, 문법, 가독성, 구조 등)에서 평가합니다. 이러한 평가를 기반으로 A+부터 D-까지의 점수를 부여합니다. 등급과 점수을 JSON 형식으로 출력합니다. 이 과정은 SGLang DSL로 다음과 같이 설명할 수 있습니다.\n@function def multi_dimensional_judge(s, path, essay): s += system(\u0026#34;Evaluate an essay about an image.\u0026#34;) s += user(image(path) + \u0026#34;Essay:\u0026#34; + essay) s += assistant(\u0026#34;Sure!\u0026#34;) # Return directly if it is not related s += user(\u0026#34;Is the essay related to the image?\u0026#34;) s += assistant(select(\u0026#34;related\u0026#34;, choices=[\u0026#34;yes\u0026#34;, \u0026#34;no\u0026#34;])) if s[\u0026#34;related\u0026#34;] == \u0026#34;no\u0026#34;: return # Judge multiple dimensions in parallel forks = s.fork(len(dimensions)) for f, dim in zip(forks, dimensions): f += user(\u0026#34;Evaluate based on the following dimension:\u0026#34; + dim + \u0026#34;. End your judgment with the word \u0026#39;END\u0026#39;\u0026#34;) f += assistant(\u0026#34;Judgment:\u0026#34; + gen(\u0026#34;judgment\u0026#34;, stop=\u0026#34;END\u0026#34;)) # Fetch the judgement results \u0026amp; merge the judgments judgment = \u0026#34;\\n\u0026#34;.join(f[\u0026#34;judgment\u0026#34;] for f in forks) # Generate a summary and a grade. Return in the JSON format. s += user(\u0026#34;Provide the judgment, summary, and a letter grade\u0026#34;) s += assistant(judgment + \u0026#34;In summary,\u0026#34; + gen(\u0026#34;summary\u0026#34;, stop=\u0026#34;.\u0026#34;) + \u0026#34;The grade of it is\u0026#34; + gen(\u0026#34;grade\u0026#34;)) schema = r\u0026#39;\\{\u0026#34;summary\u0026#34;: \u0026#34;[\\w\\d\\s]+\\.\u0026#34;, \u0026#34;grade\u0026#34;: \u0026#34;[ABCD][+-]?\u0026#34;\\}\u0026#39; s += user(\u0026#34;Return in the JSON format.\u0026#34;) # Runtime optimize for fast constrained decoding with regex s += assistant(gen(\u0026#34;output\u0026#34;, regex=schema)) state = multi_dimensional_judge.run(...) print(state[\u0026#34;output\u0026#34;]) # Runs an SGLang program SGLang를 사용하면 LM 프로그램을 간단히 작성할 수 있으며, 이전 솔루션보다 훨씬 짧습니다. 프로그램에서 fork, join, regex 등의 SGLang 의 primitive를 관찰할 수 있습니다.\nfork는 여러 차원에서 에세이를 판단하기 위한 여러 요청을 생성하며(에세이를 다른 기준을 가지고 판단), join은 모든 판단을 하나로 모읍니다. regex는 정규 표현식을 받아들이며, LLM의 출력을 특정 형식으로 제한할 수 있습니다. += 연산자는 문자열을 추가하는 데 사용됩니다.\n일부 표현들은 select, gen, extend SGLang이 asynchronous stream에서 명령을 실행되도록 지시합니다. 저자들은 이를 CUDA stream과 함께 CUDA kernel을 비동기적으로 실행하는 것으로 볼 수 있다고 언급합니다.\nRadixAttention SGLang는 RadixAttention이라는 KV cache 관리 기법을 도입합니다. 이 알고리즘은 radix tree를 사용하여 SGLang DSL 컨텍스트에서 KV cache를 효율적으로 관리합니다. (참고: radix tree는 parent 노드의 유일한 child 노드가 있을 경우 parent 노드와 병합되어 공간을 절약하는 트리입니다.) 알고리즘은 간단합니다. 프롬프트를 트리로 유지하며, 다른 프롬프트나 답변이 주어질 때 분기합니다. 실행 중인 요청이 사용하지 않을 때 LRU(Least Recently Used) 정책을 사용하여 leaf 노드를 제거합니다.\n여러 가능한 컨텍스트를 표현할 수 있는 radix tree의 예입니다. 이것은 자연스럽게 프롬프트의 여러 상태를 나타내며, 새로운 요청이 트리에 저장된 노드와 일치할 때 이전의 모든 KV cache를 재사용합니다.\n실행 과정\n트리가 비어 있습니다 \u0026ldquo;Hello\u0026rdquo; 요청이 수락되고, LLM이 \u0026ldquo;Hi\u0026quot;라고 답변합니다. 이 시퀀스는 새로운 노드 a로 저장됩니다. 새로운 요청(\u0026ldquo;Solve this problem\u0026rdquo;)이 도착하고, 대화가 일치합니다. KV cache를 안전하게 재사용할 수 있습니다. 또 다른 요청이 도착합니다. 요청은 \u0026ldquo;You are a helpful assistant\u0026rdquo;(시스템 프롬프트)까지 일치하지만, 사용자가 \u0026ldquo;hello\u0026quot;를 말하지 않았기 때문에 트리를 분기해야 합니다. 메모리 제한으로 인해 가장 최근에 사용되지 않은 노드 하나를 제거합니다. 새로운 요청이 도착하지만, 이전 시스템 프롬프트를 사용하지 않았습니다. 따라서 루트에서 분기합니다. 더 많은 쿼리가 들어오지만, 시스템 프롬프트가 없는 이전 요청과 동일한 프롬프트를 공유하므로 마지막 노드에서 분기합니다. \u0026ldquo;Hello\u0026quot;와 \u0026ldquo;Hi!\u0026rdquo; 이후에 새로운 메시지를 받으므로 새 노드를 추가합니다. 그러나 KV cache 공간이 부족하여 다른 가장 최근에 사용되지 않은 노드를 제거합니다. 이제 \u0026ldquo;Answer 3\u0026quot;까지 동일한 프롬프트를 공유하는 더 많은 요청이 있지만, 충분한 공간을 확보할 때까지 다른 노드를 제거해야 합니다. LRU 정책을 사용하여 제거합니다. 여기까지 읽으셨다면, 요청 순서가 최적이 아니어서 캐시 성능이 저하되면 어떻게 될까 궁금하실 수 있습니다. 저자들도 이를 고려했습니다. 성능을 최대화하기 위한 cache의 성능을 염두한 스케줄링 알고리즘 을 설계했습니다. 이 알고리즘은 radix-tree KV cache와 가장 잘 일치하는 접두사 길이로 요청을 정렬합니다(본질적으로 들어오는 요청을 처리하기 전에 캐시 적중률을 미리 예상합니다).\nCompressed FSM(Finite state machine) 을 사용한 constrained decoding 일부 LM 프로그램은 특정 형식(예제의 JSON과 같은)의 출력이 필요합니다. 프레젠테이션 슬라이드를 생성하는 LM 프로그램을 구축하는 경우, LLM 출력이 특정 형식을 따르기를 원합니다. SGLang는 FSM을 사용하여 이를 효율적으로 지원합니다. 디코딩 중에 올바른 LLM 출력이 때때로 항상 고정되어 있습니다. 예를 들어, LLM이 JSON을 출력하도록 프롬프트되면, 콜론, 쉼표 또는 중괄호를 언제 출력해야 하는지 항상 알고 있습니다—이는 SGLang DSL에서 regex로 표현할 수 있습니다. 예: 위 그림에서 \u0026ldquo;Harry\u0026quot;를 출력하기 전에 {\\n \u0026quot;name\u0026quot;: }를 출력해야 한다는 것을 항상 알고 있습니다. regex의 문제는 문자 및 문자열 수준에서 정의되어 LLM 토큰과 일치하지 않는다는 것입니다. 따라서 LLM이 작은 토큰을 하나씩 출력하도록 만들어야 합니다. 예: LLM이 {, \\n, \u0026quot;를 하나씩 디코딩하는데, 이는 매우 비효율적입니다.\n그러나 SGLang는 이러한 시퀀스를 re-tokenize 하여 변하지 않는 expression들의 리스트를 단일 expression 으로 \u0026ldquo;압축\u0026quot;할 수 있습니다. FSM은 어떤 압축된 토큰을 출력할지 추적하여, SGLang이 여러 expression을 한 번에 점프하고 LLM이 불피요한 토큰들을 추론하는 것을 방지하여 디코딩 과정을 가속화할 수 있게 합니다.\n위 예제에서 { \\n ____ \u0026quot;name\u0026quot;는 한 변에 표현할 수 있습니다. 해당 부분을 완전히 디코딩하는 것을 건너뛰고 단순히 붙여넣을 수 있어, LLM이 다음 출력으로 직접 진행할 수 있습니다.\n평가 SGLang는 추론 컨텍스트 인식 KV-cache 메커니즘으로 인해 에이전트 기반 AI 워크로드에서 매우 효과적이며, 이는 미래의 대부분의 추론 워크로드가 될 것으로 예상합니다.\n성능 향상은 Radix attention과 FSM(Finite state machine) 기반 디코딩에서 비롯됩니다. 논문 저자들에 따르면 최고 성능을 보인 DsPy RAG 파이프라인에서 캐시 적중률이 50-90% 사이였다고 합니다.\n개인적인 생각 우리는 agentic AI의 세계에 살고 있으며, agentic AI 의 사용 분야는 갈수록 확장되고 있습니다. AI 워크로드는 코딩, 슬라이드 생성, 음악 생성, 작업 도구 등 다양한 서비스에 통합되고 있습니다. 이러한 워크로드는 모델을 제어하기 위해 많은 시스템 프롬프트와 출력 제약이 필요합니다. 저는 개인적으로 SGLang가 radix attention과 정말 잘 맞기 때문에 이러한 경우에 매우 효율적일 것이라고 생각합니다. 또한 토큰을 생성할 필요가 없을 때 regex와 함께 FSM을 사용하여 시간과 에너지를 절약하는 아이디어를 좋아했습니다. SGLang이 항상 vLLM보다 나은 것은 아니지만, 에이전트 AI 워크로드에 훨씬 더 적합하지 않을까 생각합니다.\nReference SGLang: Efficient Execution of Structured Language Model Programs\n","permalink":"https://hyper-accel.github.io/posts/sglang-review/","summary":"\u003ch3 id=\"sglang의-철학\"\u003eSGLang의 철학\u003c/h3\u003e\n\u003cp\u003eLLM이 도입된 이후, LLM은 문제 해결, 코드 작성, 질문 답변 등 다양한 분야에서 복잡한 작업을 해결하는 데 사용되어 왔습니다. 오늘날 LLM은 에이전트 능력을 확장하여 인간의 개입 없이 사용자가 요청한 작업을 완료하고 있습니다.\u003c/p\u003e\n\u003cp\u003e이를 위해서는 skeleton of thought나 tree of thought와 같은 다양한 프롬프팅 기법이 필요합니다. 즉, 우리는 LLM이 특정 패턴을 따르도록 구조화하여 우리의 요구에 맞추고, 요구사항을 충족하도록 제어하고 안내하기 위한 프로그래밍 가능성을 필요로 합니다.\u003c/p\u003e\n\u003cp\u003e저자들은 현재 솔루션에서 이 과정이 비효율적이었다고 주장하며, 그 이유는 다음과 같습니다:\u003c/p\u003e","title":"SGLang paper review"},{"content":"Crafting compilers Compilers 이 포스팅 및 앞으로 쓰게 될 시리즈는 compiler가 무엇인지, 어떻게 만들어지는지, 그리고 직접 compiler를 만드는 방법을 설명하는 시리즈가 될 것입니다. Compiler는 (어느 정도는) 복잡한 프로그램으로, 사람이 작성한 high-level 프로그램(주로 English 형태로 존재하는)을 컴퓨터가 이해할 수 있는 binary 형식으로 변환합니다. Compiler engineering은 이러한 변환 과정을 어떻게 설계할 것인지 결정하는 일입니다.\n우선 \u0026ldquo;프로그램\u0026quot;이 무엇인지, 그리고 어떻게 생겼는지부터 생각해보겠습니다. 저는 프로그램을 하드웨어가 실행해야 하는 명령어들의 순서라고 정의할 수 있다고 생각합니다. 가장 낮은 수준에서는 프로그램은 단순히 \u0026lsquo;1\u0026rsquo;과 \u0026lsquo;0\u0026rsquo;으로 이루어진 명령어들의 시퀀스입니다. 프로그램이 표현되던 초기 형태 중 하나는 IBM 360 같은 컴퓨터에서 사용되던 assembly language였습니다. 과거의 프로그래머들은 하드웨어 명령어를 직접 작성하여, 우주 로켓의 궤적 계산이나 은행 계좌 관리 같은 아주 중요한 프로그램들을 만들었습니다. 이러한 명령어들은 컴퓨터가 각 단계에서 무엇을 해야 하는지를 직접 표현했으며, 프로그래머는 컴퓨터가 가진 모든 하드웨어 디테일을 이해해야 했습니다. Register usage, memory state, 기타 모든 하드웨어 세부 사항을 직접 계산해야 했고, 잘못 계산하면 프로그램이 오작동하거나 심각한 문제가 발생할 수 있었습니다.\n하지만 사람들이 컴퓨터에 더 많이 의존하게 되면서, 처리해야 할 작업의 복잡도와 범위는 급격히 증가했습니다. 프로그램의 크기도 커졌고, 이로 인해 전체를 assembly로 작성하는 것은 사실상 불가능해졌습니다. 이제 컴퓨터는 우리가 사용하는 거의 모든 것을 실행합니다. 출근길에 타는 엘리베이터부터 인간 능력을 뛰어넘는 AI 응용까지 모두 포함됩니다.\n프로그램이 너무 복잡해지자, 더 이상 하드웨어에 직접 명령어를 넣어 프로그래밍 하기는 매우 어려워졌습니다. 현대적인 응용 프로그램에서는 현실적으로 불가능합니다. 대신 컴퓨터 과학자들은 사람이 이해하기 쉬운 프로그래밍 언어를 만들었습니다. 이러한 프로그래밍 언어들은 필요한 추상화를 제공하여 사람이 프로그램을 작성할 수 있도록 돕는 일종의 유저 인터페이스(UI) 라고 볼 수 있습니다. 이 언어들은 사람이 사용하는 자연어에 더 가깝게 설계되었고, 인간이 사고하는 방식에 맞춰져 있습니다. 그 결과, 오늘날의 프로그래머는 레지스터 사용이나 메모리 상태 같은 컴퓨터 내부의 정확한 상태를 신경 쓰지 않고도 프로그램 작성에 집중할 수 있게 되었습니다. 현대 프로그래밍 언어는 점점 \u0026ldquo;인간 친화적인 언어\u0026quot;가 되어 가고 있습니다.\n컴파일러는 사람이 작성한 프로그램과 기계어 사이를 연결하는 다리입니다. 좋은 컴파일러는 프로그래머의 의도를 오류나 부작용 없이 정확히 전달하며, 프로그램이 가능한 한 빠르고 효율적으로 실행되도록 만듭니다. 앞서 말씀드렸듯이, 우리가 매일 사용하는 C/C++, Java, Python 같은 programming language는 모두 추상화(abstraction) 되어 있습니다. 이 언어들은 프로그래머에게 보여주고 싶지 않은 하드웨어 세부 사항을 숨깁니다. 즉, 컴파일러가 대신 처리해야 합니다. Register allocation, memory allocation, instruction selection 같은 작업이 이러한 추상화에 포함됩니다. 이것은 마치 영어–한국어 통역사가 원문의 표현을 가장 잘 전달할 수 있는 한국어 단어를 스스로 선택하는 것과 같습니다.\n지금까지 설명한 내용이 컴파일러가 하는 일입니다. 이제부터는 컴파일러가 실제로 이런 작업들을 어떻게 단계별로 수행하는지, 즉 사람이 작성한 프로그램을 어떻게 실행 가능한 기계어까지 변환하는지를 설명하겠습니다. 다소 이론적인 내용도 다루겠지만, 가능한 한 실제 구현 중심으로 설명하려 합니다. LLVM과 MLIR 같은 대표적인 컴파일러 인프라를 활용하여, 처음부터 \u0026ldquo;제대로 된\u0026rdquo; 프로그래밍 언어를 만들어보는 과정을 보여드리겠습니다.\n목차 (Table of contents) Chapter 1. Programming Language 1.1 프로그래밍 언어 만들기 (Building a Programming Language) 프로그래밍 언어란 무엇인가? 컴파일러(Compiled) vs 인터프리터(Interpreter) Managed vs. Unmanaged 함수형 프로그래밍 (Functional Programming) Hoya Language 소개 Chapter 2. Parsers Abstract Syntax Tree (AST) AST란 무엇인가 AST 최적화 Lexers, Parsers Parsing 알고리즘 Recursive-descent parsing Pratt parsing LR parsing Chapter 3. Intermediate Representations Intermediate Representation(IR)이란 무엇이며 왜 중요한가 SSA (Single Static Assignment) Block과 control flow Chapter 4. Optimizations Scalar optimizations Control-flow optimizations Vectorization Loop analysis Chapter 5. Instruction Selection 올바른 instruction 고르기 Register allocation Chapter 6. Compilers for Accelerators GPU compiler 구조 AI accelerator 전용 compiler 이번 글에서는 컴파일러의 전체적인 개념과 흐름을 먼저 살펴보았습니다. 다음 글부터는 본격적으로 프로그래밍 언어의 개념부터, 설계 및 구현하는 방법을 다루고자 합니다.\n","permalink":"https://hyper-accel.github.io/posts/crafting-compilers/","summary":"\u003ch1 id=\"crafting-compilers\"\u003eCrafting compilers\u003c/h1\u003e\n\u003ch2 id=\"compilers\"\u003eCompilers\u003c/h2\u003e\n\u003cp\u003e이 포스팅 및 앞으로 쓰게 될 시리즈는 compiler가 무엇인지, 어떻게 만들어지는지, 그리고 직접 compiler를 만드는 방법을 설명하는 시리즈가 될 것입니다. Compiler는 (어느 정도는) 복잡한 프로그램으로, 사람이 작성한 high-level 프로그램(주로 English 형태로 존재하는)을 컴퓨터가 이해할 수 있는 binary 형식으로 변환합니다. Compiler engineering은 이러한 변환 과정을 어떻게 설계할 것인지 결정하는 일입니다.\u003c/p\u003e\n\u003cp\u003e우선 \u0026ldquo;프로그램\u0026quot;이 무엇인지, 그리고 어떻게 생겼는지부터 생각해보겠습니다. 저는 프로그램을 하드웨어가 실행해야 하는 명령어들의 순서라고 정의할 수 있다고 생각합니다. 가장 낮은 수준에서는 프로그램은 단순히 \u0026lsquo;1\u0026rsquo;과 \u0026lsquo;0\u0026rsquo;으로 이루어진 명령어들의 시퀀스입니다. 프로그램이 표현되던 초기 형태 중 하나는 IBM 360 같은 컴퓨터에서 사용되던 assembly language였습니다. 과거의 프로그래머들은 하드웨어 명령어를 직접 작성하여, 우주 로켓의 궤적 계산이나 은행 계좌 관리 같은 아주 중요한 프로그램들을 만들었습니다. 이러한 명령어들은 컴퓨터가 각 단계에서 무엇을 해야 하는지를 직접 표현했으며, 프로그래머는 컴퓨터가 가진 모든 하드웨어 디테일을 이해해야 했습니다. Register usage, memory state, 기타 모든 하드웨어 세부 사항을 직접 계산해야 했고, 잘못 계산하면 프로그램이 오작동하거나 심각한 문제가 발생할 수 있었습니다.\u003c/p\u003e","title":"Crafting Compilers"},{"content":"PyTorch Conference 2025 참관기 Introduction 안녕하세요? HyperAccel ML팀 Lead 박민호입니다. 지난 10월 22일~23일에 샌프란시스코에서 열렸던 PyTorch Conference 2025에 다녀와서 보고 느낀 점을 공유하려고 합니다.\nHyperAccel 소개 저희 HyperAccel은 Large Language Model (LLM)을 효율적으로 추론하는 AI Chip을 설계하는 회사입니다. 현재 FPGA로 IP 검증을 완료했으며, ASIC 칩 및 서버는 내년에 출시 예정입니다. ASIC에서는 Inference를 위해 PyTorch를 지원하는 SDK를 제공할 예정이며, vLLM 및 Kubernetes 지원 계획입니다.\n참관 동기 이번 컨퍼런스 참관의 주요 목적은 다음과 같습니다:\nTorch Hardware Backend 구현 인사이트 확보: PyTorch의 하드웨어 백엔드 구현 방식과 최신 동향을 파악하여 우리 칩에 최적화된 백엔드를 개발하기 위한 기술적 인사이트를 얻고자 했습니다.\nPyTorch Foundation 멤버십 가입 희망: HyperAccel에서는 PyTorch 생태계에 기여하고 커뮤니티와 협력하기 위해 Foundation 멤버십 가입을 검토 중입니다. 이번 PyTorch Conference 2025에 참여하면서, Linux Foundation의 Membership Solutions 담당자인 Meredith Roach를 만나 PyTorch Membership 가입 관련 논의를 나누었습니다.\n다른 하드웨어 벤더들의 접근 방식 학습: Google TPU, AMD, Rebellions, Furiosa AI 등 다른 하드웨어 벤더들이 PyTorch, vLLM, SGLang 등에 어떻게 접근하고 통합하고 있는지 정보를 수집하고자 했습니다.\nPyTorch Conference 2025 주요 사항 Scalable 대규모 모델 학습과 추론을 위한 확장성 솔루션들이 주목받았습니다. 기존에는 대규모 분산 학습/추론을 위해 third-party SW를 사용해야 하는 경우가 많았습니다. (Megatron, DeepSpeed, Horovod, \u0026hellip;) 하지만 이번 PyTorch Conference에서는 PyTorch Organization에서 자체적으로 지원하는 분산 학습 프레임워크 및 통신 라이브러리, 추상화 개념을 소개했습니다.\nMonarch Monarch는 PyTorch를 위한 Distributed Programming Framework로써, 대규모 모델의 효율적 분산 학습과 추론을 지원하기 위해 설계되었습니다. API를 보았을 때, Ray의 Actor, Task 개념에 상당히 영향을 많이 받은 것으로 보입니다. 복잡한 병렬화 전략을 수동으로 구성할 필요 없이, 자동화된 분할 및 통신 최적화 기능을 제공합니다. 이를 통해 기존 분산 학습 프레임워크 대비 코드 복잡도와 통신 오버헤드를 크게 줄였습니다. DTensor: 여러 디바이스에 걸친 모델 병렬화를 단순화합니다. 복잡한 분산 설정 없이도 대규모 모델을 효율적으로 실행할 수 있게 해주는 추상화 레이어입니다. TorchComms PyTorch의 차세대 분산 통신을 지원하기 위한 새로운 API입니다. 기존 PyTorch Distributed의 c10d::Backend는 기술 부채가 많아 현대화 및 확장이 어려워 새로운 hardware 추가에 어려움이 있었습니다. 통신 계층을 PyTorch core와 분리하여, 새로운 collective communication이나 backend를 더 빠르고 독립적으로 구현할 수 있도록 하였습니다. 새로운 backend 구현이 용이하다는 점은 저희 HyperAccel에도 굉장히 중요한 일입니다. LLM Inference 시, Latency를 줄이기 위해서는 Tensor Parallelism을 구현하는 것이 필수적인데, 이 때 저희 Chip을 위한 통신 backend 구현이 필수적이고, 이를 TorchComms를 통해 독립적으로 구현할 수 있을 것으로 보입니다. Ray Python 분산 처리를 위한 컴퓨팅 프레임워크로, PyTorch와의 통합을 통해 대규모 ML 워크로드를 쉽게 확장할 수 있게 해줍니다. Python의 function은 Task로, class는 Actor로 간주되어 Ray Cluster내의 어느 곳에서든 실행할 수 있게 변환됩니다. Ray는 Distributed Compute Engine으로써, Container Orchestrator인 Kubernetes 위에서 동작하고, PyTorch 기반의 vLLM, SGLang, Megatron과 같은 Training\u0026amp;Inference Framework에서 제공되는 Workload를 효율적으로 분산 처리할 수 있게 도와줍니다. Even faster for advanced users 고급 사용자들을 위한 성능 최적화 도구들이 소개되었습니다.\nHelion PyTorch의 eDSL(Embedded Domain-Specific Language)로, 컴파일 타임 최적화를 통해 런타임 성능을 극대화합니다. 복잡한 연산 그래프를 더 효율적으로 실행할 수 있게 해줍니다. Transformer를 빠르게 실행하기 위해, 다양한 회사에서 엄청나게 많은 양의 Custom Kernels가 사용되고 있습니다. 하지만 새로운 하드웨어에서 Custom Kernel을 지원하기는 어려워, 이는 굉장히 빠르게 기술 부채가 될 수 있습니다. Triton 커널 작성 시 manual하게 해야 하는 작업을 자동화해주는 Higher Level DSL입니다. 실제 Helion DSL의 결과는 Triton Kernel이 되고, Triton Kernel의 Backend추가로 다양한 Hardware지원이 가능합니다. 다양한 Hardware를 agnostic하게 지원할 수 있는 필수적인 Abstraction Layer가 될 수 있을 것으로 보입니다. PyTorch User입장에서는 좀 더 효율성 높은 Kernel을 작성할 수 있는 수단이 될 수 있을 것 같습니다. CuTile GPU Architecture가 진화함에 따라, 다양한 기능들이 추가되기 시작했습니다. (Ex, TMA in Hopper, TensorCore from Turing Architecture) GPU Kernel PTX를 통해 구현을 하게되면, 하드웨어의 새로운 spec이 추가될 경우 기존 커널들은 그 기능을 지원하기 어려운 문제가 있습니다. 또한 PTX 레벨의 구현은 User가 직접 work를 block 단위로 나누고, 데이터를 tile로 나누어주어야 하고, 직접 thread에 매핑까지 해야 합니다. 이런 abstraction은 방대한 코드 작성을 불러일으킵니다. Tile IR의 경우, System이 work를 thread에 매핑하는 작성을 대신 수행해줍니다. 이런 Tile Level의 abstraction은 Triton-lang에서 소개되었으며, 위에서 소개드린 Helion에서도 Tile Level의 abstraction을 통해 DSL을 지원합니다. CUDA에서도 Tile Level의 DSL 및 IR을 지원하게 됨으로써, User와 System 사이의 적절한 abstraction layer를 설정하였습니다. Runs Everywhere PyTorch가 다양한 플랫폼과 디바이스에서 실행될 수 있도록 하는 프로젝트들이 발표되었습니다.\nPrivateUse1 and torch.accelerator torch.accelerator 통합된 accelerator 추상화 API로, 다양한 하드웨어 백엔드를 일관된 인터페이스로 사용할 수 있게 해줍니다. 기존에는 NVIDIA GPU만을 사용할 것이라는 가정으로 인해, PyTorch code에 torch.cuda.* 가 많이 사용되었습니다. 하지만 이런 코드는 Hardware 이식성을 떨어뜨리는 코드입니다. 이제 torch에서는 Device generic API인 torch.accelerator가 지원되어, hardware agnostic한 코드를 작성할 수 있도록 지원합니다. PrivateUse1 커스텀 하드웨어 백엔드를 위한 확장 가능한 인터페이스입니다. 우리와 같은 AI 칩 벤더들이 PyTorch를 자신의 하드웨어에 포팅할 수 있게 해주는 중요한 기능입니다. PyTorch의 지원을 위해 PyTorch main branch로 우리 backend가 포함되어야 할 필요 없이, Out-Of-Tree 방식인 plugin 형식으로 PyTorch 지원이 가능합니다. (Rebellions, Huawei Ascend 의 PyTorch 지원 방식) Executorch: 엣지 디바이스를 위한 경량화된 PyTorch 런타임으로, 모바일과 IoT 디바이스에서도 PyTorch 모델을 효율적으로 실행할 수 있게 해줍니다. LLM Inference Engine LLM 추론 엔진에 대한 세션이 많았고, 실제 산업계 적용 사례들이 공유되었습니다.\nvLLM: vLLM은 더욱 더 PyTorch와 서로 관여되고 있으며, vLLM은 PyTorch의 기능들을 향상시키는 데 큰 역할을 하고 있고, PyTorch의 새로운 feature들로 vLLM은 더욱 더 가속화되고 있습니다. vLLM은 LLM Inference Framework로서 새로운 Model 지원 및 Hardware를 지원할 수 있는 Hub로서 역할을 하고 있습니다. PyTorch Conference 2025에서는 기조연설 및 단독 세션에서 7개의 관련 발표가 있을 정도로 가장 주요한 프로젝트 중 하나였습니다. HyperAccel에서도 vLLM의 feature를 최대한 지원하는 것을 Software Group의 가장 큰 목표로 삼고 있습니다. SGLang SGLang도 vLLM과 같이 산업계에서 많이 사용되고 있는 LLM Inference Framework입니다. 특히 xAI Grok, AMD, TogetherAI 등에서 적극적으로 도입중인 프레임워크 입니다. 아직 GPU가 아닌 Hardware를 Backend로 붙일 수 있는 Plugin 기능이 지원되지 않았는데, 이번 Conference에서 Multi platform abstraction refactor를 통해 다양한 Hardware를 지원할 계획을 공유하였습니다. 산업계 적용 사례 Spotify가 vLLM과 Google TPU를 조합하여 대규모 음악 추천 시스템에 LLM을 적용한 사례가 발표되었습니다. 실제 프로덕션 환경에서의 성능 최적화와 운영 경험이 공유되어 매우 유용했습니다. 실제로 Prefill Heavy인 상황에서는 L4, A100 보다 TPU가 훨씬 Performance, Cost Efficiency 측면에서 훌륭했습니다. System Level LLM Inference 시스템 레벨에서의 LLM 추론 최적화에 대한 발표들이 있었습니다.\nllm-d llm-d는 Kubernetes-native distributed inference serving stack으로, 대규모 생성형 AI 모델을 효율적으로 서빙하기 위한 Production Ready 솔루션을 제공합니다. vLLM을 기본 모델 서버로, Inference Gateway를 요청 스케줄러 및 밸런서로, Kubernetes를 인프라 오케스트레이터로 통합하여 구성됩니다. 주요 기능: Intelligent Inference Scheduler: Envoy proxy 기반의 스마트 로드 밸런싱으로 P/D 분리, KV 캐시, SLA, 부하 인식 기반 라우팅을 제공합니다. Disaggregated Serving: Prefill과 Decode 단계를 독립적인 인스턴스로 분리하여 GPU 활용도를 최적화하고 TTFT(Time To First Token)와 TPOT(Time Per Output Token)를 개선합니다. Disaggregated Prefix Caching: KV 캐시를 호스트 메모리, 원격 스토리지, LMCache 등으로 Off-loading하는 Pluggable KV Cache 계층을 제공합니다. Variant Autoscaling: 트래픽과 하드웨어를 인식하는 오토스케일러로, Prefill, Decode, 지연 허용 요청을 위한 최적 인스턴스 조합을 계산합니다. 다양한 하드웨어 가속기(NVIDIA GPU, AMD GPU, Google TPU, Intel XPU)를 지원하며, 프로덕션 환경에서 검증된 Helm 차트와 가이드를 제공합니다. Dynamo Dynamo는 NVIDIA의 high-throughput, low-latency inference framework로, 멀티노드 분산 환경에서 생성형 AI 및 추론 모델을 서빙하기 위해 설계되었습니다. Inference engine agnostic으로 TRT-LLM, vLLM, SGLang 등을 지원하며, Rust와 Python으로 구현되어 성능과 확장성을 모두 고려했습니다. 주요 기능: Disaggregated Prefill \u0026amp; Decode Inference: Prefill과 Decode를 분리하여 GPU 처리량을 최대화하고 처리량과 지연시간의 균형을 맞춥니다. Dynamic GPU Scheduling: 실시간 수요에 기반한 성능 최적화를 제공합니다. LLM-aware Request Routing: KV 캐시 히트율이 가장 높은 워커로 요청을 라우팅하여 불필요한 KV 캐시 재계산을 제거합니다. Accelerated Data Transfer: NIXL(NVIDIA Inference Transfer Library)을 사용하여 추론 응답 시간을 단축합니다. KV Cache Offloading: HBM, DDR, NVMe 또는 원격 스토리지 등 여러 메모리 계층을 활용하여 시스템 처리량을 높이고 지연시간을 낮춥니다. 참관 후기 기술적 인사이트 이번 컨퍼런스에서 가장 인상 깊었던 부분은 PrivateUse1과 torch.accelerator API였습니다. 우리가 개발 중인 AI 칩에 PyTorch를 포팅하기 위해서는 이러한 확장 가능한 인터페이스가 필수적입니다. 특히 PrivateUse1을 통해 커스텀 하드웨어 백엔드를 구현하는 방법에 대한 세부 사항을 파악할 수 있어 매우 유용했습니다.\nvLLM 세션에서 특히 많은 영감을 얻었습니다. vLLM이 PyTorch 생태계와 어떻게 긴밀하게 통합되어 있는지, 그리고 새로운 하드웨어를 지원하기 위한 Hub로서의 역할을 어떻게 수행하고 있는지 확인할 수 있었습니다. 이를 통해 단순히 PyTorch 백엔드만 구현하는 것이 아니라 전체 소프트웨어 스택을 체계적으로 구성하는 것이 중요하다는 것을 깨달았습니다. 사용자들이 우리 칩을 쉽게 사용할 수 있도록 상위 레벨 추론 엔진(vLLM, SGLang 등)과의 통합뿐만 아니라, 시스템 레벨의 최적화까지 고려한 전체적인 SW 스택을 잘 구성하는 것이 핵심 과제입니다.\n커뮤니티와의 교류 PyTorch Foundation 관계자들과의 미팅을 통해 멤버십 가입 절차와 기여 방안에 대해 논의할 수 있었습니다. PyTorch Foundation에 가입하여 Torch 생태계에 함께 참여하는 것에 대해 긍정적으로 검토 중입니다. 또한 AMD, Rebellions, Furiosa AI 등 다른 하드웨어 벤더들의 기술력을 확인할 수 있었고 많은 영감을 받았습니다.\n향후 계획 컨퍼런스에서 얻은 인사이트를 바탕으로 다음과 같은 작업을 진행할 예정입니다:\nPrivateUse1 백엔드 구현: 우리 칩에 대한 PyTorch 백엔드를 PrivateUse1 인터페이스를 통해 구현 전체 SW 스택 구성: vLLM/SGLang 통합을 포함한 체계적인 소프트웨어 스택 구성 PyTorch Foundation 멤버십 검토: Torch 생태계 참여를 위한 공식 멤버십 가입 검토 오픈소스 기여: 우리의 하드웨어 백엔드 구현 경험을 커뮤니티에 공유 추신 HyperAccel 채용 안내 HyperAccel은 LLM 추론을 위한 차세대 AI 칩을 개발하고 있습니다. FPGA 검증을 완료했으며, 곧 ASIC 칩과 서버 솔루션을 출시할 예정입니다. PyTorch 생태계와의 통합을 통해 개발자들이 쉽게 사용할 수 있는 솔루션을 만들어가고 있습니다.\n채용 사이트 : https://hyperaccel.career.greetinghr.com/ko/guide\n혹시 관심이 있으시다면 언제든지 연락 주세요!\n","permalink":"https://hyper-accel.github.io/posts/pytorchcon2025-report/","summary":"\u003ch1 id=\"pytorch-conference-2025-참관기\"\u003ePyTorch Conference 2025 참관기\u003c/h1\u003e\n\u003ch2 id=\"introduction\"\u003eIntroduction\u003c/h2\u003e\n\u003cp\u003e안녕하세요? HyperAccel ML팀 Lead 박민호입니다. 지난 10월 22일~23일에 샌프란시스코에서 열렸던 PyTorch Conference 2025에 다녀와서 보고 느낀 점을 공유하려고 합니다.\u003c/p\u003e\n\u003ch3 id=\"hyperaccel-소개\"\u003eHyperAccel 소개\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"hyperaccel\" loading=\"lazy\" src=\"/posts/pytorchcon2025-report/hyperaccel.png\"\u003e\u003c/p\u003e\n\u003cp\u003e저희 \u003ca href=\"https://hyperaccel.ai/\"\u003eHyperAccel\u003c/a\u003e은 Large Language Model (LLM)을 효율적으로 추론하는 AI Chip을 설계하는 회사입니다. 현재 \u003ca href=\"https://docs.hyperaccel.ai/1.5.3/\"\u003eFPGA\u003c/a\u003e로 IP 검증을 완료했으며, ASIC 칩 및 서버는 내년에 출시 예정입니다. ASIC에서는 Inference를 위해 PyTorch를 지원하는 SDK를 제공할 예정이며, vLLM 및 Kubernetes 지원 계획입니다.\u003c/p\u003e\n\u003ch3 id=\"참관-동기\"\u003e참관 동기\u003c/h3\u003e\n\u003cp\u003e이번 컨퍼런스 참관의 주요 목적은 다음과 같습니다:\u003c/p\u003e","title":"Pytorchcon 2025 참관기"},{"content":"HyperAccel ","permalink":"https://hyper-accel.github.io/about/","summary":"\u003ch1 id=\"hyperaccel\"\u003eHyperAccel\u003c/h1\u003e","title":"About"}]