¿Cómo me aseguro de que mi programa se ejecute de principio a fin sin interrupción?

StackOverflow https://stackoverflow.com/questions/1215713

  •  06-07-2019
  •  | 
  •  

Pregunta

Estoy intentando cronometrar el código usando RDTSC (ningún otro software de creación de perfiles que he probado es capaz de cronometrar la resolución que necesito) en Ubuntu 8.10. Sin embargo, sigo obteniendo valores atípicos de los cambios de tareas e interrumpe el disparo, lo que hace que mis estadísticas sean inválidas.

Teniendo en cuenta que mi programa se ejecuta en cuestión de milisegundos, ¿es posible desactivar todas las interrupciones (que inherentemente desactivarían los interruptores de tareas) en mi entorno? ¿O necesito ir a un sistema operativo que me permite más potencia? ¿Sería mejor usar mi propio núcleo del sistema operativo para realizar este código de sincronización? Estoy tratando de probar el mejor / peor caso de un algoritmo, por lo que debe ser totalmente sólido con el tiempo.

El código relevante que estoy usando actualmente es:

inline uint64_t rdtsc()
{
    uint64_t ret;
    asm volatile("rdtsc" : "=A" (ret));
    return ret;
}

void test(int readable_out, uint32_t start, uint32_t end, uint32_t (*fn)(uint32_t, uint32_t))
{
    int i;
    for(i = 0; i <= 100; i++)
    {
        uint64_t clock1 = rdtsc();
        uint32_t ans = fn(start, end);
        uint64_t clock2 = rdtsc();

        uint64_t diff = clock2 - clock1;

        if(readable_out)
            printf("[%3d]\t\t%u [%llu]\n", i, ans, diff);
        else
            printf("%llu\n", diff);
    }
}

Puntos adicionales para aquellos que notan que no estoy manejando adecuadamente las condiciones de desbordamiento en este código. En esta etapa, solo estoy tratando de obtener una salida consistente sin saltos repentinos debido a que mi programa pierde el intervalo de tiempo.

El buen valor para mi programa es -20.

Entonces, para recapitular, ¿es posible para mí ejecutar este código sin interrupción del sistema operativo? ¿O tendré que ejecutarlo en hardware desnudo en ring0, para poder desactivar las IRQ y la programación? Gracias de antemano!

¿Fue útil?

Solución

Si llama a nanosleep () para dormir durante un segundo más o menos inmediatamente antes de cada iteración de la prueba, debería obtener un " fresh " Timeslice para cada prueba. Si compila su kernel con interrupciones de temporizador de 100HZ y su función temporizada se completa en menos de 10 ms, entonces debería ser capaz de evitar que las interrupciones de temporizador lo golpeen de esa manera.

Para minimizar otras interrupciones, desconfigure todos los dispositivos de red, configure su sistema sin intercambio y asegúrese de que esté inactivo.

Otros consejos

Tricky. No creo que pueda desactivar el sistema operativo y garantizar una programación estricta.

Lo pondría al revés: dado que funciona tan rápido, hágalo muchas veces para recopilar una distribución de resultados. Dado que Ubuntu Linux estándar no es un sistema operativo en tiempo real en sentido estricto, todos los algoritmos alternativos se ejecutarían en la misma configuración --- y luego puede comparar sus distribuciones (usando cualquier cosa, desde estadísticas de resumen hasta cuantiles y qqplots). Puedes hacer esa comparación con Python, R u Octave, ... lo que más te convenga.

Es posible que pueda salir corriendo con FreeDOS , ya que es un sistema operativo de proceso único .

Aquí está el texto relevante del segundo enlace:

  

Implementación DOS de Microsoft, que es la de   estándar de facto para sistemas DOS en el   x86 world, es un usuario único,   sistema operativo de una sola tarea. Eso   proporciona acceso sin procesar al hardware y   solo una capa mínima para las API del sistema operativo para   cosas como el archivo I / O. Esto es un   bueno cuando se trata de incrustado   sistemas, porque a menudo solo necesitas   para hacer algo sin un   sistema operativo en su camino.

     

DOS no tiene (nativamente) ningún concepto de   hilos y sin concepto de múltiple,   procesos en curso. Solicitud   el software hace llamadas al sistema a través de   uso de una interfaz de interrupción, llamando   varias interrupciones de hardware para manejar   cosas como video y audio, y   llamar a interrupciones de software para manejar   varias cosas como leer un   directorio, ejecutando un archivo, y así   adelante.

Por supuesto, probablemente obtendrá el mejor rendimiento al iniciar FreeDOS en hardware real, no en un emulador.

En realidad no he usado FreeDOS, pero supongo que dado que su programa parece ser el estándar C, podrá usar cualquier compilador estándar para FreeDOS.

Si su programa se ejecuta en milisegundos, y si se está ejecutando en Linux, Asegúrese de que la frecuencia de su temporizador (en Linux) esté establecida en 100Hz (no 1000Hz). (cd / usr / src / linux; configure menuconfig y mire " Tipo de procesador y características " - > " Frecuencia del temporizador ") De esta manera, su CPU se interrumpirá cada 10 ms.

Además, tenga en cuenta que el intervalo de tiempo predeterminado de la CPU en Linux es de 100 ms, por lo que con un buen nivel de -20, no se programará si se ejecuta durante unos pocos milisegundos.

Además, estás haciendo un bucle 101 veces en fn (). Considere dar fn () como un no-op para calibrar su sistema correctamente.

Realice estadísticas (promedio + stddev) en lugar de imprimir demasiadas veces (eso consumiría su intervalo de tiempo programado, y el terminal eventualmente obtendrá un horario, etc ... evítelo).

código de muestra de referencia RDTSC

Puede usar chrt -f 99 ./test para ejecutar ./test con la máxima prioridad en tiempo real. Entonces, al menos, no será interrumpido por otros procesos de espacio de usuario.

Además, la instalación del paquete linux-rt instalará un kernel en tiempo real, que le dará más control sobre la prioridad del manejador de interrupciones a través de interrupciones roscadas.

Si ejecuta como root, puede llamar a sched_setscheduler () y darse una prioridad en tiempo real. Consulte la documentación.

Quizás haya alguna forma de deshabilitar la programación preventiva en Linux, pero puede que no sea necesario. Potencialmente, podría utilizar la información de /proc/<pid>/schedstat o algún otro objeto en /proc para detectar cuándo ha sido reemplazado, y no tener en cuenta esas muestras de temporización.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top