Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NodeMCU examples throw errors #26

Closed
robinvanemden opened this issue Dec 27, 2019 · 24 comments
Closed

NodeMCU examples throw errors #26

robinvanemden opened this issue Dec 27, 2019 · 24 comments

Comments

@robinvanemden
Copy link
Contributor

robinvanemden commented Dec 27, 2019

About two weeks ago, we were able to run several WebAssembly modules on NodeMCU ESP microcontrollers following the esp32-pio and esp8266 platform examples.

In the meanwhile, work on wasm3 has clearly continued - we are particularly happy with the WASI support!

I am, however, now unable to run our WASM modules using the latest code base. For instance, on adapting the esp8266 example as follows:

#include <stdio.h>

#include "Arduino.h"

#define FATAL(msg, ...) { printf("Fatal: " msg "\n", ##__VA_ARGS__); return; }

#include "m3/m3.h" 
#include "m3/m3_env.h"

#include "m3/extra/fib32.wasm.h"

void run_wasm()
{
    M3Result result = c_m3Err_none;

    uint8_t* wasm = (uint8_t*)fib32_wasm;
    size_t fsize = fib32_wasm_len-1;

    IM3Environment env = m3_NewEnvironment ();
    if (!env) FATAL("m3_NewEnvironment failed");

    IM3Runtime runtime = m3_NewRuntime (env, 64*1024, NULL);
    if (!runtime) FATAL("m3_NewRuntime failed");

    IM3Module module;
    result = m3_ParseModule (env, &module, wasm, fsize);
    if (result) FATAL("m3_ParseModule: %s", result);

    result = m3_LoadModule (runtime, module);
    if (result) FATAL("m3_LoadModule: %s", result);
    
    /*result = m3_LinkWASI (runtime->modules);
    if (result) FATAL("m3_LinkWASI: %s", result); 
    
    result = m3_LinkLibC (runtime->modules);
    if (result) FATAL("m3_LinkLibC: %s", result);*/
    
    IM3Function f;
    result = m3_FindFunction (&f, runtime, "fib");
    if (result) FATAL("m3_FindFunction: %s", result);

    const char* i_argv[2] = { "3", NULL };
    result = m3_CallWithArgs (f, 1, i_argv);

    if (result) FATAL("Call: %s", result);

    long value = *(long*)(runtime->stack);

    Serial.println(value);

}

void setup()
{
  Serial.begin(115200);
  delay(10);

  Serial.print("\nwasm3 on ESP8266, build " __DATE__ " " __TIME__ "\n");

  u32 start = millis();
  run_wasm();
  u32 end = millis();

  Serial.print(String("Elapsed: ") +  (end - start) + " ms\n");
}

void loop()
{
  delay(100);
}

... one of our ESP8266's throws the following error:

wasm3 on ESP8266, build Dec 27 2019 18:59:05
Fatal: m3_NewRuntime failed
Elapsed: 6 ms

Also, updating the code of the esp32-pio example along the same lines throws a Guru Meditation error, followed by a boot loop.

Might it be possible to provide a minimal working example that runs, for instance, fib32_wasm on ESP8266 and ESP32 using the latest version of wasm3?

(Separately, linking WASI gives rise to the following error on the ESP8266:
/home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/time/clock.c:62: undefined reference to _times_r
... but that is of course a different issue)

@robinvanemden robinvanemden changed the title Several of the platform examples do not run anymore NodeMCU examples do not run anymore Dec 27, 2019
@robinvanemden robinvanemden changed the title NodeMCU examples do not run anymore NodeMCU examples throw errors Dec 27, 2019
@hberntsen
Copy link

hberntsen commented Dec 27, 2019

I just spent some time debugging this. It looks like d_m3AllocateLinearMemory needs to be defined (tested on an ESP32 (with idf) and Linux) in order not to crash.

A Git bisect pointed me to 73c990a where the Entry op reads from _mem, which is NULL when d_m3AllocateLinearMemory = 0

@vshymanskyy
Copy link
Member

vshymanskyy commented Dec 28, 2019

Yes you're right. After the initial support of different platforms was added (as an experiment), wasm3 changed a lot. So examples for MCUs are a bit left behind (I'm surprised they worked at all ;).
We'll get to fixing/updating them soon.

@vshymanskyy
Copy link
Member

vshymanskyy commented Dec 28, 2019

You should enable d_m3AllocateLinearMemory safely on any platform, that is capable of allocating at least one Wasm memory page (65536 bytes).

@robinvanemden
Copy link
Contributor Author

robinvanemden commented Dec 28, 2019

Super that you'll be able to get around to fixing/updating the MCU examples - being able to run WASM on MCU's is a great prospect! Enabling d_m3AllocateLinearMemory by itself does not seem enough to make things work yet, probably there is something I am still missing.

I don't know if it is of any use, but the latest esp-pio based wasm3 example we ran was based on commit 4c01ba4, about 17 days ago. We just removed the then still uncompleted WASI C files from the m3 directory and added an m3/m3_core.h include to the original example code:

// ESP-PIO Fibonacci test, Wasm3, no-WASI, 4c01ba4, Dec 12th

#include <stdio.h>
#include <time.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "esp_system.h"
#include "esp_spi_flash.h"

#define FATAL(msg, ...) { printf("Fatal: " msg "\n", ##__VA_ARGS__); return; }

#include "m3/m3.h"
#include "m3/m3_core.h"

#include "m3/extra/fib32.wasm.h"

void run_wasm()
{
    M3Result result = c_m3Err_none;

    u8* wasm = (u8*)fib32_wasm;
    u32 fsize = fib32_wasm_len-1;

    printf("Loading WebAssembly...\n");

    IM3Module module;
    result = m3_ParseModule (& module, wasm, fsize);
    if (result) FATAL("m3_ParseModule: %s", result);

    IM3Runtime env = m3_NewRuntime (1024);
    if (!env) FATAL("m3_NewRuntime");

    result = m3_LoadModule (env, module);
    if (result) FATAL("m3_LoadModule: %s", result);

    IM3Function f;
    result = m3_FindFunction (&f, env, "fib");
    if (result) FATAL("m3_FindFunction: %s", result);

    printf("Running...\n");

    const char* i_argv[2] = { "24", NULL };
    result = m3_CallWithArgs (f, 1, i_argv);

    if (result) FATAL("m3_CallWithArgs: %s", result);
}

void wasm_task(void*)
{
    printf("\nwasm3 on ESP32, build " __DATE__ " " __TIME__ "\n");

    clock_t start = clock();
    run_wasm();
    clock_t end = clock();

    printf("Elapsed: %d ms\n", (end - start)*1000 / CLOCKS_PER_SEC);

    for(;;) {
        vTaskDelay(0xFFFF);
    }
}

extern "C"
void app_main()
{
    /* Print chip information */
    esp_chip_info_t chip_info;
    esp_chip_info(&chip_info);
    printf("This is ESP32 chip with %d CPU cores, WiFi%s%s, ",
            chip_info.cores,
            (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
            (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");

    printf("silicon revision %d, ", chip_info.revision);

    printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
            (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");

    xTaskCreate(&wasm_task, "wasm_m3", 32768, NULL, 5, NULL);

    for(;;) {
        vTaskDelay(0xFFFF);
    }
}

Which, when run on an ESP32-WROOM-32, indeed correctly calculates the 24th term of the Fibonacci sequence:

This is ESP32 chip with 2 CPU cores, WiFi/BT/BLE, silicon revision 1, 4MB external flash

wasm3 on ESP32, build Dec 28 2019 12:53:11
Loading WebAssembly...
Running...
Result: 46368
Elapsed: 410 ms

@vshymanskyy
Copy link
Member

vshymanskyy commented Dec 28, 2019 via email

@robinvanemden
Copy link
Contributor Author

robinvanemden commented Dec 28, 2019

Thanks again!

As an aside: one of the main reasons of our interest in WASI is that often even basic C/C++ scripts compiled with Emscripten (see for instance this discussion) and clang (with wasi-libc) make use of some WASI imports. So if full WASI support is not viable, maybe a limited implementation of a subset of WASI would be able to cover the most often generated imports?

@igrr
Copy link
Contributor

igrr commented Dec 30, 2019

@vshymanskyy Would you be interested in a PR to add CI tests for the ESP32 platform (in QEMU)?

@vshymanskyy
Copy link
Member

vshymanskyy commented Dec 30, 2019

@igrr it would be much appreciated ;) I've already considered QEMU for this kind of tests.

@igrr
Copy link
Contributor

igrr commented Dec 30, 2019

First step, just adding the build test: #27.

@vshymanskyy
Copy link
Member

@robinvanemden @hberntsen should work now with esp8266, esp32-pio examples

@robinvanemden
Copy link
Contributor Author

@robinvanemden @hberntsen should work now with esp8266, esp32-pio examples

Both esp8266 and esp32-pio platform examples work perfectly again - thanks, @vshymanskyy !

Also great work on the CI tests for the ESP32, @igrr ..

@vshymanskyy
Copy link
Member

vshymanskyy commented Jan 2, 2020

Far from ideal, but I have a prototype of ESP32 running or simple WASI test:
image

@robinvanemden
Copy link
Contributor Author

That is very cool! Thanks! Is it now mainly a question of including m3_LinkWASI(), or is there rather more to it?

@vshymanskyy
Copy link
Member

vshymanskyy commented Jan 2, 2020

@robinvanemden this isn't yet available on guthub, and currently requires PSRAM, 64Kb of native stack, and so on. I think it can be included as a separate example, but it also requires a lot of cleanup ;)
We're now almost ready to issue the first release, so I'll have to put this on hold.

@vshymanskyy
Copy link
Member

@igrr FYI ;)

@igrr
Copy link
Contributor

igrr commented Jan 3, 2020

Very interested as well! Can help with cleanup for this new example.

@hberntsen
Copy link

@robinvanemden For WASI on the ESP32 you need to integrate with the FreeRTOS/ESP32 API. I am doing some experiments with Rust -> Webassembly -> wasm3 on ESP32. I already got a simple thread::sleep working by implementing a small piece of WASI. I've been trying to include Rust's standard library but even for a simple println! I run out of memory. (On x86 I already need to allocate a heap > 200K, my new ESP32 with PSRAM is being shipped from China now)

@vshymanskyy
Copy link
Member

@igrr @robinvanemden @hberntsen A basic ESP32-WASI example has landed here: https://github.com/wasm3/wasm3/tree/master/platforms/esp32-idf-wasi
Please consider contributing your improvements. Thanks!

@robinvanemden
Copy link
Contributor Author

@vshymanskyy that is great news - thanks for making the ESP32-WASI example available! I should be able to test the code on some of our ESP32s tomorrow :)

@robinvanemden
Copy link
Contributor Author

Hi @vshymanskyy, I was just able to do a quick test-run of the basic ESP32-WASI example on an ESP32-WROVER-B with 4MB of flash memory and 8MB of PSRAM, and received the following error message:

Fatal: m3_CallWithArgs: compiling function overrun its stack height limit

I presume that I should, in principle, be able to get the example to run on an ESP32-WROVER-B? I am able to put some time into a further investigation of this issue later this week. Of course, suggestions and tips are always welcome :)

@robinvanemden
Copy link
Contributor Author

It might also be useful to know the exact ESP32 make and model you made the examle work for - then I could compare specs and get an idea of where you are starting from.

@vshymanskyy
Copy link
Member

@robinvanemden I don't think your ESP32 is different too much.
Indeed I just tried running it once again, and I reproduced the same issue. I'll take a look ASAP!

@vshymanskyy
Copy link
Member

@robinvanemden fixed in 0edc1af

@robinvanemden
Copy link
Contributor Author

@robinvanemden fixed in 0edc1af

Yay! That commit solved my final issue - your example code now runs perfectly on three different types of ESP32 WROVER:

Wasm3 v0.4.1 on ESP32, build Jan 10 2020 14:45:35
Loading WebAssembly...
Running...
Hello world
Constructor OK
Hello printf!
Args: test.wasm;
Now: 8 sec, 974604000 ns
4 + 2 = 6
fib(20) = 6765 [47.255 ms]
=== done ===
Result: 0
Elapsed: 150 ms

Thanks once again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

4 participants