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

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

बाइनरी पर बैकग्राउंड

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

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

बाइनरी के ऑप्टिमाइज़र के पास कई पास हैं, जो कोड के आकार और रफ़्तार को बेहतर बना सकते हैं. इन ऑप्टिमाइज़ेशन का मकसद बाइनरीन को इतना ताकतवर बनाना है कि उसका इस्तेमाल कंपाइलर के तौर पर किया जा सके. इसमें WebAssembly के हिसाब से ऑप्टिमाइज़ किए गए ऑप्टिमाइज़ेशन शामिल हैं. ऐसा हो सकता है कि सामान्य मकसद के कंपाइलर ऐसा न करें. इन्हें Wasm छोटा करने की सुविधा के तौर पर भी समझा जा सकता है.

बाइनरी लिपि के उदाहरण उपयोगकर्ता के तौर पर AssemblyScript

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

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

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

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

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

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

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

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

Unix की दुनिया में, कंपाइल करने के लिए अक्सर इस्तेमाल होने वाले टूल, 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 में चार संभावित ऑपरेटर यानी +, -, *, / में से हर एक के लिए बाइनरी के Module#addFunction() तरीके से मॉड्यूल में एक नया फ़ंक्शन जोड़ना ज़रूरी है. Module#addFunction() तरीकों के पैरामीटर यहां दिए गए हैं:

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

आराम करने के लिए कुछ और जानकारी भी है. साथ ही, बाइनरीयन दस्तावेज़ से आपको स्पेस में नेविगेट करने में मदद मिल सकती है. हालांकि, 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 `/`.

अगर आप असल कोड बेस का इस्तेमाल करते हैं, तो कभी-कभी कुछ काम न करने वाले कोड मिल जाते हैं, जिन पर कॉल नहीं किया जाता. Wasm के लिए exampleScript को कंपाइल करने के चल रहे उदाहरण में, मृत कोड को बनावटी तरीके से जोड़ने के लिए (जिसे बाद के चरण में ऑप्टिमाइज़ किया जाएगा और हटा दिया जाएगा). इसके लिए, एक्सपोर्ट नहीं किया गया फ़ंक्शन जोड़ें.

// 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 कोड मिलने पर, बाइनरी में दो तरीके मौजूद हैं. इनकी मदद से, S-expression में .wat फ़ाइल के तौर पर टेक्स्ट के रूप में देखा जा सकता है. साथ ही, बाइनरी रिप्रज़ेंटेशन को .wasm फ़ाइल के तौर पर उपलब्ध कराया जा सकता है. इसे .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 कोड को ऑप्टिमाइज़ करने के दो तरीके मौजूद हैं. एक बाइनरी खुद में एक और एक कमांड लाइन के लिए है. डिफ़ॉल्ट तौर पर, ऑप्टिमाइज़ेशन के नियमों का स्टैंडर्ड सेट लागू होता है और 'ऑप्टिमाइज़' और 'छोटा करने का लेवल' सेट किया जा सकता है. डिफ़ॉल्ट रूप से, किसी भी नियम का इस्तेमाल नहीं किया जाता. हालांकि, पूरी तरह से कस्टमाइज़ेशन की अनुमति होती है. इसका मतलब है कि काफ़ी प्रयोग होने पर, आपके पास अपने कोड के आधार पर बेहतर नतीजों के लिए सेटिंग में बदलाव करने का विकल्प होगा.

बाइनरी.js के साथ ऑप्टिमाइज़ करना

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

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

wasm-opt --help

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

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

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

डेमो

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

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

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

स्वीकार हैं

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