Binaryen เป็นไลบรารีโครงสร้างพื้นฐานของคอมไพเลอร์และ Toolchain สำหรับ WebAssembly ซึ่งเขียนด้วย C++ โดยมีจุดมุ่งหมายเพื่อทำให้การคอมไพล์ไปยัง WebAssembly นั้นใช้งานง่าย รวดเร็ว และมีประสิทธิภาพ ในโพสต์นี้ จะใช้ตัวอย่างภาษาของเล่นสังเคราะห์ที่ชื่อ ExampleScript เรียนรู้วิธีเขียนโมดูล WebAssembly ใน JavaScript โดยใช้ API ของ Binaryen.js คุณจะพูดถึงพื้นฐานการสร้างโมดูล การเพิ่มฟังก์ชันในโมดูล และการส่งออกฟังก์ชันจากโมดูล ซึ่งจะให้ความรู้เกี่ยวกับกลไกโดยรวมของการรวบรวมภาษาโปรแกรมจริงลงใน WebAssembly นอกจากนี้ คุณยังจะได้เรียนรู้วิธีเพิ่มประสิทธิภาพโมดูล Wasm ทั้งด้วย Binaryen.js และในบรรทัดคำสั่งด้วย wasm-opt
ความเป็นมาเกี่ยวกับไบนารี
ไบนารีมี C API ที่ใช้งานง่ายในส่วนหัวเดียว และใช้จาก JavaScript ได้ด้วย โดยจะยอมรับอินพุตในแบบฟอร์ม WebAssembly แต่ก็ยอมรับกราฟโฟลว์การควบคุมทั่วไปสำหรับคอมไพเลอร์ที่ต้องการด้วย
ตัวแทนระดับกลาง (IR) คือโครงสร้างหรือโค้ดข้อมูลที่ใช้ภายในโดยคอมไพเลอร์หรือเครื่องเสมือนเพื่อแสดงซอร์สโค้ด IR ภายในของ Binaryen ใช้โครงสร้างข้อมูลแบบกะทัดรัดและออกแบบมาเพื่อการสร้างและเพิ่มประสิทธิภาพโค้ดแบบขนานแท้ โดยใช้แกน CPU ที่มีอยู่ทั้งหมด IR ของ Binaryen จะคอมไพล์เป็น WebAssembly เนื่องจากเป็นส่วนย่อยของ WebAssembly
เครื่องมือเพิ่มประสิทธิภาพของ Binaryen มีบัตรผ่านจำนวนมากที่ช่วยปรับปรุงขนาดและความเร็วของโค้ดได้ การเพิ่มประสิทธิภาพเหล่านี้มีเป้าหมายเพื่อทำให้ Binaryen มีประสิทธิภาพเพียงพอที่จะใช้เป็นแบ็กเอนด์ของคอมไพเลอร์ด้วยตัวเอง ซึ่งรวมถึงการเพิ่มประสิทธิภาพเฉพาะสำหรับ WebAssembly (ซึ่งคอมไพเลอร์สำหรับวัตถุประสงค์ทั่วไปอาจไม่ทำ) ซึ่งคุณมองว่าเป็นการลดขนาด Wasm ได้
AssemblyScript ในฐานะผู้ใช้ตัวอย่างของ Binaryen
โปรเจ็กต์จำนวนมากใช้ไบนารี เช่น AssemblyScript ซึ่งใช้ไบนารีสำหรับคอมไพล์จากภาษาที่คล้ายกับ TypeScript ไปยัง WebAssembly โดยตรง ลองใช้ตัวอย่างนี้ในสนามเด็กเล่น AssemblyScript
อินพุต AssemblyScript:
export function add(a: i32, b: i32): i32 {
return a + b;
}
โค้ด WebAssembly ที่เกี่ยวข้องในรูปแบบข้อความที่สร้างโดยไบนารีน์:
(module
(type $0 (func (param i32 i32) (result i32)))
(memory $0 0)
(export "add" (func $module/add))
(export "memory" (memory $0))
(func $module/add (param $0 i32) (param $1 i32) (result i32)
local.get $0
local.get $1
i32.add
)
)
ห่วงโซ่เครื่องมือของไบนารี
ห่วงโซ่เครื่องมือของ Binaryen มีเครื่องมือที่มีประโยชน์จำนวนมากสำหรับทั้งนักพัฒนาซอฟต์แวร์ JavaScript และผู้ใช้บรรทัดคำสั่ง ชุดย่อยของเครื่องมือดังกล่าวจะแสดงอยู่ในรายการต่อไปนี้ โดยรายการเครื่องมือทั้งหมดที่มีอยู่จะอยู่ในไฟล์ README
ของโปรเจ็กต์
binaryen.js
: ไลบรารี JavaScript แบบสแตนด์อโลนที่แสดงเมธอดแบบไบนารีสำหรับการสร้างและเพิ่มประสิทธิภาพโมดูล Wasm สำหรับบิลด์ โปรดดู binaryen.js บน npm (หรือดาวน์โหลดจาก GitHub หรือ unpkg โดยตรง)wasm-opt
: เครื่องมือบรรทัดคำสั่งที่โหลด WebAssembly และเรียกใช้ส่งผ่าน Binaryen IRwasm-as
และwasm-dis
: เครื่องมือบรรทัดคำสั่งที่ประกอบและแยกชิ้นส่วน WebAssemblywasm-ctor-eval
: เครื่องมือบรรทัดคำสั่งที่ดำเนินการกับฟังก์ชัน (หรือบางส่วนของฟังก์ชัน) ในเวลาคอมไพล์ได้wasm-metadce
: เครื่องมือบรรทัดคำสั่งเพื่อนำส่วนต่างๆ ของไฟล์ Wasm ออกด้วยวิธีที่ยืดหยุ่น ซึ่งขึ้นอยู่กับวิธีการใช้โมดูลwasm-merge
: เครื่องมือบรรทัดคำสั่งที่ผสานไฟล์ Wasm หลายไฟล์เข้าด้วยกันเป็นไฟล์เดียว เชื่อมต่อการนำเข้าที่เกี่ยวข้องกับการส่งออกเช่นเดียวกับที่ทำได้ เหมือนกับ Bundler สำหรับ JavaScript แต่สำหรับ Wasm
กำลังคอมไพล์ไปยัง WebAssembly
การคอมไพล์ภาษาหนึ่งเป็นอีกภาษาหนึ่งมักจะประกอบด้วยหลายขั้นตอน โดยขั้นตอนที่สำคัญที่สุดจะแสดงอยู่ในรายการต่อไปนี้
- การวิเคราะห์เชิงวิเคราะห์: แบ่งซอร์สโค้ดออกเป็นโทเค็น
- การวิเคราะห์ไวยากรณ์: สร้างแผนผังไวยากรณ์นามธรรม
- การวิเคราะห์เชิงความหมาย: ตรวจสอบข้อผิดพลาดและบังคับใช้กฎภาษา
- การสร้างโค้ดขั้นกลาง: สร้างการนำเสนอที่เป็นนามธรรมมากขึ้น
- การสร้างโค้ด: แปลเป็นภาษาเป้าหมาย
- การเพิ่มประสิทธิภาพโค้ดเฉพาะเป้าหมาย: เพิ่มประสิทธิภาพเพื่อเป้าหมาย
ในโลกของ Unix เครื่องมือสำหรับการคอมไพล์ที่ใช้บ่อยได้แก่ lex
และ yacc
lex
(Lexical Analysisr Generator):lex
เป็นเครื่องมือที่สร้างนักวิเคราะห์คำศัพท์ โดยใช้ชุดนิพจน์ทั่วไปและการทำงานที่เกี่ยวข้องเป็นอินพุต แล้วสร้างโค้ดสำหรับเครื่องมือวิเคราะห์คำศัพท์ที่จดจำรูปแบบในซอร์สโค้ดของอินพุตyacc
(แต่คอมไพเลอร์อีกตัวหนึ่ง):yacc
เป็นเครื่องมือที่สร้างตัวแยกวิเคราะห์สำหรับการวิเคราะห์ไวยากรณ์ ใช้คำอธิบายไวยากรณ์อย่างเป็นทางการของภาษาโปรแกรมเป็นอินพุต และสร้างโค้ดสำหรับโปรแกรมแยกวิเคราะห์ โดยทั่วไปโปรแกรมแยกวิเคราะห์จะสร้างแผนผังไวยากรณ์นามธรรม (AST) ที่แสดงโครงสร้างลำดับชั้นของซอร์สโค้ด
ตัวอย่างที่ใช้งานได้
ขอบเขตของโพสต์นี้ครอบคลุมภาษาโปรแกรมทั้งหมดไม่ได้เลย ดังนั้นเพื่อความง่าย ให้ลองพิจารณาภาษาโปรแกรมสังเคราะห์ที่มีจำกัดและไร้ประโยชน์ชื่อ ExampleScript ซึ่งทำงานโดยแสดงการดำเนินการทั่วไปผ่านตัวอย่างที่เป็นรูปธรรม
- หากต้องการเขียนฟังก์ชัน
add()
คุณจะต้องเขียนโค้ดตัวอย่างของการเพิ่ม เช่น2 + 3
- หากต้องการเขียนฟังก์ชัน
multiply()
คุณต้องเขียน เช่น6 * 12
ตามคำเตือนล่วงหน้า ไม่มีประโยชน์โดยสิ้นเชิง แต่เรียบง่ายพอที่นักวิเคราะห์คำศัพท์จะใช้นิพจน์ทั่วไปเดียวได้ นั่นคือ /\d+\s*[\+\-\*\/]\s*\d+\s*/
ต่อไปจะต้องใช้โปรแกรมแยกวิเคราะห์ จริงๆ แล้ว คุณสามารถสร้างโครงสร้างไวยากรณ์นามธรรมที่เรียบง่ายมากได้โดยใช้นิพจน์ทั่วไปที่มีแคปเจอร์กรุ๊ปที่มีชื่อ ดังนี้
/(?<first_operand>\d+)\s*(?<operator>[\+\-\*\/])\s*(?<second_operand>\d+)/
คำสั่ง ExampleScript คือ 1 รายการต่อบรรทัด โปรแกรมแยกวิเคราะห์จึงประมวลผลโค้ดได้ในแต่ละบรรทัดโดยการแยกอักขระในบรรทัดใหม่ ซึ่งก็เพียงพอสำหรับการดู 3 ขั้นตอนแรกจากรายการหัวข้อย่อยก่อนหน้านี้ ซึ่งได้แก่ การวิเคราะห์คำศัพท์ การวิเคราะห์ไวยากรณ์ และการวิเคราะห์เชิงความหมาย โค้ดสำหรับขั้นตอนเหล่านี้ อยู่ในรายการต่อไปนี้
export default class Parser {
parse(input) {
input = input.split(/\n/);
if (!input.every((line) => /\d+\s*[\+\-\*\/]\s*\d+\s*/gm.test(line))) {
throw new Error('Parse error');
}
return input.map((line) => {
const { groups } =
/(?<first_operand>\d+)\s*(?<operator>[\+\-\*\/])\s*(?<second_operand>\d+)/gm.exec(
line,
);
return {
firstOperand: Number(groups.first_operand),
operator: groups.operator,
secondOperand: Number(groups.second_operand),
};
});
}
}
การสร้างโค้ดระดับกลาง
ตอนนี้โปรแกรม ExampleScript สามารถแสดงเป็นแผนผังไวยากรณ์เชิงนามธรรมได้ (แม้ว่าจะเป็นโปรแกรมที่ค่อนข้างเรียบง่าย) ขั้นตอนถัดไปคือการสร้างตัวแทนขั้นกลางที่เป็นนามธรรม ขั้นตอนแรกคือสร้างโมดูลใหม่ในไบนารี
const module = new binaryen.Module();
แผนผังไวยากรณ์แต่ละบรรทัดประกอบด้วย firstOperand
, operator
และ secondOperand
3 ตัว สำหรับโอเปอเรเตอร์ที่เป็นไปได้แต่ละค่าใน ExampleScript ซึ่งก็คือ +
, -
, *
, /
ต้องเพิ่มฟังก์ชันใหม่ลงในโมดูลด้วยเมธอด Module#addFunction()
ของไบนารี พารามิเตอร์ของเมธอด Module#addFunction()
มีดังนี้
name
:string
แสดงชื่อของฟังก์ชันfunctionType
:Signature
แสดงถึงลายเซ็นของฟังก์ชันvarTypes
:Type[]
ระบุถึงท้องถิ่นเพิ่มเติมตามลำดับที่ระบุbody
:Expression
, เนื้อหาของฟังก์ชัน
มีรายละเอียดเพิ่มเติมเพื่อคลายเครียดและแจกแจงรายละเอียด ส่วนเอกสารประกอบของไบนารีจะช่วยให้คุณไปยังส่วนต่างๆ ของพื้นที่ทำงานได้ แต่สุดท้ายแล้ว สำหรับโอเปอเรเตอร์ +
ของ ExampleScript คุณจะพบว่าเมธอด Module#i32.add()
เป็นหนึ่งในการดำเนินการจำนวนเต็มที่มีอยู่หลายรายการ
การบวกต้องมีตัวถูกดำเนินการ 2 ตัว นั่นคือผลรวมแรกและผลรวมที่สอง หากต้องการให้ฟังก์ชันเรียกใช้ได้จริง จะต้องส่งออกด้วย Module#addFunctionExport()
module.addFunction(
'add', // name: string
binaryen.createType([binaryen.i32, binaryen.i32]), // params: Type
binaryen.i32, // results: Type
[binaryen.i32], // vars: Type[]
// body: ExpressionRef
module.block(null, [
module.local.set(
2,
module.i32.add(
module.local.get(0, binaryen.i32),
module.local.get(1, binaryen.i32),
),
),
module.return(module.local.get(2, binaryen.i32)),
]),
);
module.addFunctionExport('add', 'add');
หลังจากประมวลผลแผนผังไวยากรณ์นามธรรมแล้ว โมดูลจะประกอบด้วย 4 เมธอด โดย 3 เมธอดคือ add()
อิงตาม Module#i32.add()
, subtract()
โดยอิงตาม Module#i32.sub()
, multiply()
โดยอิงตาม
Module#i32.mul()
และค่าผิดปกติ divide()
ที่อิงตาม Module#f64.div()
เนื่องจาก ExampleScript ทํางานกับผลลัพธ์ที่เป็นทศนิยมได้ด้วย
for (const line of parsed) {
const { firstOperand, operator, secondOperand } = line;
if (operator === '+') {
module.addFunction(
'add', // name: string
binaryen.createType([binaryen.i32, binaryen.i32]), // params: Type
binaryen.i32, // results: Type
[binaryen.i32], // vars: Type[]
// body: ExpressionRef
module.block(null, [
module.local.set(
2,
module.i32.add(
module.local.get(0, binaryen.i32),
module.local.get(1, binaryen.i32)
)
),
module.return(module.local.get(2, binaryen.i32)),
])
);
module.addFunctionExport('add', 'add');
} else if (operator === '-') {
module.subtractFunction(
// Skipped for brevity.
)
} else if (operator === '*') {
// Skipped for brevity.
}
// And so on for all other operators, namely `-`, `*`, and `/`.
หากคุณจัดการกับฐานของโค้ดจริง บางครั้งอาจมีโค้ดที่ใช้งานไม่ได้ซึ่งจะไม่มีการเรียกใช้เลย วิธีการนำโค้ดที่ไม่มีการทำงานมาใช้จริง (ซึ่งจะได้รับการเพิ่มประสิทธิภาพและนำออกในขั้นตอนต่อๆ ไป) ในตัวอย่างที่เรียกใช้การคอมไพล์ของ ExampleScript ไปยัง Wasm โดยการเพิ่มฟังก์ชันที่ไม่ได้ส่งออกจะทำหน้าที่นี้
// This function is added, but not exported,
// so it's effectively dead code.
module.addFunction(
'deadcode', // name: string
binaryen.createType([binaryen.i32, binaryen.i32]), // params: Type
binaryen.i32, // results: Type
[binaryen.i32], // vars: Type[]
// body: ExpressionRef
module.block(null, [
module.local.set(
2,
module.i32.div_u(
module.local.get(0, binaryen.i32),
module.local.get(1, binaryen.i32),
),
),
module.return(module.local.get(2, binaryen.i32)),
]),
);
คอมไพเลอร์ใกล้พร้อมใช้งานแล้ว ไม่จำเป็นอย่างยิ่งแต่แนวทางปฏิบัติที่ดีในการตรวจสอบโมดูลด้วยเมธอด Module#validate()
if (!module.validate()) {
throw new Error('Validation error');
}
การได้รับรหัส Wasm ที่ได้
ในการรับโค้ด Wasm ที่ได้ จะมี 2 วิธีในไบนารีสำหรับการรับการแสดงข้อความเป็นไฟล์ .wat
ใน S-expression เป็นรูปแบบที่มนุษย์อ่านได้ และการแสดงไบนารีเป็นไฟล์ .wasm
ที่เรียกใช้ในเบราว์เซอร์ได้โดยตรง โค้ดไบนารีสามารถเรียกใช้
ในเบราว์เซอร์ได้โดยตรง หากต้องการดูว่าได้ผลหรือไม่ การบันทึกข้อมูลส่งออกสามารถช่วยได้
const textData = module.emitText();
console.log(textData);
const wasmData = module.emitBinary();
const compiled = new WebAssembly.Module(wasmData);
const instance = new WebAssembly.Instance(compiled, {});
console.log('Wasm exports:\n', instance.exports);
การแสดงข้อความที่สมบูรณ์สำหรับโปรแกรม ExampleScript พร้อมการดำเนินการทั้ง 4 อย่างมีดังนี้ ดูว่าโค้ดเสียหายยังคงอยู่ได้อย่างไร
แต่จะไม่มีการเปิดเผยโค้ดดังกล่าวตามภาพหน้าจอของ
WebAssembly.Module.exports()
(module
(type $0 (func (param i32 i32) (result i32)))
(type $1 (func (param f64 f64) (result f64)))
(export "add" (func $add))
(export "subtract" (func $subtract))
(export "multiply" (func $multiply))
(export "divide" (func $divide))
(func $add (param $0 i32) (param $1 i32) (result i32)
(local $2 i32)
(local.set $2
(i32.add
(local.get $0)
(local.get $1)
)
)
(return
(local.get $2)
)
)
(func $subtract (param $0 i32) (param $1 i32) (result i32)
(local $2 i32)
(local.set $2
(i32.sub
(local.get $0)
(local.get $1)
)
)
(return
(local.get $2)
)
)
(func $multiply (param $0 i32) (param $1 i32) (result i32)
(local $2 i32)
(local.set $2
(i32.mul
(local.get $0)
(local.get $1)
)
)
(return
(local.get $2)
)
)
(func $divide (param $0 f64) (param $1 f64) (result f64)
(local $2 f64)
(local.set $2
(f64.div
(local.get $0)
(local.get $1)
)
)
(return
(local.get $2)
)
)
(func $deadcode (param $0 i32) (param $1 i32) (result i32)
(local $2 i32)
(local.set $2
(i32.div_u
(local.get $0)
(local.get $1)
)
)
(return
(local.get $2)
)
)
)
การเพิ่มประสิทธิภาพ WebAssembly
ไบนารีมี 2 วิธีในการเพิ่มประสิทธิภาพโค้ด Wasm โดยอันแรกคือ Binaryen.js ส่วนอีกแบบหนึ่ง สำหรับบรรทัดคำสั่ง การตั้งค่าแบบแรกจะใช้ชุดกฎการเพิ่มประสิทธิภาพมาตรฐานโดยค่าเริ่มต้น และให้คุณตั้งค่าการเพิ่มประสิทธิภาพ และระดับการเพิ่มประสิทธิภาพ และกฎถัดมาโดยค่าเริ่มต้นจะใช้ชุดกฎต่างๆ ได้โดยไม่ต้องใช้กฎ แต่จะปรับแต่งได้อย่างเต็มที่แทน ซึ่งหมายความว่าเมื่อมีการทดสอบเพียงพอแล้ว คุณจะปรับแต่งการตั้งค่าเพื่อให้ได้ผลลัพธ์ที่ดีที่สุดตามโค้ดของคุณได้
การเพิ่มประสิทธิภาพด้วย Binaryen.js
วิธีที่ง่ายที่สุดในการเพิ่มประสิทธิภาพโมดูล Wasm ด้วยไบนารีคือการเรียกเมธอด Module#optimize()
ของ Binaryen.js โดยตรง และอาจตั้งค่าระดับการเพิ่มประสิทธิภาพและระดับการย่อ (ไม่บังคับ) ด้วย
// Assume the `wast` variable contains a Wasm program.
const module = binaryen.parseText(wast);
binaryen.setOptimizeLevel(2);
binaryen.setShrinkLevel(1);
// This corresponds to the `-Os` setting.
module.optimize();
การดำเนินการดังกล่าวจะนำโค้ดที่ใช้งานไม่ได้ซึ่งเกิดขึ้นก่อนหน้านี้ออกไป ดังนั้นการแสดงข้อความของตัวอย่างของเล่น ExampleScript เวอร์ชัน Wasm จึงไม่มีโค้ดดังกล่าวอีกต่อไป นอกจากนี้ โปรดทราบว่าเรานำคู่ local.set/get
ออกด้วยขั้นตอนการเพิ่มประสิทธิภาพ
SimplifyLocals
(การเพิ่มประสิทธิภาพเบ็ดเตล็ดที่เกี่ยวข้องกับท้องถิ่น) และเครื่องดูดฝุ่น
(นำโค้ดที่ไม่จำเป็นอย่างชัดเจนออก) และ
RemoveUnusedBrs
จะนำช่วงพักออกจากสถานที่ที่ไม่จำเป็น)return
(module
(type $0 (func (param i32 i32) (result i32)))
(type $1 (func (param f64 f64) (result f64)))
(export "add" (func $add))
(export "subtract" (func $subtract))
(export "multiply" (func $multiply))
(export "divide" (func $divide))
(func $add (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
(i32.add
(local.get $0)
(local.get $1)
)
)
(func $subtract (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
(i32.sub
(local.get $0)
(local.get $1)
)
)
(func $multiply (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
(i32.mul
(local.get $0)
(local.get $1)
)
)
(func $divide (; has Stack IR ;) (param $0 f64) (param $1 f64) (result f64)
(f64.div
(local.get $0)
(local.get $1)
)
)
)
มีบัตรผ่านการเพิ่มประสิทธิภาพหลายรายการ และ Module#optimize()
ก็ใช้การตั้งค่าการเพิ่มประสิทธิภาพและลดขนาดชุดเริ่มต้นของระดับนั้นๆ หากต้องการปรับแต่งทั้งหมด คุณต้องใช้เครื่องมือบรรทัดคำสั่ง wasm-opt
การเพิ่มประสิทธิภาพด้วยเครื่องมือบรรทัดคำสั่ง Wasm-opt
ไบนารีจะมีเครื่องมือบรรทัดคำสั่ง wasm-opt
เพื่อปรับแต่งบัตรที่ใช้ได้ทั้งหมด หากต้องการดูรายการตัวเลือกการเพิ่มประสิทธิภาพที่เป็นไปได้ทั้งหมด โปรดดูข้อความช่วยเหลือของเครื่องมือ เครื่องมือ wasm-opt
น่าจะเป็นเครื่องมือที่ได้รับความนิยมสูงสุด และมีการใช้งานโดยชุดเครื่องมือคอมไพเลอร์จำนวนมากเพื่อเพิ่มประสิทธิภาพโค้ด Wasm ซึ่งรวมถึง Emscripten,
J2CL,
Kotlin/Wasm,
dart2wasm,
wasm-pack และอื่นๆ
wasm-opt --help
เพื่อให้คุณได้สัมผัสถึงบัตรผ่านต่างๆ ต่อไปนี้คือข้อความที่ตัดตอนมาบางส่วนซึ่งสามารถเข้าใจได้หากไม่มีความรู้จากผู้เชี่ยวชาญ
- CodeFolding: หลีกเลี่ยงการใช้โค้ดซ้ำกันด้วยการผสานรวม (เช่น หาก
if
2 แขนมีวิธีการแชร์ในตอนท้าย) - DeadArgumentElimination: ลิงก์การเพิ่มประสิทธิภาพเวลาเพื่อนำอาร์กิวเมนต์ออกจากฟังก์ชัน หากมีการเรียกด้วยค่าคงที่เดียวกันเสมอ
- MinifyImportsAndExports: ลดขนาดเป็น
"a"
"b"
- DeadCodeElimination: นำโค้ดที่ใช้งานไม่ได้ออก
เรามีตำราอาหารในการเพิ่มประสิทธิภาพพร้อมเคล็ดลับหลายอย่างในการระบุ Flag ต่างๆ ที่สำคัญและควรลองใช้ก่อน ตัวอย่างเช่น บางครั้งการเรียกใช้ wasm-opt
ซ้ำๆ จะลดขนาดอินพุตลงอีก ในกรณีดังกล่าว การเรียกใช้ที่มี --converge
จะเป็นการทำซ้ำจนกว่าจะไม่มีการเพิ่มประสิทธิภาพเพิ่มเติมและเกิดขึ้นจนถึงจุดที่ตายตัว
ข้อมูลประชากร
หากต้องการดูแนวคิดที่นำมาใช้จริงในโพสต์นี้ ให้ทดลองเล่นในการสาธิตแบบฝังซึ่งระบุอินพุต ExampleScript ที่คุณนึกออก และโปรดดูซอร์สโค้ดของเดโม
บทสรุป
Binaryen มีชุดเครื่องมือที่มีประสิทธิภาพสำหรับการคอมไพล์ภาษาลงใน WebAssembly และเพิ่มประสิทธิภาพโค้ดที่ได้ ไลบรารี JavaScript และเครื่องมือบรรทัดคำสั่ง มีความยืดหยุ่นและใช้งานง่าย โพสต์นี้แสดงหลักการสำคัญของการรวบรวม Wasm ซึ่งเน้นถึงประสิทธิภาพและศักยภาพของไบนารีในการเพิ่มประสิทธิภาพสูงสุด แม้ว่าตัวเลือกจำนวนมากสำหรับการปรับแต่งการเพิ่มประสิทธิภาพของ Binaryen ต้องใช้ความรู้เชิงลึกเกี่ยวกับการทำงานภายในของ Wasm แต่โดยปกติแล้ว การตั้งค่าเริ่มต้นจะใช้งานได้ดีอยู่แล้ว เมื่อได้การรวบรวมแล้ว ก็ขอให้สนุกกับการรวบรวม และเพิ่มประสิทธิภาพด้วยไบนารี
ข้อความแสดงการยอมรับ
โพสต์นี้ได้รับการตรวจสอบโดย Alon Zakai, Thomas Lively และ Rachel Andrew