Droga do tej pory
Rok temu ogłosiliśmy wprowadzenie pomocy w Chrome do natywnego debugowania WebAssembly w Narzędziach deweloperskich w Chrome.
Zademonstrowaliśmy podstawowe wsparcie i rozmawialiśmy o możliwościach użycie informacji DWARF zamiast mapy źródłowe otworzy się w przyszłości:
- Rozpoznawanie nazw zmiennych
- Rodzaje druku estetycznego
- Obliczanie wyrażeń w językach źródłowych
- …i wiele innych.
Z przyjemnością przedstawiamy, w jaki sposób weszły w życie obiecane funkcje oraz postęp, jaki zespoły Emscripten i Chrome Dev Tools osiągnęły w tym roku, zwłaszcza w przypadku aplikacji w języku C i C++.
Zanim zaczniemy, miej na uwadze, że jest to nadal wersja beta musisz używać najnowszych wersji wszystkich narzędzi, na własne ryzyko. W razie jakichkolwiek problemów zgłoś je do https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.
Zacznijmy od tego samego prostego przykładu w języku C, co ostatnio:
#include <stdlib.h>
void assert_less(int x, int y) {
if (x >= y) {
abort();
}
}
int main() {
assert_less(10, 20);
assert_less(30, 20);
}
Do skompilowania używamy najnowszej wersji Emscripten i przekazujemy flagę -g
, tak jak w pierwotnym poście, aby uwzględnić informacje debugowania:
emcc -g temp.c -o temp.html
Teraz możemy wyświetlić stronę wygenerowaną z serwera HTTP hosta lokalnego (dla np. obsługa), otwórz ją w najnowszej wersji Chrome Canary.
Tym razem potrzebne będzie rozszerzenie pomocnicze, które integruje się z Chrome. Narzędzia deweloperskie i pomagają w interpretowaniu wszystkich informacji na potrzeby debugowania. zakodowane w pliku WebAssembly. Zainstaluj ją, przechodząc pod ten Link: goo.gle/wasm-debugging-extension
W DevTools możesz też włączyć debugowanie WebAssembly w sekcji Eksperymenty. Otwórz Narzędzia deweloperskie w Chrome i kliknij ikonę koła zębatego (⚙) w w prawym górnym rogu panelu Narzędzia deweloperskie otwórz panel Eksperymenty. i zaznacz WebAssembly Debugging: Włącz obsługę DWARF.
Gdy zamkniesz Ustawienia, Narzędzia deweloperskie zasugerują ponowne załadowanie strony. aby zastosować ustawienia, więc zróbmy to tak. To by było na tyle, jeśli chodzi o jednorazowe wydarzenie konfiguracji.
Teraz wróćmy do panelu Źródła, włącz opcję Wstrzymaj wyjątki (ikona ⏸), a następnie zaznacz opcję Wstrzymaj przy wykrytych wyjątkach i odśwież stronę. Narzędzia deweloperskie powinny być wstrzymane przy wyjątku:
Domyślnie zatrzymuje się on na kodzie kleju wygenerowanym przez Emscripten, ale na stronie
zobaczysz widok Stosunek wywołań, który przedstawia zrzut stosu
i może przejść do oryginalnego wiersza C, który wywołał
abort
:
Teraz w widoku Zakres zobaczysz oryginalne nazwy
i wartości zmiennych w kodzie C/C++, dzięki czemu nie trzeba
co oznaczają zniekształcone nazwy, takie jak $localN
, i jaki mają związek z
napisany przez Ciebie kod źródłowy.
Dotyczy to nie tylko wartości podstawowych, takich jak liczby całkowite, np. struktury, klasy, tablice itp.
Obsługa typów rozszerzonych
Spójrzmy na bardziej skomplikowany przykład. Ten narysujemy fraktal Mandelbrota z ten kod w C++:
#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();
}
Jak widać, aplikacja jest nadal dość mała – to pojedynczy plik zawierający 50 wierszy kodu. Tym razem używam też niektórych zewnętrznych interfejsów API, takich jak bibliotek SDL do grafiki oraz liczbami zespolonymi z biblioteki standardowej C++.
Skompiluję go z tą samą flagą -g
co powyżej, aby uwzględnić
debugowania. Poproszę też Emscripten o przesłanie pliku SDL2
pozwalająca korzystać z pamięci o dowolnym rozmiarze:
emcc -g mandelbrot.cc -o mandelbrot.html \ -s USE_SDL=2 \ -s ALLOW_MEMORY_GROWTH=1
Gdy wchodzę na wygenerowaną stronę w przeglądarce, widzę fraktalny kształt o losowych kolorach:
Po otwarciu Narzędzi deweloperskich ponownie widzę oryginalny plik C++. Ten ale w kodzie nie ma błędu (ale!), więc na początku kodu.
Po ponownym załadowaniu strony debuger zatrzyma się Kod źródłowy w języku C++:
Wszystkie zmienne są już widoczne po prawej stronie, ale tylko width
i height
są w tej chwili zainicjowane, więc nie ma za wiele do zrobienia
sprawdzić.
Ustawmy kolejny punkt przerwania w głównej pętli Mandelbrota i wznowimy aby przewinąć film do przodu.
Na tym etapie pole palette
zostało wypełnione losowymi kolorami,
i możemy rozszerzyć zarówno samą tablicę, jak i pojedynczą
SDL_Color
i sprawdź ich komponenty, aby sprawdzić,
wszystko wygląda dobrze (np. kanał alfa jest zawsze ustawiony,
do pełnej nieprzezroczystości). Możemy również rozwijać i sprawdzać rzeczywiste
urojone części liczby zespolonej przechowywane w zmiennej center
.
Jeśli chcesz uzyskać dostęp do głęboko zagnieżdżonej właściwości, która jest trudna do użycia w innym miejscu przejdź przez widok Zakres, możesz użyć Konsoli. także jego ocenę. Pamiętaj jednak, że bardziej złożone wyrażenia w języku C++ nie są jeszcze obsługiwane.
Wznówmy wykonanie kilka razy, aby zobaczyć, jak działa wewnętrzna strona x
możesz zmienić, patrząc ponownie w widoku Zakres, dodając
nazwę zmiennej do listy obserwacyjnej, oceny jej w konsoli lub
najedź kursorem na zmienną w kodzie źródłowym.
Następnie możemy dodać stwierdzenia w języku C++ i zobaczyć, jak inne zmienne również się zmieniają:
Wszystko działa świetnie, gdy dostępne są informacje debugowania, ale co, jeśli chcemy debugować kod, który nie został skompilowany z opcjami debugowania?
Debugowanie nieprzetworzonego zasobu WebAssembly
Na przykład poprosiliśmy Emscripten o udostępnienie gotowej biblioteki SDL do
zamiast kompilować sami na podstawie źródła,
obecnie debuger nie może znaleźć powiązanych źródeł.
Aby dowiedzieć się więcej o SDL_RenderDrawColor
, zapoznaj się z tymi informacjami:
Wracamy do nieprzetworzonego interfejsu debugowania WebAssembly.
Teraz wygląda to trochę strasznie, a większość programistów stron internetowych nie ale od czasu do czasu warto biblioteka utworzona bez danych debugowania. Zewnętrzna biblioteka, nad którą nie masz kontroli lub dlatego, że na któryś z błędów, które pojawiają się tylko w wersji produkcyjnej.
Aby im w tym pomóc, wprowadziliśmy kilka ulepszeń debugowania.
Jeśli już wcześniej zdarzyło Ci się korzystać
z debugowania nieprzetworzonego WebAssembly,
że cała demontaż jest teraz przedstawiony w jednym pliku
bardziej zgadywanie, której funkcji prawdopodobnie odpowiada wpis Źródła wasm-53834e3e/
wasm-53834e3e-7
.
Nowy schemat generowania nazw
Poprawiliśmy też nazwy w widoku rozłożenia. Poprzednio tylko indeksy liczbowe, a w przypadku funkcji – brak nazwy.
Teraz generujemy nazwy podobne do innych narzędzi do demontażu,
korzystając ze wskazówek z sekcji nazwy WebAssembly,
importowanie/eksportowanie i, jeśli wszystko inne zawiodło, generowanie
na podstawie typu i indeksu elementu takiego jak $func123
. Dostępne opcje
Na zrzucie ekranu powyżej pozwala to uzyskać nieco
czytelniejsze schematy
i demontaż.
Gdy informacje o typie są niedostępne, ich sprawdzenie może być trudne wartości inne niż podstawowe – na przykład wskaźniki pojawią się jako zwykłe liczby całkowite, bez możliwości sprawdzenia, co za nimi jest pamięci.
Sprawdzenie pamięci
Wcześniej można było rozwinąć tylko obiekt pamięci WebAssembly, reprezentowany przez env.memory
w widoku Zakres, aby wyszukać poszczególne bajty. Sprawdzało się to w kilku prostych sytuacjach, ale nie było
co jest szczególnie wygodne i nie pozwala na ponowną interpretację danych,
w formatach innych niż bajty. Dodaliśmy też nową funkcję, która pomoże Ci w tym zakresie: inspektor pamięci liniowej.
Po kliknięciu env.memory
prawym przyciskiem myszy powinien być widoczny nowy
opcja Sprawdź pamięć:
Po kliknięciu otworzy się Inspektor pamięci, który można sprawdzić pamięć WebAssembly w widokach szesnastkowych i ASCII, przejść do konkretnych adresów, a także zinterpretować dane w różne formaty:
Zaawansowane scenariusze i zastrzeżenia
Profilowanie kodu WebAssembly
Gdy otworzysz Narzędzia deweloperskie, kod WebAssembly zostanie „zredukowany” do wersji nieoptymalizowanej, aby umożliwić debugowanie. Ta wersja jest znacznie wolniejsza, co oznacza, że nie możesz polegać na console.time
, performance.now
i innych metodach pomiaru szybkości kodu, gdy DevTools są otwarte, ponieważ uzyskane liczby w żaden sposób nie odzwierciedlają rzeczywistej wydajności.
Zamiast tego użyj panelu wydajności w DevTools, który uruchomi kod z pełną prędkością i zapewni szczegółowy podział czasu spędzonego na różnych funkcjach:
Możesz też uruchomić aplikację z zamkniętymi Narzędziami deweloperskimi, otwórz je po zakończeniu sprawdzania, aby sprawdzić konsolę.
W przyszłości będziemy ulepszać scenariusze profilowania, ale na razie jest to należy pamiętać o zastrzeżeniu. Jeśli chcesz dowiedzieć się więcej o WebAssembly scenariuszy na poziomie warstw znajdziesz w dokumentacji dotyczącej potoku kompilacji WebAssembly.
kompilowanie i debugowanie na różnych komputerach (w tym Dockerze / hostze).
Podczas tworzenia w Dockerze, maszynie wirtualnej lub na zdalnym serwerze kompilacji: możesz napotkać ścieżki do plików źródłowych, używane podczas kompilacji, nie pasują do ścieżek w Twoim systemie plików, uruchomionych Narzędzi deweloperskich w Chrome. W takim przypadku pliki pojawią się w panelu Źródła, ale nie można go wczytać.
Aby rozwiązać ten problem, wdrożyliśmy funkcję mapowania ścieżek w z opcjami rozszerzeń C/C++. Można go używać do mapowania dowolnych ścieżek aby pomóc Narzędziom deweloperskim zlokalizować źródła.
Jeśli np. projekt na maszynie hosta znajduje się pod ścieżką C:\src\my_project
, ale został utworzony w kontenerze Dockera, w którym ta ścieżka jest reprezentowana jako /mnt/c/src/my_project
, możesz ją ponownie przypisać podczas debugowania, podając te ścieżki jako prefiksy:
Pierwszy pasujący prefiks „wygrane”. Jeśli znacie inne wersje C++
debugerów, ta opcja jest podobna do polecenia set substitute-path
w GDB lub w ustawieniu target.source-map
w LLDB.
Debugowanie zoptymalizowanych kompilacji
Podobnie jak w przypadku każdego innego języka, debugowanie działa najlepiej, jeśli optymalizacje wyłączono. Optymalizacje mogą wbudować funkcje do siebie, zmienić ich kolejność lub całkowicie usunąć jego fragmenty. mogą zmylić debugera, a tym samym – użytkownika.
Jeśli chcesz mieć bardziej ograniczone możliwości debugowania
debugowanie zoptymalizowanej kompilacji, większość optymalizacji będzie działać
z wyjątkiem wbudowania funkcji. Pozostałe problemy planujemy rozwiązać w przyszłości, ale na razie zalecamy użycie opcji -fno-inline
, aby wyłączyć kompilację z jakąkolwiek optymalizacją na poziomie -O
, np.:
emcc -g temp.c -o temp.html \ -O3 -fno-inline
Rozdzielanie danych debugowania
Dane debugowania zachowują wiele szczegółów dotyczących kodu, typów, zmiennych, funkcji, zakresów i lokalizacji. może być przydatna dla debugera. W efekcie może być ona często większa niż właściwy kod.
Aby przyspieszyć ładowanie i kompilację modułu WebAssembly, możesz
chcesz podzielić te informacje debugowania na osobny element WebAssembly
. Aby to zrobić w Emscripten, przekaż flagę -gseparate-dwarf=…
z parametrem
żądaną nazwę pliku:
emcc -g temp.c -o temp.html \ -gseparate-dwarf=temp.debug.wasm
W tym przypadku główna aplikacja przechowuje tylko nazwę pliku.
temp.debug.wasm
, a rozszerzenie pomocnicze będą w stanie zlokalizować i znaleźć
nie wczytuje się po otwarciu Narzędzi deweloperskich.
W połączeniu z optymalizacjami opisanymi powyżej ta funkcja może mogą nawet wysyłać prawie zoptymalizowane kompilacje produkcyjne aplikacji, a później debugować je za pomocą lokalnego pliku. W tym przypadku musimy też zastąpić zapisany URL, by rozszerzenie znajdź plik boczny, na przykład:
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]
Aby kontynuować...
Ale sporo nowych funkcji!
Dzięki tym nowym integracjom Narzędzia deweloperskie w Chrome zaawansowany debuger nie tylko do obsługi JavaScriptu, ale też aplikacji w językach C i C++, który ułatwia pobieranie aplikacji. i udostępniania ich we wspólnej, wieloplatformowej sieci.
To jednak jeszcze nie koniec. Oto kilka kwestii, nad którymi będziemy pracować w przyszłości:
- Pozbywanie się niedoskonałości interfejsu debugowania.
- Dodano obsługę niestandardowych programów formatujących.
- Pracujemy nad ulepszeniami profilowania na potrzeby aplikacji WebAssembly.
- Dodaliśmy obsługę zasięgu kodu, aby ułatwić wyszukiwanie nieużywanego kodu.
- Poprawiono obsługę wyrażeń podczas oceny konsoli.
- Dodawanie obsługi kolejnych języków.
- …i nie tylko
Tymczasem możesz pomóc nam, testując wersję beta własnego kodu we własnym kodzie i zgłaszając znalezione problemów na https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.
Pobierz kanały podglądu
Zastanów się, czy nie ustawić Chrome w wersji Canary, Dev lub beta jako domyślnej przeglądarki do programowania. Te kanały wersji testowej dają dostęp do najnowszych funkcji Narzędzi deweloperskich, umożliwiają testowanie najnowocześniejszych interfejsów API platformy internetowej i wykrywanie problemów w witrynie, zanim użytkownicy ją zobaczą.
Kontakt z zespołem ds. Narzędzi deweloperskich w Chrome
Skorzystaj z poniższych opcji, aby porozmawiać o nowych funkcjach i zmianach w poście lub o innych kwestiach związanych z Narzędziami deweloperskimi.
- Prześlij nam sugestię lub opinię na crbug.com.
- Aby zgłosić problem z Narzędziami deweloperskimi, kliknij Więcej opcji > Pomoc > Zgłoś problemy z Narzędziami deweloperskimi w Narzędziach deweloperskich.
- Opublikuj tweeta na stronie @ChromeDevTools.
- Napisz komentarz pod filmem dotyczącym nowości w Narzędziach deweloperskich w Narzędziach deweloperskich w YouTube lub filmach w YouTube ze wskazówkami dotyczącymi Narzędzi deweloperskich.