RichieSams / FiberTaskingLib

A library for enabling task-based multi-threading. It allows execution of task graphs with arbitrary dependencies.
Apache License 2.0
928 stars 80 forks source link

Emscripten support #134

Open pixelblender opened 3 years ago

pixelblender commented 3 years ago

Hi,

Thank you for this awesome library. Is it possible to have emscripten support using its fiber library https://emscripten.org/docs/api_reference/fiber.h.html ?

RichieSams commented 3 years ago

So, I did a bit of playing around with emscriptem. It could be possible to implement the Fiber class with emscriptem fiber API. Their API is basically identical to ours.

However, the biggest issue is lack of threads support: https://emscripten.org/docs/porting/pthreads.html If I follow the guidelines there, I can get thread creation to work. But as soon as I add pthread_join(), the whole browser hangs. Hacky example:

#include <stdio.h>
#include <pthread.h>

void *func(void *arg)
{
    int threadId = (int)arg;

    printf("I'm a thread - %d!\n", threadId);

    return nullptr;
}

int main()
{
    printf("Hello World\n");

    pthread_t test1;
    pthread_t test2;
    pthread_t test3;

    if (pthread_create(&test1, nullptr, func, (void *)1) != 0)
    {
        printf("Failed to create thread\n");
        return -1;
    }
    if (pthread_create(&test2, nullptr, func, (void *)2) != 0)
    {
        printf("Failed to create thread\n");
        return -1;
    }
    if (pthread_create(&test3, nullptr, func, (void *)3) != 0)
    {
        printf("Failed to create thread\n");
        return -1;
    }

    if (pthread_join(test1, nullptr) != 0)
    {
        printf("Failed to join thread\n");
        return -1;
    }
    if (pthread_join(test2, nullptr) != 0)
    {
        printf("Failed to join thread\n");
        return -1;
    }
    if (pthread_join(test3, nullptr) != 0)
    {
        printf("Failed to join thread\n");
        return -1;
    }

    return 0;
}

If I remove the joins, the prints all work. If I leave them in, the browser hangs trying to compile the WASM to native.

So, it could be possible in future for FTL to compile to WASM via Emscripten. But, atm, it's blocked by the lack of full threads support. A workaround would be to fork FTL and remove all worker threads. Just the main thread and fibers.

pixelblender commented 3 years ago

I tried you code and it works on my end. Did you compile it with -pthread -s PTHREAD_POOL_SIZE=4 ? PTHREAD_POOL_SIZE can be any number as long as it's bigger than 1 I think.

RichieSams commented 3 years ago

Ah. I didn't try PTHREAD_POOL_SIZE. Thanks for following up. I was using -s USE_PTHREADS=1. I think that may be old though

pixelblender commented 3 years ago

Thank you for looking into this. Per the emscripten Pthreads page that you linked, for testing Firefox won't work unless your web server explicitly write header responses related to COOP and COEP Cross-Origin Policies. Chrome should be fine I think.

RichieSams commented 3 years ago

I got it to compile, but when I try to run the triangle_num example in Chrome, it throws an exception: exception thrown: Please compile your program with async support in order to use asynchronous operations like emscripten_fiber_init

https://github.com/RichieSams/FiberTaskingLib/tree/add_wasm_support

Any ideas? I'm passing -s ASYNCIFY, but that doesn't seem to do anything. My googling isn't finding anything either. The only "real" example usage of the fiber api I was able to find was this: https://github.com/Wizcorp/byuu-web/blob/master/libco/emscripten_fiber.c

But my brief searching through the project source code, I wasn't able to find any reference to compiler / linker args.

RichieSams commented 3 years ago

Hmm. I was able to run https://github.com/emscripten-core/emscripten/blob/4d864df0a57024d667e8db171aab2c3385d04c30/tests/test_fibers.cpp

With

cmake_minimum_required(VERSION 3.8)
project(wasm_test CXX)

find_package(Threads REQUIRED)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread -s PTHREAD_POOL_SIZE=8 -s ASYNCIFY")

set (CMAKE_CXX_STANDARD 11)

SET(CMAKE_EXECUTABLE_SUFFIX .html)
add_executable(wasm-test main.cpp)
RichieSams commented 3 years ago

Ah ha!

It looks like I need

SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread -s PTHREAD_POOL_SIZE=8 -s ASYNCIFY")

When compiling the example / tests as well. Not just the lib.

It now fails with some malloc size exceptions. But debugging for another day. Time for bed for me.

pixelblender commented 3 years ago

Tested test_fibers.cpp on my end and it doesn't says anything about malloc size exception. Maybe try with -s WASM=1 ? My flags are -s WASM=1 -pthread -s PTHREAD_POOL_SIZE=4 -s ASYNCIFY. To compile, after sourcing the emsdk_env.sh I called emcmake cmake followed by emmake make.

Yes you need to use the flags for compiling AND linking. I passed it to CMAKE_CXX_FLAGS, CMAKE_C_FLAGS and CMAKE_EXE_LINKER_FLAGS