벤치마크와 프로파일링
벤치마크와 프로파일링
SGLang 서버가 어느 정도 성능을 내는지 측정하고 싶을 때, 그리고 그 성능 저하 지점이 정확히 어디인지 파헤치고 싶을 때 필요한 도구들을 한자리에 모아둔 페이지예요. 서버 스택의 어느 레벨을 보느냐에 따라 적합한 벤치마크 도구가 다르고, 프로파일링도 PyTorch Profiler부터 Nsight까지 선택지가 넓어요. 강사 목소리로 하나씩 짚어 드릴게요. 모든 명령어와 코드, 값은 원문 그대로 보존했어요.
벤치마크 (Benchmark)
SGLang은 스택의 서로 다른 레벨에서 동작하는 벤치마크 도구 네 가지를 제공해요. 아래 표는 이들의 핵심 차이를 정리한 거예요.
| 도구 | HTTP 서버 | 스케줄러 | 사용 사례 |
|---|---|---|---|
bench_serving |
예 (실행 중인 서버에 대한 비동기 HTTP 클라이언트) | 예 (서버를 통해 간접적으로) | 지연 메트릭(TTFT, TPOT, ITL)을 포함한 실제 온라인 서빙 벤치마크 |
bench_one_batch_server |
예 (실행 중인 서버에 HTTP 요청 전송) | 예 (서버를 통해 간접적으로) | HTTP와 스케줄러 오버헤드를 포함한 종단 간 단일 배치 지연 |
bench_offline_throughput |
아니오 | 예 (인프로세스에서 Engine 직접 사용) |
HTTP 오버헤드 없는 최대 처리량 측정 |
bench_one_batch |
아니오 | 아니오 (ModelRunner 직접 호출) |
단일 정적 배치의 커널 수준 지연 프로파일링 |
특별한 필요가 없다면 기본적으로 bench_serving을 사용하세요.
bench_serving 은 실행 중인 서버에 제어된 속도로, 구성 가능한 동시성으로 요청을 보내는 비동기 HTTP 부하 테스트 클라이언트예요. 첫 토큰까지의 시간(TTFT), 출력 토큰당 시간(TPOT), 토큰 간 지연(ITL), 처리량을 포함한 실제 온라인 서빙 메트릭을 측정해요. 정상 상태(steady-state) 성능을 측정하려면 num-prompts >= 5 * max-concurrency를 사용하세요. 먼저 sglang.launch_server로 서버를 띄우세요.
python3 -m sglang.bench_serving --backend sglang --max-concurrency 16 --num-prompts 80 --random-input-len 256 --random-output-len 32 --dataset-name random
bench_one_batch_server 는 단일 배치를 하나의 HTTP 요청으로 실행 중인 서버에 보내요. 배치가 하나뿐이라 서버가 정상 상태에 도달하지 못하고 메트릭이 편향될 수 있어요. 먼저 sglang.launch_server로 서버를 띄우세요.
python3 -m sglang.bench_one_batch_server --base-url http://127.0.0.1:30000 --model-path meta-llama/Meta-Llama-3.1-8B-Instruct --batch-size 32 --input-len 256 --output-len 32
--enable-multi-batch를 넘기고--batch-size를 서버의--max-running-requests의 배수로 설정하면 처리량 측정을 안정화할 수 있어요. 추가 요청은 스케줄러가 큐에 넣고 배치 단위로 승격시켜, 요청별 prefill과 첫 스텝의 과도기를 정상 상태 decode로 상쇄(amortize)해요. 이 플래그 아래에서는overall_throughput만이 권위 있는 값이에요.input_throughput,output_throughput,last_ttft, ITL은 분모에 배치 간 큐잉(cross-batch queueing)이 포함되므로 참고용으로만 봐야 해요.- 실제 프롬프트로 벤치마크할 때는
--disable-ignore-eos를 넘기세요. EOS를 지나서 강제로 decode하면 출력 분포가 횡설수설(gibberish) 쪽으로 치우칠 수 있어요. 그러면 요청이 일찍 끝나고 전체 실행의output_throughput/ITL에 배치가 줄어드는 꼬리(decaying-batch tail)가 포함돼요. 보고서에는 모든 요청이 여전히 decode 중인 구간(마지막 요청의 첫 토큰부터 첫 요청의 완료까지)만으로 측정된 정상 상태 컬럼이 추가돼요. 녹화된 트래픽은--dataset-name sharegpt또는--dataset-name custom --dataset-path <conversations.jsonl>로 재생하세요(녹화된 completion 길이는 무시되고--output-len이 공통max_new_tokens상한이 돼요). 요청별 파라미터가 있는 OpenAI 형식 트레이스는bench_serving을 사용하세요. --lora-name <name>을 넘기면 모든 프롬프트를 미리 로드된 LoRA 어댑터로 라우팅해요. 서버를--enable-lora --lora-paths <name>=<path>로 띄워야 해요.
bench_offline_throughput 은 인프로세스에서 Engine 객체를 직접 인스턴스화하고(HTTP 서버 없음) engine.generate()를 통해 모든 요청을 한 번에 제출해요. 엔진의 스케줄러가 배칭과 실행을 처리해요. 네트워크 오버헤드 없이 달성 가능한 최대 처리량을 측정해요.
python3 -m sglang.bench_offline_throughput --model-path meta-llama/Meta-Llama-3.1-8B-Instruct --num-prompts 10
bench_one_batch 는 가장 낮은 레벨의 도구예요. ModelRunner를 직접 인스턴스화하고 고정된 정적 배치에 대해 extend()/decode()를 호출하며, 스케줄러를 완전히 우회해요. prefill과 decode 단계를 분리해서 실행하므로 프로파일링은 쉬워지지만 메트릭은 비현실적이 돼요. 동적 배칭이 없어서 실제 서버가 처리할 수 있는 배치 크기에서는 메모리가 부족할 수 있어요(실서버는 prefill을 더 작은 배치로 나누기 때문). 개별 커널 성능을 프로파일링하기에 가장 적합해요.
python3 -m sglang.bench_one_batch --model-path meta-llama/Meta-Llama-3.1-8B-Instruct --batch-size 32 --input-len 256 --output-len 32
PyTorch Profiler로 프로파일링하기
Pytorch Profiler는 커널 실행 시간, 콜 스택, 커널 오버랩과 점유율(occupancy)을 검사하는 편리한 기본 도구예요.
sglang.bench_serving으로 서버 프로파일링하기
# set trace path
export SGLANG_TORCH_PROFILER_DIR=/root/sglang/profile_log
# start server
python -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct
# send profiling request from client
python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 10 --sharegpt-output-len 100 --profile
bench_serving --profile을 쓰면 출력 디렉터리는 클라이언트 쪽에서 --profile-output-dir 또는 SGLANG_TORCH_PROFILER_DIR(폴백: /tmp)로 선택한 뒤 /start_profile 요청에 담아 보내요. /start_profile을 직접 호출하면서 output_dir을 주지 않으면 서버는 자기 자신의 SGLANG_TORCH_PROFILER_DIR(폴백: /tmp)을 사용해요.
서버와 클라이언트 양쪽에 SGLANG_TORCH_PROFILER_DIR을 설정해 두면 트레이스가 어디에 쓰이는지 헷갈리지 않아서 여전히 권장해요.
자세한 내용은 Bench Serving Guide를 참고하세요.
PD 분리(Disaggregation) 모드에서 프로파일링하기
PD 분리 모드에서 프로파일링할 때는 torch profiler의 제약 때문에 prefill과 decode 워커를 따로따로 프로파일링해야 해요. bench_serving 명령은 이를 위한 전용 옵션을 제공해요.
Prefill 워커 프로파일링하기
# set trace path
export SGLANG_TORCH_PROFILER_DIR=/root/sglang/profile_log
# start prefill and decode servers (see PD disaggregation docs for setup)
python -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct --disaggregation-mode prefill
python -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct --disaggregation-mode decode --port 30001 --base-gpu-id 1
# start router
python -m sglang_router.launch_router --pd-disaggregation --prefill http://127.0.0.1:30000 --decode http://127.0.0.1:30001 --host 0.0.0.0 --port 8000
# send profiling request targeting prefill workers
python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 10 --sharegpt-output-len 100 --profile --pd-separated --profile-prefill-url http://127.0.0.1:30000
Decode 워커 프로파일링하기
# send profiling request targeting decode workers
python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 10 --sharegpt-output-len 100 --profile --pd-separated --profile-decode-url http://127.0.0.1:30001
중요 참고 사항
--profile-prefill-url과--profile-decode-url은 상호 배타적이에요 — 동시에 둘 다 프로파일링할 수 없어요.- 두 옵션 모두 다중 인스턴스 설정을 위해 여러 워커 URL을 지원해요.
# Profile multiple prefill workers
python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 10 --profile --pd-separated --profile-prefill-url http://127.0.0.1:30000 http://127.0.0.1:30002
# Profile multiple decode workers
python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 10 --profile --pd-separated --profile-decode-url http://127.0.0.1:30001 http://127.0.0.1:30003
- 서버를 시작하기 전에 모든 워커 노드에
SGLANG_TORCH_PROFILER_DIR이 설정돼 있는지 확인하세요. - PD 분리 설정에 대한 자세한 내용은 PD Disaggregation Guide를 참고하세요.
sglang.bench_offline_throughput으로 서버 프로파일링하기
export SGLANG_TORCH_PROFILER_DIR=/root/sglang/profile_log
# profile one batch with bench_one_batch.py
# batch size can be controlled with --batch argument
python3 -m sglang.bench_one_batch --model-path meta-llama/Llama-3.1-8B-Instruct --batch 32 --input-len 1024 --output-len 10 --profile
# profile multiple batches with bench_offline_throughput.py
python -m sglang.bench_offline_throughput --model-path meta-llama/Llama-3.1-8B-Instruct --dataset-name random --num-prompts 10 --profile --mem-frac=0.8
sglang.profiler로 서버 프로파일링하기
서버가 실행 중일 때(예: decode 요청을 처리하는 동안) 프로파일 요청을 서버에 보내 즉시 라이브 프로파일링을 시작할 수 있어요.
이건 python3 -m sglang.profiler 실행으로 할 수 있어요. 예를 들어:
# Terminal 1: Send a generation request
python3 -m sglang.test.send_one
# Terminal 2: Before the above request finishes, quickly launch the following command in a separate terminal.
# It will generate a profile of the above request for several decoding batches.
python3 -m sglang.profiler
위 작업을 하나의 명령으로 합칠 수도 있어요.
python3 -m sglang.test.send_one --profile
HTTP API 엔드포인트로 서버 프로파일링하기
SGLang은 실행 중인 서버에서 프로파일링을 제어하는 HTTP API 엔드포인트를 제공해요. 프로파일링을 프로그램 방식으로 시작·중지할 수 있어서 특정 워크로드 패턴을 캡처할 때 유용해요.
/start_profile 엔드포인트 사용하기
/start_profile 엔드포인트는 서버에서 프로파일링을 시작해요. 다음 파라미터로 언제 시작하고 얼마나 오래 실행할지 제어할 수 있어요.
기본 사용법:
# Start profiling immediately for 10 steps
curl -X POST http://127.0.0.1:30000/start_profile \
-H "Content-Type: application/json" \
-d '{
"num_steps": 10
}'
파라미터:
output_dir(선택): 프로파일 트레이스가 저장될 디렉터리. 지정하지 않으면SGLANG_TORCH_PROFILER_DIR환경 변수 또는 기본값/tmp를 사용해요.num_steps(선택): 프로파일링할 스텝 수. 지정하지 않으면/stop_profile로 수동 중지할 때까지 계속돼요.start_step(선택): 프로파일링을 시작할 스텝 번호(포함). 워밍업 반복을 건너뛰는 데 유용해요.activities(선택): 프로파일링할 활동 목록(예:["CPU", "GPU"]). 기본값은["CPU", "GPU"]예요.merge_profiles(선택): 분산 트레이스 병합 여부. 기본값은false예요.detailed_annotations(선택): 상세 분석을 위해 반복별 요청 및 KV 길이 집계를 트레이스의step[...]마커에 접어 넣을지 여부. 기본값은false예요. 아래 상세 어노테이션을 참고하세요.
스텝 범위에 대한 참고: 프로파일링은 start_step(포함)에서 시작해 num_steps 반복 동안 계속돼요. 예를 들어 start_step=3, num_steps=10이면 스텝 3, 4, 5, 6, 7, 8, 9, 10, 11, 12를 캡처해요(스텝 3부터 시작해 총 10스텝).
start_step을 사용한 고급 사용법:
# Wait 5 steps (warmup), then profile for 10 steps
curl -X POST http://127.0.0.1:30000/start_profile \
-H "Content-Type: application/json" \
-d '{
"output_dir": "/tmp/profiles",
"start_step": 5,
"num_steps": 10,
"activities": ["CPU", "GPU"]
}'
연속 프로파일링(수동 중지):
# Start profiling without num_steps - must manually stop with /stop_profile
curl -X POST http://127.0.0.1:30000/start_profile
상세 어노테이션 (Detailed annotations)
detailed_annotations를 true로 설정하면 SGLang의 기존 per-forward step[...] 스팬에 반복별(per-iteration) 집계를 접어 넣어요. 프로파일링이 활성화된 동안 실행되는 모든 실행 스텝에 대해 SGLang은 GPU 스트림의 해당 스텝 마커를 그 스텝의 요청 및 KV 길이 분포로 보강해서, 요청별 상세 없이도 트레이스에서 직접 계산·메모리 경계를 재구성할 수 있게 해 줘요.
네 가지 요청별 집계가 모두 추가되며, 각각 c_(context, prefill)와 g_(generation, decode)라는 단계별 접두사가 붙어요. 각 step[...] 레이블이 roofline 분석에 자족적이도록 단계별 sq는 항상 발행돼요(기본 레이블의 bs(decode)나 toks(prefill)와 중복되더라도요).
sq: 총 쿼리 토큰 수 (Σ N_Q)sqsq: 요청별 쿼리 토큰 제곱의 합 (Σ N_Q²)sqsk: 요청별 쿼리·KV 토큰 곱의 합 (Σ N_Q·N_KV)sk: 총 KV 토큰 수 (Σ N_KV)
순수 prefill(EXTEND)이나 decode(DECODE) forward는 단일 그룹을 발행하고, 혼합 forward는 c=/g= 요청 수와 함께 둘 다 발행해요. 예시 레이블:
step[EXTEND bs=1 toks=1025 c_sq=1025 c_sqsq=1050625 c_sqsk=1050625 c_sk=1025]
step[DECODE bs=64 g_sq=64 g_sqsq=64 g_sqsk=100032 g_sk=100032]
step[MIXED bs=66 c=2 g=64 c_sq=2048 c_sk=2048 c_sqsq=2097152 c_sqsk=2097152 g_sq=64 g_sk=65600 g_sqsq=64 g_sqsk=65600]
스펙큘레이티브 디코딩(EAGLE/MTP)에서는 각 요청이 스텝마다 여러 쿼리 토큰을 만들기 때문에 sq가 더 이상 bs와 같지 않아요. draft-decode와 target-verify(TARGET_VERIFY) 스텝 모두 generation 그룹으로 발행돼요. 예를 들어, 2개 요청(seq_lens=[10, 20])에 걸친 3개 draft 토큰이 있는 verify 스텝:
step[TARGET_VERIFY bs=2 g_sq=6 g_sqsq=18 g_sqsk=90 g_sk=30]
# Profile 10 steps with detailed annotations enabled
curl -X POST http://127.0.0.1:30000/start_profile \
-H "Content-Type: application/json" \
-d '{
"output_dir": "/tmp/profiles",
"num_steps": 10,
"activities": ["CPU", "GPU"],
"detailed_annotations": true
}'
어노테이션은 detailed_annotations가 켜진 상태에서 프로파일링이 활성화될 때만 나타나므로 일반 서빙 경로에는 오버헤드를 더하지 않아요. 동작은 eager와 CUDA graph 모드에서 동일해요. 트레이스를 볼 때(아래 트레이스 보기 참고) 보강된 step[...] 마커가 각 스텝의 커널과 함께 GPU 스트림에 나타나요.
/stop_profile 엔드포인트 사용하기
/stop_profile 엔드포인트는 진행 중인 프로파일링 세션을 중지하고 트레이스 파일을 저장해요.
# Stop profiling and save traces
curl -X POST http://127.0.0.1:30000/stop_profile
num_steps를 지정하지 않고 프로파일링을 시작했을 때만 이게 필요해요. num_steps를 지정하면 그만큼 스텝 후 자동으로 중지돼요.
예시 워크플로
# Terminal 1: Start the server
export SGLANG_TORCH_PROFILER_DIR=/tmp/profiles
python -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct
# Terminal 2: Start continuous profiling
curl -X POST http://127.0.0.1:30000/start_profile \
-H "Content-Type: application/json" \
-d '{
"start_step": 3
}'
# Terminal 3: Send requests to generate load
python -m sglang.bench_serving --backend sglang --num-prompts 100
# Terminal 2: Stop profiling when done
curl -X POST http://127.0.0.1:30000/stop_profile
분산 트레이스를 위한 Profiler Trace Merger
SGLang은 이제 여러 병렬 유형(TP, DP, PP, EP)이 있는 분산 설정의 프로파일링 트레이스를 자동 병합하는 것을 지원해요. 이 기능은 분산 실행 전반의 성능을 분석할 때 특히 유용해요.
멀티노드 프로파일링과 공유 스토리지 고려 사항
단일 노드 프로파일러 출력 병합은 완전히 지원돼요. 여러 노드에 걸친 분산 환경에서 프로파일링할 때는 트레이스 파일 병합이 가능하도록 공유 스토리지(예: NFS, Lustre)가 모든 노드에서 출력 디렉터리에 접근 가능해야 해요.
노드 간 접근 가능한 공유 스토리지가 없다면, 현재로서는 프로파일링 중 트레이스 파일의 자동 병합이 직접 지원되지 않아요.
HTTP API 사용법
# Start profiling with automatic trace merging enabled
curl -X POST <BASE_URL>/start_profile \
-H "Content-Type: application/json" \
-d '{
"output_dir": "/tmp/profiles", # where to store profile traces
"num_steps": 10,
"activities": ["CPU", "GPU"],
"merge_profiles": true # optional argument to merge profile traces (default=False)
}'
커맨드라인 사용법
# Start profiling with merge enabled
python -m sglang.profiler \
--num-steps 10 \
--cpu \
--gpu \
--output-dir /tmp/profiles \
--merge-profiles # optional argument to merge profile traces (default=False)
출력 파일
프로파일 병합기는 다음을 생성해요.
- 개별 랭크 트레이스 파일:
{profile_id}-TP-{tp}-DP-{dp}-PP-{pp}-EP-{ep}.trace.json.gz - 병합된 트레이스 파일:
merged-{profile_id}.trace.json.gz
CUDA graph 캡처 단계 프로파일링하기
위 도구들은 정상 상태 런타임(prefill / decode)을 프로파일링해요. 서버 시작 시 한 번 실행되는 CUDA graph 캡처 단계를 프로파일링하려면 서버를 --enable-profile-cuda-graph로 띄우세요. decode CUDA-graph 캡처에 PyTorch Profiler 패스를 실행해서 느리거나 메모리를 많이 쓰는 graph 캡처를 진단하는 데 유용해요.
--enable-profile-cuda-graph(서버 인자)는 캡처 프로파일러를 구성하고 항상 커널별 CPU/CUDA 시간 요약 테이블과 CUDA 메모리 스냅샷을 발행해요. Chrome 트레이스를 디스크에 영속화하는 것은 두 환경 변수 중 하나로 선택(opt-in)해요(둘 다 --enable-profile-cuda-graph도 설정돼 있지 않으면 no-op예요).
SGLANG_ENABLE_CUDA_GRAPH_CAPTURE_TRACE=1— 전체 캡처 패스에 대해 텐서 병렬 랭크당 병합된 단일 트레이스 하나를cuda_graph_capture-{runner}-TP-{tp_rank}.json.gz로 써요.SGLANG_GRAPH_BATCH_CAPTURE=1— 랭크당 캡처된 배치 크기마다 트레이스 하나를{runner}_bs_{bs}_rank{tp_rank}.json.gz로 써요. 프로파일러는wait=2, warmup=0, active=1스케줄(각 캡처 전의 두 dummy 실행은 건너뜀)로record_shapes,with_stack,with_flops,profile_memory를 켠 채 실행되어, 셰이프별 커널 정체성, 입력 셰이프, FLOPs, 메모리를 제공해요.
두 환경 변수를 모두 설정하면 SGLANG_ENABLE_CUDA_GRAPH_CAPTURE_TRACE(단일 병합 트레이스)가 우선해요.
# set trace path
export SGLANG_TORCH_PROFILER_DIR=/root/sglang/profile_log
# opt in to per-batch-size capture traces (or set
# SGLANG_ENABLE_CUDA_GRAPH_CAPTURE_TRACE=1 for a single combined trace per rank)
export SGLANG_GRAPH_BATCH_CAPTURE=1
# launch the server with CUDA graph capture profiling enabled
python -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct --enable-profile-cuda-graph
동작과 출력:
- 모든 트레이스는
$SGLANG_TORCH_PROFILER_DIR/graph_capture_profile/에 쓰여요(변수가 설정되지 않았으면 기본값/tmp/graph_capture_profile/). 파일은 러너 클래스와 TP 랭크로 네임스페이스가 나뉘어서 동시 캡처 패스(예: EAGLE target/draft/draft-extend)와 랭크가 충돌하지 않아요. - CUDA 메모리 스냅샷(
cuda_graph_runner_memory_usage.pickle)과 커널별 CPU/CUDA 시간 요약 테이블은 캡처 단계에 항상 발행돼요(위 환경 변수와 무관). - decode CUDA-graph 러너만 프로파일링돼요.
캡처 트레이스는 다른 PyTorch Profiler 트레이스와 같은 방식으로 봐요(아래 트레이스 보기 참고).
가능한 PyTorch 버그
어떤 경우(예: qwen 2.5 VL 사용)에 다음 에러를 만나게 될 수 있어요.
RuntimeError: !stack.empty() INTERNAL ASSERT FAILED at "/pytorch/torch/csrc/autograd/profiler_python.cpp":983, please report a bug to PyTorch. Python replay stack is empty.
이것은 Bug: vLLM Profiler와 Bug: torch.profiler.profile에 보고된 PyTorch 버그일 가능성이 높아요. 해결 방법으로 다음과 같이 환경 변수로 with_stack을 비활성화할 수 있어요.
export SGLANG_PROFILE_WITH_STACK=False
python -m sglang.bench_offline_throughput --model-path meta-llama/Llama-3.1-8B-Instruct --dataset-name random --num-prompts 10 --profile --mem-frac=0.8
트레이스 보기 (View traces)
트레이스 파일은 다음에서 로드해 시각화할 수 있어요.
- https://ui.perfetto.dev/ (모든 브라우저)
- chrome://tracing (Chrome 브라우저 전용)
브라우저가 파일 크기가 커서 트레이스를 열지 못하면, 클라이언트가 프롬프트 수와 프롬프트 출력 길이를 제어해 작은 트레이스 파일(<100MB)을 만들 수 있어요. 예를 들어 서버를 프로파일링할 때,
python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 2 --sharegpt-output-len 100 --profile
이 명령은 --num-prompts 인자로 프롬프트 수를 2로, --sharegpt-output-len 인자로 출력 시퀀스 길이를 100으로 제한해서, 브라우저가 부드럽게 열 수 있는 작은 트레이스 파일을 만들 수 있어요.
추가로, 트레이스의 cuda 커널을 통해 SGLang Python 소스 코드 위치를 파악하고 싶다면 서비스를 시작할 때 CUDA Graph를 비활성화해야 해요. 서비스를 시작하는 명령에 --disable-cuda-graph 파라미터를 쓰면 돼요.
Nsight로 프로파일링하기
Nsight systems는 레지스터·공유 메모리 사용량, 주석이 달린 코드 영역, 저수준 CUDA API와 이벤트 등 더 많은 프로파일링 정보를 드러내는 고급 도구예요.
-
전제 조건:
apt로 설치하거나 NVIDIA Docker container 또는 SGLang Docker container 안에서 실행하세요.
# install nsys
# https://docs.nvidia.com/nsight-systems/InstallationGuide/index.html
apt update
apt install -y --no-install-recommends gnupg
echo "deb http://developer.download.nvidia.com/devtools/repos/ubuntu$(source /etc/lsb-release; echo "$DISTRIB_RELEASE" | tr -d .)/$(dpkg --print-architecture) /" | tee /etc/apt/sources.list.d/nvidia-devtools.list
apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub
apt update
apt install nsight-systems-cli
- 단일 배치를 프로파일링하려면,
nsys profile --trace-fork-before-exec=true --cuda-graph-trace=node python3 -m sglang.bench_one_batch --model meta-llama/Meta-Llama-3-8B --batch-size 64 --input-len 512
- 서버를 프로파일링하려면, 예를 들어
# launch the server, set the delay and duration times according to needs
# after the duration time has been used up, server will be killed by nsys
nsys profile --trace-fork-before-exec=true --cuda-graph-trace=node -o sglang.out --delay 60 --duration 70 python3 -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct --disable-radix-cache
# client
python3 -m sglang.bench_serving --backend sglang --num-prompts 1000 --dataset-name random --random-input 1024 --random-output 512
실전에서는 --duration 인자를 큰 값으로 설정하는 걸 권장해요. 서버가 프로파일링을 중지하길 원할 때는, 먼저
nsys sessions list
를 실행해 profile-XXXXX 형태의 세션 id를 얻은 다음,
nsys stop --session=profile-XXXXX
를 실행해 프로파일러를 수동으로 종료하고 nsys-rep 파일을 즉시 생성하면 돼요.
- NVTX로 코드 영역에 주석을 달아 실행 시간을 보려면,
# install nvtx
pip install nvtx
# code snippets
import nvtx
with nvtx.annotate("description", color="color"):
# some critical code
Nsight Systems로 레이어별 NVTX 프로파일링 (Layer-wise NVTX)
SGLang은 CUDA Profiler와 결합해 Nsight Systems에서 상세한 레이어별 프로파일링을 할 수 있게 해 주는 내장 레이어별 NVTX 어노테이션을 제공해요. 레이어 수준에서 성능 병목을 찾을 때 특히 유용해요.
Nsight Systems와 /start_profile에서 --enable-layerwise-nvtx-marker 사용하기
--enable-layerwise-nvtx-marker 플래그는 모델의 모든 레이어에 NVTX 마커를 자동으로 추가해요. Nsight Systems 프로파일링과 결합하면 상세한 레이어별 성능을 볼 수 있어 강력해요.
방법 1: CUDA_PROFILER와 함께 /start_profile 사용 (프로그램 방식 제어)
이 방법은 Nsight Systems가 실행되는 동안 HTTP API로 프로파일링 시작/중지 시점을 정확히 제어할 수 있게 해 줘요.
- Nsight Systems 아래에서 레이어별 NVTX를 켠 채 서버를 띄우세요.
# Terminal 1: Start server with nsys and capture-range option
nsys profile --trace-fork-before-exec=true \
--cuda-graph-trace=node \
--capture-range=cudaProfilerApi \
--capture-range-end=stop \
-o layerwise_profile \
python -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-8B-Instruct \
--enable-layerwise-nvtx-marker \
--disable-cuda-graph
참고: CUDA graph가 캡처한 커널 실행에는 NVTX 마커가 발행되지 않아요. 모든 레이어별 NVTX 마커가 트레이스에 나타나게 하려면 --disable-cuda-graph를 사용하세요.
- 다른 터미널에서
CUDA_PROFILER활동으로/start_profile을 통해 프로파일링을 제어하세요.
# Terminal 2: Wait for server to be ready, then start CUDA profiling
# Wait 3 steps for warmup, then profile for 10 steps
curl -X POST http://127.0.0.1:30000/start_profile \
-H "Content-Type: application/json" \
-d '{
"start_step": 3,
"num_steps": 10,
"activities": ["CUDA_PROFILER"]
}'
- 부하를 만들 요청을 보내세요.
# Terminal 3: Generate workload
python -m sglang.bench_serving --backend sglang --num-prompts 100
- 프로파일링은 10스텝 후(즉
num_steps: 10덕분에) 자동으로 멈춰요.num_steps를 지정하지 않았다면 수동으로 멈춰야 해요.
# Terminal 2: Only needed if num_steps was not specified
curl -X POST http://127.0.0.1:30000/stop_profile
--capture-range=cudaProfilerApi 옵션은 Nsight Systems가 cudaProfilerStart()와 cudaProfilerStop() 호출(/start_profile과 /stop_profile이 트리거) 사이의 데이터만 캡처하도록 지시해서 오버헤드와 파일 크기를 줄여줘요. start_step 파라미터는 첫 3스텝을 건너뛰어 워밍업 오버헤드를 캡처하지 않게 해 줘요.
방법 2: /start_profile API 없이 더 간단한 접근
프로파일링 시작/중지를 세밀하게 제어할 필요가 없는 단순한 사용 사례라면, 전체 워크로드를 캡처하는 Nsight Systems로 프로파일링할 수 있어요.
# Terminal 1: Start server with layerwise NVTX
# Note: --disable-cuda-graph ensures all NVTX markers are emitted
python -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-8B-Instruct \
--enable-layerwise-nvtx-marker \
--disable-cuda-graph
# Terminal 2: Profile the benchmarking client
nsys profile --trace-fork-before-exec=true \
--cuda-graph-trace=node \
-o layerwise_profile \
python -m sglang.bench_serving --backend sglang --num-prompts 10
이 접근은 모든 서버 상호작용을 포함해 클라이언트 실행 전체를 프로파일링해요. 레이어별 NVTX 마커가 Nsight Systems 타임라인에 보일 거예요.
프로파일링 결과 보기:
생성된 .qdrep 파일을 Nsight Systems로 열어요.
nsys-ui layerwise_profile.qdrep
Nsight Systems GUI에서 다음을 볼 수 있어요.
- NVTX 범위: 각 레이어가 마커 메타데이터의 상세 정보와 함께 타임라인의 레이블이 붙은 범위로 나타나요.
- CUDA 커널: 모든 GPU 커널이 레이어 어노테이션과 함께 표시돼요.
- 레이어 계층: 전체 모듈 경로(예:
meta-llama/Meta-Llama-3.1-8B-Instruct.model.layers.0.self_attn.qkv_proj)가 특정 레이어를 식별하는 데 도움을 줘요. 접두사는--model-path의 전체 모델 경로를 사용해요. - 텐서 셰이프: 입력/출력 차원과 파라미터 셰이프가 NVTX 마커 데이터에 포함돼요.
레이어별 NVTX 프로파일링의 장점:
- 세분화된 가시성: 정확히 어느 레이어가 가장 시간을 많이 쓰는지 볼 수 있어요.
- 메모리 추적: 메모리 할당이 큰 레이어를 식별해요.
- 병목 식별: 비효율적인 연산을 빠르게 찾아요.
- 통신 오버헤드: 멀티 GPU 설정에서 레이어별 통신 비용을 확인해요.
- 개발 디버깅: 모델 아키텍처 변경이 기대한 성능 영향을 갖는지 검증해요.
기타 팁
- config.json 파일만 제공하고 dummy 가중치로 모델을 벤치마크할 수 있어요. 훈련 없이 모델 변형을 빠르게 테스트할 수 있어요. 그러려면 위 명령에
--load-format dummy를 추가하고 체크포인트 폴더에 올바른config.json만 있으면 돼요. --json-model-override-args를 사용해 수정된 설정(예: 레이어가 적은)으로 모델을 벤치마크할 수 있어요. 예를 들어 2개의 레이어와 2개의 kv 헤드만 있는 모델을 벤치마크할 수 있어요.
python -m sglang.bench_one_batch --model-path meta-llama/Meta-Llama-3.1-8B-Instruct --batch 32 --input-len 256 --output-len 32 --load-format dummy --json-model-override-args '{"num_hidden_layers": 1, "num_key_value_heads": 1}'
- PyTorch Profiler처럼 모든 CUDA 커널의 파이썬 콜 스택을 보려면
--python-backtrace=cuda를 사용할 수 있어요. (주의: CUDA 이벤트 기반 타이밍에서 커널 실행 시간이 부정확하게 길어질 수 있어요.) - 더 많은 인자는 Nsight Systems User Guide를 참고하세요.
더 알아보기 (Learn more)
- Bench Serving Guide —
bench_serving을 자세히 쓰는 방법 - 하이퍼파라미터 튜닝 — 처리량을 높이기 위한 파라미터 조정