当前位置: 首页 > 编程日记 > 正文

提高C++性能的编程技术笔记:跟踪实例+测试代码

当提高性能时,我们必须记住以下几点:

(1). 内存不是无限大的。虚拟内存系统使得内存看起来是无限的,而事实上并非如此。

(2). 内存访问开销不是均衡的。对缓存、主内存和磁盘的访问开销不在同一个数量级之上。

(3). 我们的程序没有专用的CPU,只能间歇地获得一个时间片。

(4). 在一台单处理器的计算机上,并行的线程并不是真正地并行执行,它们是轮询的。

“性能”可以有几种衡量标准,最常见的两种是空间效率和时间效率。空间效率标准寻求占用最小内存的软件解决方案。相似的,时间效率标准寻求占用最少处理器周期的解决方案。时间效率通常以响应时间和吞吐量来作为衡量标准。其它衡量标准还有编译时间和可执行文件的大小。

许多C++程序员在跟踪代码时通常的做法是,定义一个简单的Trace类将诊断信息打印到日志文件中。程序员可以在每个想要跟踪的函数中定义一个Trace对象,在函数的入口和出口Trace类可以分别写一条信息。尽管Trace对象将增加程序额外的执行开销,但是它能够帮助程序员找出问题而无须使用调试器。

最理想的跟踪性能优化的方法应该能够完全消除性能开销,即把跟踪调用嵌入在#ifdef块内。使用这种方法的不足在于必须重新编译程序来打开或关闭跟踪。还有一种选择:可以通过与正在运行的程序通信来动态地控制跟踪。Trace类能够在记录任何跟踪信息之前先检查跟踪状态。

影响C++性能的因素:I/O的开销是高昂的;函数调用的开销是要考虑的一个因素,因此我们应该将短小的、频繁调用的函数内联;复制对象的开销是高昂的,最好选择传递引用,而不是传递值。

内联对大块头函数的影响是无足轻重的。只有在针对那些调用和返回开销占全部开销的绝大部分的小型函数时,内联对性能的改善才有较大的影响。内联消除了常被使用的小函数调用所产生的函数开销。完美适合内联的函数就恰好是非常不适合跟踪的。

对象定义会触发隐形地执行构造函数和析构函数。我们称其为”隐性执行”而不是”隐性开销”是因为对象的构造和销毁并不总是意味产生开销。

通过引用传递对象还是不能保证良好的性能,所以避免对象的复制的确有利于提高性能,但是如果我们不必一开始就创建和销毁该对象的话,这种处理方式将更有利于性能的提升。

在完成同样的简单工作时,char指针有时可以比string对象更有效率。

以下是测试代码(the_tracing_war_story.cpp),分别有Trace1,Trace2,Trace3三个简单的类,它们的性能逐渐提高:

#include "the_tracing_war_story.hpp"
#include <string>
#include <iostream>
#include <chrono>namespace tracing_war_story_ {
//
// 较差的Trace1类设计
class Trace1 {
public:Trace1(const std::string& name);~Trace1();void debug(const std::string& msg);static bool traceIsActive;
private:std::string theFunctionName;
};inline Trace1::Trace1(const std::string& name) : theFunctionName(name)
{if (traceIsActive) {std::cout << "Enter function: " << name << std::endl;}
}inline Trace1::~Trace1()
{if (traceIsActive) {std::cout <<"Exit function: " << theFunctionName << std::endl;}
}inline void Trace1::debug(const std::string& msg)
{if (traceIsActive) {std::cout << msg << std::endl;}
}bool Trace1::traceIsActive = false; // 默认设置为false关闭跟踪;可以在test_tracing_war_story中设置是否开启还是关闭跟踪int addOne0(int x)
{return x+1;
}int addOne1(int x)
{std::string name = "addOne1";Trace1 t(name);return x+1;
}///
// Trace2类是对Trace1类的改进:将函数参数string类型调整为const char*
class Trace2 {
public:Trace2(const char* name);~Trace2();void debug(const char* msg);static bool traceIsActive;
private:std::string theFunctionName;
};inline Trace2::Trace2(const char* name) : theFunctionName(name)
{if (traceIsActive) {std::cout << "Enter function: " << name << std::endl;}
}inline Trace2::~Trace2()
{if (traceIsActive) {std::cout <<"Exit function: " << theFunctionName << std::endl;}
}inline void Trace2::debug(const char* msg)
{if (traceIsActive) {std::cout << msg << std::endl;}
}bool Trace2::traceIsActive = false; // 默认设置为false关闭跟踪;可以在test_tracing_war_story中设置是否开启还是关闭跟踪int addOne2(int x)
{char* name = "addOne2";Trace2 t(name);return x+1;
}/
// Trace3类是对Trace2类的改进:消除包含在Trace2类内的string成员对象的无条件的创建
class Trace3 {
public:Trace3(const char* name);~Trace3();void debug(const char* msg);static bool traceIsActive;
private:// string指针可以把string对象的创建推迟到确定跟踪处于打开状态以后std::string* theFunctionName;
};inline Trace3::Trace3(const char* name) : theFunctionName(nullptr)
{if (traceIsActive) {std::cout << "Enter function: " << name << std::endl;theFunctionName = new std::string(name);}
}inline Trace3::~Trace3()
{if (traceIsActive) {std::cout <<"Exit function: " << theFunctionName << std::endl;delete theFunctionName;}
}inline void Trace3::debug(const char* msg)
{if (traceIsActive) {std::cout << msg << std::endl;}
}bool Trace3::traceIsActive = false; // 默认设置为false关闭跟踪;可以在test_tracing_war_story中设置是否开启还是关闭跟踪int addOne3(int x)
{char* name = "addOne3";Trace3 t(name);return x+1;
}int test_tracing_war_story()
{Trace1::traceIsActive = false;/*Trace1实现就是一个无用对象对性能带来破坏性影响的实例:即创建和后面的销毁预计要使用却没有使用的不必要的对象在关闭跟踪情况下产生的开销:引发一系列计算:(1). 创建一个作用域为test_tracing_war_story的string型变量name(2). 调用Trace1的构造函数(3). Trace1的构造函数调用string的构造函数来创建一个string在此函数的结尾,Trace1对象和两个string对象被销毁:(1). 销毁string型变量name(2). 调用Trace1的析构函数(3). Trace1的析构函数为成员string调用string的析构函数在跟踪被关闭的情况下,string的成员对象从未被使用,Trace1对象本身也未被使用,所有这些用于对象的创建和销毁的计算都是纯碎的浪费*/std::string name = "test_tracing_war_story";Trace1 t(name);std::string moreInfo = "more interesting info";t.debug(moreInfo);using namespace std::chrono;high_resolution_clock::time_point timeStart, timeEnd;int count = 1000000;// 通过addOne0和addOne1测试Trace1对象的性能开销timeStart = high_resolution_clock::now();for (int i = 0; i < count; ++i) {addOne0(i);}timeEnd = high_resolution_clock::now();std::cout<< "addOne0 time spen: " <<(duration_cast<duration<double>>(timeEnd-timeStart)).count()<<" seconds"<<std::endl;timeStart = high_resolution_clock::now();for (int i = 0; i < count; ++i) {addOne1(i);}timeEnd = high_resolution_clock::now();std::cout<< "addOne1 time spen: " <<(duration_cast<duration<double>>(timeEnd-timeStart)).count()<<" seconds"<<std::endl;Trace2::traceIsActive = false;// 通过addOne2测试Trace2对象的性能开销timeStart = high_resolution_clock::now();for (int i = 0; i < count; ++i) {addOne2(i);}timeEnd = high_resolution_clock::now();std::cout<< "addOne2 time spen: " <<(duration_cast<duration<double>>(timeEnd-timeStart)).count()<<" seconds"<<std::endl;Trace3::traceIsActive = false;// 通过addOne3测试Trace3对象的性能开销timeStart = high_resolution_clock::now();for (int i = 0; i < count; ++i) {addOne3(i);}timeEnd = high_resolution_clock::now();std::cout<< "addOne3 time spen: " <<(duration_cast<duration<double>>(timeEnd-timeStart)).count()<<" seconds"<<std::endl;return 0;
}} // namespace tracing_war_story

执行结果如下:

GitHub:https://github.com/fengbingchun/Messy_Test

相关文章:

2019年不可错过的45个AI开源工具,你想要的都在这里

整理 | Jane 出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100)一个好工具&#xff0c;能提高开发效率&#xff0c;优化项目研发过程&#xff0c;无论是企业还是开发者个人都在寻求适合自己的开发工具。但是&#xff0c;选择正确的工具并不容易&#xff0c;有时这甚至是…

swift中delegate与block的反向传值

swift.jpg入门级 此处只简单举例并不深究&#xff0c;深究我也深究不来。对于初学者来说delegate或block都不是一下子能理解的&#xff0c;所以我的建议和体会就是&#xff0c;理不理解咱先不说&#xff0c;我先把这个格式记住&#xff0c;对就是格式&#xff0c;delegate或blo…

Direct2D (15) : 剪辑

为什么80%的码农都做不了架构师&#xff1f;>>> 绘制在 RenderTarget.PushAxisAlignedClip() 与 RenderTarget.PopAxisAlignedClip() 之间的内容将被指定的矩形剪辑。 uses Direct2D, D2D1;procedure TForm1.FormPaint(Sender: TObject); varcvs: TDirect2DCanvas;…

女朋友啥时候怒了?Keras识别面部表情挽救你的膝盖

作者 | 叶圣出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;【导读】随着计算机和AI新技术及其涉及自然科学的飞速发展&#xff0c;整个社会上的管理系统高度大大提升&#xff0c;人们对类似人与人之间的交流日渐疲劳而希望有机器的理解。计算机系统和机械人如果需要…

提高C++性能的编程技术笔记:构造函数和析构函数+测试代码

对象的创建和销毁往往会造成性能的损失。在继承层次中&#xff0c;对象的创建将引起其先辈的创建。对象的销毁也是如此。其次&#xff0c;对象相关的开销与对象本身的派生链的长度和复杂性相关。所创建的对象(以及其后销毁的对象)的数量与派生的复杂度成正比。 并不是说继承根…

swim 中一行代码解决收回键盘

//点击空白收回键盘 override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { view.endEditing(true) }

WinAPI: SetRect 及初始化矩形的几种办法

为什么80%的码农都做不了架构师&#xff1f;>>> 本例分别用五种办法初始化了同样的一个矩形, 运行效果图: unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls;typeTForm1 class(TForm)Butto…

Windows10上使用VS2017编译OpenCV3.4.2+OpenCV_Contrib3.4.2+Python3.6.2操作步骤

1. 从https://github.com/opencv/opencv/releases 下载opencv-3.4.2.zip并解压缩到D:\soft\OpenCV3.4.2\opencv-3.4.2目录下&#xff1b; 2. 从https://github.com/opencv/opencv_contrib/releases 下载opencv_contrib-3.4.zip并解压缩到D:\soft\OpenCV3.4.2\opencv_contrib-3…

swift 跳转网页写法

var alert : UIAlertView UIAlertView.init(title: "公安出入境网上办事平台", message: "目前您可以使用网页版进行出入境业务预约与查询&#xff0c;是否进入公安出入境办事平台&#xff1f;", delegate: nil, cancelButtonTitle: "取消", o…

智能边缘计算:计算模式的再次轮回

作者 | 刘云新来源 | 微软研究院AI头条&#xff08;ID:MSRAsia&#xff09;【导读】人工智能的蓬勃发展离不开云计算所带来的强大算力&#xff0c;然而随着物联网以及硬件的快速发展&#xff0c;边缘计算正受到越来越多的关注。未来&#xff0c;智能边缘计算将与智能云计算互为…

WinAPI: 钩子回调函数之 SysMsgFilterProc

为什么80%的码农都做不了架构师&#xff1f;>>> SysMsgFilterProc(nCode: Integer; {}wParam: WPARAM; {}lParam: LPARAM {} ): LRESULT; {}//待续...转载于:https://my.oschina.net/hermer/blog/319736

提高C++性能的编程技术笔记:虚函数、返回值优化+测试代码

虚函数&#xff1a;在以下几个方面&#xff0c;虚函数可能会造成性能损失&#xff1a;构造函数必须初始化vptr(虚函数表)&#xff1b;虚函数是通过指针间接调用的&#xff0c;所以必须先得到指向虚函数表的指针&#xff0c;然后再获得正确的函数偏移量&#xff1b;内联是在编译…

ICCV 2019 | 无需数据集的Student Networks

译者 | 李杰 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;本文是华为诺亚方舟实验室联合北京大学和悉尼大学在ICCV2019的工作。摘要在计算机视觉任务中&#xff0c;为了将预训练的深度神经网络模型应用到各种移动设备上&#xff0c;学习一个轻便的网络越来越重要。…

oc中特殊字符的判断方法

-(BOOL)isSpacesExists { // NSString *_string [NSString stringWithFormat:"123 456"]; NSRange _range [self rangeOfString:" "]; if (_range.location ! NSNotFound) { //有空格 return YES; }else { //没有空格 return NO; } } -(BOOL)i…

理解 Delphi 的类(十) - 深入方法[23] - 重载

为什么80%的码农都做不了架构师&#xff1f;>>> {下面的函数重名, 但参数不一样, 此类情况必须加 overload 指示字;调用时, 会根据参数的类型和个数来决定调用哪一个;这就是重载. }function MyFun(s: string): string; overload; beginResult : 参数是一个字符串: …

玩转ios友盟远程推送,16年5月图文防坑版

最近有个程序员妹子在做远程推送的时候遇到了困难&#xff0c;求助本帅。尽管本帅也是多彩的绘图工具&#xff0c;从没做过远程推送&#xff0c;但是本着互相帮助&#xff0c;共同进步的原则&#xff0c;本帅还是掩饰了自己的彩笔身份&#xff0c;耗时三天&#xff08;休息时间…

提高C++性能的编程技术笔记:临时对象+测试代码

类型不匹配&#xff1a;一般情况是指当需要X类型的对象时提供的却是其它类型的对象。编译器需要以某种方式将提供的类型转换成要求的X类型。这一过程可能会产生临时对象。 按值传递&#xff1a;创建和销毁临时对象的代价是比较高的。倘若可以&#xff0c;我们应该按指针或者引…

北美欧洲顶级大咖齐聚,在这里读懂 AIoT 未来!

2019 嵌入式智能国际大会即将来袭&#xff01;购票官网&#xff1a;https://dwz.cn/z1jHouwE随着海量移动设备的时代到来&#xff0c;以传统数据中心运行的人工智能计算正在受到前所未有的挑战。在这一背景下&#xff0c;聚焦于在远离数据中心的互联网边缘进行人工智能运算的「…

c# 关闭软件 进程 杀死进程

c# 关闭软件 进程 杀死进程 foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcessesByName("Server")){p.Kill();} 转载于:https://www.cnblogs.com/lxctboy/p/3999053.html

提高C++性能的编程技术笔记:单线程内存池+测试代码

频繁地分配和回收内存会严重地降低程序的性能。性能降低的原因在于默认的内存管理是通用的。应用程序可能会以某种特定的方式使用内存&#xff0c;并且为不需要的功能付出性能上的代价。通过开发专用的内存管理器可以解决这个问题。对专用内存管理器的设计可以从多个角度考虑。…

【Swift】 GETPOST请求 网络缓存的简单处理

GET & POST 的对比 源码&#xff1a; https://github.com/SpongeBob-GitHub/Get-Post.git 1. URL - GET 所有的参数都包含在 URL 中 1. 如果需要添加参数&#xff0c;脚本后面使用 ? 2. 参数格式&#xff1a;值对 参数名值 3. 如果有多个参数&#xff0c;使用 & 连接 …

深度CTR预估模型的演化之路2019最新进展

作者 | 锅逗逗来源 | 深度传送门&#xff08;ID: deep_deliver&#xff09;导读&#xff1a;本文主要介绍深度CTR经典预估模型的演化之路以及在2019工业界的最新进展。介绍在计算广告和推荐系统中&#xff0c;点击率&#xff08;Click Through Rate&#xff0c;以下简称CTR&…

2015大型互联网公司校招都开始了,薪资你准备好了嘛?

2015年的校招早就开始了&#xff0c;你还不知道吧&#xff1f;2015年最难就业季来了&#xff0c;你还没准备好嘛&#xff1f;现在就开始吧&#xff0c;已经很多大型互联网公司祭出毕业生底薪了看谷歌、看百度、看腾讯、看阿里巴巴再看传统软件公司&#xff1a;看微软、看联想、…

提高C++性能的编程技术笔记:多线程内存池+测试代码

为了使多个线程并发地分配和释放内存&#xff0c;必须在分配器方法中添加互斥锁。 全局内存管理器(通过new()和delete()实现)是通用的&#xff0c;因此它的开销也非常大。 因为单线程内存管理器要比多线程内存管理器快的多&#xff0c;所以如果要分配的大多数内存块限于单线程…

iOS中几种定时器

一、NSTimer 1. 创建方法 NSTimer *timer [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:selector(action:) userInfo:nil repeats:NO];TimerInterval : 执行之前等待的时间。比如设置成1.0&#xff0c;就代表1秒后执行方法target : 需要执行方法的对象…

手把手教你使用Flask轻松部署机器学习模型(附代码链接) | CSDN博文精选

作者 | Abhinav Sagar翻译 | 申利彬校对 | 吴金笛来源 | 数据派THU&#xff08;ID&#xff1a;DatapiTHU&#xff09;本文旨在让您把训练好的机器学习模型通过Flask API 投入到生产环境 。当数据科学或者机器学习工程师使用Scikit-learn、Tensorflow、Keras 、PyTorch等框架部署…

JQuery遮罩层

2019独角兽企业重金招聘Python工程师标准>>> css样式&#xff1a;<style type"text/css"> .mask { position: absolute; top: 0px; filter: alpha(opacity60); background-color: #777; z-index: 1002; left: 0px; …

代码覆盖测试工具Kcov简介及使用

Kcov是一个代码覆盖测试工具&#xff0c;最初基于Bcov&#xff0c;它可在FreeBSD、Linux、OSX系统中使用&#xff0c;支持的语言包括编译语言(compiled languages)、Python和Bash。与Bcov一样&#xff0c;Kcov对编译的程序使用DWARF调试信息&#xff0c;以便无需特殊编译器开关…

Google148亿元收购Fitbit,抢占苹果、三星可穿戴设备市场地盘

编译 | 夕颜出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;11 月 1 日&#xff0c;Google 母公司 Alphabet 和 可穿戴设备公司 Fitbit 同时发布新闻&#xff0c;宣布已经达成了收购后者的最终协议。Google LLC 以每股 7.35 美元的价格收购 Fitbit&#xff0c;总价值…

ios关于用xib创建的cell 自动返回cell的高度问题!

1 设置tableView的属性 self.tableView.rowHeight UITableViewAutomaticDimension; self.tableView.estimatedRowHeight 44.0; // 设置为一个接近“平均”行高的值 2 cell要约束好&#xff0c;要能够让cell知道自己的高度根据哪个控件计算就可以&#xff08;不明白看下图&…