性能测试工具 Windows 客户端软件性能测试方案实践(工具选型 + 性能分析)

dun · July 27, 2026 · 214 hits

客户端软件性能测试方案实践

测试方案总览

一、性能方案

  1. #### 需求背景

国产化客户端软件在研发和测试过程中,通常侧重于功能实现和可用性,导致软件交互、性能及稳定性测试的覆盖度不足。软件发布后,常收到卡顿、反应迟缓和崩溃等负面反馈。为解决这一问题,并确保全面的测试覆盖,测试团队对桌面端软件性能测试工具进行了深入调研,并与研发团队一起梳理了性能场景和稳定性场景。最终整理成性能测试方案,用于指导客户端软件性能测试开展。

  1. #### 测试目标

在 BimBase 桌面端软件典型用户操作下,量化 CPU、GPU、内存、磁盘 I/O、FileI/O 5 大资源消耗,识别性能瓶颈并建立可追踪基线,为版本迭代的性能、稳定性提升提供量化依据 。

  1. #### 测试内容
    1. 测试范围: 本次测试调研以基座系统为例,测试范围如下:
模块 场景 被测对象 备注
软件启动 冷启动 BimBase 主 exe 程序 进程生命周期→首帧可交互
文件 打开大文件 XXXGB 以上单模型 p3d、bfa、fbx、ifc、dgn 等文件耗时
建模 批量布置 XX 根梁 +XX 根柱 参数化驱动
模型定位 搜索 →隔离→聚焦
稳定性 长时间运行 XX 小时连续操作 监控内存泄漏、句柄泄漏等稳定性问题
交互体验 XXM 地形、XX 个元素 XXM 地形、XX 个元素,交互响应时间
  1. 被测对象
    BimBase 主进程,重点监控首帧可交互时间、导入耗时、上传成功率、内存泄漏。

  2. 测试要点
    本次性能测试重点关注以下内容:

    1. 软件的核心业务(导入模型、图元建模、生成图表 )的处理能力是否达到性能目标;
    2. 软件在打开地形(大小不同、千级和万级元素、大坐标)下的交互响应耗时;
    3. 软件在大文件上传、导入、布置、下载情况下的稳定性;
    4. 软件在长时间运行 (放置模型、模型定位、移动、旋转、复制 ) 下的稳定性; ### 二、指标与输出标准
      1. #### 指标维度与采集粒度
  • CPU 维度:%Processor Time(单位时间内进程占用处理器占比)、Context Switch(上下文切换次数,反映多线程调度开销)等,直接体现 CPU 计算压力;
  • 内存维度:Private Working Set(进程私有内存占用)、Commit Size(系统承诺分配的内存总量)等,反映内存分配与泄漏风险;
  • GPU 维度:GPU Utilization(GPU 利用率),衡量图形计算/算力资源的消耗;
  • 磁盘维度:File I/O Count(IO 操作次数)、I/O Duration(单次 IO 耗时)等,暴露存储子系统的读写效率。
    1. #### 输出标准
序号 名称 类型 交付人 备注
1 测试方案 Word 测试组 含评审记录
3 录制 脚本文件 WPR 图形模式 测试组 性能测试用
4 脚本回放文件 可复现的.etl 日志、图表
4 测试执行记录 Word 测试组 含关键场景执行记录
5 缺陷统计及分析 ones 测试组
6 测试总结报告 Word 测试组

三、工具选型

  1. #### 性能测试工具(录制 + 回放监听)Windows Performance Toolkit

下载地址: https://developer.microsoft.com/zh-cn/windows/downloads/sdk-archive/

版本(与测试人员相同版本): 适用于 Windows 11 的 Windows SDK(10.0.26100.4948)

  1. #### 性能测试脚本录制工具

WPR(Windows Performance Recorder), Windows Performance Toolkit 的自带组件,无需另外安装。

  1. #### 流量回放监听工具(进程级监听)

CPU、内存、文件 I\O、磁盘 I\O 监听工具: WPA(Windows Performance Analyzer), Windows Performance Toolkit 的自带组件,无需另外安装。

  1. #### GPU、CPU 协同工具

NVIDIA Nsight Systems:英伟达官方插件,用于 GPU-CPU 协同的 系统级性能分析工具。

性能优化思路:​多工具联动,从不同维度透视问题 。

WPA 看内核细节,Nsight 看宏观时序;两者结合可判定 GPU 空等 CPU 或反之,减少单工具盲区。

核心概念:GPU-CPU 协同工作与 “空等”

在 GPU 计算(如 CUDA)、图形渲染(如 DirectX/Vulkan)或机器学习中,一个任务通常由 CPU 和 GPU 共同完成:

1.CPU(指挥官):​​ 负责逻辑控制、准备数据、向 GPU 发送渲染/计算命令。

2.​GPU(执行者):​​ 接收命令后,并行地进行大规模数值计算或图形渲染。

理想情况下,GPU 和 CPU 都保持忙碌,流水线无缝衔接。但现实中往往会出现一方 “空等” 另一方的情况:

​GPU 空等 CPU:​​ GPU 很快就完成了上一个任务,但迟迟等不到 CPU 下发下一个命令。这通常意味着 CPU 端存在瓶颈(例如,复杂的场景图遍历、驱动开销过大、或数据准备太慢)。

​CPU 空等 GPU:​​ CPU 很快就把命令提交给了 GPU,然后就必须停下来等待 GPU 完成计算/渲染,才能进行下一步。这通常意味着你的应用是 ​GPU-Bound​(受 GPU 性能限制)的。

​单工具盲区在于:

只用 WPA(CPU 视角):​​ 看到的是 CPU 非常繁忙,但无法知道它提交命令后,GPU 在干什么。你可能误以为 CPU 繁忙是性能瓶颈,而实际上 GPU 才是拖后腿的那个。

​只用 Nsight(GPU 视角):​​ 看到的是 GPU 利用率很高,但无法知道在 GPU 两个任务之间的空闲间隙里,CPU 为什么没及时提交下一个任务。

下载地址: https://developer.nvidia.com/nsight-systems/get-started

  1. #### 注意项
    1. WPA 打开 etl 文件,打开失败 可能原因 1:与测试人员所用的 WPA 版本不一致,识别为文件损坏。

解决方法:与测试使用的 WPR、WPA 版本一致。

可能原因 2:WPA 工具未安装完成。

解决方法:卸载本地 WPA 工具,重新安装。

  1. 安装了最新版,打开 ETL 文件失败,提示系统 WPA 版本过低 原因:本地存在 2 个 WPR 程序,造成冲突,系统默认使用低版本的 WPR(system 自带的),老版本 WPR 录制的脚本,新版本 WPA 无法解析。

解决方法:修改环境变量,把新版本的 WPT10 上移到 system32 上方即可解决

  1. WPR 录制文件过大 ETL(Event Trace Log)文件的大小主要受以下几个因素的影响:

详细级别越高,数据量越大:当设置为Verbose(详细)级别时,会记录大量的细节信息,这会导致 ETL 文件迅速变大。

事件类型越多,数据量越大:如果启用了许多事件提供者(如文件 I/O、磁盘 I/O、CPU、内存、GPU 等),会生成大量事件数据。

缓冲区大小和数量:较大的缓冲区和较多的缓冲区数量会增加内存占用,从而导致 ETL 文件更大。

记录时间越长,数据量越大:长时间运行性能记录会积累大量数据。

  1. WPA 录制文件过大解决方案建议 在需记录性能数据的地方开始录脚本,例如加载大文件:先进入软件项目管理页,开始录制,打开文件完成后,第一帧可交互时结束录制。

减少缓冲区大小和数量,如果采用配置文件方式:将BufferSize2048 降低到1024,Buffers512 降低到256

移除不必要的事件提供者,如在进行打开大文件测试时,只保留 CPU、FileI/O、DeskI/O、Heap usage,去掉 GPU 和其他事件。

工具的安装与使用

一、Windows Performance Toolkit

1、软件介绍

WPT(Windows Performance Toolkit)是微软提供的一套用于分析程序性能的工具包,相对于 VS 自带的实时监听插件,WPT 支持场景录制、流量回放、可视化图表,可针对测试的原始数据进行分析(例如:排除是否其他进程干扰造成测试误判、测试机的性能本身有问题)。它其中包含两个主要的工具:

  1. WPR(Windows Performance Recorder)

事件记录工具,使用它可以监测系统状态(CPU、磁盘 I/O、堆分配、栈调用…), 并生成一个.etl(Event trace log)日志文件。

  1. WPA(Windows Performance Analyzer)

日志分析工具,使用它可以对 WPR 生成的.etl 日志文件加以分析得出方便人阅读的数据图表。

2、软件安装

下载对应系统 SDK→运行安装→仅勾选 Windows Performance Toolkit→一路 Next 完成;确保路径无中文。

3、软件使用

软件安装成功后会生成 Windows Kits 文件夹,安装路径下有 wpr.exe(Windows Performance Recorder) 和 wpa.exe(Windows Performance Analyzer)。

4、录制脚本

录制与查看须用同一版本 WPT,否则.etl 无法解析;团队统一使用 10.0.26100,共享日志前确认版本号。录制只需要 4 步:启动 WPR-->录制场景配置-->录制脚本-->保存脚本。

记录参数设置

  • 性能场景:选择记录的性能场景,如 “General”(通用)。
  • 详细级别:设置记录的详细程度,如 “Light”(轻量级)、“Verbose”(详细)。
  • 记录模式:选择记录的输出形式,如 “Memory”(内存)、“File”(文件)。
  • 资源分析选项
    • CPU usage(CPU 使用率):记录 CPU 的使用情况。
    • Disk I/O activity(磁盘 I/O 活动):记录磁盘的读写操作。
    • File I/O activity(文件 I/O 活动):记录文件系统的操作。
    • Registry I/O activity(注册表 I/O 活动):记录注册表的读写操作。
    • Networking I/O activity(网络 I/O 活动):记录网络活动。
    • Heap usage(堆使用情况):记录内存堆的使用情况。 可选择 Resource Analysis 下的 “CPU usage”,“Disk I/O activity”,“File I/O activity”,“Heap usage”,点击 Start 录制脚本。

也可以通过 Add Profiles 选项导入自定义文件,点击 Start 录制脚本,自定义文件内容比较详细,但相对生成的文件会变大。

Pttest.wprp

<WindowsPerformanceRecorder Version="1.0">
  <Profiles>
    <SystemCollector Id="WPR_initiated_WprApp_WPR_System_Collector" Name="WPR_initiated_WprApp_WPR System Collector">
      <BufferSize Value="2048" />
      <Buffers Value="512" />
    </SystemCollector>
    <EventCollector Id="WPR_initiated_WprApp_WPR_Event_Collector" Name="WPR_initiated_WprApp_WPR Event Collector">
      <BufferSize Value="2048" />
      <Buffers Value="512" />
    </EventCollector>
    <HeapEventCollector Id="WPR_initiated_WprApp_WPR_Internal_Heap_Collector" Name="WPR_initiated_WprApp_WPR Internal Heap Collector" Secure="true">
      <BufferSize Value="2048" />
      <Buffers Value="512" />
    </HeapEventCollector>
    <SystemProvider Id="WPR_initiated_WprApp_WPR_System_Collector_Provider">
      <Keywords>
        <Keyword Value="AllFaults" />
        <Keyword Value="CpuConfig" />
        <Keyword Value="CSwitch" />
        <Keyword Value="DiskIO" />
        <Keyword Value="DiskIOInit" />
        <Keyword Value="DPC" />
        <Keyword Value="FileIO" />
        <Keyword Value="FileIOInit" />
        <Keyword Value="HardFaults" />
        <Keyword Value="IdealProcessor" />
        <Keyword Value="Interrupt" />
        <Keyword Value="Loader" />
        <Keyword Value="MemoryInfo" />
        <Keyword Value="MemoryInfoWS" />
        <Keyword Value="Memory"/>
        <Keyword Value="ProcessCounter" />
        <Keyword Value="Power" />
        <Keyword Value="ProcessThread" />
        <Keyword Value="ReadyThread" />
        <Keyword Value="SampledProfile" />
        <Keyword Value="SplitIO" />
        <Keyword Value="SystemCall" />
        <Keyword Value="ThreadPriority" />
        <Keyword Value="WDFDPC" />
        <Keyword Value="WDFInterrupt" />
      </Keywords>
      <Stacks>
        <Stack Value="CSwitch" />
        <Stack Value="DiskFlushInit" />
        <Stack Value="DiskReadInit" />
        <Stack Value="DiskWriteInit" />
        <Stack Value="FileCleanup" />
        <Stack Value="FileClose" />
        <Stack Value="FileCreate" />
        <Stack Value="FileDelete" />
        <Stack Value="FileDirEnum" />
        <Stack Value="FileDirNotify" />
        <Stack Value="FileFlush" />
        <Stack Value="FileFSCTL" />
        <Stack Value="FileOpEnd" />
        <Stack Value="FileQueryInformation" />
        <Stack Value="FileRead" />
        <Stack Value="FileRename" />
        <Stack Value="FileSetInformation" />
        <Stack Value="FileWrite" />
        <Stack Value="HeapAllocation" />
        <Stack Value="HeapReallocation" />
        <Stack Value="PagefaultHard" />
        <Stack Value="SampledProfile" />
        <Stack Value="ReadyThread" />
        <Stack Value="ThreadDCEnd" />
      </Stacks>
    </SystemProvider>

     <!-- ===== 追加:缺失的两个 Provider ===== -->
    <EventProvider Id="KernelProcess" Name="Microsoft-Windows-Kernel-Process" Level="3" NonPagedMemory="true"/>
    <EventProvider Id="KernelMemory"  Name="Microsoft-Windows-Kernel-Memory"  Level="3" NonPagedMemory="true"/>
    <!-- 线程生命周期,用于 File I/O 等视图的 Thread Name -->
    <EventProvider Id="KernelThread" Name="Microsoft-Windows-Kernel-Thread" Level="3" NonPagedMemory="true"/>

    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_b675ec37-bdb6-4648-bc92-f3fdc74d3ca2" Name="b675ec37-bdb6-4648-bc92-f3fdc74d3ca2" NonPagedMemory="true" Level="3">
      <Keywords>
        <Keyword Value="0x0000000000000040" />
      </Keywords>
    </EventProvider>
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_57277741-3638-4a4b-bdba-0ac6e45da56c" Name="57277741-3638-4a4b-bdba-0ac6e45da56c" NonPagedMemory="true" Stack="true">
      <Keywords>
        <Keyword Value="0x0000000000400001" />
      </Keywords>
      <CaptureStateOnSave Timeout="30">
        <Keyword Value="0x0000000000000004" />
      </CaptureStateOnSave>
    </EventProvider>
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_36b6f488-aad7-48c2-afe3-d4ec2c8b46fa" Name="36b6f488-aad7-48c2-afe3-d4ec2c8b46fa" NonPagedMemory="true">
      <Keywords>
        <Keyword Value="0x0000000000010000" />
      </Keywords>
    </EventProvider>
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_b7a19fcd-15ba-41ba-a3d7-dc352d5f79ba" Name="b7a19fcd-15ba-41ba-a3d7-dc352d5f79ba" NonPagedMemory="true" Strict="true" />
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_e13c0d23-ccbc-4e12-931b-d9cc2eee27e4" Name="e13c0d23-ccbc-4e12-931b-d9cc2eee27e4" NonPagedMemory="true" Level="3">
      <Keywords>
        <Keyword Value="0x0000000000020098" />
      </Keywords>
      <CaptureStateOnSave Timeout="30">
        <Keyword Value="0x0000000000020118" />
      </CaptureStateOnSave>
    </EventProvider>
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_d49918cf-9489-4bf1-9d7b-014d864cf71f" Name="d49918cf-9489-4bf1-9d7b-014d864cf71f" NonPagedMemory="true" />
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_e6835967-e0d2-41fb-bcec-58387404e25a" Name="e6835967-e0d2-41fb-bcec-58387404e25a" NonPagedMemory="true">
      <Keywords>
        <Keyword Value="0x0000000000000001" />
      </Keywords>
    </EventProvider>
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_c4636a1e-7986-4646-bf10-7bc3b4a76e8e" Name="c4636a1e-7986-4646-bf10-7bc3b4a76e8e" NonPagedMemory="true" />
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_314de49f-ce63-4779-ba2b-d616f6963a88" Name="314de49f-ce63-4779-ba2b-d616f6963a88" NonPagedMemory="true" />
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_8c416c79-d49b-4f01-a467-e56d3aa8234c" Name="8c416c79-d49b-4f01-a467-e56d3aa8234c" NonPagedMemory="true" Stack="true">
      <Keywords>
        <Keyword Value="0x0000000000402000" />
      </Keywords>
    </EventProvider>
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_e7ef96be-969f-414f-97d7-3ddb7b558ccc" Name="e7ef96be-969f-414f-97d7-3ddb7b558ccc" NonPagedMemory="true">
      <Keywords>
        <Keyword Value="0x0000000000002000" />
      </Keywords>
    </EventProvider>
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_9580d7dd-0379-4658-9870-d5be7d52d6de" Name="9580d7dd-0379-4658-9870-d5be7d52d6de" NonPagedMemory="true">
      <Keywords>
        <Keyword Value="0x0000000000000200" />
      </Keywords>
    </EventProvider>
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_8e92deef-5e17-413b-b927-59b2f06a3cfc" Name="8e92deef-5e17-413b-b927-59b2f06a3cfc" NonPagedMemory="true" />
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_e4b70372-261f-4c54-8fa6-a5a7914d73da" Name="e4b70372-261f-4c54-8fa6-a5a7914d73da" NonPagedMemory="true" />
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_0a002690-3839-4e3a-b3b6-96d8df868d99" Name="0a002690-3839-4e3a-b3b6-96d8df868d99" NonPagedMemory="true" Level="3" />
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_cfeb0608-330e-4410-b00d-56d8da9986e6" Name="cfeb0608-330e-4410-b00d-56d8da9986e6" NonPagedMemory="true" />
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_751ef305-6c6e-4fed-b847-02ef79d26aef" Name="751ef305-6c6e-4fed-b847-02ef79d26aef" NonPagedMemory="true" />
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_65cd4c8a-0848-4583-92a0-31c0fbaf00c0" Name="65cd4c8a-0848-4583-92a0-31c0fbaf00c0" NonPagedMemory="true">
      <Keywords>
        <Keyword Value="0x000000000000002f" />
      </Keywords>
    </EventProvider>
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_ca11c036-0102-4a2d-a6ad-f03cfed5d3c9" Name="ca11c036-0102-4a2d-a6ad-f03cfed5d3c9" NonPagedMemory="true" Stack="true" Level="3">
      <Keywords>
        <Keyword Value="0x000000000000000f" />
      </Keywords>
      <CaptureStateOnStart Timeout="30">
        <Keyword Value="0x000000000000000f" />
      </CaptureStateOnStart>
    </EventProvider>
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_7e7d3382-023c-43cb-95d2-6f0ca6d70381" Name="7e7d3382-023c-43cb-95d2-6f0ca6d70381" NonPagedMemory="true">
      <Keywords>
        <Keyword Value="0x0000000000000001" />
      </Keywords>
      <CaptureStateOnStart Timeout="30">
        <Keyword Value="0x0000000000000001" />
      </CaptureStateOnStart>
    </EventProvider>
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_db6f6ddb-ac77-4e88-8253-819df9bbf140" Name="db6f6ddb-ac77-4e88-8253-819df9bbf140" NonPagedMemory="true" Stack="true" Level="3">
      <Keywords>
        <Keyword Value="0x000000000000000f" />
      </Keywords>
      <CaptureStateOnStart Timeout="30">
        <Keyword Value="0x000000000000000f" />
      </CaptureStateOnStart>
    </EventProvider>
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_802ec45a-1e99-4b83-9920-87c98277ba9d" Name="802ec45a-1e99-4b83-9920-87c98277ba9d" NonPagedMemory="true" Stack="true" Level="3" Strict="true">
      <Keywords>
        <Keyword Value="0x0000000000000277" />
      </Keywords>
      <CaptureStateOnStart Timeout="30">
        <Keyword Value="0x0000000000000277" />
      </CaptureStateOnStart>
    </EventProvider>
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_a688ee40-d8d9-4736-b6f9-6b74935ba3b1" Name="a688ee40-d8d9-4736-b6f9-6b74935ba3b1" NonPagedMemory="true" Level="3">
      <Keywords>
        <Keyword Value="0x000000000000ffff" />
      </Keywords>
      <CaptureStateOnStart Timeout="30">
        <Keyword Value="0x000000000000ffff" />
      </CaptureStateOnStart>
    </EventProvider>
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_83ed54f0-4d48-4e45-b16e-726ffd1fa4af" Name="83ed54f0-4d48-4e45-b16e-726ffd1fa4af" NonPagedMemory="true" />
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_6ad52b32-d609-4be9-ae07-ce8dae937e39" Name="6ad52b32-d609-4be9-ae07-ce8dae937e39" NonPagedMemory="true" Stack="true" Level="3" />
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_d8975f88-7ddb-4ed0-91bf-3adf48c48e0c" Name="d8975f88-7ddb-4ed0-91bf-3adf48c48e0c" NonPagedMemory="true" Stack="true" Level="3" />
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_a669021c-c450-4609-a035-5af59af4df18_CaptureState" Name="a669021c-c450-4609-a035-5af59af4df18" NonPagedMemory="true" Level="3" CaptureStateOnly="true">
      <CaptureStateOnSave Timeout="30">
        <Keyword Value="0x0000000000020118" />
      </CaptureStateOnSave>
    </EventProvider>
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_ce8dee0b-d539-4000-b0f8-77bed049c590_CaptureState" Name="ce8dee0b-d539-4000-b0f8-77bed049c590" NonPagedMemory="true" CaptureStateOnly="true">
      <CaptureStateOnSave Timeout="30">
        <Keyword Value="0xffffffffffffffff" />
      </CaptureStateOnSave>
    </EventProvider>
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_0f67e49f-fe51-4e9f-b490-6f2948cc6027_CaptureState" Name="0f67e49f-fe51-4e9f-b490-6f2948cc6027" NonPagedMemory="true" CaptureStateOnly="true">
      <CaptureStateOnSave Timeout="30">
        <Keyword Value="0xffffffffffffffff" />
      </CaptureStateOnSave>
    </EventProvider>
    <EventProvider Id="WPR_initiated_WprApp_WPR_Event_Collector_8c416c79-d49b-4f01-a467-e56d3aa8234c_CaptureState" Name="8c416c79-d49b-4f01-a467-e56d3aa8234c" NonPagedMemory="true" Stack="true" CaptureStateOnly="true">
      <CaptureStateOnSave Timeout="30">
        <Keyword Value="0x0000000000080000" />
      </CaptureStateOnSave>
    </EventProvider>
    <HeapEventProvider Id="WPR_initiated_WprApp_WPR_Internal_Heap_Collector_Provider">
      <HeapProcessIds>
        <HeapProcessId Value="0" />
      </HeapProcessIds>
    </HeapEventProvider>

    <Profile Id="CPUDiskIOFileIOGPUHeap.Verbose.File" Name="CPUDiskIOFileIOGPUHeap" Description="RunningProfile:DiskIO.Verbose.File, FileIO.Verbose.File, GPU.Verbose.File, Heap.Verbose.File, CPU.Verbose.File" LoggingMode="File" DetailLevel="Verbose">
      <ProblemCategories>
        <ProblemCategory Value="Resource Analysis" />
      </ProblemCategories>
      <Collectors>
        <SystemCollectorId Value="WPR_initiated_WprApp_WPR_System_Collector">
          <SystemProviderId Value="WPR_initiated_WprApp_WPR_System_Collector_Provider" />
        </SystemCollectorId>
        <EventCollectorId Value="WPR_initiated_WprApp_WPR_Event_Collector">
          <EventProviders>
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_b675ec37-bdb6-4648-bc92-f3fdc74d3ca2" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_57277741-3638-4a4b-bdba-0ac6e45da56c" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_36b6f488-aad7-48c2-afe3-d4ec2c8b46fa" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_b7a19fcd-15ba-41ba-a3d7-dc352d5f79ba" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_e13c0d23-ccbc-4e12-931b-d9cc2eee27e4" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_d49918cf-9489-4bf1-9d7b-014d864cf71f" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_e6835967-e0d2-41fb-bcec-58387404e25a" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_c4636a1e-7986-4646-bf10-7bc3b4a76e8e" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_314de49f-ce63-4779-ba2b-d616f6963a88" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_8c416c79-d49b-4f01-a467-e56d3aa8234c" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_e7ef96be-969f-414f-97d7-3ddb7b558ccc" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_9580d7dd-0379-4658-9870-d5be7d52d6de" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_8e92deef-5e17-413b-b927-59b2f06a3cfc" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_e4b70372-261f-4c54-8fa6-a5a7914d73da" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_0a002690-3839-4e3a-b3b6-96d8df868d99" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_cfeb0608-330e-4410-b00d-56d8da9986e6" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_751ef305-6c6e-4fed-b847-02ef79d26aef" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_65cd4c8a-0848-4583-92a0-31c0fbaf00c0" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_ca11c036-0102-4a2d-a6ad-f03cfed5d3c9" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_7e7d3382-023c-43cb-95d2-6f0ca6d70381" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_db6f6ddb-ac77-4e88-8253-819df9bbf140" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_802ec45a-1e99-4b83-9920-87c98277ba9d" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_a688ee40-d8d9-4736-b6f9-6b74935ba3b1" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_83ed54f0-4d48-4e45-b16e-726ffd1fa4af" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_6ad52b32-d609-4be9-ae07-ce8dae937e39" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_d8975f88-7ddb-4ed0-91bf-3adf48c48e0c" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_a669021c-c450-4609-a035-5af59af4df18_CaptureState" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_ce8dee0b-d539-4000-b0f8-77bed049c590_CaptureState" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_0f67e49f-fe51-4e9f-b490-6f2948cc6027_CaptureState" />
            <EventProviderId Value="WPR_initiated_WprApp_WPR_Event_Collector_8c416c79-d49b-4f01-a467-e56d3aa8234c_CaptureState" />
            <!-- ===== 关键:追加这3个 ===== -->
            <EventProviderId Value="KernelProcess"/>
            <EventProviderId Value="KernelMemory"/>
            <EventProviderId Value="KernelThread"/>
          </EventProviders>
        </EventCollectorId>
        <HeapEventCollectorId Value="WPR_initiated_WprApp_WPR_Internal_Heap_Collector">
          <HeapEventProviders>
            <HeapEventProviderId Value="WPR_initiated_WprApp_WPR_Internal_Heap_Collector_Provider" />
          </HeapEventProviders>
        </HeapEventCollectorId>
      </Collectors>
      <TraceMergeProperties>
        <TraceMergeProperty Id="BaseVerboseTraceMergeProperties" Name="BaseTraceMergeProperties">
          <DeletePreMergedTraceFiles Value="true" />
          <FileCompression Value="false" />
          <InjectOnly Value="false" />
          <SkipMerge Value="false" />
          <CustomEvents>
            <CustomEvent Value="ImageId" />
            <CustomEvent Value="BuildInfo" />
            <CustomEvent Value="VolumeMapping" />
            <CustomEvent Value="EventMetadata" />
            <CustomEvent Value="PerfTrackMetadata" />
            <CustomEvent Value="WinSAT" />
            <CustomEvent Value="NetworkInterface" />
          </CustomEvents>
        </TraceMergeProperty>
      </TraceMergeProperties>
    </Profile>
  </Profiles>
</WindowsPerformanceRecorder>

脚本录制完成会生成一个 etl 文件,点击 save 保存文件,这个文件可以直接用 wpa.exe 打开。


点击 Open in WPA,直接启动 wpa.exe


WPA 界面如下图:

5、WPA 使用方法

  1. 添加符号路径

把一堆内存地址瞬间翻译成人类可读的函数名/文件名/行号的唯一钥匙。没有它,你看到的将永远是 :

符号路径 = 把 “地址” 翻译成 “代码” 的翻译器。有了它,同一行立刻变成 :

添加方法:选择 Trace->configure Symbol Paths 里选中符号数据->勾选 LoadSymbols。

  1. 选择分析内容

点击需要的左侧内容浏览器中想分析的内容进行展开

  1. 打开分析窗口

双击任意图表,展开系统活动性中进程时间线分析窗口

  1. 导出图表

选择需要的图表,File->Export package->保存到本地

  1. 查看导出图表

查看者电脑预先安装好对应版本的 wpa 工具,直接打开接收的 outPut.wpapk 文件,即可打开查看性能测试图表。

二、 NVIDIA Nsight Systems

1、软件介绍

NVIDIA Nsight Systems  是一款系统级性能分析工具, 它提供了一个跨 CPU 和 GPU 的统一时间线视图 。

如何工作:​​

1.同时录制 CPU 和 GPU 的活动。

2.在时间线界面上,你会看到并排的轨道:

​CPU 轨道:​​ 显示每个 CPU 线程的活动。

​GPU 轨道:​​ 显示 GPU 上各个引擎的活动(主要是 ​Graphics​ 图形引擎和 ​Compute​ 计算引擎)。

2、软件使用

File-->new File,图中红框位置选择需要测试的应用程序,设置工作空间保存路径,点击 Start 录制

点击 save 保存,等待生成最终图表文件

3、判断 GPU、CPU 的 “空等” 现象

​识别 GPU 空闲间隙:​​ 在 GPU 轨道上,你会看到一条条连续的色块(表示 GPU 正在工作),色块之间的空白就是 ​GPU 空闲​ 时间。

​关联 CPU 活动:​​ 将时间线放大,对准 GPU 的空闲间隙,然后向上看同一时间点的 CPU 线程在做什么。

​场景 A:GPU 空等 CPU​

在 GPU 空闲间隙里,你发现 CPU 主线程正在执行一些非提交命令的任务(比如在忙别的逻辑,或者卡在某个函数里)。这说明 CPU 没有及时为 GPU 准备好下一帧的命令。

​WPA 验证:​​ 在 WPA 中分析这个时间段,你会看到那个 CPU 线程的繁忙状态,并利用符号和调用栈找到具体是哪个函数或模块耗时过长。

​场景 B:CPU 空等 GPU​

CPU 线程很早就向 GPU 提交了一个非常耗时的命令(比如一个复杂的着色器或计算核函数),然后调用了同步函数,导致 CPU 线程被阻塞(进入睡眠状态),直到 GPU 完成任务。

​在 Nsight Systems 上:​​ 你会看到 CPU 线程有一段 “空白”(睡眠),而与此同时 GPU 正在满负荷工作。

​WPA 验证:​​ 在 WPA 中,你会看到该线程在同步调用上花费了大量等待时间。

瓶颈定位思路

一、是否存在内存泄漏

解释:内存泄漏指程序中动态分配的内存,在使用完毕后没有被正确释放,导致这部分内存永远无法再被程序访问或回收,导致可用内存越来越少。系统内存被耗尽,无法再分配新内存,程序可能因为内存溢出(OOM)崩溃或被系统杀掉。

  1. 参考图表:Virtual Memory Snapshots

  2. 执行操作:进入软件操作视图,开启 WPR 脚本录制工具,频繁打开、关闭大文件,采集样本。

  3. 采集完成,打开 WPA 工具,设置好符号(设置方式见 WPA 使用)

  4. 双击 memory -> Virtual Memory Snapshots 图表,Analysis 视图,鼠标悬浮 Virtual Memory Snapshots 表头,放出以下字段:
    Process:进程名称。

EndTime (Internal use) (s):数据采样点时间戳。

Working Set (MB):正在使用的物理工作内存。

Private Working Set (MB):工作中的私有内存。

Commit (MB):提交内存。

Virtual Size (MB):进程地址空间。

  1. 什么情况下可以判断为内存泄漏? 打开文件,Working Set、Private Working Set、Commit 呈线性增长,直到打开文件完毕。

关闭文件,Working Set、Private Working Set、Commit 均降低,则排除内存泄漏。

关闭文件,Private Working Set 一直增长、Commit 开始降低,则存在内存泄漏。

二、CPU 低占用软件却卡顿

性能场景:组件库资源布设、模型复制、移动、旋转,CPU 低占用,但是软件很卡。

1、 参考图表

CPU Usage (Precise)、File I/O

2、 执行操作

启动被测软件-->启动 WPR 脚本录制工具,采集样本-->频繁布置、打开模型,等待操作完成-->保存录制数据。

打开 WPA 工具,设置好符号(设置方式见 WPA 使用)。

核心关注被测应用 在追踪时间段内的 线程级 CPU 使用与调用栈热点。

3、 关键数据提炼

BimBase 主进程 : CPU Usage: 19461 ms , Ready: 1541ms , Waits: 84715 ms , % CPU Usage: 0.74%

4、 分析过程

1. CPU 使用率极低
BimBase 主进程占用 CPU 时间仅 19461ms,占比 0.74%

→ 进程 Waits: 84715 ms 处于 “等待” 状态,而非 “计算瓶颈”

2. 等待时间极长
BimBase 主进 程 等待了 84715 ms 秒,占总时长(19461+84715=104176)的 81.32%

进 程被阻塞,不是因为 CPU 忙,而是 其他事件。

3. 结论
在整个追踪期间 CPU 使用率 非常低 ,BIMBase.exe 进程 81% 时间卡在等待状态,说明当前阶段进程处于 “空闲” 被 “I/O 或者消息阻塞” 状态,而非计算密集型任务。

1. 下一步,结合 IO 图或者 GPU 图进行进一步分析,若为用户空闲阶段,则无需优化,属于正常行为。 若 I/O 图显示此时正在大量读模型文件说明 CPU 在等磁塞 。

2. 查看 File I/O Duration by Process 视图,查看 BIMBase.exe 在整个追踪时间段内的 文件 I/O 操作耗时分布。
I/O 耗时堆叠图 + 明细表

3. 结论:
1. 单次读取耗时:≈ 0.0177 ms ,写入耗时: ≈ 0.131ms,6213 次读取,8780 次写入,总耗时≈ 3.2 秒
“平均单次读取耗时” 公式:单次耗时 = 总耗时 ÷ IRP 次数,3215ms÷ 6213 =0.518ms;

→ 极高频率、极小块、极快响应

→ 磁盘随机读取性能瓶颈已非常明显,

b. I/O 操作总量极大 , 总 IRP 次数:约 6213 次 , 总 I/O 耗时:约 3 秒

典型的 “小块随机读取” 模型,机械盘 IOPS 直接打满 。

c. CPU 图联合验证:CPU 空闲,I/O 爆满

CPU 图显示:进程等待 85 秒

I/O 图显示:14993 次 I/O,平均单次 0.214 ms

CPU 不是瓶颈,磁盘 IOPS( 每秒读写次数 ) 是瓶颈

主线程可能在等 “异步 I/O 完成事件” 或 “消息循环”,数据加载慢 。

4. 怎么看出的机械盘 IOPS 直接打满?
1. 先算 BIMBase 实际产生的 IOPS , 从图中:
2. 总 I/O 次数:≈ 60297 次(Read + Create + QueryInfo + Close + ...)总时间:85 秒 → 实际 IOPS =60297÷ 85 ≈ 709 次/秒
3. 再看机械盘的 IOPS 上限(常识值)

4. 对比结果:实际 IOPS 机械盘上限 80~120 次/s,远小于 NeXusPlatform.exe 进程的 709 次/s
5. 机械盘队列会打满,每次 I/O 延迟从 0.01 ms 涨到 1~100 ms, 用户感觉就是 “加载慢”、“卡顿”。

6. 打开 “Hard Page Faults” 视图 → 如果 Fault 次数与 Disk usage I/O 高峰重合(DISK 紫色 线条),说明 内存缺页 + 磁盘阻塞 。

5、优化方案

与开发沟通了解到,BIM 相关的软件,在进行模型文件创建时,为了保证模型文件的一致性、唯一性,行业内一般都采用单线程去进行文件读写,所以会造成这个问题,优化建议:

三、GPU 与 CPU 多维监控

性能场景:打开大文件完毕,进行构件选中、远近景构件查看,软件卡顿。

参考:Nsight Systems 视图,核心现象:CPU 帧时间远超目标,直接导致卡顿, 目标帧率为 60Hz(每帧理论最大耗时 16.67ms),但实际 CPU 帧持续时间高达 34.6ms ​(标注 “34.6 ms”),远超目标值。这直接导致画面卡顿(“Stutter”),是性能问题的最直观表现。

1. ​CPU 线程阻塞严重

上图标注了多个线程(如[10088] nvvvgf2umx.dll[14892] nvvvgf2umx.dll[18824] nvvvgf2umx.dll等)处于​“Blocked State”(阻塞状态)​,且关联到 ETW 事件(Microsoft-Windows-DxgKml)。结合下图的 CPU 核心利用率图表(黑白线条),推测这些线程可能因以下原因被阻塞:

  • 等待 GPU 资源​:如等待 GPU 命令队列完成(隐式同步)、显存访问冲突或 CUDA 流同步(如cudaDeviceSynchronize)。
  • CPU 内部竞争​:多线程争用锁、内存带宽或 IO 资源(如文件读写、网络请求),导致线程无法高效执行。

2. ​CPU 与 GPU 任务并行性不足

下图图的时间线视图中,CPU 核心利用率(顶部黑白线条)与 GPU 操作(中部绿色条带)的时间重叠度较低。结合上图的 “Queue [13.009s]”“Queue [12.181s]” 等长耗时队列,说明:

  • •CPU 未能及时向 GPU 提交任务(如渲染命令、内存传输),或 GPU 任务提交后 CPU 空闲等待结果,导致整体帧处理时间被拉长。

3、GPU 空等 CPU

CPU 未能及时向 GPU 提交任务(如渲染命令、内存传输),CPU 处于繁忙状态,性能瓶颈在 CPU。进一步分析 CPU 瓶颈,WPA 打开 Nsight Systems 视图生成的 etl 文件,这个就是前面说的: 性能优化的核心思路 --- 多工具联动,从不同维度透视问题 。

​4、使用 WPA 进行深度 CPU 剖析

从图表中 “Idle Thread 占比 87.5%”(第二张图)和 “CPU 利用率波动但整体未满载”(第一张图)的线索看,系统​整体 CPU 资源未被充分利用。问题不是出在:GPU、CPU 上。这个时候需要开发排查是否局部线程调度低效或关键进程/线程被阻塞。

稳定性测试

一、长时间运行实现方案

1、模拟场景(BimBase 建模软件进行试点)

打开项目文件,按照设置条件循环创建立方体、圆柱、球体,检测到闪退事件或者崩溃事件,打包本地日志到云存储服务器,重新进行长时间运行测试。

二、日志上报

1、实现方式

第一步:检测到崩溃事件,打包本地:D:\安装目录\根目录\logs 文件夹为 zip。

第二步:上传 zip 文件至云存储服务器,增加时间戳作为唯一文件名称。

第三步:删除本地 logs 文件下所有日志文件。

第四步:启动软件继续自动执行稳定性测试用例。

2、进程检测、日志上报接口(脱敏处理)

检查本地进程是否存活:(http://localhost:8028/api/nexus/status)

手动触发日志上传:(http://localhost:8028/api/nexus/upload-logs)

No Reply at the moment.
需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up