ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Flutter Engine DisplayList 基准测试完全指南:iOS/Android 真机运行与结果处理

Flutter Engine DisplayList 基准测试完全指南:iOS/Android 真机运行与结果处理 跨平台图形学前端【免费下载链接】engineThe Flutter engine项目地址https://gitcode.com/gh_mirrors/eng/engine点击查看免费下载导读本文以 Flutter Engine 仓库中的testing/benchmark/README_displaylist.md为骨架系统讲解 DisplayList 基准测试套件的用途、在 iOS 与 Android 真机上的完整运行流程以及如何用官方解析脚本把 Google Benchmark 的 JSON 输出加工成 PDF 图表与 CSV 数据。读完本文你将掌握ios_display_list_benchmarks与display_list_benchmarks两个构建目标的用法、adb/Xcode 的实际操作细节并理解这些测量数据是如何被翻译成 raster cache 缓存准入算法中每个绘制操作op的复杂度分数的。DisplayList 基准测试为什么需要它Flutter 在 UI 线程把一帧的绘制命令记录成 DisplayList然后在 raster 线程回放。为了决定哪些 DisplayList 值得被 raster cache 缓存引擎需要评估绘制这条 DisplayList 大概要花多少钱。这就是 display_list/benchmarking 目录下基准测试套件的意义所在DisplayList benchmarks 用于测定每个操作的相对成本以便为 raster cache 的缓存准入算法cache admission algorithm给每个 op 分配分数。由于基准测试的性质这些测试必须在真实设备上运行才能得到有代表性的结果而 iOS 与 Android 平台对代码签名的限制各不相同导致跑起这套基准测试颇为周折。文档主体正是围绕如何在 iOS / Android 上跑起来 如何处理数据展开。从仓库源码看整套体系由三块构成基准测试本体display_list/benchmarking/dl_benchmarks.cc/dl_benchmarks.h基于 Google Benchmark 框架编写构建目标display_list/BUILD.gn中的display_list_benchmarks可执行文件与ios_display_list_benchmarksdylib结果处理testing/benchmark/displaylist_benchmark_parser.py把 JSON 转为 PDF 与 CSV。基准测试套件覆盖了哪些操作在深入运行步骤前先看看基准测试本身覆盖了哪些绘制操作。dl_benchmarks.h中声明了一系列BM_*基准函数包括基准函数覆盖的绘制操作关键变量BM_DrawLineDrawLine画线线长16~2048BM_DrawRectDrawRect画矩形边长16~2048BM_DrawCircle/BM_DrawOval画圆 / 画椭圆半径 / 尺寸16~2048BM_DrawArcDrawArc画弧弧长128~2048BM_DrawPathDrawPath画路径多边形边数8~512按 Line/Quad/Conic/Cubic 四种 Verb 分别测BM_DrawPointsDrawPoints画点点数1024~32768分 Points/Lines/Polygon 三种模式BM_DrawVerticesDrawVertices画顶点网格顶点数16~2048分 TriangleStrip/TriangleFan/TrianglesBM_DrawRRect/BM_DrawDRRect圆角矩形 / 双圆角矩形边长16~256按 Symmetric/NinePatch/Complex 三种类型BM_DrawImage/BM_DrawImageRect/BM_DrawImageNine贴图 / 局部贴图 / 九宫格贴图位图尺寸128~512 / 32~256区分 Texture已在 GPU 上与 Upload需上传两种路径BM_DrawTextBlob文本绘制字形数1~256BM_DrawShadow阴影绘制光源高度1~32区分透明/不透明遮挡物四种 VerbBM_SaveLayer图层保存嵌套深度 1 / 8调用次数1~128每个基准都通过-Range(..)、-RangeMultiplier(2)设置指数增长的输入规模并通过-UseRealTime()与-Unit(benchmark::kMillisecond)记录墙钟时间毫秒。部分基准如DrawPath、DrawVertices、DrawPoints、DrawTextBlob还调用-Complexity()让 Google Benchmark 自动计算 Big-O 复杂度。属性矩阵同一操作的不同绘制状态每个操作还会搭配一组属性attributes组合来测量。dl_benchmarks.h中定义了位掩码enum BenchmarkAttributes { kEmpty 0, kStrokedStyle 1 0, // 描边样式 kFilledStyle 1 1, // 填充样式 kHairlineStroke 1 2, // 极细描边stroke width 为 0 kAntiAliasing 1 3 // 抗锯齿 };对应的画笔构造逻辑在 dl_benchmarks.cc 的GetPaintForRun()中kStrokedStyle设置DlDrawStyle::kStrokekFilledStyle设置kFillkHairlineStroke把描边宽度设为0.0fkAntiAliasing调用setAntiAlias。最终的组合通过RUN_DISPLAYLIST_BENCHMARKS(BACKEND)宏展开dl_benchmarks.hL573-L583例如描边抗锯齿kStrokedStyle | kAntiAliasing、描边极细线kStrokedStyle | kHairlineStroke等以 5 种组合覆盖每个操作的常见绘制状态描边系列Stroke线、点、矩形、椭圆、圆、弧、路径、圆角矩形、双圆角矩形、文本填充系列Fill矩形、椭圆、圆、弧、路径、圆角矩形、双圆角矩形、文本抗锯齿系列贴图、局部贴图其他系列九宫格贴图、顶点网格、阴影、SaveLayer后端Backend支持宏RUN_DISPLAYLIST_BENCHMARKS在dl_benchmarks.cc末尾按编译宏分别展开到不同后端#ifdef ENABLE_SOFTWARE_BENCHMARKS RUN_DISPLAYLIST_BENCHMARKS(Software) #endif #ifdef ENABLE_OPENGL_BENCHMARKS RUN_DISPLAYLIST_BENCHMARKS(OpenGL) #endif #ifdef ENABLE_METAL_BENCHMARKS RUN_DISPLAYLIST_BENCHMARKS(Metal) #endif即同一套操作会在 Software纯软件光栅化、OpenGL、Metal 等多个后端上分别测量——这也是结果处理阶段需要按 backend 分组绘图的原因。iOS 上使用 Metal 后端Android 上使用 OpenGL 后端取决于构建配置。iOS 上运行 DisplayList 基准测试iOS 不允许运行未签名的代码或任意可执行文件因此方案是构建一个包含基准测试代码的 dylib再链接到 Xcode 里的一个 skeleton 测试 App 中。这个 dylib 导出一个 C 函数void RunBenchmarks(int argc, char **argv)由 skeleton 测试 App 调用它来真正执行基准测试。dylib 默认不会被构建需要手动指定目标调用 ninja。目标名为ios_display_list_benchmarks$ ninja -C out/ios_profile ios_display_list_benchmarks从 display_list/BUILD.gn 可以看到该目标在is_ios条件下构建为shared_library设置了-mios-simulator-version-min$ios_testing_deployment_target等编译参数并链接benchmarking_library产物路径约定为out/ios_profile/libios_display_list_benchmarks.dylib在testing/ios/IosBenchmarks/IosBenchmarks.xcodeproj/project.pbxproj中可以看到该 dylib 被以../../../../out/ios_profile/libios_display_list_benchmarks.dylib的相对路径引用并嵌入 Frameworks/Embed Libraries。dylib 构建完成后在 Xcode 中加载flutter/testing/ios下的 IosBenchmarks 测试 App实际目录为 testing/ios/IosBenchmarks。随后需要设置签名 Team确保代码可以被签名iOS 不允许跑未签名代码设置FLUTTER_ENGINE匹配你希望使用的 Flutter Engine 构建例如ios_profile。配置完成后直接点击RunJSON 输出会打印到 Xcode 控制台。把输出复制出来保存为.json文件即可。注意控制台输出中可能混有一些与 JSON 无关的错误信息保存前需要手动清理掉这些噪音行。skeleton App 的入口逻辑见 testing/ios/IosBenchmarks/IosBenchmarks/main.mm它声明了外部函数int RunBenchmarks(int argc, char** argv)并在main里直接调用并返回其结果——也就是说真正的工作全部在 dylib 内部完成App 只是一个壳。Android 上运行 DisplayList 基准测试Android 与非 root 设备上都可以通过 adb 执行未签名二进制因此方案更直接构建一个可执行文件用 adb push 到设备再用 adb shell 执行。唯一的限制是二进制必须放在没有以noexec挂载的分区上这通常排除了 SD 卡/data/local/tmp是一个通常可用的选择。构建目标名为display_list_benchmarks会生成同名二进制display_list_benchmarks位于输出目录根部例如android_profile_arm64$ adb push out/android_profile_arm64/display_list_benchmarks /data/local/tmp/display_list_benchmarks $ adb shell /data/local/tmp/display_list_benchmarks --benchmark_formatjson | tee android-results.json第二条命令以 JSON 格式输出基准结果--benchmark_formatjson是 Google Benchmark 的标准参数并用tee同时打印到终端和写入android-results.json。得到的android-results.json即可进入下一步处理。从构建配置看display_list/BUILD.gn 中display_list_benchmarks_source源集包含benchmarking/dl_benchmarks.cc与benchmarking/dl_benchmarks.h依赖display_list、display_list_fixtures、display_list_surface_provider、testing_lib等display_list_benchmarks目标进一步包装为executable。此外CI 配置如 ci/builders/linux_host_engine.json 与 ci/builders/standalone/linux_benchmarks.json也会构建flutter/display_list:display_list_benchmarks说明该套件同时支持在 Linux host 上运行。处理结果从 JSON 到 PDF 图表与 CSVflutter/testing/benchmark目录下提供了处理脚本 displaylist_benchmark_parser.py它接收 JSON 文件输出PDF包含所有基准序列的折线图CSV可导入电子表格做进一步分析的数据。用法$ python3 displaylist_benchmark_parser.py results.json \ -o output.pdf -c output.csv命令行参数argparse定义见脚本 L133-L158参数含义默认值filename位置参数Google Benchmark 输出的 JSON 文件路径必填-o/--output-pdfPDF 图表输出文件名output.pdf-c/--output-csvCSV 数据输出文件名output.csv解析逻辑如何从 JSON 还原基准维度脚本对每条基准记录的解析逻辑process_benchmark_data()L185-L245很有参考价值。Google Benchmark 的 JSON 中name字段是以/分隔的层级结构例如BM_DrawLine/OpenGL/real_time。脚本按以下规则拆分第一个分段是基准函数名如BM_DrawLine倒数第二个分段是后端如OpenGL/Metal/Software最后一个分段是种子值benchmark seeded value即输入规模如线长、点数等中间的其余分段构成族标签family label例如路径基准中的Lines/Quads/Conics/Cubics、点基准中的Points/Lines/Polygon尾部固定出现的real_time会被丢弃。此外脚本还会从记录中提取AntiAliasing、HairlineStroke、StrokedStyle、FilledStyle等属性extrac_attributes_label()L166-L182拼进族标签并提取若干可选的统计字段DrawCallCount固定绘制调用数DrawCallCount_Varies随基准输入变化的绘制调用数VerbCount路径动词数PointCount/VertexCount/GlyphCount点 / 顶点 / 字形数量其中aggregate_name字段聚合结果如均值/中位数会被跳过。绘图与 CSV 输出绘图逻辑BenchmarkResult.plot()L58-L108按后端、按族分别绘制x 基准种子值y 耗时时间单位的折线。当某条序列的 y 值超过 200y_limit时会自动额外生成一张截断版y 轴限制在 0~200和一张完整版两张图以便同时看清低端细节与整体趋势标题中还会标注Draw Call Count。CSV 输出write_csv()L110-L130则以x 各族标签列的形式写出每一行数据并附上可选统计列方便导入 Excel/Sheets 做进一步分析。从测量数据到缓存准入分数复杂度计算原理处理出的数据最终会被手动分析用于确定 raster cache 缓存准入算法的相对权重。这个翻译过程发生在 display_list/benchmarking/dl_complexity_helper.h 及dl_complexity_gl.cc/dl_complexity_metal.cc中。该头文件明确说明了这些分数是怎么来的L15-L16Metal 和 OpenGL 的复杂度计算器使用的数据就是通过display_list_benchmarks测试套件在真实设备上采集的。几个关键设计点归一化基线复杂度分数以 100 分 ≈ 0.0005ms 为基线用 32 位无符号整数表示最大可估时间约 21 秒远超任何 DisplayList 实际光栅化耗时L45-L49低成本计算约束复杂度计算必须在光栅化前快速完成否则算复杂度的成本反而会吃掉光栅化省下的时间因此只允许简单的加减乘除、尽量用整数运算、对对数型复杂度的 op 在预期范围内做直线拟合L51-L77公式推导示例L79-L92假设y mx c除以单次基准迭代的 op 数再乘以 200,000把 0.0005ms 归一化为 100 分。例如 drawLine 基准每次迭代跑 10,000 次调用若m1/5、c0则y x/5 × 200,000 / 10,000 4x误差容忍度测量误差大且因设备而异因此目标不是精确建模而是显著优于旧的准入策略op_count 5并且刻意让大数值更准确——小数值噪声大、绝对差异小且对缓存决策影响可忽略L19-L40。打分后的复杂度分数被 raster cache 消费。在 flow/layers/display_list_raster_cache_item.cc 中缓存项通过DisplayListComplexityCalculator计算复杂度GetForBackend根据是否有gr_context选择 GPU 或软件计算器再结合DisplayListRasterCacheItem::GetCachedDisplayList等逻辑决定缓存与否。测试侧 flow/raster_cache_unittests.cc 中也能看到用DisplayListNaiveComplexityCalculator::GetInstance()做对照测试的用例。参考与延伸阅读基准测试构建配置display_list/BUILD.gn基准函数声明与宏定义display_list/benchmarking/dl_benchmarks.h基准函数实现display_list/benchmarking/dl_benchmarks.cc复杂度计算通用逻辑display_list/benchmarking/dl_complexity_helper.h结果解析脚本testing/benchmark/displaylist_benchmark_parser.pyiOS skeleton 测试 Apptesting/ios/IosBenchmarks复杂度分数在 raster cache 中的消费flow/layers/display_list_raster_cache_item.cc性能指标上传工具testing/benchmark/upload_metrics.sh配合 testing/benchmark/generate_metrics.sh 可用于指标生成与上报赞分享跨平台图形学前端【免费下载链接】engineThe Flutter engine项目地址https://gitcode.com/gh_mirrors/eng/engine点击查看免费下载相关推荐Flutter Engine DisplayList 基准测试实战从 iOS/Android 真机运行到光栅缓存权重分析Flutter Engine DisplayList 基准测试实战从 iOS/Android 真机运行到光栅缓存权重分析 DisplayList显示列表是跨平台移动开发前端UI组件桌面应用Momentum-Firmware RGB 背光完整指南3 步点亮你的设备Momentum Firmware RGB 背光完整指南3 步点亮你的设备 Momentum Firmware 是一款可定制的 Flipper Zero 开源嵌入式物联网uni-app 真机运行完全指南HBuilderX 连接 Android / iOS 真机与模拟器调试uni app 真机运行完全指南HBuilderX 连接 Android / iOS 真机与模拟器调试 导读 uni app含 uni app x由于手示例工程前端移动开发跨平台上一篇小米平板5 Windows驱动架构深度解析与优化部署指南下一篇终极音频格式转换指南FlicFlac让你5分钟掌握专业音频转换技巧创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表