Skip to content

Commit

Permalink
[WEB][RUNTIME] TVM WebAssembly JS Runtime (apache#5506)
Browse files Browse the repository at this point in the history
* [WEB] Remove the old web runtime

* [WEB][RUNTIME] TVM WebAssembly Runtime

This PR introduces a brand new TVM web runtime based on the WASM standard API.
Main highlights:

- The new runtime is rewritten using the Typescript.
- The new runtime now directly interfaces with WebAssembly's standard API,
  instead of relying on emscripten's API.
  This change will make the js runtime more portable to runtime variants.
  For example, we could also try to make it interface with the tvm's rust runtime implementation.
- System library can be provided through WASI
  - We also build a hack to enable Emscripten to generate a WASI like
    bundle for runtime environment on the Web.
- The wasm generation now uses the mainlin LLVM.
- Dynamic link(dlopen) is not used due to limitation of wasm,
  instead we rely on the recent new RPC refactor to directly
  restart a new session for each wasm binary sent to the RPC.

* Address review comments

* Skip tensorcore test
  • Loading branch information
tqchen authored May 7, 2020
1 parent 54d47cc commit 702fd0f
Show file tree
Hide file tree
Showing 51 changed files with 3,358 additions and 2,590 deletions.
6 changes: 3 additions & 3 deletions docs/api/python/contrib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ tvm.contrib.dlpack
.. automodule:: tvm.contrib.dlpack
:members:

tvm.contrib.emscripten
~~~~~~~~~~~~~~~~~~~~~~
.. automodule:: tvm.contrib.emscripten
tvm.contrib.emcc
~~~~~~~~~~~~~~~~
.. automodule:: tvm.contrib.emcc
:members:

tvm.contrib.miopen
Expand Down
4 changes: 4 additions & 0 deletions python/tvm/_ffi/libinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ def find_lib_path(name=None, search_path=None, optional=False):

dll_path.append(install_lib_dir)

if os.path.isdir(source_dir):
dll_path.append(os.path.join(source_dir, "web", "dist", "wasm"))

dll_path = [os.path.realpath(x) for x in dll_path]
if search_path is not None:
if isinstance(search_path, list):
Expand Down Expand Up @@ -154,6 +157,7 @@ def find_include_path(name=None, search_path=None, optional=False):
ffi_dir = os.path.dirname(os.path.abspath(os.path.expanduser(__file__)))
source_dir = os.path.join(ffi_dir, "..", "..", "..")
install_include_dir = os.path.join(ffi_dir, "..", "..", "..", "..")

third_party_dir = os.path.join(source_dir, "3rdparty")

header_path = []
Expand Down
48 changes: 24 additions & 24 deletions python/tvm/contrib/emscripten.py → python/tvm/contrib/emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,16 @@
# under the License.
"""Util to invoke emscripten compilers in the system."""
# pylint: disable=invalid-name
from __future__ import absolute_import as _abs

import subprocess
from .._ffi.base import py_str
from .._ffi.libinfo import find_lib_path
from tvm._ffi.base import py_str
from tvm._ffi.libinfo import find_lib_path


def create_js(output,
objects,
options=None,
side_module=False,
cc="emcc"):
"""Create emscripten javascript library.
def create_tvmjs_wasm(output,
objects,
options=None,
cc="emcc"):
"""Create wasm that is supposed to run with the tvmjs.
Parameters
----------
Expand All @@ -44,25 +42,27 @@ def create_js(output,
The compile string.
"""
cmd = [cc]
cmd += ["-Oz"]
if not side_module:
cmd += ["-s", "RESERVED_FUNCTION_POINTERS=2"]
cmd += ["-s", "NO_EXIT_RUNTIME=1"]
extra_methods = ['cwrap', 'getValue', 'setValue', 'addFunction']
cfg = "[" + (','.join("\'%s\'" % x for x in extra_methods)) + "]"
cmd += ["-s", "EXTRA_EXPORTED_RUNTIME_METHODS=" + cfg]
else:
cmd += ["-s", "SIDE_MODULE=1"]
cmd += ["-o", output]
cmd += ["-O3"]

cmd += ["-std=c++14"]
cmd += ["-s", "ERROR_ON_UNDEFINED_SYMBOLS=0"]
cmd += ["-s", "STANDALONE_WASM=1"]
cmd += ["-s", "ALLOW_MEMORY_GROWTH=1"]


objects = [objects] if isinstance(objects, str) else objects

with_runtime = False
for obj in objects:
if obj.find("libtvm_web_runtime.bc") != -1:
if obj.find("wasm_runtime.bc") != -1:
with_runtime = True

if not with_runtime and not side_module:
objects += [find_lib_path("libtvm_web_runtime.bc")[0]]
if not with_runtime:
objects += [find_lib_path("wasm_runtime.bc")[0]]

objects += [find_lib_path("tvmjs_support.bc")[0]]

cmd += ["-o", output]
cmd += objects

if options:
Expand All @@ -79,4 +79,4 @@ def create_js(output,
msg += py_str(out)
raise RuntimeError(msg)

create_js.object_format = "bc"
create_tvmjs_wasm.object_format = "bc"
11 changes: 5 additions & 6 deletions python/tvm/exec/rpc_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@
def find_example_resource():
"""Find resource examples."""
curr_path = os.path.dirname(os.path.realpath(os.path.expanduser(__file__)))
base_path = os.path.join(curr_path, "../../../")
index_page = os.path.join(base_path, "web/example_rpc.html")
base_path = os.path.abspath(os.path.join(curr_path, "..", "..", ".."))
index_page = os.path.join(base_path, "web", "apps", "browser", "rpc_server.html")
js_files = [
os.path.join(base_path, "web/tvm_runtime.js"),
os.path.join(base_path, "build/libtvm_web_runtime.js"),
os.path.join(base_path, "build/libtvm_web_runtime.js.mem")
os.path.join(base_path, "web/dist/tvmjs.bundle.js"),
os.path.join(base_path, "web/dist/wasm/tvmjs_runtime.wasi.js")
]
for fname in [index_page] + js_files:
if not os.path.exists(fname):
Expand Down Expand Up @@ -69,7 +68,7 @@ def main(args):

if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('--host', type=str, default="0.0.0.0",
parser.add_argument('--host', type=str, default="localhost",
help='the hostname of the server')
parser.add_argument('--port', type=int, default=9090,
help='The port of the RPC')
Expand Down
5 changes: 3 additions & 2 deletions tests/lint/check_file_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"scala",
"java",
"go",
"ts",
"sh",
"py",
"pyi",
Expand Down Expand Up @@ -81,6 +82,7 @@
# List of file names allowed
ALLOW_FILE_NAME = {
".gitignore",
".eslintignore",
".gitattributes",
"README",
"Makefile",
Expand All @@ -107,8 +109,7 @@
"rust/runtime/tests/test_wasm32/.cargo/config",
"apps/sgx/.cargo/config",
# html for demo purposes
"tests/webgl/test_static_webgl_library.html",
"web/example_rpc.html",
"web/apps/browser/rpc_server.html",
# images are normally not allowed
# discuss with committers before add more images
"apps/android_rpc/app/src/main/res/mipmap-hdpi/ic_launcher.png",
Expand Down
3 changes: 3 additions & 0 deletions tests/lint/rat-excludes
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ core.cpp
build
_static
_build
node_modules
dist
.*~
\#..*\#
\.#.*
Expand All @@ -40,6 +42,7 @@ RelayVisitor.py
# Specific files
package-list
MANIFEST
.eslintignore
.gitignore
.gitattributes
.gitmodules
Expand Down
4 changes: 0 additions & 4 deletions tests/scripts/task_python_docs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ cd ..
make doc
rm -f docs/doxygen/html/*.map docs/doxygen/html/*.md5

# JS doc
jsdoc -c web/.jsdoc_conf.json web/tvm_runtime.js web/README.md

# Java doc
make javadoc

Expand All @@ -54,7 +51,6 @@ rm -rf _docs
mv docs/_build/html _docs
rm -f _docs/.buildinfo
mv docs/doxygen/html _docs/doxygen
mv out _docs/jsdoc
mv jvm/core/target/site/apidocs _docs/javadoc

echo "Start creating the docs tarball.."
Expand Down
72 changes: 0 additions & 72 deletions tests/web/test_packed_func.js

This file was deleted.

24 changes: 0 additions & 24 deletions tests/webgl/README.md

This file was deleted.

58 changes: 0 additions & 58 deletions tests/webgl/test_local_gemm.py

This file was deleted.

Loading

0 comments on commit 702fd0f

Please sign in to comment.