Inhalt
Wer ist der Schnellste? Wie lange braucht ein Raspberry Pi 2 mit Windows 10 um auf einen Tastendruck zu reagieren? Und wie lange benötigt dagegen ein Arduino, dessen Code ohne Umwege auf der Hardware ausgeführt wird? Heute gehen RaspberryPi 2 mit Windows 10, Mono und Python, GHI Cerbuino Bee und Arduino Uno ins Rennen.
Testaufbau
Um die Reaktionszeit von einem Gerät zu messen, habe ich mir eine Schaltung mit einem Arduino als Stoppuhr überlegt. Über einen manuell betätigten Taster wird ein Port vom zu messenden Gerät auf Masse gezogen. Gleichzeitig wird durch die Schaltung ein Port der Stoppuhr auf Masse gezogen, wodurch diese die Zeitmessung startet. Jetzt soll das zu messende Gerät schnellstmöglich einen anderen Port auf Masse legen. Durch die Schaltung wird dadurch ein weiterer Port der Stoppuhr auf Masse gezogen, wodurch diese die Zeitmessung beendet.
Als Stoppuhr verwende ich einen Arduino. Von diesem erwarte ich eine möglichst geringe Messungenauigkeit, da dieser kein Betriebssystem hat und auch keinen Garbage Collector, der unerwartet ausgeführt wird und somit die Messergebnisse verfälschen würde.
Raspberry Pi 2
Für den RPi 2 habe ich zwei SD-Karten vorbereitet. Eine mit Windows 10 und eine mit Raspbian (Linux).
Windows 10 mit Universal App und C# (Update für Windows 10 RTM!)
Die Universal-App für Windows 10 (RTM – Build 10240, .Net Framework 4.6 / 4.0.30319.42000) geht zuerst ins Rennen.
Der Code auf der linken Seite arbeitet die Aufgabe in einer Endlosschleife ab, während der Code auf der rechten Seite die Aufgabe event-gesteuert (Hardware-Interrupt?) löst.
In der Endlosschleife benötigt der Pi im Schnitt 26 µs um zu reagieren. Dabei schwankt der Wert von 16 bis 44 µs mit Ausreißern bis 16.000 µs. Vermutlich war das Betriebssystem gerade mit anderen Dingen beschäftigt. Für gewöhnliche Anwendungsfälle ist das schnell genug, beträgt die Reaktionszeit in diesem Ausnahmefall auch nur umgerechnet 0,016 Sekunden.
Weiter geht’s mit dem event-gesteuerten Code. Dieser ist mit durchschnittlich 300 µs eine ganze Ecke langsamer.
Update 15.08.2015: Zuerst habe ich diesen Test mit der CTP von Windows 10 gemacht. Die Messung habe ich heute mit der mittlerweile verfügbaren finalen Version wiederholt. Die direkte Ansteuerung in der Schleife ist etwa acht mal schneller geworden. 🙂 Die angegebenen Werte auf dieser Seite beziehen sich auf die finale Version.
Raspbian (Linux) mit mono und C#
Auf der anderen SD-Karte habe ich Raspbian installiert. Für C# habe ich mono installiert und per RDP mit MonoDevelop entwickelt. Wenn unnötig umständlich, dann richtig. 😉
Für den Zugriff auf die GPIOs habe ich die bcm2835-Library von mikem benutzt. Mit dieser kann linuxtypisch dateibasiert (GPIOFile) oder direkt auf den entsprechenden Speicherbereich (GPIOMem) der GPIOs zugegriffen werden.
Einen Interrupt oder ein entsprechendes Event habe ich nicht gefunden. Daher tritt die Mono-Implementierung nur mit der Endlosschleife an. Diese rennt mit einer Reaktionszeit von unter 10 µs bei der GPIOMem-Variante aber sehr schnell. 10 µs ist übrigens die Untergrenze meiner Arduino-Messmethode. Leider konnte ich auch hier ab und zu mit 13.000 µs Ausreißer nach oben beobachten.
Der dateibasierte Zugriff auf die GPIOs (GPIOFile) ist mit durchschnittlich 860 µs deutlich langsamer.
Raspbian (Linux) mit Python
Ist die RDP-Sitzung schon mal offen, kann ich natürlich auch noch Python ausprobieren…
Die Python-Implementierung überraschte mich mit durchschnittlich 160 µs bei der Interrupt-Variante positiv. Die Endlosschleife schaffte sogar den Referenzwert von unter 10 µs. Leider gab es auch hier hin und wieder Ausreißer im Millisekundenbereich.
.Net Micro Framework – GHI Cerbuino Bee
Für das .Net Micro Framework tritt ein Cerbuino Bee von GHI an. Auf diese Ergebnisse war ich am meisten gespannt, denn hier gibt es kein Betriebssystem, das zwischendurch andere Aufgaben für wichtiger halten könnte. Andererseits wird der Code nur interpretiert und einen Garbage Collector gibt es auch, der ab und zu in Erscheinung treten könnte.
Die Ergebnisse bestätigen dies: Die Endlosschleifenvariante kratzt mit durchschnittlich 20 µs am optimalen Wert. Mit 60 µs ist auch die Interrupt-Variante sehr schnell dabei. Auch hier gab es hin und wieder negative Ausreißer bis in den Millisekunden-Bereich. Ob da der Garbage Collector am Werk war?
Arduino Uno
Der einzige Code, der in diesem Vergleich wirklich nah auf der Hardware läuft, ist der Arduino-Code. Der Arduino Uno hat zwar mit Abstand den langsamsten Prozessor, dieser muss jedoch nichts weiter tun als genau das, was von ihm verlangt wird.
Und das schlägt sich auch in den Testergebnissen nieder. Die Endlosschleife reagiert fast immer in unter 10 µs. Und auch mit Interrupts ist er kaum langsamer. Da kommt die Reaktion meist nach 12 µs, womit der schlanke Arduino in dieser Disziplin die klare Referenz bildet. Außerdem gab es hier logischerweise durch das fehlende Betriebssystem und sonstige Aufräumer keine Ausreißer nach oben.
Auswertung
Auch wenn die „höheren“ Kisten etwas langsamer reagieren muss man die Relation verstehen. Auf Sekunden umgerechnet dauert selbst die Reaktion des übelsten Ausreißers nur 0,023 Sekunden. Ob das hinnehmbar ist, kommt dann einfach auf den Anwendungsfall an. Interessant ist die Messung dieser Ausreißer nach oben trotzdem, wird so der Unterschied zwischen Microcontroller und sehr kleinem PC mit Betriebssystem doch klarer.
Das Blatt wendet sich bei aufwendigeren Berechnungen, wenn die schnelleren Prozessoren diesen Reaktionsnachteil durch Ihre Leistung wieder rausholen können. Benötigt eine Berechnung für die Ausgabe auf einem Arduino beispielsweise 3000 µs und auf dem Raspberry nur 500 µs, wäre der Gesamtzeitbedarf beim Arduino schlechter.
Dieser Test hat übrigens nicht den Anspruch besonders genau oder fair zu sein. 😉
Besten Dank übrigens an die Kollegen Peter und Daniel, die mir mit Arduinos und Raspberries ausgeholfen haben. 🙂
Weiterführende Links
- http://raspberrypiguide.de – Raspberry Pi GPIO How-To
Ansteuerung der Raspberry Pi GPIOs aus verschiedenen Sprachen - raspberry-sharp.org – Installing Mono on Raspberry Pi
- Windows Developer – Raspberry Pi: .NET-Entwicklung mit Mono
- bcm2835-Library
- Lösung zu: GPIOMem DllNotFoundException: libbcm2835.so
Unhandled Exception: System.TypeInitializationException: An exception was thrown by the type initializer for RaspberryPiDotNet.GPIOMem —> System.DllNotFoundException: libbcm2835.so
Sehr schöner kleiner Testvergleich mit Hauptaugenmerk auf den wichtigsten Aspekt eines Embedded System für Maker 😉
Danke
Dieser Vergleich ist doch ein bisschen Blödsinn – Entschuldigung.
Da werden „Programmiersprachen“ verglichen, ohne zu hinterfragen, wie der Algorithmus auf der CPU abgearbeitet wird. Und sobald ein Programm auf einem Betriebssystem gestartet wird, das auch Prioritäten für den Scheduler und CPU frequency scaling kennt, wird dies völlig missachtet.
Daniel, mach doch einfach mal Deine „Tests“ wenn Du die CPU-Frequenz, auf volle Geschwindigkeit, den Scheduler auf Realtime und höchste Priorität setzt. Dann werden die Anderen Prozesse nicht mehr so stören können. Aber mach es nicht zu lange, sonst springt vielleicht ein Watchdog an 😉
Auch unter mono kann „Interrupt“ getestet werden -> Stichwort poll auf einen geöffneten File-Descriptor.
Dann auch eine Frage: Warum hast Du nicht unter Windows IoT auch einen Direktzugriff auf den BCM 2835 getestet? Das ist doch der selbe Chip.
Hi Steffen!
Danke für die Anregungen.
Mein Vergleich soll eher die Technologien ansich vergleichen. „Kann ich mit Technologie XY mein Projekt umsetzen?“. Und zwar so wie die Projekte meiner Meinung nach üblicherweise umgesetzt werden (Arduinos in C, Windows 10 mit C# – über die normalen Events…). Daher der Vergleich, der technisch betrachtet sehr nach Äpfel und Birnen klingt.
Dein Vorschlag unter Windows 10 direkt auf den BCM 2835 zuzugreifen, klingt interessant. Kannst du das testen oder mir den Code dafür schicken? Genauso mit dem Interrupt-Zugriff unter mono.
Grüße!