1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| 代码培训20220924 10:00-12:000 主题:实战演练——通过性能分析器优化程序效率 参加人员:软件平台组全体10人
程序优化 基数方法:手动log时间
性能分析器,Profile, VS自带的剖析器
实际案例 CMakeLists.txt -> sln cmake -Bvs_out -G"Visual Studio 16"
窗口-》重置窗口布局 诊断工具窗口 勾选《记录CPU配置文件》选项 两个断点之间生成具体的分析-》打开详细信息
带调试信息的release模式,保证相似的速度和可以使用断点 问题: 读取文件 《打标测试3(1).dxf》 debug下全部显示很卡顿, release 速度尚可 环境: 主工程库版本 "77e2203 - 更新子目录至最新" Win10 64bit i5-10400 2.90GHz RAM:16G GPU: UHD 630 编译类型 Debug RelWithDebug 分析 View::Render()中断点显示一帧需要237/162ms CPU Profile 记录出一帧中最耗时的函数是QueryTransMatrix(), 占用每帧的72.88/68.52%消耗
在Release下速度尚可 使用CMake输出程 sln 工程,以RelWithDebug 模式编译 同样的情况View::Render()中断点显示一帧需要22/21ms左右 CPU Profile 记录 QueryTransMatrix() 中消耗是 31.82/4.55% 解决 编写了QueryTransMatrix()新算法 主工程库版本 "79da267 - 更新新的QueryTransMatrix()算法" cadc 版本 "06016e4 - 优化QueryTransMatrix()的效率" 同样条件在 Debug 下一帧需要 79/11ms左右消耗为 32.91/18.3% QueryTransMatrix()优化了85/54.95%,整体优化了67/62% 同样条件在 RelWithDebug 下一帧需要18/17ms左右消耗为 11.12/19.07% QueryTransMatrix()优化了70/86%,整体优化了20/19% 思考 20%的性能优化是长期可靠的吗,在某些条件下会不会劣化
主题 分析文件 《打标测试3(1).dxf》 的打开性能 环境 主工程库版本 "f6c154a - 修正非win下条件编译的错误" FileParser版本 "04e83b9 - Merge branch 'master' into 'master'" Win10 64bit i5-10400 2.90GHz RAM:16G 编译类型 RelWithDebug 分析 总耗时 1010/723 ms 主要性能开销 1. 47.03/42.6% FileParser\FileParser\src\dxf\dxf_reader.cpp ln 142 dxfReader::readDouble() 8.91/7.19% ln 146 " if (readString(&text))" std::getline 就使用了 8.81/7.19% 23.96/22.82% ln 149 "sd >> doubleData;//将字符串转为double" 这里的开销主要是将字符串转为double值, 为了完成字符串转double 结合上下文看, 实际的开销应该是 37.82/34.58%, 要把对应变量的构造和析构也算进去 这里可以尝试优一下
解决方案 FileParser 版本 "5e124b1 - 降低字符串转double的消耗" 总耗时 663/510ms 降低 34.4/29.5% 最终字符串转为double值的开销为总 7.54/6.08%, 性能优化 87/87.6%
这里面引申出一个问题, 对于文件解析来说, std 的字符串库的性能是否满足告诉解析
2. src\Parser\DxfParser.cpp 12.87/12.72% ln 689 "it->Transform(ViewOffset);" 6.24/6.84% ln 692 "it->Transform(USCmove);"
这里就是个很简单的问题了, 这里进行了2次变换, 总消耗 19.11/19.56% 但其实稍微观察下这个函数就知道这里的变换可以合并成一次变换
解决方案 主工程版本 "d3a7ebc - 合并DxfParser中的变换" 总耗时 936/676ms 降低 6.4/6.67% Transform 总开销为 14.69/14.64%, 性能优化 28.8/31%
合并所有优化 主工程库版本 "2bf8975 - 更新FileParser版本" 总开销 620/461ms, 优化 38.7/38.3%
思考 这个文件有什么特点, 这些优化在什么情况下会发挥到比较好的作用 主要是读double数据,切分换行 在占总消耗 19.11% 的 Transform() 中有, 其中的 ReDraw() 函数占总消耗的 12.67% 可以进行怎样的优化, 又会带来什么样的后果
往往内存操作的耗时是最高的
总体需要注意的事项 + 二八原则, 80%的消耗在20%的代码上. 在代码编写之初不要瞎优化, 写一些难以阅读的代码 + 一切优化建立在剖析数据的上, 要根据实际的情况下的剖析结果去改进 + 当运行消耗都比较分散时, 往往难以再做性能优化. 因为这时候往往是设计结构不足以应对实际需求 这时候就需要根据经验, 实际情况, 算法改进等重新进行设计 + 做好性能分析的记录, 保存环境和关键数据, 空口无凭, 有数据才能有对比
容易理解的程度:5, 4.5,4,4.5,4,5,5,5,5 讲解的形式:5,5,5,5,5,4(内容冗余),4.5,4.5,4.5 授课风格:5,5,5,4.5(再扩散一点),4.5(增加比喻),4(扩展内容),4.5(专业的词语),5,4.5
|