将 C 编译为 WebAssembly float returns 0?
Compiling C to WebAssembly float returns 0?
我做了一个简单的基准程序来测试 WebAssembly 代码和 javascript 之间的一些性能。问题是当调用我的导出函数时,我得到一个 0
值,而如果我使用 gcc
编译 C 程序,我会得到适当的输出。例如,4.843003
。
我刚刚开始 WebAssembly 编程,所以我不确定我做错了什么。当我 return 一个硬编码数字时,它似乎在我的 Chrome JS 控制台中工作正常。
我用来编译的标志:
emcc -Os main.c -o main.wasm -s WASM=1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <emscripten.h>
int MAX_SIZE = 1000000;
int MAX_RUNS = 1000;
EMSCRIPTEN_KEEPALIVE
float benchmark() {
int i, j;
float seconds;
clock_t t;
int arr[MAX_SIZE];
srand(time(0));
t = clock();
for(i = 0; i < MAX_RUNS; i++) {
for(j = 0; j < MAX_SIZE; j++) {
arr[j] = rand();
}
}
t = clock() - t;
seconds = ((float)t) / CLOCKS_PER_SEC;
return seconds;
}
我想我不太确定在 JS 代码中,importObject
是干什么用的。我刚刚按照一些教程获得了某种输出,并通过查看 wasm2wat
输出得出了这个结论:
const importObject ={
env: {
STACKTOP: 0,
STACK_MAX:65536,
abortWhosebug: function(val) { throw new Error("stackoverfow"); },
memory: new WebAssembly.Memory( { initial: 256, maximum:256 } ),
table: new WebAssembly.Table( { initial:14, maximum:14, element: "anyfunc" } ),
__memory_base:0,
__table_base:0,
_clock: () => {},
abort: () => {},
___syscall146: () => {},
_emscripten_memcpy_big: () => {},
___syscall6: () => {},
___syscall54: () => {},
_time: () => {},
___syscall140: () => {},
_printf: () => {},
_rand: () => {},
_srand: () => {},
abortOnCannotGrowMemory: () => {},
nullFunc_ii: () => {},
nullFunc_iiii: () => {},
nullFunc_jiji: () => {},
___lock: () => {},
___setErrNo: () => {},
___unlock: () => {},
_emscripten_get_heap_size: () => {},
_emscripten_memcpy_big: () => {},
_emscripten_resize_heap: () => {},
setTempRet0: () => {},
tempDoublePtr: 0,
DYNAMICTOP_PTR: 0
}
};
WebAssembly.instantiateStreaming(fetch("main.wasm"), importObject).then((m) => {
const { instance } = m;
const n = instance.exports._benchmark();
console.log(n);
});
所以我不确定这是否真的合适...关于我应该如何进行的任何想法?
clock()
总是return0
,因为_clock
没有实现。
使用 emscripten 运行时。
emcc -Os main.c -o main.js -s WASM=1
或者自己定义,像这样
_clock: () => { return Date.now() * 1000; },
正如@zakki 所说,你不应该 运行 .wasm
直接提交, 除非你知道它的意思。
WebAssembly 是一个非常小的 VM,它只能进行 运行 基本操作。它没有 any 系统库。它不知道 clock()
是什么意思,它没有任何文件系统,它不能 运行 TCP/IP 网络...它真的不能 any系统操作。
相反,Wasm 可以导入外部代码。在浏览器上下文中,Wasm 可以导入 JS 代码来模拟系统库。这就是 Emscripten 存在的原因。 Emscripten 不仅是一个 C/C++ -> Wasm 编译器,而且是一个完整的工具链,包括必要的 JS 运行时间来模拟 C 标准库 (libc)。
在你的例子中,你可以看到 time()
如何在 JS 端模拟 Emscripten source code:
clock: function() {
if (_clock.start === undefined) _clock.start = Date.now();
return ((Date.now() - _clock.start) * ({{{ cDefine('CLOCKS_PER_SEC') }}} / 1000))|0;
}
所以基本上是借用JS的Date.now()
函数来模拟的。 因此你不能 运行 .wasm
直接文件,你应该 运行 在 Emscripten JS 运行 的时候。
emcc -Os main.c -o main.js -s WASM=1
或者你可以在 HTML 和 运行 中完成。
emcc -Os main.c -o main.html -s WASM=1
我做了一个简单的基准程序来测试 WebAssembly 代码和 javascript 之间的一些性能。问题是当调用我的导出函数时,我得到一个 0
值,而如果我使用 gcc
编译 C 程序,我会得到适当的输出。例如,4.843003
。
我刚刚开始 WebAssembly 编程,所以我不确定我做错了什么。当我 return 一个硬编码数字时,它似乎在我的 Chrome JS 控制台中工作正常。
我用来编译的标志:
emcc -Os main.c -o main.wasm -s WASM=1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <emscripten.h>
int MAX_SIZE = 1000000;
int MAX_RUNS = 1000;
EMSCRIPTEN_KEEPALIVE
float benchmark() {
int i, j;
float seconds;
clock_t t;
int arr[MAX_SIZE];
srand(time(0));
t = clock();
for(i = 0; i < MAX_RUNS; i++) {
for(j = 0; j < MAX_SIZE; j++) {
arr[j] = rand();
}
}
t = clock() - t;
seconds = ((float)t) / CLOCKS_PER_SEC;
return seconds;
}
我想我不太确定在 JS 代码中,importObject
是干什么用的。我刚刚按照一些教程获得了某种输出,并通过查看 wasm2wat
输出得出了这个结论:
const importObject ={
env: {
STACKTOP: 0,
STACK_MAX:65536,
abortWhosebug: function(val) { throw new Error("stackoverfow"); },
memory: new WebAssembly.Memory( { initial: 256, maximum:256 } ),
table: new WebAssembly.Table( { initial:14, maximum:14, element: "anyfunc" } ),
__memory_base:0,
__table_base:0,
_clock: () => {},
abort: () => {},
___syscall146: () => {},
_emscripten_memcpy_big: () => {},
___syscall6: () => {},
___syscall54: () => {},
_time: () => {},
___syscall140: () => {},
_printf: () => {},
_rand: () => {},
_srand: () => {},
abortOnCannotGrowMemory: () => {},
nullFunc_ii: () => {},
nullFunc_iiii: () => {},
nullFunc_jiji: () => {},
___lock: () => {},
___setErrNo: () => {},
___unlock: () => {},
_emscripten_get_heap_size: () => {},
_emscripten_memcpy_big: () => {},
_emscripten_resize_heap: () => {},
setTempRet0: () => {},
tempDoublePtr: 0,
DYNAMICTOP_PTR: 0
}
};
WebAssembly.instantiateStreaming(fetch("main.wasm"), importObject).then((m) => {
const { instance } = m;
const n = instance.exports._benchmark();
console.log(n);
});
所以我不确定这是否真的合适...关于我应该如何进行的任何想法?
clock()
总是return0
,因为_clock
没有实现。
使用 emscripten 运行时。
emcc -Os main.c -o main.js -s WASM=1
或者自己定义,像这样
_clock: () => { return Date.now() * 1000; },
正如@zakki 所说,你不应该 运行 .wasm
直接提交, 除非你知道它的意思。
WebAssembly 是一个非常小的 VM,它只能进行 运行 基本操作。它没有 any 系统库。它不知道 clock()
是什么意思,它没有任何文件系统,它不能 运行 TCP/IP 网络...它真的不能 any系统操作。
相反,Wasm 可以导入外部代码。在浏览器上下文中,Wasm 可以导入 JS 代码来模拟系统库。这就是 Emscripten 存在的原因。 Emscripten 不仅是一个 C/C++ -> Wasm 编译器,而且是一个完整的工具链,包括必要的 JS 运行时间来模拟 C 标准库 (libc)。
在你的例子中,你可以看到 time()
如何在 JS 端模拟 Emscripten source code:
clock: function() {
if (_clock.start === undefined) _clock.start = Date.now();
return ((Date.now() - _clock.start) * ({{{ cDefine('CLOCKS_PER_SEC') }}} / 1000))|0;
}
所以基本上是借用JS的Date.now()
函数来模拟的。 因此你不能 运行 .wasm
直接文件,你应该 运行 在 Emscripten JS 运行 的时候。
emcc -Os main.c -o main.js -s WASM=1
或者你可以在 HTML 和 运行 中完成。
emcc -Os main.c -o main.html -s WASM=1