Une bifurcation plus rapide des grands processus sous Linux?

Quel est le moyen le plus rapide, le meilleur sur Linux moderne pour obtenir le même effet qu'un fork -execve combo à partir d'un grand processus ?

mon problème est que la fourche du procédé est d'environ 500mytes de gros, et un simple test de benchmarking n'atteint qu'environ 50 fourches / s du procédé (C. f ~1600 fourches / s d'un procédé de dimensions minimales) qui est trop lent pour l'application prévue.

une recherche sur google tourne vfork comme ayant été inventé comme solution à ce problème... mais aussi des avertissements concernant ne pas l'utiliser. Linux moderne semble avoir acquis connexe clone et posix_spawn appels; sont-ils susceptibles d'aider ? Quel est le remplacement moderne pour vfork ?

j'utilise 64bit Debian Lenny sur un i7 (le projet pourrait passer à Squeeze si posix_spawn aide).

28
demandé sur Tshepang 2010-04-28 20:56:05

5 réponses

sous Linux, vous pouvez utiliser posix_spawn(2)POSIX_SPAWN_USEVFORK drapeau pour éviter la surimpression des tables de page lors de la bifurcation d'un grand processus.

Voir en Minimisant l'Utilisation de la Mémoire pour la Création d'Application sous-processus pour un bon résumé de posix_spawn(2), ses avantages et quelques exemples.

Pour profiter de l' vfork(2), assurez-vous d' #define _GNU_SOURCE avant #include <spawn.h> et puis tout simplement posix_spawnattr_setflags(&attr, POSIX_SPAWN_USEVFORK)

je peux confirmer que cela fonctionne sur Debian Lenny, et fournit une accélération massive lors de la bifurcation d'un grand processus.

benchmarking the various spawns over 1000 runs at 100M RSS
                            user     system      total        real
fspawn (fork/exec):     0.100000  15.460000  40.570000 ( 41.366389)
pspawn (posix_spawn):   0.010000   0.010000   0.540000 (  0.970577)
31
répondu tmm1 2013-01-17 20:41:11

Résultat: j'allais suivre la route du sous-processus d'aide généré tôt comme suggéré par d'autres réponses ici, mais ensuite je suis tombé sur re utiliser le support de page énorme pour améliorer les performances de fourche.

après l'avoir essayé moi-même en utilisant libhugetlbfs pour simplement faire tous mon application mallocs allouer des pages immenses, je suis maintenant autour de 2400 fourches/s quelle que soit la taille du processus (sur la gamme qui m'intéresse de toute façon). Étonner.

12
répondu timday 2010-05-20 13:15:41

avez-vous réellement mesuré combien de temps les fourchettes prennent? Citant l' page vous lié,

Linux n'a jamais eu ce problème; parce que Linux a utilisé la sémantique de copie-sur-écriture en interne, Linux ne copie les pages que lorsqu'elles ont changé (en fait, il y a encore quelques tables qui doivent être copiées; dans la plupart des cas leur overhead n'est pas significatif)

of forks ne montre pas vraiment à quel point les frais généraux seront importants être. Vous devriez mesurer l' consommées par les fourches, et (ce qui est un conseil Générique) consommées seulement par les fourches que vous effectuez réellement, et non pas en évaluant la performance maximale.

mais si vous comprenez vraiment que bifurquer un grand processus est un lent, vous pouvez engendrer un petit processus auxiliaire, le processus de pipe master à son entrée, et recevoir des commandes à exec. Le petit processus fork et exec ces commande.

posix_spawn ()

cette fonction, pour autant que je sache, est implémentée via fork/exec sur les systèmes de bureau. Cependant, dans les systèmes embarqués (en particulier, les sans - MMU à bord), les processus sont générés via un syscall, interface à laquelle est posix_spawn ou une fonction similaire. Citant l' section informative de la norme POSIX décrivant posix_spawn:

  • L'échange est généralement trop lent pour un environnement en temps réel.

  • la traduction dynamique des adresses N'est pas disponible partout où POSIX peut être utile.

  • les processus sont trop utiles pour choisir simplement POSIX lorsqu'il doit être exécuté sans traduction d'adresse ou autres services MMU.

ainsi, POSIX a besoin de primitives de création de processus et d'exécution de fichiers qui peuvent être mises en œuvre efficacement sans traduction d'adresse ou d'autres services MMU.

Je ne pense pas que vous profiterez de cette fonction sur le bureau si votre but est de minimiser la consommation de temps.

8
répondu P Shved 2010-04-29 08:41:06

si vous connaissez le nombre de sous-processus à l'avance, il peut être raisonnable de préconfigurer votre application au démarrage puis de distribuer les informations de l'exécuv via un tuyau. Par ailleurs, s'il y a une sorte de "accalmie" dans votre programme, il peut être raisonnable de bifurquer à l'avance un ou deux sous-processus pour un traitement rapide à une date ultérieure. Aucune de ces options serait directement résoudre le problème, mais si l'une ou l'autre approche est adapté à votre application, il peut vous permettre de contourner le problème.

4
répondu Rakis 2010-04-28 18:02:06

je suis tombé sur ce billet de blog: http://blog.famzah.net/2009/11/20/a-much-faster-popen-and-system-implementation-for-linux/

pid = clone(fn, stack_aligned, CLONE_VM | SIGCHLD, arg);

Extrait:

L'appel système clone() vient à la rescousse. En utilisant clone () nous créons un processus enfant qui a les caractéristiques suivantes:

  • L'enfant s'exécute dans le même espace mémoire que le parent. Cela signifie qu'aucune structure de mémoire n'est copiée lorsque le processus enfant est créé. Par conséquent, tout changement à une variable autre que la pile faite par l'enfant est visible par le processus parent. Ceci est similaire à fils, et donc complètement différent de fork (), et aussi très dangereux – nous ne voulons pas que l'enfant gâche le parent.
  • l'enfant commence à partir d'une fonction d'entrée qui est appelée juste après la création de l'enfant. C'est comme des threads, et contrairement à fork().
  • l'enfant a un espace de pile séparé qui est similaire à threads et fork (), mais entièrement différent de vfork ().
  • le plus important: ce processus fils-like child peut appeler exec ().

en un mot, en appelant clone de la façon suivante, nous créons un processus enfant qui est très similaire à un fil, mais ne peut toujours appeler exec ():

cependant je pense qu'il peut encore être soumis au problème setuid:

http://ewontfix.com/7/ " setuid et vfork"

maintenant nous arrivons au pire. Filetages et vfork vous permettent d'obtenir dans un situation où deux processus partagent à la fois l'espace mémoire et en cours d'exécution au même moment. Maintenant, que se passe-t-il si un autre fil dans le le parent appelle setuid (ou toute autre fonction affectant les privilèges)? Vous se retrouver avec deux processus avec des niveaux de privilèges différents tournant dans un espace d'adressage partagé. Et c'est Une Mauvaise Chose.

prenons par exemple un serveur multithread démon, la course initialement en tant que root, c'est-à-dire en utilisant posix_spawn, implémenté naïvement avec vfork, pour exécuter une commande externe. Il ne se soucie pas si cette commande s'exécute en tant que root ou avec de faibles privilèges, puisque c'est un fixe ligne de commande fixe environnement et ne peut rien faire de nocif. (Comme une bête exemple, nous allons disons que c'est la date d'exécution comme une commande externe parce que le programmeur Je ne savais pas comment utiliser strftime.)

comme il s'en fiche, il appelle setuid dans un autre fil sans synchronisation contre l'exécution du programme externe, avec l'intention pour tomber vers un utilisateur normal et exécuter le code fourni par l'utilisateur (peut-être un script ou un module dlopen-obtained) en tant qu'utilisateur. Malheureusement, il je viens de donner à cet utilisateur la permission de mettre un nouveau code mmap lancer le code posix_spawn, ou pour changer les chaînes posix_spawn est passer à exec dans l'enfant. Whoop.

3
répondu Sam Liddicott 2016-02-09 15:58:28