-
Notifications
You must be signed in to change notification settings - Fork 112
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Multiple Pals could return spuriously from wake on address (#739)
* Add stress test benchmark Co-authored-by: Alexander Nadeau <[email protected]> * Add defensive code against spurious wakeup This commit checks that wait_on_address has not returned spuriously. * pal: spurious wake up. The code in the Pal for wake on address was incorrectly assuming the operation returning success meant it had actually changed. The specification allows for spurious wake ups. This change makes the Pals recheck for a change. --------- Co-authored-by: Alexander Nadeau <[email protected]>
- Loading branch information
Showing
7 changed files
with
153 additions
and
30 deletions.
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
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
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
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
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
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
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,122 @@ | ||
/** | ||
* This benchmark is based on | ||
* https://github.com/microsoft/mimalloc/issues/1002#issuecomment-2630410617 | ||
* | ||
* It causes large batchs of memory to be freed on a remote thread, and causes | ||
* many aspects of the backend to be under-contention. | ||
* | ||
* The benchmark has a single freeing thread, and many allocating threads. The | ||
* allocating threads communicate using a shared list of memory to free, which | ||
* is protected by a mutex. This causes interesting batch behaviour which | ||
* triggered a bug in the linux backend. | ||
*/ | ||
#include <assert.h> | ||
#include <atomic> | ||
#include <mutex> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <thread> | ||
#include <vector> | ||
using namespace std; | ||
|
||
#include <snmalloc/snmalloc.h> | ||
#define malloc snmalloc::libc::malloc | ||
#define free snmalloc::libc::free | ||
#define malloc_usable_size snmalloc::libc::malloc_usable_size | ||
|
||
std::mutex global_tofree_list_mtx; | ||
std::vector<void*> global_tofree_list; | ||
|
||
std::atomic_int mustexit; | ||
|
||
void freeloop() | ||
{ | ||
size_t max_list_bytes = 0; | ||
while (1) | ||
{ | ||
std::lock_guard<std::mutex> guard{global_tofree_list_mtx}; | ||
size_t list_bytes = 0; | ||
for (auto& p : global_tofree_list) | ||
{ | ||
list_bytes += malloc_usable_size(p); | ||
free(p); | ||
} | ||
global_tofree_list.clear(); | ||
|
||
if (list_bytes > max_list_bytes) | ||
{ | ||
printf("%zd bytes\n", list_bytes); | ||
max_list_bytes = list_bytes; | ||
} | ||
|
||
if (mustexit) | ||
return; | ||
} | ||
} | ||
|
||
void looper(size_t iterations) | ||
{ | ||
std::vector<void*> tofree_list; | ||
auto flush = [&]() { | ||
{ | ||
std::lock_guard<std::mutex> guard{global_tofree_list_mtx}; | ||
for (auto& p : tofree_list) | ||
global_tofree_list.push_back(p); | ||
} | ||
tofree_list.clear(); | ||
}; | ||
|
||
auto do_free = [&](void* p) { | ||
tofree_list.push_back(p); | ||
if (tofree_list.size() > 100) | ||
{ | ||
flush(); | ||
} | ||
}; | ||
|
||
for (size_t i = 0; i < iterations; ++i) | ||
{ | ||
size_t s = snmalloc::bits::one_at_bit(i % 20); | ||
for (size_t j = 0; j < 8; j++) | ||
{ | ||
auto ptr = (int*)malloc(s * sizeof(int)); | ||
if (ptr == nullptr) | ||
continue; | ||
*ptr = 1523; | ||
do_free(ptr); | ||
} | ||
} | ||
|
||
flush(); | ||
} | ||
|
||
int main() | ||
{ | ||
#ifdef SNMALLOC_THREAD_SANITIZER_ENABLED | ||
size_t iterations = 50000; | ||
#elif defined(__APPLE__) && !defined(SNMALLOC_APPLE_HAS_OS_SYNC_WAIT_ON_ADDRESS) | ||
size_t iterations = 50000; | ||
#else | ||
size_t iterations = 200000; | ||
#endif | ||
|
||
int threadcount = 8; | ||
vector<thread> threads; | ||
|
||
for (int i = 0; i < threadcount; ++i) | ||
threads.emplace_back(looper, iterations); | ||
|
||
std::thread freeloop_thread(freeloop); | ||
|
||
for (auto& thread : threads) | ||
{ | ||
thread.join(); | ||
} | ||
|
||
mustexit.store(1); | ||
freeloop_thread.join(); | ||
|
||
puts("Done!"); | ||
|
||
return 0; | ||
} |