Topik temu duga representatif

Temu Duga False Sharing: Bagaimana Anda Mendiagnosis dan Membetulkan Pertikaian Cache-Line?

UmumSukar
Pasukan Editorial Offer.ccDiterbitkan Dikemas kini

Soalan

Sebuah pengumpul metrik C++17 menyimpan 8 pembilang atomik secara bersebelahan. Lapan benang yang dipin ke teras fizikal berbeza masing-masing melakukan 50 juta kenaikan santai (relaxed increments) pada pembilang yang berbeza. Jumlah keseluruhannya adalah betul, tetapi pemprosesan (throughput) menurun apabila benang ditambah, dan sebuah profiler memetakan banyak peristiwa HITM ke satu cache line 64-bait yang mengandungi pembilang-pembilang tersebut. Terangkan puncanya, buktikan bahawa ia adalah perkongsian palsu dan bukannya perkongsian sebenar atau penjadualan, reka bentuk penyelesaian, dan tunjukkan bagaimana anda akan mengesahkan kedua-dua peningkatan prestasi dan kos ruang.

Masalah dan Senario yang Berkenaan

Sebuah pengumpul metrik C++17 menyimpan 8 pembilang atomik secara bersebelahan. Lapan benang yang dipin ke teras fizikal berbeza masing-masing melakukan 50 juta kenaikan santai (relaxed increments) pada pembilang yang berbeza. Pada sasaran yang diukur, setiap pembilang menduduki 8 bait dan objek bermula pada sempadan 64-bait, jadi kesemua lapan pembilang menduduki satu cache line 64-bait. Jumlah akhir adalah betul iaitu 400 juta, tetapi pemprosesan (throughput) menjadi lebih teruk apabila benang ditambah. perf c2c atau profiler yang setara memetakan banyak peristiwa HITM ke baris tersebut.

Masalah ini menguji koherens cache berbilang teras, reka letak data, bukti prestasi, dan reka bentuk eksperimen. Ia terpakai kepada peranan C++, infrastruktur, kependaman rendah, kernel pangkalan data, dan kejuruteraan prestasi. Kemahiran teras ini merentasi sempadan bahasa, sistem pengendalian, dan perkakasan, jadi kategorinya ialah general. Operasi santai (relaxed operation) melemahkan kekangan susunan memori; ia tidak menghapuskan trafik koherens yang disebabkan oleh penulisan atomik.

Anggap 64 bait sebagai sifat terukur bagi sasaran ini, bukan pemalar sejagat. Penyelesaian harus mengutamakan saiz gangguan pemusnah (destructive-interference size) bagi pelaksanaan tersebut atau reka letak yang disahkan pada sasaran yang disokong, sambil mengekalkan penanda aras padat dan tetap yang setanding.

Perkara yang Dinilai oleh Penemu Duga

Pertama, bolehkah calon memisahkan ketepatan daripada kebolehskalaan? Benang-benang menulis objek atomik yang berbeza, jadi tiada kemas kini yang hilang. Pemproses mengekalkan koherens pada granulariti cache-line, jadi alamat bebas masih boleh membatalkan satu sama lain.

Kedua, bolehkah calon menerangkan pemilikan penulisan (write ownership)? Sebelum satu teras mengubah suai mana-mana pembilang dalam baris tersebut, ia memerlukan salinan yang boleh ditulis. Apabila teras lain mengubah suai pembilang berbeza dalam baris itu, ia membatalkan salinan teras sebelumnya. Baris tersebut berpindah antara teras dan mewujudkan pensirian yang tidak berkaitan dengan kebergantungan data aplikasi.

Ketiga, bolehkah calon membina rantaian bukti? Jawapan yang kukuh tidak melompat terus daripada "multi-benang adalah lebih perlahan" kepada perkongsian palsu. Ia membandingkan satu dan banyak benang, mengepin teras, memetakan alamat dan ofset medan, mencari titik panas HITM, memerhati reka letak yang diasingkan, dan menolak perkongsian sebenar, kunci (locks), penghijrahan CPU, NUMA, dan lebar jalur memori.

Keempat, bolehkah calon memilih pembetulan kos terendah? Mengasingkan penulis aktif (hot writers) mengikut sempadan gangguan pemusnah membetulkan reka letak. Jika jumlah keseluruhan hanya dibaca selepas tugas selesai, pembilang biasa thread-local ditambah satu pengurangan adalah lebih baik kerana ia menghapuskan sebahagian besar penulisan yang dikongsi. Keperluan bacaan langsung (live-read) mengubah pilihan tersebut.

Kelima, bolehkah calon menyatakan sempadan ruang? Pada sasaran ini, mengembangkan slot 8-bait kepada 64 bait menjadikan sejuta slot lapan kali lebih besar dan boleh meningkatkan tekanan cache dan TLB. Menambah pelapik (padding) pada setiap medan tanpa pengukuran bukanlah pengoptimuman yang wajar.

Soalan untuk Dijelaskan Sebelum Menjawab

  • Adakah setiap pembilang benar-benar mempunyai satu penulis eksklusif? Jika beberapa benang mengemas kini satu objek, itu adalah perkongsian sebenar; mengasingkan medan bersebelahan tidak boleh menghapuskan pertikaian pemilikan pada objek yang sama.
  • Berapa segarkah bacaan yang diperlukan? Nilai yang dibaca hanya selepas join boleh menggunakan integer biasa thread-local. Pengumpulan data dalam talian mungkin memerlukan syard atomik dan penjumlahan semasa waktu membaca.
  • Adakah benang berjalan pada teras fizikal yang berbeza? Penghirisan masa teras yang sama, penghijrahan, terlebih langganan (oversubscription), atau SMT mengubah keputusan. Pin pengeluaran semula dan rekod topologi.
  • Apakah saiz gangguan sasaran dan reka letak sebenar? Periksa pemalar pelaksanaan, sizeof, alignof, langkah tatasusunan (array stride), dan alamat dan bukannya mempercayai susunan kod sumber.
  • Adakah sampel HITM memetakan ke ofset medan yang berbeza? HITM pada satu alamat menunjukkan perkongsian sebenar. Penulis berbeza yang menyentuh ofset berbeza dalam satu baris menyokong perkongsian palsu.

Rangka Kerja Jawapan 30 Saat

"Keputusan yang betul menunjukkan bahawa keatomikan berfungsi; kegagalan penskalaan berpunca daripada pemilikan cache-line. Lapan benang menulis lapan alamat, tetapi alamat-alamat tersebut menduduki satu coherence line. Setiap penulisan boleh membatalkan salinan yang dipegang oleh teras lain, dan penulis seterusnya mesti memperoleh semula pemilikan, jadi baris tersebut terus berpindah. memory_order_relaxed menghapuskan susunan rentas-objek, tetapi ia masih satu penulisan dan tidak boleh memintas koherens.

Saya akan mengepin benang ke teras fizikal yang berasingan, memastikan beban kerja tetap, mengukur pemprosesan daripada satu hingga lapan benang, dan menggunakan perf c2c untuk memetakan titik panas HITM ke alamat objek dan ofset medan. Jika benang yang berbeza menyentuh pembilang berbeza dalam satu baris, dan mengasingkan slot mengikut saiz gangguan pemusnah pelaksanaan mengurangkan kedua-dua HITM dan masa berlalu, itu adalah bukti perkongsian palsu.

Saya terlebih dahulu akan mengurangkan perkongsian: gunakan pembilang thread-local dan terbitkan sekali apabila bacaan langsung tidak diperlukan. Untuk bacaan langsung, gunakan syard atomik yang dipisahkan oleh cache-line dan jumlahkannya semasa membaca. Saya akan mengesahkan bahawa jumlah keseluruhan kekal 400 juta, kerja setiap benang adalah sama, peningkatan kelajuan berulang, dan kos ruang slot lapan kali ganda tidak mewujudkan masalah cache atau TLB yang lebih besar."

Penyelidikan Mendalam Langkah Demi Langkah

Langkah 1: Terangkan kesesakan dari segi cache-line

Koherens cache menjejaki baris. Beberapa teras boleh memegang salinan baca sahaja secara serentak. Sebelum teras menulis walaupun satu bait dalam baris, ia mesti mendapatkan keadaan yang membenarkan pengubahsuaian dan membatalkan salinan dalam teras lain. Teras seterusnya yang menulis bait lain dalam baris yang sama mengulangi pemindahan tersebut.

Setiap benang dalam masalah ini hanya menulis pada pembilangnya sendiri, jadi atur cara tidak mempunyai pertikaian semantik pada pemboleh ubah yang dikongsi. Perkakasan melihat penulisan berulang pada satu unit koherens. Perkongsian itu adalah "palsu" (false) kerana ia berpunca daripada reka letak fizikal dan bukannya kebergantungan algoritma. Atomics melindungi setiap nilai; ia tidak menjamin bahawa beberapa objek atomik bersebelahan diskalakan secara bebas.

Perkongsian baca sahaja biasanya membenarkan salinan dikongsi. Penulisan yang kerap mendorong pemindahan pemilikan, jadi cari teras berbeza yang menulis satu baris daripada melabelkan semua data yang biasa dibaca sebagai masalah.

Langkah 2: Buktikan diagnosis dan bukannya meneka dengan pelapik (padding)

Bina empat kumpulan bukti:

  1. Ukur 1, 2, 4, dan 8 benang dengan kerja yang sama, laporkan kenaikan sesaat dan masa setiap operasi.
  2. Pin benang ke teras fizikal berasingan dan rekodkan penghijrahan CPU, pertukaran konteks, dan penempatan NUMA.
  3. Cetak setiap alamat slot dan ofset, mengesahkan penulis yang berbeza, alamat yang berbeza, dan satu baris.
  4. Kumpulkan pemindahan cache-ke-cache dan petakannya ke objek sumber dan data.

Pada Linux, penanda aras yang boleh dihasilkan semula boleh menggunakan:

bash
perf c2c record -g -- ./counter-bench packed
perf c2c report --call-graph none

HITM bermakna operasi memuat (load) mencecah baris yang diubah suai dalam cache lain. Ia menyokong dakwaan bahawa pemindahan baris yang diubah suai berlaku, tetapi ia tidak membuktikan perkongsian palsu secara bersendirian. Periksa alamat, ofset, dan penulis. Jika semua benang mengemas kini satu pembilang, itu adalah perkongsian sebenar. Kunci (lock) bersebelahan dengan data yang dilindungi boleh menghasilkan corak yang serupa.

Langkah 3: Asingkan slot penulis aktif (hot writer) melalui reka letak

C++17 mendedahkan saiz gangguan pemusnah yang ditakrifkan oleh pelaksanaan. Elemen tatasusunan berikut mempunyai penjajaran tersebut, dan saiz setiap elemen sekurang-kurangnya pada selang yang sama, mengelakkan pembilang bersebelahan daripada dimampatkan ke dalam satu rantau gangguan pemusnah:

cpp
#include <array>
#include <atomic>
#include <cstdint>
#include <new>

struct PackedCounter {
  std::atomic<std::uint64_t> value{0};
};

struct alignas(std::hardware_destructive_interference_size) SeparatedCounter {
  std::atomic<std::uint64_t> value{0};
};

static_assert(
  sizeof(SeparatedCounter) >= std::hardware_destructive_interference_size
);

std::array<PackedCounter, 8> packed;
std::array<SeparatedCounter, 8> separated;

Pelaksanaan membekalkan pemalar ini, jadi rangkaian alat binaan dan sasaran pelaksanaan masih perlu sepadan. Jika pustaka sasaran ketiadaannya, dapatkan dasar reka letak daripada sifat platform disokong yang telah disahkan dan sahkan alamat serta prestasi. Menetapkan 64 secara tegar (hard-coding) sebagai nilai sejagat mengelirukan pemerhatian yang betul pada satu mesin dengan kebolehportan.

Untuk tatasusunan, periksa tiga perkara: penjajaran elemen pertama, langkah elemen (element stride), dan ofset medan aktif di dalam setiap elemen. Menjajarkan alamat pertama tatasusunan sahaja sambil mengekalkan langkah 8-bait tidak mengasingkan pembilang. Pelapik hujung ad hoc juga boleh rosak apabila medan berubah.

Langkah 4: Utamakan penghapusan penulisan yang dikongsi

Pengasingan baris masih melakukan 400 juta operasi atomic read-modify-write. Jika jumlah keseluruhan hanya diperlukan selepas kerja selesai, setiap benang boleh mengira dalam daftar atau integer biasa stack-local, menerbitkan satu hasil separa sebelum keluar, dan membiarkan benang utama mengurangkan (reduce) selepas join. Penerbitan dikongsi berkurangan daripada 50 juta operasi bagi setiap benang kepada satu operasi sahaja.

Jika pemantauan mesti mengambil nilai yang hampir nyata (near-live), kekalkan syard bagi setiap benang atau setiap teras dalam slot yang tidak mengganggu. Pembaca menjumlahkan lapan syard. Ini menambahkan amplifikasi bacaan dan tangkapan masa yang tidak konsisten seketika. Jumlah keseluruhan yang linearizable secara ketat adalah lebih mudah dengan satu atomik, tetapi itu memperkenalkan semula perkongsian sebenar; jawapan harus menyatakan sama ada ketekalan atau pemprosesan penulisan yang diutamakan.

Pengelompokan (batching) adalah jalan tengah. Pekerja mengumpul secara tempatan dan secara berkala menggunakan fetch_add pada pembilang global. Ia mengurangkan pemindahan pemilikan tetapi membiarkan jumlah yang kelihatan tertinggal paling banyak satu kelompok bagi setiap penulis. Pilih saiz kelompok daripada keusangan yang dibenarkan dan hasil pengukuran.

Langkah 5: Bandingkan kos ruang, lokaliti, dan penyelenggaraan

Dengan objek 8-bait dan selang gangguan 64-bait yang diukur dalam masalah ini, slot yang diasingkan adalah lapan kali ganda slot padat. Lapan slot pekerja adalah murah. Menambah pelapik pada pembilang bagi setiap satu daripada sejuta entiti akan mengembangkan set kerja dan meningkatkan tekanan cache dan jadual halaman (page-table).

Asingkan hanya medan yang terbukti kerap ditulis pada teras yang berbeza. Medan yang dibaca bersama dan jarang ditulis boleh kekal padat. Statistik berfrekuensi rendah boleh diterbitkan secara berkelompok. Set entiti yang besar boleh disyardkan mengikut benang dan bukannya dilapik mengikut entiti. Sasaran pengoptimuman ialah pemindahan pemilikan yang diukur, bukan rupa struktur.

Lindungi daripada regresi reka letak. Menambah medan, menukar pewarisan, menggantikan peruntuk (allocator), atau menukar sasaran kompilasi boleh mengubah langkah tatasusunan. Penegasan reka letak (layout assertions), pemeriksaan alamat, dan penanda aras prestasi yang fokus adalah lebih tahan lama daripada ulasan yang mendakwa bahawa struktur adalah 64 bait.

Langkah 6: Gunakan eksperimen kontrafaktual untuk mengecualikan kesesakan lain

Uji sekurang-kurangnya tiga versi: tatasusunan atomik padat, tatasusunan atomik diasingkan, dan pengiraan thread-local diikuti dengan pengurangan. Jika hanya dua versi terakhir berskala dan pemindahan cache-line berkurangan bersamanya, hujah sebab-akibat adalah lebih kukuh.

Jika pengasingan kekal perlahan, periksa pemboleh ubah kawalan dikongsi, had pemprosesan arahan atomik, memori NUMA jauh, penghijrahan CPU, beban kerja yang terlalu kecil untuk kos permulaan dan penyegerakan benang, dan lebar jalur memori yang tepu. Perkongsian palsu boleh wujud bersama kesesakan tersebut.

Jangan laporkan larian terpantas tunggal. Panaskan (warm up), ulangi, dan laporkan median serta sebaran sambil mengekalkan bendera pengkompil, dasar frekuensi, topologi benang, dan input tetap sama. Setiap hasil prestasi juga memerlukan pemeriksaan ketepatan: pembilang atau nilai yang dikurangkan mesti tetap tepat bersamaan dengan 400 juta.

Contoh Jawapan Berkualiti Tinggi

"Saya akan memisahkan ketepatan daripada kebolehskalaan terlebih dahulu. Lapan benang mengemas kini lapan objek atomik yang berbeza, jadi atomics santai (relaxed) boleh mengekalkan setiap pembilang. Walau bagaimanapun, objek tersebut berada dalam satu cache line, dan perkakasan memberikan pemilikan penulisan mengikut baris. Selepas teras 0 mengubah suai 8 bait miliknya, teras 1 masih memerlukan pemilikan keseluruhan baris untuk mengubah suai 8 bait yang berbeza dan membatalkan salinan teras 0. Apabila penulis bersilih ganti, baris tersebut berpindah antara teras dan reka letak fizikal mensirikan pembilang bebas. Relaxed menghapuskan jaminan susunan merentasi operasi, bukan koherens cache.

Saya tidak akan membuat kesimpulan daripada keluk penskalaan sahaja. Saya akan mengepin 1, 2, 4, dan 8 benang ke teras fizikal berasingan, mengekalkan 50 juta operasi bagi setiap benang, dan merekodkan pemprosesan, penghijrahan, dan topologi. Kemudian saya akan menggunakan perf c2c untuk memetakan HITM ke ofset elemen tatasusunan. Penulis berbeza pada ofset berbeza dalam satu baris menunjukkan perkongsian palsu. Ofset yang sama mencadangkan perkongsian sebenar, manakala kunci dan NUMA memerlukan pemeriksaan berasingan.

Untuk bacaan langsung, saya akan menjajarkan setiap syard ke std::hardware_destructive_interference_size, memastikan langkah tatasusunan sekurang-kurangnya sebesar nilai tersebut, dan menjumlahkan syard semasa membaca. Jika bacaan hanya berlaku apabila tugas selesai, integer biasa thread-local dengan satu penerbitan dan pengurangan selepas join adalah lebih baik kerana ia menghapuskan perkongsian daripada laluan kritikal (hot path).

Saya akan menanda aras versi padat, diasingkan, dan pengurangan tempatan berulang kali pada mesin dan binaan yang sama. Semua jumlah mesti kekal 400 juta; HITM baris pembilang dan masa berlalu harus menurun bersama selepas pengasingan, manakala pengurangan tempatan harus menghapuskan lebih banyak kos atomik. Saya juga akan merekodkan kos ruang: pada sasaran ini, slot berkembang daripada 8 bait kepada sekurang-kurangnya 64, peningkatan lapan kali ganda yang tidak boleh digunakan sewenang-wenangnya pada sejuta pembilang yang jarang diakses (cold counters)."

Kesilapan Biasa

  • Mendakwa bahawa atomics tidak boleh mengalami false-share → atomics menjadikan operasi objek tidak boleh dibahagikan tetapi tidak mengubah granulariti koherens → pisahkan ketepatan daripada pemilikan baris.
  • Mendakwa bahawa relaxed melumpuhkan koherens → ia melemahkan susunan peringkat bahasa manakala penulisan kekal koheren antara teras → bezakan keatomikan, susunan, dan koherens perkakasan.
  • Mengisytiharkan perkongsian palsu daripada HITM sahaja → perkongsian sebenar dan medan kunci juga memindahkan baris yang diubah suai → petakan alamat, ofset, dan penulis.
  • Menjajarkan asas tatasusunan sahaja → elemen 8-bait masih boleh menduduki baris yang sama → kawal kedua-dua penjajaran elemen dan langkahnya (stride).
  • Sentiasa menetapkan 64 bait secara tegar (hard-coding) → saiz gangguan bergantung pada pelaksanaan dan sasaran → gunakan nilai pelaksanaan atau dasar platform yang disahkan dan semak semula reka letak.
  • Menambah pelapik (padding) pada setiap medan → kos working-set, cache, dan TLB boleh melebihi keuntungan → asingkan hanya penulis rentas-teras aktif yang terbukti.
  • Membandingkan satu larian masa sahaja → frekuensi, penghijrahan, dan pemanasan mencipta hingar → pin topologi, ulangi, dan semak HITM serta ketepatan.
  • Mengabaikan pengurangan tempatan → pelapik menambah baik reka letak tetapi mengekalkan kerja atomik → kurangkan penulisan yang dikongsi mengikut keperluan kesegaran.

Soalan Susulan dan Maklum Balas

Soalan Susulan 1: Adakah menggantikan atomics memory_order_relaxed dengan integer biasa membetulkannya?

Jika setiap benang secara kekal memiliki elemen yang berbeza, integer biasa tidak menghasilkan persaingan data (data race), tetapi elemen bersebelahan masih boleh mengalami perkongsian palsu. Integer biasa thread-local adalah terbaik apabila bacaan berlaku selepas join. Jika benang lain membaca tatasusunan yang dikongsi secara serentak, anda mesti mewujudkan semula penyegerakan dan keterlihatan dan bukannya sekadar memadamkan atomics.

Soalan Susulan 2: Mengapakah HITM mungkin kekal bukan sifar selepas pengasingan?

Atur cara masih boleh mempunyai perkongsian sebenar dalam batas permulaan (start barrier), giliran kerja, kunci, metadata peruntuk, atau pemboleh ubah kemajuan global, dan pembaca menyentuh syard. Mula-mula sahkan bahawa titik panas baris pembilang asal menurun, kemudian periksa alamat yang selebihnya. Matlamatnya adalah untuk menghapuskan pemindahan tanpa kebergantungan perniagaan, bukan menjanjikan sifar HITM di semua tempat.

Soalan Susulan 3: Bagaimanakah pengurangan thread-local boleh menyokong metrik langsung?

Minta setiap pekerja menerbitkan delta tempatannya ke syard yang diasingkan sekali bagi setiap kelompok, dan biarkan pengumpul menjumlahkan syard tersebut. Kelompok yang lebih besar mengurangkan trafik penulisan tetapi menjadikan pemerhatian lebih lapuk; kelompok yang lebih kecil meningkatkan kesegaran tetapi meningkatkan pertikaian. Nyatakan keusangan maksimum yang boleh diterima, pilih saiz kelompok daripada had tersebut, dan ukurnya.

Soalan Susulan 4: Mengapa tidak menggunakan satu pembilang atomik global?

Ia menggunakan ruang paling sedikit, mudah dibaca, dan menyediakan satu susunan pengubahsuaian, tetapi setiap penulis mengubah suai objek yang sama, mewujudkan perkongsian sebenar. Ia mungkin sesuai untuk kadar kemas kini yang rendah atau keperluan ketekalan yang kuat. Statistik frekuensi tinggi biasanya memihak kepada pensyardan dan pengagregatan masa membaca. Membetulkan perkongsian palsu tidak boleh menghapuskan perkongsian sebenar yang sengaja diperlukan oleh kontrak.

Soalan Susulan 5: Bagaimana jika mesin penggunaan (deployment) mempunyai saiz cache-line yang berbeza daripada mesin binaan?

Nilai pustaka standard ialah sifat masa binaan yang ditakrifkan oleh pelaksanaan. Satu binari tunggal yang ditujukan untuk perkakasan heterogen memerlukan ABI dan selang gangguan yang disahkan merentasi sasaran yang disokong. Pilih reka letak konservatif yang meliputi sasaran tersebut atau bina bagi setiap sasaran, kemudian jalankan pengesahan alamat dan prestasi pada setiap kelas mesin. Pemerhatian 64-bait pada satu hos pembangunan tidak boleh menetapkan setiap reka letak penggunaan.

Sumber awam

Soalan berkaitan