VS2015性能分析过程

article/2025/9/24 2:12:04

原文转载于:https://blog.csdn.net/luoweifu/article/details/51470998

上一篇文章带你玩转Visual Studio——VC++的多线程开发讲了VC++中多线程的主要用法。多线程是提升性能和解决并发问题的有效途经。在商用程序的开发中,性能是一个重要的指标,程序的性能优化也是一个重要的工作。


找到性能瓶颈

二八法则适合很多事物:最重要的只占其中一小部分,约20%,其余80%的尽管是多数,却是次要的。在程序代码中也是一样,决定应用性能的就那20%的代码(甚至更少)。因此优化实践中,我们将精力集中优化那20%最耗时的代码上,这那20%的代码就是程序的性能瓶颈,主要针对这部分代码进行优化。

常见优化方法:

这部分我就不写,直接参见《性能调优攻略》,因为我没有自信能写出比这更好的。

如果不想这么深入地了解,看看《C++程序常见的性能调优方式》这篇文章也是不错的。

应用案例

我们以一个应用案例来讲解,以至于不会那么乏味难懂。

我们知道能被1和它本身整除的整数叫质数,假设1到任意整数N的和为Sn(Sn=1+2+3+…+n)。现在要求10000到100000之间所有质数和Sn。

可能你会觉得这问题不是So Easy吗!都不用脑袋想,咣当一下就把代码写完了,代码如下:

#include <iostream>
#include <windows.h>// 定义64位整形
typedef __int64 int64_t;// 获取系统的当前时间,单位微秒(us)
int64_t GetSysTimeMicros()
{// 从1601年1月1日0:0:0:000到1970年1月1日0:0:0:000的时间(单位100ns)
#define EPOCHFILETIME   (116444736000000000UL)FILETIME ft;LARGE_INTEGER li;int64_t tt = 0;GetSystemTimeAsFileTime(&ft);li.LowPart = ft.dwLowDateTime;li.HighPart = ft.dwHighDateTime;// 从1970年1月1日0:0:0:000到现在的微秒数(UTC时间)tt = (li.QuadPart - EPOCHFILETIME) / 10;return tt;
}// 计算1到n之间所有整数的和
int64_t CalculateSum(int n)
{if (n < 0){return -1;}int64_t sum = 0;for (int i = 0; i < n; i++){sum += i;}return sum;
}// 判断整数n是否为质数
bool IsPrime(int n)
{if (n < 2){return false;}for (int i = 2; i < n; i++){if (n %i == 0){return false;}}return true;
}void PrintPrimeSum()
{int64_t startTime = GetSysTimeMicros();int count = 0;int64_t sum = 0;for (int i = 10000; i <= 100000; i++){if (IsPrime(i)){sum = CalculateSum(i);std::cout << sum << "\t";count++;if (count % 10 == 0){std::cout << std::endl;}}}int64_t usedTime = GetSysTimeMicros() - startTime;int second = usedTime / 1000000;int64_t temp = usedTime % 1000000;int millise = temp / 1000;int micros = temp % 1000;std::cout << "执行时间:" << second << "s " << millise << "' " << micros << "''" << std::endl;
}
  • 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

然后一运行,耗时9s 659’ 552”(9秒659毫秒552微秒)。我想这肯定不是你要的结果(太慢了),如果你觉得还满意,那下面的就可以不用看了。

VS的性能分析工具

性能分析工具的选择

打开一个“性能分析”的会话:Debug->Start Diagnotic Tools Without Debugging(或按Alt+F2),VS2013在Analysis菜单中。 

性能分析 
性能分析

CPU Usage

检测CPU的性能,主要用于发现影响CPU瓶颈(消耗大量CPU资源)的代码。

GPU Usage

检测GPU的性能,常用于图形引擎的应用(如DirectX程序),主要用于判断是CPU还是GPU的瓶颈。

Memory Usage

检测应用程序的内存,发现内存。

Performance Wizard

性能(监测)向导,综合检测程序的性能瓶颈。这个比较常用,下面再逐一说明。

性能(监测)向导

  1. 指定性能分析方法; 
    性能分析方法 
    性能分析方法

    CPU Sampling(CPU采样): 
    进行采样统计,以低开销水平监视占用大量CPU的应用程序。这个对于计算量大的程序可大大节省监控时间。 
    Instrumentation(检测): 
    完全统计,测量函数调用计数和用时 
    .NET memory allocation(.NET 内存分配): 
    跟踪托管内存分配。这个好像只有托管代码(如C#)才可用,一般以C++代码好像不行。 
    Resource contention data(并发): 
    检测等待其他线程的线程,多用于多线程的并发。
  2. 选择要检测的模块或应用程序;
  3. 启动分析程序进行监测。

性能分析报告

程序分析完成之后会生成一个分析报告,这就是我们需要的结果。 

性能分析报告 
性能分析报告概要

视图类型

有几个不同的视图可供我们切换,下面加粗的部分是个人觉得比较方便和常用的视图。 
Summary(概要):整个报告概要说明 
Call Tree(调用树):以树形表格的方式展开函数之间的关系。 
Module(模块):分析调用的不同的程序模块,如不同的DLL、lib模块的耗时 
Caller/Callee(调用与被调用):以数值显示的调用与被调用的关系 
Functions(函数统计):以数值显示的各个函数的执行时间和执行次数统计值 
Marks(标记): 
Processers(进程): 
Function Detials(函数详情):以图表的方式形象地显示:调用函数-当前函数-被调用子函数之间的关系和时间比例。 


调用树 
调用树 
函数详情 
函数详情 
函数统计 
函数统计 

专用术语

如果是第一次看这报告,你还不一定能看懂。你需要先了解一些专用术语(你可以对照着Call Tree视图和Functions视图去理解): 
Num of Calls:(函数)调用次数 
Elapsed Inclusive Time:已用非独占时间 
Elapsed Exclusive Time:已用独占时间 
Avg Elapsed Inclusive Time:平均已用非独占时间 
Avg Elapsed Exclusive Time:平均已用独占时间 
Module Name:模块名称,一般为可执行文件(.exe)、动态库(.dll)、静态库(.lib)的名称。

也许看完你还迷糊,只要理解什么是独占与非独占你就都明白了。

什么是独占与非独占

非独占样本数是指的包括了子函数执行时间的总执行时间 
独占样本数是不包括子函数执行时间的函数体执行时间,函数执行本身花费的时间,不包括子(函数)树执行的时间。

解决应用案例问题

我们已经大致了解了VS2015性能分析工具的使用方法。现在回归本质,解决上面提及的应用案例的问题。

1、我们选择Function Detials视图,从根函数开始依据百分比最大的项选择,直到选择PrintPrimeSum,这时可以看到如下图: 

找出性能瓶颈1 
找出性能瓶颈1

我们可以看到IO占了50%多(49.4%+9.7%)的时间,所以IO是最大的性能瓶颈。其实,有一定编程经验的人应该都能明白,在控制台输出信息是很耗时的。我们只是需要结果,不一定非要在控制中全部输出(这样还不便查看),我们可以将结果保存到文件,这样也比输出到控制台快。

注:上图所示的时间,应该是非独占时间的百分比。

知道了瓶颈,就改进行代码优化吧:

void PrintPrimeSum()
{int64_t startTime = GetSysTimeMicros();std::ofstream outfile;outfile.open("D:\\Test\\PrimeSum.dat", std::ios::out | std::ios::app);int count = 0;int64_t sum = 0;for (int i = 10000; i <= 100000; i++){if (IsPrime(i)){sum = CalculateSum(i);outfile << sum << "\t";count++;if (count % 10 == 0){outfile << std::endl;}}}outfile.close();int64_t usedTime = GetSysTimeMicros() - startTime;int second = usedTime / 1000000;int64_t temp = usedTime % 1000000;int millise = temp / 1000;int micros = temp % 1000;std::cout << "执行时间:" << second << "s " << millise << "' " << micros << "''" << std::endl;
}
  • 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

再次执行,发现时间一下减小到:3s 798’ 218”。效果很明显!


2、但这还不够,继续检查别的问题,对新代码再次用性能分析工具检测一下。 

找出性能瓶颈2 
找出性能瓶颈2

我们发现IsPrime函数占用了62%的时间,这应该是一个瓶颈,我们能不能对其进行算法的优化?仔细想想,上面求质数的方法其实是最笨的方法,稍微对其进行优化一下:

// 判断整数n是否为质数
bool IsPrime(int n)
{if (n < 2){return false;}if (n == 2){return true;}//把2的倍数剔除掉if (n%2 == 0){return false;}// 其实不能被小于n的根以下的数整除,就是一个质数for (int i = 3; i*i <= n; i += 2){if (n % i == 0){return false;}}return true;
}
  • 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

再次执行,发现时间一下减小到:1s 312’ 75”,几乎减了一半的时间。

3、这还是有点慢,再看看还能不能进行优化。对新代码再次用性能分析工具检测一下。 

找出性能瓶颈2 
找出性能瓶颈2

CalculateSum函数占了88.5%的时间,这绝对是影响目前程序性能的主要因素。对其进行。仔细想想,求1到N的和其实就是求1、2、3 … N的等差数列的和。优化代码如下:

// 计算1到n之间所有整数的和
int64_t CalculateSum(int n)
{if (n < 0){return -1;}//(n * (1 + n)) / 2return ( n * (1 + n) ) >> 1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

再次执行,发现时间一下减小到:0s 91’ 6”,一秒中之内,基本上可以满足要求子。

总结

程序性能调优,就是数上面这样一点点地改进的过程,直到满足应用的要求。上面只用了一个视图的一种统计指标(各函数所用时间占总时间的百分比),就解决了问题。对于大型的复杂应用程序,我们可以结果多种视图的多种统计指标进行综合判断,找出程序性能的瓶颈!



http://chatgpt.dhexx.cn/article/NBMaHG0h.shtml

相关文章

吉林大学数据库系统概念2015年期末试题自做答案

简答题 1数据库中常用的完整性约束包括哪些&#xff1f; 答&#xff1a;not null unique check primary key foreign key 2简述数据库系统与文件系统的主要区别。 答&#xff1a;参考课本19页1.8 这两个系统都包含了数据集合和一组程序。数据库协调数据的物理和逻辑访…

2015年CSDN博客排名第一名,何方神圣?

2015年CSDN博客排名第一名&#xff0c;何方神圣&#xff1f; 一、引子&#xff1a; 话说博主phphot&#xff0c;雄霸天下好多年。 俱往矣&#xff0c; 落花流水春去也。 斗转星移&#xff0c;江山易主。 详细可以参见下文&#xff1a; CSDN博客排名第一名&#xff0c;何许人也 …

【转】85张PPT湖南2015年IPTV业务运营数据报告

导语 2015年&#xff0c;湖南IPTV以强势的芒果内容战略,精致的平台运营策略&#xff0c;流畅的技术产品体验&#xff0c;亲切的品牌市场形象&#xff0c;走进了248万个湖南家庭&#xff0c;全年收视次数高达42亿! 直播、回看、点播、综艺、影视、少儿&#xff0c;全屏加速&am…

传智播客 刘意_2015年Java基础视频-深入浅出精华版 笔记(2015年10月25日23:28:50)

day01 win 7系统打开DOS有趣方法&#xff1a;按住shift右键&#xff0c;单击“在此处打开命令窗口”(注意&#xff1a;在此处可以是任何的文件夹&#xff0c;不一定是桌面) 用DOS删除的文件不可以在回收站恢复&#xff1f;&#xff01;&#xff01; 常用DOS命令 d: 回车 盘符切…

2015 2020 r4烧录卡 区别_【2015年和2020年上半年市场资金结构有何差异?】东北证券金融工程择时周报20200802...

0摘要 观点综述&#xff1a;2017年以来公募基金摒弃了以往广撒网的方式&#xff0c;反而开始抱团&#xff0c;虽然基金发行、股票发行的数量增加&#xff0c;但是公募基金十大重仓股的个数却是不断降低的。这也就和我们当前的存量市场格局所呼应。在没有新增资金的存量格局之下…

VS2015+Qt5.8 联合配置

&#xff08;第一种&#xff09;VS2015Qt5.8 x86环境搭建 2018年10月16日 18:59:32 废柴Panda_M 阅读数&#xff1a;166 最近用一套别人的代码&#xff0c;发现库都是各种32位的&#xff0c;于是卸载了我辛辛苦苦下载的VS 2017和Qt5.9&#xff0c;重新弄。对应2017版本的Qt似…

2015年动画电影观影指南

整个2014年的全球动画电影市场比较平稳&#xff0c;在美国动画相对疲软的同时&#xff0c;亚洲的老牌动画强国日本与新兴崛起的中国&#xff0c;反而更为活跃&#xff0c;近30部国产动画在院线上映&#xff0c;《熊出没之夺宝熊兵》更是达到了2.47亿的票房。展望2015是超级大片…

2015年第六届C/C++ B组蓝桥杯省赛真题

这里是蓝桥杯历年的题目专栏&#xff0c;将会陆续更新将往年真题以及解答发布出来&#xff0c;欢迎各位小伙伴关注我吖&#xff0c;你们的点赞关注就是给我最好的动力&#xff01;&#xff01;&#xff01; 每天更新一届真题&#xff0c;敬请期待 蓝桥杯历年真题及详细解答 目…

纪念2015年大股灾:股票和分级基金呈现的一些哲理启示

一、之前遇到的励志表达式&#xff1a; 二、2015年千股涨停跌停那是司空见惯&#xff0c;下面是个连续跌停需要的连续涨停数量对比&#xff1a; 表明&#xff1a;持续的堕落&#xff0c;需要持续双倍的努力代价来挽回损失&#xff01;所以要注意风控&#xff0c;设置不管是股市…

NCU SEM 发文检索2015年

[1]何恩良,周莉.会计师事务所行业专长对审计质量的影响[J].中国商论,2015,27:49-51. 摘要&#xff1a;会计师事务所行业专长有利于提高审计质量。本文选择2013年沪深股市部分上市公司作为研究样本,通过回归分析验证了会计师事务所行业专长与审计质量正相关,并提出会计师事务所需…

2015数学建模国赛b题代码分析

所用代码出自2015年b285优秀论文,建模时可做参考 出租车数量 、 请求单数 、用户等待时间空间分布图 3D distributexlsread(20150906distribute.csv); Dis[]; m117; for i1:length(distribute) % 矩阵行和列的最大值 if (distribute(i,1)m1) [Dis][Dis; distribu…

2015年数模A题太阳影子定位学习笔记

To be continue … … 主要参考文献&#xff1a;[2015年国赛高教杯奖A题]电子科技大学-太阳影子定位的多目标优化模型 最近用java写了个求影长的程序&#xff0c;原地爆炸 文章目录 一、摘要二、问题重述1. 问题背景2. 需要解决的问题 三、问题分析3.1 问题一的分析3.2 问题二的…

互联网30年,泡沫如梦

人人都说互联网改变世界&#xff0c;这话没错。 但我认为互联网改变的方式&#xff0c;是泡沫。 资金&#xff0c;资源&#xff0c;人才因为一堆概念聚在一起&#xff0c;形成一个又一个的泡沫&#xff0c;然后泡沫破裂&#xff0c;大部分人失败&#xff0c;少数能够留下来的&a…

[机器学习] 半监督学习---伪标签Pseudo-Label

大数据时代中&#xff0c;在推荐、广告领域样本的获取从来都不是问题&#xff0c;似乎适用于小样本学习的伪标签技术渐渐淡出了人们的视野&#xff0c;但实际上在样本及其珍贵的金融、医疗图像、安全等领域&#xff0c;伪标签学习是一把锋利的匕首&#xff0c;简单而有效。 什么…

深度学习十大算法

首先先让我们来定义一下什么是“深度学习”。对很多人来说&#xff0c;给“深度学习”下一个定义确实很有挑战&#xff0c;因为在过去的十年中&#xff0c;它的形式已经慢慢地发生了很大的变化。 先来在视觉上感受一下“深度学习”的地位。下图是AI、机器学习和深度学习三个概念…

KBS 2021 | 联邦学习综述

目录 前言摘要1. 引言1.1 联邦学习的背景1.2 联邦学习面临的挑战 2. 相关工作2.1 联邦学习的定义 3. 联邦学习的分类3.1 数据划分3.1.1 横向联邦学习3.1.2 纵向联邦学习3.1.3 联邦迁移学习 3.2 隐私保护机制3.2.1 模型聚合3.2.2 同态加密3.2.3 差分隐私 3.3 可应用的机器学习模…

如何高效学习和阅读源码?

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;蚂蚁集团高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《EffectiveJava》独家解析》专栏作者。热门文章推荐&…

架构学习——ER图

一、什么是ER图&#xff1f; E-R图也称实体-联系图(Entity Relationship Diagram)&#xff0c;提供了表示实体类型、属性和联系的方法&#xff0c;用来描述现实世界的概念模型。 二、为什么要画ER图&#xff1f; 它是描述现实世界关系概念模型的有效方法。是表示概念关系模型…

Thingworx入门学习

Thingworx入门学习 前言thingworx入门总结 前言 Thingworx是啥&#xff1f;&#xff1f;&#xff1f; 基于物联网强大必入软件学习 thingworx的优点太多说些主要的 1.强大数据接入 2.数据分析 3.组态化模块化&#xff0c;二次开发节省成本快速开发 thingworx入门 提几点主线…

读后感:【许岑—如何成为有效学习的高手】

本博客的原创文章都是本人平时学习所做的笔记 。不要借鉴&#xff0c;不要参考 , 谢谢合作 本书关键词&#xff1a;适合自己、学习方法、短时间、注意力、解决难题、设定目标、名师