C++ Low level performance optimize 2

上一篇 文章讨论了一些底层代码的优化技巧,本文继续讨论一些相关的内容。

首先,上一篇文章讨论cache missing的重要性时,用了list做比较,目的并不是说list没有用,而是说明cache missing会对性能有重要影响。如果元素不多,并且对象复制的代价很大,那么list可能就是更好的选择。其次,这里讨论的大部分是编码时一些比较底层的技巧,当遇到性能问题时,应该先考虑是否能在高层改进算法,减少运算,实在不行,在考虑这类优化技巧。性能优化的挑战就在于没有完美的永远适用的方案,了解这些技巧让我们在优化代码时有更多武器,但最终选择哪个方案还需要更加实际情况,并且以profile的实际数据为依据来做。

1.  Data Layout

调整数据布局是常见的优化手段,做此类优化时有几点需要注意:首先是内存占用,现代编译器默认大多以16或32位对齐,因此

struct BadLayout
{
int8_t i0;
int32_t i1;
int8_t i2;
}; struct GoodLayout
{
int8_t i0;
int8_t i2;
int32_t i1;
};

sizeof(Goodlayout) >= sizeof(BadLayout) 在vs2013默认对齐设置下,BadLayout==12 byte,GoodLayout==8byte。

其次,经常访问或者相关的数据应该放到一起,减少cache missing。Going native2013 Andrei Alexandrescu介绍了facebook做的重要性能优化就是把php代码编译为c++代码,而在代码转换中重要的一步就是根据数据的”hotness”重新布局。

struct BadLayout
{
auto user0_data0;
auto user1_data1;
auto user0_data1;
auto user1_data0;
}; struct GoodLayout
{
auto user0_data0;
auto user0_data1;
auto user1_data0;
auto user1_data1; };

最后,可维护性!这一点非常重要,对于一些生命周期较长的项目来说,把数据按逻辑组织更易于维护,减少潜在bug的重要性,如果性能差别不大,我通常更愿意让代码看起来好读J

2.  Code cache

struct BitBool
{
bool b0 :;
bool b1 :;
bool b2 :;
} struct NormalBool
{
bool b0;
bool b1;
bool b2;
}

上次的例子中,这段代码比较有争议,让我们从时间和空间方面来分析。时间上,因为BitBool需要额外指令来访问元素,因此效率一定比NormalBool低,但差别非常小,几乎可以忽略。再看空间上,但从结构本身看,显然BitBool更小,但是由于访问元素需要额外指令,实际应用中,生成的代码一定比NormalBool多,读取访问的次数越多,生成的代码也越多(内联的结果),而代码也需要占用内存空间!!cache line中通常一半是代码,一半是数据。因此,不一定因为BitBool本身小就得到更好的cache。大部分文章在讨论cache missing时都只介绍了数据,而忽略了代码也需要占用内存,也会有cache missing。某些游戏引擎会在update entity时先把对象按照类型排序,就是为了减少代码的cache missing。

最后,这个例子的目的是让大家了解过度优化可能并不会带来性能提升,实际应用中两种写法的虽然有性能差距,但基本可以忽略。

 3.  more about bit field

上一个例子让我想起了bitfield另一个微妙的地方,假设f1和f2在两个不同线程中,考虑下面代码是安全的吗?

struct BitField
{
bool b0 : ;
bool b1 : ;
bool b2 : ;
uint8_t i0 :;
} BitField bf;
std::mutex mtx1;
std::mutex mtx2;
//thread 1
void f1()
{
mtx1.lock();
bf.b1 = somevalue;
mtx1.unlock();
}
//thread 2
void f2()
{
mtx2.lock();
bf.i0 = somevalue;
mtx2.unlock();
}

No!!!虽然代码可以通过编译运行,但却并不是线程安全的,因为b1,i0都属于同一快内存”单元”,因此根本无法生成只更新b1,但是不写入i0的代码!!实际上c++11明确指出了这种情况会导致race,临近的bit总是被当做一个”对象” :)

最新文章

  1. Git 仓库和记录操作到仓库
  2. UVALive 2191 Potentiometers (树状数组)
  3. timer.scheduleAtFixedRate和timer.schedule的实验
  4. UWP开发入门(十八)——使用ContentControl减少页面元素数量
  5. Effective Java 57 Use exceptions only for exceptional conditions
  6. Linux_查看进程
  7. 64位系统下注册32位dll文件
  8. android121 zhihuibeijing SlidingMenu(侧边栏效果,使用开源库)
  9. perl 函数回调 引用$client->run(sub {$client->sync});
  10. href与src 区别
  11. [Codeforces 940E]Cashback
  12. Linux AIDE(文件完整性检测)
  13. 常用的三种json软件的使用
  14. Linux Shell函数返回值
  15. 利用ant脚本 自动构建svn增量/全量 系统程序升级包【转】
  16. Java 接口关键字 interface
  17. 【BZOJ】【3339】Rmq Problem
  18. "portrait"(竖屏) "landscape"(横屏) css设置
  19. 003 python流程控制与函数
  20. unity如何停止不用字符串方式开启协程的方法

热门文章

  1. create mystic by Django
  2. paip.微信菜单直接跳转url和获取openid流程总结
  3. 如何安装、配置Apache
  4. EWM 强大的数据修复功能
  5. ImageEdit 加载图片
  6. 如何利用OCS缓存TomcatSession全局变量(转)
  7. 设置360调用样式 IE调用样式
  8. mysql自动化安装
  9. LINUX系统下添加映射存储LUN
  10. windows 2003服务器网络异常流量的处理办法