簡體   English   中英

我的CPU可以在每個CPU周期執行多個NOP嗎?

[英]Can my CPU execute multiple NOPs per CPU cycle?

我寫了一個簡單的程序,在一個循環中執行一堆NOP指令,令我驚訝的是它每秒執行大約10600000000個,或大約10Ghz,而我的CPU只有2.2GHz。

這怎么可能? CPU是將它們視為單個超級NOP,還是僅僅發現“指令級並行”意味着什么?

什么是每秒指令更好的衡量標准? 執行添加指令的時間僅為414900000 / s,是我的CPU報告的十幾個bogomips:4390.03

C代碼:

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

#define ten(a) a a a a a a a a a a
#define hundred(a) ten(a) ten(a) ten(a) ten(a) ten(a) ten(a) ten(a) \
        ten(a) ten(a) ten(a)

#define ITER 10000000
int main(void) {
  uint64_t i=0;
  uint64_t t=time(NULL);
  while(1) {
    for(int j=0; j<ITER;j++) {
    hundred(asm volatile ("nop");)
    }
    i+=ITER*100;
    printf("%lu/%lu\n", i, time(NULL)-t);
  }
  return 0;
}

編譯組件:

    .file   "gbloopinc.c"
    .section    .rodata
.LC0:
    .string "%lu/%lu\n"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $32, %rsp
    movq    $0, -16(%rbp)
    movl    $0, %edi
    call    time
    movq    %rax, -8(%rbp)
.L4:
    movl    $0, -20(%rbp)
    jmp .L2
.L3:
#APP
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
# 15 "gbloopinc.c" 1
    nop
# 0 "" 2
#NO_APP
    addl    $1, -20(%rbp)
.L2:
    cmpl    $9999999, -20(%rbp)
    jle .L3
    addq    $1000000000, -16(%rbp)
    movl    $0, %edi
    call    time
    subq    -8(%rbp), %rax
    movq    %rax, %rdx
    movq    -16(%rbp), %rax
    movq    %rax, %rsi
    movl    $.LC0, %edi
    movl    $0, %eax
    call    printf
    jmp .L4
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609"
    .section    .note.GNU-stack,"",@progbits

這與多核無關。 核心不是“端口”。


每個時鍾4個NOP是超標量/無序CPU的問題/報廢管道寬度。 NOP甚至不需要執行單元/執行端口(ALU或加載或存儲),因此您甚至不受整數執行單元數量的限制。 即使Core2(英特爾的第一個4寬x86 CPU)每個時鍾也可以運行4個NOP。

正如您所猜測的,這是指令級並行的一個例子。 NOP當然沒有輸入依賴性。

在Sandybridge CPU上(每個核心有3個ALU執行單元),每個時鍾可以運行3個ADD和一個加載或存儲指令,因為它的管道寬度為4微秒。 請參閱Agner Fog的microarch pdf以及 標簽wiki中的其他鏈接。 在一系列獨立的ADD指令中,如

add  eax, eax
add  ebx, ebx
add  ecx, ecx
add  edx, edx
...

你會看到SnB上每個時鍾吞吐量大約3個,整數ALU執行端口的瓶頸。 Haswell可以在每個時鍾4個ADD運行它,因為它有一個第四個ALU執行端口,可以處理非向量整數運算(和分支)。

無序CPU通常具有比執行單元數更寬的前端和發布/退出寬度。 只要有一個空閑執行單元,就會有更多指令被解碼並准備好執行,從而提高了它們的利用率。 否則,如果由於串行依賴性導致執行停止或減速,則無序機器只能看到當前正在執行的操作。 (例如, add eax,eax / add eax,eax需要第一次添加的輸出作為第二次添加的輸入,因此每個時鍾只能運行一次insn。)

我將進一步擴展HansPassant的評論。

現代處理器既有超標量也有多核。 很容易理解多核處理器是什么 - 它有多個核心。 另一方面,超標量需要更多關於硬件的知識。 這是一個stackexchange問​​題 ,解釋了處理器超標量意味着什么。 超標量處理器在同一核心中具有許多功能單元,並且具有大量流水線。 這就是為什么可以在單個核心中同時分派和繼續多個指令的原因。 以下是處理器中的一些功能單元:整數加法/減法,浮點乘法,浮點除法,整數乘法,整數除法。

我鼓勵您向Google提供有關超標量處理器的更多信息,並特別查找有關您的處理器的更多信息。

暫無
暫無

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

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