Windows 10 IoT Digital I/O Performance, Teil 1

5. Oktober 2016

Seit Microsoft im vergangenen Sommer sein Windows 10 IoT für das Internet of Things herausgebracht hat, ist eine rege Entwicklergemeinde entstanden, die Hardwareprojekte auf Basis dieses Betriebssystems realisiert. In dieser Artikelserie wird die Performance des Systems bei der Verarbeitung digitaler Hardwaresignale untersucht.

Insbesondere die Unterstützung der äußerst populären Hardwareplattform Raspberry PI 2 und 3 machen die Verwendung von Windows 10 IoT interessant. Als Mitglied der Universal Windows Platform Familie ermöglicht diese Windows 10 Variante für Geräte es Entwicklern, die gewohnte Toolchain mit Visual Studio 2015 zu benutzen und dabei gelernte Skills weiter zu verwenden.

Digital I/O

Die Raspberry Einplatinencomputer stellen über einer Stiftleiste eine Vielzahl an Signalen zur Verfügung, die bei der Kommunikation mit Hardwarekomponenten eingesetzt werden können: 2 serielle SPI Busse, 1 serieller I²C Bus sowie 24 digitale Ein- und Ausgänge (Digital I/O). Letztere können beliebig als Eingang oder Ausgang konfiguriert werden und spielen bei praktisch allen Einsatzszenarien eine entscheidende Rolle. Fast jeder Hardwarebaustein, der an den Raspberry gekoppelt wird, nutzt zur Steuerung digitale Ein- und Ausgänge.

Sollen anspruchsvollere Aufgaben als z.B. das simple Blinken einer LED im Sekundentakt erledigt werden, ist durchaus die Performance von Bedeutung, mit der Windows 10 IoT die Digital I/Os des Raspberry bedienen kann. Hier kommen zwei Anforderungsfälle bzw. Performancefragen ins Spiel:

  • Mit welcher Frequenz kann ein Digitaleingang gelesen bzw. Digitalausgang geschrieben werden? Dies kann z.B. bei Verwendung von Pulsweitenmodulation PWM (der Raspberry PI hat keine Analogein- oder ausgänge) oder beim Sampling/Multiplexen von Eingängen interessant werden.
  • Wie lange dauert es minimal, bis auf einen Zustandswechsel eines Digitaleingangs reagiert wird? Diese Verzögerungszeit ist wichtig, um beispielsweise fest im Datenblatt definierte Timings eines Hardwarebausteins einhalten zu können.

Programmierung

Die Entwicklung eines Programms für Windows 10 IoT erfolgt über das Erstellen einer Universal Windows App. Hierfür wird das entsprechende Project Template im Visual Studio benutzt. Der Zugriff auf Hardwarekomponenten wird durch Hinzufügen einer Universal Extensions Referenz im Projekt auf die Windows IoT Extensions for the UWP zur Verfügung gestellt:

Add Reference

Für das Management der Digital I/Os sind unter Windows 10 IoT die Klassen GpioController und GpioPin vorgesehen. GpioController dient als übergeordnete Managementklasse dem Abfragen der verfügbaren GpioPins sowie deren Konfiguration als Ein- oder Ausgang. Das Lesen und Schreiben von  Signalen wird dann über GpioPin mit den Methoden Read und Write erledigt. Diese legen damit die im ersten Anforderungsfall beschriebene maximale Lese- und Schreibfrequenz fest. Zum Erkennen von Zustandsänderungen eines Eingangs stellt GpioPin das Event ValueChanged zur Verfügung. Die im zweiten Anforderungsfall dargestellte Verzögerungszeit ist also genau die Dauer, die vom Ändern des Signalzustands bis zum Erreichen der auf ValueChanged registrierten Eventhandlermethode verstreicht.

Das Scheitern eines Projektes des Autors führte dazu, einmal die Ausführungszeiten von Vorgängen mit Digital I/Os zu messen. Konkret gab es Probleme beim Einsatz zweier Hardwarekomponenten, die jeweils zu hohe Anforderungen an die digitale Signalverarbeitungsgeschwindigkeit stellten.

Im ersten Fall sollte ein VLSI Soundchip zur Wandlung eines analogen Stereo Audiosignals in digitale Wavedaten mit 44kHz / 16 Bits zum Einsatz kommen. Dies erforderte die zyklische Prüfung eines Eingangssignals des Chips pro übertragenem Byte der Wavedaten. Eine einfache Rechnung ergibt dann eine minimale Lesefrequenz des Steuersignals von 44kHz * 2 (Stereo) * 2 (16 Bits) = 176kHz. Anders herum ausgedrückt darf die maximale Dauer eines Lesevorgangs eines Eingangssignals im gegebenen Anwendungsfall 5,6µs nicht übersteigen. Um auf der sicheren Seite zu sein, sollte ein Lesen des Digitaleingangs noch deutlich schneller sein, damit noch Zeit für restliche Aufgaben wie die Bearbeitung der Wavedaten (Filtern, Wegschreiben, Konvertieren) zur Verfügung steht. Die Erwartung ist, dass dies auf einer 900MHz CPU kein Problem darstellen dürfte.

Messung

Die Messung der Ausführungsgeschwindigkeit kann mit der folgenden kurzen Methode durchgeführt werden:

   1: /// <summary>

   2: /// Perform GPIO reads in a close inner loop

   3: /// </summary>

   4: public async Task DoReads()

   5: {

   6:     // Get default GPIO controller

   7:     var gpioController = await GpioController.GetDefaultAsync();

   8:

   9:     // Open pin #6 for input 

  10:     using (var gpioReader = gpioController.OpenPin(6, GpioSharingMode.Exclusive)) {

  11:         gpioReader.SetDriveMode(GpioPinDriveMode.Input);

  12:         // Reset counter

  13:         this.PerformanceCounter.Reset();

  14:         // Do reads as long as measurement is active

  15:         while (this.isMeasurementActive) {

  16:             var value = gpioReader.Read();

  17:             this.PerformanceCounter.Counter++;

  18:         }

  19:     }

  20:     this.stopMeasurement.Set();

  21: }

Das Prinzip ist sehr einfach: In einer kurzen Schleife wird so schnell wie möglich ein Digitaleingang gelesen und ein Zähler (long) inkrementiert (Zeilen 15-18). Eine äußere Messmethode ermittelt dann in regelmäßigen Abständen die Inkrements pro Zeit. Dabei wird für die Zeitmessung die im Raspberry Pi mit High Precision implementierte StopWatch Klasse verwendet. Daraus kann direkt die Frequenz berechnet werden, mit der die Schleife läuft. Um den Einfluss des Messalgorithmus herauszurechnen, wurde zunächst die Schleife mit auskommentierter Zeile 16 ohne Lesen des Digitaleingangs verwendet. Anschließend wurde dann die echte Messung durchgeführt. Analog kann das Verfahren für das Schreiben eines Digitalausgangs angewendet werden. Die folgende Tabelle listet die Ergebnisse für verschiedene Versionen von Windows 10 IoT auf einem Raspberry Pi 2:

Ergebnisse
.

Windows 10 IoT Version Frequenz leer Dauer leer Frequenz Lesen Dauer Lesen Frequenz Schreiben Dauer Schreiben
1507 14MHz 70ns 41kHz 24µs 40kHz 25µs
1511 14MHz 70ns 167kHz 6µs 167kHz 6µs
1608 14Mhz 72ns 250kHz 4µs 222kHz 4,5µs

.
Bewertung

Zunächst ist festzustellen, dass der Einfluss der Messmethode zu vernachlässigen ist. Die Leerschleife läuft rund drei Größenordnungen schneller als unter Verwendung einer Messung. Dann ist zu beobachten, dass mit jeder Windows 10 IoT Version das Handling der Digital I/Os signifikant verbessert wurde. Besonders von Version 1507 auf 1511 konnte ein Performanceschub um grob den Faktor 4 erzielt werden. Alle Ergebnisse wurden übrigens im Debugmode gemessen. Das Kompilieren des Programms mit der native Toolchain, d.h. Erzeugen von nativem Arm Code, beschleunigt die Leerschleife um etwa den Faktor 4 auf 61MHz (16ns Zykluszeit), hat jedoch keinen messbaren Einfluss auf Schreiben oder Lesen via GpioPin. Hier spielt wohl letztlich die Implementierung im Kernel die entscheidende Rolle.

Damit besteht unter Version 1608 zum ersten Mal die Möglichkeit, das oben beschriebene Anwendungsszenario zu realisieren. Dennoch kann man die Messergebnisse insgesamt nur als sehr enttäuschend bezeichnen. Ähnliche Benchmarks unter anderen Betriebssystemen bei Verwendung nativen Codes zeigen ganz andere Werte: So ist unter Linux mit Hilfe von C Code und Einsatz der native Library eine Frequenz von 22MHz bei eine Zykluszeit von 45ns zu erreichen. Dies ist ca. 2 Größenordnungen oder um den Faktor 100 besser, als der mit der neuesten Windows 10 IoT und C# erreichbare Wert. Diese Werte eröffnen noch ganz andere Anwendungsmöglichkeiten und stellen die Verwendung von Windows 10 IoT für viele Hardwareprojekte komplett in Frage.

Es ist klar, dass Windows 10 IoT nicht den Anspruch hat, mit harten Echtzeitbetriebssystemen wie etwa LynxOS oder OS-9 zu konkurrieren. Jedoch werden die offensichtlich bestehenden Möglichkeiten der Raspberry Pi Hardware noch nicht einmal annähernd ausgeschöpft. Hier existiert also noch reichlich Optimierungspotential und –bedarf, damit auch Performance herausfordernde Projekte möglich werden.

 

Im zweiten Teil der Serie wird das Zeitverhalten von Windows 10 IoT bei Hardwareevents untersucht.