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ıştırdığı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();
}
Hâlâ oldukça küçük bir örnek ve çok büyük bir uygulamada karşılaşacağınız gerçek sorunların hiçbirini büyük olasılıkla görmeyeceksiniz, ancak yine de size yeni özelliklerin neler olduğunu 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. Ç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.
Binaryen atlanıyor
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. Hata ayıklama derlemelerinde, Binaryen geçişlerine ihtiyaç duymadığımız takdirde 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. Bu sayede hızlı yolda olduğumuzdan 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 simgeler arasında kesin bağımlılıklar uygulamak için yapar. Daha büyük projelerde giriş dosyalarının (llvm-nm
kullanılarak) bu ek taraması, bağlantı süresini önemli ölçüde artırabilir.
Bunun yerine, emcc
'ye JavaScript işlevlerinin tüm yerel bağımlılıkları eklemesini 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, toplam dosya boyutunun yalnızca küçük bir parçasıdır (yukarıdaki llvm-objdump
çıkışına bakın) ancak bazı durumlarda çok önemli olabilir. Uygulamanızın "ad" bölümü çok büyükse ve cüce hata ayıklama bilgileri hata ayıklama ihtiyaçlarınız için yeterliyse "ad" bölümünü çıkarmak avantajlı olabilir:
$ emstrip --no-strip-all --remove-section=name mandelbrot.wasm
Bu işlem, DWARF hata ayıklama bölümlerini korurken WebAssembly "name" bölümünü kaldırır.
Fission'u hata ayıklama
Çok fazla hata ayıklama verisi içeren ikili dosyalar, yalnızca derleme süresine değil, 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. Hata ayıklama fizyonları, 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 bunların tümünü aşağıdaki gibi DWARF adı verilen bir pakette (.dwp
) toplamamız gerekir:
$ emdwp -e mandelbrot.wasm -o mandelbrot.dwp
Tek tek nesnelerden DWARF paketi oluşturmanın avantajı, fazladan bir dosya sunmanızdır. Ş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 5. sürümünü etkinleştirmek (şu anda varsayılan olarak etkin değildir) de hata ayıklama işlemine daha hızlı başlamamıza yardımcı olacak 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çimi sayesinde başka bir faydalı özelliğe de erişim elde ediyoruz. -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
simgesini 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 göz atabiliriz:
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ğ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 son sürümü yoksa ve emsdk
kullanıyorsanız emsdk/upstream/bin
dizininde bulabilirsiniz.
Önizleme kanallarını indirme
Chrome Canary, Yeni geliştirilenler veya Beta'yı varsayılan geliştirme tarayıcınız olarak kullanabilirsiniz. Bu önizleme kanalları, en son DevTools özelliklerine erişmenizi sağlar, en yeni web platformu API'lerini test etmenize olanak tanır 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.