Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/pull.yml
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,8 @@ jobs:
id-token: write
contents: read
strategy:
matrix:
enable-etdump: ['', '--enable-etdump']
fail-fast: false
with:
runner: linux.2xlarge
Expand All @@ -820,7 +822,7 @@ jobs:
source .ci/scripts/setup-emscripten.sh

# Test selective build
bash scripts/build_wasm_tests.sh
bash scripts/build_wasm_tests.sh ${{ matrix.enable-etdump }}

# Install Jest
cd cmake-out-wasm/extension/wasm/test
Expand Down
7 changes: 7 additions & 0 deletions extension/wasm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ list(

add_library(executorch_wasm OBJECT wasm_bindings.cpp)

if(EXECUTORCH_ENABLE_EVENT_TRACER)
list(APPEND link_libraries etdump)
target_compile_definitions(
executorch_wasm PUBLIC EXECUTORCH_ENABLE_EVENT_TRACER
)
endif()

target_compile_options(executorch_wasm PUBLIC ${_common_compile_options})
target_include_directories(
executorch_wasm PUBLIC ${_common_include_directories}
Expand Down
5 changes: 5 additions & 0 deletions extension/wasm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ The output `my_project.js` should contain both the emitted JS code and the conte
- `getMethods()`: Returns the list of methods in the model.
- `loadMethod(methodName)`: Load a method from the model.
- `getMethodMetadata(methodName)`: Get the metadata of a method.
- `etdump()`: If enabled, flushes the etdump buffer and return the results.
- `execute(methodName, inputs)`: Execute a method with the given inputs.
- `forward(inputs)`: Execute the forward method with the given inputs.
- `delete()`: Delete the model from memory.
Expand Down Expand Up @@ -118,6 +119,10 @@ The output `my_project.js` should contain both the emitted JS code and the conte
- `name`: The name of the tensor.
- These are value types and do not need to be manually deleted.

### ETDumpResult
- `buffer`: The buffer containing the ETDump data.
- `delete()`: Delete the ETDumpResult from memory.

### ScalarType
- Only `Float` and `Long` are currently supported.
- `value`: The int constant value of the enum.
Expand Down
27 changes: 24 additions & 3 deletions extension/wasm/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,27 @@ add_custom_target(
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/package.json
)

if(EXECUTORCH_ENABLE_EVENT_TRACER)
set(ETDUMP_UNIT_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/unittests_etdump.js)
else()
set(ETDUMP_UNIT_TESTS
${CMAKE_CURRENT_SOURCE_DIR}/unittests_etdump_disabled.js
)
endif()

add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/unittests_full.js
COMMAND cat ${CMAKE_CURRENT_SOURCE_DIR}/unittests.js ${ETDUMP_UNIT_TESTS} >
${CMAKE_CURRENT_BINARY_DIR}/unittests_full.js
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/unittests.js ${ETDUMP_UNIT_TESTS}
COMMENT "Copying unittests_full.js to build output directory"
)

add_custom_target(
executorch_wasm_unittests
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/unittests_full.js
)

add_executable(executorch_wasm_tests)
target_link_libraries(executorch_wasm_tests PRIVATE executorch_wasm)
target_link_options(
Expand All @@ -48,7 +69,7 @@ target_link_options(
--embed-file
"${MODELS_DIR}@/"
--pre-js
${CMAKE_CURRENT_SOURCE_DIR}/unittests.js
${CMAKE_CURRENT_BINARY_DIR}/unittests_full.js
-sASSERTIONS=2
)
set_target_properties(
Expand All @@ -57,9 +78,9 @@ set_target_properties(
set_property(
TARGET executorch_wasm_tests
APPEND
PROPERTY LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/unittests.js
PROPERTY LINK_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/unittests_full.js
)
add_dependencies(
executorch_wasm_tests executorch_wasm_test_models
executorch_wasm_tests executorch_wasm_unittests executorch_wasm_test_models
executorch_wasm_test_package_json
)
24 changes: 24 additions & 0 deletions extension/wasm/test/unittests_etdump.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

describe("ETDump", () => {
test("etdump enabled", () => {
const module = et.Module.load("add_mul.pte");
const inputs = [et.Tensor.ones([2, 2]), et.Tensor.ones([2, 2]), et.Tensor.ones([2, 2])];
const output = module.forward(inputs);

inputs.forEach((input) => input.delete());
output.forEach((output) => output.delete());
const etdump = module.etdump();
const buffer = etdump.buffer;
expect(buffer).toBeInstanceOf(Uint8Array);
expect(buffer.length).toBeGreaterThan(0);
etdump.delete();
module.delete();
});
});
15 changes: 15 additions & 0 deletions extension/wasm/test/unittests_etdump_disabled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

describe("ETDump", () => {
test("etdump disabled", () => {
const module = et.Module.load("add_mul.pte");
expect(() => module.etdump()).toThrow();
module.delete();
});
});
79 changes: 76 additions & 3 deletions extension/wasm/wasm_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
#include <executorch/runtime/core/exec_aten/util/tensor_util.h>
#include <numeric>

#ifdef EXECUTORCH_ENABLE_EVENT_TRACER
#include <executorch/devtools/etdump/etdump_flatcc.h>
#endif

#define THROW_JS_ERROR(errorType, message, ...) \
({ \
char msg_buf[256]; \
Expand Down Expand Up @@ -51,10 +55,15 @@ using executorch::aten::Tensor;
using ::executorch::extension::BufferDataLoader;
using ::executorch::runtime::Error;
using ::executorch::runtime::EValue;
using ::executorch::runtime::EventTracer;
using ::executorch::runtime::Result;
using ::executorch::runtime::Tag;
using ::executorch::runtime::TensorInfo;

#ifdef EXECUTORCH_ENABLE_EVENT_TRACER
using executorch::etdump::ETDumpGen;
#endif

namespace executorch {
namespace extension {
namespace wasm {
Expand Down Expand Up @@ -495,6 +504,35 @@ struct ET_EXPERIMENTAL JsMethodMeta {
}
};

/**
* EXPERIMENTAL: Wrapper around ETDumpResult for JavaScript.
*/
#ifdef EXECUTORCH_ENABLE_EVENT_TRACER
class ET_EXPERIMENTAL JsETDumpResult final {
public:
JsETDumpResult() = delete;
JsETDumpResult(const JsETDumpResult&) = delete;
JsETDumpResult& operator=(const JsETDumpResult&) = delete;
JsETDumpResult(JsETDumpResult&&) = default;
JsETDumpResult& operator=(JsETDumpResult&&) = default;

explicit JsETDumpResult(uint8_t* buffer, size_t size)
: buffer_(buffer), size_(size) {}

~JsETDumpResult() {
free(buffer_);
}

val get_buffer() const {
return val(typed_memory_view(size_, buffer_));
}

private:
uint8_t* buffer_;
size_t size_;
};
#endif

/**
* EXPERIMENTAL: Wrapper around extension/Module for JavaScript.
*/
Expand All @@ -518,17 +556,32 @@ class ET_EXPERIMENTAL JsModule final {
val memory_view = val(typed_memory_view(length, buffer.data()));
memory_view.call<void>("set", data);
auto loader = std::make_unique<BufferDataLoader>(buffer.data(), length);

#ifdef EXECUTORCH_ENABLE_EVENT_TRACER
std::unique_ptr<EventTracer> etdump_gen = std::make_unique<ETDumpGen>();
#else
std::unique_ptr<EventTracer> etdump_gen = nullptr;
#endif
return std::make_unique<JsModule>(
std::move(buffer), std::make_unique<Module>(std::move(loader)));
std::move(buffer),
std::make_unique<Module>(
std::move(loader), nullptr, nullptr, std::move(etdump_gen)));
}

static std::unique_ptr<JsModule> load(val data) {
if (data.isNull() || data.isUndefined()) {
THROW_JS_ERROR(TypeError, "Data cannot be null or undefined");
}
if (data.isString()) {
return std::make_unique<JsModule>(
std::make_unique<Module>(data.as<std::string>()));
#ifdef EXECUTORCH_ENABLE_EVENT_TRACER
std::unique_ptr<EventTracer> etdump_gen = std::make_unique<ETDumpGen>();
#else
std::unique_ptr<EventTracer> etdump_gen = nullptr;
#endif
return std::make_unique<JsModule>(std::make_unique<Module>(
data.as<std::string>(),
Module::LoadMode::File,
std::move(etdump_gen)));
} else if (data.instanceof (val::global("Uint8Array"))) {
return load_from_uint8_array(data);
} else if (data.instanceof (val::global("ArrayBuffer"))) {
Expand Down Expand Up @@ -569,6 +622,18 @@ class ET_EXPERIMENTAL JsModule final {
return JsMethodMeta::from_method_meta(res.get());
}

#ifdef EXECUTORCH_ENABLE_EVENT_TRACER
std::unique_ptr<JsETDumpResult> etdump() {
ETDumpGen* etdump_gen = dynamic_cast<ETDumpGen*>(module_->event_tracer());
if (etdump_gen == nullptr) {
return nullptr;
}
auto etdump_data = etdump_gen->get_etdump_data();
return std::make_unique<JsETDumpResult>(
static_cast<uint8_t*>(etdump_data.buf), etdump_data.size);
}
#endif

val_array<val> execute(const std::string& method, val js_inputs) {
std::vector<EValue> inputs;
if (js_inputs.isArray()) {
Expand Down Expand Up @@ -613,11 +678,19 @@ EMSCRIPTEN_BINDINGS(WasmBindings) {
#define JS_DECLARE_TAG(NAME) .value(#NAME, Tag::NAME)
EXECUTORCH_FORALL_TAGS(JS_DECLARE_TAG);

#ifdef EXECUTORCH_ENABLE_EVENT_TRACER
class_<JsETDumpResult>("ETDumpResult")
.property("buffer", &JsETDumpResult::get_buffer);
#endif

class_<JsModule>("Module")
.class_function("load", &JsModule::load)
.function("getMethods", &JsModule::get_methods)
.function("loadMethod", &JsModule::load_method)
.function("getMethodMeta", &JsModule::get_method_meta)
#ifdef EXECUTORCH_ENABLE_EVENT_TRACER
.function("etdump", &JsModule::etdump)
#endif
.function("execute", &JsModule::execute)
.function("forward", &JsModule::forward);
class_<JsTensor>("Tensor")
Expand Down
12 changes: 11 additions & 1 deletion scripts/build_wasm_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.

for arg in "$@"; do
if [ "$arg" == "--enable-etdump" ]; then
ETDUMP_OPTS="-DEXECUTORCH_ENABLE_EVENT_TRACER=ON \
-DEXECUTORCH_BUILD_DEVTOOLS=ON \
-DFLATCC_ALLOW_WERROR=OFF"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment here on why this flag is required?

# FlatCC generates warnings depending on the compiler version.
# This may be removed once the warnings are fixed.
fi
done

CMAKE_OUT=cmake-out-wasm

cd "$(dirname "${BASH_SOURCE[0]}")/../"
Expand All @@ -16,7 +26,7 @@ emcmake cmake . -DEXECUTORCH_BUILD_WASM=ON \
-DEXECUTORCH_SELECT_OPS_LIST="aten::mm.out,aten::add.out" \
-DEXECUTORCH_BUILD_TESTS=ON \
-DCMAKE_BUILD_TYPE=Release \
-B"${CMAKE_OUT}"
${ETDUMP_OPTS} -B"${CMAKE_OUT}"

if [ "$(uname)" == "Darwin" ]; then
CMAKE_JOBS=$(( $(sysctl -n hw.ncpu) - 1 ))
Expand Down
Loading