2 poin oleh GN⁺ 2023-11-17 | 1 komentar | Bagikan ke WhatsApp
  • Dukungan Linux untuk preemption real-time adalah pekerjaan yang telah menunggu masuk ke mainline selama hampir 20 tahun, dan Thomas Gleixner menyatakan di Linux Plumbers Conference 2023 bahwa hambatan besar terakhirnya adalah printk()
  • Tujuannya adalah agar proses dengan prioritas tertinggi dapat berjalan dengan latensi pendek yang dapat diprediksi, dan untuk itu banyak bagian inti kernel telah ditulis ulang selama waktu yang lama
  • printk() dapat dipanggil dari konteks apa pun sehingga jauh lebih rumit daripada sekadar keluaran log, dan output sinkron saat ini bertentangan dengan target latensi real-time
  • Sejak 2018, sekitar 300 patch telah masuk upstream atau sedang menunggu di linux-next, dan tugas yang tersisa adalah handover pesan darurat serta penanganan keamanan driver konsol
  • Setelah pembenahan printk() selesai dan sisa kode real-time siap di linux-next, penggabungan pada merge window yang sama juga dimungkinkan, tetapi Gleixner mengatakan ia tidak akan lagi memprediksi kapan itu selesai

Pekerjaan preemption real-time yang berlangsung hampir 20 tahun

  • Dukungan real-time Linux pertama kali muncul di LWN pada 2004, dan lama terlihat seperti “tinggal sedikit lagi selesai”
  • LWN bahkan menulis judul the realtime preemption endgame pada 2009, tetapi di Linux Plumbers Conference 2023, Gleixner menilai bahwa kali ini garis akhirnya benar-benar sudah dekat
  • Bagi Gleixner sendiri, ini adalah pekerjaan yang berlangsung hampir 25 tahun
    • Ia mulai mengerjakan dukungan real-time Linux pada 1999
    • Proyeknya sendiri juga telah berlanjut hampir 20 tahun
  • Ia mengatakan akan ada “a big party” saat pekerjaan ini selesai, tetapi hambatan besar terakhir yang tersisa adalah printk()

Latensi yang ingin dikurangi oleh preemption real-time

  • Tujuan preemption real-time adalah agar proses dengan prioritas tertinggi selalu bisa berjalan dengan latensi minimum dan dapat diprediksi
  • Untuk itu, kernel harus bisa dipreempt dalam sebanyak mungkin situasi, dan pengecualian harus dibatasi pada cakupan yang sempit dan jelas
  • Cara kerja dasarnya telah mapan sejak lama, tetapi menyelesaikan detail-detail masalahnya membutuhkan waktu yang panjang
  • Dalam proses ini, banyak bagian dari kernel inti telah ditulis ulang, dan manfaatnya meluas ke seluruh kernel, melampaui use case real-time

Mengapa printk() menjadi hambatan terakhir

  • Ketika kode kernel perlu mengirim pesan ke konsol dan log, ia memanggil printk() atau fungsi yang dibangun di atasnya
  • Ini terlihat seperti output sederhana, tetapi printk() harus bekerja dalam hampir semua konteks
    • Dapat dipanggil bahkan dari handler non-maskable interrupt
    • Dapat dipanggil lagi dari dalam pemanggilan printk() lain
    • Dalam situasi crash sistem, informasi output bisa sangat penting sehingga sulit membatasi konteks pemanggilannya
  • Karena tuntutan ini, printk() memiliki masalah konkurensi, locking, dan penanganan driver yang saling terkait secara kompleks
  • printk() di kernel saat ini memiliki struktur sinkron sepenuhnya
    • Pemanggilan tidak akan kembali sampai pesan dikirim ke semua tujuan yang telah dikonfigurasi
    • Gleixner menyebut struktur ini “stupid”
    • Terutama saat boot, sebagian besar output mungkin hanya noise, tetapi sistem tetap harus menunggu sampai semuanya dikirim
  • Waktu tunggu ini berbenturan langsung dengan latensi yang ingin dikurangi oleh pekerjaan real-time
  • Para pengembang real-time sudah lama memindahkan output printk() ke thread terpisah agar menjadi asinkron, tetapi kode itu lebih mirip serangkaian hack daripada solusi mendasar

Pengerjaan ulang printk() sejak 2018

  • Masalah printk() mulai ditangani secara serius sejak 2018, dan sekitar 300 patch telah masuk upstream atau sedang menunggu di linux-next
  • Saat ini, tiga set patch terakhir untuk menyelesaikan pekerjaan itu sedang berjalan
  • Salah satu detail tersulit adalah mekanisme handover
    • Ketika kernel harus mencetak pesan darurat seperti saat crash, kernel mungkin perlu mengambil alih kontrol dari konsol yang sedang mencetak pesan berprioritas lebih rendah
    • Tidak mudah melakukan ini dengan aman dalam konteks apa pun
  • Tantangan lain adalah menandai driver konsol yang tidak aman digunakan dalam konteks tertentu
    • Misalnya, jika perlu mencetak pesan saat non-maskable interrupt tetapi memerlukan pengaturan mode video, itu tidak akan bisa bekerja
  • Gleixner menjawab bahwa tidak ada perubahan konsep mendasar dalam setahun terakhir
    • Kernel memiliki 76 driver konsol yang perlu diperbaiki
    • Kode handover telah diubah agar driver dapat diperbarui satu per satu, tanpa harus memperbaiki semuanya sekaligus
    • Diskusi tambahan terbaru tentang pekerjaan printk() ada di artikel ini

Output asinkron dan syarat penggabungan ke mainline

  • Ketika Masami Hiramatsu bertanya pesan kernel mana yang harus dicetak secara sinkron, Gleixner menjawab bahwa hampir semuanya harus dibuat asinkron
  • Output asinkron mengurangi latensi yang muncul dari pemanggilan printk(), dan memungkinkan adanya thread kernel terpisah untuk setiap konsol
    • Konsol yang cepat bisa berjalan dengan kecepatannya sendiri tanpa menunggu konsol yang paling lambat
  • Kode diubah agar pesan penting disalin sepenuhnya ke buffer pesan sebelum baris pertama dicetak
    • Ini adalah langkah antisipasi jika driver konsol yang rusak merusak seluruh sistem
  • Untuk urutan output yang lebih aman, sistem menulis terlebih dahulu ke konsol yang diketahui aman
    • Misalnya, jika ada persistent-memory store, sistem menyimpan pesan lebih dulu sebelum mengirimkannya ke perangkat fisik
    • Ini adalah cara untuk mempertahankan isi output meskipun driver yang rusak mematikan sistem
  • Gleixner mengatakan pekerjaan ini memang sudah dekat, tetapi printk() sulit diprediksi, sehingga ia tidak akan lagi menyebutkan perkiraan waktu selesai
  • Meski begitu, ia berharap sisa kode preemption real-time bisa masuk ke mainline sebelum ulang tahun ke-20 pada akhir 2024
  • Ketika Clark Williams bertanya apakah sisa kode real-time akan dimasukkan pada merge window yang sama setelah patch printk() masuk upstream, Gleixner menjawab “yes” secara bersyarat
    • Jika semua kode sudah staged di linux-next dan tampak siap, itu bisa dicoba

1 komentar

 
GN⁺ 2023-11-17
Opini Hacker News
  • QNX sudah menangani bagian ini dengan benar sejak puluhan tahun lalu. Mikrokernel memiliki batas atas untuk semua pekerjaan yang dilakukannya, dan kodenya pun hanya puluhan ribu baris
    Mikrokernel hanya melakukan alokasi memori, dispatch CPU, dan pengiriman pesan antarproses. Sisanya, termasuk driver dan logger, semuanya berada di ruang pengguna, dan bisa dipreempt oleh thread dengan prioritas lebih tinggi
    Kernel QNX tidak menangani string. Tidak ada parsing, formatting, maupun pesan. Linux sudah menjadi terlalu besar untuk real-time, dan karena harus membuat jutaan baris kode kernel semuanya bisa dipreempt, strukturnya sendiri tidak cocok untuk real-time. Itulah sebabnya butuh 20 tahun untuk memperbaikinya

    • Contoh modernnya adalah seL4. Setahu saya ia tidak melakukan alokasi memori dinamis, dan juga telah diverifikasi secara formal untuk berbagai properti
      Kontribusi terbesarnya terhadap desain kernel mungkin adalah penggunaan capability secara menyeluruh, sebagai cara untuk mengekspor kendali ke ruang pengguna dengan aman sekaligus fleksibel
    • Bukankah QNX dipakai di sistem infotainment mobil? Saya penasaran dipakai di mana lagi
      Membesarnya kernel itu sendiri tidak terlalu saya khawatirkan. Banyak waktu pengembangan dicurahkan ke Linux, dan meskipun desktop tidak setinggi server dalam prioritas, pekerjaan untuk membuat kernel berkinerja baik di perangkat portabel dan semacamnya juga akan menguntungkan pengguna desktop
    • Saat ini kernel SDP 8 berjumlah 15.331 baris, termasuk komentar dan Makefile
    • Terlihat seperti fungsi main yang terstruktur baik dalam C atau bahasa turunan C. main hanya mengoordinasikan pemanggilan fungsi lain, dan meskipun di sini kernel QNX melakukan inisialisasi lebih sedikit, konsep besarnya mirip
      Saya bukan pengembang kernel, tetapi cara mempertahankannya tetap sederhana seperti ini tampak bagus
    • Sekitar 90% dari “kernel berjuta-juta baris” adalah driver perangkat. Jika ingin berjalan di hardware sembarang, pada akhirnya mikrokernel pun tetap membutuhkannya
  • Ada contoh yang menunjukkan bagaimana kernel tetap berusaha mengeluarkan pesan log dengan cara apa pun bahkan pada sistem yang sedang sekarat, dan bagaimana itu digunakan di lingkungan produksi nyata
    https://netflixtechblog.com/kubernetes-and-kernel-panics-ed6...

  • Saya penasaran apakah setelah masalah ini diperbaiki, sebagian kombinasi hardware/software yang dibuat untuk real-time bisa cukup banyak digantikan. Sekarang ada banyak pilihan chip ARM dan x86 yang murah, hemat daya, dan ber-clock tinggi
    Karena clock-nya sangat tinggi, meskipun ada kasus yang terlewat, sering kali ada banyak siklus cadangan sehingga real-time yang sempurna mungkin menjadi kurang penting. Saya tahu ini tidak elegan maupun efisien, tetapi kadang komponen umum mengalahkan ketepatan

    • Pekerjaan yang membutuhkan hard real-time tidak bisa dipuaskan dengan “meski terlewat masih ada banyak siklus cadangan”. Ini juga bukan sekadar soal siklus CPU
      Satu pekerjaan yang dibuat buruk bisa menahan kernel dan mencegahnya melakukan hal yang berguna. Inti hard real-time adalah “tidak ada apa pun yang bisa menghalangi eksekusi pekerjaan penting ini”. Di bidang otomotif atau dirgantara, sistem kendali harus tetap berjalan dalam kondisi apa pun
    • Aplikasi dengan kebutuhan real-time sungguhan biasanya memiliki persyaratan yang begitu ketat sehingga bahkan kemungkinan gagal yang sangat kecil pun tidak dapat diterima. Pikirkan avionik, perangkat medis, otomotif, dan aplikasi militer
      Jika benar-benar membutuhkan real-time, berarti memang benar-benar membutuhkannya, dan “cukup mendekati” itu tidak ada. Namun ini hanya kesan saya sebagai orang luar
    • Saat membuat aplikasi real-time dengan chip ARM hemat daya dan ber-clock tinggi, sistem operasi sama sekali tidak dipakai. Untuk penggunaan seperti itu, x86 juga tidak dipertimbangkan
      Sistem operasi, sekalipun RTOS, terlalu banyak mengganggu. Saya tidak tahu perubahan ini akan mengubah apa. Namun ini bergantung pada aplikasinya, dan ada banyak kasus yang hanya membutuhkan “hampir real-time”, jadi bisa berguna untuk penggunaan seperti itu
    • Benar, tetapi ini tidak akan secara ajaib menghilangkan kebutuhan akan core khusus. Kemungkinan besar bentuknya adalah menginstruksikan scheduler agar menempatkan pekerjaan real-time yang tidak boleh dipreempt hanya pada satu core LITTLE
  • Diskusi di sini berfokus pada pembedaan antara aplikasi real-time “hard” dan “soft”. Untuk hard real-time, kemungkinan besar Anda sejak awal tidak ingin memakai sistem operasi umum seperti Linux, sementara pada soft real-time seperti konferensi video atau pemutaran audio, sesekali tersendat atau kehilangan beberapa frame bukanlah bencana
    Argumennya adalah bahwa RT Linux akan menjadi solusi kuat untuk penggunaan soft real-time seperti itu. Namun penggunaan soft yang diusulkan itu sekarang pun sudah bisa dilakukan dengan embedded Linux. Pemutaran video atau audio software berlatensi rendah bukannya tidak mungkin, dan 20 tahun lalu pun sudah mungkin
    Masalah muncul ketika pada sistem yang sibuk, I/O yang tidak bisa dipreempt sering menyela, tetapi di lingkungan embedded hal seperti itu jarang terjadi. Ada alasan yang meyakinkan untuk membuat kernel sepenuhnya bisa dipreempt dan memberi lebih banyak kendali penjadwalan, tetapi itu tidak banyak berkaitan dengan alasan bahwa Linux harus menggantikan sistem operasi real-time minimal atau kode bare-metal
    Ini lebih mirip praktik higienis yang baik, dan membuat sistem operasi bekerja lebih baik di bawah beban bahkan untuk aplikasi non-real-time

  • Ini kabar baik, tetapi sekalipun kernel Linux menjadi real-time, perangkat kerasnya kemungkinan besar tetap tidak real-time karena cache dan sihir rumit di dalam CPU
    Perangkat keras yang besar dan kompleks tidak cocok untuk real-time sejati. Karena itu AbsInt dan alat worst-case execution time (WCET) terutama menangani arsitektur CPU yang sederhana. 8051 benar-benar akan bertahan selamanya. Sebagai catatan, ada juga Zephyr RTOS

    • Sejauh yang saya tahu, fitur-fitur CPU modern tidak menghalangi penggunaan real-time. Apa pun bisa dipakai untuk membuat sistem real-time selama punya batas atas dan bisa ditalar
      Cukup asumsikan kondisi seperti tidak ada cache hit sama sekali dan beban maksimum. Kalau kita bisa menetapkan batas atas waktu yang dibutuhkan, itu tidak masalah
    • Menurut saya ini cukup berguna pada board kelas mikrokontroler yang “besar” seperti Raspberry Pi. Di sana ada semacam budaya real-time, dan meski tidak melakukan bit banging langsung dengan CPU, dari luar semuanya terlihat tepat waktu
      Timer bisa menerima input encoder kuadratur dan hanya mengirim interrupt saat wrapping, atau sistem GPIO bisa dihubungkan ke DMA untuk melakukan streaming memori ke pin output tanpa campur tangan CPU. Streaming ke DAC atau transfer DMA dari ADC ke memori juga memungkinkan. Hal-hal seperti ini sering melewati cache demi latensi yang dapat diprediksi
    • SpaceX menggunakan prosesor x86 di roketnya. Helikopter drone kecil yang dikirim NASA ke Mars juga memakai core ARM yang “cukup besar”, sampai-sampai bisa menjalankan Android lama
    • Pernyataan bahwa perangkat keras besar dan kompleks tidak cocok untuk real-time sejati tidak selalu tepat. Ada core real-time kelas atas seperti Arm Cortex-R82
      Dalam praktiknya, banyak sistem real-time harus memproses dan mengagregasi data sensor yang terus bertambah, sehingga makin lama makin kuat
    • 68000-lah raja real-time yang sebenarnya
  • Saat masih junior, saya mengalami banyak sekali wawancara yang membuat frustrasi karena pewawancara tidak tahu apa sebenarnya arti real-time. Banyak orang melewatkan konsep “dan latensi yang dapat diprediksi” seperti di tulisan itu, dan tampaknya menganggap real-time sekadar berarti “cepat”

    • Saya bahkan ingin menghapus bagian “minimal”. Inti real-time adalah adanya batas atas yang dapat diprediksi untuk sebuah pekerjaan. Ini berarti sistem tersebut bisa saja rata-rata lebih lambat daripada sistem non-real-time
      Jika mengendalikan sistem pengereman mobil, “latensi rata-rata 50 ms tetapi maksimum 80 ms” mungkin bisa diterima, tetapi “latensi rata-rata 1 ms tetapi bisa menjadi panjang secara arbitrer dan mungkin memakan beberapa detik” tidak bisa diterima
    • Seperti ungkapan lama, “real time” bukan “real fast”. Pembedaan antara hard real-time dan soft real-time memang membuatnya agak kabur, tetapi menurut saya banyak pengembang perangkat lunak juga tidak benar-benar memahami apa itu real-time
  • Logging sinkron kembali menimbulkan masalah. Di perusahaan, kami mengalami hal serupa karena GLOG (library logging Google); misalnya jika stdout adalah file, ia bisa terblokir pada I/O disk
    Saat layanan kami berhenti lebih dari 100 ms, 90–99% penyebabnya adalah GLOG

    • Saya sering berdiskusi seperti ini dengan rekan-rekan soal logging. “Ada API best-effort dan API guaranteed-delivery.” “Kami ingin guaranteed delivery!” “Kalau antarmuka logging guaranteed-delivery sedang offline atau lambat, layanan bisa berhenti; tidak apa-apa?” “Tidak boleh, jangan sampai berhenti!”
      “Kalau sesuatu wajib dicatat sebagai log tetapi log tidak bisa ditulis, apa yang akan dilakukan?” Belakangan saya cukup menunjuk ke teorema CAP dan mengatakan bahwa logging sama seperti sistem terdistribusi lainnya. Mungkin karena ada artikel Wikipedia dengan gambar segitiga dan kata “teorema”, orang-orang cenderung menerimanya
    • Pernah seluruh lingkungan produksi berhenti sekali karena server syslog macet. Log sedang didorong lewat TCP, dan blocking itu merambat ke seluruh lingkungan produksi
      Setelah itu kami beralih ke pengiriman UDP. Lebih baik kehilangan sebagian log daripada kehilangan seluruh operasi produksi
    • Di library logging $MSFT juga ada masalah jenis “library logging merusak semuanya”. Bayangkan 100 thread masing-masing memiliki buffer logging 300 MB
      Tentu saja memorinya hancur, dan server pun crash bahkan pada SKU termahal Azure App Service
    • Jika ketersediaan produk bergantung pada ±100 ms, berarti desainnya sangat keliru, dan itu bukan salah library logging. Pengguna tidak akan peduli apakah setelah menekan tombol proses selesai 100 ms lebih lama
  • Ini benar-benar mengingatkan masa lalu. Sekitar 17–18 tahun lalu, saya mengompilasi kernel Debian dengan RT_PREEMPT untuk dipakai pada peralatan ilmiah yang membutuhkan timing lebih ketat
    Latensi dan jitternya sangat mengesankan. Setelah itu hampir tidak pernah saya pikirkan lagi, tetapi saat membuat aplikasi embedded dengan Raspberry Pi dan tidak ingin beralih ke mikrokontroler yang memakai RTOS, sepertinya ini punya banyak kegunaan

    • Menarik Anda menyebut Raspberry Pi. Satu atau dua hari lalu saya melihat tulisan bahwa RpiOS dimulai dan berjalan di atas RTOS
      Saya pernah melihat usulan lama bahwa Linux bisa dijalankan sebagai sebuah task di RTOS, jadi ini terasa sangat menarik. Hal-hal yang membutuhkan deadline hard real-time dijalankan di RTOS, sehingga tidak terpengaruh latensi yang bisa ditimbulkan oleh sistem memori virtual. Saya tidak ingat apakah itu hanya ide sederhana atau benar-benar diimplementasikan, dan saya juga baru sekali melihat penyebutan bahwa RpiOS berada di atas RTOS, jadi saya penasaran
  • Penasaran apa artinya ini bagi pengguna umum. Apakah ini fitur yang hanya diaktifkan dalam situasi yang sangat spesifik, atau bisa juga menghadirkan sistem yang lebih responsif bagi masyarakat umum?

    • Sejauh yang saya pahami, real-time membuat sistem menjadi lebih lambat. Agar menjadi real-time, semuanya harus diberi alokasi waktu
      Setiap tugas mendapat anggaran X dan tidak boleh melampauinya. Jika dalam kasus terbaik cepat tetapi dalam kasus terburuk lambat, itu berarti sistem harus selalu mengasumsikan kasus terburuk
    • RT tidak selalu memperbaiki latensi, melainkan memberi batas atas tetap pada sebagian tugas. Namun, pekerjaan yang diperlukan untuk memungkinkan RT jelas dapat memperbaiki latensi pada kasus umum
      Contoh menghindari pemanggilan printk() sinkron persis seperti itu, dan seharusnya memperbaiki latensi saat beban tinggi meski RT tidak diaktifkan. Saya rasa kernel RT yang sepenuhnya di-upstream tidak akan berperilaku berbeda dari kernel biasa kecuali benar-benar menjalankan proses RT. Alasan upstream memakan waktu lama adalah karena diperlukan kompromi untuk memungkinkan RT, dan menurut artikel, kompromi seperti itu kini tidak banyak tersisa
    • Jika yang dimaksud pengguna “umum” adalah pengguna desktop, tidak ada perubahan besar. Namun ini hal besar bagi perangkat tertanam seperti kendali industri dan peralatan telekomunikasi
      Karena ketika penjadwalan real-time diperlukan, mereka bisa menggunakan kernel mainline terbaru
    • Sejauh yang saya pahami, Linux menjadi pilihan dalam situasi yang membutuhkan RTOS. Ini ditujukan untuk sistem penting seperti penerbangan dan perangkat medis, dan tidak banyak berpengaruh bagi pengguna umum
    • Pengguna akhir desktop yang paling umum merasakan manfaatnya adalah orang-orang yang melakukan pekerjaan audio. Di sana latensi, terutama jitter, bisa cukup merepotkan
  • Penasaran bagaimana pendapat kalian tentang Xenomai[1]. Sudah beberapa tahun menggunakannya tanpa masalah
    Di BeagleBone Black, jitter biasanya berada di kisaran ratusan nanodetik, dan saya menganggapnya real-time “keras”. Bisa menjadwalkan tugas periodik dalam satuan puluhan mikrodetik dan tidak pernah terlewat
    Berbeda dengan Real-Time Linux yang mencoba membuat Linux itu sendiri dapat dipreempt, Xenomai pada dasarnya adalah kernel tersendiri dan menjalankan Linux sebagai tugas di atasnya. Ia menyediakan ABI sehingga tugas buatan pengguna dapat berjalan berdampingan dengan Linux atau dengan prioritas lebih tinggi. Misalnya, masalah printk() dapat dilewati: Xenomai tidak peduli dan dengan senang hati melakukan context switch dari printk untuk menjalankan tugas pengguna
    Kekurangannya adalah di dalam konteks Xenomai, pemanggilan sistem biasa tidak dapat dilakukan. Sebenarnya bisa, tetapi tentu saja itu merusak model real-time. Misalnya, jika memanggil printf() atau malloc() dari dalam tugas Xenomai, itu tidak dapat dipreempt. ABI Xenomai sebisa mungkin mereplikasi hal-hal yang mungkin dibutuhkan dari sisi pemanggilan sistem, dan jika Anda puas menangani alokasi heap sendiri, ia bekerja dengan sangat baik
    [1]: https://xenomai.org/