خلال مؤتمر 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 ميغابايت. في حال time
أيضًا الأمر emcc
، سنلاحظ أنّ تشغيله على الجهاز يستغرق 1.5 ثانية تقريبًا. هذه الأرقام تجعل خط الأساس صغيرًا ولطيفًا، لكنها صغيرة جدًا على الأرجح لن يراقبها أحد. مع ذلك، في التطبيقات الحقيقية يمكن أن يصل حجم البرنامج الثنائي لتصحيح الأخطاء إلى غيغابايت ويستغرق بضع دقائق لإنشاءه.
تخطي Binaryen
عند إنشاء تطبيق Wasm باستخدام 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 وإعادة كتابة البرنامج الثنائي بشكل غير متوقع. وبهذه الطريقة، يمكننا التأكد من أننا نبقى على المسار السريع.
على الرغم من أن المثال الذي ذكرناه صغير إلى حد ما، لا يزال بإمكاننا رؤية تأثير تخطي Binaryen! وفقًا لـ time
، يتم تشغيل هذا الأمر لمدة أقل من ثانية واحدة بقليل، أي أسرع بنصف ثانية من ذي قبل.
التعديلات المتقدمة
تخطّي فحص ملف الإدخال
عند ربط مشروع Emscripten، عادةً ما يفحص emcc
كل ملفات ومكتبات عناصر الإدخال. وهو يفعل ذلك لتنفيذ اعتماديات دقيقة بين دوال مكتبة JavaScript والرموز الأصلية في برنامجك. وبالنسبة إلى المشاريع الأكبر حجمًا، يمكن أن يؤدي هذا الفحص الإضافي لملفات الإدخال (باستخدام llvm-nm
) إلى زيادة مدة الربط بشكل كبير.
ويمكن تشغيله بدلاً من ذلك باستخدام -sREVERSE_DEPS=all
الذي يشير إلى emcc
لتضمين جميع الاعتماديات الأصلية المحتملة لدوال JavaScript. هذا الرمز البرمجي صغير الحجم، ولكنّه يمكن أن يزيد من مدّة الربط، ويمكن أن يكون مفيدًا في إصدارات تصحيح الأخطاء.
بالنسبة لمشروع صغير مثل المثال الذي ذكرناه، لا يحدث فرق حقيقي ولكن إذا كان لديك المئات أو حتى الآلاف من ملفات الكائنات في مشروعك، فيمكن أن يحسن ذلك بشكل ملحوظ أوقات الربط.
إزالة القسم "name"
في المشاريع الكبيرة، خاصةً تلك التي تستخدم كثيرًا من نماذج C++ ، يمكن أن يكون قسم "name" في WebAssembly كبيرًا جدًا. في المثال الذي عرضناه، لا يشكّل هذا الرمز سوى جزء صغير من الحجم الإجمالي للملف (اطّلِع على نتائج llvm-objdump
أعلاه)، ولكن في بعض الحالات، قد يكون مهمًا للغاية. إذا كان قسم "name" في تطبيقك كبيرًا جدًا، وكانت معلومات تصحيح الأخطاء القزمة كافية لتلبية احتياجات تصحيح الأخطاء، فمن المفيد إزالة قسم "name":
$ emstrip --no-strip-all --remove-section=name mandelbrot.wasm
سيؤدي ذلك إلى إزالة قسم "اسم" WebAssembly مع الاحتفاظ بأقسام تصحيح أخطاء 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
النصّ المختصر: ما هي ميزة استخدام انشطار تصحيح الأخطاء؟
وهناك مزايا عديدة لتقسيم معلومات تصحيح الأخطاء إذا كان أحدها يعمل مع تطبيقات كبيرة:
الربط بشكل أسرع: لم يعد الرابط بحاجة إلى تحليل معلومات تصحيح الأخطاء بالكامل عادة ما تحتاج الروابط إلى تحليل بيانات DWARF الموجودة في البرنامج الثنائي بالكامل. تتعامل برامج الربط مع الملفات الثنائية الأصغر حجمًا، ما يؤدي إلى حدوث أوقات ربط أسرع (خاصةً في التطبيقات الكبيرة الحجم)، وذلك من خلال إزالة أجزاء كبيرة من معلومات تصحيح الأخطاء في ملفات منفصلة.
تصحيح الأخطاء بشكل أسرع: يمكن لبرنامج تصحيح الأخطاء تخطّي تحليل الرموز الإضافية في ملفات
.dwo
/.dwp
لإجراء بعض عمليات البحث عن الرموز. بالنسبة إلى بعض عمليات البحث (مثل الطلبات المتعلقة بتخطيط الخط لملفات Wasm-to-C++ )، لا نحتاج إلى الاطّلاع على بيانات تصحيح الأخطاء الإضافية. وهذا يوفر لنا الوقت، ولا نحتاج إلى تحميل بيانات تصحيح الأخطاء الإضافية وتحليلها.
1: إذا لم يكن لديك إصدار حديث من llvm-objdump
على نظامك، وكنت تستخدم emsdk
، يمكنك العثور عليه في الدليل emsdk/upstream/bin
.
تنزيل قنوات المعاينة
يمكنك استخدام Chrome كناري أو إصدار مطوّري البرامج أو الإصدار التجريبي من المتصفِّح التلقائي للتطوير. وتتيح لك قنوات المعاينة هذه الوصول إلى أحدث ميزات "أدوات مطوري البرامج" واختبار أحدث واجهات برمجة التطبيقات للأنظمة الأساسية للويب والعثور على المشاكل على موقعك الإلكتروني قبل أن يفعلها المستخدمون.
التواصل مع فريق "أدوات مطوري البرامج في Chrome"
استخدِم الخيارات التالية لمناقشة الميزات والتغييرات الجديدة في المشاركة أو مناقشة أي معلومات أخرى متعلّقة بأدوات مطوري البرامج.
- يمكنك إرسال اقتراح أو ملاحظات إلينا عبر crbug.com.
- الإبلاغ عن مشكلة في "أدوات مطوري البرامج" باستخدام خيارات إضافية > مساعدة > الإبلاغ عن مشاكل في "أدوات مطوري البرامج" في "أدوات مطوري البرامج"
- يمكنك نشر تغريدة على @ChromeDevTools.
- شارِك في التعليقات على الميزات الجديدة في فيديوهات YouTube أو نصائح حول أدوات مطوّري البرامج فيديوهات YouTube.