xref: /openbsd-src/gnu/llvm/compiler-rt/lib/gwp_asan/tests/thread_contention.cpp (revision 1f9cb04fc6f537ca6cf5a53c28927340cba218a2)
13cab2bb3Spatrick //===-- thread_contention.cpp -----------------------------------*- C++ -*-===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick 
93cab2bb3Spatrick #include "gwp_asan/tests/harness.h"
103cab2bb3Spatrick 
113cab2bb3Spatrick // Note: Compilation of <atomic> and <thread> are extremely expensive for
123cab2bb3Spatrick // non-opt builds of clang.
133cab2bb3Spatrick #include <atomic>
143cab2bb3Spatrick #include <cstdlib>
153cab2bb3Spatrick #include <thread>
163cab2bb3Spatrick #include <vector>
173cab2bb3Spatrick 
asyncTask(gwp_asan::GuardedPoolAllocator * GPA,std::atomic<bool> * StartingGun,unsigned NumIterations)183cab2bb3Spatrick void asyncTask(gwp_asan::GuardedPoolAllocator *GPA,
193cab2bb3Spatrick                std::atomic<bool> *StartingGun, unsigned NumIterations) {
203cab2bb3Spatrick   while (!*StartingGun) {
213cab2bb3Spatrick     // Wait for starting gun.
223cab2bb3Spatrick   }
233cab2bb3Spatrick 
243cab2bb3Spatrick   // Get ourselves a new allocation.
253cab2bb3Spatrick   for (unsigned i = 0; i < NumIterations; ++i) {
263cab2bb3Spatrick     volatile char *Ptr = reinterpret_cast<volatile char *>(
27*1f9cb04fSpatrick         GPA->allocate(GPA->getAllocatorState()->maximumAllocationSize()));
283cab2bb3Spatrick     // Do any other threads have access to this page?
293cab2bb3Spatrick     EXPECT_EQ(*Ptr, 0);
303cab2bb3Spatrick 
313cab2bb3Spatrick     // Mark the page as from malloc. Wait to see if another thread also takes
323cab2bb3Spatrick     // this page.
333cab2bb3Spatrick     *Ptr = 'A';
343cab2bb3Spatrick     std::this_thread::sleep_for(std::chrono::nanoseconds(10000));
353cab2bb3Spatrick 
363cab2bb3Spatrick     // Check we still own the page.
373cab2bb3Spatrick     EXPECT_EQ(*Ptr, 'A');
383cab2bb3Spatrick 
393cab2bb3Spatrick     // And now release it.
403cab2bb3Spatrick     *Ptr = 0;
413cab2bb3Spatrick     GPA->deallocate(const_cast<char *>(Ptr));
423cab2bb3Spatrick   }
433cab2bb3Spatrick }
443cab2bb3Spatrick 
runThreadContentionTest(unsigned NumThreads,unsigned NumIterations,gwp_asan::GuardedPoolAllocator * GPA)453cab2bb3Spatrick void runThreadContentionTest(unsigned NumThreads, unsigned NumIterations,
463cab2bb3Spatrick                              gwp_asan::GuardedPoolAllocator *GPA) {
473cab2bb3Spatrick 
483cab2bb3Spatrick   std::atomic<bool> StartingGun{false};
493cab2bb3Spatrick   std::vector<std::thread> Threads;
503cab2bb3Spatrick   if (std::thread::hardware_concurrency() < NumThreads) {
513cab2bb3Spatrick     NumThreads = std::thread::hardware_concurrency();
523cab2bb3Spatrick   }
533cab2bb3Spatrick 
543cab2bb3Spatrick   for (unsigned i = 0; i < NumThreads; ++i) {
553cab2bb3Spatrick     Threads.emplace_back(asyncTask, GPA, &StartingGun, NumIterations);
563cab2bb3Spatrick   }
573cab2bb3Spatrick 
583cab2bb3Spatrick   StartingGun = true;
593cab2bb3Spatrick 
603cab2bb3Spatrick   for (auto &T : Threads)
613cab2bb3Spatrick     T.join();
623cab2bb3Spatrick }
633cab2bb3Spatrick 
TEST_F(CustomGuardedPoolAllocator,ThreadContention)643cab2bb3Spatrick TEST_F(CustomGuardedPoolAllocator, ThreadContention) {
653cab2bb3Spatrick   unsigned NumThreads = 4;
663cab2bb3Spatrick   unsigned NumIterations = 10000;
673cab2bb3Spatrick   InitNumSlots(NumThreads);
683cab2bb3Spatrick   runThreadContentionTest(NumThreads, NumIterations, &GPA);
693cab2bb3Spatrick }
70