Sfondo:
L'overhead delle chiamate di sistema è molto più ampio dell'overhead delle chiamate di funzione (stima varia da 20 a 100x), principalmente a causa del passaggio da uno spazio utente all'altro e dallo spazio del kernel. È comune alle funzioni in linea salvare l'overhead delle chiamate di funzione e le chiamate di funzione sono molto più economiche delle syscalls. È ovvio che gli sviluppatori vorrebbero evitare alcune delle spese generali di chiamata del sistema occupandosi del maggior numero di operazioni nel kernel in un syscall possibile.
Problema:
Questo ha creato molte chiamate di sistema (superflue?) come sendmmsg () 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 lseek di lettura e scrive syscalls. È solo questione di tempo prima che questo 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 ed i vari sviluppatori di BSD non lascerebbero andare così lontano, ma il mio punto è che se ci fosse un syscall in 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 sul lato libc.
Sono state proposte molte soluzioni complesse che includono alcuni tipi di thread syscall speciali per syscalls non bloccanti a syscalls di processi batch; tuttavia, questi metodi aggiungono una notevole complessità sia al kernel che allo user space più o meno allo stesso modo di libxcb vs libX11 (le chiamate asincrone richiedono molte più impostazioni)
Soluzione:?
Un syscall di batch generico. Ciò allevierebbe il costo maggiore (switch in modalità multipla) senza le complessità associate alla presenza di thread del kernel specializzati (sebbene tale funzionalità possa essere aggiunta in seguito).
C'è fondamentalmente già una buona base per un prototipo nel syscall di socketcall (). Estendetelo semplicemente prendendo una serie di argomenti per prendere invece una serie di ritorni, puntatore a matrici di argomenti (che include il numero di syscall), il numero di syscall e un argomento flags ... qualcosa del tipo:
batch(void *returns, void *args, long ncalls, long flags);
Una delle principali differenze potrebbe essere che gli argomenti probabilmente tutti devono essere puntatori per semplicità in modo che i risultati di syscalls precedenti possano essere utilizzati dalle successive syscalls (ad esempio il descrittore di file da open()
da utilizzare in read()
/ write()
)
Alcuni possibili vantaggi:
- meno spazio utente - > spazio del kernel - > commutazione dello spazio utente
- possibile switch del compilatore -fcombine-syscalls per provare a eseguire il batch in modo automatico
- indicatore opzionale per operazioni asincrone (restituire fd per guardarlo immediatamente)
- capacità di implementare le future funzioni combinate di syscall nello spazio utente
Domanda:
È possibile implementare un syscall di batch?
- Mi mancano alcuni trucchi ovvi?
- Sto sopravvalutando i vantaggi?
Vale la pena per me preoccuparmi di implementare un syscall di batch (non lavoro su Intel, Google o RedHat)?
- Ho già applicato patch al mio kernel, ma ho avuto problemi con LKML.
- La storia ha dimostrato che anche se qualcosa è ampiamente utile per gli utenti "normali" (utenti finali non aziendali senza accesso git write), potrebbe non essere mai accettato upstream (unionfs, aufs, cryptodev, tuxonice, ecc ...)
References: