Kelebihan dan Kekurangan HugePages

Kelebihan dan Kekurangan HugePages

Terjemahan artikel disiapkan untuk mahasiswa kursus "Pengelola Linux".

Sebelumnya saya telah berbicara tentang cara menguji dan mengaktifkan Hugepages di Linux.
Artikel ini hanya akan berguna jika Anda benar-benar mempunyai tempat untuk menggunakan Hugepages. Saya telah bertemu banyak orang yang tertipu oleh prospek bahwa Hugepages secara ajaib akan meningkatkan produktivitas. Namun, hugepaging adalah topik yang kompleks dan dapat menurunkan kinerja jika digunakan secara tidak benar.

Bagian 1: Memverifikasi bahwa halaman besar diaktifkan di Linux (asli di sini)

Masalah:
Anda perlu memeriksa apakah HugePages diaktifkan di sistem Anda.

solusi:
Ini cukup sederhana:

cat /sys/kernel/mm/transparent_hugepage/enabled

Anda akan mendapatkan sesuatu seperti ini:

always [madvise] never

Anda akan melihat daftar opsi yang tersedia (selalu, gila, tidak pernah), dan opsi yang sedang aktif akan diapit tanda kurung (secara default gila).

gila maksudnya transparent hugepages diaktifkan hanya untuk area memori yang secara eksplisit meminta penggunaan halaman besar gila(2).

selalu maksudnya transparent hugepages selalu diaktifkan untuk semua proses. Hal ini biasanya meningkatkan kinerja, namun jika Anda memiliki kasus penggunaan di mana banyak proses menggunakan sejumlah kecil memori, maka beban memori secara keseluruhan dapat meningkat secara dramatis.

tak pernah maksudnya transparent hugepages tidak akan disertakan bahkan ketika diminta menggunakan madvise. Untuk mengetahui lebih lanjut, hubungi dokumentasi Kernel Linux.

Cara mengubah nilai default

Opsi 1: Langsung berubah sysfs (setelah reboot parameter akan kembali ke nilai default):

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

Opsi 2: Ubah default sistem dengan mengkompilasi ulang kernel dengan konfigurasi yang dimodifikasi (opsi ini hanya disarankan jika Anda menggunakan kernel khusus):

  • Untuk menyetel selalu secara default, gunakan:
    CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
  • Untuk mengatur madvise sebagai default, gunakan:
    CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y

Bagian 2: Kelebihan dan Kekurangan HugePages

Kami akan mencoba menjelaskan secara selektif kelebihan, kekurangan, dan kemungkinan kelemahan menggunakan Hugepages. Karena artikel yang rumit secara teknologi dan bertele-tele kemungkinan besar akan sulit dipahami oleh orang-orang yang tertipu dan berpikir bahwa Hugepages adalah obat mujarab, saya akan mengorbankan keakuratan demi kesederhanaan. Perlu diingat bahwa banyak topik yang sangat kompleks dan oleh karena itu sangat disederhanakan.

Harap dicatat bahwa kita berbicara tentang sistem x64 86-bit yang menjalankan Linux, dan saya hanya berasumsi bahwa sistem tersebut mendukung halaman besar yang transparan (karena halaman besar tidak ditimpa bukan suatu kerugian), seperti yang terjadi di hampir semua Linux modern. lingkungan.

Saya akan melampirkan penjelasan teknis lebih lanjut pada tautan di bawah ini.

Memori Virtual

Jika Anda seorang programmer C++, Anda tahu bahwa objek di memori memiliki alamat tertentu (nilai penunjuk).

Namun, alamat-alamat ini tidak serta merta mencerminkan alamat fisik di memori (alamat RAM). Mereka mewakili alamat dalam memori virtual. Prosesor memiliki modul MMU (unit manajemen memori) khusus yang membantu kernel memetakan memori virtual ke lokasi fisik.

Pendekatan ini memiliki banyak keuntungan, namun yang paling penting adalah:

  • Kinerja (karena berbagai alasan);
  • Isolasi program, yaitu tidak ada program yang dapat membaca dari memori program lain.

Apa itu halaman?

Memori virtual dibagi menjadi beberapa halaman. Masing-masing halaman menunjuk ke memori fisik tertentu, bisa menunjuk ke suatu area di RAM, atau bisa menunjuk ke alamat yang ditetapkan ke perangkat fisik, seperti kartu video.

Sebagian besar halaman yang Anda buka mengarah ke RAM atau ditukar, artinya halaman tersebut disimpan di hard drive atau SSD Anda. Kernel mengelola tata letak fisik setiap halaman. Jika halaman palsu diakses, kernel menghentikan thread yang mencoba mengakses memori, membaca halaman dari hard drive/SSD ke dalam RAM, dan kemudian melanjutkan mengeksekusi thread.

Proses ini bersifat stream transparan, artinya tidak harus dibaca langsung dari HDD/SSD. Ukuran halaman normal adalah 4096 byte. Ukuran halaman besar adalah 2 megabita.

Buffer asosiatif terjemahan (TLB)

Ketika suatu program mengakses halaman memori, CPU harus mengetahui halaman fisik mana yang akan digunakan untuk membaca data (yaitu, memiliki peta alamat virtual).

Kernel memiliki struktur data (tabel halaman) yang berisi semua informasi tentang halaman yang digunakan. Dengan menggunakan struktur data ini, Anda dapat memetakan alamat virtual ke alamat fisik.

Namun, tabel halaman cukup kompleks dan lambat, jadi kita tidak bisa menganalisis seluruh struktur data setiap kali suatu proses mengakses memori.

Untungnya, prosesor kami memiliki TLB yang menyimpan pemetaan antara alamat virtual dan fisik. Artinya meskipun kita perlu mengurai tabel halaman pada upaya akses pertama, semua akses berikutnya ke halaman dapat ditangani di TLB, sehingga memungkinkan pengoperasian yang cepat.

Karena diimplementasikan sebagai perangkat fisik (yang menjadikannya cepat), kapasitasnya terbatas. Jadi jika Anda ingin mengakses lebih banyak halaman, TLB tidak akan dapat menyimpan pemetaan untuk semuanya, sehingga menyebabkan program Anda berjalan lebih lambat.

Halaman besar datang untuk menyelamatkan

Lalu apa yang bisa kita lakukan untuk menghindari luapan TLB? (Kami berasumsi program tersebut masih membutuhkan jumlah memori yang sama).

Di sinilah Hugepage berperan. Daripada 4096 byte hanya membutuhkan satu entri TLB, satu entri TLB kini dapat menghasilkan 2 megabita. Anggaplah TLB memiliki 512 entri, di sini tanpa Hugepages kita dapat mencocokkan:

4096 bβ‹…512=2 MB

Lalu bagaimana kita membandingkannya dengan mereka:

2 MBβ‹…512=1 GB

Inilah mengapa Hugepages luar biasa. Mereka dapat meningkatkan produktivitas tanpa banyak usaha. Namun ada peringatan penting di sini.

Pemalsuan halaman besar

Kernel secara otomatis memonitor seberapa sering setiap halaman memori digunakan. Jika memori fisik (RAM) tidak mencukupi, kernel akan memindahkan halaman yang kurang penting (jarang digunakan) ke hard disk untuk mengosongkan sebagian RAM untuk halaman yang lebih penting.
Pada prinsipnya, hal yang sama berlaku untuk Hugepages. Namun, kernel hanya dapat menukar seluruh halaman, bukan byte individual.

Katakanlah kita mempunyai program seperti ini:

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

Dalam hal ini, kernel perlu mengganti (membaca) informasi sebanyak 2 megabyte dari hard drive/SSD hanya agar Anda dapat membaca satu byte. Sedangkan untuk halaman biasa, hanya 4096 byte yang perlu dibaca dari harddisk/SSD.

Oleh karena itu, jika hugepage ditimpa, pembacaannya hanya akan lebih cepat jika Anda perlu mengakses seluruh halaman. Ini berarti bahwa jika Anda mencoba mengakses berbagai bagian memori secara acak dan hanya membaca beberapa kilobyte, Anda harus menggunakan halaman biasa dan tidak mengkhawatirkan hal lain.

Di sisi lain, jika Anda perlu mengakses sebagian besar memori secara berurutan, halaman besar akan meningkatkan kinerja Anda. Namun, Anda perlu mengujinya sendiri (bukan dengan perangkat lunak abstrak) dan melihat mana yang bekerja lebih cepat.

Alokasi dalam memori

Jika Anda menulis C, Anda tahu bahwa Anda dapat meminta sejumlah kecil memori (atau hampir sewenang-wenang besar) dari heap menggunakan malloc(). Katakanlah Anda membutuhkan memori 30 byte:

char* mymemory = malloc(30);

Bagi seorang programmer, tampaknya Anda "meminta" 30 byte memori dari sistem operasi dan mengembalikan pointer ke beberapa memori virtual. Tapi sebenarnya malloc () hanyalah fungsi C yang memanggil dari dalam fungsi tersebut brk dan brk untuk meminta atau mengosongkan memori dari sistem operasi.

Namun, meminta lebih banyak memori untuk setiap alokasi tidak efisien; kemungkinan besar beberapa segmen memori telah dibebaskan (free()), dan kita dapat menggunakannya kembali. malloc() mengimplementasikan algoritma yang cukup kompleks untuk menggunakan kembali memori yang dibebaskan.

Pada saat yang sama, segala sesuatu terjadi tanpa Anda sadari, jadi mengapa hal itu harus membuat Anda khawatir? Tapi karena tantangannya free() tidak berarti itu memori harus segera dikembalikan ke sistem operasi.

Ada yang namanya fragmentasi memori. Dalam kasus ekstrim, terdapat segmen heap yang hanya menggunakan beberapa byte, sementara semua yang ada di antaranya telah dibebaskan (free()).

Harap dicatat bahwa fragmentasi memori adalah topik yang sangat kompleks, dan bahkan perubahan kecil pada suatu program dapat berdampak signifikan. Dalam kebanyakan kasus, program tidak akan menyebabkan fragmentasi memori yang signifikan, namun Anda harus menyadari bahwa jika ada masalah dengan fragmentasi di beberapa area heap, halaman besar dapat memperburuk situasi.

Penggunaan halaman besar secara selektif

Setelah membaca artikel ini, Anda telah menentukan bagian mana dari program Anda yang dapat memperoleh manfaat dari penggunaan halaman besar dan mana yang tidak. Jadi apakah halaman besar harus diaktifkan?

Untung bisa pakai madvise()untuk mengaktifkan halaman besar hanya untuk area memori yang berguna.

Pertama, periksa apakah hugepage berjalan dalam mode madvise() menggunakan Instruksi di awal artikel.

Lalu, gunakan madvise()untuk memberi tahu kernel di mana tepatnya menggunakan halaman besar.

#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)

Perhatikan bahwa metode ini hanyalah saran kepada kernel tentang cara mengelola memori. Ini tidak berarti bahwa kernel akan secara otomatis menggunakan halaman besar untuk memori tertentu.

Lihat dokumentasi (halaman manual) gilauntuk mempelajari lebih lanjut tentang manajemen memori dan madvise(), topik ini memiliki kurva pembelajaran yang sangat curam. Jadi jika Anda ingin benar-benar menguasainya, bersiaplah untuk membaca dan mengujinya selama beberapa minggu sebelum Anda mengharapkan hasil yang positif.

Apa yang harus dibaca?

Ada pertanyaan? Tulis di komentar!

Sumber: www.habr.com

Tambah komentar