Modern araçlarla WebAssembly hatalarını ayıklama

Ingvar Stepanyan
Ingvar Stepanyan

Yolda şu ana kadar

Bir yıl önce, Chrome ilk desteği duyurdu yerel WebAssembly hata ayıklamasına yardımcı olabilir.

Temel adım desteğini gösterdik ve fırsatlardan bahsettik. yerine DWARF bilgilerinin kullanımı kaynak haritaları gelecekte bizim için açılacaktır:

  • Değişken adlarını çözme
  • Şık yazdırma türleri
  • Kaynak dillerdeki ifadeleri değerlendirme
  • ...ve çok daha fazlası!

Bugün, vadettiğimiz özelliklerin hayata geçtiğini göstermekten heyecan duyuyoruz. Emscripten ve Chrome Geliştirici Araçları ekiplerinin C ve C++ uygulamaları için bu yıl öne çıkıyorlar.

Başlamadan önce, bunun hâlâ beta sürüm olduğunu lütfen unutmayın için tüm araçların en yeni sürümünü kullanmanız gerekir. sorumluluğu üstlenirsiniz. Herhangi bir sorunla karşılaşırsanız lütfen https://bugs.chromium.org/p/chromium/issues/entry?template=DevTools+issue.

Son seferki basit C örneğinden başlayalım:

#include <stdlib.h>

void assert_less(int x, int y) {
  if (x >= y) {
    abort();
  }
}

int main() {
  assert_less(10, 20);
  assert_less(30, 20);
}

Derlemek için en son Emscripten kodunu kullanıyoruz. ve hata ayıklamayı dahil etmek için orijinal yayında olduğu gibi bir -g işareti iletin. bilgi:

emcc -g temp.c -o temp.html

Artık oluşturulan sayfayı bir localhost HTTP sunucusundan ( örneğin, serve ile) ve en son Chrome Canary'de açmanız gerekir.

Bu kez, Chrome ile entegre edilebilen yardımcı bir uzantıya da ihtiyacımız olacak. Geliştirici Araçları'na erişim sağlar ve tüm hata ayıklama bilgilerini anlamasını sağlar. webAssembly dosyasında kodlanır. Lütfen bu bağlantıyı ziyaret ederek yükleyin bağlantı: goo.gle/wasm-debugging-extension

Ayrıca, Geliştirici Araçları'nda WebAssembly hata ayıklama özelliğini de Denemeler. Chrome Geliştirici Araçları'nı açın, ekranın alt kısmındaki dişli () simgesini tıklayın sağ üst köşesinden Denemeler paneline gidin WebAssembly Hata Ayıklama: DWARF desteğini etkinleştir'i işaretleyin.

Geliştirici Araçları ayarlarının Denemeler bölmesi

Ayarlar'ı kapattığınızda Geliştirici Araçları kendini yeniden yüklemenizi önerir. Bunu yapalım. Bir defalık bu kadar kurulumu.

Şimdi Kaynaklar paneline geri dönüp Duraklatma istisnalar (⏸ simgesi), ardından Yakalanan istisnalarda duraklat'ı işaretleyin ve sayfayı yeniden yükleyin. Geliştirici Araçları'nın bir istisna nedeniyle duraklatıldığını görürsünüz:

&quot;Yakalanan istisnalarda duraklat&quot; seçeneğinin nasıl etkinleştirileceğini gösteren Kaynaklar panelinin ekran görüntüsü

Varsayılan olarak Emscripten tarafından oluşturulan birleştirici kodda durur ancak gösteren yığın izlemeleri (stack trace) gösteren bir Arama Grubu bir hata alır ve çağrı yapan orijinal C satırına gidebilir abort:

Geliştirici Araçları &quot;assert_less&quot; işlevinde duraklatıldı ve kapsam görünümünde &quot;x&quot; ile &quot;y&quot; değerlerini gösteriyor

Artık Kapsam görünümüne baktığınızda orijinal adların ve değerlerini C/C++ kodundaki değişkenlerin değerleri ile ilişkilendirir ve artık $localN gibi karışık isimlerin ne anlama geldiğini ve kaynak kodundan kaynaklanabilir.

Bu, yalnızca tam sayılar gibi temel değerler için değil, bileşik değerler için de geçerlidir. sıralar, modeller, diziler vb. türler arasında yer alır.

Zengin tür desteği

Bunları göstermek için daha karmaşık bir örneğe bakalım. Bu ilk 10 kare olacak şekilde bir Mandelbrot fraktal şu C++ kodunu takip edin:

#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();
}

Gördüğünüz gibi bu uygulama da oldukça küçük. Uygulama, 50 satır kod içeren bir dosya ama bu defa ben de için SDL kitaplığı gibi harici API'ler karmaşık sayılar ve bunların C++ standart kitaplığı.

Dahil etmek için yukarıdakiyle aynı -g işaretiyle derleyeceğim. hata ayıklama bilgilerini aktaracağım. Ayrıca, Emscripten'den SDL2 kitaplığını açabilir ve rastgele boyutlandırılmış belleğe izin verebilirsiniz:

emcc -g mandelbrot.cc -o mandelbrot.html \
     -s USE_SDL=2 \
     -s ALLOW_MEMORY_GROWTH=1

Oluşturulan sayfayı tarayıcıda ziyaret ettiğimde güzel rastgele renklere sahip fraktal şekil:

Demo sayfası

Geliştirici Araçları'nı tekrar açtığımda orijinal C++ dosyasını görebiliyorum. Bu ancak kodda herhangi bir hata yok (üe!). Bu nedenle, kodumuzun başına koyabileceğimiz yeni bir

Sayfayı tekrar yüklediğimizde, hata ayıklayıcı hemen C++ kaynağı:

&quot;SDL_Init&quot; aramasında Geliştirici Araçları duraklatıldı

Sağ tarafta tüm değişkenlerimizi görebiliyoruz, ancak yalnızca width ve height şu anda başlatılmış olduğundan yapılması gereken pek bir şey yoktur. inceleyin.

Ana Mandelbrot döngümüze başka bir ayrılma noktası ekleyip ileri sarabilirim.

Geliştirici Araçları, iç içe yerleştirilmiş döngülerin içinde duraklatıldı

Bu noktada palette aracımız rastgele renklerle dolduruldu. hem dizinin kendisini hem de şunları doğrulamak için SDL_Color yapıyı ve bileşenlerini inceleyin her şey yolunda görünüyor (örneğin, "alfa" kanalı tam opaklığa). Benzer şekilde, mevcut müşteri tabanının center değişkeninde depolanan karmaşık sayının sanal bölümleri.

İçermesi zor olan, derin iç içe yerleştirilmiş bir mülke erişmek istiyorsanız Kapsam görünümünden erişebilirsiniz. Burada Konsol çok önemlidir! Ancak daha karmaşık C++ ifadelerinin desteklenmemektedir.

&quot;palet[10].r&quot; sonucunu gösteren konsol paneli

Yürütmeye birkaç kez devam edelim ve iç x öğesinin nasıl olduğunu Kapsam görünümüne tekrar bakarak, yeni bir kitle eklemek için bunu izleme listesine ekleyerek, konsolda değerlendirerek veya kaynak koddaki değişkenin üzerine gelin:

Kaynaktaki &quot;x&quot; değişkeni üzerine, &quot;3&quot; değerini gösteren ipucu

Buradan, C++ ifadelerini devreye alabilir veya bunların nasıl diğer değişkenler de değişiyor:

&quot;renk&quot;, &quot;nokta&quot; ve diğer değişkenlerin değerlerini gösteren ipuçları ve kapsam görünümü

Elbette, hata ayıklama bilgisi mevcut olduğunda tüm bunlar harika çalışıyor ancak hata ayıklama ile oluşturulmamış bir kodda hata ayıklamak istersek seçenekleri mi var?

Ham WebAssembly hata ayıklama

Örneğin, Emscripten'den her örnek için önceden oluşturulmuş bir SDL kitaplığı kaynağından kendimiz derlemek yerine, en azından Şu anda hata ayıklayıcının ilişkili kaynakları bulması mümkün değildir. SDL_RenderDrawColor devreye girelim:

&quot;mandelbrot.wasm&quot;nin sökme görünümünü gösteren Geliştirici Araçları

Ham WebAssembly hata ayıklama deneyimine geri döndük.

Çok korkutucu görünüyor ve çoğu Web geliştiricisinin isteyeceği bir şey değil, zaman zaman bir hata ayıklamanız gerekebilir, ancak veya hata ayıklama bilgileri içermeyen bir kitaplık Kontrolün sizde olmadığı 3. taraf kitaplığı veya yalnızca üretimde oluşan hatalardan biriyle karşılaşabilirsiniz.

Bu durumlarda yardımcı olmak için, Okuyucu Gelirleri Yöneticisi'nin hata ayıklama deneyiminden yararlanabilirsiniz.

Öncelikle, daha önce ham WebAssembly hata ayıklaması kullandıysanız artık tüm parçaların tek bir dosyada gösterildiğini fark edeceksiniz; Kaynaklar girişinin wasm-53834e3e/ wasm-53834e3e-7 muhtemelen hangi işleve karşılık geldiği tahmin edilir.

Yeni ad oluşturma şeması

Ayırma görünümündeki adları da iyileştirdik. Önceden gördüğünüz ya da işlevler söz konusu olduğunda hiçbir ad yoktur.

Şimdi ise diğer sökme araçlarına benzer adlar oluşturarak WebAssembly adı bölümündeki ipuçlarını kullanarak, yolların içe/dışa aktarılabilmesi ve son olarak, diğer her şey başarısız olursa, bunları, $func123 gibi öğenin türüne ve dizinine göre de düzenleyebilirsiniz. Şunları yapabilirsiniz: yukarıdaki ekran görüntüsünde, bu yöntemin biraz da daha okunabilir yığın izlemeleri ve parçalarına ayırmaya yardımcı olur.

Tür bilgisi yoksa bu bilgileri denetlemek zor olabilir. temel öğeler dışındaki tüm değerler (örneğin, işaretçiler gösterilir) bunların arkasında ne bulunduğunu bilmenin mümkün olmadığı, normal tam sayılar hafızada bulabilirsiniz.

Bellek denetimi

Daha önce, yalnızca Kapsam görünümünde env.memory ile gösterilen WebAssembly bellek nesnesini genişletebiliyordunuz. kullanılabilir. Bu yöntem bazı basit senaryolarda işe yaradı ancak ve verilerin yeniden yorumlanmasına izin vermemek, özellikle farklı biçimlerde olabilir. Bu yeni özelliğin, kullanıcılara doğrusal bellek denetleyici kullanmayı deneyin.

env.memory öğesini sağ tıklarsanız artık yeni bir Belleği incele adlı seçeneği görebilirsiniz:

Kapsam bölmesindeki &quot;env.memory&quot;, &quot;Belleği İncele&quot;nin gösterildiği içerik menüsü öğe

Tıklandığında, tarayıcı penceresinde bir Bellek Denetleyicisi açılır WebAssembly belleğini, onaltılık ve ASCII görünümlerinde inceleyebilirsiniz. belirli adreslere gitmenin yanı sıra, verilerinizi farklı biçimler:

Geliştirici Araçları&#39;ndaki, belleğin onaltılık ve ASCII görünümlerini gösteren Bellek Denetleyicisi bölmesi

Gelişmiş senaryolar ve uyarılar

WebAssembly kodunda profil oluşturma

Geliştirici Araçları'nı açtığınızda WebAssembly kodu "katmanlanır" dönüştürmek optimize edilmemiş sürümü tıklayın. Bu sürüm çok daha yavaş. Bu da console.time, performance.now özelliklerine güvenemeyeceğiniz anlamına gelir. ve diğer yöntemler de kodsuz olduğunda elde ettiğiniz sayılar gerçek dünya performansını temsil etmediğinden, mümkün değil.

Bunun yerine Geliştirici Araçları Performans panelini kullanmalısınız. Bu da kodu tam hızda çalıştırır ve size bir farklı fonksiyonlarda harcanan zamanın ayrıntılı dökümü:

Çeşitli Wasm işlevlerinin gösterildiği profil oluşturma paneli

Alternatif olarak, uygulamanızı Geliştirici Araçları kapalıyken çalıştırabilirsiniz. İşiniz bittiğinde Konsolu incelemek için bunları açın.

Gelecekte profil çıkarma senaryolarını geliştireceğiz, ancak şimdilik bir dikkat etmeniz gerekir. WebAssembly hakkında daha fazla bilgi edinmek isterseniz WebAssembly derleme ardışık düzeni ile ilgili dokümanlarımıza göz atın.

Farklı makinelerde (Docker / ana makine dahil) derleme ve hata ayıklama

Docker, sanal makine veya uzak derleme sunucusunda derleme yaparken kaynak dosyalara giden yolların belirli bir süre içinde oluşturma sırasında kullanılan yolların, kendi dosya sisteminizdeki çalıştığını fark edebilirsiniz. Bu durumda, dosyalar Kaynaklar paneli görünüyor, ancak yüklenemiyor.

Bu sorunu düzeltmek için C/C++ uzantı seçenekleri vardır. Bunu rastgele yolları ve hedefleri yeniden eşlemek için Geliştirici Araçları'nın kaynakları bulmasına yardımcı olabilirsiniz.

Örneğin, ana makinenizdeki proje bir yolun C:\src\my_project ancak şurada bir Docker container'ının içinde derlenmiştir: bu yol /mnt/c/src/my_project olarak temsil ediliyordu. Yeniden eşlemek için ön ek olarak belirterek bu yolları hata ayıklama sırasında geri alabilirsiniz:

C/C++ hata ayıklama uzantısının Seçenekler sayfası

Eşleşen ilk ön ek "kazanır". Diğer C++ öğelerine aşinaysanız bu seçenek set substitute-path komutuna benzerdir veya LLDB'de target.source-map ayarı yapın.

Optimize edilmiş derlemelerde hata ayıklama

Diğer dillerde olduğu gibi, hata ayıklama için optimizasyonlar devre dışı bırakıldı. Optimizasyonlar satır içi fonksiyonların bir başkasına satır içi olarak tekrar tekrar sıralanabilir veya kodun bir kısmını tamamen kaldırdığınızı fark edeceksiniz. Tüm bunlar, hata ayıklayıcının kafasını karıştırabilir ve sonuç olarak da kullanıcı olarak siz olabilirsiniz.

Daha sınırlı bir hata ayıklama deneyiminin sizin için sakıncası yoksa ve yine de hata ayıklamak istiyorsanız optimizasyonların çoğu ( satır içi işlevin hariç tutulması dışında) beklenenler. Kalan hizmet bedelini gidermeyi sorun ile karşı karşıya kalabilirsiniz. Ancak şimdilik -fno-inline kullanarak şu işlemleri yapabilirsiniz: Bu özelliği, -O düzeyindeki optimizasyonlarla derlerken devre dışı bırakın, örneğin:

emcc -g temp.c -o temp.html \
     -O3 -fno-inline

Hata ayıklama bilgilerini ayırma

Hata ayıklama bilgileri, kodunuzla ilgili birçok ayrıntıyı, türler, değişkenler, fonksiyonlar, kapsamlar ve konumlar gibi yardımcı olabilir. Sonuç olarak, genellikle daha fazla bilgi edineceksiniz.

WebAssembly modülünün yüklenmesini ve derlenmesini hızlandırmak için bu hata ayıklama bilgilerini farklı bir WebAssembly dosyası olarak kaydedebilirsiniz. Bunu Emscripten'de yapmak için-gseparate-dwarf=… istediğiniz bir dosya adına sahip olmanız gerekir:

emcc -g temp.c -o temp.html \
     -gseparate-dwarf=temp.debug.wasm

Bu durumda, ana uygulama yalnızca bir dosya adı saklar temp.debug.wasm ve yardımcı uzantı, Geliştirici Araçları'nı açtığınızda da yükleyebilirsiniz.

Bu özellik, yukarıda açıklanan gibi optimizasyonlarla birleştirildiğinde, neredeyse optimize edilmiş üretim yapılarını göndermek için bile oluşturup daha sonra yerel bir yan dosyayla hatalarını ayıklayabilirsiniz. Böyle durumlarda Ayrıca, uzantının yüklenmesinin daha kolay olması için depolanan URL'yi yan dosyayı bulun. Örneğin:

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]

Devam etmek için...

Vay canına, bir sürü yeni özellik sunduk.

Tüm bu yeni entegrasyonlarla Chrome Geliştirici Araçları, için değil, aynı zamanda C ve C++ uygulamaları için de güçlü, birçok farklı araçta yerleşik olarak bulunan uygulamaları kullanmak ve bunları paylaşılan, platformlar arası bir Web'e taşıma.

Ancak yolculuğumuz henüz sona ermedi. Değineceğimiz konulardan bazıları daha fazla bilgiye ihtiyacınız var:

  • Hata ayıklama deneyimindeki sorunlu kısımları temizleme.
  • Özel tür biçimlendiricileri için destek eklendi.
  • Daha iyi hale getirmek için WebAssembly uygulamaları için profil kaldırma.
  • Bulmayı kolaylaştırmak için kod kapsamı desteği eklendi değiştirilmemiş koda izin vermelidir.
  • Konsol değerlendirmesinde ifadeler için sağlanan desteği iyileştirme.
  • Daha fazla dil için destek eklendi.
  • …ve daha fazlası!

Bu arada, lütfen şu anki beta sürümünü kendi kodunuzda deneyip bulduğunuzu bildirerek bize yardımcı olun. sorunları https://bugs.chromium.org/p/chromium/issues/entry?template=DevTools+issue.

Önizleme kanallarını indirme

Varsayılan geliştirme tarayıcınız olarak Chrome Canary, Dev veya Beta'yı kullanabilirsiniz. Bu önizleme kanalları en yeni Geliştirici Araçları özelliklerine erişmenizi, son teknoloji ürünü web platformu API'lerini test etmenizi ve kullanıcılarınızdan önce sitenizdeki sorunları bulmanızı sağlar.

Chrome Geliştirici Araçları ekibiyle iletişim kurma

Yayındaki yeni özellikleri ve değişiklikleri ya da Geliştirici Araçları ile ilgili diğer her şeyi tartışmak için aşağıdaki seçenekleri kullanın.

  • Öneri veya geri bildirimlerinizi crbug.com adresinden bize iletebilirsiniz.
  • Geliştirici Araçları sorunlarını bildirmek için Diğer seçenekler'i Daha fazla > Yardım > Geliştirici Araçları'nda Geliştirici Araçları ile ilgili sorunları bildirin.
  • @ChromeDevTools adresinden tweet atabilirsiniz.
  • Geliştirici Araçları YouTube videoları veya Geliştirici Araçları ipuçları YouTube videolarına yorum yazın.