- Kernel Linux selama ini mempertahankan beberapa mode preemption sebagai kompromi antara throughput dan waktu respons, dan dengan rangkaian patch baru dari Peter Zijlstra, pembahasan preemption malas (PREEMPT_LAZY) kembali bergerak serius
PREEMPT_NONE,PREEMPT_VOLUNTARY,PREEMPT_FULL, danPREEMPT_RTyang ada saat ini berbeda dalam cakupan kapan preemption diizinkan; makin sering preemption terjadi, responsivitas bisa membaik tetapi beban pada throughput dan kontensi lock juga meningkatPREEMPT_LAZYmemakai flagTIF_NEED_RESCHED_LAZYuntuk menandai bahwa “penjadwalan ulang diperlukan, tetapi tidak harus segera”, lalu menunda sebagian besar preemption hingga timer tick- Dalam jangka panjang, tujuannya adalah mengurangi mode preemption non-real-time menjadi
PREEMPT_LAZYdanPREEMPT_FULL, serta menghapus sebagian besar pemanggilancond_resched()di berbagai bagian kernel - Rangkaian patch saat ini masih memerlukan stabilisasi, peninjauan titik pemanggilan, dan pengujian performa lebih lanjut; pada pengujian awal, throughput
PREEMPT_LAZYsedikit di bawahPREEMPT_VOLUNTARY
Mode preemption Linux kernel yang ada saat ini
- Kernel saat ini menyediakan beberapa mode preemption yang mengatur kapan task yang sedang berjalan bisa dipreempt oleh task lain
PREEMPT_NONE: mode paling sederhana yang hanya mengizinkan preemption saat task yang sedang berjalan telah menghabiskan time slice-nyaPREEMPT_VOLUNTARY: mode yang menambahkan banyak titik di dalam kernel tempat preemption bisa dilakukan bila diperlukanPREEMPT_FULL: mode yang mengizinkan preemption di hampir semua titik, kecuali pada bagian yang diblokir kernel seperti saat memegang spinlockPREEMPT_RT: mode yang lebih memprioritaskan preemption daripada hampir segalanya, dan membuat sebagian besar kode yang memegang spinlock juga bisa dipreempt
- Tingkat preemption yang lebih tinggi memungkinkan respons lebih cepat terhadap event seperti pergerakan mouse atau sinyal anomali yang akan segera terjadi di reaktor nuklir
- Sebaliknya, jika preemption terlalu sering, throughput keseluruhan dari pekerjaan intensif CPU yang berjalan lama bisa menurun dan kontensi lock juga dapat meningkat
- Banyak distribusi membangun kernel dengan mode semu
PREEMPT_DYNAMIC- Saat boot, salah satu dari tiga mode non-real-time di atas bisa dipilih
- Nilai default-nya adalah
PREEMPT_VOLUNTARY - Pada sistem dengan
debugfsyang ter-mount, mode saat ini bisa diperiksa di/sys/kernel/debug/sched/preempt
Mengapa cond_resched() diperlukan
PREEMPT_NONEdanPREEMPT_VOLUNTARYtidak mengizinkan preemption arbitrer selama kode kernel sedang berjalan- Jika pekerjaan panjang terus berlangsung di dalam kernel, latensi berlebihan bisa muncul bahkan pada sistem yang tidak memprioritaskan latensi minimum
- Untuk menghindari hal ini, pemanggilan
cond_resched()ditambahkan di berbagai loop yang berjalan lama- Setiap pemanggilan adalah titik preemption sukarela tambahan
- Ini juga bekerja dalam mode
PREEMPT_NONE - Ada ratusan pemanggilan seperti ini di kernel
- Pendekatan ini adalah heuristik yang hanya bekerja pada lokasi yang ditambahkan oleh pengembang
- Bisa ada pemanggilan yang tidak perlu
- Bisa juga ada lokasi yang seharusnya memiliki pemanggilan tetapi terlewat
- Akibatnya, logika pengambilan keputusan scheduling menyebar ke seluruh kode kernel
Cara kerja inti preemption malas
- Kernel melihat beberapa variabel sekaligus saat menentukan apakah task saat ini bisa dipreempt
- Salah satunya,
TIF_NEED_RESCHED, adalah flag yang menandakan bahwa task berprioritas lebih tinggi sedang menunggu akses CPU- Saat task berprioritas tinggi bangun, flag ini bisa disetel pada task yang sedang berjalan
- Jika flag ini tidak ada, kernel tidak perlu mempreempt task saat ini
- Kernel dapat memeriksa
TIF_NEED_RESCHEDdi berbagai titik untuk mempreempt task saat ini- Timer tick scheduler
- Saat kembali ke user space setelah system call
- Saat interrupt handler selesai
- Pemanggilan
cond_resched()
- Patch preemption malas menambahkan flag baru
TIF_NEED_RESCHED_LAZY- Artinya penjadwalan ulang memang diperlukan, tetapi tidak wajib dijalankan seketika
- Dalam mode
PREEMPT_LAZY, sebagian besar event menyetel flag baru ini alih-alihTIF_NEED_RESCHED
- Pada titik saat kernel kembali ke user space, jika salah satu dari dua flag tersebut disetel, scheduler akan dipanggil
- Pada titik preemption sukarela dan jalur kembali dari interrupt, hanya
TIF_NEED_RESCHEDyang diperiksa
Kompromi yang dihasilkan PREEMPT_LAZY
- Dalam
PREEMPT_LAZY, sebagian besar event di dalam kernel tidak langsung mempreempt task yang sedang berjalan - Sebagai gantinya, handler timer tick memeriksa apakah
TIF_NEED_RESCHED_LAZYdisetel- Jika ya,
TIF_NEED_RESCHEDjuga akan disetel - Hasilnya, task yang sedang berjalan bisa dipreempt
- Jika ya,
- Sebuah task biasanya akan berjalan selama waktu yang mendekati time slice-nya, kecuali jika ia secara sukarela melepaskan CPU
- Perilaku ini diharapkan menghasilkan throughput yang baik
- Dengan perubahan ini,
PREEMPT_LAZYjuga dapat berjalan dengan preemption kernel yang hampir selalu aktif, sepertiPREEMPT_FULL- Jika preemption counter mengizinkan, preemption bisa terjadi kapan saja
- Jika tidak ada kondisi lain yang menghalangi, bahkan kode kernel yang berjalan lama pun dapat dipreempt
- Jika preemption segera benar-benar diperlukan, penundaannya tidak dilakukan
- Misalnya, jika hasil pemrosesan interrupt membuat task real-time menjadi runnable, maka
TIF_NEED_RESCHEDakan disetel - Dalam situasi ini, preemption terjadi hampir seketika tanpa menunggu timer tick
- Misalnya, jika hasil pemrosesan interrupt membuat task real-time menjadi runnable, maka
- Jika hanya
TIF_NEED_RESCHED_LAZYyang disetel, preemption tidak akan terjadi- Karena itu, kernel
PREEMPT_LAZYjauh lebih kecil kemungkinannya untuk mempreempt task yang sedang berjalan dibanding kernelPREEMPT_FULL
- Karena itu, kernel
Pekerjaan yang masih tersisa hingga cond_resched() bisa dihapus
- Tujuan jangka panjangnya adalah mengurangi mode preemption non-real-time menjadi dua jenis
PREEMPT_LAZYPREEMPT_FULL
PREEMPT_LAZYakan menempati posisi di antaraPREEMPT_NONEdanPREEMPT_VOLUNTARY, dan direncanakan menggantikan keduanya- Jika preemption menjadi mungkin hampir di mana saja, kebutuhan untuk menambahkan titik preemption sukarela secara terpisah di lokasi tertentu akan berkurang
- Saat ini pemanggilan
cond_resched()masih tersisa- Ini masih dibutuhkan selama
PREEMPT_NONEdanPREEMPT_VOLUNTARYmasih ada - Ini juga membantu agar tidak muncul masalah selama proses stabilisasi preemption malas
- Ini masih dibutuhkan selama
- Dalam rangkaian patch saat ini,
cond_resched()hanya memeriksaTIF_NEED_RESCHED- Karena itu, dalam
PREEMPT_VOLUNTARYatauPREEMPT_NONE, banyak situasi yang sebelumnya langsung dipreempt bisa menjadi tertunda
- Karena itu, dalam
- Steve Rostedt secara khusus menanyakan apakah transisi akan lebih mudah jika
cond_resched()tetap mempertahankan makna lamanya, terutama padaPREEMPT_VOLUNTARY - Thomas Gleixner menilai pilihan untuk hanya memeriksa
TIF_NEED_RESCHEDadalah keputusan yang tepat- Karena itu akan memaksa peninjauan semua pemanggilan
cond_resched() - Pemanggilan yang tidak perlu memeriksa bit lazy dapat dihapus saat
PREEMPT_LAZYditerapkan - Pemanggilan yang memang perlu memeriksa bit lazy harus tetap dipertahankan
- Karena itu akan memaksa peninjauan semua pemanggilan
- Gleixner memperkirakan kurang dari 5% dari pemanggilan
cond_resched()akan perlu memeriksaTIF_NEED_RESCHED_LAZY - Sebelum transisi selesai, ratusan pemanggilan
cond_resched()harus ditinjau, dan sebagian besar perlu dihapus - Rangkaian patch terpisah dari Ankur Arora menangani sebagian detail terkait
- Pengujian performa yang luas juga masih diperlukan
- Dalam pengujian awal Mike Galbraith, throughput preemption malas sedikit di bawah
PREEMPT_VOLUNTARY
- Dalam pengujian awal Mike Galbraith, throughput preemption malas sedikit di bawah
Tujuan akhir
- Hasil dari pekerjaan preemption malas ini bisa membuat kernel menjadi sedikit lebih kecil dan sederhana
- Tujuannya adalah kernel yang memberikan latensi yang dapat diprediksi tanpa harus menaburkan pemanggilan terkait scheduler ke seluruh kode
- Pendekatan saat ini tampak sebagai solusi yang lebih baik, tetapi masih diperlukan waktu untuk benar-benar sampai ke tahap itu
1 komentar
Opini Hacker News
Terlihat menjanjikan. Seperti EEVDF, arahnya menyederhanakan kondisi saat ini sekaligus memperbaikinya, jadi sulit membayangkan yang lebih baik dari ini
Saya penasaran mengapa tingkat preemption bukan mode global, melainkan bukan properti dari event tertentu. Beberapa event harus ditangani dengan latensi lebih rendah daripada event lain
Jadi prioritas tertinggi yang bisa dimiliki sebuah event pun dibatasi oleh seberapa pendek jatah waktu yang bisa diterima program sebelum melewati context switch. Agar dapat merespons event jenis apa pun secara andal dengan latensi rendah, semua program yang intensif CPU harus selalu membayar biaya performa, meskipun event itu sangat jarang terjadi
Titik preemption potensial adalah properti scheduler, dan itulah yang dibahas di sini sebagai mode global. Semakin banyak titik preemption, tentu semakin besar kemungkinan proses dipreempt pada saat yang tidak nyaman, tetapi sekaligus semakin banyak pula kesempatan untuk mencerminkan prioritas dengan benar. Tingkat preemption yang Anda sebut dalam pertanyaan, yaitu prioritas yang diberikan scheduler, memang merupakan properti proses dan bisa dikonfigurasi. Scheduler bawaan Linux juga memberi jatah waktu lebih banyak pada proses yang memiliki prioritas dan berusaha lebih jarang mempreempt proses lain
SCHED_IDLE, SCHED_BATCH, SCHED_NORMAL/OTHER menggunakan preemption tertunda, sedangkan FIFO, RR, DEADLINE memakai perilaku Full yang lama
Karena itu, penting untuk meminimalkan jumlah aplikasi yang berjalan, atau mengontrol secara manual momen-momen singkat yang dialami sebagian besar pengguna. Kadang pekerjaan yang intensif CPU pun lebih mungkin merupakan kode buruk daripada penggunaan sumber daya yang benar-benar efisien. Dalam game, performa harus diprioritaskan, tetapi perlu keseimbangan yang halus agar sistem tidak dibuat berhenti demi multitasking. Bagaimanapun, ini terutama untuk pekerjaan idle, jadi tampaknya tidak perlu diotomatisasi lebih jauh daripada sekadar memberi perintah sederhana agar pengguna bisa men-toggle beberapa tindakan dari skrip
Disebutkan bahwa “kernel saat ini memiliki empat mode yang mengatur kapan satu task dapat dipreempt demi task lain”; saya penasaran apakah ini tentang task kernel atau juga mencakup task pengguna
Saya tidak menemukan angka di thread tertaut tempat patch diunggah. Saya penasaran karena seharusnya sudah ada semacam benchmark awal yang menunjukkan potensi praktis dari perubahan ini
Disebutkan bahwa pengujian performa yang luas diperlukan, Mike Galbraith telah memulai pekerjaan awal, dan hasilnya menunjukkan throughput preemption tertunda sedikit lebih rendah daripada PREEMPT_VOLUNTARY
Saya penasaran seberapa kuat scheduler terikat dengan bagian kode kernel lainnya
Misalnya, jika ingin menyederhanakan scheduler secara besar-besaran untuk aplikasi komputasi ilmiah yang sama sekali tidak peduli pada preemption, apakah itu bisa dilakukan dengan cara yang bersih dan modular? Apakah ada manfaat nyata juga
tasksetNamun dengan begitu Anda benar-benar harus menetapkan pekerjaan ke CPU secara manual, dan sangat mudah juga terjadi semua pekerjaan malah ditempatkan di CPU yang salah. Cara standarnya adalah mengatur interrupt mask agar interrupt tidak masuk ke CPU “kerja”, dan menggunakan cpuset supaya hanya cgroup tertentu yang berjalan pada cpuset yang diberikan
Karena run list menjadi sangat pendek, apa pun yang dilakukan scheduler dampaknya akan cukup kecil. Jika aplikasi tidak banyak melakukan I/O, interrupt juga tidak banyak. Jika bisa memakai kernel tickless—saya tidak tahu sekarang masih opsi terpisah atau sudah default—bisa jadi hampir tidak ada interrupt untuk waktu yang lama
Namun alasan untuk menyederhanakan besar-besaran adalah menghindari bug, bukan karena akan mendapat banyak performa dibanding scheduler default yang dikonfigurasi dengan baik. Ada banyak konfigurasi, tetapi bug di area itu juga tidak banyak. Penyederhanaan yang naif biasanya lebih banyak menghilangkan performa daripada menambahnya. Jika menjalankan sistem non-interaktif, perubahan paling mudah adalah memperbesar kuota waktu proses