Sfondo:
L'overhead delle chiamate di sistema è molto più ampio dell'overhead delle chiamate di funzione (le stime vanno da 20 a 100x) principalmente a causa del passaggio dal contesto dello spazio utente allo spazio del kernel e viceversa. È comune incorporare le funzioni per risparmiare sull'overhead delle chiamate di funzione e le chiamate di funzione sono molto più economiche delle syscall. È ovvio che gli sviluppatori vorrebbero evitare un po 'del sovraccarico delle chiamate di sistema occupandosi di quante più operazioni possibili nel kernel in un syscall possibile.
Problema:
Questo ha creato un sacco di chiamate (superflui?) Di sistema come sendmmsg () , recvmmsg () così come il chdir, aperto, lseek e / o combinazioni di link simbolici come: openat
, mkdirat
, mknodat
, fchownat
, futimesat
, newfstatat
, unlinkat
, fchdir
, ftruncate
, fchmod
, renameat
, linkat
, symlinkat
, readlinkat
, fchmodat
, faccessat
, lsetxattr
, fsetxattr
, execveat
, lgetxattr
, llistxattr
, lremovexattr
, fremovexattr
, flistxattr
, fgetxattr
, pread
, pwrite
ecc ...
Ora Linux ha aggiunto copy_file_range()
che apparentemente combina leggi cerca e scrivi syscalls. È solo questione di tempo prima che diventi fcopy_file_range (), lcopy_file_range (), copy_file_rangeat (), fcopy_file_rangeat () e lcopy_file_rangeat () ... ma poiché ci sono 2 file coinvolti invece di X più chiamate, potrebbe diventare X ^ 2 Di Più. OK, Linus e i vari sviluppatori di BSD non lo lascerebbero andare così lontano, ma il mio punto è che se ci fosse un syscall di batch, tutti (la maggior parte?) Di questi potrebbero essere implementati nello spazio utente e ridurre la complessità del kernel senza aggiungere molto se c'è un sovraccarico dal lato libc.
Sono state proposte molte soluzioni complesse che includono alcuni thread di syscall speciali per syscall non bloccanti per syscall di processo batch; tuttavia questi metodi aggiungono una notevole complessità sia al kernel che allo spazio utente allo stesso modo di libxcb vs. libX11 (le chiamate asincrone richiedono molta più configurazione)
Soluzione?:
Un syscall di batch generico. Ciò allevierebbe il costo più grande (switch di modalità multipla) senza le complessità associate all'avere thread del kernel specializzati (sebbene tale funzionalità possa essere aggiunta in seguito).
Fondamentalmente esiste già una buona base per un prototipo nel syscall socketcall (). Basta estenderlo dal prendere una matrice di argomenti per prendere invece una matrice di ritorni, puntatore a matrici di argomenti (che include il numero di syscall), il numero di syscalls e un argomento flags ... qualcosa come:
batch(void *returns, void *args, long ncalls, long flags);
Una differenza sostanziale sarebbe che gli argomenti dovrebbero probabilmente essere tutti puntatori per semplicità in modo che i risultati delle precedenti chiamate possano essere usati dalle successive chiamate (ad esempio il descrittore di file da open()
utilizzare in read()
/ write()
)
Alcuni possibili vantaggi:
- meno spazio utente -> spazio kernel -> commutazione spazio utente
- possibile switch del compilatore -fcombine-syscalls per provare a eseguire il batch automaticamente
- flag opzionale per il funzionamento asincrono (restituire fd per guardare immediatamente)
- capacità di implementare future funzioni di syscall combinate nello spazio utente
Domanda:
È possibile implementare un syscall di batch?
- Mi sto perdendo degli ovvi gotchas?
- Sto sopravvalutando i benefici?
Vale la pena preoccuparmi di implementare un syscall di batch (non lavoro in Intel, Google o Redhat)?
- In precedenza ho patchato il mio kernel, ma temo di avere a che fare con LKML.
- La storia ha dimostrato che anche se qualcosa è ampiamente utile per gli utenti "normali" (utenti finali non aziendali senza accesso in scrittura git), potrebbe non essere mai accettato a monte (unionfs, aufs, cryptodev, tuxonice, ecc ...)
Riferimenti:
batch
syscalls inbatch
syscalls, è possibile creare un albero di chiamate arbitrariamente profondo di syscalls arbitrarie. Fondamentalmente, puoi mettere l'intera applicazione in un unico syscall.