簡體   English   中英

不同運營商的執行時間

[英]Execution time of different operators

我正在閱讀Knuth的計算機編程藝術,我注意到他指出DIV命令比他的MIX匯編語言中的ADD命令長6倍。

為了測試與現代架構的相關性,我編寫了以下代碼片段:

#include <time.h>
#include <stdio.h>
#include <stdlib.h>


int main(int argc, char *argv[])
{
    clock_t start;
    unsigned int ia=0,ib=0,ic=0;
    int i;
    float fa=0.0,fb=0.0,fc=0.0;
    int sample_size=100000;

    if (argc > 1)
        sample_size = atoi(argv[1]);

#define TEST(OP) \
    start = clock();\
    for (i = 0; i < sample_size; ++i)\
        ic += (ia++) OP ((ib--)+1);\
    printf("%d,", (int)(clock() - start))
    TEST(+);
    TEST(*);
    TEST(/);
    TEST(%);
    TEST(>>);
    TEST(<<);
    TEST(&);
    TEST(|);
    TEST(^);
#undef TEST

//TEST must be redefined for floating point types
#define TEST(OP) \
    start = clock();\
    for (i = 0; i < sample_size; ++i)\
        fc += (fa+=0.5) OP ((fb-=0.5)+1);\
    printf("%d,", (int)(clock() - start))
    TEST(+);
    TEST(*);
    TEST(/);
#undef TEST

    printf("\n");
    return ic+fc;//to prevent optimization!
}

然后,我使用此命令行生成了4000個測試樣本(每個樣本包含每種類型的100000個操作的樣本大小):

for i in {1..4000}; do ./test >> output.csv; done

最后,我用Excel打開了結果並繪制了平均值。 我發現的是相當令人驚訝的。 以下是結果圖: 結果圖

實際平均值(從左到右):463.36475,437.38475,806.59725,821.70975,419.56525,417.85725,426.35975,425.9445,423.792,549.91975,544.11825,543.11425

總的來說這是我的預期(除法和模數都很慢,浮點結果也是如此)。

我的問題是:為什么整數和浮點乘法的執行速度都比其對應的快? 這是一個很小的因素,但它在許多測試中都是一致的。 在TAOCP中,Knuth將ADD列為2個單位時間,而MUL取10個。從那時起,CPU架構發生了什么變化?

不同的指令在同一CPU上占用不同的時間; 並且相同的指令可能在不同的CPU上花費不同的時間。 例如,對於英特爾最初的Pentium 4移位相對昂貴且加法速度相當快,因此向寄存器添加寄存器比將寄存器移位1更快; 對於英特爾最近的CPU,移位和添加速度大致相同(移位速度比原來的奔騰4速度快,並且在“循環”方面加速較慢)。

更復雜的是,不同的CPU可能能夠同時執行更多或更少的操作,並且具有影響性能的其他差異。

理論上(並不一定在實踐中):

移位和布爾運算(AND,OR,XOR)應該是最快的(每個位可以並行完成)。 接下來應該是加法和減法(相對簡單,但由於從一對位到下一位的進位,所以結果的所有位都不能並行完成)。

乘法應該慢很多,因為它涉及許多添加,但其中一些添加可以並行完成。 對於一個簡單的例子(使用十進制數字而不是二進制),像12 * 34(有多個數字)的東西可以分解成“單個數字”形式,變成2 * 4 + 2 * 3 * 10 + 1 * 4 * 10 + 1 * 3 * 100; 所有“單位”乘法可以並行完成,然后可以並行完成2次加法,然后可以完成最后一次加法。

分工主要是“比較和減去,如果更大,重復”。 它是最慢的,因為它不能並行完成(下一次比較需要減法的結果)。 模數是除法的余數,與除法基本相同(對於大多數CPU來說,它實際上是相同的指令 - 例如, DIV指令給出了商和余數)。

對於浮點; 每個數字都有2個部分(有效數和指數),因此事情變得復雜一些。 浮點移位實際上是增加或減去指數(並且應該與整數加法/減法大致相同)。 對於浮點加法,減法和布爾運算,您需要均衡指數,然后單獨對有效位數進行操作(並且“均衡”和“執行操作”不能並行完成)。 乘法是乘以有效數並添加指數(並調整偏差),其中兩個部分可以並行完成,因此總成本是最慢的(乘以有效數); 所以它和整數乘法一樣快。 除法是划分有效數並減去指數(並調整偏差),其中兩個部分可以並行完成,總成本是最慢的(划分有效數); 所以它和整數除法一樣快。

注意:我在各個地方進行了簡化,以便更容易理解。

要測試執行時間,請查看匯編列表中生成的指令,並查看處理器的文檔以獲取這些指令,並注意FPU是執行操作還是直接在代碼中執行。

然后,將每條指令的執行時間相加。

但是,如果cpu是流水線或多線程的,則操作可能比計算的時間少很多。

確實,除法和模(除法運算)比加法慢。 這背后的原因是ALU(算術邏輯單元)的設計。 ALU是並行加法器和邏輯電路的組合。 通過重復減法執行除法,因此需要更多級別的減法邏輯使得除法比加法更慢。 分裂中涉及的門的傳播延遲增加了蛋糕上的櫻桃。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM