[移山之道 第九章]

9.4  VSTS 效能分析工具

啊,效能分析,Performance!这是每一个程序员都梦想的事儿,让自己的程序跑得又快又好,最好是比别的同学快一个数量级,别人的程序是O(N^2),而我的程序是O(n*logN),或者是O(N),这是多爽的一项成就呀!VSTS提供了方便的效能分析工具,让我们能很快地找到程序的效能瓶颈,从而能有的放矢,改进程序。下面我们看一个具体的例子。

和同学们的作业类似,有这样一道题:

写一个程序,分析一个文本文件中各个词出现的频率,并且把频率最高的10个词打印出来。

果冻很快用C#写好了程序,命名为WordFreq.exe,然后运行了一下,验证了正确性,程序的基本框架如代码清单9-3所示(全部程序可以在移山社区网站下载):

代码清单9-3  WordFreq程序,程序框架

DoIt()

{

ProcessFile()  //store all words in a big buffer

ProcessBuffer()  //calculate and store the frequency of each word

OutputResult()   //output top 10

}

ProcessBuffer()

{

GetOneWord()   //get one word from buffer

FreqOneWord()

}

FreqOneWord(word)

{

Find the word in the array list,

If (found)

Update the frequency

If (not found)

Add the word in the array list with frequency = 1

}

OutputResult()

{

ArrayList.Sort()   //sort the array

Output Top 10 entry;

}

文本文件大约是30KB~300KB大小。在运行效能分析之前,阿超让大家预计占用时间最多的是什么函数,或者哪些语句。大家众说纷纭,有的说是处理文件,因为I/O很花时间,有的说是排序,有的说是处理每个词。还有人建议应该把排序和处理每一个词同时进行,这样就能加快速度。

我们看看到底会是什么情况。第一步,要确保编译的程序是Release版本。然后在VS界面中选中Tools | Performance Tools | Performance Wizard(如图9-1所示)。

图9-1  效能分析,选择分析方法

我们看到可以选择两种分析方法:

(1)        抽样(Sampling)

(2)        代码注入(Instrumentation)

通俗地解释,抽样就是当程序运行时,Visual Studio时不时看一看这个程序运行在哪一个函数内,并记录下来,程序结束后,Visual Studio就会得出一个关于程序运行时间分布的大致的印象。这种方法的优点是不需要改动程序,运行较快,可以很快地找到瓶颈。但是不能得出精确的数据,代码中的调用关系(CallTree)也不能准确表示。

另一方面,代码注入就是将检测的代码加入到每一个函数中,这样程序的一举一动都被记录在案,程序的各个效能数据都可以被精准地测量。这一方法的缺点是程序的运行时间会大大加长,还会产生很大的数据文件,数据分析的时间也相应增加。同时,注入的代码也影响了程序真实的运行情况(这有点像量子物理学中的“测试的光线干扰了测试物体本身”的现象)。

我们一般的做法是,先用抽样的方法找到效能瓶颈所在,然后对特定的模块用代码注入的方法进行详细分析。

对程序进行效能分析,我们先要弄清下面这几个名词,如表9-1所示:

表9-1  效能分析的名词解释

名  词

含  义

调用者Caller

函数Foo()中调用了Bar(),Foo()就是调用者

被调用函数Callee

见上,Bar()就是被调用函数

调用关系树Call Tree

从程序的Main()函数开始,调用者和被调用函数就形成了一个树形关系——调用树

消逝时间Elapsed Time

从用户的角度来看程序运行所花的时间。当用户看到一个程序没有反应,用户并不知道程序此时是在运行自己的代码,还是被调度出去了,或者操作系统此时正在忙别的事情

应用程序时间Application Time

应用程序占用CPU的时间,不包括CPU在核心态时花费的时间

续表

名  词

含  义

本函数时间Exclusive Time

所有在本函数花费的时间,不包括被调用者使用的时间

所有时间Inclusive Time

包含本函数和所有调用者使用的时间

理解了上面的各种概念后,我们就不难理解“消逝的本函数时间(Elapsed Exclusive Time)”等其他组合名词所代表的概念了。

我们先进行抽样分析,在效能浏览器(Performance Explorer)中开始效能分析即可。

图9-2是WordFreq程序处理一个30KB的文本文件时的情况:

图9-2  用抽样的方法分析效能

大家可以看到最花时间的三个函数是:

WordFreq.Freq.FreqOneWord(string)

System.String.EqualsHelper(string,string)

System.Collections.ArrayList.get_Item(int32)

三个函数加起来占用了整个程序84%的时间。看来我们得分析为什么这三个函数会被调用得这么频繁,开销这么大了。

我们现在可以进行代码注入的分析,同样运行程序后,我们看看图9-3的调用树(Call Tree)报告。

图9-3  代码注入方法产生的效能报告

结合实际的代码(见代码清单9-4),可以看到在WordFreq. FreqOneWord函数中,究竟发生了什么:

代码清单9-4  FreqOneWord()

private void FreqOneWord(string w)

{

// see if we have a match, if not, add it to the end,

// then assign it initial frequency 1;

// if yes, inc the frequency by 1

for (int i = 0; i < m_wordList.Count; i++)

{

Frequency fi = (Frequency)m_wordList[i];

if (fi.str == w)

{

fi.n++;

return;

}

}

//now we have to append it to the end.

Frequency f = new Frequency();

f.str = w;

f.n = 1;

m_wordList.Add(f);

}

我们可以清楚地看到:

WordFreq.Freq.FreqOneWord(string)被调用了8 150次,说明有8 150个词被处理了。但是,System.Collections.ArrayList.Add(object)被调用了1 112次,说明有1 112个不同的词被加入到ArrayList中。下面三个函数被调用的次数相似,它们都花了很多的时间。

System.Collections.ArrayList.get_Count()

System.Collections.ArrayList.get_Item(int32)

System.String.op_Equality(string,string)

果冻:(大叫起来)当我写这一个语句的时候

for (int i = 0; i < m_wordList.Count; i++)

没想到m_wordList.Count,也就是ArrayList.GetCount(),会花这么多时间,累计被调用了1631884次!

我可以马上把代码改成:

int count = m_wordList.Count;

for (int i = 0; i < count; i++)

这样会如何?大家等了一会儿,代码分析的结果出来了(如图9-4所示):

图9-4  改进过的程序效能分析图

可以看到System.Collections.ArrayList.get_Count()的调用次数和时间都大幅度地下降了。

我们可以继续进行“效能测试,分析,改进,再效能测试”的流程,逐渐提高程序的效能和我们的编程水平。

大家也要注意避免没有做分析就过早地进行“效能提高”,刚才有人提到我们可能要提高排序的性能,但是从图9-4来看,System.Collections. ArrayList.Sort()只占了FreqOneWord()不到1/50的时间,如果我们不经分析就盲目优化,也许会事倍功半。

9.5  本章讨论

果冻:噫吁唏,危乎高哉!我以前一直害怕做效能分析,看来是否会用效能分析工具来提高程序质量是一个优秀程序员的标志之一。我在今天之前都是盲人骑瞎马。

小飞:改成盲人摸象更恰当。我听说,如果一个程序员从来没有用过效能分析工具,那他就不是一个程序员,只是一个编程爱好者罢了。

我的WC 程序事实上是最快的。但是在今天的程序评比之前,我想更进一步,就再优化了一下,估计能把速度提高2%。没想到出了一个小错误,导致报告的结果(行数、词数、字数)仅仅差了1。由于程序不正确,因此不能参加速度评比。我才是最需要大喊“噫吁唏”的人。

阿超:这有两个教训:

(1)先保证正确性,再提高效能。一个“仅仅差了1”的错误可能会导致缓冲区溢出(Buffer Overflow)的严重漏洞。

(2)如果效能的提高效果在5%以下,用户不会注意到程序效能的区别。所以要考虑那些微小的提高是否值得。

另外,WordFreq算法的时间复杂度是多少,能否再优化?请写实际程序加以验证。

荔荔:怎么才能快捷地得到有适量重复文字的文件,来帮助我们进行测试和效能分析?

九条:我是这样做的,在电脑的根目录下,运行“dir /s > c:\temp\test.txt”命令。

阿超:好主意,大家还有没有别的办法?

VS2012:

Visual Studio 2012 提供了更好的效能测试的功能, 请看这些博客:

  http://www.cnblogs.com/smart-code/archive/2012/09/23/2699053.html

  http://www.cnblogs.com/Gun-N-Rose/archive/2012/09/23/2699220.html

  http://www.cnblogs.com/bigbadwolf/archive/2012/09/24/2699438.html

  http://www.cnblogs.com/Gun-N-Rose/archive/2012/09/24/2699804.html

现代软件工程讲义 2 开发技术 - 效能分析相关推荐

  1. 现代软件工程讲义 2 开发技术 - 单元测试 amp; 回归测试

    [移山之道 第11章] 1单元测试 你的RP是由你的程序质量决定的. --阿超 这一章讲的是两人合作,既然程序是两个人写的,那就会出现一个人写的模块被另一个人写的模块调用的情况.很多误解.疏忽都发生在 ...

  2. 游戏外包开发技术难点分析

    游戏开发涉及多个领域的技术,因此在开发过程中可能会遇到很多技术难点.今天和大家分享一些常见的游戏开发技术难点,希望对大家开发游戏有一定帮助.北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流合 ...

  3. 现代软件工程讲义 7 开发 开发阶段的日常管理

    [移山之道 14 章] 14.6  开发阶段的日常管理 14.6.1  闭门造车(leave me alone) 荔荔:我今天真失败!在办公室里坐了10个小时,但是真正能花在开发工作上的可能只有3个小 ...

  4. 软件开发技术职位分析及职业规划

    分析 虽然说每个行业都必须要时刻学习,但软件行业技术的可持续性与积累性较差.例如:中医越做越吃香,而多年前的诺基亚开发已被抛弃. 严重青春饭 社交圈很难往上走 连续不离散的无意义学习 上升通道受限于运 ...

  5. 抖音账号矩阵系统|源码搭建开发技术部署分析

    抖音账号矩阵的主体逻辑是依据多个账号来分发不同的短视频到多个平台上,形成矩阵形式来做霸屏开发的技术工具.目前抖音账号矩阵开发,需要技术公司有一定的权限接口才能借助于官方平台来做开发,目前的视频发布权限 ...

  6. 服务外包技术培训——后端开发技术栈分析(Java)

    技术栈 http://www.atguigu.com/download.shtml 学习资源 https://space.bilibili.com/302417610/channel/detail?c ...

  7. 2017软件工程第三次作业--效能分析

    运行程序得出如下结果: 要求0 以 战争与和平 作为输入文件,重读向由文件系统读入.连续三次运行,给出每次消耗时间.CPU参数. 1. 2. 3. 要求1 给出你猜测程序的瓶颈.你认为优化会有最佳效果 ...

  8. 对我的学科方向软件工程开发技术方向的认识

    写于2007年9月 摘要 目前北京交通大学软件学院软件工程专业分为两个方向,即软件开发技术方向和数字媒体方向.我将要选择软件开发技术方向.软件开发技术方向的培养目标是: 培养学生掌握现代软件开发的过程 ...

  9. 客户端软件GUI开发技术漫谈:原生与跨平台解决方案分析

    原生开发应用开发 Microsoft阵营的 Winform WinForm是·Net开发平台中对Windows Form的一种称谓. 如果你想深入的美化UI,需要耗费很大的力气,对于目前主流的CSS样 ...

最新文章

  1. 用fieldset标签轻松实现Tab选项卡效果
  2. 软件开发---全套规范
  3. android button自定义样式详解,Android自定义格式显示Button的布局思路
  4. mybatis3 中 @Provider 的使用方式
  5. file_exists函数总是返回false
  6. 北妈每日一题:如何拿到 金条、蛋糕和大钻石
  7. 我在中关村,给不了的你爱的国贸(ZZ)
  8. 面试pythone_Python面试考题
  9. 如何导出共享文件夹的权限或转移
  10. 不能忽视 php warning
  11. android之添加raw文件
  12. 微信小程序上传图片失败总结
  13. 基于 Verilog 的经典数字电路设计(7)JK 触发器与 T 触发器
  14. 2055040-79-2,Acid-PEG5-TEMPO具有末端羧酸和TEMPO部分的PEG连接剂
  15. echarts3D地球点击事件无效
  16. Pom.xml文件教程详解
  17. 用计算机画有常数的函数图像,函数图像
  18. 华为中标广东电信IPTV项目
  19. 电脑进不去游戏显示重新连接服务器,幻塔无法连接服务器怎么办?游戏进不去解决方法...
  20. 2022暑期杭电第八场

热门文章

  1. phpmyadmin登陆错误:The requested URL /phpmyadmin was not found on this serve
  2. Java 装箱和拆箱
  3. javascript中setInterval,setTimeout的区别跟用法
  4. JavaScript获取URL参数
  5. sql server 模糊查询
  6. 数据结构——堆栈的C++实现
  7. 计算机网络概述(一)
  8. 关于宿主机没有Vmware虚拟网卡的问题分析与解决
  9. go 接口 构造器_Go 中接口值的复制
  10. sql加上唯一索引后批量插入_MySQL当批量插入遇上唯一索引