Perjalanan sejauh ini
Setahun yang lalu, Chrome mengumumkan dukungan awal untuk proses debug WebAssembly native di Chrome DevTools.
Kami telah menunjukkan dukungan langkah dasar dan membahas peluang penggunaan informasi DWARF, bukan peta sumber yang terbuka untuk kita di masa mendatang:
- Me-resolve nama variabel
- Jenis pencetakan yang rapi
- Mengevaluasi ekspresi dalam bahasa sumber
- …dan banyak lagi.
Hari ini, kami dengan senang hati menampilkan fitur yang dijanjikan yang telah diwujudkan dan progres yang telah dibuat oleh tim Emscripten dan Chrome DevTools selama tahun ini, khususnya, untuk aplikasi C dan C++.
Sebelum memulai, perlu diingat bahwa ini masih merupakan versi beta dari pengalaman baru. Anda harus menggunakan versi terbaru dari semua alat dengan risiko Anda sendiri, dan jika Anda mengalami masalah, laporkan ke https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.
Mari kita mulai dengan contoh C sederhana yang sama seperti sebelumnya:
#include <stdlib.h>
void assert_less(int x, int y) {
if (x >= y) {
abort();
}
}
int main() {
assert_less(10, 20);
assert_less(30, 20);
}
Untuk mengompilasi, kita menggunakan Emscripten terbaru
dan meneruskan flag -g
, seperti dalam postingan asli, untuk menyertakan informasi
debug:
emcc -g temp.c -o temp.html
Sekarang kita dapat menayangkan halaman yang dihasilkan dari server HTTP localhost (misalnya, dengan serve), dan membukanya di Chrome Canary terbaru.
Kali ini kita juga akan membutuhkan ekstensi bantuan yang terintegrasi dengan Chrome DevTools membantu memahami semua informasi proses debug dikodekan dalam file WebAssembly. Instal dengan membuka link: goo.gle/wasm-debugging-extension
Anda juga dapat mengaktifkan proses debug WebAssembly di Eksperimen DevTools. Buka Chrome DevTools, klik ikon roda gigi (⚙) di sudut kanan atas panel DevTools, buka panel Eksperimen, lalu centang WebAssembly Debugging: Enable DWARF support.
Saat Anda menutup Settings, DevTools akan menyarankan untuk memuat ulang itself untuk menerapkan setelan, jadi mari kita lakukan hal itu. Itu saja untuk penyiapan satu kali.
Sekarang kita dapat kembali ke panel Sumber, mengaktifkan Jeda pada pengecualian (ikon ⏸), lalu mencentang Jeda pada pengecualian yang tertangkap dan memuat ulang halaman. Anda akan melihat DevTools dijeda pada pengecualian:
Secara default, kode ini berhenti pada kode glue yang dihasilkan Emscripten, tetapi di sebelah kanan, Anda dapat melihat tampilan Call Stack yang mewakili stacktrace error, dan dapat membuka baris C asli yang memanggil abort
:
Sekarang, jika melihat di tampilan Cakupan, Anda dapat melihat nama aslinya
variabel dalam kode C/C++, dan tidak lagi harus mencari
apa arti nama yang rusak seperti $localN
dan bagaimana kaitannya dengan
kode sumber yang Anda tulis.
Ini tidak hanya berlaku untuk nilai primitif seperti bilangan bulat, tetapi juga untuk gabungan seperti struktur, class, array, dll.!
Dukungan jenis kaya
Mari lihat contoh yang lebih rumit untuk menunjukkannya. Ini kita akan menggambar fraktal Mandelbrot dengan kode C++ berikut:
#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();
}
Anda dapat melihat bahwa aplikasi ini masih cukup kecil-hanya satu file yang berisi 50 baris kode-tetapi kali ini saya juga menggunakan beberapa API eksternal, seperti library SDL untuk grafik serta bilangan kompleks dari library standar C++.
Saya akan mengompilasinya dengan flag -g
yang sama seperti di atas untuk menyertakan
informasi debug, dan saya juga akan meminta
Emscripten untuk menyediakan file SDL2
dan memungkinkan ukuran memori
secara arbitrer:
emcc -g mandelbrot.cc -o mandelbrot.html \ -s USE_SDL=2 \ -s ALLOW_MEMORY_GROWTH=1
Saat mengunjungi laman yang dibuat di browser, saya dapat melihat bentuk fraktal dengan beberapa warna acak:
Saat membuka DevTools, sekali lagi, saya dapat melihat file C++ asli. Ini waktu, namun, kita tidak memiliki kesalahan di kode (wow!), jadi mari kita atur beberapa titik henti sementara di awal kode.
Saat kita memuat ulang halaman lagi, debugger akan dijeda tepat di dalam sumber C++ kita:
Kita sudah bisa melihat semua variabel di sebelah kanan, tetapi hanya width
dan height
diinisialisasi saat ini, sehingga tidak ada banyak
memeriksa.
Mari kita tetapkan titik henti sementara lain di dalam loop Mandelbrot utama kita, dan lanjutkan {i>executable<i} untuk melewati sedikit ke depan.
Pada tahap ini, palette
telah diisi dengan beberapa warna acak,
dan kita dapat memperluas array itu sendiri, serta setiap
struktur SDL_Color
dan memeriksa komponennya untuk memverifikasi bahwa
semuanya terlihat bagus (misalnya, saluran "alpha" selalu ditetapkan
ke opasitas penuh). Demikian pula, kita dapat memperluas
dan memeriksa masalah
bagian imajiner dari bilangan kompleks yang disimpan dalam variabel center
.
Jika Anda ingin mengakses properti bersarang yang dalam yang sulit untuk buka melalui tampilan Cakupan, Anda dapat menggunakan Konsol evaluasi! Namun, perlu diperhatikan bahwa ekspresi C++ yang lebih kompleks belum didukung.
Mari kita lanjutkan eksekusi beberapa kali dan kita dapat melihat bagaimana x
bagian dalam
berubah dengan melihat di tampilan Cakupan lagi, menambahkan
nama variabel ke daftar pantauan, mengevaluasinya di konsol, atau dengan
arahkan kursor ke variabel tersebut di kode sumber:
Dari sini, kita dapat melakukan step-in atau step-over pada pernyataan C++, dan mengamati bagaimana variabel lain juga berubah:
Baik, jadi semua ini berfungsi dengan baik jika informasi debug tersedia, tetapi bagaimana jika kita ingin men-debug kode yang tidak di-build dengan opsi proses debug?
Proses debug WebAssembly mentah
Misalnya, kami meminta Emscripten untuk menyediakan library SDL bawaan bagi
kami, bukan mengompilasi sendiri dari sumber, sehingga-setidaknya
saat ini-debugger tidak dapat menemukan sumber terkait.
Mari kita masuk lagi untuk masuk ke SDL_RenderDrawColor
:
Kita kembali ke pengalaman proses debug WebAssembly mentah.
Sekarang, terlihat agak menakutkan dan bukan sesuatu yang akan dialami oleh banyak pengembang Web perlu ditangani, tetapi terkadang Anda mungkin ingin men-debug yang dibangun tanpa informasi debug--baik karena itu Libraryrd pihak ketiga yang tidak dapat Anda kendalikan, atau karena Anda menemui salah satu {i>bug<i} yang hanya terjadi pada tahap produksi.
Untuk membantu dalam kasus tersebut, kami juga telah melakukan beberapa peningkatan pada pengalaman proses debug dasar.
Pertama-tama, jika sebelumnya Anda menggunakan proses debug WebAssembly mentah, Anda mungkin
melihat bahwa seluruh proses disassembly kini ditampilkan dalam satu file. Tidak perlu lagi menebak fungsi mana yang mungkin sesuai dengan entri Sumber wasm-53834e3e/
wasm-53834e3e-7
.
Skema pembuatan nama baru
Kami juga memperbaiki nama di tampilan pembongkaran. Sebelumnya Anda akan melihat hanya indeks numerik, atau, untuk fungsi, tanpa nama sama sekali.
Sekarang kita membuat nama yang mirip
dengan alat pembongkaran lainnya, dengan
menggunakan petunjuk dari bagian nama WebAssembly,
jalur impor/ekspor dan, terakhir, jika semuanya gagal, menghasilkan
berdasarkan jenis dan indeks item seperti $func123
. Anda dapat
melihat bagaimana, dalam screenshot di atas, hal ini sudah membantu mendapatkan
stacktrace dan disassembly yang sedikit lebih mudah dibaca.
Jika tidak ada informasi jenis yang tersedia, pemeriksaan akan sulit dilakukan nilai apa pun selain primitif-misalnya, pointer akan muncul sebagai bilangan bulat biasa, tidak ada cara untuk mengetahui apa yang disimpan di belakangnya memori.
Pemeriksaan memori
Sebelumnya, Anda hanya dapat meluaskan objek memori WebAssembly, yang diwakili oleh env.memory
di tampilan Cakupan untuk mencari
setiap byte. Hal ini berfungsi dalam beberapa skenario sederhana, tetapi tidak
sangat mudah untuk diperluas dan tidak memungkinkan untuk menafsirkan ulang data
dalam format selain nilai byte. Kami telah menambahkan fitur
baru untuk membantu
dengan ini juga: pemeriksa memori linear.
Jika Anda mengklik kanan pada env.memory
, Anda akan melihat
opsi yang disebut Inspect memory:
Setelah diklik, Memory Inspector akan muncul, tempat Anda dapat memeriksa memori WebAssembly dalam tampilan heksadesimal dan ASCII, membuka alamat tertentu, serta menafsirkan data dalam format yang berbeda:
Skenario dan peringatan lanjutan
Membuat profil kode WebAssembly
Saat Anda membuka DevTools, kode WebAssembly akan "ditingkatkan" menjadi
versi yang tidak dioptimalkan untuk mengaktifkan proses debug. Versi ini jauh lebih lambat,
yang berarti Anda tidak dapat mengandalkan console.time
, performance.now
,
dan metode lain untuk mengukur kecepatan kode saat DevTools
terbuka, karena angka yang Anda dapatkan tidak akan mewakili performa di dunia nyata
sama sekali.
Sebagai gantinya, Anda harus menggunakan panel Performance DevTools yang akan menjalankan kode dengan kecepatan penuh dan memberi Anda rincian waktu yang dihabiskan di berbagai fungsi:
Atau, Anda dapat menjalankan aplikasi dengan DevTools tertutup, dan membukanya setelah selesai untuk memeriksa Konsol.
Kami akan meningkatkan skenario pembuatan profil di masa mendatang, tetapi untuk saat ini peringatan yang harus diperhatikan. Jika Anda ingin mempelajari lebih lanjut skenario tingkatan WebAssembly, lihat dokumen kami tentang pipeline kompilasi WebAssembly.
Membangun dan melakukan proses debug di berbagai mesin (termasuk Docker / host)
Saat membangun di Docker, mesin virtual, atau di server build jarak jauh, Anda mungkin akan mengalami situasi di mana jalur ke file sumber tidak cocok dengan jalur pada sistem file Anda sendiri, Chrome DevTools sedang berjalan. Dalam hal ini, file akan muncul di Sumber tetapi gagal dimuat.
Untuk memperbaiki masalah ini, kami telah menerapkan fungsi pemetaan jalur di opsi ekstensi C/C++. Anda dapat menggunakannya untuk memetakan ulang jalur arbitrer dan membantu DevTools menemukan sumber.
Misalnya, jika project di mesin host Anda berada di jalur
C:\src\my_project
, tetapi di-build di dalam penampung Docker tempat
jalur tersebut direpresentasikan sebagai /mnt/c/src/my_project
, Anda dapat memetakan ulang
jalur tersebut selama proses debug dengan menentukan jalur tersebut sebagai awalan:
Awalan pertama yang cocok, "kemenangan". Jika Anda sudah terbiasa dengan debugger C++
lainnya, opsi ini mirip dengan perintah set substitute-path
di GDB atau setelan target.source-map
di LLDB.
Men-debug build yang dioptimalkan
Seperti bahasa lainnya, proses debug akan berfungsi optimal jika pengoptimalan dinonaktifkan. Pengoptimalan dapat menyisipkan fungsi satu ke yang lain, menyusun ulang kode, atau menghapus bagian dari kode secara bersamaan-dan semua ini memiliki untuk membingungkan debugger dan, akibatnya, Anda sebagai pengguna.
Jika Anda tidak keberatan dengan pengalaman proses debug yang lebih terbatas dan masih ingin
men-debug build yang dioptimalkan, maka sebagian besar pengoptimalan akan berfungsi sebagai
diharapkan, kecuali untuk fungsi inline. Kami berencana untuk menangani sisa
masalah pada masa mendatang. Namun, untuk saat ini, gunakan -fno-inline
untuk
menonaktifkannya saat mengompilasi dengan pengoptimalan level -O
, mis.:
emcc -g temp.c -o temp.html \ -O3 -fno-inline
Memisahkan informasi debug
Informasi debug menyimpan banyak detail tentang kode Anda, yang ditentukan jenis, variabel, fungsi, ruang lingkup, dan lokasi-apa pun yang mungkin berguna bagi debugger. Akibatnya, file ini sering kali dapat lebih besar dari kode itu sendiri.
Untuk mempercepat pemuatan dan kompilasi modul WebAssembly, Anda mungkin
ingin memisahkan informasi debug ini ke dalam file WebAssembly
terpisah. Untuk melakukannya di Emscripten, teruskan tanda -gseparate-dwarf=…
dengan
nama file yang diinginkan:
emcc -g temp.c -o temp.html \ -gseparate-dwarf=temp.debug.wasm
Dalam hal ini, aplikasi utama hanya akan menyimpan nama file
temp.debug.wasm
, dan ekstensi helper akan dapat menemukan dan
memuatnya saat Anda membuka DevTools.
Jika digabungkan dengan pengoptimalan seperti yang dijelaskan di atas, fitur ini dapat digunakan untuk mengirimkan build produksi yang hampir dioptimalkan aplikasi, dan kemudian men-debug-nya dengan file sisi lokal. Dalam hal ini, kita juga harus mengganti URL yang disimpan untuk membantu ekstensi menemukan file samping, misalnya:
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]
Untuk dilanjutkan...
Wah, banyak sekali fitur barunya!
Dengan semua integrasi baru tersebut, Chrome DevTools menjadi layak, kuat, debugger tidak hanya untuk JavaScript, tetapi juga untuk aplikasi C dan C++, membuatnya semakin mudah untuk mengambil aplikasi, yang dibangun dalam berbagai dan membawanya ke Web lintas platform bersama.
Namun, perjalanan kita belum berakhir. Beberapa hal yang akan kami kerjakan mulai sekarang:
- Membersihkan kekurangan dalam pengalaman proses debug.
- Menambahkan dukungan untuk pemformat jenis kustom.
- Sedang mengerjakan perbaikan pembuatan profil untuk aplikasi WebAssembly.
- Menambahkan dukungan untuk cakupan kode agar lebih mudah ditemukan kode yang tidak digunakan.
- Meningkatkan dukungan untuk ekspresi dalam evaluasi konsol.
- Menambahkan dukungan untuk lebih banyak bahasa.
- …dan lainnya!
Sementara itu, bantu kami dengan mencoba versi beta saat ini pada kode Anda sendiri dan laporkan masalah apa pun yang ditemukan ke https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.
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, menguji API platform web canggih, dan menemukan masalah di situs Anda sebelum pengguna menemukannya.
Menghubungi tim Chrome DevTools
Gunakan opsi berikut untuk membahas fitur dan perubahan baru dalam postingan, atau hal lain yang terkait dengan DevTools.
- Kirim saran atau masukan kepada kami melalui 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.