《深刻理解计算机系统》读书笔记:5.5 vs 5.6

0x00 前言

没有看过或者没有看到这里的小伙伴们,看到这个标题必定以为摸不着头脑。那这里就先来解释一下背景。函数

double poly(double a[], double x, long degree)
{
    long i;
    double result = a[0];
    double xpwr = x;
    for (i = 1; i <= degree; i++) {
        result += a[i] * xpwr;
        xpwr = x * xpwr;
    }
    return result;
}
double polyh(double a[], double x, long degree)
{
    long i;
    double result = a[degree];
    for (i = degree; i >= 0; i--) {
        result = a[i] + x * result;
    }
    return result;
}

这是 CSAPP 的两道题,每一题是一段代码,这两段代码实现了同一个功能。这两道题有一个共同的问题,比较这两段代码的性能。性能

0x01 答案

这里的答案是,poly 的性能比 polyh 的性能要高。poly 的 CPE 是 5,而 polyh 的 CPE 是 8。code

这就显得很尴尬了,我原觉得两个函数的 CPE 都是 8。class

0x02 个人猜测

polyh 的 CPE 是 8 我没有疑问,由于这个循环里的操做是没法并行的,也就是下一次迭代会依赖上一次迭代产生的结果。因此,CPE = 5 + 3,5 是浮点数乘法的延迟下届,3 是浮点数加法的延迟下界。效率

poly 的 CPE 我本来认为也是 8,两个乘法是能够并行的,可是这个加法的是依赖于第一个乘法的值,没法并行,因此 CPE = 5 + 3 = 8。循环

0x03 指令集并行和流水线

上面的是个人猜测,因此我认为这里的答案是它们的 CPE 是相同的,性能也是相同的。可是如前面所写,答案并非这样的。因而,我把以前看的东西都翻出来想了一下,真的不是这样的。并行

现代 CPU 是有一个流水线的概念的。什么是流水线呢,想象一下汽车车间,咱们造一辆汽车,是分红了不少道工序的,好比装配发动机、装车门、轮子等等。现代 CPU 也是相似的,咱们看到的一条指令,在执行的时候,经历了一长串的流水线,致使了指令真正的执行顺序和咱们看到的多是不同的,可是因为现代出来的这种机制,能够确保最后的结果是和咱们看到的是同样的。总结

0x04 解释

poly 函数,在执行的时候,因为有两个浮点数乘法单元,因此 a[i] * xpwrxpwr = x * xpwr 能够并行执行。而 a[i] * xpwr 能够经过流水线的数据转移,让这个加法 result + a[i] * xpwr 能够在下一次迭代的时候执行,由于每次迭代的时候,两个乘法都不会依赖 result 这个结果。这样,加法和乘法能够并行执行。浮点乘法的延迟下界是 5,浮点加法的延迟下界是 3,因此浮点乘法是关键路径,CPE 也天然就是 5 了。数据

再来看看 polyh 函数。这个函数的循环里只有一个浮点乘法运算和一个浮点加法运算。先来看看浮点乘法运算,x * result,很显然,每一次乘法都须要依赖上一次迭代的结果,致使了加法没法和乘法并行执行。因而,CPE 就成了 5 + 3 = 8 了。计算机

0x05 最后

这个例子,我以为颇有趣,由于它涉及到了一个流水线的细节。同时,也说明了,并非操做少的代码,效率就高。

本文为做者本身读书总结的文章,因为做者的水平限制,不免会有错误,欢迎你们指正,感激涕零。

0x06 参考文献

《深刻理解计算机系统(第 3 版)》第 四、5 章

相关文章
相关标签/搜索