Forum: PC-Programmierung C - Schnelle Datenauswertung auf PC - Multi-Threading?


von Tueftler (Gast)


Lesenswert?

Guten Morgen werte Kollegen,

Momentan bin ich dabei mich etwas näher mit der PC-Programmierung zu 
beschäfitgen, vorrangig in C.
Bisher war ich nur auf dem Mikrocontroller - Embedded - Bereich tätig, 
mit allen Vorzügen: einfaches Debuggen und analysieren von z.B. Timings 
mittels Pin-Toggeln etc.

Nun bin ich an einem Punkt angekommen, wo ich mal ein par Hinweise und 
Tips benötigen könnte (ich zähle auf euch :D):

Der Mikrocontroller sendet ADC-Daten (105 KSp/s, 24-Bit/32-Bit)per UDP 
an meinen PC (Ist ein 24-Bit ADC (ADS1271), dessen Daten auf 32-Bit 
erweitert werden).
Diese werden erst in einem Array gespeichert (Umwandlung in 
32-Bit-Datentyp) und anschließend zum loggen in einer Datei abgelegt.
(Es werden immer 4096 Byte = 1024 Werte in 4 UDP-Paketen empfangen und 
dann bearbeitet).
Das Empfangen der Daten dauert momentan ca. 10ms = 1000Werte.

Somit erhalte ich ca. 400KByte/s an Daten die auch alle fehlerfrei 
empfangen werden und auch in der Datei richtig abgelegt werden.

Problem:
Diese Daten sollen nun mit der FFTW-Bibliothek analysiert werden.
Das Einbinden und benutzen der FFTW-Lib ist kein Problem und 
funktioniert auch ohne Probleme.
Jedoch habe ich keine Ahnung wie lange der PC braucht um eine FFT eines 
Datensatzes (1024 Byte) auszuführen.
Das Programm folgt momentan einem linearen Fluss, weshalb ich etwas 
Bedenken habe, dass Daten verloren gehen, während die FFT ausgeführt 
wird.

Wie erreiche ich also am besten, dass die Daten per UDP gleichzeitig 
empfangen werden und verarbeitet werden?
Dabei kann ich durchaus einen kleinen zeitlichen Versatz in Kauf nehmen 
nach dem Schema:
1. Fülle Buffer1 mit Daten die empfangen werden (im Hintergrund) und 
bearbeite die Daten in Buffer2 währenddessen.
2. Fülle Buffer2 mit Daten die empfangen werden (im Hintergrund) und 
bearbeite die Daten in Buffer1....

- Wie lautet hierzu das richtige Stichwort?
- Bin ich mit Threading richtig beraten?
- Wie kann ich genaue Timings am PC messen?
  Habe keinen Prallel-Port, nur USB, Ethernet...

PC-System ist ein UBUNTU, Compiler GCC.

Mit Dank und Grüßen im Vorraus,
Tueftler

von Tom M. (Gast)


Lesenswert?

Aus dem Bauch raus würde ich die beiden Funktionen in eigenständigen 
Prozessen realisieren:

-UDP Empfang ganz einfach mit nc/netcat, in eine pipe reinschaufeln
-Analyse/Visualisierung mit deinem C Programm nach Wahl

Etwas kritisch könnte die Puffergrösse der pipe sein, auf meiner Kiste 
ist die nur wenige KB (ulimit -a). Die etwas zu Vergrössern schadet 
sicher nix, ansonsten wird der schreibende Prozess (nc) blockieren, bis 
wieder Platz frei ist.

von Karl H. (kbuchegg)


Lesenswert?

Tueftler schrieb:

> Das Empfangen der Daten dauert momentan ca. 10ms = 1000Werte.
>
> Somit erhalte ich ca. 400KByte/s an Daten die auch alle fehlerfrei
> empfangen werden und auch in der Datei richtig abgelegt werden.
>
> Problem:
> Diese Daten sollen nun mit der FFTW-Bibliothek analysiert werden.
> Das Einbinden und benutzen der FFTW-Lib ist kein Problem und
> funktioniert auch ohne Probleme.
> Jedoch habe ich keine Ahnung wie lange der PC braucht um eine FFT eines
> Datensatzes (1024 Byte) auszuführen.

Miss es einfach aus.
Auch auf einem PC gibt es sowas wie einen Clock-Tick, den man abfragen 
kann.
Goggle mal nach clock()

Würde mich aber wundern, wenn das auf einem heutigen PC 10ms dauern 
würde.

> Wie erreiche ich also am besten, dass die Daten per UDP gleichzeitig
> empfangen werden und verarbeitet werden?

Ehe du dich da jetzt in Experimente mit Multithreading einlässt, miss 
doch erst mal aus, ob du überhaupt ein Problem hast, das gelöst werden 
muss.
Der Ethernet Stack empfängt die Daten ja sowieso schon parallel zu 
deinem Programm.

von Andreas M. (amesser)


Lesenswert?

Tueftler schrieb:
> Diese werden erst in einem Array gespeichert (Umwandlung in
> 32-Bit-Datentyp) und anschließend zum loggen in einer Datei abgelegt.
> (Es werden immer 4096 Byte = 1024 Werte in 4 UDP-Paketen empfangen und
> dann bearbeitet).
> Das Empfangen der Daten dauert momentan ca. 10ms = 1000Werte.

Hast Du daran gedacht, das UDP Pakete auch mal verloren gehen können und 
Du dich um diesen Fehlerfall in deiner Software selbst kümmern must? 
Wenn möglich würde ich eher TCP verwenden, wobei man das auch später 
noch ändern kann.

> Somit erhalte ich ca. 400KByte/s an Daten die auch alle fehlerfrei
> empfangen werden und auch in der Datei richtig abgelegt werden.
>
> Problem:
> Diese Daten sollen nun mit der FFTW-Bibliothek analysiert werden.
> Das Einbinden und benutzen der FFTW-Lib ist kein Problem und
> funktioniert auch ohne Probleme.
> Jedoch habe ich keine Ahnung wie lange der PC braucht um eine FFT eines
> Datensatzes (1024 Byte) auszuführen.
> Das Programm folgt momentan einem linearen Fluss, weshalb ich etwas
> Bedenken habe, dass Daten verloren gehen, während die FFT ausgeführt
> wird.

Der Linux Kernel wird eine gewisse Menge an Daten Puffern bevor er 
anfängt eingehende UDP Pakete zu verwerfen. Wieviel das ist kann ich 
jedoch nicht genau sagen. Immer dann wenn dein PC genötigt wird die 
Auslagerungspartition zu benutzen könnte es schwierig werden. Auch 
dieses Problem würde durch Verwendung von TCP behoben

> Wie erreiche ich also am besten, dass die Daten per UDP gleichzeitig
> empfangen werden und verarbeitet werden?
> Dabei kann ich durchaus einen kleinen zeitlichen Versatz in Kauf nehmen
> nach dem Schema:
> 1. Fülle Buffer1 mit Daten die empfangen werden (im Hintergrund) und
> bearbeite die Daten in Buffer2 währenddessen.
> 2. Fülle Buffer2 mit Daten die empfangen werden (im Hintergrund) und
> bearbeite die Daten in Buffer1....
>
> - Wie lautet hierzu das richtige Stichwort?
> - Bin ich mit Threading richtig beraten?
> - Wie kann ich genaue Timings am PC messen?
>   Habe keinen Prallel-Port, nur USB, Ethernet...

Ja, Multithreading ist dazu ein guter Ansatz. Du möchtest einen 
Ringpuffer verwenden. Normalerweise sollte aber die Rechenleistung 
locker ausreichen um das linear abzuarbeiten - auch hier, TCP hilft Dir.

Um die Timings in dem Programm zu bestimmen kannst Du gprof benutzen. 
Einführung z.B. hier: 
http://www.linuxfocus.org/Deutsch/March2005/article371.shtml. Mit den 
richtigen Optionen kann man Timings auch für jede einzelne Programmzeile 
bestimmen. Denke aber daran, das ein PC kein deterministisches System 
wie ein Mikrocontroller ist. Die Timings können sich von Aufruf zu 
Aufruf ändern und hängen von zig Einflüssen ab, u.a.:

- aktive Programme
- Netzwerkverkehr
- Nutzerinteraktion

Daher, nimm TCP und Du hast es viel einfacher.

von Tueftler (Gast)


Lesenswert?

Hallo,

herzlichen Dank für eure zahlreichen Antworten!
Inzwischen läuft die Sache recht gut! Zum Glück ohne weiteres Threading.

Bin
@Tom:
Tom M. schrieb:
> -UDP Empfang ganz einfach mit nc/netcat, in eine pipe reinschaufeln
> -Analyse/Visualisierung mit deinem C Programm nach Wahl
>
> Etwas kritisch könnte die Puffergrösse der pipe sein, auf meiner Kiste
> ist die nur wenige KB (ulimit -a). Die etwas zu Vergrössern schadet
> sicher nix, ansonsten wird der schreibende Prozess (nc) blockieren, bis
> wieder Platz frei ist.

Habe anfangs auch mit NetCat experimentiert, als ich auf dem 
Mikrocontroller den LwIP-Stack in Betrieb genommen habe.
Verwundert war ich darüber, dass immer maximal 1024 Byte angekommen 
sind, egal wieviele ich per UDP gesendet habe... und par tout keinen 
Fehler in meinem MC-Programm finden konnte. Da hat NC anscheinend einen 
Bug (siehe auch Internet). Von daher war ich mit NC erstmal bedient.

@Karl:
Karl Heinz Buchegger schrieb:
> Miss es einfach aus.
> Auch auf einem PC gibt es sowas wie einen Clock-Tick, den man abfragen
> kann.
> Goggle mal nach clock()
>
> Würde mich aber wundern, wenn das auf einem heutigen PC 10ms dauern
> würde.

Mit clock() hats leider nicht funktioniert, evtl. hat mein System-Timer 
eine zu geringe Auflösung?!
Mit clock_gettime() funktioniert es und es werden sogar Nanosekunden 
ausgegeben... (Wie genau das wohl ist....?!)
http://linux.die.net/man/3/clock_gettime

Habe dann die Zeitfresser identifiziert und wandle nun nur int32_t in 
strings um und keine float um die Daten zu loggen.
Den größten Einfluss hatte aber immer noch die Optimierung, nun auf 3 
gesetzt.
Somit benötigt die FFT über 4096 (rein Rellwertige Float-)Datenpunkte 
zwischen 70...200 Micro-Sekunden.

@Andreas:
Andreas Messer schrieb:
> Hast Du daran gedacht, das UDP Pakete auch mal verloren gehen können und
> Du dich um diesen Fehlerfall in deiner Software selbst kümmern must?
> Wenn möglich würde ich eher TCP verwenden, wobei man das auch später
> noch ändern kann.

Habe mich gerade für UDP entschieden, da es einen geringeren Overhead 
hat und damit vermutlich auch schneller ist?!
Momentan ist der MC mit dem PC über einen Router verbunden, an dem 
nichts weiter hängt, von daher hoffe ich, dass da nichts verloren geht, 
werde aber in Zukunft vielleicht noch einen Index mitschicken, der es 
dann ermöglicht die Daten auf Konsistenz zu prüfen.

Vielen Dankf für den Link,
Sieht sehr interessant aus, werde ich gleich mal probieren, 
Profiling-Daten zu erstellen um zu sehen, wo sich das Programm die 
meiste Zeit aufhält. (Vermutlich in der UDP-Empfangsroutine, wo erstmal 
16 Pakete zu je 1024Byte gesammelt werden).

So Long,
Vielen Dank,
Tueftler

von Florzo (Gast)


Lesenswert?

Ich wuerde mit Integern arbeiten, nicht mit float und auch nicht mit 
strings.

UDP ist das Mittel der Wahl wenn man ein verlorenses Packet verschmerzen 
kann, wenn Geschwindigkeit wichtiger ist. zB Bild und Ton werden als UDP 
uebertragen. TCP ist das mittel der Wahl wenn alles sicher ankommen 
muss, zb bei eibem filetransfer.

von Kai S. (kai1986)


Lesenswert?

Hallo,

falls du Multi-Threading und/oder grafische Oberfläche programmieren 
möchtest könntest PureBasic benutzen.
http://www.purebasic.com/german/index.php

Die Sprache hat nur minimale Geschwindigkeitseinbusen gegenüber gutem C 
Code und für Multithreading schreibt man eine ganz normale Funktion und 
führt sie mit einer Befehlszeile lediglich asynchron zum Hauptprogramm 
aus. Es kann auch sehr einfach auf C - Bibliotheken zugegriffen werden. 
Die Hilfe ist auch außergewöhnlich gut (in Deutsch, Englisch und 
Französisch vorhanden) mit sehr vielen querverweisen zu hilfreichen 
Befehlen. Der Aufbau ist sehr stark mit C verwandt.

Ja, ich weiß es ist eine kostenpflichtige Sprache, allerdings halten 
sich die Kosten mit 80€ in Grenzen und die Lizenzbedingungen sind 
traumhaft. Zudem ist sie nahezu Plattformunabhängig (kann auf 
Windows/Linux/Mac kompiliert werden).

Gruß Kai

von Arc N. (arc)


Lesenswert?

http://www.fftw.org/speed/
http://www.fftw.org/speed/Pentium3-1.266GHz/

mflops = 5 N log2(N) / (time for one FFT in microseconds)
~10 us für eine 256 Punkt FFT auf dem Pentium3...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.