2017-2018-1 20155214 《信息安全系统设计基础》第14周学习总结

2017-2018-1 20155214 《信息安全系统设计基础》第14周学习总结

教材第5章学习内容总结

咱们描述许多提升代码性能的技术。理想的状况是编译器可以接受咱们编写的任何代码并产生尽量高效的、具备指定行为的机器级程序现代编译器采用了复杂的分析和优化方式并且变得愈来愈好,然而即便是最好的编译器也受到了妨碍优化因素的阻碍。程序员必须编写容易优化的代码,帮助编译器。html

总结本章新收获

  • 5.1 优化编译器的能力和局限性
    在只执行安全的优化中编译器必须假设不一样的指针可能会指向内存中的同一个位置。

两个指针可能指向一个内存位置称为 内存别名使用git

void twiddle1(long *xp,long *yp){
    *xp += *yp;
    *xp += *yp;
}

当考虑指针 xp 和 yp 指向相同内存地址时,该函数可能产生二义性,及xp值翻了4倍程序员

当函数修改全局变量等 反作用 时,可能会妨碍优化。
那么算法

long counter = 0;

long func1opt(){
    long t = 4 * counter + 6;
    counter += 4;
    return t;
}

经过内联替换函数调用
显然优于

long func1in(){
    long t = counter++;
    t += counter++;
        t += counter++;
            t += counter++;
            return t;
}
  • 每元素的周期数CPE
void psum2(float a[],float p[],long n)
{
    long i;
    p[0] = a[0];
    for(i = 1;i < n-1;i += 2){
        float mid_val =p[i-1] + a[i];
        p[i] = mid_val;
        p[i+1] = mid_val + a[i+1];
    }
    
    if(i < n)
    p[i] = p[i-1] + a[i];
}

当使用for循环迭代计算前置和。每次调用函数都会执行创建栈帧和恢复栈帧,这一段代码的耗时是一个定值S。随着循环次数n的变化,总的耗时T=S + n*L,其中L为for循环的单位循环执行时间,在本书中又称做每元素周期数CPE。数组

上述代码的运行时间近似于 368+6.0n ,所以psum2的CPE为6.0。安全

  • 未经优化的代码是从C到机器代码的直接翻译,一般效率明显较低。简单地使用 -O1 ,就会进行基本的优化。显著地提高程序性能。
  • 经过移动要执行屡次可是计算结果不会改变的计算,称为代码移动。能够帮助编译器进行优化。
void combine4(vec_ptr v,data_t *dest){
    long i;
    long length = vec_length(v);
    data_t *data = get_vec_start(v);
    data_t acc = IDENT;
    
    for(i = 0;i < length;i++){
        acc = acc + data[i];
    }
    *dest = acc;
}

经过将循环中的累计结果放在临时的局部变量中,能够消除每次循环迭代没必要要的内存读写
  • 乱序处理
    目前的高级处理器,为了提升内部逻辑元件的利用率以提升运行速度,一般会采用多指令发射、乱序执行等各类措施。如今广泛使用的一些超标量处理器一般可以在一个指令周期内并发执行多条指令。
    从编译器的角度来看,编译器可以对很大一个范围的代码进行分析,可以从更大的范围内分辨出能够并发的指令,并将其尽可能靠近排列让处理器更容易预取和并发执行,充分利用处理器的乱序并发功能。因此现代的高性能编译器在目标码优化上都具有对指令进行乱序优化的能力。而且能够对访存的指令进行进一步的乱序,减小逻辑上没必要要的访存,以及尽可能提升 Cache命中率和CPU的LSU(load/store unit)的工做效率。因此在打开编译器优化之后,看到生成的汇编码并不严格按照代码的逻辑顺序是正常的。

  • 5.8循环展开

若是计算循环索引和测试循环条件的循环开销部分所占比重过大,这时就能够考虑使用一种被称做"循环展开"的方式来优化代码。所谓循环展开就是经过在每次迭代中执行更多的数据操做来减少循环开销的影响。其基本思想是设法把操做对象线性化,而且在一次迭代中访问线性数据中的一小组而非单独的某个。这样获得的程序将执行更少的迭代次数,因而循环开销就被有效地下降了。数据结构

循环展开技术的好处在于它能减少循环开销的影响。但它也不是没有缺点的,天下没有免费的午饭!首先,循环展开增长了生成的目标代码的数量,这很容易理解,由于循环体在源代码级别就已经变得庞大。读者能够试想它们被翻译成目标代码时的状况。为了验证这一点,读者可使用Visual C++来对比使用循环展开先后循环体的汇编代码的长度,验证结果将代表循环展开对目标代码的长度的确有很大的影响。固然,在咱们所举的例子中,循环展开所要付出的代价都是比较小的。固然这并不能归纳其余全部的状况,所以这个空间换时间的折中最优位置还须要针对具体问题来作具体的分析。 使用循环展开时一方面要考虑实际待处理数组的长度,并由此选择一个较好的展开度;另外一方面要综合考虑这个展开度对时空开销比例的影响,在尽可能不会使目标代码空间消耗激增的前提下得到最高的时间收益。另外,也可让编译器为咱们完成这些工做。一般,编译器能够很容易地执行循环展开,但这须要设定其优化级别足够高,因此程序员也能够选择让编译器来完成这个工做。固然,咱们曾经提醒过读者,在开发阶段并不适合将优化级别设置得太高,所以若是你但愿让编译器执行循环展开,那么最好等到软件开发完成以后。并发

for(i=0;i<limit;i+=2){
    acc = (acc OP data[i]) OP data[i+1];
}
经过减小循环次数,减小关键路径上的操做数量。
  • 从新结合变换
for(i=0;i<limit;i+=2){
    acc = acc OP (data[i] OP data[i+1]);
}
经过从新结合变换,提升程序并行性。

结对学习搭档讲解问题

  • 什么是amdahl定律?

想要大幅提升整个系统的速度,必须提升整个系统很大一部分的速度。取决于这个部分有多么重要和速度提升了多少。函数

  • 编写高效程序须要几类活动?
  1. 必须选择一组合适的算法和数据结构;
  2. 必须编写出编译器能有效优化以转换成高效可执行代码的源代码。
  3. 针对处理运算量特别大的计算,将一个任务分红多个部分,这些部分能够在 多核和多处理器的某种组合上并行地计算。

结对学习搭档连接

博客园连接:http://www.cnblogs.com/LeeX1997/性能

结对学习照片

其余(感悟、思考等,可选)

经过本周的再次学习,让我对于如何编写高效代码有了进一步理解。
更重要的是,对于 高级语言-编译器-处理器 之间的关系更明确了。

代码托管

参考资料

相关文章
相关标签/搜索