1. 요청 하나가 지나는 프로세스와 경계
LLM 서빙 프레임워크를 처음 열면 대개 스케줄러부터 찾는다. 하지만 스케줄러 코드를 아무리 읽어도 “이 함수는 누가 부르고, 저 큐에는 누가 넣는가"가 풀리지 않는다. Mini-SGLang 은 한 프로세스짜리 프로그램이 아니기 때 …
sgl-project/mini-sglang
을
커밋 9a91cfa 에 고정해 놓고 여덟 편에 걸쳐 읽습니다. 인용한 코드는 모두
그 커밋의 permalink 로 이어집니다.
HTTP 요청 하나가 답으로 돌아오기까지 지나는 프로세스 경계에서 시작해, Req/Batch 상태 장부, chunked prefill 예산, 페이지 할당, 접두사 재사용을 위한 radix cache 와 eviction, 두 스트림으로 CPU 스케줄링을 감추는 방법, 그리고 여러 TP rank 가 같은 결정에 도달하는 구조까지 따라갑니다.
각 편은 앞 편을 읽었다고 가정합니다. 1편부터 순서대로 읽는 편이 낫습니다.
LLM 서빙 프레임워크를 처음 열면 대개 스케줄러부터 찾는다. 하지만 스케줄러 코드를 아무리 읽어도 “이 함수는 누가 부르고, 저 큐에는 누가 넣는가"가 풀리지 않는다. Mini-SGLang 은 한 프로세스짜리 프로그램이 아니기 때 …
1편에서 스케줄러가 받은 것은 CPU 위의 1차원 int32 텐서였다. 그 토큰열이 답으로 자라는 동안, 시스템은 “이 요청이 어디까지 갔는가"를 어딘가에 적어 두어야 한다. 그 장부가 Req 다.
2편에서 요청 하나는 세 길이로 표현되는 장부가 됐다. 이제 질문은 하나다. 대기 중인 요청이 여럿일 때, 이번 스텝에 무엇을 얼마나 넣을 것인가. 답은 예산 두 개와 조건 다섯 개다. 그리고 예산을 넘는 프롬프트를 어떻게 처리하는지에 이 저장소의 깔 …
3편에서 요청 하나가 “자리를 잡았다"고 했다. 그 자리의 정체가 이 편의 주제다. KV cache 는 페이지 단위로 관리된다. 그런데 요청마다 하나씩 있는 page_table 을 열어 보면 페이지 번호가 아니라 토큰 하나하나의 위 …
4편에서 요청 하나가 자기 자리를 잡는 법을 봤다. 그런데 같은 시스템 프롬프트로 들어오는 요청 백 개가 각자 같은 계산을 반복하면 그 자리는 금방 동난다. 그래서 이미 계산한 접두사를 다시 쓴다. 다시 쓰기 시작하면 두 가지 질문이 새로 생긴다. 어 …
지금까지 다섯 편에 걸쳐 스케줄러가 하는 일을 봤다. 메시지를 받고, 예산을 계산하고, 트리를 걷고, 페이지를 잡고, 표를 채운다. 전부 CPU 일이다. 그동안 GPU 는 무엇을 하고 있는가. 아무것도 안 하고 있다면, 모델을 아무리 빨리 돌려도 그 …
6편 마지막에 _prepare_batch 의 일곱 줄을 열거하면서 마지막 두 줄을 남겨 뒀다. pad_batch 와 prepare_metadata 다. 이 편이 그 둘을 연다. 지금까지 세운 것은 전부 파이썬 객체였다. Req 의 길이 세 개, 슬롯 …
1편에서 스케줄러가 TP 크기만큼 뜬다는 것을 보고, 그 뒤 여섯 편은 하나의 스케줄러 안에서 일어나는 일을 읽었다. 이제 그 전부를 rank 수만큼 복제한다. 여기서 문제가 생긴다. 스케줄러는 매 스텝 결정을 내린다. 어떤 요청을 배치에 넣을지, 어 …