Grazas polos seus comentarios! Gustaríame actualizar o tempo actual para conectarse como ngx_time_update(). Cambiei o meu exemplo para usar só CLOCK_REALTIME, pero sempre uns 400 microsegundos tarde. Github.com/hnakamur/iororn/commit / … Isto significa que isto clock_gettime leva uns 400 nanosegundos na miña máquina?

Si, só soa de algunha maneira. Pero, se estás nun x86 PC en Linux, 400 NS para o clock_gettime pode ser un pouco alto (orde de magnitude superior – Ver abaixo). Se está a usar un procesador arm (por exemplo, Raspberry Pi, nvidia jetson), isto pode ser correcto.

Non sei como obtén 400 microsegundos. Pero, tiven que facer moitas cousas en tempo real en Linux e 400 é similar ao que miderei como unha sobrecarga para facer un cambio de contexto e / ou espertar un proceso / fío despois dun syscall a suspensión.

i uso gettimeofday máis. Agora estou a usar só clock_gettime(CLOCK_REALTIME,...) porque é o mesmo, agás que obteñas nanosegundos en vez de microsegundos.

Só para que o saiba, aínda que clock_gettime é unha chamada de sistema, hoxe en día, na maioría dos sistemas, usa a capa VDSO. O núcleo inxecta o código especial na aplicación do espazo de usuario, para que poida acceder directamente a tempo sen a sobrecarga dun syscall.

Se o é interesado, pode executarse baixo gdb e desmontar o código para ver que simplemente accede a certas localidades de memoria especiais en vez de facer unha chamada de sistema.

Non penso Ten demasiado que preocuparse por iso. Use o clock_gettime(CLOCK_MONOTONIC,...) e configuralo flags de 0. Non se teñen en conta os gastos xerais, a efectos do , porque a capaiorn usala.

Cando fago ese tipo de cousas e que quero / necesito calcular o custo adicional de clock_gettime que chama clock_gettime loop (por exemplo 1000 veces) e intento manter o tempo total por baixo dunha porción de tempo. Eu uso a diferenza mínima entre os tempos en cada iteración. Isto compensa a calquera corte de tempo.

O mínimo é o custo adicional da chamada en si.

Hai outras suxestións que podes facer para minimizar a latencia no espazo de usuario (por exemplo, Aumentar a prioridade do proceso, bloquear a afinidade da CPU e I / S interromper a afinidade), pero poden implicar outras cousas e, se non ten moito coidado, poden producir resultados peores.

Antes de comezar a tomar Acción extraordinaria, ten que ter unha metodoloxía sólida para o calendario de análise de medición / comparativa para demostrar que os seus resultados poden non responder aos seus requisitos de calendario / débito / latencia. Se non, fai cousas complicadas sen ningunha vantaxe real / medida / necesaria.

Abaixo, un código que acabo de crear, simplificado, pero en función do código que xa teño / usado para calibrar a 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;}

No meu sistema, un Core i7 a 2,67 GHz, a saída é:

MIN:0.000000019 TOT:0.000254999 AVG:0.000000025

Entón, recibo 25 ns de sobrecargas. Pero, de novo, cada sistema pode ser diferente en certa medida.

Actualizar:

Nota que o procesadorx86 ten unha “velocidade” .. O sistema operativo pode aumentar ou diminuír a frecuencia do procesador semi-automaticamente. As velocidades máis baixas aforran enerxía. As velocidades máis altas son o máximo rendemento.

Isto faise cunha heurística (por exemplo, se o sistema operativo detecta que o proceso é un gran usuario do procesador, aumentará a velocidade).

Para forzar a velocidade máxima, Linux a este directorio:

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

onde N é o número do número de CPU (por exemplo 0-7)

Segundo este directorio, hai unha serie de ficheiros de interese. Deberían ser explícitos.

En particular, mire scaling_governor. Ten ondemand ou performance.

Para forzar a velocidade máxima, como root, configure isto en performance (por exemplo):

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

Fai isto para todos os procesadores.

Con todo, acabo de facelo no meu sistema e tiña pouco efecto. Así, o kernel heurístico pode mellorar.

En canto aos 400us, cando un proceso espera algo, cando estea “esperto”, é un proceso en dous pasos.

O proceso é marcou “executable”.

Nun momento dado, o sistema / CPU realiza unha replanificación. O proceso executarase de acordo coa política de planificación e prioridade no proceso.

Para moitas chamadas do sistema, a replanción ocorre durante a próxima interrupción do temporizador / reloxo / sistema. Así, para algúns, pode haber un atraso que pode subir a unha marca de reloxo completo (é dicir) por un valor de 1000, isto pode subir ata 1 m (1000 EUA) máis tarde.

En media, isto representa a metade ou 500 US.

Para algunhas chamadas do sistema, cando o proceso está marcado como executable, realízase unha replanción inmediatamente. Se o proceso ten unha maior prioridade, executarase de inmediato.

Cando miraba por primeira vez, vin todos os camiños do código no kernel e a única chamada de sistema que fixo o inmediato Replanning foi SYSV IPC, para . Noutras palabras, cando o proceso fixo msgsnd, calquera proceso B espera que se execute a mensaxe dada.

Pero outros non (por exemplo futex). Agardarían o temporizador. Moitas cousas cambiaron desde entón, e agora, máis sycalls farán un adiamento inmediato. Por exemplo, recentemente medía futex e parecía facer a replanificación rápida.

Ademais, o planificador do kernel cambiou. O novo programador pode espertar / realizar certas cousas nunha fracción de reloxo de reloxo. Entón, para ti, os 400 nós, é o aliñamento do próximo reloxo.

Pero, simplemente podería ser a sobrecarga para facer a chamada do sistema. Para probar isto, cambiei o meu programa de proba para abrir /dev/null e engadido read(fd,buf,1) no ciclo de proba.

Recibín un valorMIN: de 529 nós. Así, o atraso que obtén podería simplemente ser o tempo necesario para facer o cambio de traballo.

Isto é o que eu chamaría “moi bo por agora”.

para obter a resposta “Razor “, Probablemente terás que escribir un condutor básico personalizado e facelo. Isto é o que os sistemas embebidos farían se debían (por exemplo) para cambiar un PINGPIO en cada intervalo.

Pero, se todo o que fai é , a sobrecarga e o subxacente ten write(1,...) a mergullar o atraso real.

Tamén teña en conta que cando fai , crea o buffer de saída e cando o buffer FILE *stdout está cheo, está cheo, está baleirado a través de write.

Para obter un mellor rendemento, é mellor facer int len = sprintf(buf,"current time is ..."); write(1,buf,len); ademais, cando Faga isto, se os buffers do kernel para a TTY de I / S están cheos, o proceso suspenderase ata que o I / O foi enviado ao dispositivo TTY.

Para facelo, ten que controlar o espazo dispoñible e ignore algunhas mensaxes se non hai espazo suficiente para conterlas.

Debes facer : ioctl(1,TIOCOUTQ,...) para obter o espazo dispoñible e ignorar algunhas mensaxes se é inferior ao tamaño da mensaxe que desexa xerar (por exemplo, len Valor anterior).

Para o seu uso, probablemente estea máis interesado na mensaxe de última hora, en lugar de saír todas as mensaxes

Leave a comment

O teu enderezo electrónico non se publicará Os campos obrigatorios están marcados con *