การคอมไพล์และเพิ่มประสิทธิภาพ Wasm ด้วยไบนารี

Binaryen เป็นคอมไพเลอร์และ Toolchain ไลบรารีโครงสร้างพื้นฐานสำหรับ WebAssembly ที่เขียนด้วย C++ ซึ่งมีเป้าหมายเพื่อสร้าง การคอมไพล์ไปยัง WebAssembly ที่ใช้งานง่าย รวดเร็ว และมีประสิทธิภาพ ในโพสต์นี้ การใช้แท็ก เรียนรู้วิธีเขียนภาษาของเล่นสังเคราะห์ที่ชื่อ ExampleScript โมดูล WebAssembly ใน JavaScript ที่ใช้ API แบบ Binaryen.js คุณจะพูดถึง พื้นฐานในการสร้างโมดูล การเพิ่มฟังก์ชันในโมดูล และการส่งออก จากโมดูล ซึ่งจะให้ความรู้เกี่ยวกับ กลไกการรวบรวมภาษาโปรแกรมจริงไปยัง WebAssembly นอกจากนั้น คุณจะได้เรียนรู้วิธีเพิ่มประสิทธิภาพโมดูล Wasm ทั้งด้วย Branchen.js และใน บรรทัดคำสั่งด้วย wasm-opt

ความเป็นมาเกี่ยวกับไบนารีเลน

ไบนารีมีฟังก์ชัน C API ในส่วนหัวเดียว และสามารถ ที่ใช้จาก JavaScript ยอมรับอินพุตใน แบบฟอร์ม WebAssembly แต่ยังยอมรับ โฟลว์กราฟการควบคุม สำหรับคอมไพเลอร์ที่ต้องการ

ตัวแทนระดับกลาง (IR) คือโครงสร้างข้อมูลหรือโค้ดที่ใช้ โดยคอมไพเลอร์หรือเครื่องเสมือนเพื่อแสดงถึงซอร์สโค้ด ไบนารีเลน IR ภายในใช้โครงสร้างข้อมูลที่กะทัดรัดและออกแบบมาเพื่อให้ขนานกันโดยสมบูรณ์ การสร้างและเพิ่มประสิทธิภาพโค้ด โดยใช้แกน CPU ที่มีอยู่ทั้งหมด IR ของไบนารี คอมไพล์ลงใน WebAssembly เนื่องจากเป็นส่วนย่อยของ WebAssembly

เครื่องมือเพิ่มประสิทธิภาพของ Branchen มีบัตรผ่านจำนวนมากที่ช่วยปรับปรุงขนาดและความเร็วของโค้ดได้ เหล่านี้ การเพิ่มประสิทธิภาพมีเป้าหมายเพื่อทำให้ไบนารีมีศักยภาพเพียงพอที่จะใช้เป็นคอมไพเลอร์ แบ็กเอนด์ของตัวเอง ซึ่งรวมถึงการเพิ่มประสิทธิภาพเฉพาะสำหรับ WebAssembly ( คอมไพเลอร์อเนกประสงค์อาจไม่สามารถทำได้) ซึ่งคุณอาจมองว่าเป็น Wasm ก็ได้ การลดขนาด

AssemblyScript ในฐานะผู้ใช้ตัวอย่างของ Branchen

หลายโปรเจ็กต์ใช้ไบนารี เช่น AssemblyScript ซึ่งใช้ไบนารีเพื่อ คอมไพล์จากภาษาเหมือน TypeScript ไปยัง WebAssembly โดยตรง ลองดูตัวอย่าง ในสนามเด็กเล่น AssemblyScript

อินพุต AssemblyScript:

export function add(a: i32, b: i32): i32 {
  return a + b;
}

โค้ด WebAssembly ที่เกี่ยวข้องในรูปแบบข้อความที่สร้างโดย Branchen:

(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
 )
)

สนามเด็กเล่น AssemblyScript ที่แสดงโค้ด WebAssembly ที่สร้างขึ้นตามตัวอย่างก่อนหน้านี้

เครื่องมือเชนของไบนารี

เครื่องมือเชน Binen มีเครื่องมือที่มีประโยชน์มากมายสำหรับทั้ง JavaScript นักพัฒนาซอฟต์แวร์และผู้ใช้บรรทัดคำสั่ง โดยเครื่องมือเหล่านี้บางส่วนจะแสดงอยู่ในส่วน การติดตาม เวลา รายการเครื่องมือที่มีอยู่ทั้งหมด มีอยู่ในไฟล์ README ของโปรเจ็กต์

  • binaryen.js: ไลบรารี JavaScript แบบสแตนด์อโลนที่แสดงเมธอดแบบไบนารี สำหรับ การสร้างและเพิ่มประสิทธิภาพโมดูล Wasm สำหรับบิลด์ โปรดดู binaryen.js บน npm (หรือดาวน์โหลดโดยตรงจาก GitHub หรือ unpkg)
  • wasm-opt: เครื่องมือบรรทัดคำสั่งที่โหลด WebAssembly และเรียกใช้ไบนารี IR ส่งต่อ
  • wasm-as และ wasm-dis: เครื่องมือบรรทัดคำสั่งที่ใช้ประกอบและถอดแยกชิ้นส่วน WebAssembly
  • wasm-ctor-eval: เครื่องมือบรรทัดคำสั่งที่สามารถเรียกใช้ฟังก์ชัน (หรือส่วนต่างๆ ของ ) ในเวลาคอมไพล์
  • wasm-metadce: เครื่องมือบรรทัดคำสั่งเพื่อนำส่วนต่างๆ ของไฟล์ Wasm ออกในแบบยืดหยุ่น ทั้งนี้ขึ้นอยู่กับวิธีการใช้โมดูล
  • wasm-merge: เครื่องมือบรรทัดคำสั่งที่รวมไฟล์ Wasm หลายไฟล์ให้เป็นไฟล์เดียว แล้วเชื่อมต่อการนำเข้าที่เกี่ยวข้องกับการส่งออก ชอบ Bundler สำหรับ JavaScript แต่สำหรับ Wasm

กำลังคอมไพล์ไปยัง WebAssembly

การรวบรวมภาษาหนึ่งเป็นอีกภาษาหนึ่ง มักมีหลายขั้นตอน รายการที่สำคัญจะแสดงอยู่ในรายการต่อไปนี้

  • การวิเคราะห์แบบยืดหยุ่น: แบ่งซอร์สโค้ดออกเป็นโทเค็น
  • การวิเคราะห์ไวยากรณ์: สร้างแผนผังไวยากรณ์นามธรรม
  • การวิเคราะห์เชิงความหมาย: ตรวจหาข้อผิดพลาดและบังคับใช้กฎด้านภาษา
  • การสร้างโค้ดขั้นกลาง: สร้างการนำเสนอแบบนามธรรมมากขึ้น
  • การสร้างโค้ด: แปลเป็นภาษาเป้าหมาย
  • การเพิ่มประสิทธิภาพโค้ดเฉพาะเป้าหมาย: เพิ่มประสิทธิภาพสำหรับเป้าหมาย

ในโลก Unix เครื่องมือที่ใช้บ่อยในการคอมไพล์คือ lex และ yacc:

  • lex (Lexical Analyzer Generator): lex เป็นเครื่องมือที่สร้างคลังศัพท์ โปรแกรมวิเคราะห์ หรือเรียกอีกชื่อหนึ่งว่า lexers หรือเครื่องมือสแกน ต้องใช้ชุดค่าปกติ นิพจน์และการดำเนินการที่เกี่ยวข้องเป็นอินพุต และสร้างโค้ดสำหรับ เครื่องมือวิเคราะห์คำศัพท์ที่จดจำรูปแบบในซอร์สโค้ดของอินพุต
  • 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 สามารถแสดงเป็นโครงสร้างไวยากรณ์นามธรรมได้ (แม้ว่าจะค่อนข้างเรียบง่าย) ขั้นตอนถัดไปคือการสร้างนามธรรม ตัวแทนระดับกลาง ขั้นตอนแรกคือ สร้างโมดูลใหม่ใน Branchen

const module = new binaryen.Module();

แต่ละบรรทัดของโครงสร้างไวยากรณ์นามธรรมจะมีสามบรรทัดที่ประกอบด้วย firstOperand, operator และ secondOperand สำหรับแต่ละตัวเลือก 4 อย่างที่เป็นไปได้ โอเปอเรเตอร์ใน ExampleScript ซึ่งก็คือ +, -, *, / ต้องเพิ่มฟังก์ชันลงในโมดูล ด้วยเมธอด Module#addFunction() ของไบนารี พารามิเตอร์ของ Module#addFunction() เมธอดมีดังนี้

  • name: string ใช้แทนชื่อของฟังก์ชัน
  • functionType: Signature หมายถึงลายเซ็นของฟังก์ชัน
  • varTypes: Type[] หมายถึงท้องถิ่นเพิ่มเติมตามลำดับที่ระบุ
  • body: Expression, เนื้อหาของฟังก์ชัน

มีรายละเอียดเพิ่มเติมส่วนหนึ่ง ของการผ่อนคลายและเจาะลึก เอกสารประกอบเกี่ยวกับไบนารี ช่วยคุณไปยังส่วนต่างๆ ของพื้นที่ทำงานได้ แต่ท้ายที่สุดแล้วสำหรับ + ของ ExampleScript คุณจะถูกนำมาที่เมธอด Module#i32.add() ในฐานะที่เป็นหนึ่งใน พร้อมใช้งาน การดำเนินการจำนวนเต็ม การบวกต้องใช้ตัวถูกดำเนินการ 2 ตัว คือตัวบวกแรกและตัวที่ 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 วิธีใน Branchen ในการรับ การนำเสนอด้วยข้อความ เป็นไฟล์ .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)
  )
 )
)

ภาพหน้าจอของคอนโซล DevTools ของการส่งออกโมดูล WebAssembly ที่แสดงฟังก์ชัน 4 อย่าง ได้แก่ บวก หาร คูณ และลบออก (แต่ไม่ใช่โค้ดที่ใช้งานไม่ได้)

การเพิ่มประสิทธิภาพ WebAssembly

ไบนารีมี 2 วิธีในการเพิ่มประสิทธิภาพโค้ด Wasm หนึ่งใน Binaryen.js เอง และ สำหรับบรรทัดคำสั่ง ประเภทแรกใช้ชุดการเพิ่มประสิทธิภาพมาตรฐาน โดยค่าเริ่มต้น และทำให้คุณสามารถตั้งค่าการเพิ่มประสิทธิภาพ ระดับการย่อขนาด และ โดยค่าเริ่มต้นจะไม่ใช้กฎใดๆ แต่อนุญาตให้ปรับแต่งได้อย่างเต็มที่ ซึ่งหมายความว่าเมื่อมีการทดสอบเพียงพอแล้ว คุณจะปรับแต่งการตั้งค่าสำหรับ ผลลัพธ์ที่ดีที่สุดตามโค้ดของคุณ

การเพิ่มประสิทธิภาพด้วย Branchen.js

วิธีที่ง่ายที่สุดในการเพิ่มประสิทธิภาพโมดูล Wasm โดยใช้ Branchen คือ เรียกใช้เมธอด Module#optimize() ของ Branchen.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();

การดำเนินการดังกล่าวจะลบโค้ดที่ใช้งานไม่ได้ซึ่งถูกนำไปใช้งานจริงก่อนหน้านี้ ดังนั้น การนำเสนอแบบข้อความในเวอร์ชัน Wasm ของตัวอย่างของเล่น ExampleScript ไม่ อีกต่อไป โปรดทราบด้วยว่าจะนำคู่ local.set/get ออกอย่างไร ขั้นตอนการเพิ่มประสิทธิภาพ SimplifyLocals (การเพิ่มประสิทธิภาพอื่นๆ ที่เกี่ยวข้องกับท้องถิ่น) และ เครื่องดูดฝุ่น (นำโค้ดที่ไม่จำเป็นอย่างเห็นได้ชัดออก) และ return จะถูกนำออกโดย RemoveUnusedBrs (นำช่วงพักออกจากสถานที่ที่ไม่จำเป็น)

 (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

สำหรับการปรับแต่งบัตรที่ต้องการใช้ได้อย่างเต็มรูปแบบ Branchen ได้รวม เครื่องมือบรรทัดคำสั่ง wasm-opt หากต้องการ รายการตัวเลือกการเพิ่มประสิทธิภาพที่เป็นไปได้ทั้งหมด ให้ตรวจสอบข้อความช่วยเหลือของเครื่องมือ เครื่องมือ wasm-opt น่าจะได้รับความนิยมมากที่สุด เครื่องมือเหล่านี้และใช้โดยเครื่องมือคอมไพเลอร์หลายๆ เชนเพื่อเพิ่มประสิทธิภาพโค้ด Wasm รวมถึง Emscripten J2CL Kotlin/Wasm dart2wasm wasm-pack และอื่นๆ

wasm-opt --help

เพื่อให้คุณเข้าใจเกี่ยวกับบัตรผ่าน นี่คือข้อความบางส่วนที่ตัดตอนมาจาก จะเข้าใจได้หากไม่มีความรู้ของผู้เชี่ยวชาญ:

  • CodeFolding: หลีกเลี่ยงการใช้โค้ดซ้ำโดยการรวมโค้ดดังกล่าว (เช่น หาก 2 if จะมีวิธีการที่ใช้ร่วมกันในตอนท้าย)
  • DeadArgumentElimination: บัตรผ่านการเพิ่มประสิทธิภาพเวลาของลิงก์เพื่อนำอาร์กิวเมนต์ออก ลงในฟังก์ชันหากมีการเรียกด้วยค่าคงที่เดียวกันเสมอ
  • MinifyImportsAndExports: ลดขนาดไฟล์เป็น "a", "b"
  • DeadCodeElimination: นำโค้ดที่ใช้งานไม่ได้ออก

มี สูตรการเพิ่มประสิทธิภาพ พร้อมให้เคล็ดลับหลายประการในการระบุว่า การรายงานใดมีมากกว่า ทั้งสำคัญและคุ้มค่าที่จะทดลองก่อน ตัวอย่างเช่น บางครั้งเรียกใช้ wasm-opt ซ้ำแล้วซ้ำอีกจะทำให้อินพุตมีขนาดเล็กลง ในกรณีดังกล่าว การเรียกใช้ พร้อมด้วย --converge Flag ดำเนินการซ้ำไปเรื่อยๆ จนกว่าจะไม่มีการเพิ่มประสิทธิภาพเพิ่มเติมเกิดขึ้น ถึง แล้ว

สาธิต

ถ้าต้องการดูการทำงานจริงของแนวคิดในโพสต์นี้ ให้ลองเล่นด้วยแท็กแบบฝัง สาธิตโดยให้อินพุต ExampleScript ที่คุณนึกได้ นอกจากนี้ อย่าลืม ดูซอร์สโค้ดของการสาธิต

บทสรุป

Branchen มีชุดเครื่องมือที่มีประสิทธิภาพสำหรับการรวบรวมภาษาไปยัง WebAssembly และ การเพิ่มประสิทธิภาพโค้ดที่ได้ ไลบรารี JavaScript และเครื่องมือบรรทัดคำสั่ง ให้ความยืดหยุ่นและความสะดวกในการใช้งาน โพสต์นี้แสดงให้เห็นหลักการสำคัญของ การรวบรวม Wasm ซึ่งเน้นถึงประสิทธิภาพและศักยภาพของ Binaryen สำหรับ การเพิ่มประสิทธิภาพสูงสุด แม้ว่าตัวเลือกมากมายในการกำหนดค่าของไบนารี การเพิ่มประสิทธิภาพจำเป็นต้องมีความรู้อย่างลึกซึ้งเกี่ยวกับภายในของ Wasm การตั้งค่าเริ่มต้นใช้งานได้ดีอยู่แล้ว ขอให้สนุกกับการรวบรวมและการเพิ่มประสิทธิภาพ กับไบนารีเลน!

กิตติกรรมประกาศ

โพสต์นี้ได้รับการตรวจสอบโดย Alon Zakai Thomas Lively และ Rachel Andrew