Di Chrome Dev Summit 2020, kami mendemonstrasikan dukungan proses debug Chrome untuk aplikasi WebAssembly di web untuk pertama kalinya. Sejak itu, tim telah menginvestasikan banyak energi untuk membuat pengalaman developer berskala besar, bahkan sangat besar. Dalam postingan ini, kami akan menunjukkan tombol yang kami tambahkan (atau berfungsi) di berbagai alat dan cara menggunakannya.
Proses debug yang skalabel
Mari kita lanjutkan dari postingan tahun 2020. Berikut adalah contoh yang kita lihat saat itu:
#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();
}
Ini masih merupakan contoh yang cukup kecil dan Anda mungkin tidak akan melihat masalah sebenarnya yang akan Anda lihat di aplikasi yang sangat besar, tetapi kami masih dapat menunjukkan fitur barunya kepada Anda. Penyiapan dan pengujiannya cepat dan mudah.
Dalam postingan terakhir, kita telah membahas cara mengompilasi dan men-debug contoh ini. Mari kita lakukan lagi, tetapi mari kita juga lihat //performance//:
$ emcc -sUSE_SDL=2 -g -O0 -o mandelbrot.html mandelbrot.cc -sALLOW_MEMORY_GROWTH
Perintah ini menghasilkan biner wasm 3 MB. Dan sebagian besar dari informasi tersebut, seperti yang Anda duga, adalah informasi debug. Anda dapat memverifikasinya dengan alat llvm-objdump
[1], misalnya:
$ llvm-objdump -h mandelbrot.wasm
mandelbrot.wasm: file format wasm
Sections:
Idx Name Size VMA Type
0 TYPE 0000026f 00000000
1 IMPORT 00001f03 00000000
2 FUNCTION 0000043e 00000000
3 TABLE 00000007 00000000
4 MEMORY 00000007 00000000
5 GLOBAL 00000021 00000000
6 EXPORT 0000014a 00000000
7 ELEM 00000457 00000000
8 CODE 0009308a 00000000 TEXT
9 DATA 0000e4cc 00000000 DATA
10 name 00007e58 00000000
11 .debug_info 000bb1c9 00000000
12 .debug_loc 0009b407 00000000
13 .debug_ranges 0000ad90 00000000
14 .debug_abbrev 000136e8 00000000
15 .debug_line 000bb3ab 00000000
16 .debug_str 000209bd 00000000
Output ini menunjukkan semua bagian yang ada dalam file wasm yang dihasilkan, sebagian besar adalah bagian WebAssembly standar, tetapi ada juga beberapa bagian kustom yang namanya diawali dengan .debug_
. Di sinilah biner berisi informasi debug kita. Jika kita menambahkan semua ukuran, kita akan melihat bahwa info debug mencakup sekitar 2,3 MB dari file 3 MB. Jika kita juga time
perintah emcc
, kita akan melihat bahwa di komputer kita, perintah tersebut memerlukan waktu sekitar 1,5 detik untuk dijalankan. Angka ini menjadi dasar pengukuran yang bagus, tetapi angkanya sangat kecil sehingga mungkin tidak ada yang memperhatikannya. Namun, dalam aplikasi sebenarnya, biner debug dapat dengan mudah mencapai ukuran dalam GB dan memerlukan waktu beberapa menit untuk di-build.
Melewati Binaryen
Saat mem-build aplikasi wasm dengan Emscripten, salah satu langkah build terakhirnya adalah menjalankan pengoptimal Binaryen. Binaryen adalah toolkit compiler yang mengoptimalkan dan melegalkan biner WebAssembly(-like). Menjalankan Binaryen sebagai bagian dari build cukup mahal, tetapi hanya diperlukan dalam kondisi tertentu. Untuk build debug, kita dapat mempercepat waktu build secara signifikan jika kita menghindari kebutuhan untuk melakukan pass Binaryen. Kartu Binaryen yang paling umum diperlukan adalah untuk melegalkan tanda tangan fungsi yang melibatkan nilai bilangan bulat 64 bit. Dengan memilih integrasi BigInt WebAssembly menggunakan -sWASM_BIGINT
, kita dapat menghindari hal ini.
$ emcc -sUSE_SDL=2 -g -O0 -o mandelbrot.html mandelbrot.cc -sALLOW_MEMORY_GROWTH -sWASM_BIGINT -sERROR_ON_WASM_CHANGES_AFTER_LINK
Kita telah memasukkan flag -sERROR_ON_WASM_CHANGES_AFTER_LINK
untuk tindakan yang baik. Fitur ini membantu mendeteksi kapan Binaryen berjalan dan menulis ulang biner secara tidak terduga. Dengan cara ini, kita dapat memastikan bahwa kita tetap berada di jalur cepat.
Meskipun contohnya cukup kecil, kita masih dapat melihat efek dari melewati Binaryen. Menurut time
, perintah ini berjalan kurang dari 1 detik, jadi setengah detik lebih cepat dari sebelumnya.
Penyesuaian lanjutan
Melewati pemindaian file input
Biasanya saat menautkan project Emscripten, emcc
akan memindai semua file objek dan library input. Hal ini dilakukan untuk menerapkan dependensi yang tepat antara fungsi library JavaScript dan simbol native dalam program Anda. Untuk project yang lebih besar, pemindaian tambahan file input ini (menggunakan llvm-nm
) dapat menambah waktu penautan secara signifikan.
Sebagai gantinya, Anda dapat menjalankan dengan -sREVERSE_DEPS=all
yang memberi tahu emcc
untuk menyertakan semua kemungkinan dependensi native fungsi JavaScript. Ini memiliki overhead ukuran kode kecil, tetapi dapat mempercepat waktu penautan dan dapat berguna untuk build debug.
Untuk project sekecil contoh kita, hal ini tidak akan membuat perbedaan yang signifikan, tetapi jika Anda memiliki ratusan atau bahkan ribuan file objek dalam project, hal ini dapat secara signifikan meningkatkan waktu penautan.
Menghapus bagian “name”
Dalam project besar, terutama yang memiliki banyak penggunaan template C++, bagian “name” WebAssembly dapat menjadi sangat besar. Dalam contoh kita, ini hanya sebagian kecil dari keseluruhan ukuran file (lihat output llvm-objdump
di atas), tetapi dalam beberapa kasus, ukurannya bisa sangat signifikan. Jika bagian “name” aplikasi Anda sangat besar, dan informasi debug dwarf sudah cukup untuk kebutuhan proses debug Anda, akan lebih baik jika bagian “name” dihapus:
$ emstrip --no-strip-all --remove-section=name mandelbrot.wasm
Tindakan ini akan menghapus bagian “name” WebAssembly sekaligus mempertahankan bagian debug DWARF.
Men-debug fisi
Biner dengan banyak data debug tidak hanya membebani waktu build, tetapi juga waktu proses debug. Debugger perlu memuat data dan membuat indeks untuk data tersebut, sehingga dapat merespons kueri dengan cepat, seperti "Apa jenis variabel lokal x?".
Fission debug memungkinkan kita membagi informasi debug untuk biner menjadi dua bagian: satu, yang tetap ada dalam biner, dan satu, yang terdapat dalam file objek DWARF (.dwo
) terpisah. Fitur ini dapat diaktifkan dengan meneruskan flag -gsplit-dwarf
ke Emscripten:
$ emcc -sUSE_SDL=2 -g -gsplit-dwarf -gdwarf-5 -O0 -o mandelbrot.html mandelbrot.cc -sALLOW_MEMORY_GROWTH -sWASM_BIGINT -sERROR_ON_WASM_CHANGES_AFTER_LINK
Di bawah ini, kami menampilkan berbagai perintah dan file yang dihasilkan dengan mengompilasi tanpa data debug, dengan data debug, dan terakhir dengan data debug dan pemisahan debug.
Saat memisahkan data DWARF, sebagian data debug berada bersama dengan biner, sedangkan sebagian besar data dimasukkan ke dalam file mandelbrot.dwo
(seperti yang diilustrasikan di atas).
Untuk mandelbrot
, kita hanya memiliki satu file sumber, tetapi umumnya project lebih besar dari ini dan menyertakan lebih dari satu file. Debug fission menghasilkan file .dwo
untuk setiap file tersebut. Agar debugger versi beta saat ini (0.1.6.1615) dapat memuat informasi debug terpisah ini, kita perlu menggabungkan semuanya ke dalam paket DWARF (.dwp
) seperti ini:
$ emdwp -e mandelbrot.wasm -o mandelbrot.dwp
Membangun paket DWARF dari setiap objek memiliki keunggulan bahwa Anda hanya perlu menayangkan satu file tambahan. Saat ini kami juga sedang berupaya memuat setiap objek dalam rilis mendatang.
Apa yang terjadi dengan DWARF 5?
Anda mungkin telah melihat bahwa kami menyelipkan flag lain ke dalam perintah emcc
di atas, -gdwarf-5
. Mengaktifkan simbol DWARF versi 5, yang saat ini bukan versi default, adalah trik lain untuk membantu kita memulai proses debug dengan lebih cepat. Dengannya, informasi tertentu disimpan dalam biner utama yang dihilangkan oleh versi default 4. Secara khusus, kita dapat menentukan kumpulan lengkap file sumber hanya dari biner utama. Hal ini memungkinkan debugger melakukan tindakan dasar seperti menampilkan hierarki sumber lengkap dan menetapkan titik henti sementara tanpa memuat dan mengurai data simbol lengkap. Hal ini membuat proses debug dengan simbol terpisah menjadi jauh lebih cepat, sehingga kita selalu menggunakan flag command line -gsplit-dwarf
dan -gdwarf-5
secara bersamaan.
Dengan format debug DWARF5, kita juga mendapatkan akses ke fitur berguna lainnya. Ini memperkenalkan indeks nama dalam data debug yang akan dihasilkan saat meneruskan flag -gpubnames
:
$ emcc -sUSE_SDL=2 -g -gdwarf-5 -gsplit-dwarf -gpubnames -O0 -o mandelbrot.html mandelbrot.cc -sALLOW_MEMORY_GROWTH -sWASM_BIGINT -sERROR_ON_WASM_CHANGES_AFTER_LINK
Selama sesi proses debug, pencarian simbol sering kali terjadi dengan menelusuri entitas berdasarkan nama, misalnya, saat mencari variabel atau jenis. Indeks nama mempercepat penelusuran ini dengan langsung mengarah ke unit kompilasi yang menentukan nama tersebut. Tanpa indeks nama, penelusuran menyeluruh terhadap seluruh data debug akan diperlukan untuk menemukan unit kompilasi yang benar yang menentukan entitas bernama yang kita cari.
Untuk yang ingin tahu: Melihat data debug
Anda dapat menggunakan llvm-dwarfdump
untuk melihat data DWARF. Mari kita coba:
llvm-dwarfdump mandelbrot.wasm
Hal ini memberi kita ringkasan tentang “Unit kompilasi” (secara kasar, file sumber) yang memiliki informasi debug. Dalam contoh ini, kita hanya memiliki info debug untuk mandelbrot.cc
. Info umum akan memberi tahu kita bahwa kita memiliki unit kerangka, yang berarti kita memiliki data yang tidak lengkap pada file ini, dan ada file .dwo
terpisah yang berisi info debug yang tersisa:
Anda juga dapat melihat tabel lain dalam file ini, misalnya pada tabel baris yang menampilkan pemetaan bytecode wasm ke baris C++ (coba gunakan llvm-dwarfdump -debug-line
).
Kita juga dapat melihat info debug yang terdapat dalam file .dwo
terpisah:
llvm-dwarfdump mandelbrot.dwo
TL;DR: Apa keuntungan menggunakan pemisahan debug?
Ada beberapa keuntungan untuk memisahkan informasi proses debug jika Anda menggunakan aplikasi besar:
Penautan yang lebih cepat: Penaut tidak perlu lagi mengurai seluruh informasi debug. Penaut biasanya perlu mengurai seluruh data DWARF yang ada dalam biner. Dengan menghapus sebagian besar informasi debug ke dalam file terpisah, penaut menangani biner yang lebih kecil, yang menghasilkan waktu penautan yang lebih cepat (terutama untuk aplikasi besar).
Proses debug yang lebih cepat: Debugger dapat melewati penguraian simbol tambahan dalam file
.dwo
/.dwp
untuk beberapa pencarian simbol. Untuk beberapa pencarian (seperti permintaan pada pemetaan baris file wasm-to-C++), kita tidak perlu melihat data debug tambahan. Hal ini menghemat waktu, karena kita tidak perlu memuat dan mengurai data debug tambahan.
1: Jika tidak memiliki versi terbaru llvm-objdump
di sistem, dan Anda menggunakan emsdk
, Anda dapat menemukannya di direktori emsdk/upstream/bin
.
Mendownload saluran pratinjau
Sebaiknya gunakan Chrome Canary, Dev, atau Beta sebagai browser pengembangan default Anda. Saluran pratinjau ini memberi Anda akses ke fitur DevTools terbaru, memungkinkan Anda menguji API platform web canggih, dan membantu Anda menemukan masalah di situs sebelum pengguna melakukannya.
Hubungi tim Chrome DevTools
Gunakan opsi berikut untuk membahas fitur baru, update, atau hal lain yang terkait dengan DevTools.
- Kirim masukan dan permintaan fitur kepada kami di crbug.com.
- Laporkan masalah DevTools menggunakan Opsi lainnya > Bantuan > Laporkan masalah DevTools di DevTools.
- Tweet ke @ChromeDevTools.
- Berikan komentar di video YouTube Yang baru di DevTools atau video YouTube Tips DevTools.