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://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.

Geçen seferkiyle aynı basit C örneğiyle 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 bir yapıştırma kodunda durur ancak sağ tarafta hatanın yığın izlemesini temsil eden bir Çağrı Yığını görünümü görebilirsiniz ve abort'yi çağıran orijinal C satırına gidebilirsiniz:

DevTools, &quot;assert_less&quot; işlevinde duraklatıldı ve Kapsam görünümünde &quot;x&quot; ve &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ğı:

DevTools, &quot;SDL_Init&quot; çağrısında 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üzün içine başka bir kesme noktası ayarlayalım ve biraz ileri atlamak için yürütmeyi devam ettirelim.

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

Bu noktada palette bazı rastgele renklerle doldurulmuştur. Hem dizinin kendisini hem de bağımsız SDL_Color yapılarını genişletip her şeyin iyi göründüğünü doğrulamak için bileşenlerini inceleyebiliriz (örneğin, "alpha" kanalının her zaman tam opaklığa ayarlandığından emin olabiliriz). 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++ ifadelerine adım atabilir veya adım atlayabilir ve diğer değişkenlerin nasıl değiştiğini gözlemleyebiliriz:

&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 temel hata ayıklama deneyiminde de bazı iyileştirmeler yaptık.

Öncelikle, daha önce ham WebAssembly hata ayıklama özelliğini kullandıysanız artık tüm kod ayrıştırmasının tek bir dosyada gösterildiğini fark edebilirsiniz. Artık wasm-53834e3e/ wasm-53834e3e-7 Kaynaklar girişinin hangi işleve karşılık geldiğini tahmin etmeniz gerekmez.

Yeni ad oluşturma şeması

Demonte 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.

Artık WebAssembly ad bölümündeki ipuçlarını, içe/dışa aktarma yollarını kullanarak ve diğer tüm yöntemler başarısız olursa $func123 gibi öğenin türüne ve dizine göre adları diğer disassembler araçlarına benzer şekilde oluşturuyoruz. Ş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 yer alır.

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şlevlerini gösteren 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 bir derleme sunucusunda derleme yaparken, derleme sırasında kullanılan kaynak dosyaların yollarının, Chrome DevTools'un çalıştığı kendi dosya sisteminizde bulunan yollarla eşleşmediği durumlarla karşılaşabilirsiniz. Bu durumda, dosyalar Kaynaklar panelinde gösterilir ancak yüklenemez.

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, işlevleri birbirine satır içi olarak yerleştirebilir, kodu yeniden sıralayabilir veya kod parçalarını tamamen kaldırabilir. Tüm bunların hata ayıklayıcıyı ve dolayısıyla kullanıcı olarak sizi şaşırtma olasılığı vardır.

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, kodunuz, tanımlanmış türler, değişkenler, işlevler, kapsamlar ve konumlar hakkında birçok ayrıntıyı (hata ayıklayıcı için yararlı olabilecek her şeyi) korur. 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.

Yukarıda açıklanan optimizasyonlarla birlikte kullanıldığında bu özellik, uygulamanızın neredeyse optimize edilmiş üretim derlemelerini göndermek ve daha sonra yerel taraftaki bir dosyayla bu derlemelerde hata ayıklama yapmak için bile kullanılabilir. 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.
  • Konsolda değerlendirme için ifadelere yönelik destek iyileştirildi.
  • 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://issues.chromium.org/issues/new?noWizard=true&amp;template=0&amp;component=1456350.

Önizleme kanallarını indirme

Varsayılan geliştirme tarayıcınız olarak Chrome Canary, Geliştirici veya Beta sürümünü 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.