Open Celebraty opened 1 year ago
AOT mode supports the host function call.
hostFunctionType
? Is the function type all correct?@q82419
Can you help to provide your wasm file and a simple go code to reproduce it? In this situation, it should pass or there are bugs. Thanks.
@q82419
package main
import (
"encoding/binary"
"fmt"
"math"
"os"
"github.com/second-state/WasmEdge-go/wasmedge"
)
var hostFunctionType = wasmedge.NewFunctionType([]wasmedge.ValType{wasmedge.ValType_I32}, []wasmedge.ValType{wasmedge.ValType_I32})
var allWasiFunction = map[string]func(
data interface{}, frame *wasmedge.CallingFrame, params []interface{}) ([]interface{}, wasmedge.Result){
"get_prerank_request_data": PrerankGetRequestValue,
"update_prerank_response": PrerankUpdateResponse,
}
func compileWasm(wasmPath string) string {
// Create Configure
conf := wasmedge.NewConfigure(wasmedge.THREADS, wasmedge.EXTENDED_CONST, wasmedge.TAIL_CALL, wasmedge.WASI)
// Create Compiler
compiler := wasmedge.NewCompilerWithConfig(conf)
outputPath := wasmPath + ".so"
// Compile WASM AOT
err := compiler.Compile(wasmPath, outputPath)
if err != nil {
fmt.Println("Go: Compile WASM to AOT mode Failed!!")
}
conf.Release()
compiler.Release()
return outputPath
}
func GetVm(wasmPath string) *wasmedge.VM {
wasmedge.SetLogErrorLevel()
wasmPath = compileWasm(wasmPath) // if i delete the line, everything went ok
var (
conf = wasmedge.NewConfigure(wasmedge.WASI)
err error
vm = wasmedge.NewVMWithConfig(conf)
wasiobj = vm.GetImportModule(wasmedge.WASI)
)
wasiobj.InitWasi(
os.Args[1:], // The args
os.Environ(), // The envs
[]string{".:."}, // The mapping preopens
)
module := wasmedge.NewModule("env")
for name, function := range allWasiFunction {
temp := wasmedge.NewFunction(hostFunctionType, function, nil, 20)
module.AddFunction(name, temp)
}
err = vm.LoadWasmFile(wasmPath)
if err != nil {
fmt.Printf("failed to load wasm, err=%v\n", err)
return nil
}
vm.RegisterModule(module)
err = vm.Validate()
if err != nil {
fmt.Printf("Validate err=%v\n", err)
return nil
}
err = vm.Instantiate()
if err != nil {
fmt.Printf("Instantiate err=%v\n", err)
return nil
}
conf.Release()
wasiobj.Release()
return vm
}
var curPrerankRequest *PreRankColumnRequest
var curPrerankResponse *RankResponse
var curPrerankVm *wasmedge.VM
type PreRankColumnRequest struct {
Country string `json:"country"`
PpCtrs []float64 `json:"pp_ctrs"`
BidPrices []int64 `json:"bid_prices"`
}
type RankResponse struct {
Score []float64 `json:"score"`
}
func PrerankUpdateResponse(data interface{}, callframe *wasmedge.CallingFrame, params []interface{}) ([]interface{}, wasmedge.Result) {
curPrerankResponse.Score = make([]float64, len(curPrerankRequest.BidPrices))
offset := params[0].(int32)
mem := callframe.GetMemoryByIndex(0)
buf, _ := mem.GetData(uint(offset), uint(8*len(curPrerankRequest.BidPrices)))
curpos := 0
for idx := range curPrerankResponse.Score {
curPrerankResponse.Score[idx] = ReadFloat64(&buf, &curpos)
}
return []interface{}{0}, wasmedge.Result_Success
}
func PrerankGetRequestValue(data interface{}, callframe *wasmedge.CallingFrame, params []interface{}) ([]interface{}, wasmedge.Result) {
if len(params) != 1 {
return nil, wasmedge.Result_Fail
}
dataLen := uint(len(curPrerankRequest.BidPrices) * 8)
pointerBuf, _ := callframe.GetMemoryByIndex(0).GetData(uint(params[0].(int32)), 4)
pos := 0
pointer, _ := curPrerankVm.Execute("allocMem", int32(dataLen))
requestType := ReadInt32(&pointerBuf, &pos)
pos = 0
buf, _ := callframe.GetMemoryByIndex(0).GetData(uint(pointer[0].(int32)), dataLen)
switch requestType {
case 0:
for _, val := range curPrerankRequest.PpCtrs {
PutFloat64(&buf, val, &pos)
}
case 1:
for _, val := range curPrerankRequest.BidPrices {
PutInt64(&buf, val, &pos)
}
}
pos = 0
PutInt32(&pointerBuf, pointer[0].(int32), &pos)
return []interface{}{0}, wasmedge.Result_Success
}
func ExecutePrerankWasi(vm *wasmedge.VM, input *PreRankColumnRequest, funcName string) *RankResponse {
// 为 subject 分配内存,并获得其指针
// 包括一个字节,用于我们在下面添加的 NULL 结束符
response := &RankResponse{}
curPrerankRequest = input
curPrerankVm = vm
curPrerankResponse = response
resp, err := vm.Execute(funcName, int32(len(input.BidPrices)))
if err != nil {
fmt.Printf("prerank with wasi err=%v, resp=%v\n", err, resp)
return nil
}
return response
}
func PutFloat64(bytes *[]byte, f float64, curPos *int) {
bits := math.Float64bits(f)
binary.LittleEndian.PutUint64((*bytes)[*curPos:], bits)
*curPos += 8
}
func PutInt64(bytes *[]byte, i int64, curPos *int) {
binary.LittleEndian.PutUint64((*bytes)[*curPos:], uint64(i))
*curPos += 8
}
func PutInt32(bytes *[]byte, i int32, curPos *int) {
binary.LittleEndian.PutUint32((*bytes)[*curPos:], uint32(i))
*curPos += 4
}
func ReadInt32(bytes *[]byte, curPos *int) int32 {
bits := binary.LittleEndian.Uint32((*bytes)[*curPos : *curPos+4])
*curPos += 4
return int32(bits)
}
func ReadFloat64(bytes *[]byte, curPos *int) float64 {
bits := binary.LittleEndian.Uint64((*bytes)[*curPos : *curPos+8])
ret := math.Float64frombits(bits)
*curPos += 8
return ret
}
func main() {
vm := GetVm("output/bench.wasm")
response := ExecutePrerankWasi(vm, &PreRankColumnRequest{}, "prerank_with_wasi")
fmt.Printf("response=%v\n", response)
}
#include "emscripten/emscripten.h"
#include <stdio.h>
#include <unistd.h>
extern "C" {
int update_prerank_response(void *request);
void *get_prerank_request_data(int field);
}
char* prerank_wasi(int length) {
double *ppctrs = (double *)get_prerank_request_data(0);
long long *bidPrices = (long long*)get_prerank_request_data(1);
void *result = malloc(length * 8);
double *ptr = (double *)result;
for (int i = 0; i < length; ++i) {
*ptr = ppctrs[i] * bidPrices[i];
++ptr;
}
update_prerank_response(result);
free(ppctrs);
free(bidPrices);
free(result);
return nullptr;
}
mkdir -p output
emcc -g -O3 -o output/bench.html cpp/wasm_edge.cpp -s STANDALONE_WASM -sERROR_ON_UNDEFINED_SYMBOLS=0
by the command directly
go run cmd/wasm_edge.go
and then get the err:
[2023-03-15 10:41:10.462] [error] execution failed: out of bounds memory access, Code: 0x88
[2023-03-15 10:41:10.462] [error] When executing function name: "prerank_with_wasi"
prerank with wasi err=out of bounds memory access, resp=[]
if i delete the wasm_edge.go code:
wasmPath = compileWasm(wasmPath)
then i can get the correct response:
response=&{[]}
Hi @Celebraty ,
As your code above, this may be the AOT issue I mentioned, not the host functions. Because the error occurred in the WASM, not in host functions.
From your code, I have additional suggestions in the GetVM
function:
module
object which registered into the VM, and call release()
after finishing the VM. https://wasmedge.org/book/en/sdk/go/ref.html#host-module-registrationsvm.GetImportModule()
API should not be released (although this doesn't matter, because the object didn't get the ownership of the module instance context).@q82419 thanks for your help, i have tried to add a response for the GetVM function, it can return the module which registered into the VM, and the new error occur :
libc++abi: terminating with uncaught exception of type std::__1::system_error: mutex lock failed: Invalid argument
signal: abort trap
do you have any idea how to resolve the problem
@q82419 After more attempts, it was found that the following two errors appeared randomly
first(just as the err before):
[error] execution failed: out of bounds memory access, Code: 0x88
[error] When executing function name: "prerank_with_wasi"
second:
libc++abi: terminating with uncaught exception of type std::__1::system_error: mutex lock failed: Invalid argument
signal: abort trap
finally,i found that this issue happens only on mac;there aren't any issue occured on linux
What i want
just like wasmer, i declare some wasi functions in C++, and call them in C++
then, i defined them in golang, and register them to wasi module, it can run correctly
What's the problem
when i try host function in wasmedge, my register code is
then i call the calculate_score_wasi function, get the error
so, is my fault or the wasmedge hasn't support ? please help, thanks a lot