बाइनरी के साथ Wasm को कंपाइल और ऑप्टिमाइज़ करना

Binaryen, C++ में लिखी गई WebAssembly के लिए एक कंपाइलर और टूलचैन इंफ़्रास्ट्रक्चर लाइब्रेरी है. इसका मकसद, WebAssembly में कोड को आसानी से, तेज़ी से, और असरदार तरीके से कंपाइल करना है. इस पोस्ट में, ExampleScript नाम की सिंथेटिक टॉय लैंग्वेज के उदाहरण का इस्तेमाल करके, Binaryen.js API का इस्तेमाल करके JavaScript में WebAssembly मॉड्यूल लिखने का तरीका जानें. इस कोर्स में, मॉड्यूल बनाने, मॉड्यूल में फ़ंक्शन जोड़ने, और मॉड्यूल से फ़ंक्शन एक्सपोर्ट करने के बुनियादी तरीकों के बारे में बताया गया है. इससे आपको WebAssembly में, असल प्रोग्रामिंग भाषाओं को कंपाइल करने की प्रोसेस के बारे में जानकारी मिलेगी. इसके अलावा, आपको Binaryen.js और wasm-opt की मदद से, कमांड लाइन पर Wasm मॉड्यूल को ऑप्टिमाइज़ करने का तरीका भी पता चलेगा.

Binaryen के बारे में जानकारी

Binaryen में एक ही हेडर में, आसानी से इस्तेमाल किया जा सकने वाला C API होता है. साथ ही, इसका इस्तेमाल JavaScript से भी किया जा सकता है. यह WebAssembly फ़ॉर्मैट में इनपुट स्वीकार करता है. हालांकि, यह उन कंपाइलर के लिए सामान्य कंट्रोल फ़्लो ग्राफ़ भी स्वीकार करता है जो इस फ़ॉर्मैट को पसंद करते हैं.

इंटरमीडिएट रिप्रज़ेंटेशन (आईआर), डेटा स्ट्रक्चर या कोड होता है. इसका इस्तेमाल, सोर्स कोड को दिखाने के लिए, कंपाइलर या वर्चुअल मशीन के अंदर किया जाता है. Binaryen का इंटरनल आईआर, कॉम्पैक्ट डेटा स्ट्रक्चर का इस्तेमाल करता है. साथ ही, इसे सभी उपलब्ध सीपीयू कोर का इस्तेमाल करके, पूरी तरह से पैरलल कोड जनरेशन और ऑप्टिमाइज़ेशन के लिए डिज़ाइन किया गया है. Binaryen का आईआर, WebAssembly का सबसेट होने की वजह से, WebAssembly में कंपाइल हो जाता है.

Binaryen के ऑप्टिमाइज़र में कई पास होते हैं, जिनसे कोड के साइज़ और स्पीड को बेहतर बनाया जा सकता है. इन ऑप्टिमाइज़ेशन का मकसद, Binaryen को इतना बेहतर बनाना है कि इसे अपने-आप कंपाइलर बैकएंड के तौर पर इस्तेमाल किया जा सके. इसमें WebAssembly के लिए खास तौर पर बनाए गए ऑप्टिमाइज़ेशन शामिल हैं. ऐसा हो सकता है कि अलग-अलग तरह के कंपाइलर ऐसा न कर पाएं. इन्हें Wasm का छोटा रूप दिया जा सकता है.

Binaryen के उदाहरण के तौर पर AssemblyScript

Binaryen का इस्तेमाल कई प्रोजेक्ट करते हैं. उदाहरण के लिए, AssemblyScript, जो TypeScript जैसी भाषा से सीधे WebAssembly में कंपाइल करने के लिए, Binaryen का इस्तेमाल करता है. 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
 )
)

AssemblyScript का प्लेग्राउंड, जिसमें पिछले उदाहरण के आधार पर जनरेट किया गया WebAssembly कोड दिखाया गया है.

बाइनरी टूलचेन

Binaryen टूलचेन, JavaScript डेवलपर और कमांड लाइन के उपयोगकर्ताओं, दोनों के लिए कई काम के टूल उपलब्ध कराता है. इन टूल का एक सबसेट नीचे दिया गया है; प्रोजेक्ट की README फ़ाइल पर शामिल टूल की पूरी सूची उपलब्ध है.

  • binaryen.js: यह एक स्टैंडअलोन JavaScript लाइब्रेरी है, जो Wasm मॉड्यूल बनाने और उन्हें ऑप्टिमाइज़ करने के लिए, Binaryen के तरीकों को दिखाती है. बिल्ड के लिए, npm पर binaryen.js देखें (या इसे सीधे GitHub या unpkg से डाउनलोड करें).
  • wasm-opt: कमांड-लाइन टूल, जो WebAssembly को लोड करता है और उस पर Binaryen IR पास चलाता है.
  • wasm-as और wasm-dis: ये कमांड-लाइन टूल, WebAssembly को असेंबल और डिसअसेम्बल करते हैं.
  • wasm-ctor-eval: कमांड-लाइन टूल, जो कंपाइल करने के समय फ़ंक्शन (या फ़ंक्शन के कुछ हिस्सों) को चला सकता है.
  • wasm-metadce: कमांड-लाइन टूल, जिसका इस्तेमाल करके Wasm फ़ाइलों के कुछ हिस्सों को आसानी से हटाया जा सकता है. यह इस बात पर निर्भर करता है कि मॉड्यूल का इस्तेमाल कैसे किया जा रहा है.
  • wasm-merge: यह कमांड लाइन टूल, कई Wasm फ़ाइलों को एक फ़ाइल में मर्ज करता है. इससे, संबंधित इंपोर्ट को एक्सपोर्ट से कनेक्ट किया जाता है. जैसे, JavaScript के लिए बंडलर, लेकिन Wasm के लिए.

WebAssembly में कंपाइल किया जा रहा है

आम तौर पर, एक भाषा से दूसरी भाषा में कॉन्टेंट को कंपाइल करने के लिए कई चरण पूरे करने पड़ते हैं. इनमें से सबसे अहम चरण नीचे दिए गए हैं:

  • लेक्सिकल विश्लेषण: सोर्स कोड को टोकन में बांटें.
  • सिंटैक्स का विश्लेषण: एब्स्ट्रैक्ट सिंटैक्स ट्री बनाएं.
  • सेमांटिक विश्लेषण: गड़बड़ियों की जांच करना और भाषा के नियमों को लागू करना.
  • इंटरमीडिएट कोड जनरेशन: ज़्यादा बेहतर तरीके से दिखाएं.
  • कोड जनरेट करना: टारगेट की भाषा में अनुवाद करें.
  • टारगेट के हिसाब से कोड ऑप्टिमाइज़ेशन: टारगेट के लिए ऑप्टिमाइज़ करें.

यूनिक्स वर्ल्ड में, अक्सर कंपाइल करने के लिए इस्तेमाल किए जाने वाले टूल ये हैं: lex और yacc:

  • lex (Lexical Analytics Generator): lex एक ऐसा टूल है जो लेक्सिकल ऐनालाइज़र जनरेट करता है. इन्हें लेक्सर या स्कैनर भी कहा जाता है. यह इनपुट के तौर पर रेगुलर एक्सप्रेशन और उनसे जुड़ी कार्रवाइयों का एक सेट लेता है. साथ ही, लेक्सिकल ऐनालाइज़र के लिए कोड जनरेट करता है, जो इनपुट सोर्स कोड में पैटर्न की पहचान करता है.
  • yacc (एक और कंपाइलर कंपाइलर): yacc एक ऐसा टूल है जो सिंटैक्स विश्लेषण के लिए पार्सर जनरेट करता है. यह प्रोग्रामिंग भाषा के व्याकरण के बारे में जानकारी को इनपुट के तौर पर लेता है और पार्स करने वाले टूल के लिए कोड जनरेट करता है. आम तौर पर, पार्स करने वाले टूल, अब्स्ट्रैक्ट सिंटैक्स ट्री (एएसटी) जनरेट करते हैं. ये एएसटी, सोर्स कोड के हैरारकी वाले स्ट्रक्चर को दिखाते हैं.

काम का उदाहरण

इस पोस्ट के दायरे को देखते हुए, पूरी प्रोग्रामिंग भाषा को कवर करना नामुमकिन है. इसलिए, अपनी समझ को आसान बनाने के लिए, ExampleScript नाम की एक बहुत सीमित और काम न आने वाली प्रोग्रामिंग भाषा का इस्तेमाल करें. यह प्रोग्रामिंग भाषा के लिए, सटीक उदाहरणों की मदद से सामान्य ऑपरेशन के बारे में बताती है.

  • add() फ़ंक्शन लिखने के लिए, किसी भी जोड़ के उदाहरण को कोड में लिखें, जैसे कि 2 + 3.
  • उदाहरण के लिए, multiply() फ़ंक्शन लिखने के लिए, 6 * 12 लिखें.

पहले से दी गई चेतावनी के मुताबिक, यह बिलकुल बेकार है, लेकिन इसके लेक्सिकल ऐनालाइज़र को एक रेगुलर एक्सप्रेशन मानकर इस्तेमाल करने के लिए काफ़ी आसान है: /\d+\s*[\+\-\*\/]\s*\d+\s*/.

इसके बाद, एक पार्सर होना चाहिए. असल में, कैप्चरिंग ग्रुप के नाम वाले रेगुलर एक्सप्रेशन का इस्तेमाल करके, किसी ऐब्स्ट्रैक्ट सिंटैक्स ट्री का बहुत आसान वर्शन बनाया जा सकता है: /(?<first_operand>\d+)\s*(?<operator>[\+\-\*\/])\s*(?<second_operand>\d+)/.

ExampleScript कमांड हर लाइन में एक ही नियम लागू किया जा सकता है. इसलिए, पार्सर नई लाइन के वर्णों को बांटकर, कोड को लाइन के हिसाब से प्रोसेस कर सकता है. इससे, बुलेट की सूची में दिए गए पहले तीन चरणों की जांच करने के लिए काफ़ी है. ये चरण हैं: लेक्सिकल विश्लेषण, सिंटैक्स विश्लेषण, और सेमांटिक विश्लेषण. इन चरणों का कोड, यहां दी गई लिस्टिंग में मौजूद है.

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 प्रोग्राम को ऐब्स्ट्रैक्ट सिंटैक्स ट्री के तौर पर दिखाया जा सकता है. भले ही, यह काफ़ी आसान है, इसलिए अगला चरण है, ऐब्स्ट्रैक्ट इंटरमीडिएट का प्रतिनिधित्व करना. पहला चरण, Binaryen में नया मॉड्यूल बनाना है:

const module = new binaryen.Module();

अब्सट्रैक्ट सिंटैक्स ट्री की हर लाइन में एक ट्रिपल होता है, जिसमें firstOperand, operator, और secondOperand शामिल होते हैं. ExampleScript में मौजूद चार ऑपरेटर, यानी +, -, *, / के लिए, Binaryen के Module#addFunction() तरीके का इस्तेमाल करके, मॉड्यूल में एक नया फ़ंक्शन जोड़ना ज़रूरी है. Module#addFunction() तरीकों के पैरामीटर इस तरह के होते हैं:

  • name: string, फ़ंक्शन का नाम दिखाता है.
  • functionType: Signature, फ़ंक्शन के हस्ताक्षर के बारे में बताता है.
  • varTypes: Type[], दिए गए क्रम में अन्य लोकल कोड दिखाता है.
  • body: एक Expression, फ़ंक्शन का कॉन्टेंट.

इस बारे में ज़्यादा जानकारी पाने के लिए, Binaryen दस्तावेज़ पढ़ें. इससे आपको इस बारे में ज़्यादा जानकारी मिल सकती है. हालांकि, आखिर में, ExampleScript के + ऑपरेटर के लिए, आपको Module#i32.add() का तरीका दिखेगा. यह कई उपलब्ध इंटिजर ऑपरेशन में से एक है. जोड़ने के लिए दो ऑपरेंड की ज़रूरत होती है, पहला और दूसरा जोड़. फ़ंक्शन को असल में कॉल करने के लिए, उसे 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');

एब्स्ट्रैक्ट सिंटैक्स ट्री को प्रोसेस करने के बाद, मॉड्यूल में चार तरीके होते हैं. इनमें से तीन तरीके पूर्णांक संख्याओं के साथ काम करते हैं. जैसे, Module#i32.add() पर आधारित add(), Module#i32.sub() पर आधारित subtract(), Module#i32.mul() पर आधारित multiply(), और Module#f64.div() पर आधारित आउटलायर divide(). ऐसा इसलिए है, क्योंकि 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 कोड पाने के लिए, Binaryen में दो तरीके मौजूद हैं. पहला, S-एक्सप्रेशन में .wat फ़ाइल के तौर पर टेक्स्ट के तौर पर दिखाया गया, जो कि इंसान के पढ़ने लायक फ़ॉर्मैट में होता है. दूसरा, .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 प्रोग्राम के लिए, टेक्स्ट के तौर पर पूरी जानकारी नीचे दी गई है. ध्यान दें कि डेड कोड अब भी मौजूद है, लेकिन 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 मॉड्यूल एक्सपोर्ट के DevTools कंसोल का स्क्रीनशॉट, जिसमें चार फ़ंक्शन दिख रहे हैं: जोड़ना, भाग देना, गुणा करना, और घटाना. हालांकि, इसमें एक्सपोज़ नहीं किया गया डेड कोड नहीं दिख रहा है.

WebAssembly को ऑप्टिमाइज़ करना

Wasm कोड को ऑप्टिमाइज़ करने के लिए,binaryen दो तरीके देता है. Binaryen.js में एक और कमांड लाइन के लिए एक. पहला विकल्प, डिफ़ॉल्ट रूप से ऑप्टिमाइज़ेशन के नियमों का स्टैंडर्ड सेट लागू करता है. साथ ही, आपको ऑप्टिमाइज़ और छोटा करने का लेवल सेट करने की सुविधा देता है. वहीं, दूसरा विकल्प डिफ़ॉल्ट रूप से किसी भी नियम का इस्तेमाल नहीं करता. हालांकि, इसमें सेटिंग को पूरी तरह से पसंद के मुताबिक बनाया जा सकता है. इसका मतलब है कि ज़रूरत के मुताबिक प्रयोग करके, अपने कोड के आधार पर ऑप्टिमाइज़ेशन के लिए सेटिंग को बेहतर बनाया जा सकता है.

Binaryen.js का इस्तेमाल करके ऑप्टिमाइज़ करना

Binaryen की मदद से Wasm मॉड्यूल को ऑप्टिमाइज़ करने का सबसे आसान तरीका यह है कि आप सीधे तौर पर Binaryen.js के Module#optimize() तरीके को कॉल करें. इसके अलावा, ऑप्टिमाइज़ और छोटा करने के लेवल को सेट करना भी ज़रूरी नहीं है.

// 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 (स्थानीय वैरिएबल से जुड़े अलग-अलग ऑप्टिमाइज़ेशन) और Vacuum (बेवजह इस्तेमाल होने वाले कोड को हटाता है). साथ ही, 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-ऑप्ट कमांड लाइन टूल की मदद से ऑप्टिमाइज़ किया जा रहा है

इस्तेमाल किए जाने वाले पास को पूरी तरह से पसंद के मुताबिक बनाने के लिए, Binaryen में wasm-opt कमांड लाइन टूल शामिल होता है. ऑप्टिमाइज़ेशन के संभावित विकल्पों की पूरी सूची पाने के लिए, टूल का सहायता मैसेज देखें. शायद wasm-opt टूल, इस टूल में सबसे ज़्यादा लोकप्रिय है. इसका इस्तेमाल कई कंपाइलर टूलचेन की मदद से Wasm कोड को ऑप्टिमाइज़ करने के लिए किया जाता है. इनमें Emscripten, J2CL, Kotlin/Wasm,dart2wasm, वासm-pack,और अन्य टूल शामिल हैं.

wasm-opt --help

पास के बारे में आपको जानकारी देने के लिए, यहां कुछ पास के बारे में बताया गया है. इनमें से कुछ ऐसे पास हैं जिन्हें विशेषज्ञों की जानकारी के बिना भी समझा जा सकता है:

  • कोडफ़ोल्डिंग: डुप्लीकेट कोड को मर्ज करने से बच सकता है (उदाहरण के लिए, अगर दो if आर्म के आखिर में कुछ शेयर किए गए निर्देश होते हैं).
  • DeadArgumentElimation: अगर किसी फ़ंक्शन को हमेशा एक जैसे कॉन्सटेंट के साथ कॉल किया जाता है, तो फ़ंक्शन में आर्ग्युमेंट को हटाने के लिए टाइम ऑप्टिमाइज़ेशन पास को लिंक करें.
  • MinifyImportsAndExports: इन फ़ंक्शन को "a", "b" तक छोटा कर देता है.
  • DeadCodeElimination: डैड कोड हटाएं.

ऑप्टिमाइज़ेशन कुकबुक में कई सलाह दी गई हैं. इनसे यह पता चलता है कि कौनसे फ़्लैग ज़्यादा अहम हैं और जिन्हें पहले आज़माना चाहिए. उदाहरण के लिए, कभी-कभी wasm-opt को बार-बार इस्तेमाल करने पर, इनपुट का साइज़ और भी छोटा हो जाता है. ऐसे मामलों में, --converge फ़्लैग के साथ चलाने पर, तब तक दोहराव होता रहता है, जब तक कोई और ऑप्टिमाइज़ेशन नहीं होता और तय किए गए पॉइंट तक नहीं पहुंचा जाता.

डेमो

इस पोस्ट में बताए गए कॉन्सेप्ट को काम करते हुए देखने के लिए, एम्बेड किए गए डिमो को चलाएं. इसके लिए, अपनी पसंद के मुताबिक ExampleScript का कोई भी इनपुट दें. साथ ही, डेमो का सोर्स कोड देखना न भूलें.

मीटिंग में सामने आए नतीजे

बाइनरीयन, WebAssembly में भाषाओं को कंपाइल करने और उनसे बनने वाले कोड को ऑप्टिमाइज़ करने के लिए एक बेहतरीन टूलकिट देता है. इसकी JavaScript लाइब्रेरी और कमांड-लाइन टूल, इस्तेमाल में आसान और सुविधाजनक हैं. इस पोस्ट में, Wasm को कंपाइल करने के मुख्य सिद्धांतों के बारे में बताया गया है. साथ ही, यह भी बताया गया है कि बाइनरीयन कितना असरदार है और इसे ज़्यादा से ज़्यादा ऑप्टिमाइज़ कैसे किया जा सकता है. Binaryen के ऑप्टिमाइज़ेशन को पसंद के मुताबिक बनाने के कई विकल्पों के लिए, Wasm के इंटरनल के बारे में अच्छी जानकारी ज़रूरी होती है. हालांकि, आम तौर पर डिफ़ॉल्ट सेटिंग पहले से ही बेहतर तरीके से काम करती हैं. इसके बाद, Binaryen की मदद से कोड को कॉम्पाइल और ऑप्टिमाइज़ करने का आनंद लें!

धन्यवाद

इस पोस्ट की समीक्षा अलोन ज़काई, थॉमस लाइवली, और रेचल एंड्रयू ने की है.