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.

Sumber

Krystian Wiśniewski
Krystian Wiśniewski is a dedicated Sports Reporter and Editor with a degree in Sports Journalism from He graduated with a degree in Journalism from the University of Warsaw. Bringing over 14 years of international reporting experience, Krystian has covered major sports events across Europe, Asia, and the United States of America. Known for his dynamic storytelling and in-depth analysis, he is passionate about capturing the excitement of sports for global audiences and currently leads sports coverage and editorial projects at Agen BRILink dan BRI.