wamr-wasi-extensions: add a cmake package to provide our wasi extension (#4344)

* wasi_ephemeral_nn.h: add a convenience wrapper header
* wamr-wasi-extensions: add a cmake package to provide our wasi extension

the sample app was tested with:
* wasmtime
* iwasm with https://github.com/bytecodealliance/wasm-micro-runtime/pull/4308

currently only contains wasi-nn.
maybe it makes sense to add lib-socket things as well.

cf. https://github.com/bytecodealliance/wasm-micro-runtime/issues/4288
This commit is contained in:
YAMAMOTO Takashi 2025-06-12 10:33:25 +09:00 committed by GitHub
parent 928598f1ce
commit 3a087c4244
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 241 additions and 0 deletions

View File

@ -0,0 +1,7 @@
/*
* Copyright (C) 2025 Midokura Japan KK. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#define WASM_ENABLE_WASI_EPHEMERAL_NN 1
#include "wasi_nn.h"

View File

@ -0,0 +1,8 @@
# Copyright (C) 2025 Midokura Japan KK. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
cmake_minimum_required (VERSION 3.14)
project(wamr-wasi-extensions LANGUAGES C)
add_subdirectory(nn)

View File

@ -0,0 +1,25 @@
# Copyright (C) 2025 Midokura Japan KK. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
add_library(wamr-wasi-nn INTERFACE)
set(wasi_nn_header_dir ${CMAKE_CURRENT_SOURCE_DIR}/../../core/iwasm/libraries/wasi-nn/include)
set(headers
${wasi_nn_header_dir}/wasi_ephemeral_nn.h
${wasi_nn_header_dir}/wasi_nn.h
${wasi_nn_header_dir}/wasi_nn_types.h
)
set_property(TARGET wamr-wasi-nn PROPERTY PUBLIC_HEADER ${headers})
target_include_directories(wamr-wasi-nn
INTERFACE
$<BUILD_INTERFACE:${wasi_nn_header_dir}>
$<INSTALL_INTERFACE:include>)
install(TARGETS wamr-wasi-nn
EXPORT wamr-wasi-nn-config
PUBLIC_HEADER DESTINATION include/wamr)
install(EXPORT wamr-wasi-nn-config
DESTINATION lib/cmake/wamr-wasi-nn)

View File

@ -0,0 +1,13 @@
# Copyright (C) 2025 Midokura Japan KK. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
cmake_minimum_required(VERSION 3.14)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED YES)
set(CMAKE_C_EXTENSIONS NO)
project(nn-classification-openvino LANGUAGES C)
add_executable(nn-classification-openvino "app.c")
find_package(wamr-wasi-nn REQUIRED)
target_link_libraries(nn-classification-openvino wamr-wasi-nn)

View File

@ -0,0 +1,169 @@
/*
* Copyright (C) 2025 Midokura Japan KK. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <sys/stat.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wamr/wasi_ephemeral_nn.h>
/*
* what this application does is basically same as:
* https://github.com/bytecodealliance/wasmtime/tree/efa236e58d09570baaf27865da33fb852fcf40a5/crates/wasi-nn/examples/classification-example
*
* map_file/unmap_file are copy-and-pasted from:
* https://github.com/yamt/toywasm/blob/0eaad8cacd0cc7692946ff19b25994f106113be8/lib/fileio.c
*/
int
map_file(const char *path, void **pp, size_t *sizep)
{
void *p;
size_t size;
ssize_t ssz;
int fd;
int ret;
fd = open(path, O_RDONLY);
if (fd == -1) {
ret = errno;
assert(ret != 0);
return ret;
}
struct stat st;
ret = fstat(fd, &st);
if (ret == -1) {
ret = errno;
assert(ret != 0);
close(fd);
return ret;
}
size = st.st_size;
if (size > 0) {
p = malloc(size);
}
else {
/* Avoid a confusing error */
p = malloc(1);
}
if (p == NULL) {
close(fd);
return ENOMEM;
}
ssz = read(fd, p, size);
if (ssz != size) {
ret = errno;
assert(ret != 0);
close(fd);
return ret;
}
close(fd);
*pp = p;
*sizep = size;
return 0;
}
void
unmap_file(void *p, size_t sz)
{
free(p);
}
static void
print_result(const float *result, size_t sz)
{
/*
* just dump the raw result.
* you can postprocess the output with eg. "sort -k2nr | head"
*/
int i;
for (i = 0; i < sz / sizeof(float); i++) {
printf("%d %f\n", i, result[i]);
}
}
int
main(int argc, char **argv)
{
wasi_nn_error nnret;
int ret;
void *xml;
size_t xmlsz;
ret = map_file("fixture/model.xml", &xml, &xmlsz);
if (ret != 0) {
fprintf(stderr, "failed to load fixture/model.xml: %s\n",
strerror(ret));
exit(1);
}
void *weights;
size_t weightssz;
ret = map_file("fixture/model.bin", &weights, &weightssz);
if (ret != 0) {
fprintf(stderr, "failed to load fixture/model.bin: %s\n",
strerror(ret));
exit(1);
}
/* note: openvino takes two buffers, namely IR and weights */
graph_builder builders[2] = { {
.buf = xml,
.size = xmlsz,
},
{
.buf = weights,
.size = weightssz,
} };
graph g;
nnret = load(builders, 2, openvino, cpu, &g);
unmap_file(xml, xmlsz);
unmap_file(weights, weightssz);
if (nnret != success) {
fprintf(stderr, "load failed with %d\n", (int)nnret);
exit(1);
}
graph_execution_context ctx;
nnret = init_execution_context(g, &ctx);
if (nnret != success) {
fprintf(stderr, "init_execution_context failed with %d\n", (int)nnret);
exit(1);
}
void *tensordata;
size_t tensordatasz;
ret = map_file("fixture/tensor.bgr", &tensordata, &tensordatasz);
if (ret != 0) {
fprintf(stderr, "failed to load fixture/tensor.bgr: %s\n",
strerror(ret));
exit(1);
}
tensor tensor = {
.dimensions = { .buf = (uint32_t[]){1, 3, 224, 224,}, .size = 4, },
.type = fp32,
.data = tensordata,
};
nnret = set_input(ctx, 0, &tensor);
unmap_file(tensordata, tensordatasz);
if (nnret != success) {
fprintf(stderr, "set_input failed with %d\n", (int)nnret);
exit(1);
}
nnret = compute(ctx);
if (nnret != success) {
fprintf(stderr, "compute failed with %d\n", (int)nnret);
exit(1);
}
float result[1001];
uint32_t resultsz;
nnret = get_output(ctx, 0, (void *)result, sizeof(result), &resultsz);
if (nnret != success) {
fprintf(stderr, "get_output failed with %d\n", (int)nnret);
exit(1);
}
print_result(result, resultsz);
}

19
wamr-wasi-extensions/test.sh Executable file
View File

@ -0,0 +1,19 @@
#! /bin/sh
# Copyright (C) 2025 Midokura Japan KK. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
PREFIX=/tmp/wamr
WASI_SDK=${WASI_SDK:-/opt/wasi-sdk}
cmake -B build-lib \
-DCMAKE_TOOLCHAIN_FILE=${WASI_SDK}/share/cmake/wasi-sdk.cmake \
-DCMAKE_INSTALL_PREFIX=${PREFIX} \
.
cmake --build build-lib -t install
cmake -B build-app-nn \
-DCMAKE_TOOLCHAIN_FILE=${WASI_SDK}/share/cmake/wasi-sdk.cmake \
-DCMAKE_PREFIX_PATH=${PREFIX} \
samples/nn
cmake --build build-app-nn