Cómo dormir unos microsegundos

8 minutos de lectura

avatar de usuario
nikratio

Considere el siguiente código:

#include <stdio.h>
#include <time.h>
#include <math.h>

// Compile with gcc -lrt -lm -o test_clock test_clock.c

#define CLOCK CLOCK_MONOTONIC

int main(int argc, char** argv) {
    double temp, elapsed;
    int j;
    struct timespec requestStart, requestEnd, req;

    // Pseudo-sleep
    clock_gettime(CLOCK, &requestStart);
    temp = 0;
    for(j=0; j < 40; j++)
        temp += sin(j);
    clock_gettime(CLOCK, &requestEnd);
    elapsed = ( requestEnd.tv_sec - requestStart.tv_sec ) / 1e-6
                 + ( requestEnd.tv_nsec - requestStart.tv_nsec ) / 1e3;
    printf("Elapsed: %lf us\n", elapsed);

    // Nanosleep
    clock_gettime(CLOCK, &requestStart);
    req.tv_nsec = 5000;
    req.tv_sec = 0;
    clock_nanosleep(CLOCK, 0, &req, NULL);
    clock_gettime(CLOCK, &requestEnd);
    elapsed = ( requestEnd.tv_sec - requestStart.tv_sec ) / 1e-6
                 + ( requestEnd.tv_nsec - requestStart.tv_nsec ) / 1e3;

    printf("Elapsed: %lf us\n", elapsed);

}

En mi sistema 2.6.32, el resultado es

Elapsed: 5.308000 us
Elapsed: 69.142000 us

Estoy de acuerdo en que esto es más probable porque nanosleep() le pide al núcleo que reprograme el proceso. ¿Cómo puedo evitar esto? Quiero mantener la propiedad de la CPU y simplemente permanecer inactivo durante un período de tiempo preciso.

  • Tienes tanto linux como tiempo real como etiquetas. ¿Por qué? Son tiza y queso.

    –David Heffernan

    13 de febrero de 2011 a las 21:10

  • @David: No es que haya gente loca trabajando en linux-rt o algo así… oh espera.

    – efímero

    13 de febrero de 2011 a las 21:18

  • Estoy intrigado: ¿Cuál es exactamente el contexto? ¿Para qué necesitas ese tipo de precisión?

    – asdf

    6 de julio de 2011 a las 11:05

  • @asdf: control de retroalimentación en tiempo real de plasmas confinados magnéticamente.

    – Nikratio

    18 de agosto de 2011 a las 0:38

avatar de usuario
Yann Droneaud

Si desea que su aplicación pueda “dormir” con la mayor precisión posible, primero ponga su aplicación en condiciones de tiempo real

  • use una clase de programador en tiempo real para su programa/hilo: SCHED_FIFO o SCHED_RR
  • eleve la prioridad de su programa/subproceso
  • y si va a “dormir” por menos de la cantidad mínima que el núcleo va a manejar, manualmente busywait

Mira esto http://www.drdobbs.com/184402031

Y esta otra pregunta: ¿uso elevado de la CPU nanosleep?

  • Con prioridad en tiempo real, nanosleep funciona exactamente como yo quiero. ¡Gracias!

    – Nikratio

    14 de febrero de 2011 a las 16:32

  • SCHED_DEADLINE ¡está viniendo! lwn.net/Artículos/356576 lwn.net/Artículos/396634 Esperemos que mejore la usabilidad de RT en Linux. (Si no tienes cuidado con SCHED_FIFO/SCHED_RRpuede bloquear fácilmente toda la máquina).

    – efímero

    14 de febrero de 2011 a las 17:18

  • Realmente quería saber cómo para encender el SCHED_RR suave programador de turnos en tiempo real, así que lo descubrí y acabo de agregar una respuesta al respecto aquí.

    – Gabriel grapas

    7 abr a las 23:30

El programador del sistema operativo no va a hacer nada como “oh, quite este hilo del procesador durante exactamente 86 ciclos de reloj y luego vuelva a encenderlo”.

Renuncias al procesador, has renunciado al procesador. El sistema operativo te volverá a poner cuando lo desees. Lo más probable es que tenga que esperar hasta que cualquier otra cosa que se esté ejecutando abandone el procesador antes de poder volver a colarse.

  • Además, dependiendo del conjunto de chips, la CPU y algunas otras cosas, clock_gettime() podría ser costoso y no muy determinista. Es un poco difícil señalar cuál es el mayor problema aquí, incluso si el primer método indica que el problema es que el subproceso se adelanta y no la implementación del reloj.

    – Federico

    13 de febrero de 2011 a las 21:11


  • Bueno, serás reprogramado inmediatamente con sched_setscheduler(SCHED_FIFO) (o SCHED_RR o SCHED_DEADLINE, Cuando esté disponible). Pero esos son casos muy especiales.

    – efímero

    13 de febrero de 2011 a las 21:16

  • No quiero tomar el hilo del procesador, solo quiero no hacer nada durante un tiempo preciso. ¿No hay manera de lograr eso?

    – Nikratio

    13 de febrero de 2011 a las 21:47

  • @Nikratio: si necesita ejecutar con precisión en un momento determinado, básicamente necesita un sistema operativo en tiempo real. De lo contrario, no tiene garantía de que no se le cambiará el procesador en ningún momento dado. ¿Por qué necesitas correr precisamente en este momento?

    – Anónimo.

    13 de febrero de 2011 a las 21:55

  • @bestsss: Definitivamente era un sistema multitarea. Tal vez debería leer un relato del aterrizaje del Apolo 11, donde un componente de software (el radar de aterrizaje) no pudo mantenerse al día y cumplir con los plazos, pero el sistema pudo mantener todos los demás componentes con requisitos en tiempo real funcionando sin problemas.

    – Anónimo.

    14 de febrero de 2011 a las 2:23

Bueno, tendrás que aprender a vivir con eso ya que la página de manual dice, en parte: the actual time slept may be longer, due to system latencies and possible limitations in the timer resolution of the hardware 🙂

Ahora en cuanto a la responder a su pregunta, mi mejor suposición es que se debe a que su primer ciclo se está ejecutando en proceso. En otras palabras, no hay cambios de contexto involucrados ya que está ejecutando la CPU al máximo y estará haciendo todo ese trabajo dentro de los quanta de 100 ms que le dio el programador.

Sin embargo, hay una buena posibilidad de que nanosleep lo cambiará ya que está pidiendo explícitamente que lo pongan a dormir. No será tan ineficiente como simplemente poner su proceso en un lugar estrecho while bucle hasta que termine la duración 🙂

Eso significa que está sujeto a todos los caprichos del programador incluido el hecho de que otro proceso puede agotar totalmente sus cuantos, por lo tanto, su proceso puede estar fuera de allí durante al menos 100 ms. En un sistema lo suficientemente cargado, podría estar fuera de servicio durante bastante tiempo.

// busy wait for 10 microseconds
struct timespec ttime,curtime;

// get the time
clock_gettime(CLOCK_REALTIME,&ttime);

// clear the nanoseconds and keep the seconds in order not to overflow the nanoseconds
ttime.tv_nsec = 0;

// set it back
clock_settime(CLOCK_REALTIME,&ttime);

// get the time again 
clock_gettime(CLOCK_REALTIME,&ttime);

// increase the nano seconds by 10*1000
ttime.tv_nsec += 10000;

// loop
while(true){
  clock_gettime(CLOCK_REALTIME,&curtime);
  if (curtime.tv_nsec > ttime.tv_nsec)
    break;
}

// es mucho mejor que el usleep.

avatar de usuario
Saurabh

puedes usar usleep método para dormir en unidades de microsegundos.

  • Eso es más o menos lo mismo que clock_nanosleep, que, como se explica en las preguntas y otras respuestas, no hace el trabajo.

    – Nikratio

    9 oct 2012 a las 13:39

avatar de usuario
Martín Beckett

Eficiencia: un sistema operativo que permitiera activar y desactivar tareas con una precisión de unos pocos ciclos de reloj haría muy poco más.

Hay sistemas operativos especializados que hacen esto, pero en el hardware normal paga muchos gastos generales por el hipervisor.

  • Eso es más o menos lo mismo que clock_nanosleep, que, como se explica en las preguntas y otras respuestas, no hace el trabajo.

    – Nikratio

    9 oct 2012 a las 13:39

Esta es una respuesta pendiente: no conozco las partes internas relevantes de Linux, espero que un experto pueda venir y aclararlo.

Una posibilidad es que 69us sea simplemente la sobrecarga bruta de desprogramar y luego reprogramar el subproceso. Aunque la suspensión es corta, el kernel puede hacer mucho trabajo para realizar un cambio de contexto (o la mitad de un cambio de contexto, si no hay nada que programar) y luego deshacerlo casi de inmediato. No sé cuánto tiempo “debería” tomar Linux en una PC típica.

Si eso no lo explica, un programador generalmente tiene un concepto de “fracción de tiempo”, que es cuánto tiempo se dejará que se ejecute un subproceso programado antes de que el programador piense en cambiarlo, a menos que se desprograme a sí mismo o algo con mayor la prioridad se convierte en programable. El kernel tendrá temporizadores de bajo nivel que dispararán interrupciones al final de un intervalo de tiempo (además de las interrupciones que se dispararán para ciertos otros eventos, como E/S, que podrían desbloquear un hilo). Cuando finaliza un segmento de tiempo, el programador puede decidir si continuar con el mismo hilo o cambiar a otro.

Entonces, parece que cuando duerme, (a) el programador no está configurando un temporizador que hará que su subproceso sea programable en el momento solicitado, solo está esperando un intervalo de tiempo, por lo que la CPU está inactiva más de lo necesario ; o bien (b) está haciendo que su subproceso sea programable en el momento solicitado, pero cuando abandonó la ejecución al dormir, entró otro subproceso de igual prioridad, y el programador no tiene motivos para preferirlo a usted hasta que sea “su turno”. ” de nuevo de acuerdo con las reglas que el programador suele usar para decidir qué subproceso programar.

Sin embargo, 69us es bastante corto para ser un artefacto de corte de tiempo.

Parece que tiene una solución rudimentaria: puede retrasar por períodos muy cortos sentándose en un bucle para verificar el tiempo, como un bloqueo giratorio. Sin embargo, como todos los demás dicen, en un sistema que no es en tiempo real, más o menos por definición, no puede exigir que el programador ejecute su hilo en un momento específico. Incluso en un sistema en tiempo real, si está compitiendo con subprocesos de igual prioridad, puede perder, y si está compitiendo con subprocesos de mayor prioridad, será perder.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad