ver usuario todos terminar procesos proceso mostrar los ejecucion detener corriendo comandos administracion linux process debian exec fork

usuario - ¿Un forking más rápido de grandes procesos en Linux?



ver procesos de un usuario linux (5)

¿Cuál es la forma más rápida y mejor en el Linux moderno de lograr el mismo efecto que un combo execve de un proceso grande ?

Mi problema es que el proceso de bifurcación tiene un tamaño de ~ 500 MByte, y una prueba de evaluación comparativa simple logra solo 50 forks / s del proceso (cf ~ 1600 forks / s de un proceso de tamaño mínimo) que es demasiado lento para la aplicación prevista.

Algunos vfork Google vfork que vfork se inventó como la solución a este problema ... pero también advertencias acerca de no usarlo . Parece que Linux moderno ha adquirido clone relacionados y llamadas posix_spawn ; ¿Es probable que estos ayuden? ¿Cuál es el reemplazo moderno para vfork ?

Estoy usando 64bit Debian Lenny en un i7 (el proyecto podría moverse a Squeeze si posix_spawn ayudaría).


¿Realmente mediste cuanto tiempo toman los tenedores? Citando la página que has enlazado ,

Linux nunca tuvo este problema; Debido a que Linux utilizó la semántica de copia en escritura internamente, Linux solo copia las páginas cuando se modifican (en realidad, todavía hay algunas tablas que deben copiarse; en la mayoría de los casos, su sobrecarga no es significativa)

Así que el número de bifurcaciones realmente no muestra cuán grande será la sobrecarga. Debe medir el tiempo consumido por las horquillas y (que es un consejo genérico) consumido solo por las horquillas que realmente realiza, no por la evaluación comparativa de rendimiento máximo.

Pero si realmente descubre que forzar un proceso grande es lento, puede generar un pequeño proceso auxiliar, canalizar el proceso maestro a su entrada y recibir comandos para que se exec . El pequeño proceso fork y exec estos comandos.

posix_spawn ()

Esta función, por lo que entiendo, se implementa a través de fork / exec en sistemas de escritorio. Sin embargo, en los sistemas integrados (en particular, en aquellos que no tienen MMU a bordo), los procesos se generan a través de un syscall, una interfaz para la cual es posix_spawn o una función similar. Citando la sección informativa del estándar POSIX que describe posix_spawn :

  • El intercambio es generalmente demasiado lento para un entorno en tiempo real.

  • La traducción dinámica de direcciones no está disponible en todas partes en las que POSIX puede ser útil.

  • Los procesos son demasiado útiles para simplemente optar por POSIX cuando se debe ejecutar sin traducción de direcciones u otros servicios de MMU.

Por lo tanto, POSIX necesita primitivas de creación de procesos y ejecución de archivos que puedan implementarse de manera eficiente sin la traducción de direcciones u otros servicios MMU.

No creo que se beneficie de esta función en el escritorio si su objetivo es minimizar el consumo de tiempo.


En Linux, puede usar posix_spawn(2) con el indicador POSIX_SPAWN_USEVFORK para evitar la sobrecarga de copiar tablas de páginas cuando se procesa un proceso grande.

Consulte Minimizar el uso de memoria para crear subprocesos de aplicaciones para obtener un buen resumen de posix_spawn(2) , sus ventajas y algunos ejemplos.

Para aprovechar las ventajas de vfork(2) , asegúrese de #define _GNU_SOURCE antes de #include <spawn.h> y luego simplemente posix_spawnattr_setflags(&attr, POSIX_SPAWN_USEVFORK)

Puedo confirmar que esto funciona en Debian Lenny, y proporciona una aceleración masiva cuando se realiza un gran proceso.

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)


Me he encontrado con esta entrada 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);

Extracto:

La llamada al sistema clone () viene al rescate. Usando clone () creamos un proceso hijo que tiene las siguientes características:

  • El niño se ejecuta en el mismo espacio de memoria que el padre. Esto significa que no se copian estructuras de memoria cuando se crea el proceso hijo. Como resultado de esto, cualquier cambio en cualquier variable no apilada hecha por el hijo es visible por el proceso principal. Esto es similar a los hilos, y por lo tanto es completamente diferente de fork (), y también es muy peligroso: no queremos que el niño arruine al padre.
  • El niño se inicia desde una función de entrada que se llama justo después de que se creó el niño. Esto es como hilos, y a diferencia de fork ().
  • El niño tiene un espacio de pila separado que es similar a hilos y bifurcación (), pero completamente diferente a vfork ().
  • Lo más importante: este proceso hijo similar a un subproceso puede llamar a exec ().

En pocas palabras, al llamar a clon de la siguiente manera, creamos un proceso hijo que es muy similar a un hilo, pero aún puede llamar a exec ():

Sin embargo, creo que todavía puede estar sujeto al problema setuid:

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

Ahora llegamos a lo peor de todo. Los subprocesos y vfork te permiten acceder a una situación en la que dos procesos comparten espacio de memoria y se ejecutan al mismo tiempo. Ahora, ¿qué sucede si otro subproceso en el padre llama a setuid (o cualquier otra función que afecte los privilegios)? Usted termina con dos procesos con diferentes niveles de privilegios que se ejecutan en un espacio de direcciones compartido. Y esto es algo malo.

Considere, por ejemplo, un demonio de servidor de subprocesos múltiples, que se ejecuta inicialmente como raíz, que utiliza posix_spawn, implementado ingenuamente con vfork, para ejecutar un comando externo. No importa si este comando se ejecuta como root o con privilegios bajos, ya que es una línea de comandos fija con un entorno fijo y no puede hacer nada perjudicial. (Como un ejemplo estúpido, digamos que es la fecha de ejecución como un comando externo porque el programador no pudo averiguar cómo usar strftime).

Como no le importa, llama a setuid en otro subproceso sin ninguna sincronización contra la ejecución del programa externo, con la intención de desplegar a un usuario normal y ejecutar el código proporcionado por el usuario (tal vez un script o un módulo obtenido por dlopen). usuario. Desafortunadamente, solo le dio permiso a ese usuario para hacer un nuevo código de mmap sobre el código posix_spawn en ejecución, o para cambiar las cadenas que posix_spawn está pasando a exec en el hijo. Whoops.


Si conoce la cantidad de subproceso antes de tiempo, puede ser razonable pre-bifurcar su aplicación al inicio y luego distribuir la información ejecutiva a través de una tubería. Alternativamente, si hay algún tipo de "pausa" en su programa, podría ser razonable anticipar un subproceso o dos para un cambio rápido en un momento posterior. Ninguna de estas opciones resolvería directamente el problema, pero si cualquiera de los dos enfoques es adecuado para su aplicación, podría permitirle evitar el problema.


Resultado : Iba a ir por la ruta del subproceso auxiliar de generación temprana como lo sugieren otras respuestas aquí, pero luego me encontré con que estaba usando el soporte de página enorme para mejorar el rendimiento de las bifurcaciones.

Después de haberlo intentado usando libhugetlbfs para hacer que todos los mallocs de mi aplicación asignaran páginas enormes, ahora obtengo alrededor de 2400 forks / s sin importar el tamaño del proceso (en el rango que me interesa de todos modos). Asombroso.