-
Notifications
You must be signed in to change notification settings - Fork 0
Performance de
English · Deutsch
Das Zeichenbudget für alle, die einen Bildschirm hinzufügen oder ändern.
Die Frame Rate dieses Panels begrenzt die Bandbreite des PSRAM (Pseudo-Static Random-Access Memory), nicht die CPU (Central Processing Unit). Die LCD-Einheit (Liquid-Crystal Display) liest ununterbrochen einen Framebuffer mit etwa 30 MB/s aus dem PSRAM, und die Framebuffer liegen hinter einem Write-Back-, Write-Allocate-Datencache (64 KB, 8-fach assoziativ, 64-Byte-Lines). Jedes Pixel, das die CPU schreibt, kostet einen 64-Byte-Line-Fill und ein 64-Byte-Write-Back, sofern die Line nicht schon geladen ist. Die Kosten eines Frames sind deshalb eine Anzahl von Cache-Line-Fills, und die lässt sich auf dem Host exakt messen.
tools/frame_cost.py baut die echten Bildschirme für den Host und lässt sie
unter cachegrind mit der Cache-Geometrie des ESP32-S3 laufen. Es meldet die
Differenz zwischen einem und elf gerenderten Frames, sodass Prozessstart und
das erste Füllen jedes Buffers herausfallen.
$ python3 tools/frame_cost.py
panel 39.0 Hz, ~39 MB/s effective -> 976 KiB of traffic per panel frame
mode lines/frame traffic est. ms est. fps
-------------------------------------------------------
frame 8,856 1107 KiB 29.1 19.5
frame-idle 1,274 159 KiB 4.2 39.0
held 4,777 597 KiB 15.7 39.0
sim 9,817 1227 KiB 32.2 19.5
throttle 10,598 1325 KiB 34.8 19.5
chrome 33,106 4138 KiB 108.7 7.8
overview 953 119 KiB 3.1 39.0
servo 15,759 1970 KiB 51.7 13.0
servo-grip 3,026 378 KiB 9.9 39.0
analyser 871 109 KiB 2.9 39.0
logs 937 117 KiB 3.1 39.0
settings 862 108 KiB 2.8 39.0
battery 871 109 KiB 2.9 39.0
balance 865 108 KiB 2.8 39.0
programmer 895 112 KiB 2.9 39.0
balance-sim 2,395 299 KiB 7.9 39.0
settings-sim 2,407 301 KiB 7.9 39.0
battery-sim 2,401 300 KiB 7.9 39.0
analyser-chrome 39,234 4904 KiB 128.8 6.5
logs-chrome 16,061 2008 KiB 52.7 13.0
settings-chrome 23,591 2949 KiB 77.4 9.8
battery-chrome 36,987 4623 KiB 121.4 7.8
balance-chrome 40,685 5086 KiB 133.5 6.5
programmer-chrome 28,480 3560 KiB 93.5 9.8
picker 902 113 KiB 3.0 39.0
picker-chrome 15,883 1985 KiB 52.1 13.0
clear 12,006 1501 KiB 39.4 19.5
vlines 8,160 1020 KiB 26.8 19.5
hlines 0 0 KiB 0.0 39.0
| Modus | Was er misst |
|---|---|
frame |
der Motorprüfstand auf einem Frame, in dem ein Telemetriesample eintrifft |
frame-idle |
der Motorprüfstand auf einem Frame zwischen zwei Samples, ohne Berührung |
held |
der Motorprüfstand zwischen zwei Läufen: live Anzeigen über einem Plot, der den letzten hält |
sim |
wie frame, mit dem SIMULATION-Watermark |
throttle |
der Motorprüfstand mit einem Finger am Gas, der Drag-Fall |
chrome |
der Motorprüfstand ohne Cache, vollständig neu gezeichnet |
overview |
das Menü, Chrome gecacht |
servo |
der Servobildschirm mit neu gezeichnetem Arm |
servo-grip |
der Servobildschirm, nur der Griff neu gezeichnet |
analyser, logs, settings, battery, balance, programmer, picker
|
ein ruhiger Frame dieses Bildschirms, Chrome gecacht |
<screen>-sim |
derselbe Bildschirm mit dem SIMULATION-Watermark |
<screen>-chrome |
derselbe Bildschirm, auf jedem Frame invalidiert |
clear |
ein Löschen des ganzen Bildschirms |
vlines |
siebzehn senkrechte Linien über die volle Höhe |
hlines |
dieselbe Pixelzahl als waagerechte Linien |
Die absoluten Zahlen verschieben sich zwischen Maschinen um einige Fills, weil
argv und die Umgebungsvariablen denselben Cache belegen wie der Framebuffer.
frame_cost.py --check-doc prüft die Tabelle deshalb mit einer Toleranz von
1 %.
Zeilenweise zeichnen. Siebzehn senkrechte Linien über die volle Höhe kosten 8 160 Fills; dieselbe Pixelzahl als waagerechte Linien kostet null, weil jede Line vom vorigen Pixel noch geladen ist. Die Oberfläche ist in waagerechte Bänder gegliedert, und eine senkrechte Trennlinie ist eine bewusste Ausgabe.
Das Chrome cachen. Alles neu zu zeichnen kostet etwa das Dreißigfache des
eingeschwungenen Zustands. Jeder Bildschirm führt je Framebuffer eine
Bitmaske dessen, was er schon gezeichnet hat; dafür ist das Argument
buffer_index von render() da. Das Panel wechselt zwischen zwei Buffern;
ein Bildschirm, der nur den gerade gezeichneten Buffer invalidiert, lässt den
anderen einen Frame zurück, was als Flackern erscheint.
Ein Stencil, das sich nicht bewegt, wird gecacht. SIMULATION wird auf
jedem Frame gezeichnet, sobald die Prüfstandswerte LINK_BN_SIMULATED tragen,
also auch bei einem Coprozessor, der mit simulierten Werten antwortet.
Gedrehter Text scannt seine gedrehte Bounding-Box, von Ecke zu Ecke also die
ganze Canvas, und rotiert und dividiert je Pixel, um die 3 439 Pixel zu
schreiben, die das Watermark bedeckt: 0,9 % der Canvas. ui_watermark nimmt
diese Punkte einmal auf und schreibt sie danach nur noch, mit 144 721
Instruktionen je Frame statt 8 412 078.
Eine Zahl von Fills ist keine Zahl von Zyklen. Die Tabelle oben misst Cache-Line-Fills, und das Watermark kostet davon nur 1 586: es ist Arithmetik je Pixel, kein Traffic. Es kostete das 58-Fache dessen, was die Tabelle nahelegte, und die Tabelle konnte das nicht zeigen. Wo die gemessene Frame-Zeit eines Modus über dem liegt, was seine Fills vorhersagen, erst Instruktionen zählen, dann der Schätzung trauen.
Ein Bedienelement, das sich jeden Frame bewegt, bekommt seinen eigenen
Zähler. Ein Drag liefert eine Berührung je Frame. Die Buttons und das Gas
des Motorbildschirms teilten eine Revision, weshalb ein Drag jedes
Bedienelement daneben neu zeichnete. Das Gas hat jetzt seinen eigenen
und zeichnet die Box der Anzeige und die bemalte Region des Sliders neu:
Der Modus throttle in der Tabelle oben misst das gegen einen Sample-Frame.
Der Flip quantisiert auf ganze Panel-Frames: ein Drag liegt entweder
innerhalb von zwei davon oder wartet auf einen dritten, also 19,5 fps oder
13,0. Auf der Hardware mit 50,5 ms gemessen, nahm der alte Drag den dritten.
Zu löschen ist, was ein Widget bemalt, nicht was es einnimmt. Der Daumen des
Sliders und sein Schatten stehen 5 px oben und 7 px unten über den Track
hinaus, und die Hero-Ziffern sind 32 px hoch mit 3 px Schräge auf einer 30 px
hohen Zeile. Ein Clear in der Grösse des Tracks oder der Zeile lässt daher an
jeder Position, die der Finger passiert hat, einen Daumen und die Füsse der
Ziffern stehen. ui_slider_painted_rect() liefert die Region, statt sie den
Aufrufer herleiten zu lassen.
Nur auf Frames zeichnen, die etwas zu zeichnen haben. Samples kommen mit
20 Hz, das Panel zeichnet mit 39 Hz, also hat etwa jeder zweite Frame nichts
Neues. Der Prüfstandsbildschirm führt den Push-Zähler des Plots und eine
Revisionsnummer der Bedienelemente, jeweils je Framebuffer, und zeichnet Plot,
Anzeigen und Bedienelemente nur neu, wenn der zugehörige Zähler sich bewegt
hat. each_framebuffer_is_updated_independently in test_motor hält die
Zähler je Buffer fest.
Das Panel bewegt 976 KiB je Frame bei 39 Hz. Ein Frame, der das Doppelte kostet, landet bei 19,5 fps (Frames pro Sekunde), also einem Frame je 20-Hz-Telemetriesample; schneller zu zeichnen würde identische Pixel neu malen, langsamer würde Samples verlieren. CI (Continuous Integration) hält jeden Modus an eine Obergrenze:
| Modi | Obergrenze (Fills) | Fängt |
|---|---|---|
frame, sim
|
15 600 | einen Prüfstandsframe, der ein Telemetriesample überschreitet |
overview |
2 000 | einen Bildschirm mit gecachtem Chrome, der neu zu zeichnen begonnen hat |
servo |
17 000 | ein Wachsen der Arm- und Griffzeichnung |
servo-grip |
4 000 | ein Atmen, das die ganze Karte neu zeichnet |
| die sieben Bildschirmmodi | 1 200 | einen Bildschirm, der neu zu zeichnen begonnen hat |
die drei -sim-Modi |
2 800 | ein Watermark, das über die volle Canvas hinauswächst |
die sieben -chrome-Modi |
45 000 | ein wachsendes vollständiges Neuzeichnen |
Braucht ein künftiger Bereich mehr Platz, sind die verbleibenden Hebel vom gröbsten zum feinsten: die Höhe des Plots, seine Breite, und das Simulations-Watermark auf den tatsächlich neu gezeichneten Bereich zu clippen.
Die Logzeile DRAW … WAIT … des ESP32-S3, alle 300 Frames ausgegeben, ist
die Prüfung auf der Hardware: DRAW ist die Zeichenzeit, WAIT die Zeit, die
der Buffer-Wechsel blockiert hat. Ein gesunder Frame besteht überwiegend aus
WAIT.
rcbench
English
Using the bench
- What this is for
- Building
- Bringing up the link
- First run on hardware
- Screens
- Balancing
- Servo procedures
- Receiver buses
- Safety
- BLHeli_32 parameters
Reference
Deutsch
Den Prüfstand benutzen
- Worum es geht
- Bauen
- Den Link in Betrieb nehmen
- Erster Lauf auf der Hardware
- Bildschirme
- Auswuchten
- Servoverfahren
- Empfängerbusse
- Sicherheit
- BLHeli_32-Parameter
Referenz