Bisherige Entwicklung
Vor einem Jahr wurde in Chrome die erste Unterstützung angekündigt für natives WebAssembly-Debugging in den Chrome-Entwicklertools.
Wir haben die Unterstützung für grundlegende Stufen demonstriert und über die Möglichkeiten gesprochen, die sich durch die Verwendung von DWARF-Informationen anstelle von Quellkarten in Zukunft ergeben:
- Variablennamen auflösen
- Quelltextformatierungen
- Ausdrücke in den Ausgangssprachen auswerten
- ...und vieles mehr!
Heute möchten wir zeigen, wie die versprochenen Funktionen und die Fortschritte der Emscripten- und Chrome DevTools-Teams insbesondere für C- und C++-Apps.
Bevor wir beginnen, möchten wir Sie darauf hinweisen, dass dies noch eine Betaversion der neuen Version ist. Die Verwendung der neuesten Version aller Tools erfolgt auf eigenes Risiko. Sollten Probleme auftreten, melden Sie sie bitte unter https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.
Beginnen wir mit demselben einfachen C-Beispiel wie beim letzten Mal:
#include <stdlib.h>
void assert_less(int x, int y) {
if (x >= y) {
abort();
}
}
int main() {
assert_less(10, 20);
assert_less(30, 20);
}
Zur Kompilierung verwenden wir die neueste Emscripten-Version.
und übergeben Sie wie im ursprünglichen Beitrag ein -g
-Flag, um
Informationen:
emcc -g temp.c -o temp.html
Jetzt können wir die generierte Seite von einem lokalen HTTP-Server aus bereitstellen (z. B. mit serve) und sie in der neuesten Version von Chrome Canary öffnen.
Dieses Mal benötigen wir auch eine Hilfserweiterung, die in die Chrome DevTools eingebunden ist und dabei hilft, alle in der WebAssembly-Datei codierten Informationen zur Fehlerbehebung zu verstehen. Sie können sie unter goo.gle/wasm-debugging-extension installieren.
Außerdem müssen Sie das WebAssembly-Debugging in den DevTools unter Experiments aktivieren. Öffnen Sie die Chrome-Entwicklertools, klicken Sie in der Symbolleiste auf das Zahnradsymbol (⚙) Gehen Sie rechts oben im Bereich „Entwicklertools“ zum Bereich Tests. und wählen Sie WebAssembly Debugging: Enable DWARF support (WebAssembly-Debugging: DWARF-Unterstützung aktivieren) aus.
Wenn Sie die Einstellungen schließen, werden Sie von den Entwicklertools aufgefordert, sie neu zu laden, um die Einstellungen anzuwenden. Tun wir das. Das war's für die einmalige einrichten.
Jetzt können wir zum Bereich Quellen zurückkehren, Bei Ausnahmen pausieren (Symbol ⏸) aktivieren, dann Bei erkannten Ausnahmen pausieren auswählen und die Seite neu laden. Die Entwicklertools sollten bei einer Ausnahme pausiert sein:
Standardmäßig wird bei einem von Emscripten generierten Glue-Code angehalten. Rechts sehen Sie jedoch eine Aufrufabfolge, die den Stacktrace des Fehlers darstellt. Sie können auch zur ursprünglichen C-Zeile wechseln, die abort
aufgerufen hat:
In der Ansicht Umfang sehen Sie jetzt die ursprünglichen Namen,
und Werte von Variablen im C/C++-Code und müssen nicht mehr
findest du heraus, was fehlerhafte Namen wie $localN
bedeuten und wie sie mit dem
Quellcodes, den Sie geschrieben haben.
Dies gilt nicht nur für primitive Werte wie Ganzzahlen, sondern auch für Typen wie Strukturen, Klassen, Arrays usw. anwenden.
Rich-Type-Unterstützung
Sehen wir uns dazu ein etwas komplizierteres Beispiel an. Dieses Mal zeichnen wir mit dem folgenden C++-Code ein Mandelbrot-Fraktal:
#include <SDL2/SDL.h>
#include <complex>
int main() {
// Init SDL.
int width = 600, height = 600;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window;
SDL_Renderer* renderer;
SDL_CreateWindowAndRenderer(width, height, SDL_WINDOW_OPENGL, &window,
&renderer);
// Generate a palette with random colors.
enum { MAX_ITER_COUNT = 256 };
SDL_Color palette[MAX_ITER_COUNT];
srand(time(0));
for (int i = 0; i < MAX_ITER_COUNT; ++i) {
palette[i] = {
.r = (uint8_t)rand(),
.g = (uint8_t)rand(),
.b = (uint8_t)rand(),
.a = 255,
};
}
// Calculate and draw the Mandelbrot set.
std::complex<double> center(0.5, 0.5);
double scale = 4.0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
std::complex<double> point((double)x / width, (double)y / height);
std::complex<double> c = (point - center) * scale;
std::complex<double> z(0, 0);
int i = 0;
for (; i < MAX_ITER_COUNT - 1; i++) {
z = z * z + c;
if (abs(z) > 2.0)
break;
}
SDL_Color color = palette[i];
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
SDL_RenderDrawPoint(renderer, x, y);
}
}
// Render everything we've drawn to the canvas.
SDL_RenderPresent(renderer);
// SDL_Quit();
}
Wie Sie sehen, ist diese Anwendung noch ziemlich klein – es ist eine einzelne Datei mit 50 Codezeilen. Dieses Mal verwende ich jedoch auch einige externe APIs, z. B. die SDL-Bibliothek für Grafiken sowie komplexe Zahlen aus der C++-Standardbibliothek.
Ich werde sie mit demselben -g
-Flag wie oben kompilieren,
und bitte Emscripten, die SDL2-Datei
und Arbeitsspeicher mit beliebiger Größe zulassen:
emcc -g mandelbrot.cc -o mandelbrot.html \ -s USE_SDL=2 \ -s ALLOW_MEMORY_GROWTH=1
Wenn ich die generierte Seite im Browser aufrufe, sehe ich die schöne Fraktalform mit einigen zufälligen Farben:
Wenn ich die Entwicklertools wieder öffne, sehe ich die ursprüngliche C++-Datei. Dieses Allerdings haben wir keinen Fehler im Code (Puh!), also legen wir einen Haltepunkt am Anfang des Codes.
Wenn wir die Seite noch einmal neu laden, wird der Debugger direkt in unserer C++-Quelldatei angehalten:
Auf der rechten Seite sind bereits alle Variablen zu sehen, aber nur width
und height
sind derzeit initialisiert, es kann also nicht viel
prüfen.
Setzen wir einen weiteren Haltepunkt in unserer Mandelbrot-Hauptschleife und setzen um ein bisschen weiterzuspringen.
Wir haben palette
mit zufälligen Farben gefüllt,
Wir können sowohl das Array selbst
als auch die einzelnen Elemente erweitern,
SDL_Color
strukturiert und ihre Komponenten auf
alles in Ordnung ist (z. B. ist der Kanal "Alpha" immer
volle Deckkraft). Ebenso können wir den reellen und imaginären Teil der komplexen Zahl, die in der Variablen center
gespeichert ist, ausweiten und prüfen.
Wenn Sie auf eine tief verschachtelte Eigenschaft zugreifen möchten, die ansonsten schwer zu Rufen Sie über die Ansicht Scope (Umfang) auf. Sie können die Console verwenden. Bewertung ab. Beachten Sie jedoch, dass komplexere C++-Ausdrücke keine unterstützt.
Wir setzen die Ausführung einige Male fort, um zu sehen, wie die innere x
indem Sie erneut in der Ansicht Umfang
der Beobachtungsliste hinzufügen, in der Konsole auswerten
Bewegen Sie den Mauszeiger auf die Variable im Quellcode:
Hier können wir C++-Anweisungen Schritt für Schritt ausführen und beobachten, wie sich auch andere Variablen ändern:
Okay, das funktioniert also hervorragend, wenn Debug-Informationen verfügbar sind. Was aber, wenn wir Code debuggen möchten, der nicht mit den Debugging-Optionen erstellt wurde?
Rohes WebAssembly-Debugging
Wir haben Emscripten beispielsweise gebeten, eine vorkonfigurierte SDL-Bibliothek für uns bereitzustellen, anstatt sie selbst aus der Quelle zu kompilieren. Daher kann der Debugger zumindest derzeit keine zugehörigen Quellen finden.
Lassen Sie uns noch einmal einsteigen, um in den SDL_RenderDrawColor
einzusteigen:
Wir sind wieder beim reinen WebAssembly-Debugging.
Es sieht jetzt etwas beängstigend aus und ist für die meisten Webentwickler nicht relevant. mit denen Sie sich befassen müssen, aber gelegentlich möchten Sie Fehler ohne Informationen zur Fehlerbehebung erstellt wurde – Drittanbieter-Bibliothek, die Sie nicht steuern können, oder weil Sie auf einen dieser Fehler stößt, der nur in der Produktion auftritt.
Um dies zu unterstützen, haben wir einige Verbesserungen an der grundlegenden auch für die Fehlerbehebung.
Wenn Sie zuvor unformatiertes WebAssembly-Debugging verwendet haben,
die gesamte Demontage in einer einzigen Datei
Sie sollten genauer wissen, welcher Funktion ein Sources-Eintrag wasm-53834e3e/
wasm-53834e3e-7
zugeordnet werden kann.
Neues Schema zur Namensgenerierung
Außerdem wurden die Namen in der Demontageansicht verbessert. Bisher wurden diese nur numerische Indizes oder, im Fall von Funktionen, überhaupt keinen Namen.
Jetzt generieren wir Namen ähnlich wie bei anderen Deaktivierungstools. Dazu verwenden wir Hinweise aus dem WebAssembly-Namensabschnitt, Import-/Exportpfade und, wenn alles andere fehlschlägt, generieren wir sie basierend auf dem Typ und dem Index des Elements wie $func123
. Sie können
Wie im Screenshot oben gezeigt,
Stacktraces und deren
Demontage besser lesbar sind.
Wenn keine Typinformationen verfügbar sind, ist der Zugriff möglicherweise schwierig. alle Werte außer den Primitiven, z. B. werden Zeiger angezeigt, als reguläre Ganzzahlen dargestellt, ohne zu wissen, was sich hinter ihnen zu speichern.
Arbeitsspeicherprüfung
Bisher konnten Sie das WebAssembly-Speicherobjekt, das in der Ansicht Umfang durch env.memory
dargestellt wird, nur maximieren, um einzelne Bytes abzurufen. Das funktionierte in einigen einfachen Szenarien, war aber nicht besonders praktisch zu erweitern und erlaubte nicht, Daten in anderen Formaten als Bytewerten neu zu interpretieren. Dazu haben wir eine neue Funktion hinzugefügt: einen linearen Speicherprüfer.
Wenn Sie mit der rechten Maustaste auf das env.memory
klicken, sollte jetzt eine neue
mit der Option Arbeitsspeicher prüfen:
Daraufhin wird der Memory Inspector Sie können den WebAssembly-Arbeitsspeicher in Hexadezimal- und ASCII-Ansichten zu bestimmten Adressen navigieren und die Daten in verschiedene Formate verwenden:
Erweiterte Szenarien und Einschränkungen
Profilerstellung für WebAssembly-Code
Wenn Sie die Entwicklertools öffnen, wird WebAssembly-Code in eine nicht optimierte Version heruntergestuft, um das Debuggen zu ermöglichen. Diese Version ist viel langsamer,
Das bedeutet, dass Sie sich nicht auf console.time
, performance.now
und andere Methoden zur Messung
der Codegeschwindigkeit, während die Entwicklertools
da die angezeigten Zahlen nicht die tatsächliche Leistung
überhaupt nicht.
Verwenden Sie stattdessen in den Entwicklertools das Steuerfeld „Leistung“. Dadurch wird der Code mit voller Geschwindigkeit ausgeführt und Sie erhalten eine Eine detaillierte Aufschlüsselung der für die verschiedenen Funktionen aufgewendeten Zeit:
Alternativ können Sie Ihre Anwendung mit geschlossenen Entwicklertools ausführen und Wenn Sie fertig sind, öffnen Sie sie, um die Console zu überprüfen.
Wir werden die Profiling-Szenarien in Zukunft verbessern, aber derzeit ist dies ein wichtiger Hinweis. Weitere Informationen zu WebAssembly-Tiering-Szenarien finden Sie in unserer Dokumentation zur WebAssembly-Kompilierungspipeline.
Builds und Debugging auf verschiedenen Maschinen (einschließlich Docker/Host)
Wenn Sie in einer Docker-Umgebung, auf einer virtuellen Maschine oder auf einem Remote-Build-Server erstellen, kommt es wahrscheinlich vor, dass die Pfade zu den Quelldateien, die während des Builds verwendet werden, nicht mit den Pfaden in Ihrem eigenen Dateisystem übereinstimmen, in dem die Chrome DevTools ausgeführt werden. In diesem Fall werden Dateien im Bereich Quellen angezeigt, aber nicht geladen.
Um dieses Problem zu beheben, haben wir eine Pfadzuordnungsfunktion Erweiterungsoptionen für C/C++. Sie können damit beliebige Pfade neu zuordnen und damit die Entwicklertools Quellen leichter finden können.
Wenn sich das Projekt auf Ihrem Hostcomputer beispielsweise unter dem Pfad C:\src\my_project
befindet, aber in einem Docker-Container erstellt wurde, in dem dieser Pfad als /mnt/c/src/my_project
dargestellt wurde, können Sie ihn beim Debuggen neu zuordnen, indem Sie diese Pfade als Präfixe angeben:
Das erste übereinstimmende Präfix „gewinnt“. Wenn Sie mit anderen C++-
Debugger erstellt haben, ähnelt diese Option dem Befehl set substitute-path
in GDB oder eine target.source-map
-Einstellung in LLDB.
Optimierte Builds beheben
Wie bei allen anderen Sprachen funktioniert das Debugging am besten, wenn die Optimierungen deaktiviert. Durch Optimierungen können Funktionen inline angeordnet oder neu angeordnet werden. oder Teile des Codes ganz entfernen. den Debugger und folglich Sie als Nutzer zu verwirren.
Wenn Ihnen eine eingeschränkte Debugging-Funktion nichts ausmacht,
einen optimierten Build zu beheben, funktionieren die meisten Optimierungen
mit Ausnahme der Inline-Funktion für die Funktion. Wir haben vor, die verbleibenden
in Zukunft zu beheben. Verwenden Sie für den Moment -fno-inline
,
bei der Kompilierung mit Optimierungen auf -O
-Ebene deaktivieren, z.B.:
emcc -g temp.c -o temp.html \ -O3 -fno-inline
Debug-Informationen trennen
In den Debug-Informationen werden viele Details zu Ihrem Code, zu definierten Typen, Variablen, Funktionen, Bereichen und Speicherorten gespeichert – alles, was für den Debugger nützlich sein könnte. Daher kann sie häufig größer sein als die Code selbst.
Um das Laden und Kompilieren des WebAssembly-Moduls zu beschleunigen,
diese Debug-Informationen in eine separate WebAssembly-
-Datei. Dazu übergeben Sie in Emscripten ein -gseparate-dwarf=…
-Flag mit
einen gewünschten Dateinamen:
emcc -g temp.c -o temp.html \ -gseparate-dwarf=temp.debug.wasm
In diesem Fall speichert die Hauptanwendung nur einen Dateinamen temp.debug.wasm
. Die Hilfserweiterung kann ihn finden und laden, wenn Sie die DevTools öffnen.
In Kombination mit den oben beschriebenen Optimierungen kann diese Funktion können sogar fast optimierte Produktions-Builds und später mit einer lokalen Side-Datei debuggen. In diesem Fall Außerdem müssen wir die gespeicherte URL überschreiben, damit die Erweiterung die Nebendatei suchen, zum Beispiel:
emcc -g temp.c -o temp.html \ -O3 -fno-inline \ -gseparate-dwarf=temp.debug.wasm \ -s SEPARATE_DWARF_URL=file://[local path to temp.debug.wasm]
Wird fortgesetzt...
Wow, das waren viele neue Funktionen!
Mit all diesen neuen Integrationen werden die Chrome-Entwicklertools zu einem leistungsstarken Debugger, der nicht nur für JavaScript, sondern auch für C- und C++-Apps geeignet ist. So können Apps, die mit einer Vielzahl von Technologien erstellt wurden, einfacher denn je in ein gemeinsames, plattformübergreifendes Web übertragen werden.
Unsere Reise ist jedoch noch nicht vorbei. Einige der Dinge, von hier an arbeiten:
- Die Grenzen der Debugging-Funktion säubern.
- Benutzerdefinierte Typformatierer werden jetzt unterstützt.
- Wir arbeiten an Verbesserungen des Profilings für WebAssembly-Apps.
- Codeabdeckung wird unterstützt, um die Suche zu erleichtern nicht verwendetem Code.
- Verbesserte Unterstützung von Ausdrücken bei der Konsolenerstellung.
- Weitere Sprachen werden unterstützt.
- und weitere!
In der Zwischenzeit können Sie die aktuelle Betaversion mit Ihrem eigenen Code testen und alle gefundenen Probleme unter https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350 melden.
Vorschaukanäle herunterladen
Sie können Canary, Dev oder Beta als Standardbrowser für die Entwicklung verwenden. Diese Vorschaukanäle bieten Ihnen Zugriff auf die neuesten DevTools-Funktionen, die Möglichkeit, innovative Webplattform-APIs zu testen, und die Möglichkeit, Probleme auf Ihrer Website zu finden, bevor Ihre Nutzer sie sehen.
Chrome-Entwicklertools-Team kontaktieren
Mit den folgenden Optionen können Sie über die neuen Funktionen und Änderungen im Beitrag oder über andere Themen im Zusammenhang mit den Entwicklertools diskutieren.
- Senden Sie uns über crbug.com einen Vorschlag oder Feedback.
- Problem mit den Entwicklertools über Weitere Optionen melden > Hilfe > Hier kannst du Probleme mit den Entwicklertools in den Entwicklertools melden.
- Tweeten Sie an @ChromeDevTools.
- Hinterlasse Kommentare in den YouTube-Videos zu Neuerungen bei den Entwicklertools oder in den YouTube-Videos mit Tipps zu Entwicklertools.