2010-09-25 14 views
7

Estoy tratando de escribir un programa que establece automáticamente prioridades de proceso basadas en un archivo de configuración (básicamente pares de prioridad de ruta).Ajustando automáticamente las prioridades del proceso bajo Linux

Pensé que la mejor solución sería un módulo kernel que reemplazara la llamada al sistema execve(). Lástima, la tabla de llamadas del sistema no se exporta en las versiones del núcleo> 2.6.0, por lo que no es posible reemplazar las llamadas al sistema sin Realmente feos hacks.

Yo no quieren hacer lo siguiente:

binarios -Reemplazar con scripts de shell, que empiezan y Renice los binarios. -Patch/recompilar mi núcleos existentes Ubuntu -Do hacks feo como la lectura de la memoria del núcleo ejecutable y adivinar la ubicación de la tabla syscall -Polling de los procesos en ejecución

I realmente quiero ser:

Capaz de controla la prioridad de cualquier proceso en función de su ruta ejecutable y un archivo de configuración. Las reglas se aplican a cualquier usuario.

¿Alguno de ustedes tiene alguna idea sobre cómo completar esta tarea?

Respuesta

4

Si se ha conformado con una solución de sondeo, la mayoría de las funciones que desea implementar ya existen en el Automatic Nice Daemon. Puede configurar niveles agradables para procesos basados ​​en nombre de proceso, usuario y grupo. Incluso es posible ajustar las prioridades del proceso de forma dinámica en función de la cantidad de tiempo de CPU que ha utilizado hasta ahora.

+0

¡Gracias, Dmitry! – netom

1

Claro, simplemente itere a través de/proc/nnn/exe para obtener la ruta de acceso de la imagen en ejecución. Solo usa los que tienen barras, los otros son procesos de kernel.

Compruebe si ya ha procesado ese, de lo contrario busque la nueva prioridad en su archivo de configuración y use renice (8) para modificar su prioridad.

+0

¿Eso no cuenta como "sondeo de procesos en ejecución" (que el consultante quiere evitar)? – timday

+0

Supongo, pero aún podría ser el mejor enfoque. – DigitalRoss

+0

Sí, por el momento, esto es lo que no quiero hacer. Pero esta solución no es tan mala, podría vivir con eso. Pero no me gustan las encuestas, y no me gustan los algoritmos que no se ejecutan en O (1);). Esta es una encuesta en O (n), y no me gusta, pero funcionará, estoy seguro. Si el hack del enlazador no funciona, me temo que debo continuar con esta solución. DigitalRoss, gracias por pensar fuera de la caja;) – netom

1

Hay otro punto de ataque que podría considerar: reemplace el sistema dynamic linker por uno modificado que aplique su lógica. (Vea esto paper para algunos buenos ejemplos de lo que es posible del arte en gran parte descuidado del pirateo de enlazadores).

Donde este enfoque tendrá problemas es con binarios puramente vinculados estáticamente. Dudo que haya mucho en un sistema moderno que en realidad no vincule algo dinámicamente (cosas como busybox-static son las excepciones obvias, aunque podrías considerar la posibilidad de obtener una capa mínima fuera de tus controles como característica cuando todo sale mal) , así que esto puede no ser un gran problema. Por otro lado, si las políticas de prioridad tienen la intención de poner orden en un sistema multiusuario compartido sobrecargado, es posible que vea a los usuarios inteligentes preparar versiones de aplicaciones enlazadas estáticas para evitar las prioridades impuestas por el vinculador.

+0

Definitivamente verificare esta posibilidad, gracias. Ahora tengo que descubrir cómo reemplazar/piratear libc en algún lugar _muy_ temprano en el proceso de arranque, sin modificar los archivos que vienen con los paquetes de Ubuntu (todavía quiero actualizar el sistema cuando sale algo nuevo). – netom

+0

Seguramente solo prepararía una libc modificada, la empacaría como .deb e instalaría (reemplazando la libc predeterminada) en los sistemas en los que desea poder aplicar estas políticas. Mi suposición es que prácticamente todo enlaza dinámicamente libc en estos días, por lo que los binarios existentes deberían simplemente recoger el nuevo ldd/ld-linux.so con bastante alegría. – timday

+0

Ok, esto está bien, pero no quiero perder la simplicidad de las actualizaciones automáticas. ¿Hay alguna manera de "parchar" binarios existentes? Me refiero a reemplazar ciertas funciones, con, digamos, un script del enlazador o tal cosa. Realmente no soy un experto en problemas específicos de vinculador. – netom

2

A veces, el sondeo es una necesidad, e incluso más óptimo en el final - lo creas o no. Depende de muchas variables.

Si la sobrecarga de sondeo es lo suficientemente baja, supera con creces la complejidad, el costo y el RIESGO adicionales de desarrollar sus propios ganchos de kernel de estilo para recibir notificaciones de los cambios que necesita. Dicho esto, cuando ganchos o eventos de notificación están disponibles, o se pueden inyectar fácilmente, sin duda se deben utilizar si la situación llama.

Este es el pensamiento clásico de la "perfección" del programador. Como ingenieros, luchamos por la perfección. Sin embargo, este es el mundo real y, a veces, se deben hacer concesiones. Irónicamente, la solución más perfecta puede ser la menos eficiente en algunos casos.

Desarrollo una herramienta de automatización de optimización de procesos y procesos similar para Windows llamada Process Lasso (no es un anuncio, es gratis). Tuve una opción similar para hacer y tener una solución híbrida en su lugar. Los ganchos del modo Kernel están disponibles para ciertos eventos relacionados con el proceso en Windows (creación y destrucción), pero no solo no están expuestos en el modo de usuario, sino que tampoco son útiles para monitorear otras métricas de proceso. No creo que ningún SO vaya a informarte de forma nativa sobre cualquier cambio en cualquier métrica de proceso. La sobrecarga de tantos ganchos diferentes podría ser mucho mayor que la simple votación.

Por último, teniendo en cuenta la ALTA frecuencia de los cambios de proceso, puede ser mejor manejar todos los cambios a la vez (sondeo a intervalos) frente a eventos/ganchos de notificación, que deben procesarse muchas veces más por segundo.

Tiene derecho a mantenerse alejado de las secuencias de comandos. ¿Por qué? Porque son lentos (er). Por supuesto, el programador de Linux hace un trabajo bastante bueno en el manejo de subprocesos enlazados de CPU degradando su prioridad y recompensando (actualizando) la prioridad de los subprocesos enlazados de E/S, así que incluso en altas cargas un script debería ser sensible, supongo.

+0

Admito que la votación es _necessary_, _sometimes_. Pero en mi opinión, en este caso, sería lento (er) y muy de raza-ish. Tengo varios cientos o miles de procesos y sondearlos cada segundo o más es definitivamente más lento que disparar un gancho en el inicio del proceso. – netom

+1

Sí, ciertamente estoy de acuerdo, siempre y cuando solo mires la creación y destrucción del proceso. Si estuvieras rastreando los cambios en el uso de la memoria virtual, por ejemplo, obviamente tendrías que sondear porque recibir una notificación por cada cambio daría como resultado una gran cantidad de notificaciones por segundo para esa sola métrica. Entiende mi punto;). –

+0

Sí, absolutamente. :) – netom

1

Si desea hacerlo como un módulo kernel, entonces podría considerar hacer su propio cargador binario. Consulte los siguientes archivos fuente del kernel para ver ejemplos:

$KERNEL_SOURCE/fs/binfmt_elf.c 
$KERNEL_SOURCE/fs/binfmt_misc.c 
$KERNEL_SOURCE/fs/binfmt_script.c 

Le pueden dar una primera idea de por dónde empezar.

Puede modificar el cargador ELF para buscar una sección adicional en los archivos ELF y, cuando lo encuentre, utilizar su contenido para cambiar las prioridades de programación. Entonces, ni siquiera necesitaría administrar archivos de configuración separados, sino simplemente agregar una nueva sección a cada ejecutable ELF que desee administrar de esta manera y listo. Consulte objcopy/objdump de las herramientas de binutils para saber cómo agregar nuevas secciones a los archivos ELF.

0

¿Alguien de ustedes tiene alguna idea sobre cómo completar esta tarea?

Como idea , considerar el uso de apparmor en quejarse modo. Eso registraría ciertos mensajes en syslog, que podría escuchar.

0

Si los procesos en cuestión se inician ejecutando un archivo ejecutable con una ruta conocida, puede usar el mecanismo inotify para ver los eventos en ese archivo. Al ejecutarlo, se activará un evento I_OPEN y I_ACCESS.

Lamentablemente, esto no le indicará qué proceso provocó que se desencadene el evento, pero puede verificar qué /proc/*/exe son un enlace simbólico al archivo ejecutable en cuestión y renice la identificación del proceso en cuestión.

E.g.aquí es una aplicación crudo en Perl usando Linux::Inotify2 (que, en Ubuntu, es proporcionada por el paquete liblinux-inotify2-perl):

perl -MLinux::Inotify2 -e ' 
    use warnings; 
    use strict; 
    my $x = shift(@ARGV); 
    my $w = new Linux::Inotify2; 
    $w->watch($x, IN_ACCESS, sub 
    { 
    for (glob("/proc/*/exe")) 
    { 
     if (-r $_ && readlink($_) eq $x && m#^/proc/(\d+)/#) 
     { 
     system(@ARGV, $1) 
     } 
    } 
    }); 
    1 while $w->poll 
' /bin/ls renice 

Por supuesto, puede guardar el código Perl en un archivo, por ejemplo onexecuting, anteponga una primera línea #!/usr/bin/env perl , haga que el archivo sea ejecutable, colóquelo en su $PATH, y a partir de entonces use onexecuting /bin/ls renice.

Luego puede usar esta utilidad como base para implementar varias políticas para renumerar ejecutables. (o haciendo otras cosas).

Cuestiones relacionadas