簡體   English   中英

Intel x64處理器上16位和32位乘法的CPU周期

[英]CPU cycles for 16 bit and 32 bit multiplications on Intel x64 processors

我正在C中實現一個數學庫,該數學庫大量使用乘法。 最初,我所有的乘法都是使用uint16_t完成的。 最近,我將其中許多更改為uint32_t並且看到我的代碼運行時幾乎翻了一番。 正如我在Intel x64處理器中所認為的那樣,我感到困惑,32位和16位乘法需要相同的時鍾周期。 我寫了診斷代碼,請在下面找到

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#include "cpucycles.c"

#define REPEAT 10000
#define OUT_REPEAT 100000

void main(){

    uint16_t a_16[REPEAT], b_16[REPEAT], c_16[REPEAT];
    uint32_t a_32[REPEAT], b_32[REPEAT], c_32[REPEAT];
    int32_t i,j;
    uint64_t clock1, clock2, CLOCK16, CLOCK32;
    uint64_t acc=0;
    time_t t;

    srand((unsigned) time(&t));

    clock1=clock2=CLOCK16=CLOCK32=0;

    for(j=0;j<OUT_REPEAT;j++){


        for(i=0;i<REPEAT;i++){

            a_16[i]=rand()& ( (1<<13) -1); //need 13-bit integers only
            b_16[i]=rand()& ( (1<<13) -1);

            a_32[i]=rand()&( (1<<19) -1);
            b_32[i]=rand()&( (1<<19) -1); //need 19-bit integers only
        }

        clock1=cpucycles();
        for(i=0;i<REPEAT;i++){
            c_16[i]=a_16[i]*b_16[i];
        }
        clock2=cpucycles();
        CLOCK16=CLOCK16+(clock2-clock1);    

        clock1=cpucycles();
        for(i=0;i<REPEAT;i++){
            c_32[i]=a_32[i]*b_32[i];
        }
        clock2=cpucycles();
        CLOCK32=CLOCK32+(clock2-clock1);    

        for(i=0;i<REPEAT;i++){
            acc=(acc+(c_32[i]-(uint32_t)c_16[i])); //this is just to prevent compiler optimization
        }
        printf("Iteration: %d,  acc:%llu\n", j, acc);
        acc=0;
    }

    printf("\n--------------------------------------------\n");
    printf("Time for 16 bit multiplication : %llu\n", CLOCK16/OUT_REPEAT);
    printf("Time for 32 bit multiplication : %llu\n", CLOCK32/OUT_REPEAT);
    printf("\n--------------------------------------------\n");
}

cpucycles代碼來自ECRYPT ,如下所示,

#include "cpucycles.h"

long long cpucycles(void)
{
  unsigned long long result;
  asm volatile(".byte 15;.byte 49;shlq $32,%%rdx;orq %%rdx,%%rax"
    : "=a" (result) ::  "%rdx");
  return result;
}

使用單核並禁用超線程/ TurboBoost的一次示例運行的結果

--------------------------------------------
Time for 16 bit multiplication : 2795
Time for 32 bit multiplication : 4190

--------------------------------------------

最后是lscpu給出的我的cpuinfo(摘錄)

Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Model name:            Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz

現在我的問題是

  1. 在x64平台上,與32位乘法相比,16位乘法占用總時間的一半是否正確? 或我做錯了什么。

  2. 如果是,您能給我一些參考來證明這種行為嗎?

先感謝您。 我感謝您的幫助。

在x64平台上,與32位乘法相比,16位乘法占用總時間的一半是否正確? 或我做錯了什么。

不,這本身是不正確的。 分別不是您實際測試過的。

您的短循環可輕松實現矢量化,因此這正是編譯器所做的。 根據目標CPU的生成,這意味着可以使用128、256或512位向量類型,可以將其划分為不同的字長(8位,16位,32位,64位,128位),然后可以對多個元素執行矢量化乘法一旦。 不僅是乘法,而且從內存到內存的數字加載和存儲都已完全向量化,並且不僅對單個元素進行運算。

簡而言之,與32位相比,同一向量中可以容納兩倍多的16位整數。 而且您的代碼實際上也不受乘法的限制-它受加載/存儲的限制,因此您僅成功地測量出16位整數的大小是32位整數的一半,因此在進行矢量化並由加載/存儲綁定時,您可以加載同時增加兩倍的元素。

如果希望對特定指令進行基准測試(在本例中為單元素乘法),則需要通過內聯匯編顯式使用該特定指令。 您還需要了解所有會影響性能的副作用和前提條件,流水線超標量體系結構通常對於基准測試而言並非微不足道。

否則,期望編譯器盡可能優化(向量化,折疊,內聯等)代碼。

暫無
暫無

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

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