Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How to Boost Your Code with WebAssembly

FUJI Goro
November 30, 2019

How to Boost Your Code with WebAssembly

FUJI Goro

November 30, 2019
Tweet

More Decks by FUJI Goro

Other Decks in Technology

Transcript

  1. ࣗݾ঺հ • FUJI Goro / @__gfx__ • ͜͜਺೥͸΢ΣϒΤϯδχΞͱͯ͠ Rails/React/TypeScript/ GraphQL

    ͋ͨΓͷٕज़Λ࢖ͬͯαʔϏε։ൃΛͯ͠·ͨ͠ • ͜ͷτʔΫ͸झຯͰ @msgpack/msgpack Λ։ൃͨ͠ͱ͖ ͷܦݧʹج͖ͮ·͢ • ࠷ۙCDN providerͷFastlyʹస৬͠·ͨ͠ • స৬͔ͯ͠Β͸ओʹCݴޠͰHTTP serverΛ։ൃͯ͠·͢
  2. WebAssemblyલ໷ (2012~) • EmscriptenʹΑͬͯC/C++ΛJSʹίϯύΠϧ͢Δ ͜ͱ͸Ͱ͖͍ͯͨ (2012~) • ྫ: https://github.com/gfx/perl.js (2014)

    • ͨͩ͜͠Ε͸ඇৗʹಈ࡞଎౓͕஗͔ͬͨ • JSͰCPUΛΤϛϡϨʔτ͢ΔͷͰ஗͍ͷ͸ٕज़ తඞવͩͬͨ
  3. WebAssembly (2015~) • 2015೥ʹWebAssemblyͷ࢓༷ͷٞ࿦͕։࢝ • 2017೥ʹChrome, Safari, Firefox, Edgeͱ͍ͬͨϞμ ϯϒϥ΢βͰͷ

    v1.0 (“MVP”) αϙʔτ͕׬ྃ • 2019೥͸WASIͷൃද΍Bytecode Allienceͷൃ଍ͳ Ͳɺϒϥ΢β֎Ͱͷ༻్͕૿͑ͯ͘Δ • ݱࡏ͸SIMDͳͲͷ͞ΒͳΔػೳ(“post MVP”)͕ਐߦத
  4. WebAssemblyͷ଎౓ͱ҆શੑ • ʮ଎͍ʯͱ͸͍͏΋ͷͷCΑΓ਺ഒ஗͍ • ͜Ε͸҆શੑͷͨΊະఆٛಈ࡞ (UB) Λͳ͍ͯ͘͠Δ͔Β • ͨͱ͑͹ɺCͰ͸഑ྻͷൣғ֎΁ͷΞΫηε͸UB •

    WasmͰ͸֬อͨ͠ϝϞϦͷൣғ֎΁ͷΞΫηε΋ఆٛࡁΈ • ͜ͷ҆શੑ͕ͦ͜େ͖ͳར఺ • UB͕ͳ͍͔Βͦ͜όάͷ͋ΔWasmͰ΋҆શʹ࣮ߦͰ͖Δ
  5. WebAssembly࠾༻ࣄྫ • eBayͷࣄྫ - όʔίʔυεΩϟφ for Web • “WebAssembly at

    eBay - a Real-World Use Case” • https://tech.ebayinc.com/engineering/ webassembly-at-ebay-a-real-world-use-case/ • WasmؚΉ͍͔ͭ͘ͷ࣮૷Λฒྻʹ࣮ߦͯ͠࠷଎ Ͱ੒ޭͨ݁͠ՌΛ࠾༻͢Δͱ͍͏ΞʔΩςΫνϟ
  6. WebAssembly as a universal executable binary • ༨ஊ: WebAssembly͸͸ϢχόʔαϧͳόΠφϦͱͯ͠ ੒௕ͭͭ͋͠Δ

    • ͜ΕΛਐΊ͍ͯΔͷ͕ Bytecode Allience ͱ͍͏ஂମ • ྫ: Lucet (Fastly→Bytecode Allience): WasmΛωΠςΟ ϒίʔυʹίϯύΠϧ͢ΔπʔϧΩοτ • Compute@Edge (Fastly): ͸LucetͰίϯύΠϧͨ͠ WasmΛCDNͷΤοδαʔόʔͰ࣮ߦ͢Δ࢓૊Έ
  7. ݴޠ͝ͱͷಈ࡞଎౓Πϝʔδ • Ϋϥε1 “θϩΦʔόʔϔου” • C, C++, Rust • Ϋϥε3

    “ߴ଎ͳίϯύΠϥ” • Java, C#, Go, Swift • Ϋϥε5 “ߴ଎ͳΠϯλϓϦλ” • JavaScript (V8), Dart • Ϋϥε50 “ී௨ͷΠϯλϓϦλ” • Ruby, Python, Perl, PHP
  8. WebAssemblyʹΑΔߴ଎Խ • ੡඼શମΛ C / C++ / Rust / Go

    Ͱ࣮૷͠Wasmʹ ίϯύΠϧ͢Δ • ͦΕͳΓʹීٴ͠͸͡Ί͍ͯΔ • ੡඼ͷҰ෦ΛWasmʹίϯύΠϧͯ͠ߴ଎Խ͢Δ • ͜ͷτʔΫͰͷؔ৺ࣄ͸ͬͪ͜ • ͜ͷ༻్ͷՁ஋͸ະ஌਺
  9. ݴޠ: AssemblyScript • બ୒ࢶ: C / C++ / Rust /

    Go / AssemblyScript • ࠓճ͸ϥϯλΠϜ͕Ұ൪খͦ͞͏ͳ AssemblyScriptΛબ୒
  10. ϦϙδτϦ • https://github.com/msgpack/msgpack- javascript • v1.9.3 ݱࡏͷ࿩ • npm install

    @msgpack/msgpack ͰΠϯείՄೳ • ͨͩ͠Wasm൛͸ݱࡏweb޲͚ͷϏϧυͰ͸࢖ ΘΕͳ͍Α͏ʹͳ͍ͬͯΔ
  11. ࣮૷ • MessagePack decoderͷҰ෦ɺจࣈྻͷσίʔυΛ JS / Wasm (AS) ͰͦΕͧΕͰ࣮૷ͨ͠ɻ·ͨV8૊Έ ࠐΈͷಉ͡ڍಈͷωΠςΟϒίʔυؔ਺΋ϕϯν

    ϚʔΫର৅ͱͨ͠ • ΍͍ͬͯΔ͜ͱ͸UTF-8ͷ഑ྻΛUTF-16ͷ഑ྻʹม ׵͢Δ͜ͱ • AssemblyScriptʹҠ২ͯ͠100ߦఔ౓ͷίʔυ
  12. JS൛ͷίʔυʢൈਮʣ export function utf8DecodeJs(bytes: Uint8Array, inputOffset: numbe byteLength: number): string

    { let offset = inputOffset; const end = offset + byteLength; const units: Array<number> = []; while (offset < end) { const byte1 = bytes[offset++]; if ((byte1 & 0x80) === 0) { // 1 byte units.push(byte1); } // ... } return String.fromCharCode(...units); }
  13. ωΠςΟϒίʔυ൛ͷίʔυ const sharedTextDecoder = new TextDecoder(); export function utf8DecodeTD(bytes: Uint8Array,

    inputOffset: numbe byteLength: number): string { const stringBytes = bytes.subarray(inputOffset, inputOffset + byteLength); return sharedTextDecoder!.decode(stringBytes); }
  14. AS൛ͷίʔυʢൈਮ, AS 0.6ʣ export function utf8DecodeToUint16Array(outputPtr: usize, inputPtr: usize, byteLength:

    usize): usize { let inputOffset = inputPtr; let outputOffset = outputPtr; let inputOffsetEnd = inputOffset + byteLength; const u16s = sizeof<u16>(); while (inputOffset < inputOffsetEnd) { let byte1: u16 = load<u8>(inputOffset++); if ((byte1 & 0x80) === 0) { // 1 byte store<u16>(outputOffset, byte1); outputOffset += u16s; } } return (outputOffset - outputPtr) / u16s; }
  15. AS൛ͷίʔυʢJSଆʣ // wm = InstantiatedWasmModule.exports type pointer = number; //

    32-bit integer export function utf8DecodeWasm(bytes: Uint8Array, inputOffset: numbe byteLength: number): string { const inputPtr: pointer = wm.malloc(byteLength); const outputPtr: pointer = wm.malloc(byteLength * 2); try { setMemoryU8(inputPtr, bytes.subarray(inputOffset, inputOffset + byteLength), byteLength); const outputArraySize = wm.utf8DecodeToUint16Array(outputPtr, inputPtr, byteLength); const units = new Uint16Array(wm.memory.buffer, outputPtr, outputArraySize); return String.fromCharCode(...units); } finally { wm.free(inputPtr); wm.free(outputPtr); } }
  16. Wasm function΁ͷೖྗ • Wasmʹ౉ͤΔ஋͸2छྨ • (1) WASM functionͷݺͼग़͠ͷҾ਺ͱͯ͠ɺ೚ҙݸͷ੔਺·ͨ͸ුಈখ ਺఺਺ •

    (2) WASM moduleͷbuffer: ArrayBufferʹ஋Λॻ͖ࠐΉɻArrayBufferʹॻ ͖ࠐΊΔ஋ͳΒͳΜͰ΋OK • Ͳ͜ʹॻ͖ࠐΜ͔ͩͷoffset (੔਺) Λ(1)ͱͯ͠Ҿ਺ͱͯ͠౉͢ • Cݴޠతʹݴ͑͹͜Ε͕ϙΠϯλͱ౳Ձ • ASͰ͸ load<T>(offset) ؔ਺ͰಡΈग़ͤΔ
  17. Wasm function͔Βͷग़ྗ • ੔਺·ͨ͸ුಈখ਺఺਺1͚ͭͩ • ʢWasmతʹ͸೚ҙͷ਺ͷ஋ΛฦͤΔʣ • ࠓճ͸ೖྗ஋ͱͯ͠outputPtr (offset) Λ౉͠ɺ

    Wasm function͸ग़ྗ஋ΛoutputPtrͷҐஔʹॻ ͖ࠐΈɺॻ͖ࠐΜͩαΠζΛWasm function͔ Βฦ͢ͱ͍͏͜ͱʹͨ͠
  18. Wasm functionͷγάωνϟ • ίϝϯτ͖ͭͰ࠶ܝ͢Δͱɺ͜Μͳײ͡ export function utf8DecodeToUint16Array( outputPtr: usize, //

    output offset inputPtr: usize, // input offset byteLength: usize, // input length ): usize; // output length
  19. AssemblyScriptͷϋϚΓͲ͜Ζ • ϙΠϯλܕ͸ͳ͘ɺΦϑηοτͱͯ͠ usize (uint32_t) ܕ͕͋Δ͚ͩ • load<u16>() / store<u16>()

    ͳͲ͸ϦτϧΤϯσΟΞϯͱنఆ͞Εͯ ͍Δ͕ɺJSଆͷtyped arrays (Uint16Array) ͸ϗετͷΤϯσΟΞϯ ͳͷͰ࢓༷తʹ͸ΤϯσΟΞϯޓ׵ੑ͕ͳ͍ • ͔͠͠ɺ͖ΐ͏ͼͷϚγϯ͸΄΅͢΂ͯϦτϧΤϯσΟΞϯͳͷ ͰɺԿ΋ߟ͑ͳͯ͘΋ಈ͍ͯ͠·͏ʢASͷ໰୊Ͱ͸ͳ͍͕ʣ • ݟͨ໨͕TypeScriptͳ͜ͱʹؾ͕࣋ͪҾ͖ͣΒΕͯຌϛε͕සൃ͢Δ
  20. ؀ڥ • macOS 10.14 • NodeJS 12.6.0 • v8 7.5

    ʢChrome 75૬౰ʣ • ࠓճ͸NodeJSͷΈͰϕϯνϚʔΫΛͨ͠
  21. νϟʔτͷݟํ • ॎ࣠͸ log10 (ops per sec) • ͦͷ··ͩͱݟͮΒ͍ͷͰର਺ʹͯ͋͠Δ •

    ஋͕େ͖͍΄Ͳੑೳ͕Α͍ • ԣ࣠͸σʔλαΠζ • ಉ͡σʔλαΠζಉ࢜Ͱൺֱ͢Δ͜ͱ • σʔλαΠζ͕ҟͳΔσʔλͷൺֱ͸ແҙຯ
  22. ϕϯνϚʔΫ݁Ռ 0 2 4 6 8 10 100 200 500

    1000 10000 utf8DecodeJs utf8DecodeWasm TextDecoder default, NodeJS/v12.6.0, v8/7.5
  23. ϕϯνϚʔΫ݁Ռ (—no-opt) 0 2 4 6 8 10 100 200

    500 1000 10000 utf8DecodeJs utf8DecodeWasm TextDecoder --no-opt NodeJS v12.6.0, v8 7.5 on macOS
  24. ϕϯνϚʔΫ݁Ռ (default) 0 2 4 6 8 10 100 200

    500 1000 10000 utf8DecodeJs utf8DecodeWasm TextDecoder default, NodeJS/v12.6.0, v8/7.5