2016-02-12 4 views
11

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.

  1. Impostazione affinità per un particolare nucleo isolato.
  2. priorità Ambito programmazione al massimo con il tampone presa SCHED_FIFO
  3. Aumenta dimensioni
  4. interfaccia di rete Ambito interrompere affinità stesso nucleo che elabora applicazione
  5. Spinning sopra recvfrom usando poll(),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:

  1. 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).
  2. 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)
  3. 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.

+2

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. –

+0

Ti suggerirei, se possibile, di provare a utilizzare un kernel Linux compilato con PREEMPT_RT. – LPs

+1

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

risposta

1

Innanzitutto, è necessario verificare la precisione del metodo di registrazione cronologica; clock_gettime. La risoluzione è di nanosecondi, ma l'accuratezza e la precisione sono in questione. Questa non è la risposta al tuo problema, ma informa su quanto sia affidabile il timestamping prima di procedere. Vedere Difference between CLOCK_REALTIME and CLOCK_MONOTONIC? per il motivo per cui CLOCK_MONOTONIC deve essere utilizzato per l'applicazione.

Sospetto che la maggior parte delle fluttuazioni del tempo di decodifica sia dovuta a un numero variabile di operazioni per decodifica, commutazione di contesto del sistema operativo o IRQ.

Operazioni per decodifica Non posso commentare poiché il codice è stato semplificato nel tuo post. Questo problema può anche essere profilato e controllato.

commutazione di contesto processo può essere facilmente ispezionabile e monitorato https://unix.stackexchange.com/a/84345

Come detto Ron, questi sono molto severi requisiti di temporizzazione per una rete. Deve essere una rete isolata e un unico scopo. La tua osservazione riguardo la decodifica nel tempo quando ssh'ing indica tutto il resto del traffico deve essere prevenuta. Questo è inquietante, dati NIC separati. Quindi sospetto che gli IRQ siano il problema. Vedi/proc/interrupts.

Per ottenere tempi di decodifica coerenti su intervalli lunghi (ore-> giorni) è necessario semplificare drasticamente il sistema operativo. Rimozione di processi e servizi non necessari, hardware e magari creazione del proprio kernel. Tutto per l'obiettivo di ridurre il cambio di contesto e gli interrupt. A quel punto dovrebbe essere considerato un sistema operativo in tempo reale. Ciò migliorerà solo la probabilità di un tempo di decodifica coerente, non la garanzia.

Il mio lavoro sta sviluppando un sistema di acquisizione dati che è una combinazione di FPGA ADC, PC ed ethernet. Inevitabilmente, l'inconsistenza di un PC multiuso significa che alcune funzionalità devono essere spostate su hardware dedicato. Considera i pro/contro dello sviluppo della tua applicazione per PC piuttosto che spostarlo sull'hardware.

+0

Sto usando 'CLOCK_MONOTONIC' per prendere i timestamp. E il tempo calcolato coincide con il risultato osservato. – Vikram

+0

Ho isolato alcuni core della cpu usando il comando del kernel 'isolcpus'. Nel controllare i processi in esecuzione usando 'ps -eF', trovo che nessun processo gira su quei nuclei isolati tranne la migrazione, ksoftirqd, kworker. So che questi non possono essere evitati. – Vikram