In diesem Beitrag erzählt der Chromium-Mitarbeiter Ahmed Elwasefi, wie er über das Google Summer of Code zum Mitwirkenden wurde und welche Probleme mit der Barrierefreiheit er erkannt und behoben hat.
Als ich mich meinem letzten Jahr im Fachbereich Informatik an der Deutschen Universität in Kairo näherte, beschloss ich, nach Möglichkeiten zu suchen, einen Beitrag zu Open Source zu leisten. Ich begann, die Liste der für Anfänger geeigneten Probleme in Chromium zu durchsuchen, und fand mich besonders von der Barrierefreiheit angezogen. Auf der Suche nach Ratschlag stieß ich auf Aaron Leventhal, dessen Fachwissen und Hilfsbereitschaft mich dazu inspirierten, mit ihm ein Projekt zu starten. Diese Zusammenarbeit wurde zu meinem Google Summer of Code-Erlebnis, bei dem ich die Möglichkeit erhielt, mit dem Chromium-Team für Barrierefreiheit zusammenzuarbeiten.
Nachdem ich das Google Summer of Code erfolgreich abgeschlossen hatte, arbeitete ich weiter an einem nicht gelösten Scrollproblem, um die Leistung zu verbessern. Dank zweier Zuschüsse aus dem OpenCollective-Programm von Google konnte ich weiter an diesem Projekt arbeiten und gleichzeitig zusätzliche Aufgaben übernehmen, die sich auf die Optimierung des Codes für eine bessere Leistung konzentrierten.
In diesem Blogpost berichte ich über meine Erfahrungen mit Chromium in den letzten anderthalb Jahren und erläutere die technischen Verbesserungen, die wir insbesondere im Bereich der Leistung erzielt haben.
Auswirkungen von Code für Bedienungshilfen auf die Leistung in Chrome
Der Code für die Barrierefreiheit in Chrome hilft Hilfstechnologien wie Screenreadern, auf das Web zuzugreifen. Wenn sie aktiviert ist, kann sich das jedoch auf die Ladezeiten, die Leistung und die Akkulaufzeit auswirken. Wenn er nicht benötigt wird, bleibt er inaktiv, um die Leistung nicht zu beeinträchtigen. Bei etwa 5–10% der Nutzer ist Code für Bedienungshilfen aktiviert, oft aufgrund von Tools wie Passwortmanagern und Antivirensoftware, die APIs für die Bedienungshilfen der Plattform verwenden. Diese Tools nutzen diese APIs, um mit Seiteninhalten zu interagieren und sie zu ändern, z. B. um Passwortfelder für Passwortmanager und Formularausfüller zu finden.
Die Gesamtverschlechterung der wichtigsten Messwerte ist noch nicht bekannt. Ein aktueller Test mit der Funktion „Auto Disable Accessibility“ (automatische Deaktivierung der Barrierefreiheit, wenn sie nicht verwendet wird) hat jedoch gezeigt, dass sie ziemlich hoch ist. Das Problem wird durch die enorme Menge an Berechnungen und Kommunikation in zwei Hauptbereichen der Chrome-Codebase für Barrierefreiheit verursacht: dem Renderer und dem Browser. Der Renderer sammelt Informationen zu Webinhalten und Änderungen an Inhalten und berechnet die Barrierefreiheitseigenschaften für einen Knotenbaum. Alle geänderten Knoten werden dann serialisiert und über eine Pipe an den UI-Haupt-Thread des Browserprozesses gesendet. Dieser Thread empfängt und deserialisiert diese Informationen in denselben Knotenbaum und konvertiert sie dann in ein geeignetes Format für Hilfstechnologien von Drittanbietern wie Screenreader.
Verbesserte Bedienungshilfen in Chromium
Die folgenden Projekte wurden während des Summer of Code abgeschlossen und danach durch das OpenCollective-Programm von Google finanziert.
Cache-Verbesserung
In Chrome gibt es eine spezielle Datenstruktur namens Zugänglichkeitsbaum, die dem DOM-Baum entspricht. Sie wird verwendet, um Hilfstechnologien den Zugriff auf Webinhalte zu ermöglichen. Wenn ein Gerät Informationen aus diesem Baum benötigt, sind diese manchmal noch nicht verfügbar. In diesem Fall muss der Browser diese Anfragen für später planen.
Bisher wurde diese Planung mit einer Methode namens „Closures“ durchgeführt, bei der Callbacks in eine Warteschlange gestellt wurden. Dieser Ansatz erforderte zusätzlichen Aufwand, da die Schließungen auf eine bestimmte Weise verarbeitet werden.
Um dies zu verbessern, haben wir zu einem System mit Enumerationen gewechselt. Jede Aufgabe wird einem bestimmten Enum-Wert zugewiesen. Sobald der Baum für die Barrierefreiheit fertig ist, wird die richtige Methode für diese Aufgabe aufgerufen. Durch diese Änderung wurde der Code verständlicher und die Leistung um über 20% verbessert.
Probleme mit der Scrollleistung finden und beheben
Als Nächstes habe ich untersucht, wie sich die Leistung verbessert, wenn die Bounding-Box-Sereialisierung deaktiviert wird. Begrenzungsrahmen sind die Positionen und Größen von Elementen auf einer Webseite, einschließlich Details wie Breite, Höhe und Position relativ zum übergeordneten Element.
Um das zu testen, haben wir den Code, der die Begrenzungsboxen verarbeitet, vorübergehend entfernt und Leistungstests durchgeführt, um die Auswirkungen zu sehen. Bei einem Test, focus-links.html, wurde eine enorme Verbesserung von etwa 1.618 % erzielt. Diese Erkenntnis bildete die Grundlage für weitere Arbeit.
Langsamen Test untersuchen
Ich habe angefangen zu untersuchen, warum dieser bestimmte Test mit Begrenzungsboxen langsam war. Beim Test wurde der Fokus nur nacheinander auf mehrere Links gelegt. Das Hauptproblem muss also entweder das Fokussieren von Elementen oder das Scrollen sein, das durch die Fokusaktion ausgelöst wurde. Um das zu testen, habe ich dem focus()
-Aufruf im Leistungstest {preventScroll: true}
hinzugefügt, um das Scrollen zu beenden.
Wenn das Scrollen deaktiviert war, sank die Testzeit bei aktiven Begrenzungsfeldberechnungen auf 1,2 Millisekunden. Das zeigte, dass das Scrollen das eigentliche Problem war.
Ich habe einen neuen Test namens scroll-in-page.html erstellt, um den Test focus-links zu replizieren. Statt den Fokus zu verwenden, wird hier mit scrollIntoView()
durch die Elemente gescrollt. Ich habe sowohl das flüssige als auch das sofortige Scrollen mit und ohne Begrenzungsbox-Berechnungen getestet.
Die Ergebnisse zeigten, dass der Vorgang mit dem sofortigen Scrollen und den Begrenzungsrahmen etwa 66 Millisekunden dauerte. Das optimierte Scrollen war mit etwa 124 ms sogar noch langsamer. Nachdem wir die Begrenzungsboxen deaktiviert hatten, ging es ganz schnell, da keine Ereignisse ausgelöst wurden.
Wir wussten, was passiert war, aber warum?
Wir wussten jetzt, dass das Scrollen die Ursache für die große Verzögerung bei der Serialisierung der Barrierefreiheit ist, aber wir mussten noch herausfinden, warum. Dazu wurden die beiden Tools perf und pprof verwendet, um die Arbeit im Browserprozess aufzuschlüsseln. Diese Tools werden häufig in C++ für das Profiling verwendet. Die folgenden Grafiken zeigen einen Ausschnitt des interessanten Teils.
Bei der Untersuchung haben wir festgestellt, dass das Problem nicht am Deserialisierungscode selbst, sondern an der Häufigkeit der Aufrufe lag. Um das zu verstehen, müssen wir uns ansehen, wie Updates für die Barrierefreiheit in Chromium funktionieren. Updates werden nicht einzeln gesendet. Stattdessen gibt es einen zentralen Speicherort namens AXObjectCache
, an dem alle Unterkünfte gespeichert werden. Wenn sich ein Knoten ändert, benachrichtigen verschiedene Methoden den Cache, um diesen Knoten für die spätere Serialization als schmutzig zu kennzeichnen. Anschließend werden alle Eigenschaften der geänderten Notizen, einschließlich unveränderter Eigenschaften, serialisiert und an den Browser gesendet. Dieses Design vereinfacht den Code und reduziert die Komplexität durch einen einzigen Aktualisierungspfad. Es wird jedoch langsam, wenn es viele „als schmutzig markieren“-Ereignisse gibt, z. B. durch Scrollen. Lediglich die Werte für scrollX
und scrollY
ändern sich. Trotzdem werden die restlichen Properties jedes Mal mit ihnen serialisiert. Die Aktualisierungsrate erreichte hier über 20 Mal pro Sekunde.
Bei der Bounding-Box-Sereialisierung wird dieses Problem durch einen schnelleren Serialization-Pfad behoben, über den nur die Details der Bounding-Box gesendet werden. So sind schnelle Aktualisierungen möglich, ohne dass andere Properties beeinträchtigt werden. Mit dieser Methode werden Änderungen am Begrenzungsrahmen effizient verarbeitet.
Problem beim Scrollen behoben
Die Lösung war klar: Fügen Sie die aktuellen Scroll-Offsets in die Bounding-Box-Sereialisierung ein. So werden Aktualisierungen beim Scrollen über den schnellen Pfad verarbeitet, was die Leistung ohne unnötige Verzögerungen verbessert. Durch das Packen von Scroll-Offset-Werten mit Begrenzungsbox-Daten optimieren wir den Prozess für reibungslosere und effizientere Aktualisierungen. Das sorgt für eine weniger ruckelige Darstellung für Nutzer, die die Barrierefreiheit aktiviert haben. Nach der Implementierung der Fehlerbehebung konnte in Scrolltests eine Verbesserung von bis zu 825% erzielt werden.
Codevereinfachungen
In dieser Zeit habe ich mich im Rahmen eines Projekts namens Onion Soup auf die Codequalität konzentriert. Dabei wird der Code vereinfacht, indem Code, der unnötig über mehrere Schichten verteilt ist, reduziert oder entfernt wird.
Das erste Projekt zielte darauf ab, die Serialisierung von Bedienungshilfendaten vom Renderer an den Browser zu optimieren. Bisher mussten die Daten eine zusätzliche Schicht durchlaufen, bevor sie ihr Ziel erreichten. Das hat die Komplexität unnötig erhöht. Wir haben diesen Vorgang vereinfacht, indem wir die Daten direkt senden und den Zwischenhändler weglassen.
Außerdem haben wir einige veraltete Ereignisse identifiziert und entfernt, die unnötige Arbeit im System verursacht haben, z. B. ein Ereignis, das ausgelöst wurde, wenn ein Layout fertig war. Wir haben sie durch eine effizientere Lösung ersetzt.
Außerdem wurden weitere kleinere Verbesserungen vorgenommen. Leider konnten wir hier keine Leistungsverbesserungen feststellen. Wir sind aber stolz darauf, dass der Code jetzt viel verständlicher und selbstdokumentierender ist. So können wir die Leistung in Zukunft weiter verbessern. Die tatsächlichen Änderungen finden Sie in meinem Gerrit-Profil.
Fazit
Die Zusammenarbeit mit dem Chromium-Team für Barrierefreiheit war eine lohnende Erfahrung. Durch die Bewältigung verschiedener Herausforderungen, von der Optimierung der Scrollleistung bis hin zur Vereinfachung der Codebasis, habe ich ein tieferes Verständnis für die Entwicklung in einem so großen Projekt gewonnen und wichtige Tools für das Profiling kennengelernt. Außerdem habe ich gelernt, wie wichtig Barrierefreiheit für die Schaffung eines Webs ist, das für alle inklusiv ist. Die Verbesserungen, die wir vorgenommen haben, verbessern nicht nur die Nutzerfreundlichkeit für Nutzer, die auf Hilfstechnologien angewiesen sind, sondern tragen auch zur allgemeinen Leistung und Effizienz des Browsers bei.
Die Leistungsergebnisse waren beeindruckend. Durch die Umstellung auf Enums für die Aufgabenplanung konnte die Leistung beispielsweise um über 20% gesteigert werden. Außerdem führte unsere Scroll-Korrektur zu einer Verringerung der Scrolltests um bis zu 825%. Durch die Vereinfachung des Codes wurde er nicht nur übersichtlicher und wartungsfreundlicher, sondern es wurde auch der Weg für zukünftige Verbesserungen geebnet.
Ich möchte mich bei Stefan Zager, Chris Harrelson und Mason freed für ihre Unterstützung und Anleitung während des ganzen Jahres bedanken, insbesondere bei Aaron Leventhal, ohne den diese Chance nicht möglich gewesen wäre. Ich möchte mich auch bei Tab Atkins-Bittner und dem GSoC-Team für ihre Unterstützung bedanken.
Wenn Sie an einem sinnvollen Projekt mitwirken und Ihre Fähigkeiten weiterentwickeln möchten, kann ich Ihnen Chromium nur wärmstens empfehlen. Das ist eine gute Möglichkeit, sich weiterzubilden. Programme wie Google Summer of Code sind ein hervorragender Ausgangspunkt für Ihren Einstieg.