-
Notifications
You must be signed in to change notification settings - Fork 667
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test(wasi-threads): add tests for wasi threads
- Loading branch information
Showing
8 changed files
with
469 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#!/bin/bash | ||
|
||
CC=${CC:=/opt/wasi-sdk/bin/clang} | ||
WASI_SYSROOT=${WASI_SYSROOT:=~/dev/wasi-libc/sysroot} | ||
WAMR_DIR=../../../../.. | ||
|
||
for test_c in *.c; do | ||
test_wasm="$(basename $test_c .c).wasm" | ||
|
||
echo "Compiling $test_c to $test_wasm" | ||
$CC \ | ||
--sysroot $WASI_SYSROOT \ | ||
-target wasm32-wasi-threads \ | ||
-pthread -ftls-model=local-exec \ | ||
-z stack-size=32768 \ | ||
-Wl,--export=__heap_base \ | ||
-Wl,--export=__data_end \ | ||
-Wl,--shared-memory,--max-memory=1966080 \ | ||
-Wl,--export=wasi_thread_start \ | ||
-Wl,--export=malloc \ | ||
-Wl,--export=free \ | ||
-I $WAMR_DIR/samples/wasi-threads/wasm-apps \ | ||
$WAMR_DIR/samples/wasi-threads/wasm-apps/wasi_thread_start.S \ | ||
$test_c -o $test_wasm | ||
done |
128 changes: 128 additions & 0 deletions
128
core/iwasm/libraries/wasi-threads/test/create_threads_until_limit.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
/* | ||
* Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. | ||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
*/ | ||
|
||
#ifndef __wasi__ | ||
#error This example only compiles to WASM/WASI target | ||
#endif | ||
|
||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <assert.h> | ||
#include <stdbool.h> | ||
|
||
#include "wasi_thread_start.h" | ||
|
||
enum CONSTANTS { | ||
MAX_NUM_THREADS = 4, /* Should be the same as "--max-threads" */ | ||
NUM_RETRY = 5, | ||
SECOND = 1000 * 1000 * 1000, /* 1 second */ | ||
TIMEOUT = 10LL * SECOND | ||
}; | ||
|
||
int g_count = 0; | ||
|
||
typedef struct { | ||
start_args_t base; | ||
int th_ready; | ||
int th_continue; | ||
int th_done; | ||
bool no_ops; | ||
} shared_t; | ||
|
||
void | ||
__wasi_thread_start_C(int thread_id, int *start_arg) | ||
{ | ||
shared_t *data = (shared_t *)start_arg; | ||
|
||
if (data->no_ops) { | ||
__builtin_wasm_memory_atomic_wait32(NULL, 0, 2 * SECOND); | ||
return; | ||
} | ||
|
||
__atomic_store_n(&data->th_ready, 1, __ATOMIC_SEQ_CST); | ||
__builtin_wasm_memory_atomic_notify(&data->th_ready, 1); | ||
|
||
if (__builtin_wasm_memory_atomic_wait32(&data->th_continue, 0, TIMEOUT) | ||
== 2) { | ||
assert(false && "Wait should not time out"); | ||
} | ||
|
||
__atomic_fetch_add(&g_count, 1, __ATOMIC_SEQ_CST); | ||
|
||
__atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST); | ||
__builtin_wasm_memory_atomic_notify(&data->th_done, 1); | ||
} | ||
|
||
int | ||
main(int argc, char **argv) | ||
{ | ||
shared_t data[MAX_NUM_THREADS] = { 0 }; | ||
int thread_ids[MAX_NUM_THREADS]; | ||
|
||
for (int i = 0; i < MAX_NUM_THREADS; i++) { | ||
assert(start_args_init(&data[i].base)); | ||
thread_ids[i] = __wasi_thread_spawn(&data[i]); | ||
printf("Thread created with id=%d\n", thread_ids[i]); | ||
assert(thread_ids[i] > 0 && "Thread creation failed"); | ||
|
||
for (int j = 0; j < i; j++) { | ||
assert(thread_ids[i] != thread_ids[j] && "Duplicated TIDs"); | ||
} | ||
|
||
if (__builtin_wasm_memory_atomic_wait32(&data[i].th_ready, 0, TIMEOUT) | ||
== 2) { | ||
assert(false && "Wait should not time out"); | ||
} | ||
} | ||
|
||
printf("Attempt to create thread when not possible\n"); | ||
shared_t data_fail = { 0 }; | ||
assert(start_args_init(&data_fail.base)); | ||
int thread_id = __wasi_thread_spawn(&data_fail); | ||
start_args_deinit(&data_fail.base); | ||
assert(thread_id < 0 && "Thread creation should fail"); | ||
|
||
printf("Unlock created threads\n"); | ||
for (int i = 0; i < MAX_NUM_THREADS; i++) { | ||
__atomic_store_n(&data[i].th_continue, 1, __ATOMIC_SEQ_CST); | ||
__builtin_wasm_memory_atomic_notify(&data[i].th_continue, 1); | ||
} | ||
|
||
printf("Wait for threads to finish\n"); | ||
for (int i = 0; i < MAX_NUM_THREADS; i++) { | ||
if (__builtin_wasm_memory_atomic_wait32(&data[i].th_done, 0, TIMEOUT) | ||
== 2) { | ||
assert(false && "Wait should not time out"); | ||
} | ||
|
||
start_args_deinit(&data[i].base); | ||
} | ||
|
||
printf("Value of count after update: %d\n", g_count); | ||
assert(g_count == (MAX_NUM_THREADS) | ||
&& "Global count not updated correctly"); | ||
|
||
/* --------------------------------------------------- */ | ||
|
||
printf("Create new threads without waiting from them to finish\n"); | ||
shared_t data_no_join[MAX_NUM_THREADS] = { 0 }; | ||
for (int i = 0; i < MAX_NUM_THREADS; i++) { | ||
/* No graceful memory free to simplify the test */ | ||
assert(start_args_init(&data_no_join[i].base)); | ||
data_no_join[i].no_ops = true; | ||
|
||
int thread_id = -1; | ||
for (int j = 0; j < NUM_RETRY && thread_id < 0; j++) { | ||
thread_id = __wasi_thread_spawn(&data_no_join[i]); | ||
if (thread_id < 0) | ||
__builtin_wasm_memory_atomic_wait32(NULL, 0, SECOND); | ||
} | ||
|
||
printf("Thread created with id=%d\n", thread_id); | ||
assert(thread_id > 0 && "Thread creation should succeed"); | ||
} | ||
|
||
return EXIT_SUCCESS; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* | ||
* Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. | ||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
*/ | ||
|
||
#ifndef __wasi__ | ||
#error This example only compiles to WASM/WASI target | ||
#endif | ||
|
||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <assert.h> | ||
|
||
#include "wasi_thread_start.h" | ||
|
||
enum CONSTANTS { | ||
NUM_THREADS = 5, | ||
NUM_ITER = 1000, | ||
SECOND = 1000 * 1000 * 1000, /* 1 second */ | ||
TIMEOUT = 10LL * SECOND | ||
}; | ||
|
||
int g_count = 0; | ||
|
||
typedef struct { | ||
start_args_t base; | ||
int th_done; | ||
} shared_t; | ||
|
||
void | ||
__wasi_thread_start_C(int thread_id, int *start_arg) | ||
{ | ||
shared_t *data = (shared_t *)start_arg; | ||
|
||
for (int i = 0; i < NUM_ITER; i++) | ||
__atomic_fetch_add(&g_count, 1, __ATOMIC_SEQ_CST); | ||
|
||
__atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST); | ||
__builtin_wasm_memory_atomic_notify(&data->th_done, 1); | ||
} | ||
|
||
int | ||
main(int argc, char **argv) | ||
{ | ||
shared_t data[NUM_THREADS] = { 0 }; | ||
int thread_ids[NUM_THREADS]; | ||
|
||
for (int i = 0; i < NUM_THREADS; i++) { | ||
assert(start_args_init(&data[i].base)); | ||
thread_ids[i] = __wasi_thread_spawn(&data[i]); | ||
assert(thread_ids[i] > 0 && "Thread creation failed"); | ||
} | ||
|
||
printf("Wait for threads to finish\n"); | ||
for (int i = 0; i < NUM_THREADS; i++) { | ||
if (__builtin_wasm_memory_atomic_wait32(&data[i].th_done, 0, TIMEOUT) | ||
== 2) { | ||
assert(false && "Wait should not time out"); | ||
} | ||
|
||
start_args_deinit(&data[i].base); | ||
} | ||
|
||
printf("Value of count after update: %d\n", g_count); | ||
assert(g_count == (NUM_THREADS * NUM_ITER) | ||
&& "Global count not updated correctly"); | ||
|
||
return EXIT_SUCCESS; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* | ||
* Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. | ||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
*/ | ||
|
||
#ifndef __wasi__ | ||
#error This example only compiles to WASM/WASI target | ||
#endif | ||
|
||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <assert.h> | ||
#include <stdbool.h> | ||
#include <pthread.h> | ||
|
||
#include "wasi_thread_start.h" | ||
|
||
enum CONSTANTS { | ||
NUM_THREADS = 4, | ||
NUM_ITER = 200, | ||
SECOND = 1000 * 1000 * 1000, /* 1 second */ | ||
TIMEOUT = 10LL * SECOND | ||
}; | ||
|
||
pthread_mutex_t mutex; | ||
int g_count = 0; | ||
|
||
typedef struct { | ||
start_args_t base; | ||
int th_done; | ||
} shared_t; | ||
|
||
void | ||
__wasi_thread_start_C(int thread_id, int *start_arg) | ||
{ | ||
shared_t *data = (shared_t *)start_arg; | ||
|
||
for (int i = 0; i < NUM_ITER; i++) { | ||
pthread_mutex_lock(&mutex); | ||
g_count++; | ||
pthread_mutex_unlock(&mutex); | ||
} | ||
|
||
__atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST); | ||
__builtin_wasm_memory_atomic_notify(&data->th_done, 1); | ||
} | ||
|
||
int | ||
main(int argc, char **argv) | ||
{ | ||
shared_t data[NUM_THREADS] = { 0 }; | ||
int thread_ids[NUM_THREADS]; | ||
|
||
if (pthread_mutex_init(&mutex, NULL) != 0) { | ||
printf("Failed to init mutex.\n"); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
for (int i = 0; i < NUM_THREADS; i++) { | ||
assert(start_args_init(&data[i].base)); | ||
thread_ids[i] = __wasi_thread_spawn(&data[i]); | ||
assert(thread_ids[i] > 0 && "Thread creation failed"); | ||
} | ||
|
||
printf("Wait for threads to finish\n"); | ||
for (int i = 0; i < NUM_THREADS; i++) { | ||
if (__builtin_wasm_memory_atomic_wait32(&data[i].th_done, 0, TIMEOUT) | ||
== 2) { | ||
assert(false && "Wait should not time out"); | ||
} | ||
|
||
start_args_deinit(&data[i].base); | ||
} | ||
|
||
printf("Value of count after update: %d\n", g_count); | ||
assert(g_count == (NUM_THREADS * NUM_ITER) | ||
&& "Global count not updated correctly"); | ||
|
||
if (pthread_mutex_destroy(&mutex) != 0) { | ||
printf("Failed to init mutex.\n"); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
return EXIT_SUCCESS; | ||
} |
75 changes: 75 additions & 0 deletions
75
core/iwasm/libraries/wasi-threads/test/spawn_multiple_times.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/* | ||
* Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. | ||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
*/ | ||
|
||
#ifndef __wasi__ | ||
#error This example only compiles to WASM/WASI target | ||
#endif | ||
|
||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <assert.h> | ||
#include <stdbool.h> | ||
|
||
#include "wasi_thread_start.h" | ||
|
||
enum CONSTANTS { | ||
NUM_ITER = 50, | ||
NUM_RETRY = 5, | ||
SECOND = 1000 * 1000 * 1000, /* 1 second */ | ||
TIMEOUT = 5LL * SECOND | ||
}; | ||
|
||
typedef struct { | ||
start_args_t base; | ||
int th_done; | ||
} shared_t; | ||
|
||
int g_count = 0; | ||
|
||
void | ||
__wasi_thread_start_C(int thread_id, int *start_arg) | ||
{ | ||
shared_t *data = (shared_t *)start_arg; | ||
|
||
g_count++; | ||
|
||
__atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST); | ||
__builtin_wasm_memory_atomic_notify(&data->th_done, 1); | ||
} | ||
|
||
int | ||
main(int argc, char **argv) | ||
{ | ||
shared_t data = { 0 }; | ||
if (!start_args_init(&data.base)) { | ||
printf("Stack allocation for thread failed\n"); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
for (int i = 0; i < NUM_ITER; i++) { | ||
data.th_done = 0; | ||
|
||
printf("Creating thread\n"); | ||
int thread_id = -1; | ||
for (int j = 0; j < NUM_RETRY && thread_id < 0; j++) { | ||
thread_id = __wasi_thread_spawn(&data); | ||
if (thread_id < 0) | ||
__builtin_wasm_memory_atomic_wait32(NULL, 0, SECOND); | ||
} | ||
assert(thread_id > 0 && "Thread creation should succeed"); | ||
|
||
printf("Waiting for thread to finish\n"); | ||
if (__builtin_wasm_memory_atomic_wait32(&data.th_done, 0, TIMEOUT) | ||
== 2) { | ||
assert(false && "Wait should not time out"); | ||
} | ||
printf("Thread has finished\n"); | ||
} | ||
|
||
assert(g_count == NUM_ITER && "Count has not been updated correctly"); | ||
|
||
start_args_deinit(&data.base); | ||
return EXIT_SUCCESS; | ||
} |
Oops, something went wrong.