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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
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.1k
実践TypeScriptトークバトル
gfx
1
1.2k
歴史的経緯の説明 as code
gfx
7
2.9k
Elasticsearchによる 全文検索の実装 in Rails
gfx
6
9.8k
すばらしきGraphQLのSEKAIへようこそ
gfx
20
9.9k
マルチテナント・ウェブアプリケーションの実践
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
代数的データ型って何が嬉しいの? #frontend_phpcon_do
kajitack
8
3.7k
[2026年度第1回ORセミナー] 計画最適化ベンチャーと競技プログラミング人材
terryu16
0
270
Webフレームワークの ベンチマークについて
yusukebe
0
170
Lessons from Spec-Driven Development
simas
PRO
0
210
Lemonade + Foundry Toolkit でお手軽アプリ開発
seosoft
1
360
A2UI という光を覗いてみる
satohjohn
1
140
net-httpのHTTP/2対応について
naruse
0
500
Spec Driven Development | AI Summit Lisbon
danielsogl
PRO
0
200
エージェンティックRAGにAWSで入門しよう!
har1101
8
1.7k
Javaの型とAI時代に型が大事な理由 / java types and type in AI era
kishida
2
140
RTSPクライアントを自作してみた話
simotin13
0
610
Vite+ Unified Toolchain for the Web
naokihaba
0
320
Featured
See All Featured
The Curious Case for Waylosing
cassininazir
1
390
WCS-LA-2024
lcolladotor
0
650
How to train your dragon (web standard)
notwaldorf
97
6.7k
Context Engineering - Making Every Token Count
addyosmani
9
970
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
850
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
0
320
30 Presentation Tips
portentint
PRO
1
330
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
440
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.3k
Building Flexible Design Systems
yeseniaperezcruz
330
40k
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
170
[SF Ruby Conf 2025] Rails X
palkan
2
1.1k
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ʣ
ʹΑͬͯҰ෦ͷλεΫ͕ܶతʹߴ Խ͢ΔՄೳੑ͋Γ