Pada akhir tahun 2024, Harold Aptroot memposting ini:
Rupanya shlx adalah instruksi “latensi sedang” (3 siklus) di Alder Lake. Kekecewaanku tak terukur, dan hariku hancur.
— Twitter / langit biru / mastodon
Saya segera kutu buku itu membentak karena saya menyukai analisis kinerja tingkat rendah, dan kebetulan saya memiliki laptop Alder Lake.
Sedikit latar belakang: Danau Alder adalah prosesor Intel Core generasi ke-12. Ini adalah generasi pertama dengan “arsitektur hybrid”, yang berisi inti kinerja (P) dan efisiensi (E).
SHLX
adalah instruksi shift kiri yang diperkenalkan di BMI2 set instruksi. Perbedaan utama dengan SHL
apakah itu SHLX
tidak mempengaruhi BENDERA daftar. Ini juga merupakan instruksi 3 operan:
SHL RAX, CL ; RAX = RAX << CL
; (only CL allowed as shift count)
SHLX RAX, RBX, RDX ; RAX = RBX << RDX
; (any register allowed as shift count)
Pergeseran kiri adalah salah satu hal paling sederhana untuk diterapkan pada perangkat keras, jadi cukup mengejutkan bahwa ini memerlukan 3 siklus CPU penuh. Sudah 1 siklus di setiap CPU lain yang saya ketahui. Bahkan ada 1 siklus di Danau Alder inti efisiensi! Hanya inti kinerja yang memiliki masalah kinerja khusus ini.
Angka 3 siklus yang dikutip Harold berasal dari uops.info. Mereka bahkan mendokumentasikan persisnya urutan instruksi digunakan dalam benchmark mereka yang mengukur latensi 3 siklus, dengan sampel bangku nano perintah untuk mereproduksinya. Menjalankan perintah itu di laptop saya memang mengukur 3 siklus latensi.
Di sisi lain, sumber lain (seperti Intel Dan InstLatX64) mengklaim latensinya adalah 1 siklus. Apa yang menyebabkannya? Saya memutuskan untuk menulis patokan saya sendiri untuk mencoba memahami perbedaannya.
.intel_syntax noprefix
.globl main
main:
MOV RDX, 10000 ; RDX = 10000
XOR RAX, RAX ; RAX = 0
.LOOP:
MOV RCX, 1 ; RCX = 1
.rept 10000
SHLX RAX, RAX, RCX ; RAX = RAX << RCX
; (repeated 10,000 times)
.endr
DEC RDX
JNZ .LOOP ; (loop 10,000 times)
XOR EAX, EAX
RET ; return 0
Kode ini berisi loop luar dengan 10.000 iterasi. Di dalam loop, kami melakukan inisialisasi RCX
ke 1, lalu jalankan SHLX RAX, RAX, RCX
10.000 kali. Secara total, kami berlari SHLX
10.000.000 kali, jadi semua instruksi lainnya (termasuk yang sebelumnya main()
berjalan) dapat diabaikan. saya menggunakan taskset -c 0
untuk menyematkannya ke inti P, dan perf
untuk pengukuran:
$ gcc shlx.s -o shlx
$ taskset -c 0 perf stat --cputype=core -e 'cycles,instructions' ./shlx
Performance counter stats for './shlx':
301,614,809 cpu_core/cycles:u/
100,155,910 cpu_core/instructions:u/ # 0.33 insn per cycle
Di sini kita melihat 0,33 instruksi per siklus alias latensi 3 siklus.
Mari kita coba inisialisasi RCX
berbeda:
.LOOP:
- MOV RCX, 1
+ MOV ECX, 1
ECX
adalah bagian bawah 32-bit dari 64-bit RCX
daftar. Pada x86-64, menulis register 32-bit secara implisit menyetel separuh atas register 64-bit yang sesuai ke nol. Jadi kedua instruksi ini harus berperilaku sama. Namun:
Performance counter stats for './shlx':
100,321,870 cpu_core/cycles:u/
100,155,867 cpu_core/instructions:u/ # 1.00 insn per cycle
Sepertinya SHLX
bekerja secara berbeda tergantung pada bagaimana register penghitungan shift diinisialisasi. Jika Anda menggunakan instruksi 64-bit dengan segera, kinerjanya lambat. Hal ini juga berlaku untuk instruksi seperti INC
(yang mirip dengan ADD
dengan 1 segera).
.LOOP:
- MOV RCX, 1
+ XOR RCX, RCX
+ INC RCX
Performance counter stats for './shlx':
300,138,108 cpu_core/cycles:u/
100,165,881 cpu_core/instructions:u/ # 0.33 insn per cycle
Di sisi lain, instruksi 32-bit, dan instruksi 64-bit tanpa perintah langsung (bahkan tanpa operasi), membuatnya cepat. Semua cara untuk menginisialisasi RCX ini menghasilkan latensi 1 siklus:
.LOOP:
MOV ECX, 1
.LOOP:
XOR RCX, RCX
.LOOP:
MOV RCX, 1
MOV RCX, RCX
MOV RCX, 1
.LOOP:
PUSH RCX
POP RCX
Sangat aneh bagi saya bahwa instruksi yang digunakan untuk mengatur register hitungan shift dapat membuat SHLX
instruksi 3× lebih lambat. Perbedaan ukuran operan 32-bit vs. 64-bit sangat mengejutkan saya SHLX
hanya melihat 6 bit terbawah dari jumlah shift.
Saya belum memiliki penjelasan yang baik mengenai hal ini, namun saya akan memperbarui halaman ini jika saya dapat mengetahuinya.