zoukankan      html  css  js  c++  java
  • C++ Low level performance optimize 2

      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 :1;
             bool b1 :1;
             bool b2 :1;
    }
    
    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 : 1;
             bool b1 : 1;
             bool b2 : 1;
             uint8_t i0 :3;
    }
    
    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总是被当做一个”对象” :)

     

  • 相关阅读:
    C# 关于替换SQL中某个字段的部分内容
    c# sharepoint client object model 创建工作流历史记录
    c# sharepoint client object model 创建文档库
    c# sharepoint client object model 创建列表库
    C# Windows Server 2016 IIS的安装与配置
    C# 判断当前请求是GET还是POST
    SQL 无法执行脚本
    SharePoint 2013 配置 -- 基于表单的身份认证
    C# 浏览器URL地址殊字符转义编码
    C# Session 只有在配置文件或 Page 指令中将 enableSessionState 设置为 true 时,才能使用会话状态。
  • 原文地址:https://www.cnblogs.com/clayman/p/3659312.html
Copyright © 2011-2022 走看看