Sto scrivendo un codice, che riceve pacchetti Ethernet raw (senza TCP/UDP) ogni 1 ms dal server. Per ogni pacchetto ricevuto, la mia applicazione deve rispondere con 14 pacchetti non elaborati. Se il server non riceve i 14 pacchetti prima di inviare il pacchetto programmato per ogni 1 ms, il server solleva un allarme e l'applicazione deve scoppiare. La comunicazione server-client è un collegamento uno a uno.Ricezione pacchetti socket RAW con precisione in microsecondi
Il server è un hardware (FPGA) che genera pacchetti a intervalli di 1 ms. L'applicazione client viene eseguita su una macchina Linux (RHEL/Centos 7) con 10G SolarFlare NIC.
La mia prima versione del codice è come questo
while(1)
{
while(1)
{
numbytes = recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL);
if(numbytes > 0)
{
//Some more lines here, to read packet number
break;
}
}
for (i=0;i<14;i++)
{
if (sendto(sockfd,(void *)(sym) , sizeof(sym), 0, NULL, NULL) < 0)
perror("Send failed\n");
}
}
misuro il tempo di ricezione prendendo timestamp (usando clock_gettime
) prima della chiamata recvfrom
e uno dopo, mi stampo le differenze di tempo di questi timestamp e stampa loro ogni volta che la differenza di orario supera l'intervallo consentito di 900-1100 us.
Il problema che sto affrontando è che il pacchetto di ricezione tempo viene fluctuating.Something come questo (le stampe sono in microsecondi)
Decode Time : 1234
Decode Time : 762
Decode Time : 1593
Decode Time : 406
Decode Time : 1703
Decode Time : 257
Decode Time : 1493
Decode Time : 514
and so on..
E a volte i tempi di decodifica superano 2000us e l'applicazione si rompono.
In questa situazione, l'applicazione si interromperebbe in qualsiasi momento tra 2 secondi e alcuni minuti.
Opzioni provate da me fino ad ora.
- Impostazione affinità per un particolare nucleo isolato.
- priorità Ambito programmazione al massimo con il tampone presa
SCHED_FIFO
- Aumenta dimensioni
- interfaccia di rete Ambito interrompere affinità stesso nucleo che elabora applicazione
- Spinning sopra
recvfrom
usandopoll(),select()
chiamate.
Tutte queste opzioni offrono un miglioramento significativo rispetto alla versione iniziale del codice. Ora l'applicazione dovrebbe funzionare per ~ 1-2 ore. Ma questo non è ancora abbastanza.
Alcune osservazioni:
- ottengo aa enorme discarica di queste stampe tempo decodifica, ogni volta che prendo sessioni SSH di macchina Linux mentre l'applicazione è in esecuzione (che mi fa pensare la comunicazione di rete su un'altra interfaccia 1G Ethernet sta creando interferenze con l'interfaccia Ethernet 10G).
- L'applicazione ha prestazioni migliori in RHEL (tempi di esecuzione di circa 2-3 ore) rispetto a Centos (tempi di esecuzione di circa 30 minuti - 1,5 ore)
- I tempi di esecuzione variano anche con macchine Linux con configurazioni hardware diverse con lo stesso OS.
Si prega di suggerire se ci sono altri metodi per migliorare il tempo di esecuzione dell'applicazione.
Grazie in anticipo.
Oltre al tempo di elaborazione, è necessario comprendere che nel mondo reale le reti variano notevolmente i tempi di consegna dei pacchetti. È possibile attenuarlo fino ad un certo punto se questo è tutto sulla rete (non viaggia su Internet) se sono in atto politiche di QoS solide e si definiscono le code di priorità per questo traffico. Altrimenti, non proverei nemmeno a provare a usare qualcosa con tempi così ravvicinati su una rete. –
Ti suggerirei, se possibile, di provare a utilizzare un kernel Linux compilato con PREEMPT_RT. – LPs
Sarebbe bello sapere cosa si vuole ottenere, in modo sicuro, l'invio di pacchetti con questa precisione non è possibile su Ethernet. Suggerirei di avere un altro FPGA per elaborare i dati e l'interfaccia con il PC. – Koshinae