From 2aa6aa62c6182317679596f7372dde6ee3665d15 Mon Sep 17 00:00:00 2001 From: Thomas Lively <7121787+tlively@users.noreply.github.com> Date: Tue, 24 Nov 2020 21:16:30 -0800 Subject: [wasm-split] Read and use profiles (#3400) Read the profiles produced by wasm-split's instrumentation to guide splitting. In this initial implementation, all functions that the profile shows to have been called are kept in the initial module. In the future, users may be able to tune this so that functions that are run later will still be split out. --- test/lit/wasm-split/call_exports.mjs | 25 ++++++++++++ test/lit/wasm-split/profile-guided.wast | 67 +++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 test/lit/wasm-split/call_exports.mjs create mode 100644 test/lit/wasm-split/profile-guided.wast (limited to 'test/lit/wasm-split') diff --git a/test/lit/wasm-split/call_exports.mjs b/test/lit/wasm-split/call_exports.mjs new file mode 100644 index 000000000..546564d2e --- /dev/null +++ b/test/lit/wasm-split/call_exports.mjs @@ -0,0 +1,25 @@ +// Instantiates an instrumented module, calls the given exports, then collects +// its wasm-split profile and writes it to a given file. +// +// Usage: +// +// node call_exports.mjs * + +import * as fs from 'fs'; + +let wasm = process.argv[2]; +let outFile = process.argv[3]; + +// Create the Wasm instance +let { _, instance } = await WebAssembly.instantiate(fs.readFileSync(wasm)); + +// Call the specified exports +for (let i = 4; i < process.argv.length; i++) { + console.log('calling', process.argv[i]); + instance.exports[process.argv[i]](); +} + +// Create and read the profile +let profileSize = instance.exports['__write_profile'](0, 2**32 - 1); +let profileData = Buffer.from(instance.exports.memory.buffer, 0, profileSize); +fs.writeFileSync(outFile, profileData); diff --git a/test/lit/wasm-split/profile-guided.wast b/test/lit/wasm-split/profile-guided.wast new file mode 100644 index 000000000..f2d79f99c --- /dev/null +++ b/test/lit/wasm-split/profile-guided.wast @@ -0,0 +1,67 @@ +;; Instrument the binary + +;; RUN: wasm-split --instrument %s -o %t.instrumented.wasm + +;; Create profiles + +;; RUN: node %S/call_exports.mjs %t.instrumented.wasm %t.foo.prof foo +;; RUN: node %S/call_exports.mjs %t.instrumented.wasm %t.bar.prof bar +;; RUN: node %S/call_exports.mjs %t.instrumented.wasm %t.both.prof foo bar +;; RUN: node %S/call_exports.mjs %t.instrumented.wasm %t.none.prof + +;; Create profile-guided splits + +;; RUN: wasm-split %s --profile=%t.foo.prof -v -o1 %t.foo.1.wasm -o2 %t.foo.2.wasm \ +;; RUN: | filecheck %s --check-prefix FOO + +;; FOO: Keeping functions: deep_foo_callee, foo, foo_callee, shared_callee +;; FOO: Splitting out functions: bar, bar_callee, uncalled + +;; RUN: wasm-split %s --profile=%t.bar.prof -v -o1 %t.bar.1.wasm -o2 %t.bar.2.wasm \ +;; RUN: | filecheck %s --check-prefix BAR + +;; BAR: Keeping functions: bar, bar_callee, shared_callee +;; BAR: Splitting out functions: deep_foo_callee, foo, foo_callee, uncalled + +;; RUN: wasm-split %s --profile=%t.both.prof -v -o1 %t.both.1.wasm -o2 %t.both.2.wasm \ +;; RUN: | filecheck %s --check-prefix BOTH + +;; BOTH: Keeping functions: bar, bar_callee, deep_foo_callee, foo, foo_callee, shared_callee +;; BOTH: Splitting out functions: uncalled + +;; RUN: wasm-split %s --profile=%t.none.prof -v -o1 %t.none.1.wasm -o2 %t.none.2.wasm \ +;; RUN: | filecheck %s --check-prefix NONE + +;; NONE: Keeping functions: +;; NONE: Splitting out functions: bar, bar_callee, deep_foo_callee, foo, foo_callee, shared_callee, uncalled + + +(module + (memory $mem 1 1) + (export "memory" (memory $mem)) + (export "foo" (func $foo)) + (export "bar" (func $bar)) + (export "uncalled" (func $uncalled)) + + (func $foo + (call $foo_callee) + (call $shared_callee) + ) + + (func $bar + (call $shared_callee) + (call $bar_callee) + ) + + (func $uncalled) + + (func $foo_callee + (call $deep_foo_callee) + ) + + (func $bar_callee) + + (func $shared_callee) + + (func $deep_foo_callee) +) -- cgit v1.2.3