Add mutex stress test (#2472)
As a part of stress-testing we want to ensure that mutex implementation is working correctly and protecting shared resource to be allocated from other threads when mutex is locked. This test covers the most common situations that happen when some program uses mutexes like locks from various threads, locks from the same thread etc.
This commit is contained in:
@ -34,7 +34,10 @@ while [[ $# -gt 0 ]]; do
|
||||
done
|
||||
|
||||
# Stress tests names
|
||||
thread_start_file_exclusions=("spawn_stress_test.wasm" "linear_memory_size_update.wasm" "stress_test_threads_creation.wasm")
|
||||
thread_start_file_exclusions=("linear_memory_size_update.wasm")
|
||||
|
||||
rm -rf *.wasm
|
||||
rm -rf *.aot
|
||||
|
||||
for test_c in *.c; do
|
||||
test_wasm="$(basename $test_c .c).wasm"
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
{
|
||||
"lib-wasi-threads tests": {
|
||||
"spawn_stress_test": "Stress tests are incompatible with the other part and executed differently",
|
||||
"stress_test_threads_creation": "Stress tests are incompatible with the other part and executed differently"
|
||||
}
|
||||
}
|
||||
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
enum CONSTANTS {
|
||||
NUM_ITER = 100000,
|
||||
NUM_RETRY = 8,
|
||||
MAX_NUM_THREADS = 8,
|
||||
RETRY_SLEEP_TIME_US = 2000,
|
||||
};
|
||||
|
||||
unsigned prime_numbers_count = 0;
|
||||
|
||||
bool
|
||||
is_prime(unsigned int num)
|
||||
{
|
||||
for (unsigned int i = 2; i <= (unsigned int)(sqrt(num)); ++i) {
|
||||
if (num % i == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void *
|
||||
check_if_prime(void *value)
|
||||
{
|
||||
unsigned int *num = (unsigned int *)(value);
|
||||
usleep(10000);
|
||||
if (is_prime(*num)) {
|
||||
__atomic_fetch_add(&prime_numbers_count, 1, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
validate()
|
||||
{
|
||||
unsigned int counter = 0;
|
||||
for (unsigned int i = 2; i <= NUM_ITER; ++i) {
|
||||
counter += is_prime(i);
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
void
|
||||
spawn_thread(pthread_t *thread, unsigned int *arg)
|
||||
{
|
||||
int status_code = -1;
|
||||
int timeout_us = RETRY_SLEEP_TIME_US;
|
||||
for (int tries = 0; status_code != 0 && tries < NUM_RETRY; ++tries) {
|
||||
status_code = pthread_create(thread, NULL, &check_if_prime, arg);
|
||||
assert(status_code == 0 || status_code == EAGAIN);
|
||||
if (status_code == EAGAIN) {
|
||||
usleep(timeout_us);
|
||||
timeout_us *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
assert(status_code == 0 && "Thread creation should succeed");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
pthread_t threads[MAX_NUM_THREADS];
|
||||
unsigned int args[MAX_NUM_THREADS];
|
||||
double percentage = 0.1;
|
||||
|
||||
for (unsigned int factorised_number = 2; factorised_number < NUM_ITER;
|
||||
++factorised_number) {
|
||||
if (factorised_number > NUM_ITER * percentage) {
|
||||
fprintf(stderr, "Stress test is %d%% finished\n",
|
||||
(unsigned int)(percentage * 100));
|
||||
percentage += 0.1;
|
||||
}
|
||||
|
||||
unsigned int thread_num = factorised_number % MAX_NUM_THREADS;
|
||||
if (threads[thread_num] != 0) {
|
||||
assert(pthread_join(threads[thread_num], NULL) == 0);
|
||||
}
|
||||
|
||||
args[thread_num] = factorised_number;
|
||||
|
||||
usleep(RETRY_SLEEP_TIME_US);
|
||||
spawn_thread(&threads[thread_num], &args[thread_num]);
|
||||
assert(threads[thread_num] != 0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_NUM_THREADS; ++i) {
|
||||
assert(threads[i] == 0 || pthread_join(threads[i], NULL) == 0);
|
||||
}
|
||||
|
||||
// Check the test results
|
||||
assert(
|
||||
prime_numbers_count == validate()
|
||||
&& "Answer mismatch between tested code and reference implementation");
|
||||
|
||||
fprintf(stderr, "Stress test finished successfully\n");
|
||||
return 0;
|
||||
}
|
||||
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
enum CONSTANTS {
|
||||
NUM_ITER = 200000,
|
||||
NUM_RETRY = 8,
|
||||
MAX_NUM_THREADS = 8,
|
||||
RETRY_SLEEP_TIME_US = 4000,
|
||||
SECOND = 1000 * 1000 * 1000
|
||||
};
|
||||
|
||||
int threads_executed = 0;
|
||||
unsigned int threads_creation_tried = 0;
|
||||
unsigned int threads_in_use = 0;
|
||||
|
||||
void *
|
||||
thread_func(void *arg)
|
||||
{
|
||||
(void)(arg);
|
||||
__atomic_fetch_add(&threads_executed, 1, __ATOMIC_RELAXED);
|
||||
__atomic_fetch_sub(&threads_in_use, 1, __ATOMIC_SEQ_CST);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
spawn_thread(pthread_t *thread)
|
||||
{
|
||||
int status_code = -1;
|
||||
int timeout_us = RETRY_SLEEP_TIME_US;
|
||||
for (int tries = 0; status_code != 0 && tries < NUM_RETRY; ++tries) {
|
||||
status_code = pthread_create(thread, NULL, &thread_func, NULL);
|
||||
__atomic_fetch_add(&threads_creation_tried, 1, __ATOMIC_RELAXED);
|
||||
|
||||
assert(status_code == 0 || status_code == EAGAIN);
|
||||
if (status_code == EAGAIN) {
|
||||
usleep(timeout_us);
|
||||
timeout_us *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
assert(status_code == 0 && "Thread creation should succeed");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
double percentage = 0.1;
|
||||
|
||||
for (int iter = 0; iter < NUM_ITER; ++iter) {
|
||||
if (iter > NUM_ITER * percentage) {
|
||||
fprintf(stderr, "Spawning stress test is %d%% finished\n",
|
||||
(unsigned int)(percentage * 100));
|
||||
percentage += 0.1;
|
||||
}
|
||||
while (__atomic_load_n(&threads_in_use, __ATOMIC_SEQ_CST)
|
||||
== MAX_NUM_THREADS) {
|
||||
usleep(100);
|
||||
}
|
||||
|
||||
__atomic_fetch_add(&threads_in_use, 1, __ATOMIC_SEQ_CST);
|
||||
pthread_t tmp;
|
||||
spawn_thread(&tmp);
|
||||
pthread_detach(tmp);
|
||||
}
|
||||
|
||||
while ((__atomic_load_n(&threads_in_use, __ATOMIC_SEQ_CST) != 0)) {
|
||||
__builtin_wasm_memory_atomic_wait32(&threads_in_use, 0, SECOND);
|
||||
}
|
||||
|
||||
assert(__atomic_load_n(&threads_in_use, __ATOMIC_SEQ_CST) == 0);
|
||||
|
||||
// Validation
|
||||
assert(threads_creation_tried >= threads_executed
|
||||
&& "Test executed more threads than were created");
|
||||
assert((1. * threads_creation_tried) / threads_executed < 2.5
|
||||
&& "Ensuring that we're retrying thread creation less than 2.5 "
|
||||
"times on average ");
|
||||
|
||||
fprintf(stderr,
|
||||
"Spawning stress test finished successfully executed %d threads "
|
||||
"with retry ratio %f\n",
|
||||
threads_creation_tried,
|
||||
(1. * threads_creation_tried) / threads_executed);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user