در Chrome Dev Summit 2020 ، ما برای اولین بار پشتیبانی از اشکال زدایی Chrome را برای برنامه های WebAssembly در وب به نمایش گذاشتیم. از آن زمان، تیم انرژی زیادی را برای ایجاد مقیاس تجربه توسعهدهنده برای برنامههای کاربردی بزرگ و حتی بزرگ سرمایهگذاری کرده است. در این پست دستگیره هایی را که در ابزارهای مختلف اضافه کرده ایم (یا کار کرده ایم) و نحوه استفاده از آنها را به شما نشان خواهیم داد!
اشکال زدایی مقیاس پذیر
بیایید از جایی که در پست 2020 خود را ترک کردیم ادامه دهیم. در اینجا مثالی است که در آن زمان به آن نگاه می کردیم:
#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();
}
این هنوز یک نمونه نسبتا کوچک است و احتمالاً هیچ یک از مشکلات واقعی را که در یک برنامه واقعاً بزرگ می بینید، نخواهید دید، اما ما همچنان می توانیم ویژگی های جدید را به شما نشان دهیم. راه اندازی سریع و آسان و تلاش برای خودتان!
در آخرین پست، نحوه کامپایل و اشکال زدایی این مثال را مورد بحث قرار دادیم. بیایید دوباره این کار را انجام دهیم، اما اجازه دهید نگاهی هم به //performance// بیندازیم:
$ emcc -sUSE_SDL=2 -g -O0 -o mandelbrot.html mandelbrot.cc -sALLOW_MEMORY_GROWTH
این دستور یک باینری wasm 3 مگابایتی تولید می کند. و بخش عمده ای از آن، همانطور که ممکن است انتظار داشته باشید، اطلاعات اشکال زدایی است. برای مثال میتوانید این را با ابزار llvm-objdump
[1] تأیید کنید:
$ 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
این خروجی تمام بخش هایی را که در فایل wasm تولید شده هستند به ما نشان می دهد، اکثر آنها بخش های WebAssembly استاندارد هستند، اما چندین بخش سفارشی نیز وجود دارد که نام آنها با .debug_
شروع می شود. اینجاست که باینری حاوی اطلاعات اشکال زدایی ماست! اگر همه اندازه ها را جمع کنیم، می بینیم که اطلاعات اشکال زدایی تقریباً 2.3 مگابایت از فایل 3 مگابایتی ما را تشکیل می دهد. اگر دستور emcc
را نیز time
کنیم، می بینیم که در دستگاه ما تقریباً 1.5 ثانیه اجرا شده است. این اعداد یک پایه کوچک خوب ایجاد می کنند، اما آنقدر کوچک هستند که احتمالاً هیچ کس به آنها توجهی نمی کند. با این حال، در برنامه های واقعی، باینری اشکال زدایی به راحتی می تواند به اندازه گیگابایت برسد و ساخت آن چند دقیقه طول می کشد!
پرش باینرین
هنگام ساخت یک برنامه wam با Emscripten ، یکی از مراحل ساخت نهایی آن اجرای بهینه ساز Binaryen است. Binaryen یک جعبه ابزار کامپایلر است که باینری های WebAssembly(مانند) را هم بهینه می کند و هم قانونی می کند. اجرای Binaryen به عنوان بخشی از ساخت، نسبتاً گران است، اما فقط تحت شرایط خاصی مورد نیاز است. برای ساختهای اشکالزدایی، اگر از نیاز به پاسهای Binaryen اجتناب کنیم، میتوانیم زمان ساخت را به میزان قابل توجهی افزایش دهیم. متداولترین پاس مورد نیاز Binaryen برای قانونی کردن امضاهای تابع شامل مقادیر صحیح 64 بیتی است. با انتخاب ادغام WebAssembly BigInt با استفاده از -sWASM_BIGINT
می توانیم از این امر جلوگیری کنیم.
$ emcc -sUSE_SDL=2 -g -O0 -o mandelbrot.html mandelbrot.cc -sALLOW_MEMORY_GROWTH -sWASM_BIGINT -sERROR_ON_WASM_CHANGES_AFTER_LINK
برای اندازه گیری خوب، پرچم -sERROR_ON_WASM_CHANGES_AFTER_LINK
را به کار انداخته ایم. این کمک می کند تا زمانی که Binaryen در حال اجرا است و به طور غیرمنتظره ای باینری را بازنویسی می کند. به این ترتیب، میتوانیم مطمئن شویم که در مسیر سریع باقی میمانیم.
اگرچه مثال ما نسبتاً کوچک است، اما هنوز هم میتوانیم اثر پرش باینرین را ببینیم! طبق time
، این دستور کمتر از 1 ثانیه اجرا می شود، بنابراین نیم ثانیه سریعتر از قبل!
ترفندهای پیشرفته
رد شدن از اسکن فایل ورودی
معمولاً هنگام پیوند دادن یک پروژه Emscripten، emcc
تمام فایلها و کتابخانههای شی ورودی را اسکن میکند. این کار را به منظور پیاده سازی وابستگی های دقیق بین توابع کتابخانه جاوا اسکریپت و نمادهای بومی در برنامه شما انجام می دهد. برای پروژه های بزرگتر، این اسکن اضافی فایل های ورودی (با استفاده از llvm-nm
) می تواند به میزان قابل توجهی به زمان پیوند اضافه کند.
در عوض میتوان با -sREVERSE_DEPS=all
اجرا کرد که به emcc
میگوید تمام وابستگیهای بومی توابع جاوا اسکریپت را شامل شود. این حجم کد کوچکی دارد اما می تواند زمان پیوند را سرعت بخشد و برای ساخت اشکال زدایی مفید باشد.
برای پروژهای به کوچکی مثال ما، این تفاوت واقعی ندارد، اما اگر صدها یا حتی هزاران فایل شی در پروژه خود داشته باشید، میتواند به طور معناداری زمان پیوند را بهبود بخشد.
حذف بخش "نام".
در پروژههای بزرگ، بهویژه پروژههایی که از الگوی C++ زیاد استفاده میکنند، بخش WebAssembly «نام» میتواند بسیار بزرگ باشد. در مثال ما این فقط کسری کوچک از اندازه کلی فایل است (به خروجی llvm-objdump
در بالا مراجعه کنید) اما در برخی موارد می تواند بسیار مهم باشد. اگر بخش "نام" برنامه شما بسیار بزرگ است و اطلاعات اشکال زدایی کوتوله برای نیازهای اشکال زدایی شما کافی است، حذف بخش "نام" می تواند مفید باشد:
$ emstrip --no-strip-all --remove-section=name mandelbrot.wasm
این کار بخش WebAssembly "name" را از بین می برد و در عین حال بخش های اشکال زدایی DWARF را حفظ می کند.
شکافت اشکال زدایی
باینری ها با داده های اشکال زدایی زیاد نه تنها بر زمان ساخت بلکه بر زمان اشکال زدایی نیز فشار وارد می کنند. دیباگر باید داده ها را بارگیری کند و باید یک شاخص برای آن بسازد تا بتواند به سرعت به پرس و جوهایی مانند "نوع متغیر محلی x چیست؟" پاسخ دهد.
شکافت اشکالزدایی به ما امکان میدهد اطلاعات اشکالزدایی یک باینری را به دو بخش تقسیم کنیم: یکی، که در باینری باقی میماند، و یکی، که در یک فایل جداگانه به نام شی DWARF ( .dwo
) موجود است. می توان آن را با ارسال پرچم -gsplit-dwarf
به Emscripten فعال کرد:
$ 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
در زیر، دستورات مختلف و فایلهایی را نشان میدهیم که با کامپایل بدون دادههای دیباگ، با دادههای اشکالزدایی، و در نهایت با دادههای دیباگ و شکافت اشکالزدایی تولید میشوند.
هنگام تقسیم داده های DWARF، بخشی از داده های اشکال زدایی همراه با باینری قرار می گیرد، در حالی که بخش بزرگی در فایل mandelbrot.dwo
قرار می گیرد (همانطور که در بالا نشان داده شده است).
برای mandelbrot
ما فقط یک فایل منبع داریم، اما به طور کلی پروژه ها بزرگتر از این هستند و شامل بیش از یک فایل هستند. شکافت اشکال زدایی یک فایل .dwo
برای هر یک از آنها ایجاد می کند. برای اینکه نسخه بتای فعلی اشکالزدا (0.1.6.1615) بتواند این اطلاعات اشکالزدایی تقسیمشده را بارگیری کند، باید همه آنها را در بستهای به اصطلاح DWARF ( .dwp
) جمع کنیم:
$ emdwp -e mandelbrot.wasm -o mandelbrot.dwp
ساختن پکیج DWARF از بین اشیاء مجزا این مزیت را دارد که شما فقط باید یک فایل اضافی را ارائه دهید! ما در حال حاضر در حال کار بر روی بارگیری تمام اشیاء مجزا در نسخه بعدی هستیم.
DWARF 5 چه خبر؟
ممکن است متوجه شده باشید، ما یک پرچم دیگر را به دستور emcc
بالا، -gdwarf-5
مخفی کردیم. فعال کردن نسخه 5 نمادهای DWARF که در حال حاضر پیش فرض نیست، ترفند دیگری است که به ما کمک می کند تا اشکال زدایی را سریعتر شروع کنیم. با آن، اطلاعات خاصی در باینری اصلی ذخیره می شود که نسخه پیش فرض 4 آن را حذف کرده است. به طور خاص، ما می توانیم مجموعه کامل فایل های منبع را فقط از باینری اصلی تعیین کنیم. این به دیباگر اجازه می دهد تا اقدامات اساسی مانند نمایش درخت منبع کامل و تعیین نقاط شکست بدون بارگیری و تجزیه داده های نماد کامل انجام دهد. این امر اشکال زدایی با نمادهای تقسیم را بسیار سریعتر می کند، بنابراین ما همیشه از پرچم های خط فرمان -gsplit-dwarf
و -gdwarf-5
با هم استفاده می کنیم!
با فرمت اشکال زدایی DWARF5 به یکی دیگر از ویژگی های مفید نیز دسترسی پیدا می کنیم. این یک فهرست نام را در داده های اشکال زدایی معرفی می کند که هنگام عبور پرچم -gpubnames
ایجاد می شود:
$ 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
در طول یک جلسه اشکال زدایی، جستجوی نماد اغلب با جستجوی یک موجودیت با نام انجام می شود، به عنوان مثال، هنگام جستجوی یک متغیر یا یک نوع. نمایه نام با اشاره مستقیم به واحد کامپایل که آن نام را تعریف می کند، این جستجو را تسریع می کند. بدون فهرست نام، یک جستجوی جامع در کل داده های اشکال زدایی برای یافتن واحد کامپایل صحیحی که موجودیت نامگذاری شده مورد نظر ما را تعریف می کند، مورد نیاز است.
برای افراد کنجکاو: نگاه کردن به داده های اشکال زدایی
شما می توانید llvm-dwarfdump
برای نگاه کردن به داده های DWARF استفاده کنید. بیایید این را امتحان کنیم:
llvm-dwarfdump mandelbrot.wasm
این به ما یک نمای کلی در مورد "واحدهای کامپایل" (به طور کلی، فایلهای منبع) که اطلاعات اشکال زدایی آنها را داریم، میدهد. در این مثال، ما فقط اطلاعات اشکال زدایی mandelbrot.cc
را داریم. اطلاعات عمومی به ما اطلاع میدهد که ما یک واحد اسکلت داریم، که فقط به این معنی است که ما دادههای ناقص روی این فایل داریم، و یک فایل .dwo
جداگانه وجود دارد که حاوی اطلاعات اشکالزدایی باقی مانده است:
همچنین می توانید به جداول دیگر این فایل نگاهی بیندازید، به عنوان مثال در جدول خط که نگاشت بایت کد wasm به خطوط C++ را نشان می دهد (سعی کنید از llvm-dwarfdump -debug-line
استفاده کنید).
همچنین میتوانیم به اطلاعات اشکالزدایی که در فایل .dwo
جداگانه موجود است نگاهی بیندازیم:
llvm-dwarfdump mandelbrot.dwo
TL;DR: مزیت استفاده از شکافت اشکال زدایی چیست؟
اگر کسی با برنامه های کاربردی بزرگ کار می کند، چندین مزیت برای تقسیم اطلاعات اشکال زدایی وجود دارد:
پیوند سریعتر: پیوند دهنده دیگر نیازی به تجزیه کل اطلاعات اشکال زدایی ندارد . پیوند دهنده ها معمولاً نیاز دارند کل داده های DWARF را که در باینری هستند تجزیه کنند. با حذف بخشهای بزرگی از اطلاعات اشکالزدایی در فایلهای جداگانه، پیونددهندهها با باینریهای کوچکتر سروکار دارند، که منجر به زمانهای پیوند سریعتر میشود (مخصوصاً برای برنامههای بزرگ صادق است).
اشکالزدایی سریعتر: اشکالزدا میتواند از تجزیه نمادهای اضافی در فایلهای
.dwo
/.dwp
برای برخی جستجوهای نماد صرفنظر کند . برای برخی جستجوها (مانند درخواستهای مربوط به نگاشت خط فایلهای wam-to-C++)، نیازی به بررسی دادههای دیباگ اضافی نداریم. این باعث صرفه جویی در وقت ما می شود و نیازی به بارگیری و تجزیه داده های دیباگ اضافی نیست.
1 : اگر نسخه اخیر llvm-objdump
را روی سیستم خود ندارید و از emsdk
استفاده می کنید، می توانید آن را در پوشه emsdk/upstream/bin
پیدا کنید.
کانال های پیش نمایش را دانلود کنید
استفاده از Chrome Canary ، Dev یا Beta را به عنوان مرورگر توسعه پیشفرض خود در نظر بگیرید. این کانالهای پیشنمایش به شما امکان دسترسی به جدیدترین ویژگیهای DevTools را میدهند، به شما اجازه میدهند APIهای پلتفرم وب پیشرفته را آزمایش کنید و به شما کمک میکنند تا قبل از کاربران، مشکلات سایت خود را پیدا کنید!
با تیم Chrome DevTools در تماس باشید
از گزینههای زیر برای بحث در مورد ویژگیهای جدید، بهروزرسانیها یا هر چیز دیگری مربوط به DevTools استفاده کنید.
- بازخورد و درخواست های ویژگی را برای ما در crbug.com ارسال کنید.
- یک مشکل DevTools را با استفاده از گزینه های بیشتر > راهنما > گزارش مشکل DevTools در DevTools گزارش کنید.
- توییت در @ChromeDevTools .
- نظرات خود را در مورد موارد جدید در ویدیوهای DevTools YouTube یا DevTools Tips ویدیوهای YouTube بگذارید.