ใน 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 MB และข้อมูลส่วนใหญ่นั้นก็คือข้อมูลการแก้ไขข้อบกพร่อง คุณสามารถยืนยันข้อมูลนี้ได้ด้วยเครื่องมือ 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 MB จากไฟล์ขนาด 3 MB หากเราtime
คําสั่ง emcc
ด้วย เราจะเห็นว่าเครื่องใช้เวลาประมาณ 1.5 วินาทีในการเรียกใช้ ตัวเลขเหล่านี้เป็นเกณฑ์พื้นฐานที่ดี แต่มีจำนวนน้อยมากจนอาจไม่มีใครสนใจ อย่างไรก็ตาม ในแอปพลิเคชันจริง ไฟล์ไบนารีสำหรับการแก้ไขข้อบกพร่องอาจมีขนาดใหญ่ถึง GB และใช้เวลาสร้างหลายนาที
ข้าม Binaryen
เมื่อสร้างแอปพลิเคชัน WASM ด้วย Emscripten ขั้นตอนสุดท้ายในการสร้างแอปพลิเคชันอย่างหนึ่งคือเรียกใช้เครื่องมือเพิ่มประสิทธิภาพ Binaryen Binaryen เป็นชุดเครื่องมือคอมไพเลอร์ที่ทั้งเพิ่มประสิทธิภาพและทำให้ไบนารี WebAssembly (หรือที่คล้ายกัน) เป็นไปตามข้อกำหนดทางกฎหมาย การใช้ Binaryen เป็นส่วนหนึ่งของบิลด์นั้นค่อนข้างแพง แต่ต้องใช้ในบางเงื่อนไขเท่านั้น สำหรับบิลด์แก้ไขข้อบกพร่อง เราจะเร่งเวลาบิลด์ได้อย่างมากหากไม่ต้องใช้การผ่าน Binaryen พาส Binaryen ที่จําเป็นโดยทั่วไปที่สุดมีไว้เพื่อทำให้ลายเซ็นฟังก์ชันที่เกี่ยวข้องกับค่าจำนวนเต็ม 64 บิตถูกต้อง การเลือกเข้าร่วมการผสานรวม BigInt ของ WebAssembly โดยใช้ -sWASM_BIGINT
จะช่วยหลีกเลี่ยงปัญหานี้ได้
$ emcc -sUSE_SDL=2 -g -O0 -o mandelbrot.html mandelbrot.cc -sALLOW_MEMORY_GROWTH -sWASM_BIGINT -sERROR_ON_WASM_CHANGES_AFTER_LINK
เราได้เพิ่ม Flag -sERROR_ON_WASM_CHANGES_AFTER_LINK
ไว้ด้วย ซึ่งจะช่วยตรวจจับเมื่อ Binaryen ทำงานอยู่และเขียนไบนารีใหม่โดยไม่คาดคิด วิธีนี้จะช่วยให้เราดำเนินการได้อย่างรวดเร็ว
แม้ว่าตัวอย่างของเราจะมีขนาดเล็ก แต่เรายังคงเห็นผลของการข้าม Binaryen time
แจ้งว่าคําสั่งนี้ทํางานได้ภายในเวลาไม่ถึง 1 วินาที เร็วขึ้นครึ่งวินาทีจากเดิม
การปรับแต่งขั้นสูง
การข้ามการสแกนไฟล์อินพุต
โดยปกติแล้ว เมื่อลิงก์โปรเจ็กต์ Emscripten emcc
จะสแกนไฟล์ออบเจ็กต์และไลบรารีอินพุตทั้งหมด การดำเนินการนี้เพื่อให้ใช้ Dependency ที่แม่นยำระหว่างฟังก์ชันของไลบรารี JavaScript กับสัญลักษณ์เนทีฟในโปรแกรมได้ สำหรับโปรเจ็กต์ขนาดใหญ่ การสแกนไฟล์อินพุตเพิ่มเติมนี้ (โดยใช้ llvm-nm
) อาจทำให้เวลาลิงก์นานขึ้นอย่างมาก
คุณอาจเรียกใช้ด้วย -sREVERSE_DEPS=all
แทนได้ ซึ่งจะบอกให้ emcc
รวมข้อกําหนดเบื้องต้นแบบเนทีฟที่เป็นไปได้ทั้งหมดของฟังก์ชัน JavaScript การดำเนินการนี้มีโอเวอร์เฮดขนาดโค้ดเล็กน้อย แต่ช่วยเพิ่มความเร็วในการลิงก์และมีประโยชน์สำหรับบิลด์แก้ไขข้อบกพร่อง
สำหรับโปรเจ็กต์ขนาดเล็กอย่างในตัวอย่างของเรา การดำเนินการนี้จะไม่มีความแตกต่างมากนัก แต่หากคุณมีไฟล์ออบเจ็กต์หลายร้อยหรือหลายพันไฟล์ในโปรเจ็กต์ การดำเนินการนี้จะช่วยปรับปรุงเวลาลิงก์ได้อย่างมาก
การตัดส่วน "ชื่อ"
ในโปรเจ็กต์ขนาดใหญ่ โดยเฉพาะโปรเจ็กต์ที่มีการใช้เทมเพลต C++ จำนวนมาก ส่วน "ชื่อ" ของ WebAssembly อาจมีขนาดค่อนข้างใหญ่ ในตัวอย่างของเรา ไฟล์มีเพียงส่วนเล็กๆ ของขนาดไฟล์โดยรวม (ดูเอาต์พุตของ llvm-objdump
ด้านบน) แต่ในบางกรณี ไฟล์อาจมีขนาดมาก หากส่วน "ชื่อ" ของแอปพลิเคชันมีขนาดใหญ่มาก และข้อมูลการแก้ไขข้อบกพร่องของ DWARF เพียงพอต่อความต้องการในการแก้ไขข้อบกพร่อง คุณอาจได้ประโยชน์จากการถอดส่วน "ชื่อ" ออก ดังนี้
$ emstrip --no-strip-all --remove-section=name mandelbrot.wasm
ซึ่งจะตัดส่วน "ชื่อ" ของ WebAssembly ออกขณะที่เก็บส่วนแก้ไขข้อบกพร่อง DWARF ไว้
การแยกส่วนการแก้ไขข้อบกพร่อง
ไฟล์ไบนารีที่มีข้อมูลการแก้ไขข้อบกพร่องจำนวนมากไม่เพียงแต่จะเพิ่มเวลาในการบิลด์เท่านั้น แต่ยังเพิ่มเวลาในการแก้ไขข้อบกพร่องด้วย โปรแกรมแก้ไขข้อบกพร่องต้องโหลดข้อมูลและสร้างดัชนีสําหรับข้อมูลดังกล่าว เพื่อให้ตอบคําค้นหาได้อย่างรวดเร็ว เช่น "ตัวแปร x ประเภทใด"
การแยกการแก้ไขข้อบกพร่องช่วยให้เราแยกข้อมูลการแก้ไขข้อบกพร่องของไบนารีออกเป็น 2 ส่วนได้ โดย 1 ส่วนจะยังคงอยู่ในไบนารี และอีก 1 ส่วนจะอยู่ในไฟล์ออบเจ็กต์ DWARF (.dwo
) แยกต่างหาก ซึ่งเปิดใช้ได้โดยการส่ง Flag -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
เรามีไฟล์ต้นฉบับเพียงไฟล์เดียว แต่โดยทั่วไปแล้วโปรเจ็กต์จะมีขนาดใหญ่กว่านี้และมีไฟล์มากกว่า 1 ไฟล์ การแยกข้อบกพร่องจะสร้างไฟล์ .dwo
ให้กับข้อบกพร่องแต่ละรายการ เพื่อให้โปรแกรมแก้ไขข้อบกพร่องเวอร์ชันเบต้าปัจจุบัน (0.1.6.1615) โหลดข้อมูลการแก้ไขข้อบกพร่องแบบแยกนี้ได้ เราจำเป็นต้องรวมข้อมูลทั้งหมดไว้ในสิ่งที่เรียกว่าแพ็กเกจ DWARF (.dwp
) ดังนี้
$ emdwp -e mandelbrot.wasm -o mandelbrot.dwp
การสร้างแพ็กเกจ DWARF จากออบเจ็กต์แต่ละรายการมีข้อดีตรงที่คุณต้องแสดงไฟล์เพิ่มเพียงไฟล์เดียวเท่านั้น ขณะนี้เรากำลังดำเนินการโหลดแต่ละออบเจ็กต์ทั้งหมดในรุ่นที่จะเปิดตัวในอนาคต
DWARF 5 คืออะไร
คุณอาจสังเกตเห็นว่าเราได้ใส่ Flag อื่นลงในคําสั่ง emcc
ด้านบน -gdwarf-5
การเปิดใช้สัญลักษณ์ DWARF เวอร์ชัน 5 ซึ่งปัจจุบันไม่ใช่ค่าเริ่มต้นเป็นอีกวิธีหนึ่งที่จะช่วยให้เราเริ่มแก้ไขข้อบกพร่องได้เร็วขึ้น ซึ่งจะเก็บข้อมูลบางอย่างไว้ในไบนารีหลักที่เวอร์ชัน 4 เริ่มต้นละเว้นไว้ กล่าวโดยละเอียดคือ เราระบุชุดไฟล์ต้นฉบับทั้งหมดได้จากไฟล์ไบนารีหลักเพียงไฟล์เดียว ซึ่งจะช่วยให้โปรแกรมแก้ไขข้อบกพร่องดำเนินการพื้นฐานต่างๆ ได้ เช่น แสดงลําดับชั้นซอร์สโค้ดทั้งหมดและตั้งจุดหยุดชั่วคราวโดยไม่ต้องโหลดและแยกวิเคราะห์ข้อมูลสัญลักษณ์ทั้งหมด ซึ่งทำให้การแก้ไขข้อบกพร่องด้วยสัญลักษณ์แยกเร็วขึ้นมาก เราจึงใช้แฟล็กบรรทัดคำสั่ง -gsplit-dwarf
และ -gdwarf-5
ร่วมกันเสมอ
รูปแบบการแก้ไขข้อบกพร่อง DWARF5 ยังช่วยให้เราเข้าถึงฟีเจอร์ที่มีประโยชน์อีกอย่างหนึ่งด้วย โดยจะเพิ่มดัชนีชื่อในข้อมูลการแก้ไขข้อบกพร่องที่จะสร้างขึ้นเมื่อส่งผ่าน Flag -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
สำหรับการค้นหาสัญลักษณ์บางรายการ สำหรับการค้นหาบางอย่าง (เช่น คำขอเกี่ยวกับการแมปบรรทัดของไฟล์ Wasm กับ C++) เราไม่จำเป็นต้องตรวจสอบข้อมูลการแก้ไขข้อบกพร่องเพิ่มเติม วิธีนี้ช่วยประหยัดเวลาของเราได้โดยไม่ต้องโหลดและแยกวิเคราะห์ข้อมูลการแก้ไขข้อบกพร่องเพิ่มเติม
1: หากไม่มี llvm-objdump
เวอร์ชันล่าสุดในระบบและใช้ emsdk
อยู่ คุณจะเห็นไฟล์ดังกล่าวในไดเรกทอรี emsdk/upstream/bin
ดาวน์โหลดแชแนลตัวอย่าง
ลองใช้ Chrome Canary, Dev หรือ เบต้า เป็นเบราว์เซอร์สำหรับนักพัฒนาซอฟต์แวร์เริ่มต้น ช่องทางเวอร์ชันตัวอย่างเหล่านี้จะช่วยให้คุณเข้าถึงฟีเจอร์ล่าสุดของ DevTools, ทดสอบ API ของแพลตฟอร์มเว็บที่ล้ำสมัย และช่วยคุณค้นหาปัญหาในเว็บไซต์ได้ก่อนที่ผู้ใช้จะพบ
ติดต่อทีมเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome
ใช้ตัวเลือกต่อไปนี้เพื่อพูดคุยเกี่ยวกับฟีเจอร์ใหม่ การอัปเดต หรือสิ่งอื่นๆ ที่เกี่ยวข้องกับเครื่องมือสำหรับนักพัฒนาเว็บ
- ส่งความคิดเห็นและคำขอฟีเจอร์ถึงเราได้ที่ crbug.com
- รายงานปัญหาเกี่ยวกับเครื่องมือสำหรับนักพัฒนาเว็บโดยใช้ ตัวเลือกเพิ่มเติม > ความช่วยเหลือ > รายงานปัญหาเกี่ยวกับเครื่องมือสำหรับนักพัฒนาเว็บในเครื่องมือสำหรับนักพัฒนาเว็บ
- ทวีตถึง @ChromeDevTools
- แสดงความคิดเห็นในวิดีโอ YouTube เกี่ยวกับข่าวสารใน DevTools หรือวิดีโอ YouTube เกี่ยวกับเคล็ดลับใน DevTools