AI Profiling全流程使用指南

更新时间:2025-03-28 03:47:27

LLM的普及推动了对AI训练与推理的精细化性能检测与调优需求,众多在GPU节点上运行的业务,期望对GPU容器进行在线性能分析。在Kubernetes容器场景中,AI Profiling作为基于eBPF和动态进程注入的无侵入式性能分析工具,支持对运行GPU任务的容器进程进行在线检测,涵盖Python进程、CPU调用、系统调用、CUDA库和CUDA核函数五个方面的数据采集能力。通过对采集数据进行分析,可以更好地定位容器应用运行的性能瓶颈并掌握对资源的利用程度,进而对应用进行优化。而对线上业务来说,可动态挂卸载的Profiling工具可以实时地对在线业务进行较为细致的分析,且无需对业务代码进行修改。本文将为您介绍AI Profiling全流程使用方式。

准备工作

  • 当前版本的AI ProfilingPython Profiling能力依赖于Python解释器的USDT功能。若要启用Python Profiling,请在业务容器中使用以下命令确认业务Pod是否已开启USDT。

    python -c "import sysconfig; print(sysconfig.get_config_var('WITH_DTRACE'))"

    如果输出为1,则表示可以启用Python Profiling,若为0,则无法开启。

    说明

    Profiling任务目前仅支持在ACK集群中ECS及灵骏节点上运行。

  • 如果希望使用本功能,请提交工单联系容器服务团队获取最新版本的kubectl-plugin下载链接及最新版本的Profiling镜像地址。

操作步骤

步骤一:部署kubectl插件

AI Profiling的部署采用kubectl-plugin的方式,具体步骤如下:

  1. 执行以下命令安装该插件,本文以Linux_amd64为例。

    wget https://xxxxxxxxxxxxxxxxx.aliyuncs.com/kubectl_prof_linux_amd64
    mv kubectl_prof_linux_amd64 /usr/local/bin/kubectl-prof
    chmod +x /usr/local/bin/kubectl-prof
  2. 执行以下命令,查看插件是否安装成功。

    kubectl prof deploy -h

    预期输出:

    deploy the profiling tool pod
    
    Usage:
      kubectl-profile deploy [flags]
    
    Aliases:
      deploy, run
    
    Flags:
          --container string        Specify the target container name
      -d, --duration uint           Specify the profiling duration in seconds (default 60)
      -h, --help                    help for deploy
          --image string            Specify the profiling tool image
          --kubeconfig string       Specify the kubeconfig file
          --memory-limit string     Specify the memory limit (default "1Gi")
          --memory-request string   Specify the memory request (default "128Mi")
          --namespace string        Specify the target pod namespace (default "default")
          --node string             Specify the node name
          --pod string              Specify the target pod name
          --region-id string        Specify the region-id
          --ttl uint                Specify the ttl (default 60)

步骤二:选取目标业务容器并创建Profiling任务

  1. 选定业务Pod,获取其Namespace、NameNode参数,本文以一个Pytorch训练任务为例。

    NAME                              READY   STATUS    RESTARTS   AGE   IP               NODE
    pytorch-train-worker-sample   	  1/1     Running   0          82s   172.23.224.197   cn-beijing.10.0.17.XXX
  2. 使用获取的参数执行以下命令提交Profiling Job。指定检测的业务Pod和容器,Profiling Job将在业务Pod的目标容器所在节点创建Profiling Pod。 

    kubectl prof deploy \
        --image xxxxxxxxxx \                # 请替换为阿里云提供的Profiling镜像地址
        --duration 100000 \ 		# Profiling Pod环境持续的时间
        --namespace default \ 		# 业务Pod的Namespace 
        --region-id cn-beijing \		# 环境所在的阿里云Region ID
        --pod pytorch-train-worker-sample \ # 业务Pod的Name
        --container pytorch \		# 业务Pod的Container Name
        --memory-limit 10G \		# Profiling Pod的内存限制
        --memory-request 1G			# Profiling Pod的内存申请

步骤三:触发开启Profiling

  1. 执行如下命令,查看Profiling Pod相关信息。

    kubectl get pod

    预期输出:

    NAME                                                   READY   STATUS    RESTARTS   AGE
    ai-profiler-89bf5b305acf2ec-xxxxx                      2/2     Running   0          1m
  2. 执行如下命令,进入Profiling Pod。

    kubectl exec -ti ai-profiler-89bf5b305acf2ec-xxxxx -c debugger -- bash
  3. 执行以下命令,列出所有的GPU进程,并生成Profiling命令模板。

    llmtracker generateCommand

    预期输出:

    I0314 11:42:42.389890 2948136 generate.go:51] GPU PIDs in container:
    
    I0314 11:42:42.389997 2948136 generate.go:53] PID: xxxxx, Name: {"pid":xxxxx}
    I0314 11:42:42.390008 2948136 generate.go:69] The profiling command is:
    
    llmtracker profile\
    -p <ProcessID-To-Profiling>\
    -t <Profiling-Type(python,cuda,syscall,cpu or all)>\
    -o /tmp/data.json\
    -v 5\
    --cpu-buffer-size <CPU-Buffer-Size, recommand to 20>\
    --probe-file <Enable-CUDA-Lib-Profile-File>\
    -d <Duration-To-Profiling>\
    --delay <Delay-Time>\
    --enable-cuda-kernel <Enable-CUDA-Kenrel-Profile(true or none)>
    
    I0314 14:37:12.436071 3083714 generate.go:86] Profiling Python Path is: /usr/bin/python3.10. If you want to profiling Python, please ser the environment variable:
    export EBPF_USDT_PYTHON_PATH=/usr/bin/python3.10
    说明

    若您需要开启Python层面的Profiling,需要在执行Profiling环境中先设置输出中的环境变量。

    参数及说明如下所示:

    参数

    说明

    参数

    说明

    -p

    指定需要进行ProfilingPID。可多次使用以支持多个PID。

    -t

    指定Profiling类型,可选项为python、cuda、syscall、cpu。如需全部开启,请填all

    -o

    指定Profiling结果的输出文件路径和名称,默认为/tmp/data.json

    -v

    指定日志输出的等级。

    --cpu-buffer-size

    指定eBPF数据采集的CPU缓冲区大小,默认值为20。

    --probe-file

    指定CUDA Lib Profiling所需的模板文件,请参见AI Profiling附录了解编写规范,也可直接使用默认模板

    -d

    设置Profiling任务的持续时间,单位为秒。由于长时间开启Profiling会抓取大量数据, 导致内存和磁盘压力增大,不建议超过60s。

    --delay

    设置Profiling启动的延迟时间,单位为秒,若您开启CUDA Kernel部分的Profiling,该参数建议设置为2以上。

    --enable-cuda-kernel

    指定是否开启CUDA Kernel部分的Profiling,设置为true为开启。

    更多参数详情,请执行llmtracker profile -h命令查看。

  4. 使用如下示例内容执行Profiling,根据需求修改生成的Profiling命令。

    说明

    本示例为开启了全部Profiling项(包含CUDA Kernel Profiling),CUDA Lib配置为probe.json,输出文件路径为/tmp/data.json,且添加--delay 3 -d 5表明延迟3s开始并持续5sProfiling。

    export EBPF_USDT_PYTHON_PATH=/usr/bin/python3.10
    llmtracker profile -p xxxxx -t all -o /tmp/data.json -v 5 --enable-cuda-kernel true --cpu-buffer-size 20 --probe-file probe.json --delay 3 -d 5
  5. 执行如下命令,格式化结果文件并导出。

    说明
    • 本步骤将结果文件转换为规范格式,以便于在TimeLine中展示和在SysOM中分析。

    • 如果结果文件包含CUDA KernelProfiling数据,则需要添加参数--cupti-dir,并将其固定为路径 /tmp

    • 若需使用SysOM的分析和展示功能,结果文件必须输出到目录 /output

    llmtracker export -i /tmp/data.json -o /output/out.json --cupti-dir /tmp

步骤四:Profiling结果展示

使用SysOM展示分析(推荐)

阿里云提供基于SysOM的自动化存储、可视化展示与分析能力。

执行以下命令触发SysOM的分析。在命令中填写阿里云账号的AccessKey IDAccessKey Secret,同时确保该账号具备访问SysOM资源的权限。

llmtracker analysis -a xxx -s xxx --endpoint sysom.cn-hangzhou.aliyuncs.com -p xxxxx -o out.json

预期输出:

I0314 11:45:11.505791 2950230 analysis.go:46] Start to upload profiling result file
I0314 11:45:11.934619 2950230 analysis.go:51] Stdout: thread ongpu started.
I0314 11:45:11.934637 2950230 analysis.go:68] 95e84fed-f2a6-4a35-87ca-8521087d010c
I0314 11:45:11.934643 2950230 analysis.go:69] Analysis result link: https://alinux.console.aliyun.com/system-observation/ai-infra-observation/result/?analysisId=xxx

命令最后返回SysOM的分析展示链接,直接访问即可查看分析结果。

使用Tensorboard展示分析

若您使用OSSNAS等存储,您可以参见查看TensorBoard查看结果数据的方式,在集群中启动一个挂载了包含Profiling结果数据的PVCTensorBoard Pod,打开TensorBoard查看相关数据。

使用Chrome Tracing展示分析

若您使用本地存储,需要将生成的profiling结果文件拷贝到本地,然后通过Chrome Tracing(Perfetto)打开文件进行查看。

效果展示

SysOM展示
Tensorboard展示
Chrome Tracing展示

如果使用SysOM分析能力,点击访问返回的分析链接可以看到如下效果展示,包括GPU CUDA核函数的细节分析、数据总览、详细的TimeLine展示:

image

image.png

image

使用Tensorboard展示的TimeLine效果如下:

image.png

本地使用Chrome Tracing展示的TimeLine效果如下:

image

AI Profiling附录

CUDA Lib配置文件

  1. 获取目标库的递归依赖并进一步筛选库文件。在筛选出或确认自己期望追踪的库文件后,可以通过ldd命令来获取目标抓取库文件的链接依赖,从而确定可以抓取有效数据的库文件范围。

    image

  2. 确定了目标库文件后,需要确认该库中的模板符号。本步骤以libnccl.so为例,执行如下命令,获取该库中所有的符号信息。

     readelf -Ws libnccl.so.2 | grep pnccl

    预期输出:

    ...
       223: 00000000000557d0   650 FUNC    GLOBAL DEFAULT   11 pncclGroupStart
       224: 0000000000050200   243 FUNC    GLOBAL DEFAULT   11 pncclRedOpDestroy
       225: 0000000000062081   656 FUNC    GLOBAL DEFAULT   11 pncclCommAbort
       227: 000000000006320c   721 FUNC    GLOBAL DEFAULT   11 pncclCommUserRank
       228: 0000000000064ee0    20 FUNC    GLOBAL DEFAULT   11 pncclGetVersion
       231: 0000000000045f60  1778 FUNC    GLOBAL DEFAULT   11 pncclAllGather
       232: 00000000000604f8  1578 FUNC    GLOBAL DEFAULT   11 pncclCommInitAll
       233: 000000000004ff20   728 FUNC    GLOBAL DEFAULT   11 pncclRedOpCreatePreMulSum
       238: 0000000000074520   653 FUNC    GLOBAL DEFAULT   11 pncclCommDeregister
       240: 00000000000474b0    30 FUNC    GLOBAL DEFAULT   11 pncclBcast
       243: 000000000006173d   789 FUNC    GLOBAL DEFAULT   11 pncclCommFinalize
       244: 00000000000483d0  2019 FUNC    GLOBAL DEFAULT   11 pncclSend
    ...
  3. 组装Profiling所需的JSON配置文件,需要构建一个类似于以下格式的JSON文件。该配置文件应定义Probe所需要的信息,包括UProbe中目标库文件在容器中的相对路径、库文件中期望监控方法的Symbol、KProbe中期望监控系统方法的Symbol,默认参考模板如下。

    展开查看默认参考模板

    [
        {
            "category": "cuda",
            "uprobes": [
                {
                    "type": "cuda",
                    "libraries": [
                        {
                            "library": "/usr/lib/x86_64-linux-gnu/libcuda.so.1",
                            "symbols": [
    							"cuStreamSynchronize",
                                "cuMemcpyHtoD_v2",
                                "cuMemcpyDtoH_v2",
                                "cuMemcpyDtoD_v2",
                                "cuMemcpyDtoA_v2",
                                "cuMemcpyAtoD_v2",
                                "cuMemcpyHtoA_v2",
                                "cuMemcpyAtoH_v2",
                                "cuMemcpyAtoA_v2",
                                "cuMemcpyHtoAAsync_v2",
                                "cuMemcpyAtoHAsync_v2",
                                "cuMemcpy2D_v2",
                                "cuMemcpy2DUnaligned_v2",
                                "cuMemcpy3D_v2",
                                "cuMemcpyHtoDAsync_v2",
                                "cuMemcpyDtoHAsync_v2",
                                "cuMemcpyDtoDAsync_v2",
                                "cuMemcpy2DAsync_v2",
                                "cuMemcpy3DAsync_v2"
                            ]
                        },
                        {
                            "library": "/usr/local/lib/python3.10/dist-packages/nvidia/cuda_runtime/lib/libcudart.so.12",
                            "symbols": [
                                "cudaLaunchKernel",
                                "cudaLaunchKernelExC"
                            ]
                        }
                    ]
                },
                {
                    "type": "cuBLAS",
                    "libraries": [
                        {
                            "library": "/usr/local/lib/python3.10/dist-packages/nvidia/cublas/lib/libcublasLt.so.12",
                            "symbols": [
                                "cublasLtMatmul",
                                "cublasLtMatrixTransform"
                            ]
                        },
                        {
                            "library": "/usr/local/lib/python3.10/dist-packages/nvidia/cublas/lib/libcublas.so.12",
                            "symbols": [
                                "cublasGemmEx",
                                "cublasGemmBatchedEx",
                                "cublasGemmStridedBatchedEx",
                                "cublasGemmGroupedBatchedEx",
                                "cublasSgemmEx",
                                "cublasCgemmEx"
                            ]
                        }
                    ]
                },
                {
                    "type": "nccl",
                    "libraries": [
                        {
                            "library": "/usr/local/lib/python3.10/dist-packages/nvidia/nccl/lib/libnccl.so.2",
                            "symbols": [
                                "pncclAllReduce",
                                "pncclAllGather",
                                "pncclReduce",
                                "pncclBroadcast",
                                "pncclBcast",
                                "pncclReduceScatter",
                                "pncclSend",
                                "pncclRecv",
                                "pncclGroupStart",
                                "pncclGroupEnd",
                                "_Z20ncclGroupJobCompleteP12ncclGroupJob",
                                "_Z17ncclGroupJobAbortP12ncclGroupJob",
                                "pncclCommInitRank",
                                "pncclCommInitAll",
                                "pncclCommFinalize",
                                "pncclCommDestroy"
                            ]
                        }
                    ]
                },
                {
                    "type": "torch",
                    "libraries": [
                        {
                            "library": "/usr/local/lib/python3.10/dist-packages/torch/lib/libtorch_cuda.so",
                            "symbols": [
                                "_ZN5torch4cuda4nccl4recvERN2at6TensorEPvN3c104cuda10CUDAStreamEi",
                                "_ZN5torch4cuda4nccl4sendERKN2at6TensorEPvN3c104cuda10CUDAStreamEi",
                                "_ZN4c10d16ProcessGroupNCCL8WorkNCCL17synchronizeStreamEv",
                                "_ZN5torch4cuda4nccl7all2allERSt6vectorIN2at6TensorESaIS4_EES7_PvRN3c104cuda10CUDAStreamE",
                                "_ZN5torch4cuda4nccl7scatterERKSt6vectorIN2at6TensorESaIS4_EERS4_PvRN3c104cuda10CUDAStreamEi"
                            ]
                        }
                    ]
                }
            ]
        }
    ]
    

Profiling Overhead影响数据参考

vLLM推理Overhead数据参考

测试环境
  • 推理框架:vLLM-0.6.4

  • 推理模型:Qwen2-1.5B

  • GPU卡型:NVIDIA A10

  • 测试机型:ecs.ebmgn7ix.32xlarge

  • 测试参数:采集时长30 s,Buffer Size 10

  • 评测标准:outputToken/s

  • 百分比含义:(baseline output token数 - 开启profilingoutput token数)/ baseline output token数 * 100%

测试数据

Benchmark Batchsize = 1

eBPF采集项

Baseline(无任何采集)

不开启CUDA核函数采集

开启CUDA核函数采集

eBPF采集项

Baseline(无任何采集)

不开启CUDA核函数采集

开启CUDA核函数采集

eBPF采集

55.77

44.64(19.96%)

cpu

55.32(0.81%)

45.2(18.29%)

syscall

55.21(0.10%)

47.78(13.63%)

cuda

49.15(11.87%)

43.4(21.55%)

python

29.72(46.71%)

25.5(53.90%)

cpu + syscall + cuda + python

26.93(51.71%)

21.66(60.85%)

Benchmark Batchsize = 16

eBPF采集项

Baseline(无任何采集)

不开启CUDA核函数采集

开启CUDA核函数采集

eBPF采集项

Baseline(无任何采集)

不开启CUDA核函数采集

开启CUDA核函数采集

eBPF采集

266.83

240.08(10.02%)

cpu

258.45(3.14%)

240.35(7.00%)

syscall

261.76(1.9%)

250.49(3.08%)

cuda

253.14(5.13%)

236.49(8.50%)

python

186.1(30.26%)

173.8(32.75%)

cpu + syscall + cuda + python

178.8(32.99%)

157.02(39.24%)

  • 本页导读 (1)
  • 准备工作
  • 操作步骤
  • 步骤一:部署kubectl插件
  • 步骤二:选取目标业务容器并创建Profiling任务
  • 步骤三:触发开启Profiling
  • 步骤四:Profiling结果展示
  • 效果展示
  • AI Profiling附录
  • CUDA Lib配置文件
  • Profiling Overhead影响数据参考
AI助理

点击开启售前

在线咨询服务

你好,我是AI助理

可以解答问题、推荐解决方案等