Kelebihan dan Kekurangan HugePages

Kelebihan dan Kekurangan HugePages

Terjemahan artikel yang disediakan untuk pelajar kursus "Pentadbir Linux".

Sebelum ini, saya bercakap tentang cara menguji dan mendayakan Hugpages di Linux.
Artikel ini hanya berguna jika anda benar-benar mempunyai tempat untuk menggunakan Hugepages. Saya telah bertemu dengan ramai orang yang tertipu dengan prospek bahawa Hugpageges akan meningkatkan produktiviti secara ajaib. Walau bagaimanapun, hugepaging adalah topik yang kompleks dan boleh merendahkan prestasi jika digunakan secara tidak betul.

Bahagian 1: Mengesahkan bahawa halaman besar didayakan pada Linux (original di sini)

Masalah:
Anda perlu menyemak sama ada HugePages didayakan pada sistem anda.

penyelesaian:
Ia agak mudah:

cat /sys/kernel/mm/transparent_hugepage/enabled

Anda akan mendapat sesuatu seperti ini:

always [madvise] never

Anda akan melihat senarai pilihan yang tersedia (selalu, madvise, tidak pernah), dan pilihan yang sedang aktif akan disertakan dalam kurungan (secara lalai madvise).

madvise bermakna transparent hugepages didayakan hanya untuk kawasan memori yang secara eksplisit meminta penggunaan halaman besar madvise(2).

sentiasa bermakna transparent hugepages sentiasa didayakan untuk semua proses. Ini biasanya meningkatkan prestasi, tetapi jika anda mempunyai kes penggunaan di mana banyak proses menggunakan sejumlah kecil memori, maka beban memori keseluruhan boleh meningkat secara mendadak.

pernah bermakna transparent hugepages tidak akan disertakan walaupun diminta menggunakan madvise. Untuk mengetahui lebih lanjut, hubungi dokumentasi Inti Linux.

Bagaimana untuk menukar nilai lalai

Pilihan 1: Langsung tukar sysfs (selepas but semula parameter akan kembali ke nilai lalainya):

echo always >/sys/kernel/mm/transparent_hugepage/enabled
echo madvise >/sys/kernel/mm/transparent_hugepage/enabled
echo never >/sys/kernel/mm/transparent_hugepage/enabled

Pilihan 2: Tukar lalai sistem dengan menyusun semula kernel dengan konfigurasi yang diubah suai (pilihan ini hanya disyorkan jika anda menggunakan kernel tersuai):

  • Untuk menetapkan sentiasa secara lalai, gunakan:
    CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
  • Untuk menetapkan madvise sebagai lalai, gunakan:
    CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y

Bahagian 2: Kelebihan dan Kelemahan HugePages

Kami akan cuba menerangkan secara selektif kelebihan, keburukan dan kemungkinan perangkap menggunakan Hugpages. Memandangkan artikel berteknologi yang kompleks dan bertele-tele berkemungkinan sukar untuk difahami bagi orang yang terpedaya dengan pemikiran Hugepages adalah ubat penawar, saya akan mengorbankan ketepatan untuk kesederhanaan. Perlu diingat bahawa banyak topik adalah sangat rumit dan oleh itu sangat dipermudahkan.

Sila ambil perhatian bahawa kita bercakap tentang sistem x64 86-bit yang menjalankan Linux, dan saya hanya mengandaikan bahawa sistem itu menyokong halaman besar yang telus (kerana ia bukan satu kelemahan bahawa halaman besar tidak ditimpa), seperti yang berlaku di hampir mana-mana Linux moden persekitaran.

Saya akan melampirkan lebih banyak penerangan teknikal dalam pautan di bawah.

Memori maya

Jika anda seorang pengaturcara C++, anda tahu bahawa objek dalam memori mempunyai alamat tertentu (nilai penunjuk).

Walau bagaimanapun, alamat ini tidak semestinya mencerminkan alamat fizikal dalam ingatan (alamat RAM). Mereka mewakili alamat dalam ingatan maya. Pemproses mempunyai modul MMU (unit pengurusan memori) khas yang membantu kernel memetakan memori maya ke lokasi fizikal.

Pendekatan ini mempunyai banyak kelebihan, tetapi yang paling penting ialah:

  • Prestasi (atas pelbagai sebab);
  • Pengasingan program, iaitu, tiada program boleh membaca dari ingatan program lain.

Apakah halaman?

Memori maya dibahagikan kepada halaman. Setiap halaman individu menghala ke memori fizikal tertentu, ia boleh menghala ke kawasan dalam RAM, atau ia boleh menghala ke alamat yang diberikan kepada peranti fizikal, seperti kad video.

Kebanyakan halaman yang anda berurusan sama ada menunjuk ke RAM atau ditukar, bermakna ia disimpan pada cakera keras atau SSD anda. Kernel menguruskan susun atur fizikal setiap halaman. Jika halaman palsu diakses, kernel menghentikan benang yang cuba mengakses memori, membaca halaman dari pemacu keras/SSD ke dalam RAM, dan kemudian terus melaksanakan utas.

Proses ini adalah strim telus, bermakna ia tidak semestinya dibaca terus dari HDD/SSD. Saiz halaman biasa ialah 4096 bait. Saiz halaman besar ialah 2 megabait.

Penimbal bersekutu terjemahan (TLB)

Apabila atur cara mengakses halaman memori, CPU mesti mengetahui halaman fizikal mana untuk membaca data (iaitu, mempunyai peta alamat maya).

Kernel mempunyai struktur data (jadual halaman) yang mengandungi semua maklumat tentang halaman yang digunakan. Menggunakan struktur data ini, anda boleh memetakan alamat maya ke alamat fizikal.

Walau bagaimanapun, jadual halaman agak rumit dan perlahan, jadi kami tidak boleh menganalisis keseluruhan struktur data setiap kali proses mengakses memori.

Nasib baik, pemproses kami mempunyai TLB yang menyimpan pemetaan antara alamat maya dan fizikal. Ini bermakna walaupun kita perlu menghuraikan jadual halaman pada percubaan akses pertama, semua akses seterusnya ke halaman boleh dikendalikan dalam TLB, membolehkan operasi pantas.

Kerana ia dilaksanakan sebagai peranti fizikal (yang menjadikannya pantas di tempat pertama), kapasitinya terhad. Jadi, jika anda ingin mengakses lebih banyak halaman, TLB tidak akan dapat menyimpan pemetaan untuk kesemuanya, menyebabkan program anda berjalan lebih perlahan.

Hugpages datang untuk menyelamatkan

Jadi apakah yang boleh kita lakukan untuk mengelakkan limpahan TLB? (Kami menganggap program masih memerlukan jumlah memori yang sama).

Di sinilah Hugpages masuk. Daripada 4096 bait yang memerlukan hanya satu entri TLB, satu entri TLB kini boleh menunjuk kepada 2 megabait yang hebat. Katakan TLB mempunyai 512 entri, di sini tanpa Hugpages kita boleh memadankan:

4096 bβ‹…512=2 MB

Kemudian bagaimana kita boleh membandingkan dengan mereka:

2 MBβ‹…512=1 GB

Inilah sebab mengapa Hugepages hebat. Mereka boleh meningkatkan produktiviti tanpa banyak usaha. Tetapi terdapat kaveat penting di sini.

Penipuan Hugpages

Kernel secara automatik memantau kekerapan setiap halaman memori digunakan. Jika memori fizikal (RAM) tidak mencukupi, kernel akan mengalihkan halaman yang kurang penting (kurang kerap digunakan) ke cakera keras untuk mengosongkan beberapa RAM untuk halaman yang lebih penting.
Pada dasarnya, perkara yang sama berlaku untuk Hugepages. Walau bagaimanapun, kernel hanya boleh menukar keseluruhan halaman, bukan bait individu.

Katakan kita mempunyai program seperti ini:

char* mymemory = malloc(2*1024*1024); // Π’ΠΎΠ·ΡŒΠΌΠ΅ΠΌ это Π·Π° ΠΎΠ΄Π½Ρƒ Hugepage!
// Π—Π°ΠΏΠΎΠ»Π½ΠΈΠΌ mymemory ΠΊΠ°ΠΊΠΈΠΌΠΈ-Π»ΠΈΠ±ΠΎ Π΄Π°Π½Π½Ρ‹ΠΌΠΈ
// Π‘Π΄Π΅Π»Π°Π΅ΠΌ ΠΌΠ½ΠΎΠ³ΠΎ Π΄Ρ€ΡƒΠ³ΠΈΡ… Π²Π΅Ρ‰Π΅ΠΉ,
// ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΡ€ΠΈΠ²Π΅Π΄ΡƒΡ‚ ΠΊ ΠΏΠΎΠ΄ΠΌΠ΅Π½Π΅ страницы mymemory
// ...
// Запросим доступ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΊ ΠΏΠ΅Ρ€Π²ΠΎΠΌΡƒ Π±Π°ΠΉΡ‚Ρƒ
putchar(mymemory[0]); 

Dalam kes ini, kernel perlu menggantikan (membaca) sebanyak 2 megabait maklumat daripada cakera keras/SSD hanya untuk anda membaca satu bait. Bagi halaman biasa, hanya 4096 bait perlu dibaca daripada cakera keras/SSD.

Oleh itu, jika hugepage ditindih, ia hanya lebih pantas dibaca jika anda perlu mengakses keseluruhan halaman. Ini bermakna jika anda cuba mengakses bahagian memori yang berlainan secara rawak dan hanya membaca beberapa kilobait, anda harus menggunakan halaman biasa dan tidak perlu risau tentang perkara lain.

Sebaliknya, jika anda perlu mengakses sebahagian besar memori secara berurutan, halaman besar akan meningkatkan prestasi anda. Walau bagaimanapun, anda perlu mengujinya sendiri (bukan dengan perisian abstrak) dan lihat perkara yang berfungsi dengan lebih pantas.

Peruntukan dalam ingatan

Jika anda menulis C, anda tahu bahawa anda boleh meminta jumlah memori yang kecil (atau hampir sewenang-wenangnya besar) daripada timbunan menggunakan malloc(). Katakan anda memerlukan 30 bait memori:

char* mymemory = malloc(30);

Kepada pengaturcara, nampaknya anda "meminta" 30 bait memori daripada sistem pengendalian dan mengembalikan penunjuk kepada beberapa memori maya. Tetapi sebenarnya malloc () hanyalah fungsi C yang memanggil dari dalam fungsi brk dan sbrk untuk meminta atau membebaskan memori daripada sistem pengendalian.

Walau bagaimanapun, meminta lebih banyak memori untuk setiap peruntukan adalah tidak cekap; kemungkinan besar beberapa segmen memori telah pun dibebaskan (free()), dan kita boleh menggunakannya semula. malloc() melaksanakan algoritma yang agak kompleks untuk menggunakan semula memori yang dibebaskan.

Pada masa yang sama, segala-galanya berlaku tanpa disedari untuk anda, jadi mengapa ia perlu membimbangkan anda? Tetapi kerana cabaran free() tidak bermakna begitu memori semestinya dikembalikan serta-merta ke sistem pengendalian.

Terdapat perkara seperti pemecahan memori. Dalam kes yang melampau, terdapat segmen timbunan di mana hanya beberapa bait digunakan, manakala segala-galanya di antaranya telah dibebaskan (free()).

Sila ambil perhatian bahawa pemecahan memori adalah topik yang sangat kompleks, malah perubahan kecil pada program boleh memberi kesan yang ketara. Dalam kebanyakan kes, program tidak akan menyebabkan pemecahan memori yang ketara, tetapi anda harus sedar bahawa jika terdapat masalah dengan pemecahan di beberapa kawasan timbunan, halaman besar boleh memburukkan keadaan.

Penggunaan halaman besar secara terpilih

Selepas membaca artikel itu, anda telah menentukan bahagian mana dalam program anda boleh mendapat manfaat daripada menggunakan hugepages dan mana yang tidak. Jadi patutkah largepages didayakan sama sekali?

Nasib baik boleh guna madvise()untuk mendayakan hugepaging hanya untuk kawasan ingatan di mana ia akan berguna.

Mula-mula, semak bahawa hugepages berjalan dalam mod madvise() menggunakan Directions pada permulaan artikel.

Kemudian, gunakan madvise()untuk memberitahu kernel dengan tepat di mana untuk menggunakan hugepages.

#include <sys/mman.h>
// АллоцируйтС большоС количСство памяти, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ Π±ΡƒΠ΄Π΅Ρ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ
size_t size = 256*1024*1024;
char* mymemory = malloc(size);
// ΠŸΡ€ΠΎΡΡ‚ΠΎ Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅ hugepages…
madvise(mymemory, size, MADV_HUGEPAGE);
// … ΠΈ Π·Π°Π΄Π°ΠΉΡ‚Π΅ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅
madvise(mymemory, size, MADV_HUGEPAGE | MADV_SEQUENTIAL)

Ambil perhatian bahawa kaedah ini hanyalah nasihat kepada kernel tentang cara menguruskan memori. Ini tidak bermakna bahawa kernel akan secara automatik menggunakan hugepages untuk memori tertentu.

Rujuk dokumentasi (manpage)madviseuntuk mengetahui lebih lanjut tentang pengurusan ingatan dan madvise(), topik ini mempunyai keluk pembelajaran yang sangat curam. Jadi jika anda berniat untuk menjadi benar-benar mahir, bersedia untuk membaca dan menguji selama beberapa minggu sebelum anda menjangkakan apa-apa keputusan yang positif.

Apa yang perlu dibaca?

Ada soalan? Tulis dalam komen!

Sumber: www.habr.com

Tambah komen