Mekanisme penjadwalan
Pemrosesan data dalam grafik MediaPipe terjadi di dalam node pemrosesan yang ditentukan sebagai
subclass CalculatorBase
. Sistem penjadwalan memutuskan kapan
setiap kalkulator harus dijalankan.
Setiap grafik memiliki setidaknya satu antrean penjadwal. Setiap antrean penjadwal memiliki tepat satu executor. Node ditetapkan secara statis ke antrean (dan oleh karena itu ke eksekutor). Secara default, ada satu antrean, yang eksekutornya adalah kumpulan thread dengan sejumlah thread berdasarkan kemampuan sistem.
Setiap node memiliki status penjadwalan, yang dapat berupa not ready, siap, atau running. Fungsi kesiapan menentukan apakah node siap dijalankan. Fungsi ini dipanggil saat inisialisasi grafik, setiap kali node selesai berjalan, dan setiap kali status input node berubah.
Fungsi kesiapan yang digunakan bergantung pada jenis node. Node tanpa input aliran dikenal sebagai node sumber; node sumber selalu siap dijalankan, sampai memberi tahu framework bahwa tidak ada lagi data untuk dihasilkan, dan pada saat itu node sumber tersebut akan ditutup.
Node non-sumber siap jika memiliki input untuk diproses, dan jika input tersebut membentuk kumpulan input yang valid sesuai dengan kondisi yang ditetapkan oleh kebijakan input node (dibahas di bawah). Sebagian besar node menggunakan kebijakan input default, tetapi beberapa node menentukan node yang berbeda.
Saat node sudah siap, tugas ditambahkan ke antrean penjadwal terkait, yang merupakan antrean prioritas. Fungsi prioritas saat ini bersifat tetap, dan mempertimbangkan properti statis node serta pengurutan topologinya dalam grafik. Misalnya, node yang lebih dekat ke sisi output grafik memiliki prioritas lebih tinggi, sedangkan node sumber memiliki prioritas terendah.
Setiap antrean dilayani oleh eksekutor, yang bertanggung jawab untuk benar-benar menjalankan tugas dengan memanggil kode kalkulator. Berbagai eksekutor dapat disediakan dan dikonfigurasi; eksekutor ini dapat digunakan untuk menyesuaikan penggunaan resource eksekusi, misalnya dengan menjalankan node tertentu pada thread yang berprioritas lebih rendah.
Sinkronisasi Stempel Waktu
Eksekusi grafik MediaPipe terdesentralisasi: tidak ada jam global, dan node yang berbeda dapat memproses data dari stempel waktu yang berbeda secara bersamaan. Hal ini memungkinkan throughput yang lebih tinggi melalui pipeline.
Namun, informasi waktu sangat penting bagi banyak alur kerja persepsi. Node yang menerima beberapa aliran input umumnya perlu mengoordinasikannya dalam beberapa cara. Misalnya, detektor objek dapat menghasilkan daftar persegi panjang batas dari sebuah frame, dan informasi ini dapat dimasukkan ke node rendering, yang harus memprosesnya bersama dengan frame asli.
Oleh karena itu, salah satu tanggung jawab utama framework MediaPipe adalah menyediakan sinkronisasi input untuk node. Dalam mekanisme framework, peran utama stempel waktu adalah berfungsi sebagai kunci sinkronisasi.
Selain itu, MediaPipe dirancang untuk mendukung operasi deterministik, yang penting dalam banyak skenario (pengujian, simulasi, batch processing, dll.), sekaligus memungkinkan penulis grafik untuk melonggarkan determinisme jika diperlukan untuk memenuhi batasan real-time.
Dua tujuan sinkronisasi dan determinisme mendasari beberapa pilihan
desain. Secara khusus, paket yang dikirim ke aliran data tertentu harus memiliki stempel waktu yang meningkat
secara monoton: ini bukan hanya asumsi yang berguna bagi banyak node, tetapi
juga diandalkan oleh logika sinkronisasi. Setiap aliran data memiliki
terikat stempel waktu, yang merupakan stempel waktu serendah mungkin yang diizinkan untuk paket
baru di aliran data. Saat paket dengan stempel waktu T
tiba, batas tersebut
akan otomatis berlanjut ke T+1
, yang mencerminkan persyaratan monoton. Hal ini
memungkinkan framework untuk mengetahui dengan pasti bahwa tidak ada lagi paket dengan stempel waktu
yang lebih rendah dari T
yang akan tiba.
Kebijakan input
Sinkronisasi ditangani secara lokal pada setiap node, menggunakan kebijakan input yang ditentukan oleh node.
Kebijakan input default, yang ditentukan oleh DefaultInputStreamHandler
, menyediakan
sinkronisasi input yang deterministik, dengan jaminan berikut:
Jika paket dengan stempel waktu yang sama disediakan di beberapa aliran input, paket tersebut akan selalu diproses bersama, terlepas dari urutan kedatangannya secara real time.
Set input diproses dalam urutan stempel waktu yang benar-benar menaik.
Tidak ada paket yang dibuang, dan pemrosesannya sepenuhnya deterministik.
Node siap memproses data sesegera mungkin dengan jaminan di atas.
Untuk menjelaskan cara kerjanya, kita perlu memperkenalkan definisi stempel waktu yang telah ditentukan. Kita mengatakan bahwa stempel waktu dalam streaming akan diselesaikan jika lebih rendah dari batas stempel waktu. Dengan kata lain, stempel waktu diselesaikan untuk aliran data setelah status input pada stempel waktu tersebut tidak dapat dibatalkan: apakah ada paket, atau ada kepastian bahwa paket dengan stempel waktu tersebut tidak akan tiba.
Stempel waktu ditetapkan di beberapa streaming jika ditetapkan di setiap streaming tersebut. Selain itu, jika stempel waktu telah diselesaikan, hal ini menandakan bahwa semua stempel waktu sebelumnya juga telah diselesaikan. Dengan demikian, stempel waktu yang telah ditetapkan dapat diproses secara pasti dalam urutan menaik.
Berdasarkan definisi ini, kalkulator dengan kebijakan input default siap digunakan jika ada stempel waktu yang ditetapkan di semua aliran input dan berisi paket pada setidaknya satu aliran input. Kebijakan input menyediakan semua paket yang tersedia untuk stempel waktu yang telah ditentukan sebagai satu set input ke kalkulator.
Salah satu konsekuensi dari perilaku deterministik ini adalah, untuk node dengan beberapa aliran input, secara teoritis mungkin ada waktu tunggu yang secara teoritis tidak terbatas hingga stempel waktu diselesaikan, dan pada saat itu, jumlah paket yang tidak terbatas dapat di-buffer. (Perhatikan node dengan dua stream input, salah satunya terus mengirim paket, sementara yang lain mengirim apa pun dan tidak memajukan batas.)
Oleh karena itu, kami juga menyediakan kebijakan input kustom: misalnya, memisahkan
input dalam kumpulan sinkronisasi yang berbeda yang ditentukan oleh
SyncSetInputStreamHandler
, atau menghindari sinkronisasi sepenuhnya dan
memproses input segera setelah input tersebut diterima ditentukan oleh
ImmediateInputStreamHandler
.
Kontrol alur
Ada dua mekanisme kontrol alur utama. Mekanisme backpressure membatasi
eksekusi node upstream saat paket yang di-buffer pada aliran data mencapai
batas (yang dapat dikonfigurasi) yang ditentukan oleh CalculatorGraphConfig::max_queue_size
. Mekanisme
ini mempertahankan perilaku deterministik, dan mencakup sistem pencegahan deadlock
yang melonggarkan batas yang dikonfigurasi saat diperlukan.
Sistem kedua terdiri dari penyisipan node khusus yang dapat menghapus paket
sesuai dengan batasan real-time (biasanya menggunakan kebijakan input kustom)
yang ditentukan oleh FlowLimiterCalculator
. Misalnya, pola umum menempatkan
node kontrol alur pada input subgrafik, dengan koneksi loopback dari
output akhir ke node kontrol alur. Dengan demikian, node kontrol alur dapat
melacak jumlah stempel waktu yang diproses dalam grafik downstream,
dan menghapus paket jika jumlah ini mencapai batas (dapat dikonfigurasi); dan karena paket
dipindahkan ke upstream, kita menghindari pekerjaan sia-sia yang akan dihasilkan dari pemrosesan
stempel waktu sebagian, lalu meninggalkan paket di antara tahap perantara.
Pendekatan berbasis kalkulator ini memberi penulis grafik kontrol atas lokasi paket dapat diberikan, serta memungkinkan fleksibilitas dalam mengadaptasi dan menyesuaikan perilaku grafik bergantung pada batasan resource.