培训会议主讲记录20220924

2022年9月24号星期六 10时至12时 14时至15时30分

与会:全体软件平台组10人

培训内容

C/C++代码培训:实战演练——使用性能剖析器优化效率

这一次花费了不少时间来做准备,准备了两个实际生产环境中的问题。通过现场现场演练,使用VS自带的新能分析器来一步一步展示如何配置环境,通过CPU剖析找到热点代码,分析问题优化改进,并验证结果。最后剩下一些时间,额外的展示了内存使用的分析。

课件的是在提前预演问题时准备的,将过程和记录下来。

效果和心得

这一次与会人员的反馈比较好,清楚地展示教导了如何使用剖析器优化代码的过程和思路。

经过上一次的教训,这次使用了自己的高性能笔记本(插电),大大减少的编译和剖析器的耗时。

改进

附文最后带有,当场进行的培训质量打分,获得了比较高的评价。

有反馈到,讲解的例子有点多,耗时过长。在准备时,有点担心没能达到很好的效果,又刚好遇上的不同的案例,就想着多一点内容,哪怕没能很好的掌握这次培训的技能,也能够很好的加深映像。这个反馈给我的实际映像是,有很多同事实际的水平可能比工作中的水平要高不少,往往因为各种因素消极怠工。

也有反馈到,希望拓展的内容更多。在现场的讲解中也确实遇到,许多拓展的东西更吸引注意力。不过这一块需要讲解的需要相当深厚的水平,这块我准备的很多拓展内容都是事先准备的,想要信手沾来还有点难度,需要更加努力。

还有一块是将一些专业的词汇写下来,可供有兴趣的同学自己去额外查找学习

附文

附当场的主讲记录

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