免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: sonicling
打印 上一主题 下一主题

[C] 问一下大家用什么方法计时以获取程序的效率? [复制链接]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
11 [报告]
发表于 2012-09-04 23:52 |只看该作者
回复 10# OwnWaterloo

关于提到手工Instrumentation。。。   不是说这方法不好。。。  其实我也做过这样的事情。。。
与专用工具各有优劣,就像log(手工Instrumentation) vs debuger(自动化profiling工具)。 前者只依赖语言本身,不依赖外部工具。


提到手工Instrumentation的意思就是想解释Instrumentation是个什么含义。。。就是在被监视代码中插入额外代码收集数据,然后分析。
另外那种采样的方式就不会插入额外代码,而是定期检测目前在调用哪个函数,收集这样的数据来分析。
至于检测active的函数,估计就是只记录各个时刻的eip,最终在map file(这货有很多名字。。。 总之就是记录address -> symbol的文件)里查。

论坛徽章:
0
12 [报告]
发表于 2012-09-05 00:26 |只看该作者
本帖最后由 sonicling 于 2012-09-05 00:36 编辑

回复 11# OwnWaterloo


    啥时候升级到Team System版本试试。或者移植到linux下用gprof测试一下,反正只用到了标准库,系统库已经做了预见性转接,没有使用第三方库。

说起来手工检查性能也有好处,就是可以快速看到想看到的内容,作简单分析即可快速得到结论。经过两天的折腾,程序性能还是提高了不少。

"generic_parser::parse" spent 2855ms
"main" spent 2933ms // main 调用了 generic_parser::parse,多出的时间是初始化时间+误差。
// 后面是累加计时器的输出,打印的是对应函数所有被调用总运行时间。
"RUN PROCESSOR in processor_manager<class abstract_node_info,class abstract_parser,struct cpp_processor_factory>::process" spent 764ms
"cpp_parser::parse_ast_node" spent 1137ms // parse_ast_node调用了上面那个函数,多出的时间是查询数据+误差
"generic_parser<class abstract_node_info,struct cpp_parser_package<struct comment_filter> >::parse_ast" spent 1325ms // 该函数调用了上面那个函数,多出的时间基本是误差
"ast_parser<class abstract_node_info>::process_definition" spent 204ms
"generic_processor<class abstract_node_info,struct cpp_parser_package<struct comment_filter> >::reduce" spent 1825ms // 该函数调用了上面两个函数,多出的时间是倒腾数据+误差
struct agc::allocator<char> -- Memory Usage Report :
Maximum Usage : 929 KB


最后那个reduce函数是据信调用最频繁,工作量也最大的函数。

这里面的误差是个很头疼的东西。这个GetThreadTimes导致的误差不光影响了感官,被调用函数的计时也会影响调用者的计时。如果只执行1次,那个误差其实可以忽略不计。但是那些累加出来的数据也包含了累加的误差,调用越频繁误差越大。这是个很头疼的问题。instrumentation方式的自动测试应该也有误差,不知道有多大。基于采样的方式想来应该有统计误差,就是说可能存在漏掉的数据(我不清楚具体的实现方法,设想如此)。

取消所有测试点后的结果:
"main" spent 1856ms
struct agc::allocator<char> -- Memory Usage Report :
Maximum Usage : 929 KB


除去reduce函数之外,还有1s的时间用在其他部分。目前还没着手分析。就这么手动分析了两天,总时间已经从2800+ms缩小到1800+。

不过手动分析需要先对程序结构进行精确的掌握,然后就是需要大量的编译时间,因为所有的计时点是人工有针对性选择的,每修改一次计时点就要重新编译,再对程序提出修改方案并实施,又要编译。估计这两天有一大半的时间耗在编译工程上了。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
13 [报告]
发表于 2012-09-05 01:00 |只看该作者
回复 12# sonicling

Windows下不能用gprof么?

论坛徽章:
0
14 [报告]
发表于 2012-09-05 01:10 |只看该作者
OwnWaterloo 发表于 2012-09-05 01:00
回复 12# sonicling

Windows下不能用gprof么?


对啊,我傻了,呵呵。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
15 [报告]
发表于 2012-09-05 01:39 |只看该作者
本帖最后由 OwnWaterloo 于 2012-09-05 01:42 编辑

回复 14# sonicling

那个问题我是真心问的。。。
因为在Windows上切换到gnu那套之后就没做过什么实际的项目了。。。
比如使用的库不是由自己编译的情况。。。   记得是有专门的_p版本。。。
但Windows上能得到其他人编译出来的就不错了。。。 要自己从源代码编译,尤其是从非Windows port而来的。。。 各种痛苦。。。


PS:
我第1次用VS这个performance tools的时候。。。 犯了件很搓的事。。。
背景是读取条码。。。我负责处理图像,室友负责分析条码。。。
做完了就开始人肉分析可能会出问题的地方。。。 然后各种优化。。。 最终凑合可以用了。。。

后来用这个工具一测。。。 完全傻了。。。 大量的时间(具体数值不记得了,反正高到离谱)花在读取像素值的函数上。。。
嗯。。。这是一个函数。。。   不是一个指针算术然后直接内存访问。。。
在项目才开始的时候,分配接口时就只是传递给室友一个CvImage,他用cvGet2D获取像素值。

  1. typedef struct CvScalar { double val[4]; } CvScalar;
  2. CvScalar cvGet2D(const CvArr* arr, int idx0, int idx1);
复制代码
你看这个签名就知道有多吓人了。。。
CvImage与cvGet2D就有点类似动态类型了,无论什么图像都可以通过这个函数获取,运行时各种判断嘛。。。然后返回一个4元素(因为最多只支持4通道)的double数组。。。
也不记得是因为当时菜,还是因为一开始具体类型定不下来,才用的这个。。。 总之后来我们都把这件事忘了。。。
然后人肉分析各种性能问题。。。 我这边就是减少中间图像的产生,他那边就不清楚了。。。  都没找到要害。。。

论坛徽章:
0
16 [报告]
发表于 2012-09-05 09:38 |只看该作者
本帖最后由 adam_w2 于 2012-09-05 10:07 编辑

>>>目前我的做法就是针对疑似性能低下的部分手动安插计时器进行计时。

“手动安插计时器“非常不可取,很多时候,性能瓶颈的位置会出人意料的,特别是现代编译器做了大量工作的情况下。

建议用 gprof 或者 vs 类似的功能剖析,不要瞎蒙,浪费时间。

gprof 这类工具虽然插入了代码,和真实的运行情况稍有差异,但由于每个函数都增加了相同的负担,因此仍然能大
致上反映程序的热点。

我个人会经常对程序 gprof。

据说 Intel 的 VTune 使用 CPU 内部的性能寄存器监控运行状态,更精确,不侵入程序,不过个人没那么高的要求,
没用过。

论坛徽章:
0
17 [报告]
发表于 2012-09-05 12:23 |只看该作者
回复 15# OwnWaterloo


    我只知道gnu那套可以部署到Windows上,gprof应该可以用。但是有什么注意事项就不清楚了。

论坛徽章:
0
18 [报告]
发表于 2012-09-05 12:33 |只看该作者
回复 16# adam_w2


    你说的情况的确是这样的。不过目前我并没有打算去优化全部的地方,而且这个项目最大的瓶颈在哪我很清楚,可能并不单纯靠技巧就能优化。

这个项目是计算密集型的项目,只用到了C++标准库,系统库很少调用,很少IO,所以基本上看函数所在的调用层次以及频率就能估计出他的时间耗费。手动添加计时主要是为了验证自己的估计。如果能找到一个侵入性小的自动检测工具当然是最好了,目前用在这方面的时间预算不够,等下次优化时再弄。

论坛徽章:
0
19 [报告]
发表于 2012-09-05 12:50 |只看该作者
回复 15# OwnWaterloo


    我以前也做过图像处理,当时还是编程新手,只负责准备数据和显示结果,所以性能看都看的出来。一开始用GetPixel去获取图像的颜色,读取墙纸大小的图片就无法忍受了。后来才知道可以用GDI+直接获取图像的颜色数组。

后来做脚本解释器,里面用到大量的字符串,而且发现主要是字符串的存储和比较,于是弄了一张表存放所有读到的字符串,然后所有存储的字符串用编号代替,效率大大提高。仅这一项改进就优化掉了一大半的时间耗费。

这次的优化主要也是针对字符串,使用的技术还是那个。因为这次涉及到字符串的连接等操作,所以编号和原始字符串在很多地方混用,代码写得很混乱。这次把他们规整一下,能用编号就尽量用编号来表示字符串,又得到不少的性能提升。

现在这个优化方法已经被我用到目前来说的极限了,代码里出现的基本都是字符串编号了。再要继续优化得从结构设计入手了,目前没有思路。

论坛徽章:
0
20 [报告]
发表于 2012-09-05 15:59 |只看该作者
Windows...

GetTickCount 不知道linux
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP