精华内容
下载资源
问答
  • 主要给大家介绍了关于C++性能剖析教程之循环展开的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 计算机体系结构作业WINDLX处理器实验五循环展开矩阵向量乘法汇编程序
  • CPU 设计。胡伟武 cpu设计文档。
  • 我们可以使用许多概念,例如循环展开,循环嵌套优化等。 问题陈述 输入:两个N * N矩阵。 N = 2 ^ {K},其中K是自然数。 输出:长度为2N-1的数组。 样本输入/输出: 我必须执行的三个主要活动: 单线程DMM...
  • 循环展开实现实例

    2015-12-20 13:43:43
    完整实现了计算机体系结构中的循环展开,包括迭代复制、寄存器重命名、调度等
  • 循环展开

    千次阅读 2015-07-29 14:26:10
    循环展开:减少循环次数来提高程序性能。如果展开次数太多,反而会造成性能急剧下降。因为展开次数太多,那么运算过程中中间变量会很多,而计算机的寄存器个数是固定的,当变量个数超了寄存 器,那么变量只能存到栈...
    

    循环展开:减少循环次数来提高程序性能。如果展开次数太多,反而会造成性能急剧下降。因为展开次数太多,那么运算过程中中间变量会很多,而计算机的寄存器个数是固定的,当变量个数超了寄存

    器,那么变量只能存到栈中从而导致性能下降

    实例代码如下

    long long getSystemTime() {
            struct timeb t;
            ftime(&t);
            return 1000 * t.time + t.millitm;
    }
    
    int main()
    {
     	int                     * b_test_data = (int *)malloc(80000000*sizeof(int));
            int                       b_loop;
            long long                 b_begin, b_end, b_ttl = 0;
    
            for(b_loop = 0; b_loop < 80000000; b_loop++)
            {
                    b_test_data[b_loop] = 1;
            }
    
            b_begin = getSystemTime();
    
            for(b_loop = 0; b_loop < 80000000; b_loop++)
            {
                    b_ttl = b_ttl + b_test_data[b_loop];
            }
    
            b_end = getSystemTime();
    
            printf("time = %lu, b_ttl = %lu\n", b_end - b_begin, b_ttl);
            return 0;
    }

    执行结果:


    展开:

    int main()
    {
    	int                     * b_test_data = (int *)malloc(80000000*sizeof(int));
            int                             b_loop;
            long long               b_begin, b_end, b_ttl = 0;
    
            for(b_loop = 0; b_loop < 80000000; b_loop++)
            {
                    b_test_data[b_loop] = 1;
            }
    
            b_begin = getSystemTime();
    	
    	/*循环展开操作*/
            for(b_loop = 0; b_loop < 80000000 - 1; b_loop+=2)
            {
                    b_ttl = b_ttl + b_test_data[b_loop] + b_test_data[b_loop + 1];
            }
    
            for(; b_loop < 80000000; b_loop++)
            {
                    b_ttl = b_ttl + b_test_data[b_loop];
            }
    
            b_end = getSystemTime();
    
            printf("time = %lu, b_ttl = %lu\n", b_end - b_begin, b_ttl);
            return 0;
    }


    执行结果:


    展开全文
  • 代码执行流水之循环展开优化

    千次阅读 2020-05-12 17:57:07
    目录 引言 流水线定义 指令执行流水 指令流水图 循环展开优化 引言 详细的流水线分析大家可以参考:计算机体系结构——流水线技术(Pipelining)。本篇只是由探讨循环展开如何提高代码执行效率延申过来的,因此只...

    目录

    引言

    流水线定义

    指令执行流水

    指令流水图

    循环展开优化


    引言

    详细的流水线分析大家可以参考:计算机体系结构——流水线技术(Pipelining)本篇只是由探讨循环展开如何提高代码执行效率延申过来的,因此只说明基本的流水线定义以及关于循环展开的部分。

     

    流水线定义

    计算机中的流水线是把一个重复的过程分解为若干个子过程,每个子过程与其他子过程并行进行。由于这种工作方式与工厂中的生产流水线十分相似, 因此称为流水线技术,从本质上讲,流水线技术是一种时间并行技术。

     

    流水线工作设计

    • 基本思想:延伸重叠方式,使指令解释过程进一步细化,提高各部件的利用率,以提高指令执行速度
    • 理想目标:完成任务的时间与其中某个指令执行时间无关,只与指令执行的频率有关(假设一个任务有n个指令,将完成一个指令分为m个段,每段执行时间为△t ,则理想目标是完成任务的时间是T=m△t+(n-1)△t;当n >> m时,T=(n-1)△t。 指令执行频率为  1 / △t: 即 与m无关,只和指令执行的速度△t有关)

    指令执行流水

    取指:

      指令取指(InstrucTIon Fetch)是指将指令从存储器中读取出来的过程。

    译码:

      指令译码(InstrucTIon Decode)是指将存储器中取出的指令进行翻译的过程。经过译码之后得到指令需要的操作数寄存器索引,可以使用此索引从通用寄存器组(Register File,Regfile)中将操作数读出。

    执行:

      指令译码之后所需要进行的计算类型都已得知,并且已经从通用寄存器组中读取出了所需的操作数,那么接下来便进行指令执行(InstrucTIon Execute)。指令执行是指对指令进行真正运算的过程。譬如,如果指令是一条加法运算指令,则对操作数进行加法操作;如果是减法运算指令,则进行减法操作。

      在“执行”阶段的最常见部件为算术逻辑部件运算器(ArithmeTIc Logical Unit,ALU),作为实施具体运算的硬件功能单元。

    访存:

      存储器访问指令往往是指令集中最重要的指令类型之一,访存(Memory Access)是指存储器访问指令将数据从存储器中读出,或者写入存储器的过程。

    写回:

      写回(Write-Back)是指将指令执行的结果写回通用寄存器组的过程。如果是普通运算指令,该结果值来自于“执行”阶段计算的结果;如果是存储器读指令,该结果来自于“访存”阶段从存储器中读取出来的数据。

     

    指令流水图

    横坐标:表示时间,即各个任务或指令在流水线中 所在该时刻所对应的子过程

    纵坐标:表示某个任务或某条指令,即流水线依次 处理的任务或指令

     

    循环展开优化

         在流水线中,往往因为指令顺序安排不合理而导致CPU等待空转,产生延迟,影响流水线效率。

         解决办法:循环展开和指令调度

         前提假设:假设采用MIPS的5段整数流水线:

                          分支的延迟:1个时钟周期。

                          整数load指令的延迟:1个时钟周期。

                          整数运算部件是全流水或者重复设置了足够的份数。

         从例题入手理解

         例: 对于下面的源代码,转换成MIPS汇编语言, 在不进行指令调度和进行指令调度两种情况下,分析其代码一次循环所需的执行时间。

    for (i=1024; i>=0; i--)
         x[i] = x[i] + s;

      Loop:L.D F0,0(R1) 

         ADD.D F4,F0,F2

         S.D F4, 0(R1)

         DADDIU  R1,R1,#-8

         BNE R1,R2,Loop、

         其中:   整数寄存器R1:指向向量中的当前元素(初值为向量中最高端元素的地址)

                     浮点寄存器F2:用于保存常数s

                     第二部浮点加法需要4个周期

         分析:

         假设一个浮点计算部件需要4周期完成一个计算,若该部件不使用流水线,则延迟为 :

    循环展开:

          在上例中,只有L.D、ADD.D和S.D这3条指令是有效操作 (取、加、存) ,占用3个时钟周期。 而DADDIU、空转和BEN这3个时钟周期都是附加的循环控制开销。可以通过循环展开的方式消除冗余,减少循环控制开销

    • 循环展开技术

           把循环体的代码复制多次并按顺序排列,然后相应调整循环的结束条件

           这给编译器进行指令调度带来了更大的空间

     

         将上述例子中的循环展开3次得到4个循环体,然后对展开 后的指令序列在不调度和调度两种情况下,分析代码的性能。

         分配寄存器(不重复使用寄存器 ):

          F0、F4:用于展开后的第1个循环体

          F2:保存常数

          F6、F8:展开后的第2个循环体

          F10、F12:第3个循环体

          F14、F16:第4个循环体

         下面分三种情况比较循环展开和指令调度节省的时间:

    • 第一种情况:

         

    • 第二种情况:

          对指令序列进行优化调度,以减少空转周期

          浮点加法部件采用流水指令流出时钟

     

              

     

    • 第三种情况:

          对指令序列进行优化调度,以减少空转周期

          浮点运算部件不采用流水

         

    • 循环展开和指令调度时要注意以下几个方面:

           保证正确性。 在循环展开和调度过程中尤其要注意两个地方的正确性:循环控制,操作数偏移量的修改。

           注意有效性。 只有能够找到不同循环体之间的无关性,才能有效 地使用循环展开。

           使用不同的寄存器。 (否则可能导致新的冲突)

           删除多余的测试指令和分支指令,并对循环结束代码和新的循环体代码进行相应的修正。

           注意对存储器数据的相关性分析     

           注意新的相关性

      3.指令级并行

      指令调度可以通过两种形式实现:静态调度和动态调度

    • 静态调度

       依靠编译器(编译器需要做的很复杂,很完善)对代码进行静态调度,以减少相关和冲突。

       它不是在程序执行的过程中、而是在编译期间进行代码调度和优化。

       通过把相关的指令拉开距离来减少可能产生的停顿。

    •  动态调度

       在程序的执行过程中,依靠专门硬件对代码进行调度,减少数据相关导致的停顿。

       能够处理一些在编译时情况不明的相关(比如涉及到存储器访问的相关),并简化了编译器;

       能够使本来是面向某一流水线优化编译的代码在其他的流水线(动态调度)上也能高效地执行。

       以硬件复杂性的显著增加为代价

    展开全文
  • 优化循环的方法-循环展开

    千次阅读 2019-01-16 11:11:36
    循环展开是一种程序变换,通过增加每次迭代计算的元素的数量,减少循环的迭代次数。 用代码来说明就是将 for (i = 0; i &lt; len; i++) { sum += arry[i] } 替换为 for (i = 0; i &lt; len; i += 2) { ...

    更多文章

    循环展开是一种程序变换,通过增加每次迭代计算的元素的数量,减少循环的迭代次数。

    用代码来说明就是将

    for (i = 0; i < len; i++) {
    	sum += arry[i]
    }
    

    替换为

    for (i = 0; i < len; i += 2) {
    	newSum += arry[i] + arry[i + 1]
    }
    

    循环展开对于算术运算来说,优化的作用是很大的。我分别对整数运算和浮点数运算作了多次测试,得出表格如下:

    操作整数整数(优化后)浮点数浮点数(优化后)
    +360163354164
    -379167341177
    *350160364163
    /1185715263

    测试环境

    • cpu:i5-7400
    • 浏览器: chrome 70.0.3538.110

    运算是用了1千万个数,取值是运行十次测试得出的平均数。附上加法测试的代码

    const arry = []
    let num = 10000000
    while (num) {
    	arry.push(num)
    	num--
    }
    
    let sum = 0
    let last = new Date()
    let i 
    let len = arry.length
    for (i = 0; i < len; i++) {
    	sum += arry[i]
    }
    let now = new Date()
    
    console.log(now - last)
    
    let newSum = 0
    last = new Date()
    for (i = 0; i < len; i += 2) {
    	newSum += arry[i] + arry[i + 1]
    }
    now = new Date()
    
    console.log(now - last)
    console.log(sum, newSum)
    
    展开全文
  • 代码优化---循环展开

    千次阅读 2018-06-26 10:10:38
    发现了一个有意思名称-》循环展开,就搜索了下。   放一下搜索后的内容和自己的想法。   原文地址 代码细节的终极优化之循环展开、多路并行 void combine5(double data[],int length) {  double sum = 0.0;...

    今天在看阿里技术公众号的文章-》含代码 | 支付宝如何优化移动端深度学习引擎?发现了一个有意思名称-》循环展开,就搜索了下。

     

    放一下搜索后的内容和自己的想法。

     

    原文地址  代码细节的终极优化之循环展开、多路并行

    void combine5(double data[],int length)
    {
          double sum = 0.0;
          for(int i=0;i<length;i++)
          {
            sum *= data[i];
          }
          cout<<sum<<endl;
    }


    void combine6(double data[],int length)
    {
          double sum = 0.0;
          int limit = length-1;
          int i;
          for(i=0;i<limit;i+=2)
          {
               sum = sum*data[i]*data[i+1];
          }
          for(;i<length;i++)
          {
              sum *= data[i];
          }
          cout<<sum<<endl;
    }


    void combine7(double data[],int length)
    {
          double sum1=0.0,sum2=0.0;
          int limit = length-1;
          int i;
          for(i=0;i<limit;i+=2)
          {
                sum1 *= data[i]; // 合并下标为偶数的值, 0按偶数算
                sum2 *= data[i+1]; // 合并下标为奇数的值
          }
          double sum = sum1*sum2;
          for(;i<length;i++)
          {
               sum *= data[i];
          }
          cout<<sum<<endl;

    }

     

    原文作者的观点:

    combine5 做了简单的优化,combine6做了循环展开,combine7既循环展开又多路并行。若combine5运行时间为5,combine6运行时间就是2.5!combine7的运行时间就会使1!IA32后的指令集都会支持如此优化,但绝大多数编译器不会帮你把代码改写成这个样子,所以自己写是最好的。如果加上SSE,会把CPU的能力榨干。

     

     

    自己的看法:

    把代码流程梳理下 ,就是C5 单步 单业务操作,C6 单步多业务操作,C7 多步多业务操作。 在硬件条件不好或者业务计算量大的时候,就可以明显的发现差异和区别。

     

    我自己早两天也有相同类似的情况。不过在数据库相似的例子 ->(若有10000条数据需要实现插入操作)

    简单就是for insert 10000下。  类似  C5。

    如果将 多个 insert 插入合并成一个insert , 类似 C6

    如果将  多个insert  分两个insert。然后并行两个程序 同步插入。类似C7.

     

    有些东西与代码无关,在乎于思路、计算机底层或者原理性的东西。好的理念和思路具备广泛的通用性。

     

     

     

     

    展开全文
  • 关于 循环展开

    千次阅读 2019-04-03 23:09:44
    可以尝试在循环前面加上 #pragma unroll 的作用是提示CUDA编译器,表明这个循环将被自动展开
  • CUDA——性能优化之循环展开

    千次阅读 2020-02-24 01:21:05
    循环展开(#pragma unroll) 循环展开顾名思义就是将循环体展开。 全部展开或者展开一部分都可以有效提高性能。 以下是一个循环体 float sum=0; for(int i=0;i<n;++i) { sum+=a[i]; } 循环部分展开 for(int i=...
  • 在软件流水中应用循环展开可以实现分数值的启动间距,提高资源的利用率,同时基于展开的优化技术可以降低程序的资源需求和关键路径的长度 。 提出了基于程序特性的展开因子算法UTBPC(Unrolling Times Based Program ...
  • 当前 GCC 的主要优化都是基于 GIMPLE 表示形式实现的,包括过程间优化、传统标量优化、循环优化、向量化等。 GCC 的 all_passes 遍表中的 expand 过程将 GCC 的 GIMPLE 表示形式转化为另外一种表示形式 RTL。 ...
  • 目录 动态分支预测技术 概念 分支预测的有效性取决于 动态分支预测技术的目的 分支预测表 BHT 1个预测位 2个预测位 ...指令调度与循环展开 ...循环展开 ...循环展开和指令调度的注意事项 指令级并行总...
  • 循环展开技术

    千次阅读 2013-04-26 07:14:33
    循环展开技术转载:http://blog.chinaunix.net/uid-122937-id-2983686.html循环一直令我们头疼,因为循环体内总是隐藏着热点!请读者回顾上一小节中的示例代码。for(i = 0; i temp = temp * (array[i]); } ...
  • 这种方式就是把循环展开,据说可以提高性能,但测试效果不明显,在谷歌50中展开反倒变慢了,IE10这种变快了。看来实际使用中中还是需要测试测试代码: function doProcess(value1, value2) { return value1 + value...
  • 计算机系统结构实验-循环展开和指令调度.pdf
  •  loop unrolling 不同于内存优化(hardware accessing),这是一种指令级优化(software programming...如果说编程上For循环是一种以计算性能的打折作为代价来实现编程的简单化的编程思路,那么Loop unrolling将是一
  • 计算机系统结构实验,流水线中的相关,循环展开及指令调度,记分牌算法和Tomasulo算法,Cache性能分析,伪相联Cache与虚拟Cache(选做),LRU页面置换算法模拟(选做)
  • 上述最优循环展开代码调度是我们手工完成的,能够完成高效的调度是因为我们知道R1代表枚举变量,并知道R1-32前的-16(R1)和16(R1)指向的同一内存区域,但编译器确定对存储器引用却不是那么容易,如其无法确定: ...
  • 文章目录简介循环展开和粗化锁分析Assembly日志禁止Loop unrolling总结 简介 之前在讲JIT的时候,有提到在编译过程中的两种优化循环展开和粗化锁,今天我们和小师妹一起从Assembly的角度来验证一下这两种编译优化...
  • 程序优化之循环展开

    千次阅读 2015-07-24 09:56:20
    硬件环境:DSP TMS320C6670开发板 时钟频率:1.2GHz 注:该型号DSP具有两条数据通路和两套寄存器,在测试结果中会体现...版本4则充分利用了数据通路、流水线处理等,并减少了循环次数,因而性能更优越。
  • c++模板元编程三:循环展开

    千次阅读 2015-04-05 16:29:05
    2.2 loop unrolling 循环展开前面enum一节介绍的是和template联合,引发编译器递归的奇妙作用。template本身无需enum配合也可以达到递归的效果。// test template recursive for loop unrolling cout ...
  • 循环展开(Unroll loop) 的方法。 将上面的代码修改如下: Cvalue += ds_A[ty][0] * ds_B[0][tx]+ds_A[ty][1] * ds_B[1][tx] +ds_A[ty][2] * ds_B[2][tx]+ds_A[ty][3] * ds_B[3][tx] +ds_A[ty][4] *...
  • CUDA笔记2-循环展开

    千次阅读 2014-06-22 12:15:52
    #CUDA循环展开 --- ##串行循环展开  [loop unrolling](http://en.wikipedia.org/wiki/Loop_unwinding)是一种牺牲程序的尺寸来加快执行速度的优化方法。拿数组来说,数组的数据在内存中是连续存储的,...
  • 循环展开优化详议

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 141,131
精华内容 56,452
关键字:

循环展开