Kenapa halaman ini penting
Halaman ini menjelaskan bagaimana Alur Scheduler Tick dan Drain masuk ke model eksekusi ZeroKernel yang lebih besar, masalah apa yang sebenarnya diselesaikan, dan trade-off apa yang benar-benar Anda bayar saat fitur ini dipakai di firmware produksi. Tujuannya bukan melihat Alur Scheduler Tick dan Drain sebagai satu API terpisah, tetapi memahami posisinya di dalam bounded scheduling, disiplin queue, visibilitas fault, dan pemilihan profile.
Baca topik ini sebagai kontrak operasional. Mulai dari jalur paling kecil yang benar-benar jalan, pasang dulu di profile lean, lalu baru naik ke routing, diagnostics, atau state transport yang lebih kaya setelah Anda bisa membuktikan hasil timing-nya tetap layak dibanding tambahan flash dan RAM. Pola pikir ini yang menjaga ZeroKernel tetap berguna di board kecil dan tidak berubah jadi abstraksi yang gemuk.
Pola paling aman selalu sama: tentukan batas runtime-nya, jaga hot path tetap pendek, ukur efeknya dengan compare script, lalu baru naikkan kompleksitas. Contoh di bawah bukan pemanis; itu adalah pola minimum yang bisa Anda ambil ke firmware nyata saat Anda butuh integrasi yang rapi, bukan loop manual yang sulit dipertahankan.
Tiga pola yang langsung bisa dipakai
Pakai satu task bounded untuk hot path, lalu biarkan scheduler menjaga phase alignment seiring waktu.
ZeroKernel.begin(boardMillis);
ZeroKernel.addTask("Fast", fastTask, 10, 0, true);
ZeroKernel.tick();
Pindahkan routing dan transport non-kritikal dari body task utama agar fast path tetap terprediksi.
const auto key = ZeroKernel.makeTopicKey("telemetry.sample");
ZeroKernel.publishDeferredFast(key, sampleValue);
ZeroKernel.flushEvents();
Baca timing report dan stats bersamaan agar Anda bisa membuktikan biaya tiap lapisan abstraksi.
const auto stats = ZeroKernel.getStats();
const auto timing = ZeroKernel.getTimingReport();
Serial.println(timing.maxTickMs);
Apa yang perlu Anda cek saat memakainya
- Validasi timing lebih dulu, baru bentuk API. API yang terlihat rapi bukan kemenangan kalau fast miss justru naik.
- Pilih profile paling kecil yang masih cocok, lalu aktifkan modul opsional hanya saat payoff terukurnya benar-benar jelas.
- Jaga callback dan langkah transport tetap bounded supaya watchdog, panic flow, dan batas queue tetap punya arti.
Kesalahan umum yang membuat hasil jadi menyesatkan
- Jangan menyalin pola demo ke firmware produksi tanpa mengukurnya di board dan profile build yang benar-benar akan dipakai.
- Jangan membaca angka sukses tanpa membaca queue depth, timing, dan label workload di sampingnya.
- Jangan menyalakan diagnostics atau kompatibilitas berat di target lean hanya karena default-nya terasa nyaman.
Urutan kerja yang disarankan
Boot runtime, daftar task minimum yang berguna, lalu buktikan baseline timing bersih sebelum menambah lapisan opsional.
Masukkan routing, diagnostics, atau transport satu lapisan demi satu agar biaya dan payoff-nya tetap jelas.
Update docs, chart, atau klaim publik hanya setelah workload yang sama lolos jalur validasi yang sama lebih dari sekali.
Kenapa tick adalah detak operasional runtime
tick() adalah satu panggilan yang memajukan runtime. Semua properti penting yang Anda pedulikan—cadence task, inspeksi watchdog, pengurasan queue, signal runtime, dan transisi state—bergantung pada panggilan ini berlangsung sering dan bersih.
Karena itu loop utama firmware sebaiknya tetap kecil. Semakin dekat loop Anda ke bentuk “panggil tick, lalu selesai”, semakin mudah runtime mempertahankan janjinya. Begitu kode di sekelilingnya mulai menambah loop manual, blocking wait, atau retry liar, Anda sedang mengembalikan masalah yang tadi ingin dihilangkan.
Anggap tick() sebagai metronom eksekusi. Anda tidak ingin ada kode lain yang “mengimprovisasi” di sekelilingnya.
Apa yang terjadi dalam satu putaran scheduler
- Runtime membaca clock aktif.
- Ia mengecek task mana yang due dengan aritmetika waktu yang aman untuk wrap-around.
- Ia memilih task terbaik berdasarkan due time, priority, dan state task.
- Ia menjalankan satu callback yang bounded.
- Ia menguras event, command, dan work queue secara terbatas.
- Ia memperbarui watchdog, timing report, dan transisi state kernel.
Struktur ini yang menjaga runtime tetap deterministik. Ia menghindari dua ekstrem: terlalu sedikit kerja sampai runtime tidak berguna, dan terlalu banyak kerja per tick sampai muncul scheduler tersembunyi di dalam scheduler utama.
Apa yang tidak boleh terjadi di tick
Jalur tick() yang sehat harus pendek dan berulang. Ia bukan tempat untuk menunggu socket selesai, memutar retry jaringan sampai konek, atau menunggu periferal sampai siap.
- Jangan block pada I/O di kode yang membungkus
tick(). - Jangan memanggil
tick()secara rekursif dari dalam task. - Jangan menganggap queue drain gratis; itu tetap kerja yang punya biaya timing.
Tiga pola loop yang perlu dikenali
void loop() {
ZeroKernel.tick();
}
Ini bentuk loop steady-state yang paling disarankan. Jika loop Anda bisa tetap seperti ini, perilaku runtime akan paling mudah dijaga.
void loop() {
sampleFrontPanelButtons();
ZeroKernel.tick();
}
Ini masih boleh saat fungsi tambahannya kecil, bounded, dan tidak memulai pekerjaan blocking sendiri. Gunakan secukupnya.
void loop() {
while (!client.connected()) {
reconnectClient();
}
ZeroKernel.tick();
}
Ini pola yang harus dihindari. Loop utama berubah menjadi retry loop manual dan scheduler akan kelaparan saat konektivitas sedang buruk.
Cara tahu tick masih sehat
Pakai angka, bukan perasaan. Jika fast_miss tetap nol, queue depth tetap bounded, dan maksimum tick time tidak drift naik setelah perubahan, maka loop masih bekerja sebagaimana mestinya. Kalau angka ini memburuk, solusi biasanya adalah memindahkan kerja keluar dari jalur langsung, bukan memanggil tick() lebih agresif.
Script compare ada untuk membuat hal ini terlihat. Itu cara tercepat untuk tahu apakah perubahan Anda benar-benar membantu atau hanya memindahkan biaya ke tempat lain.
FAQ tick
Apakah tick boleh dipanggil dari dalam task lain?
Tidak. Panggil sekali dari loop utama. Tick yang bersarang membuat runtime sulit diprediksi dan bisa merusak model bounded.
Kenapa tick tetap jadi salah satu API paling penting?
Karena semua klaim runtime—timing, queue bound, update watchdog—bergantung pada tick dipanggil dengan sering dan bersih.
Bagaimana cara menurunkan tekanan pada tick saat project membesar?
Pindahkan pekerjaan berat ke deferred queue atau modul, kurangi publish yang tidak perlu, dan jaga hanya logic yang benar-benar sensitif waktu tetap di jalur utama.