[ICON] Benchmark der GPIO-Bibliothek

  • Hallo zusammen,

    auf diesen Beitrag setze ich auf, um einen Benchmark über meine GPIO-Bibliothek zu bringen.

    Mal aus wirklich ernsthaftem Interesse: das waere aber doch wohl auch kaum Icon, oder? Benchmarks sind dazu schwer zu finden, aber die ICON-Homepage fuehrt klar aus, dass es nur interpretiert ist. Und die GPIO-Lib von dir sieht nach Druebersicht auch nach ganz normaler file-basierter IO aus. Gross anders ist das mit Bordmitteln ja auch nicht hinzubekommen.

    Im konkreten Fall hier wuerde ich denken die paar hundert Hertz sind machbar, besonders mit PIGPIO - denn es geht ja um aggregierte Daten mit Timestamps, da spielen weder Schedulerpraezision noch Performance der Sprache eine signifikante Rolle.


    Verwendete GPIO-Bibliothek

    Ich verwende die aktuellste Version meiner GPIO-Library, die zuletzt hier Beitrag #9 gepostet wurde.

    Diese Bibliothek wird im Icon-Quellcode durch folgende Zeile

    Code
    link GPIO

    eingebunden.

    Eingesetzte Raspberry Pi-Modelle
    Der Benchmark wird auf folgenden mir vorliegenden Modellen durchgeführt:

    • B
    • B+
    • A+
    • 3B

    Testmethodik
    Ein Arduino erzeugt über einen Zeitraum von einer Sekunde auf einem digitalen Ausgabe-Pin einen LOW-Pegel, hält diesen für eine vorgegebene Zeit, wechselt auf einen HIGH-Pegel, hält diesen für eine vorgegebene Zeit. Über einen Spannungsteiler (R1 = 3k3, R2 = 1k8 - dadurch liegt max. knapp 3,3 V bei Arduino-HIGH = 5 V an) wird dieser Pegel auf einem digitalen Eingabe-Pin des Raspberry Pi empfangen.


    Test 1: Halten von 4 Zyklen á 1000 ms LOW, 1000 ms HIGH
    Auf dem Arduino läuft folgendes Sketch

    Hier habe ich eine etwas ungewöhnliche Technik verwendet. In [font="Courier New"]setup()[/font] passiert alles Interessante, in [font="Courier New"]loop()[/font] befindet sich nur eine Verzögerung. Warum so?

    Ganz einfach. [font="Courier New"]setup()[/font] läuft einmal durch, [font="Courier New"]loop()[/font] wird in einer Endlosschleife ständig wiederholt, bis ein neues Sketch daherkommt oder der Strom abgeschaltet wird. Wenn ich hier Aktionen starte, die die CPU des Arduino zu 100% auslastet, dann ist er weniger empfänglich, wenn ich das Sketch aktualisieren oder tauschen möchte.

    Ein weiterer Vorteil besteht darin, dass ich das Sketch komfortabel durch den Reset-Taster starten kann. Und - bei der hier geposteten Version - nach 2 Sekunden ein Messwert vorhanden ist.


    Auf dem Raspberry Pi läuft folgendes Programm

    Programm-Deutung:
    Die GPIO-Bibliothek wird eingebunden und der zu verwendende PIN definiert.

    In der Hauptroutine [font="Courier New"]main()[/font] wird die Variable [font="Courier New"]HIGHs[/font] auf 0 gesetzt.

    Die Zeile

    Code
    while GPIO(PIN) = 0 do {}


    wartet solange, wie auf dem GPIO-Pin 0 = LOW anliegt. Wir erinnern uns: Das Arduino-Programm erzeugt für 1000 ms LOW, dann für 1000 ms HIGH. Mit dieser Zeile wird sichergestellt, dass die Endlosschleife ([font="Courier New"]repeat{}[/font]) erst dann gestartet wird, sobald der erste HIGH-Pegel erkannt wurde.

    In der Endlosschleife wird der [font="Courier New"]GPIO(PIN)[/font] = GPIO(17) gelesen. Handelt es sich um HIGH, dann wird der Zähler [font="Courier New"]HIGHs[/font] hochgezählt. Bei LOW wird die Endlosschleife mit [font="Courier New"]break[/font] abgebrochen.
    Nach Verlassen wird die Endlosschleife wird der Wert von [font="Courier New"]HIGHs[/font] angezeigt.

    Und jetzt mache ich es mir ganz einfach:
    Der Arduino sendet für 1000 ms HIGH-Pegel. Das Programm auf dem RPi hat einen HIGH-Pegel bereits gelesen. HIGHs entspricht dann einfach der Frequenz mit der Einheit 1/s.

    Ich vernachlässige mal, dass HIGHs eigentlich mit 1 initialisiert werden müsste - denn das erste Signal ist ja bereits ausgelesen worden. Aber egal. So kleinkariert bin ich heute mal nicht.

    Dieses Programm wird aus Geany heraus durch Drücken der Taste F5 compiliert und gestartet. Nachdem das Programm ein Textausgabe-Fenster erzeugt hat, betätige ich den Reset-Taster des Arduino.

    Messwerte
    Das Programm wird aus Geany heraus gestartet:
    HIGHs (RPi B+) mit [font="Courier New"]link graphics[/font]
    1863
    1817
    1846
    1861
    1863
    -----
    Mittelwert: 1850 Hz

    Das Programm wird aus LXTerminal heraus gestartet:
    HIGHs (RPi B+) ohne [font="Courier New"]link graphics[/font]
    1868
    1875
    1888
    1865
    1853
    -----
    Mittelwert: 1870 Hz

    Das Programm wird aus der Konsole ohne X11-Umgebung gestartet:
    HIGHs (RPi B+) ohne X11-Umgebung
    1951
    1966
    1941
    1924
    1935
    -----
    Mittelwert 1943 Hz


    Hier die Benchmark-Daten für RPi A+
    Aus Geany heraus gestartet:
    2052
    2021
    2041
    2051
    2032
    -----
    Mittelwert 2039


    Das Programm wird aus LXTerminal heraus gestartet:
    2020
    2012
    2001
    1921
    1920
    -----
    Mittelwert 1975


    Das Programm wird aus der Konsole ohne X11-Umgebung gestartet:
    2107
    2109
    2143
    2107
    2119
    -----
    Mittelwert 2117



    Hier die Benchmark-Daten für RPi 3B
    Aus Geany heraus gestartet:

    -----
    Mittelwert


    Das Programm wird aus LXTerminal heraus gestartet:

    -----
    Mittelwert


    Das Programm wird aus der Konsole ohne X11-Umgebung gestartet:

    -----
    Mittelwert


    Fortsetzung folgt.


    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

    3 Mal editiert, zuletzt von Andreas (16. Oktober 2017 um 21:32)

  • So, ich habe mich auch mal ans benchmarking gemacht. Ich bin erstmal deinem Vorbild gefolgt. Mein Controller ist ein anderer, ich verwende ein Pimoroni Propeller HAT. Der Propeller sitzt auf dem PI und wird mit einem Programm bestueckt, das einfach nur ein .5Hz Rechteck ausgibt. In der Summe also auch so wie du eine 1-sekuendige HIGH-Phase.

    Mein Python Skript synchronisiert sich darauf, und wenn es eine steigende Flanke erkennt, triggert es einen Messlauf.

    Die Ergebnisse sind deutlich anders als deine. Ein typischer Lauf sieht so aus:

    Code
    pi@pi:~/projects/pi-gpio-benchmark$ sudo python rpi-gpio-test.py
    294682

    Also ~300K Samples / Sekunde. Das sind mehrere Groessenordnungen mehr, als du - und ich kann mir ehrlich gesagt nicht vorstellen, dass Python 1000mal schneller ist als ICON. Da du leider deinen GPIO-Code nicht offenlegst, kann ich ueber die Ursachen aber nur spekulieren.

    Aller Code findet sich hier:

    https://github.com/deets/pi-gpio-benchmark

    Kritik & Fehlersuche natuerlich explizit erwuenscht, vielleicht mache ich etwas katastrophal dummes.

  • Jetzt noch mal in C, und wiringPI. Auch wenn ich das nicht mag, erstmal schauen, was es kann. Dort gibt es zwei GPIO-Modi: direktes lesen, und ueber sysfs. Ersteres schafft 800K samples pro sekunde, letzteres allerdings nur rund 190K. Also sogar langsamer als RPi.GPIO.

    Ich lasse mir noch mal ein paar andere einfallen bei Gelegenheit.

  • Hallo __deets__

    der Code ist in den Icon-Tutorials Teil 12, 24 und 25 "offen gelegt". Die Referenz in Beiztrag #1 dieses Threads enthält einen Link auf die aktuelle Version.

    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • Andreas: wenn ich dem Link folge komme ich zu einer ZIP-Datei "GPIO_u1_u2.zip" die zwei Dateien enthaelt - GPIO.u1 und GPIO.u2. Und GPIO.u1 hat folgenden Inhalt (Auszug):

    Das sieht mir nicht nach ICON aus wie man es zB auf http://www.cs.arizona.edu/icon/docs/ipd266.htm findet. Sondern eher nach Bytecode. Stimmt das? Wenn ja - das ist ja nun nicht offengelegter Quellcode, was ich meinte. Oder verpasse ich hier etwas offensichliches? Kenne mich mit Icon ja nicht aus.
    Automatisch zusammengefügt:
    Nachtrag: um klar zu machen, worum es mir geht: es ist dir voellig ueberlassen, wie du deine Libraries verbreitest. Nicht mein Bier. Mich interessiert in diesem Kontext hier nur, wieso es zu diesen so unterschiedlichen Ergebnissen kommt. Das kann ich natuerlich nicht beurteilen, wenn ich die "Innereien" deiner GPIO-Implementierung nicht kenne. Muss ich aber natuerlich auch nicht.

    Generell noch eine Anmerkung zu der Benchmarkerei: so oder so ist das sehr trocken. In Python schafft man ganz bestimmt keine sinnvolle Signalverarbeitung mit ~300K samples. Da wuerde ich schon bei 1-2KHz eine Grenze annehmen (das zumindest haben eigene Prograemmchen mal so ergeben). Vielleicht faellt uns noch ein "real world" benchmark ein, aber auch so finde ich die Ergebnisse erstmal Einsichtsbildend.


  • Also ~300K Samples / Sekunde. Das sind mehrere Groessenordnungen mehr, als du - und ich kann mir ehrlich gesagt nicht vorstellen, dass Python 1000mal schneller ist als ICON. Da du leider deinen GPIO-Code nicht offenlegst, kann ich ueber die Ursachen aber nur spekulieren.

    Soweit ich das aus dem Code vermute, nimmst du Python 3.x ?

    Bei Python 3.x wurden einige Bibliotheken inzwischen direkt in C++ implementiert, die Python-Befehle laufen nur noch auf Wrapper...
    (Ich finde leider aktuell den Link nicht, in dem ich das mal gelesen habe..)

    Ich habe solche Performance-Hübe zwischen Python 2.x und 3.x jedenfalls schon beobachtet (DB-Access-Code, lief wesentlich schneller unter P 3.x).
    Es gibt aber auch viele Hinweise darauf, dass P3.x Code langsamer ist als P2.x - vielleicht hängt das auch mit der Art der Programmierung zusammen...

    Egal: Die Performance von ICON scheint eben doch nur "mäßig" zu sein... jedenfalls beim Zugriff auf die GPIOs...

  • Hallo __deets__,

    dann nimm mal die PDF-Datei, die im Icon-Tutorial Teil 24 verlinkt ist. Die ist bzgl. GPIO-Setzen und -Abfragen unverändert.

    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • Zentris: ich verwende Python2.7. Und ja, das ist eine Extension-Library. Das ist ja nun genau eine der Staerken der Sprache - das einbinden von C Bibliotheken ist simpel. Siehe OpenCV, Qt (ok, das ist nich simpel, aber verfuegbar), etc. PIGPIO hingegen kommt per Socket. Da muss ich noch mal schauen, was da so geht.

    Ein guter Freund ist Radioastronom und hat terabyteweise Daten zu verarbeiten - macht er auch alles mit Python, aber natuerlich matplotlib, Numpy etc. Am Ende also C oder gar Assembler - nur schick verpackt in einfach zu nutzenden APIs. Das ist was mich als Programmierer am Ende interessiert.

    Andreas: ich habe Tutorial 24 gefunden. Das sind diverse PDFs in denen so weit ich sehen kann (das ist *viel*) aber nur die Verwendung, nicht die eigentliche GPIO-Bibliothek gezeigt wird. Damit ist mir nach wie vor nicht klar, wie die GPIO Library selbst aufgebaut ist.

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!