¡Gracias por sus comentarios! Me gustaría actualizar la hora actual para conectarse como ngx_time_update(). Cambié mi ejemplo para usar solo CLOCK_REALTIME, pero siempre unos 400 microsegundos tarde. Github.com/hnakamur/iorn/commit / … ¿significa esto que este clock_gettime toma alrededor de 400 nanosegundos en mi máquina?

Sí, simplemente suena, de alguna manera. Pero, si está en una PC de x86 en Linux, 400 NS para la clock_gettime Los gastos generales pueden ser un poco altos (Orden de magnitud superior superior – vea abajo). Si está utilizando un procesador arm (por ejemplo, Raspberry Pi, nvidia jetson), esto puede ser correcto.

No sé cómo obtienes 400 microsegundos. Pero, tuve que hacer muchas cosas en tiempo real en Linux, y 400 es similar a lo que medí como una sobrecarga para hacer un cambio de contexto y / o despertar un proceso / hilo después de un SYSIONALL la suspensión.

Yo uso gettimeofday más. Ahora estoy usando solo clock_gettime(CLOCK_REALTIME,...) porque es lo mismo, excepto que obtiene nanosegundos en lugar de microsegundos.

Solo para que lo sepa, aunque es es una llamada del sistema, hoy en día, en la mayoría de los sistemas, utiliza la capa VDSO. El núcleo inyecta el código especial en la aplicación del espacio del usuario, de modo que puede acceder directamente a tiempo sin la sobrecarga de un syscall.

si está Interesado, puede ejecutarse debajo de gdb y desmonte el código para ver que simplemente acceda a ciertas ubicaciones de memoria especial en lugar de realizar una llamada del sistema.

No creo Tienes demasiado que preocuparte por eso. Use el clock_gettime(CLOCK_MONOTONIC,...) y configúrelo flags de 0. Las sobrecargas no se tienen en cuenta, a los efectos del ioring Llamada, porque su iorn la capa lo usa.

Cuando hago ese tipo de cosas, y que quiero / necesito Calcule el costo adicional de clock_gettime se llama clock_gettime bucle (por ejemplo, 1000 veces), y trato de mantener el tiempo total debajo de una rebanada de tiempo. Uso la diferencia mínima entre los tiempos en cada iteración. Esto compensa cualquier corte de tiempo.

El mínimo es el costo adicional de la llamada en sí.

Hay otras consejos que puede hacer para minimizar la latencia en el espacio de usuario (por ejemplo, Aumentar la prioridad del proceso, bloquee la afinidad de la CPU y la afinidad de la I / O de la CPU), pero pueden involucrar algunas otras cosas, y si no tiene mucho cuidado, pueden producir peores resultados.

Antes de comenzar a tomar Acción extraordinaria, debe tener una metodología sólida para el programa de medición / análisis comparativo para demostrar que sus resultados pueden no responder a sus requisitos de calendario / débito / latencia. De lo contrario, usted hace cosas complicadas sin ninguna ventaja / necesaria real / medible.

a continuación, un código que acabo de crear, simplificado, pero en función del código que ya he / utilizado para calibrar sobrecarga:

#include <stdio.h>#include <time.h>#define ITERMAX 10000typedef long long tsc_t;// tscget -- get time in nanosecondsstatic inline tsc_ttscget(void){ struct timespec ts; tsc_t tsc; clock_gettime(CLOCK_MONOTONIC,&ts); tsc = ts.tv_sec; tsc *= 1000000000; tsc += ts.tv_nsec; return tsc;}// tscsec -- convert nanoseconds to fractional secondsdoubletscsec(tsc_t tsc){ double sec; sec = tsc; sec /= 1e9; return sec;}tsc_tcalibrate(void){ tsc_t tscbeg; tsc_t tscold; tsc_t tscnow; tsc_t tscdif; tsc_t tscmin; int iter; tscmin = 1LL << 62; tscbeg = tscget(); tscold = tscbeg; for (iter = ITERMAX; iter > 0; --iter) { tscnow = tscget(); tscdif = tscnow - tscold; if (tscdif < tscmin) tscmin = tscdif; tscold = tscnow; } tscdif = tscnow - tscbeg; printf("MIN:%.9f TOT:%.9f AVG:%.9f\n", tscsec(tscmin),tscsec(tscdif),tscsec(tscnow - tscbeg) / ITERMAX); return tscmin;}intmain(void){ calibrate(); return 0;}

En mi sistema, un núcleo i7 a 2.67 GHz, la salida es:

MIN:0.000000019 TOT:0.000254999 AVG:0.000000025

Entonces, recibo 25 ns de gastos generales. Pero, nuevamente, cada sistema puede ser diferente en cierta medida.

Actualización:

Tenga en cuenta que los procesadores x86 tienen una «velocidad» . El sistema operativo puede aumentar o disminuir la frecuencia del procesador semi-automáticamente. Las velocidades más bajas ahorran energía. Las velocidades más altas son el máximo rendimiento.

Esto se hace con una heurística (por ejemplo, si el sistema operativo detecta que el proceso es un usuario grande del procesador, aumentará la velocidad).

Para forzar la velocidad máxima, Linux a este directorio:

/sys/devices/system/cpu/cpuN/cpufreq

donde N es el número de la CPU (por ejemplo, 0-7)

en este directorio, hay una serie de archivos de interés. Deben ser explícitos.

En particular, mira a scaling_governor. Tiene ondemand o performance.

Para forzar la velocidad máxima, como root, configure esto en performance (por ejemplo):

echo "performance" > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

Haga esto para todos los procesadores.

Sin embargo, acabo de hacerlo en mi sistema, y tenía poco efecto. Por lo tanto, el kernel heurístico puede haber mejorado.

En cuanto a los 400US, cuando un proceso espera algo, cuando está «despierto», es un proceso en dos pasos.

El proceso es Marcado «ejecutable».

En un momento dado, el sistema / CPU realiza una replanificación. El proceso se ejecutará de acuerdo con la política de planificación y prioridad en el proceso.

Para muchas llamadas del sistema, se produce la replanificación durante la interrupción del siguiente temporizador / reloj / sistema. Por lo tanto, para algunos, puede haber un retraso que pueda subir a una marca de reloj completa (es decir, para decir) para un valor de 1000, esto puede subir a 1 ms (1000 US) más tarde.

En promedio, esto representa la mitad o 500 US.

Para algunas llamadas del sistema, cuando el proceso Está marcado como ejecutable, se realiza un replanning inmediatamente. Si el proceso tiene una prioridad más alta, se ejecutará de inmediato.

Cuando miré esto por primera vez, observé todas las rutas de código en el kernel, y la única llamada del sistema que hizo la inmediata Rellanning fue SYSV IPC, para msgsnd/msgrcv. En otras palabras, cuando el proceso hizo msgsnd, se ejecuta cualquier proceso B a la espera del mensaje dado.

pero otros no (por ejemplo, futex). Esperarían el temporizador. Muchas cosas han cambiado desde entonces, y ahora, más Syscalls hará posponer inmediata. Por ejemplo, recientemente me medí futex, y parecía hacer el rápido replanning.

Además, el planificador del kernel ha cambiado. El nuevo programador puede despertar / realizar ciertas cosas en una fracción de marca de reloj. Entonces, para usted, los 400 US, es la alineación en el próximo reloj.

Pero, simplemente podría sobrecargarse para que la llamada del sistema. Para probar esto, cambié mi programa de prueba para abrir /dev/null, y agregué read(fd,buf,1) en el bucle de prueba.

Tengo un valor de MIN: de 529 US. Por lo tanto, el retraso que obtiene podría ser simplemente el momento necesario para realizar el cambio de trabajo.

es lo que llamaría «bastante bueno por ahora».

Para obtener la respuesta «Razor «, Probablemente tendrás que escribir un conductor central personalizado y hacerlo. Esto es lo que harían los sistemas integrados si le debían (por ejemplo,) para cambiar un PIN de GPIO en cada intervalo.

Pero, si todo lo que haces es , la sobrecarga y el subyacente tienen write(1,...) tendencia a sumergir el retraso real.

También tenga en cuenta que cuando hace , crea el búfer de salida y cuando el búfer FILE *stdout está lleno, se vacía a través de write.

Para un mejor rendimiento, es mejor hacerlo int len = sprintf(buf,"current time is ..."); write(1,buf,len); además, cuando usted Haga eso, si se llenan los tampones de kernel para la I / O TTY, el proceso se suspenderá hasta que se haya enviado la E / S hasta el dispositivo TTY.

Para hacer esto, debe monitorear el espacio disponible e ignore algunos mensajes si no hay suficiente espacio para contenerlos.

Debes hacer : ioctl(1,TIOCOUTQ,...) para obtener el espacio disponible e ignorar algunos mensajes si es menor que el tamaño del mensaje que desea generar (por ejemplo, el len Valor anterior).

Para su uso, probablemente esté más interesado en el mensaje de última hora, en lugar de salir de todos los mensajes

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *