Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
AssemblyScriptでライブラリコードの高速化をしてみる
FUJI Goro
July 24, 2019
Programming
4
2.1k
AssemblyScriptでライブラリコードの高速化をしてみる
FUJI Goro
July 24, 2019
Tweet
Share
More Decks by FUJI Goro
See All by FUJI Goro
How to Boost Your Code with WebAssembly
gfx
2
2k
実践TypeScriptトークバトル
gfx
1
690
歴史的経緯の説明 as code
gfx
7
2.2k
Elasticsearchによる 全文検索の実装 in Rails
gfx
5
8k
すばらしきGraphQLのSEKAIへようこそ
gfx
20
8.1k
マルチテナント・ウェブアプリケーションの実践
gfx
14
8.7k
How to choose the ORM on Android
gfx
1
3.7k
How Do We Get Along With Static Types
gfx
5
2.9k
"OSSにコントリビュート" なんてしてる場合じゃない!
gfx
21
13k
Other Decks in Programming
See All in Programming
Kotlin 最新動向2022 #tfcon #techfeed
ntaro
1
740
機能横断型チームにおける技術改善
takeshiakutsu
3
390
ゼロから作る Protocol Buffer のパーサーとレキサー / Writing Protocol Buffer Parser/Lexer in Go from scratch
yoheimuta
1
160
Testing, how hard can it be? (Droidcon Lisbon 2022)
dpreussler
3
200
Microsoft Teams の 会議アプリ開発のはじめかた / How to start Microsoft Teams app development
karamem0
0
1.4k
Modern Web Apps with Spring Boot, Angular & TypeScript
toedter
12
14k
ゴーファーくんと学ぶGo言語の世界/golang-world-with-gopher
iwasiman
1
140
Monadic Java
mariofusco
4
250
CLIツールにSwift Concurrencyを適用させようとしている話
417_72ki
3
130
Jakarta EE 10 is Coming Your Way
ivargrimstad
0
1.7k
バンドル最適化マニアクス at tfconf
mizchi
3
1.6k
코드 품질 1% 올리기
pluu
0
780
Featured
See All Featured
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
349
27k
The Cult of Friendly URLs
andyhume
68
4.7k
Making Projects Easy
brettharned
98
4.3k
The World Runs on Bad Software
bkeepers
PRO
56
5.2k
Scaling GitHub
holman
451
140k
Building Your Own Lightsaber
phodgson
94
4.6k
Rebuilding a faster, lazier Slack
samanthasiow
62
7.2k
Learning to Love Humans: Emotional Interface Design
aarron
261
37k
Code Reviewing Like a Champion
maltzj
506
37k
Side Projects
sachag
449
37k
GraphQLとの向き合い方2022年版
quramy
16
8k
Producing Creativity
orderedlist
PRO
333
37k
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ʣ
ʹΑͬͯҰ෦ͷλεΫ͕ܶతʹߴ Խ͢ΔՄೳੑ͋Γ