Kernel Linux y renice/ionice
Daniel Serpell
dserpell en gmail.com
Mar Feb 1 17:16:19 CLST 2011
¡Hola!
El Tue, Feb 01, 2011 at 09:15:22AM -0300, Ricardo Albarracin B. escribio:
> El Mon, 31 Jan 2011 23:28:42 -0300
> Aldrin Martoq <amartoq en dcc.uchile.cl> escribió:
>
> > Mejor cuéntanos qué pretendes hacer...
> >
>
> Precisamente eso.... reasignar más tiempo de CPU a algunos procesos
> críticos para evitar la perdida de datos en capturas de hasta 50KBPS a
> través de una USB, hay un buffer que se llena y hay datos que se
> pierden. La recoleción de datos llega a varios millones imagina esa
> taza en 5 a 10 minutos.
>
[...]
>
> El caso mío es distinto al que planteas, ya que uso un sistema de
> captura de datos de alto rendimiento y una opción es ir a un sistema
> operativo de tiempo real, pero antes es agotar todos los recursos antes
> de llegar a ese extremo, el problema lo resuelvo con máquinas más
> potentes pero no es la idea, el tema es con máquinas por ejemplo como
> las Atom.
Lo que más te conviene aquí es cambiar la clase de schedulling del programa,
pasar de la clase estándar a la clase round-robin. Esto garantiza que
tu aplicación va a recibir CPU cada cierto tiempo por lo menos.
Para hacerlo, basta con utilizar la llamada sched_setscheduler(), ve en
su página de manual. En nuestro caso, agregamos esto:
void set_priority()
{
struct sched_param sp;
sp.sched_priority = 10;
sched_setscheduler(0, SCHED_RR, &sp);
}
Todas las tareas en round-robin tienen más prioridad que las tareas
estándares, esto significa que si usas el 100% de CPU, nada más se
ejecutará en tu computador. Esto no es un problema si la aplicación
sólo recibe datos, ya que debería realizar la recepción y luego volver
a esperar más datos.
El problema ahora es que no quieres que la aplicación tenga permisos
de super-usuario. Si usas Linux mayor a 2.6.12, la solución es cambiar
el límite de prioridad permitida de los procesos por medio de la
capacidad "RLIMIT_RTPRIO" usando setrlimit. Esto se hace con el
siguiente pseudocódigo:
// Programa ejecutado con UID=0, cambia los límites
setrlimit(...);
if(!fork())
{
// Cambia a usuario 1000 (por ejemplo)
setuid(1000);
// Ejecuta el programa
execve(....);
}
// Termina.
exit(0);
Obviamente, con manejo de errores, etc. Lamentablemente el programa
"padre" debe todavía ser root, esto es difícil de evitar, ya que de
alguna manera se tiene que dar el permiso.
Nota que en versiones de Linux mayores a 2.6.25 puedes también fijar
el límite "RLIMIT_RTTIME", el cual limita el total de tiempo que un
proceso de prioridad RT puede utilizar de una sola vez. Esto sirve
para impedir que un proceso RT use el 100% de CPU y haga que el resto
del sistema no responda. Ve en el manual de "setrlimit".
Por último, si insistes en que el proceso inicial (que fija los
límites) no sea ejecutado como root, puedes utilizar el sistema de
capacidades de Linux, ve capabilities(7), con énfasis en la sección
llamada "File Capabilities". La gracia es que, si usas un sistema
de archivos que lo soporte, puedes asignar a un ejecutable la
capacidad "CAP_SYS_NICE", usando "setcap cap_sys_nice+p programa".
Lee bien, eso si, lo que esto permite al proceso.
Lamentablemente, en UBIFS que usamos aquí no hay soporte para
capabilities.
Daniel.
Más información sobre la lista de distribución Linux