Chrome Dev Summit 2020'de, Chrome'un WebAssembly uygulamaları için hata ayıklama desteğini web'de ilk kez gösterdik. O zamandan beri ekip, geliştirici deneyimini büyük ve hatta çok büyük uygulamalar için ölçeklendirecek şekilde geliştirmeye çok fazla enerji harcadı. Bu yayında, farklı araçlara eklediğimiz (veya çalışmasını sağladığımız) düğmeleri ve bunların nasıl kullanılacağını göstereceğiz.
Ölçeklenebilir hata ayıklama
2020'deki gönderimizde kaldığımız yerden devam edelim. O zamanlar incelediğimiz örnek:
#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();
}
Bu örnek hâlâ oldukça küçüktür ve büyük bir uygulamada karşılaşacağınız gerçek sorunlardan hiçbirini görme olasılığınız yoktur. Yine de yeni özelliklerin neler olduğunu size gösterebiliriz. Kurulumu ve denemesi hızlı ve kolaydır.
Son yayında, bu örneğin nasıl derleneceğini ve nasıl hata ayıklayacağınızı ele almıştık. Bunu tekrar yapalım ancak //performance// bölümüne de göz atalım:
$ emcc -sUSE_SDL=2 -g -O0 -o mandelbrot.html mandelbrot.cc -sALLOW_MEMORY_GROWTH
Bu komut, 3 MB boyutunda bir wasm ikili dosyası oluşturur. Bunun büyük kısmı, tahmin edebileceğiniz gibi hata ayıklama bilgileridir. Bunu llvm-objdump
aracıyla [1] doğrulayabilirsiniz. Örneğin:
$ 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
Bu çıkışta, oluşturulan wasm dosyasında bulunan tüm bölümler gösterilir. Bunların çoğu standart WebAssembly bölümleridir ancak adı .debug_
ile başlayan birkaç özel bölüm de vardır. İkili dosya, hata ayıklama bilgilerinizi burada içerir. Tüm boyutları topladığımızda, hata ayıklama bilgilerinin 3 MB'lık dosyamızın yaklaşık 2,3 MB'ını oluşturduğunu görürüz. emcc
komutunu da time
edersek makinemizde komutun yaklaşık 1, 5 saniye sürdüğünü görürüz. Bu sayılar güzel bir referans noktası oluşturuyor ancak o kadar küçükler ki muhtemelen kimse bunlara dikkat etmez. Ancak gerçek uygulamalarda hata ayıklama ikili dosyası kolayca GB'lara ulaşabilir ve derlenmesi dakikalar sürebilir.
Skipping Binaryen
Emscripten ile bir wasm uygulaması oluştururken son derleme adımlarından biri Binaryen optimizatörünü çalıştırmaktır. Binaryen, hem WebAssembly (benzeri) ikili dosyaları optimize eden hem de yasallaştıran bir derleyici araç paketidir. Derleme kapsamında Binaryen'in çalıştırılması oldukça pahalıdır ancak yalnızca belirli koşullarda gereklidir. Binaryen geçişlerine gerek kalmamasını sağlarsak hata ayıklama derlemeleri için derleme süresini önemli ölçüde hızlandırabiliriz. En yaygın olarak gerekli olan Binaryen geçişi, 64 bit tam sayı değerleri içeren işlev imzalarının yasallaştırılmasıdır. -sWASM_BIGINT
kullanarak WebAssembly BigInt entegrasyonunu etkinleştirerek bu sorunu önleyebiliriz.
$ emcc -sUSE_SDL=2 -g -O0 -o mandelbrot.html mandelbrot.cc -sALLOW_MEMORY_GROWTH -sWASM_BIGINT -sERROR_ON_WASM_CHANGES_AFTER_LINK
Güvenli olması için -sERROR_ON_WASM_CHANGES_AFTER_LINK
işaretini de ekledik. Binaryen'in ne zaman çalıştığını ve ikili dosyayı beklenmedik bir şekilde yeniden yazdığını tespit etmenize yardımcı olur. Böylece, hızlı bir şekilde ilerlediğimizden emin olabiliriz.
Örneğimiz oldukça küçük olsa da Binaryen'i atlamanın etkisini görebiliriz. time
'ye göre bu komut 1 saniyenin biraz altında sürede çalışıyor. Yani öncekinden yarım saniye daha hızlı.
Gelişmiş ince ayarlar
Giriş dosyası taramasını atlama
Normalde bir Emscripten projesi bağlanırken emcc
, tüm giriş nesne dosyalarını ve kitaplıklarını tarar. Bunu, programınızdaki JavaScript kitaplık işlevleri ile yerel semboller arasında hassas bağımlılıklar uygulamak için yapar. Daha büyük projelerde, giriş dosyalarının llvm-nm
kullanılarak ek olarak taranması bağlantı süresini önemli ölçüde uzatabilir.
Bunun yerine, emcc
'ye JavaScript işlevlerinin tüm yerel bağımlılıkları dahil etmesini söyleyen -sREVERSE_DEPS=all
ile çalıştırabilirsiniz. Bu yöntem, küçük bir kod boyutu yükü oluşturur ancak bağlantı sürelerini kısaltabilir ve hata ayıklama derlemeleri için yararlı olabilir.
Örneğimizdeki kadar küçük bir proje için bu durum gerçek bir fark yaratmaz ancak projenizde yüzlerce hatta binlerce nesne dosyanız varsa bağlantı sürelerini önemli ölçüde iyileştirebilir.
"Ad" bölümünü kaldırma
Büyük projelerde (özellikle çok fazla C++ şablonu kullanılan projelerde) WebAssembly "ad" bölümü çok büyük olabilir. Örneğimizde bu değer, toplam dosya boyutunun yalnızca küçük bir kısmıdır (yukarıdaki llvm-objdump
çıktısına bakın) ancak bazı durumlarda çok önemli olabilir. Uygulamanızın "ad" bölümü çok büyükse ve hata ayıklama ihtiyaçlarınız için dwarf hata ayıklama bilgileri yeterliyse "ad" bölümünü kaldırmak avantajlı olabilir:
$ emstrip --no-strip-all --remove-section=name mandelbrot.wasm
Bu işlem, DWARF hata ayıklama bölümlerini korurken WebAssembly "ad" bölümünü kaldırır.
Fission'u hata ayıklama
Çok fazla hata ayıklama verisi içeren ikili dosyalar, derleme süresine olduğu kadar hata ayıklama süresine de baskı uygular. Hata ayıklayıcının, "x yerel değişkeninin türü nedir?" gibi sorgulara hızlıca yanıt verebilmek için verileri yüklemesi ve bunlar için bir dizin oluşturması gerekir.
Hata ayıklama bölme, bir ikili dosyanın hata ayıklama bilgilerini iki bölüme ayırmamıza olanak tanır: biri ikili dosyada kalan, diğeri ise ayrı bir DWARF nesnesi (.dwo
) dosyasında bulunan bölüm. -gsplit-dwarf
işaretçisi Emscripten'e iletilerek etkinleştirilebilir:
$ 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
Aşağıda, farklı komutları ve hata ayıklama verileri olmadan, hata ayıklama verileri ile ve son olarak hem hata ayıklama verileri hem de hata ayıklama bölme işlemiyle derleme yapılarak hangi dosyaların oluşturulduğunu gösteriyoruz.
DWARF verileri bölündüğünde, hata ayıklama verilerinin bir kısmı ikili programla birlikte bulunurken büyük kısmı mandelbrot.dwo
dosyasına yerleştirilir (yukarıda gösterildiği gibi).
mandelbrot
için yalnızca bir kaynak dosyamız var ancak genellikle projeler bundan daha büyüktür ve birden fazla dosya içerir. Bölme işlemini hata ayıklama işlemi, her biri için bir .dwo
dosyası oluşturur. Hata ayıklayıcının mevcut beta sürümünün (0.1.6.1615) bu bölünmüş hata ayıklama bilgilerini yükleyebilmesi için tüm bunları aşağıdaki gibi bir DWARF paketinde (.dwp
) toplamamız gerekir:
$ emdwp -e mandelbrot.wasm -o mandelbrot.dwp
DWARF paketini tek tek nesnelerden oluşturmanın avantajı, yalnızca bir tane ek dosya yayınlamanız gerekmesidir. Şu anda gelecekteki bir sürümde tüm nesneleri tek tek yüklemek için çalışıyoruz.
DWARF 5 ile ilgili sorun nedir?
Yukarıdaki emcc
komutuna -gdwarf-5
başka bir işaret eklediğimizi fark etmiş olabilirsiniz. DWARF sembollerinin şu anda varsayılan olarak kullanılmayan 5. sürümünü etkinleştirmek, hata ayıklama işlemine daha hızlı başlamamıza yardımcı olacak başka bir yöntemdir. Bu sayede, ana ikili dosyada varsayılan 4. sürümün atladığı belirli bilgiler saklanır. Daha açık belirtmek gerekirse, kaynak dosyaların tamamını yalnızca ana ikili dosyadan belirleyebiliriz. Bu sayede hata ayıklayıcı, tam simge verilerini yükleyip ayrıştırmadan kaynak ağacının tamamını gösterme ve kesme noktaları ayarlama gibi temel işlemleri yapabilir. Bu, bölünmüş sembollerle hata ayıklama işlemini çok daha hızlı hale getirir. Bu nedenle, -gsplit-dwarf
ve -gdwarf-5
komut satırı işaretlerini her zaman birlikte kullanırız.
DWARF5 hata ayıklama biçimiyle başka bir kullanışlı özelliğe de erişebiliriz. -gpubnames
bayrağı iletilirken oluşturulacak hata ayıklama verilerine bir ad dizini ekler:
$ 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
Hata ayıklama oturumunda, sembol aramaları genellikle bir öğeyi ada göre aramak (ör. bir değişken veya tür ararken) şeklinde gerçekleşir. Ad dizini, doğrudan adı tanımlayan derleme birimini işaret ederek bu aramayı hızlandırır. Ad dizini olmadan, aradığımız adlandırılmış öğeyi tanımlayan doğru derleme birimini bulmak için tüm hata ayıklama verilerinin kapsamlı bir şekilde aranması gerekir.
Merak edenler için: Hata ayıklama verilerine bakma
DWARF verilerine göz atmak için llvm-dwarfdump
'ü kullanabilirsiniz. Bunu deneyelim:
llvm-dwarfdump mandelbrot.wasm
Bu sayede, hata ayıklama bilgilerine sahip olduğumuz "Derleme birimleri"ne (genel olarak kaynak dosyalar) genel bir bakış elde edebiliriz. Bu örnekte yalnızca mandelbrot.cc
için hata ayıklama bilgileri mevcuttur. Genel bilgiler, iskelet birimi olduğunu gösterir. Bu, bu dosyayla ilgili verilerin eksik olduğu ve kalan hata ayıklama bilgilerini içeren ayrı bir .dwo
dosyası olduğu anlamına gelir:
Bu dosyadaki diğer tablolara da göz atabilirsiniz. Örneğin, wasm bayt kodunun C++ satırlarıyla eşlemesini gösteren satır tablosuna (llvm-dwarfdump -debug-line
kullanmayı deneyin) bakabilirsiniz.
Ayrı .dwo
dosyasında bulunan hata ayıklama bilgilerine de bakabiliriz:
llvm-dwarfdump mandelbrot.dwo
Özet: Hata ayıklama için bölme kullanmanın avantajı nedir?
Büyük uygulamalarla çalışıyorsanız hata ayıklama bilgilerini bölmenin çeşitli avantajları vardır:
Daha hızlı bağlantı: Bağlantılayıcının artık hata ayıklama bilgilerinin tamamını ayrıştırması gerekmez. Bağlantı oluşturucuların genellikle ikili dosyada bulunan DWARF verilerinin tamamını ayrıştırması gerekir. Hata ayıklama bilgilerinin büyük bir kısmını ayrı dosyalara ayırarak bağlayıcılar daha küçük ikili dosyalarla çalışır. Bu da daha hızlı bağlantı sürelerine (özellikle büyük uygulamalar için) neden olur.
Daha hızlı hata ayıklama: Hata ayıklayıcı, bazı simge aramaları için
.dwo
/.dwp
dosyalarındaki ek simgeleri ayrıştırmayı atlayabilir. Bazı aramalar için (ör. wasm'den C++ dosyalarına satır eşleme istekleri) ek hata ayıklama verilerini incelememiz gerekmez. Bu sayede ek hata ayıklama verilerini yükleyip ayrıştırmak zorunda kalmadığımız için zamandan tasarruf ederiz.
1: Sisteminizde llvm-objdump
'nin güncel bir sürümü yoksa ve emsdk
kullanıyorsanız emsdk/upstream/bin
dizininde bulabilirsiniz.
Önizleme kanallarını indirme
Varsayılan geliştirme tarayıcınız olarak Chrome Canary, Yeni Geliştirilenler veya Beta sürümünü kullanabilirsiniz. Bu önizleme kanalları, en son DevTools özelliklerine erişmenize, en yeni web platformu API'lerini test etmenize ve sitenizdeki sorunları kullanıcılarınızdan önce bulmanıza yardımcı olur.
Chrome Geliştirici Araçları Ekibi ile iletişime geçme
Yeni özellikler, güncellemeler veya Geliştirici Araçları ile ilgili başka herhangi bir konu hakkında konuşmak için aşağıdaki seçenekleri kullanın.
- crbug.com adresinden bize geri bildirim ve özellik isteği gönderin.
- Geliştirici Araçları'nda Diğer seçenekler > Yardım > Geliştirici Araçları sorunu bildir'i kullanarak bir Geliştirici Araçları sorununu bildirin.
- @ChromeDevTools hesabına tweet gönderin.
- Geliştirici Araçları'ndaki yenilikler veya Geliştirici Araçları'yla ilgili ipuçları konulu YouTube videolarına yorum bırakın.