Pertanyaan Kapan diperlukan instruksi x86 LFENCE, SFENCE, dan MFENCE?


Ok, saya telah membaca Qs berikut dari SO mengenai pagar CPU x86 (LFENCE, SFENCE dan MFENCE):

dan:

dan saya harus jujur ​​saya masih belum yakin kapan pagar diperlukan. Saya mencoba untuk memahami dari sudut pandang menghapus kunci sepenuhnya dan mencoba menggunakan penguncian yang lebih rinci melalui pagar, untuk meminimalkan penundaan latensi.

Pertama di sini ada dua pertanyaan spesifik yang saya tidak mengerti:

Kadang-kadang ketika melakukan sebuah toko, sebuah CPU akan menulis ke penyangga tokonya alih-alih ke cache L1. Namun saya tidak mengerti istilah-istilah di mana CPU akan melakukan ini?

CPU2 mungkin ingin memuat nilai yang telah ditulis ke buffer penyimpanan CPU1. Seperti yang saya pahami, masalahnya adalah CPU2 tidak dapat melihat nilai baru di buffer penyimpanan CPU1. Mengapa protokol MESI tidak dapat menyertakan pembasmi penyangga toko sebagai bagian dari protokolnya ??

Secara umum, dapatkah seseorang mencoba menjelaskan skenario keseluruhan dan membantu menjelaskan kapan LFENCE/MFENCE dan SFENCE instruksi diperlukan?

NB Salah satu masalah membaca di sekitar subjek ini adalah jumlah artikel yang ditulis "umumnya" untuk beberapa arsitektur CPU, ketika saya hanya tertarik pada arsitektur Intel x86-64 secara khusus.


32
2017-12-22 01:40


asal


Jawaban:


Jawaban paling sederhana: Anda harus menggunakan salah satu dari 3 pagar (LFENCE, SFENCE, MFENCE) untuk menyediakan salah satu dari 6 Konsistensi data:

  • Santai
  • Konsumsi
  • Memperoleh
  • Melepaskan
  • Dapatkan Pembebasan
  • Sekuensial

C ++ 11:

Awalnya, Anda harus mempertimbangkan masalah ini dari sudut pandang tingkat urutan akses memori, yang didokumentasikan dengan baik dan distandarkan dalam C ++ 11. Anda harus membaca terlebih dahulu: http://en.cppreference.com/w/cpp/atomic/memory_order

x86 / x86_64:

1. Konsistensi Acquire-Release: Maka, penting untuk memahami bahwa dalam x86 untuk mengakses RAM konvensional (ditandai dengan default sebagai WB - Tulis Kembali, dan efek yang sama dengan WT (Tulis Tempur) atau UC (Tidak Dapat Dicuri)) dengan menggunakan asm MOV tanpa ada perintah tambahan secara otomatis menyediakan urutan memori untuk Acquire-Release Consistency - std::memory_order_acq_rel. Yaitu. untuk memori ini masuk akal untuk digunakan saja std::memory_order_seq_cst hanya untuk memberikan konsistensi berurutan. Yaitu ketika Anda menggunakan: std::memory_order_relaxed atau std::memory_order_acq_rel maka kode assembler dikompilasi untuk std::atomic::store() (atau std::atomic::load()) akan sama - saja MOV Tanpa apapun L/S/MFENCE.

catatan: Tapi Anda harus tahu, bahwa tidak hanya CPU tetapi dan C + + - kompilator dapat mengatur ulang operasi dengan memori, dan semua 6 hambatan memori selalu mempengaruhi pada C ++ - compiler terlepas dari arsitektur CPU.

Kemudian, Anda harus tahu, bagaimana bisa dikompilasi dari C ++ ke ASM (kode mesin asli) atau bagaimana Anda bisa menulisnya di assembler. Untuk memberikan Konsistensi apa pun, kecualikan Sekuensial Anda dapat menulis sederhana MOV, sebagai contoh MOV reg, [addr] dan MOV [addr], reg  dll.

2. Konsistensi Berurutan: Tetapi untuk memberikan Konsistensi Sekuensial Anda harus menggunakan implisit (LOCK) atau pagar eksplisit (L / S /MFENCE) seperti yang dijelaskan di sini: Mengapa GCC tidak menggunakan LOAD (tanpa pagar) dan STORE + SFENCE untuk Konsistensi Berurutan?

  1. LOAD (tanpa pagar) dan STORE + MFENCE
  2. LOAD (tanpa pagar) dan LOCK XCHG
  3. MFENCE + LOAD dan STORE (tanpa pagar)
  4. LOCK XADD (0) dan STORE (tanpa pagar)

Sebagai contoh, GCC menggunakan 1, tetapi MSVC menggunakan 2. (Tetapi Anda harus tahu, bahwa MSVS2012 memiliki bug: Apakah semantik `std :: memory_order_acquire` memerlukan instruksi prosesor pada x86 / x86_64? )

Kemudian, Anda dapat membaca Herb Sutter, tautan Anda: https://onedrive.live.com/view.aspx?resid=4E86B0CF20EF15AD!24884&app=WordPdf&authkey=!AMtj_EflYn2507c

Pengecualian aturan:

Aturan ini berlaku untuk akses dengan menggunakan MOV ke RAM konvensional ditandai dengan default sebagai WB - Tulis Kembali. Memori menandai di Tabel Halaman, di setiap PTE (Halaman Tabel Enrty) untuk setiap Halaman (4 KB memori terus menerus).

Tetapi ada beberapa pengecualian:

  1. Jika kita menandai memori di Tabel Laman sebagai Tulis Gabungan (ioremap_wc() di POSIX), maka otomatis hanya menyediakan Acquire Consistency, dan kita harus bertindak seperti di paragraf berikut.

  2. Lihat jawaban atas pertanyaan saya: https://stackoverflow.com/a/27302931/1558037

  • Menulis ke memori tidak diurutkan ulang dengan tulisan lain, dengan pengecualian berikut:      
    • menulis dieksekusi dengan instruksi CLFLUSH;
    • streaming store (menulis) dieksekusi dengan instruksi bergerak non-temporal (MOVNTI, MOVNTQ, MOVNTDQ, MOVNTPS, dan MOVNTPD); dan
    • operasi string (lihat Bagian 8.2.4.1).

Dalam kedua kasus 1 & 2 Anda harus menggunakan tambahan SFENCE antara dua menulis ke alamat yang sama bahkan jika Anda ingin Acquire-Release Consistency, karena di sini otomatis hanya menyediakan Acquire Consistency dan Anda harus melakukan Release (SFENCE) dirimu sendiri.

Jawablah dua pertanyaan Anda:

Terkadang ketika melakukan penyimpanan, sebuah CPU akan menulis ke penyangga tokonya   bukannya cache L1. Namun saya tidak mengerti istilahnya   mana CPU akan melakukan ini?

Dari sudut pandang pengguna, cache L1 dan Store Buffer bertindak berbeda. L1 cepat, tetapi Simpan-Penyangga lebih cepat.

  • Store-Buffer - adalah Antrian sederhana di mana toko hanya Menulis, dan yang tidak dapat diurutkan ulang - itu dibuat untuk peningkatan kinerja dan Sembunyikan Latensi akses ke cache (L1 - 1ns, L2 - 3ns, L3 - 10ns) (CPU-Core berpikir bahwa Write telah disimpan ke cache dan mengeksekusi perintah selanjutnya, tetapi pada saat yang sama tulisan Anda hanya disimpan ke Store-Buffer dan akan disimpan ke cache L1 / 2/3 nanti), yaitu CPU-Core tidak perlu untuk menunggu kapan penulisan akan disimpan ke cache.

  • Cache L1 / 2/3 - terlihat seperti array asosiasi transparan (alamat - nilai). Ini cepat tetapi bukan yang tercepat, karena x86 secara otomatis menyediakan Acquire-Release Consistency dengan menggunakan cache koheren protokol MESIF/MOESI. Hal ini dilakukan untuk pemrograman multithread yang lebih sederhana, tetapi menurunkan kinerja. (Sungguh, kita dapat menggunakan Write Contentions Algoritma dan struktur data gratis tanpa menggunakan cache koheren, yaitu tanpa MESIF / MOESI misalnya di atas PCI Express). Protokol MESIF / MOESI berhasil QPI yang menghubungkan Cores dalam CPU dan Core antara CPU yang berbeda dalam sistem multiprosesor (ccNUMA).

CPU2 mungkin ingin memuat nilai yang telah ditulis ke CPU1   simpan penyangga. Seperti yang saya pahami, masalahnya adalah CPU2 tidak bisa melihat   nilai baru di buffer penyimpanan CPU1.

Iya nih.

Mengapa protokol MESI tidak bisa?   termasuk flushing store buffer sebagai bagian dari protokolnya ??

Protokol MESI tidak bisa hanya mencakup pembilasan penyangga toko sebagai bagian dari protokolnya, karena:

  • Protoklos MESI / MOESI / MESIF tidak berhubungan dengan Store-Buffer dan tidak mengetahuinya.
  • Secara otomatis pembilasan Store Buffer di setiap Penulisan akan menurunkan kinerja - dan akan membuatnya tidak berguna.
  • Pembajakan Manual Penyangga Toko pada semua CPU-Cores jarak jauh (kita tidak tahu di mana Core store-buffer mengandung Write yang diperlukan) dengan menggunakan beberapa perintah - akan menurunkan kinerja (dalam 8 CPU x 15 Cores = 120 Core pada saat yang sama dengan Flush Store -Buffer - ini mengerikan)

Tapi Pembalasan Penyiraman manual pada CPU-Core saat ini - ya, Anda dapat melakukannya dengan mengeksekusi SFENCE perintah. Kamu dapat memakai SFENCE dalam dua kasus:

  • Untuk memberikan Konsistensi Sequential pada RAM dengan Write Back cacheable
  • Untuk memberikan Acquire-Release Consistency pada pengecualian aturan: RAM dengan Write Combined cacheable, untuk penulisan yang dieksekusi dengan instruksi CLFLUSH dan untuk perintah SSE / AVX Non-Temporal

catatan:

Apakah kita perlu LFENCE dalam beberapa kasus di x86 / x86_64? - pertanyaannya tidak selalu jelas: Apakah itu masuk akal instruksi LESSEN dalam prosesor x86 / x86_64?

Platform lainnya:

Kemudian, Anda dapat membaca seperti dalam teori (untuk prosesor bulat dalam vakum) dengan Store-Buffer dan Invalidate-Queue, tautan Anda: http://www.puppetmastertrading.com/images/hwViewForSwHackers.pdf

Dan bagaimana Anda dapat memberikan Konsistensi Berurutan pada platform lain, tidak hanya dengan L / S / MFENCE dan LOCK tetapi dengan LL / SC: http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html


31
2017-12-24 10:37