Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
AssemblyScriptでライブラリコードの高速化をしてみる
Search
FUJI Goro
July 24, 2019
Programming
3.3k
5
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
AssemblyScriptでライブラリコードの高速化をしてみる
FUJI Goro
July 24, 2019
More Decks by FUJI Goro
See All by FUJI Goro
ステートレスなLLMでステートフルなAI agentを作る - YAPC::Fukuoka 2025
gfx
7
2k
How to Boost Your Code with WebAssembly
gfx
2
3.2k
実践TypeScriptトークバトル
gfx
1
1.2k
歴史的経緯の説明 as code
gfx
7
2.9k
Elasticsearchによる 全文検索の実装 in Rails
gfx
6
9.8k
すばらしきGraphQLのSEKAIへようこそ
gfx
20
10k
マルチテナント・ウェブアプリケーションの実践
gfx
14
9.8k
How to choose the ORM on Android
gfx
1
4.4k
How Do We Get Along With Static Types
gfx
5
3.5k
Other Decks in Programming
See All in Programming
言葉の格闘技のススメ~紙とペンと言葉から始める、キャリアの描き方~
progresscicada
1
120
【やさしく解説 設計編・中級 #6】良いアーキテクチャとは ~ 一本の登り道の、行き先 ~
panda728
PRO
0
200
Android CLI
fornewid
0
210
壊れたパーサから始める関数型設計と構成的なパーサ #fp_matsuri
raiga0310
2
440
JAWS-UG横浜 #102 AWSサ終供養LT会 成仏できない AWS サービスたち 〜本日、三体供養します〜
maroon1st
0
310
そこに3びきプロダクトがいるじゃろう——生成AI時代における“価値が届かない理由”の構造
kosuket
0
400
freee が目指す データ マネジメント戦略 AI-Ready 時代を支える 攻めのガバナンスとは
freee
PRO
0
240
生成AI導入の「期待外れ」を乗り越える ー 開発フロー改革が目指す、真の組織変革
starfish719
0
3.8k
自動化したのに回らないテスト運用の壁ーAI時代の品質責任と生産性
mfunaki
0
120
生成AIで帳票OCRが「簡単に」作れる時代になった?
kon_shou
0
410
Embedded SREと共に達成した会員管理システムのAWS移行 - SRE NEXT 2026 ランチスポンサーセッション
niftycorp
PRO
1
3.4k
PHPだって関数型したい 〜できること、できないこと〜 / fp-in-php
jsoizo
1
270
Featured
See All Featured
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
570
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
67
56k
Darren the Foodie - Storyboard
khoart
PRO
3
3.5k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
66
57k
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
460
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
Music & Morning Musume
bryan
47
7.3k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
510
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.5k
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
1
2.8k
Designing Powerful Visuals for Engaging Learning
tmiket
1
470
Transcript
AssemblyScriptͰϥΠϒϥϦ ίʔυͷߴԽΛͯ͠ΈΔ Emscripten & WebAssembly night!! #8 In Mercari, Inc.
,2019/07/24 by FUJI Goro (@__gfx__)
ࣗݾհ • FUJI Goro / @__gfx__ • ϑϩϯτΤϯυͱ͔Web APIͱ͔ •
࠷͍ۙͯ͠Δٕज़GraphQLͱ TypeScriptͱWebAssembly
WebAssembly as a universal executable binary • Φϓτϐ: WebAssemblyʹϢχόʔαϧͳόΠφϦͱ ͯ͠ظͯ͠Δ
• ͭ·ΓϓϥοτϑΥʔϜඇґଘͳόΠτίʔυ • ࢼ͠ʹzopfli (C library) ΛwasmʹϏϧυͯ͠ @gfx/ zopfli ͱͯͯ͠͠Έͨ • native binding൛ΑΓ͍͕Πϯείָ͕ͳͷͰͦ͜ ͦ͜ΘΕΔΑ͏ʹͳͬͨ
WASM in intereters • কདྷతʹRuby / Perl / Python ͱ͍ͬͨΠϯλϓϦλ͕
WASM࣮ߦΤϯδϯΛ࣋ͭΑ͏ʹͳΔͷͰͳ͍͔ • ͜ͷํͰͷࢼΈ͕wasmerͰɺ͢Ͱʹϝδϟʔͳݴޠ༻ͷ binding͕͋Δ • WASM͕ϏϧυࡁΈόΠφϦͷϑΥʔϚοτͱͯ͠ϝ δϟʔʹͳΔͱ͍͍ͳ͋…ͱࢥ͍ͬͯΔ • ߴͳwasmॲཧܥඞཁʢwasmer͕Ͳ͏͔ະௐࠪʣ
ؓٳ
WebAssemblyͷ༻్ • طଘͷ C / C++ / Rust / Go
ΛJSʹίϯύΠϧ ͢Δ • ͦΕͳΓʹ҆ఆ͍ͯͯ͠ී௨ʹศར • ৽͍͠ͷҰ෦ΛWebAsemblyͰߴԽ͢Δ • ࠓճͬͪ͜ • ͜ͷ༻్ͷύϑΥʔϚϯεະͰʁʁ
ͬͯΈͨ
ݴޠ: AssemblyScript • બࢶͱͯ͠ C / C++ / Rust /
Go / AssemblyScript • ࠓճϥϯλΠϜ͕Ұ൪খͦ͞͏ͳ AssemblyScriptΛબ • ʢଞͷݴޠࢼ͔͕ͨͬͨؒ͠ʹ߹Θͣʣ
AssemblyScript • TypeScriptͷαϒηοτΛߏจͱͯ͠ར༻ͨ͠શ͘ ৽͍͠ϓϩάϥϛϯάݴޠ • ॻ͖ຯTypeScriptΑΓC/C++ʹ͍ۙ • ͱ͍͏͔TypeScriptͷൽ͚ͩͯ͠தΛ͘Γൈ ͍ͯC/C++Λ٧Ίͨ͠ݴޠͱ͍͏͖ •
ͨͩ͠CΑΓଟػೳɺC++ΑΓශऑ
AssemblyScriptͷ࠷దԽث • AssemblyScriptͷόοΫΤϯυBynarien • Emscripten͕Β͖࣮ͬͯͨ͘ͷ͋Δόο ΫΤϯυ • ʢ͍·EmscriptenLLVM backendਪ͠ʣ •
খ͞ͳؔͷΠϯϥΠϯԽͳͲɺجຊతͳ࠷ద ԽBynarien͕ͬͯ͘ΕΔ
ςʔϚ: MessagePack codec • ͦͦWebAssemblyόΠτྻ (ArrayBuffer) ͔͠ѻ͑ͳ͍ͷͰɺಘҙ ݶΒΕͦ͏ • खݩͷίʔυͩͱMessagePackόΠφϦγ
ϦΞϥΠβͳͷͰWASMͰߴԽͷ༨͋ Γͦ͏ͩͱ౿Μͩ
ϦϙδτϦ • https://github.com/msgpack/msgpack-javascript • v1.6.0 ݱࡏͷ • npm install @msgpack/msgpack
ͰΠϯείՄೳ • ͨͩ͠WASM൛ݱࡏweb൛ͰΘΕͳ͍Α͏ʹͳͬ ͍ͯΔ • WASM·ΘΓͷίʔυ͍ͣΕফͨ͠ΓRustʹॻ͖͑ͨ Γ͢Δ͔
࣮ • MessagePack decoderͷҰ෦ɺจࣈྻͷσ ίʔυΛJS / WASM (AS) / ωΠςΟϒίʔυ
ͦΕͧΕͰ࣮ͨ͠ • ͍ͬͯΔ͜ͱUTF-8ͷྻΛUTF-16ͷ ྻʹม͢Δ͜ͱ • AssemblyScriptʹҠ২ͯ͠100ߦఔ
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); }
ωΠςΟϒίʔυ൛ͷίʔυ 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); }
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; }
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); } }
WASM functionͷೖྗ • WASMʹͤΔ2छྨ • (1) WASM functionͷݺͼग़͠ͷҾͱͯ͠ɺҙݸͷ·ͨුಈখ •
(2) WASM moduleͷbuffer: ArrayBufferʹΛॻ͖ࠐΉɻArrayBufferʹॻ ͖ࠐΊΔͳΒͳΜͰOK • Ͳ͜ʹॻ͖ࠐΜ͔ͩͷoffsetΛ(1)ͷҾͱͯ͢͠ • Cݴޠతʹݴ͑͜Ε͕ϙΠϯλ • ASͰ load<T>(offset) ؔͰಡΈग़ͤΔ
WASM function͔Βͷग़ྗ • ·ͨුಈখ1͚ͭͩ • ʢWASMతʹҙͷͷΛฦͤΔ͕ʣ • ࠓճೖྗͱͯ͠outputPtr (offset) Λ͠ɺ
WASM functionग़ྗΛoutputPtrͷҐஔʹ ॻ͖ࠐΈɺॻ͖ࠐΜͩαΠζΛWASM function ͔Βฦ͢ͱ͍͏͜ͱʹͨ͠
WASM functionͷγάωνϟ • ίϝϯτ͖ͭͰ࠶ܝ͢Δͱɺ͜Μͳײ͡ export function utf8DecodeToUint16Array( outputPtr: usize, //
output offset inputPtr: usize, // input offset byteLength: usize, // input length ): usize; // output length
AS (0.6) ͷϋϚΓͲ͜Ζ • ϙΠϯλܕ͕ͳͯ͘͢ usize (uint32_t) ܕ • load<u16>()
/ store<u16>() ͳͲϦτϧΤϯσΟΞϯͱنఆ ͞Ε͍ͯΔ͕ɺJSଆͷtyped arrays (Uint16Array) ϗετͷΤ ϯσΟΞϯͳͷͰຊޓੑ͕ͳ͍ • ͔͠͠ɺ͖ΐ͏ͼͷϚγϯϦτϧΤϯσΟΞϯͳͷͰಈ͍ ͯ͠·͏ʢASͷͰͳ͍͕ʣ • ݟ͕ͨTypeScriptͳ͜ͱʹؾ͕࣋ͪҾ͖ͣΒΕͯຌϛε͕සൃ ͢Δ
AS (0.7) ͷϋϚΓͲ͜Ζ • ͳ͓ݱߦόʔδϣϯ (0.7) ϦϑΝϨϯεΧ ϯτϥϯλΠϜ͕Ճ͞ΕͨͷͰJSͱͷ૬ޓ ӡ༻͕ΑΓ͘͠ͳͬͨ •
msgpack-javascript·ͩAS 0.7ʹରԠͰ͖ ͍ͯͳ͍ɺͱ͍͏͔͍ͬͦASΛࣺͯͯRust ʹ͠Α͏ͱࢥ͍ͬͯΔ
ϕϯνϚʔΫ
ڥ • macOS 10.14 • NodeJS 12.6.0 • v8 7.5
ʢChrome 75૬ʣ • ࠓճNodeJSͷΈͰϕϯνϚʔΫΛͨ͠
ϕϯνϚʔΫίʔυ • https://gist.github.com/gfx/ e3e33c80848f734a81dbd030fca16230 • “A”.repeat(N) ʢNσʔλαΠζʣͱ͍͏ σʔλΛUTF-8Τϯίʔυͨ͠όΠτྻΛɺ JS൛ /
WASM൛ / ωΠςΟϒίʔυ൛ͷؔ Ͱจࣈྻʹσίʔυ͢Δ
νϟʔτͷݟํ • ॎ࣠ log10 (ops per sec) • ͦͷ··ͩͱݟͮΒ͍ͷͰରʹͯ͋͠Δ •
͕େ͖͍΄Ͳੑೳ͕Α͍ • ԣ࣠σʔλαΠζ • ಉ͡σʔλαΠζಉ࢜Ͱൺֱ͢Δ͜ͱ • σʔλαΠζ͕ҟͳΔσʔλͷൺֱແҙຯ
ϕϯνϚʔΫ݁Ռ 0 2 4 6 8 10 100 200 500
1000 10000 utf8DecodeJs utf8DecodeWasm TextDecoder default, NodeJS/v12.6.0, v8/7.5
νϟʔτ͔ΒಡΈऔΕΔ͜ͱ • σʔλαΠζ͕খ͍͞ͱ͖JS൛͕࠷ • WASM൛ / ωΠςΟϒίʔυ൛ॲཧࣗମߴ ͕ͩݺͼग़͠ͷΦʔόʔϔου͕େ͖͍ͨΊ • σʔλαΠζ͕େ͖͘ͳΔͱ
ωΠςΟϒίʔυ൛ >> WASM൛ > JS൛ • ͦͦJS൛ͱWASM൛ͰͦΕ΄Ͳࠩͳ͍
JS൛ͱWASM൛ͷ͕ࠩͳ͍ʁʁ • ͔֬ʹσʔλαΠζ͕େ͖͘ͳΔͱWASM൛ͷ΄͏͕গͩ͠ ͚ͱ͍ܾ͑ఆతʹ͍ • ͔ͦ͠͠ͷ͍͍ࠩͤͥे%Ͱɺ։ൃΛߟ͑ΔͱWASM ൛ίεύ͕ѱ͍ • AssemblyScript͕ͭΒ͍ͱ͍͏͜ͱ͋Δ͕ɺͦͦݴޠ Λ·͍ͨͩϒϦοδΛϝϯς͢Δͷٕज़తͳқ͕ߴ͍
• ݁ہɺV8ͷ࠷దԽJITίϯύΠϥ͕ڧ͗͢ΔͷͰ͍JSίʔυ ͷॻ͖ํΛֶͿͷ͕ίεύ͕Α͍
ୈҰ෦
ୈೋ෦
~ v8 —no-opt ฤ ~
V8ͷΞʔΩςΫνϟ(2017)
࠷దԽJITίϯύΠϥ TurboFan • ͔ͨ͠ʹV8TurboFan͕ޮ͚ര • ͔͠͠ΣϒϖʔδͷॳճಡΈࠐΈ͔࣌Βૢ ࡞ՄೳʹͳΔ·ͰͷؒɺTurboFanʹΑΔ࠷ దԽ͕·ͩޮ͍ͯͳ͍͔͠Εͳ͍ • ͭ·ΓTurboFanͷੑೳΛଌΔϕϯνϚʔΫ͕
͋ͳͨͷέʔεʹద߹͢ΔͱݶΒͳ͍
v8 —no-opt • v8ͷ࠷దԽΛແޮʹ࣮ͯ͠ߦ͢ΔΦϓγϣϯ • nodejsͰ͜ͷΦϓγϣϯ͕͑Δ • ͜ͷΦϓγϣϯ͖ͰϕϯνϚʔΫΛ͢Δ ͱɺͨͱ͑ҰॠͰ࣮ߦΛऴ͑ΔίϚϯυϥ ΠϯπʔϧΣϒϖʔδͷॳظԽίʔυͷ
࣮ߦͳͲͷڥΛΤϛϡϨʔτͰ͖Δ
nodejs —no-opt Ͱ࠶ܭଌ
ϕϯνϚʔΫ݁Ռ (—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
ϕϯνϚʔΫ݁Ռ (default) 0 2 4 6 8 10 100 200
500 1000 10000 utf8DecodeJs utf8DecodeWasm TextDecoder default, NodeJS/v12.6.0, v8/7.5
νϟʔτ͔ΒಡΈऔΕΔ͜ͱ • ࠷దԽ͕ޮ͔ͳ͍ͱ͖͔ͳΓখ͍͞σʔλα ΠζͰ WASM൛ >> JS൛ • ࠷దԽ͕ޮ͍͍ͯͯWASM൛ͷ΄͏͕JS൛Α Γগ͍͠
• ىಈ࣌ͷϘτϧωοΫ͕WASMͷಘҙͦ͏ͳλ εΫͰ͋ΕWASMԽΛݕ౼ͯ͠Αͦ͞͏
·ͱΊ: ʮ·ͩૣ͍ʯ • ʮAssemblyScriptͰϥΠϒϥϦίʔυͷߴ ԽΛͯ͠ΈΔʯͷՄೳ͕ͩίεύѱ͍ • WASMJITʹΑΔ࠷దԽ͕ޮ͍͍ͯͳͯ͘ ͍ͷͰঢ়گʹΑͬͯޮՌ͋Γͦ͏ • WASMࣗମ͕·ͩख़͍ͯ͠ͳ͍ͷͰɺ݁
ͱͯ͠ʮ·ͩૣ͍ʯͱ͍͏͜ͱʹ͓ͯ͘͠
Appendix
ݺͼग़͠ͷΦʔόʔϔου • WASMݺͼग़͠ͷΦʔόʔϔουೖྗΛArrayBufferίϐʔ ͨ͠Γग़ྗΛArrayBuffer͔Βίϐʔͨ͠Γ͢Δͷ͕΄ͱΜͲ • ݱࡏWASMʹఏҊ͞Ε͍ͯΔ reference-types ɺanyrefͱ͍͏ ܕͰJSͷΦϒδΣΫτΛWASMʹͤΔΑ͏ʹͳΔ༷ •
anyrefࣗମԿૢ࡞Ͱ͖ͳ͍͕ͩɺ ͨͱ͑ࠓճͷ߹ WASM moduleʹରͯ͠ readU8FromUint8Array(u8array: anyref, offset: usize): u8 Έ͍ͨͳؔΛexport͢Δ͜ͱͰೖྗ ΛArrayBufferʹίϐʔͤͣʹࢀরͰ͖ΔΑ͏ʹͳΔʢͣʣ
ύϑΥʔϚϯεͷࠓޙ • WASMॴḨόΠτίʔυͳͷͰ࣮ߦ͕͜Ε͔ ΒܶతʹมΘΔͱ͍͏͜ͱͳͦ͞͏ • ͍·ωΠςΟϒίʔυͷ30%-50%΄Ͳͷ • ͨͩ͠ɺωΠςΟϒίʔυΛࣗ༝ʹ͑ͳ͍ڥ ʢϒϥβʣͰɺ͜Ε͔ΒWASMʹ͘Δػೳʢͨ ͱ͑SIMDʣ
ʹΑͬͯҰ෦ͷλεΫ͕ܶతʹߴ Խ͢ΔՄೳੑ͋Γ