2016-02-12 18 views
11

Piszę kod, który odbiera surowe pakiety ethernetowe (bez TCP/UDP) co 1ms z serwera. W przypadku każdego odebranego pakietu moja aplikacja musi odpowiedzieć 14 nieprzetworzonymi pakietami. Jeśli serwer nie odbierze 14 pakietów, zanim wyśle ​​pakiet zaplanowany na każde 1 ms, serwer zgłosi alarm, a aplikacja musi się zepsuć. Komunikacja między serwerem a klientem to połączenie jeden-jeden.Odbieranie pakietów gniazd RAW z dokładnością do mikrosekund

Serwer to sprzęt (FPGA), który generuje pakiety z dokładnością do 1ms. Aplikacja kliencka działa na maszynie Linux (RHEL/Centos 7) z 10G SolarFlare NIC.

Moja pierwsza wersja kodu jest jak ten

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"); 
    } 
} 

zmierzyć czasu odbioru poprzez znaczniki czasu (używając clock_gettime) przed wywołaniem recvfrom i jeden po niej drukować różnice czasowe tych znaczników czasu i wydrukować je, gdy różnica czasu przekracza dopuszczalny zakres 900-1100 nas.

Problem jestem stoi to, że pakiet otrzymać czas fluctuating.Something tak (odciski są w mikrosekund)

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

a czasami czasy dekodowania przekraczać 2000us i stosowania pęknie.

W tej sytuacji aplikacja może zostać przerwana w dowolnym miejscu w zakresie od 2 sekund do kilku minut.

Opcje wypróbowane przeze mnie do tej pory.

  1. Ustawianie powinowactwa do określonego izolowanego rdzenia.
  2. ustawień priorytetów szeregowania maksymalnie buforem gniazda SCHED_FIFO
  3. Zwiększenie wielkości
  4. sieciowa Ustawienie przerwania powinowactwo do samego rdzenia, który procesów nakładania
  5. Spinning na recvfrom pomocą poll(),select() połączenia.

Wszystkie te opcje dają znaczną poprawę w stosunku do początkowej wersji kodu. Teraz aplikacja działała przez ~ 1-2 godziny. Ale to wciąż nie wystarcza.

Kilka obserwacji:

  1. mam aa ogromny zrzut tych odbitek czasu dekodowania, gdy biorę sesji ssh na komputerze z systemem Linux, podczas gdy aplikacja jest uruchomiona (co sprawia, że ​​myślę komunikację sieciową na inny interfejs 1G Ethernet powoduje zakłócenia w interfejsie Ethernet 10G).
  2. Aplikacja działa lepiej w RHEL (czas pracy około 2-3 godzin) niż Centos (czas pracy około 30 minut - 1,5 godziny)
  3. Czas pracy jest również różny w przypadku maszyn Linux z różnymi konfiguracjami sprzętowymi z tym samym OS.

Proszę zasugerować, czy istnieją inne metody poprawy czasu działania aplikacji.

Z góry dziękuję.

+2

Oprócz czasu przetwarzania, musisz zrozumieć, że w rzeczywistym świecie sieci znacznie różnią się czasem dostarczania pakietów. Możesz to w pewnym stopniu złagodzić, jeśli jest to wszystko w twojej sieci (nie przechodzi przez Internet), jeśli masz solidne zasady QoS w miejscu i definiujesz kolejki priorytetowe dla tego ruchu. W przeciwnym razie nie próbowałbym nawet próbować używać czegoś z tak bliskim czasem w sieci. –

+0

Proponuję Ci, jeśli możesz, spróbować użyć skompilowanego jądra Linux PREEMPT_RT. – LPs

+1

Byłoby miło wiedzieć, co chcesz osiągnąć, ponieważ, certyfikując, wysyłanie pakietów z tą dokładnością nie jest możliwe przez Ethernet. Sugerowałbym posiadanie kolejnego FPGA do przetworzenia twojego interfejsu danych AND z twoim PC. – Koshinae

Odpowiedz

1

Najpierw należy zweryfikować poprawność metody znakowania czasem; clock_gettime. Rozdzielczość wynosi nanosekundy, ale chodzi o dokładność i precyzję. To nie jest odpowiedź na twój problem, ale informuje o tym, jak wiarygodne jest oznaczanie znacznika czasu przed kontynuowaniem. Zobacz Difference between CLOCK_REALTIME and CLOCK_MONOTONIC?, dlaczego CLOCK_MONOTONIC powinien być używany dla twojej aplikacji.

Podejrzewam, że większość fluktuacji czasu dekodowania jest spowodowana zmienną liczbą operacji na dekodowanie, przełączaniem kontekstowym systemu operacyjnego lub przerwaniami IRQ.

Operacje na kodowanie Nie mogę komentować, ponieważ kod został uproszczony w twoim poście. Ten problem można również profilować i sprawdzać.

przełączania kontekstu w procesie mogą być łatwo kontrolowane i monitorowane https://unix.stackexchange.com/a/84345

Zgodnie Ron, są bardzo wysokie wymagania synchronizacyjne do sieci. Musi to być izolowana sieć i jeden cel. Wasze obserwacje dotyczące czasu dekodowania w czasie, gdy ssh'ing wskazuje na cały inny ruch, muszą zostać zablokowane. Jest to niepokojące, biorąc pod uwagę oddzielne karty sieciowe. Tak więc podejrzewam, że problemem są IRQ. Zobacz/proc/interrupts.

Osiągnięcie stałych czasów dekodowania w długich odstępach czasu (w godzinach-> dniach) będzie wymagało drastycznego uproszczenia systemu operacyjnego. Usuwam niepotrzebne procesy i usługi, sprzęt i prawdopodobnie buduję własne jądro. Wszystko po to, by ograniczyć przełączanie kontekstów i przerywanie. W tym momencie należy wziąć pod uwagę system operacyjny czasu rzeczywistego. To tylko zwiększy prawdopodobieństwo spójnego czasu dekodowania, a nie gwarancji.

Moja praca polega na opracowaniu systemu akwizycji danych, który stanowi połączenie FPGA ADC, PC i Ethernet. Nieuchronnie niespójność komputera wielofunkcyjnego oznacza, że ​​pewne funkcje muszą zostać przeniesione do dedykowanego sprzętu. Zastanów się nad zaletami/wadami tworzenia aplikacji na PC zamiast przenoszenia jej na sprzęt.

+0

Używam 'CLOCK_MONOTONIC' do podejmowania znaczników czasu. A obliczony czas jest zgodny z obserwowanym wynikiem. – Vikram

+0

Mam izolowane kilka rdzeni procesora za pomocą komendy jądra 'isolcpus'. Sprawdzając uruchomione procesy za pomocą 'ps -eF', stwierdzam, że żadne procesy nie działają na tych izolowanych rdzeniach z wyjątkiem migracji, ksoftirqd, kworker. Wiem, że nie można ich uniknąć. – Vikram