30 #include "../PerfUtils/Cycles.h" 35 using PerfUtils::Cycles;
42 extern volatile uint32_t numCores;
43 extern volatile uint32_t maxNumCores;
46 extern FILE* errorStream;
79 , generation(generation) { }
95 return !(*
this == other);
99 void init(
int* argcp = NULL,
const char** argv = NULL);
103 void sleep(uint64_t ns);
126 explicit SpinLock(std::string name) : state(false), name(name) {}
127 SpinLock() : state(
false), name(
"unnamed") {}
133 uint64_t startOfContention = 0;
134 while (state.exchange(
true, std::memory_order_acquire) !=
false) {
135 if (startOfContention == 0) {
136 startOfContention = Cycles::rdtsc();
138 uint64_t now = Cycles::rdtsc();
139 if (Cycles::toSeconds(now - startOfContention) > 1.0) {
141 "%s SpinLock locked for one second; deadlock?\n",
143 startOfContention = now;
159 return !state.exchange(
true, std::memory_order_acquire);
165 state.store(
false, std::memory_order_release);
176 std::atomic<bool> state;
195 template <
typename LockType>
void wait(LockType& lock);
196 template <
typename LockType>
void waitFor(LockType& lock, uint64_t ns);
201 std::deque<ThreadId> blockedThreads;
226 virtual void runThread() = 0;
252 : mainFunction(mainFunction) {
254 "Arachne requires the function and arguments for a thread to " 255 "fit within one cache line.");
310 struct alignas(CACHE_LINE_SIZE) {
311 char data[CACHE_LINE_SIZE];
324 const int maxThreadsPerCore = 56;
331 const size_t SpaceForSavedRegisters = 48;
336 const uint64_t BLOCKED = ~0L;
342 const uint64_t UNOCCUPIED = ~0L - 1;
344 void schedulerMainLoop();
345 void swapcontext(
void **saved,
void **target);
346 void threadMain(
int id);
348 extern thread_local
int kernelThreadId;
351 extern std::vector<ThreadContext**> allThreadContexts;
359 uint64_t occupied : 56;
361 uint8_t numOccupied : 8;
364 extern std::vector< std::atomic<MaskAndCount> *> occupiedAndCount;
365 extern thread_local std::atomic<MaskAndCount> *localOccupiedAndCount;
368 static std::deque<uint64_t> mockRandomValues;
377 if (!mockRandomValues.empty()) {
378 uint64_t returnValue = mockRandomValues.front();
379 mockRandomValues.pop_front();
389 static uint64_t x = 123456789, y = 362436069, z = 521288629;
423 template<
typename _Callable,
typename... _Args>
425 createThread(
int kId, _Callable&& __f, _Args&&... __args) {
427 kId = kernelThreadId;
429 auto task = std::bind(
430 std::forward<_Callable>(__f), std::forward<_Args>(__args)...);
446 while ((slotMap.
occupied & (1L << index)) && index < maxThreadsPerCore)
450 (slotMap.
occupied | (1L << index)) & 0x00FFFFFFFFFFFFFF;
453 success = occupiedAndCount[kId]->compare_exchange_strong(oldSlotMap,
458 new (&allThreadContexts[kId][index]->threadInvocation)
460 allThreadContexts[kId][index]->wakeupTimeInCycles = 0;
461 return ThreadId(allThreadContexts[kId][index],
485 template<
typename _Callable,
typename... _Args>
491 int choice1 =
static_cast<int>(random()) % numCores;
492 int choice2 =
static_cast<int>(random()) % numCores;
493 while (choice2 == choice1 && numCores > 1)
494 choice2 =
static_cast<int>(random()) % numCores;
496 if (occupiedAndCount[choice1]->load().numOccupied <
497 occupiedAndCount[choice2]->load().numOccupied)
514 template <
typename LockType>
void 517 TimeTrace::record(
"Wait on Core %d", kernelThreadId);
519 blockedThreads.push_back(
520 ThreadId(loadedContext, loadedContext->generation));
524 TimeTrace::record(
"About to acquire lock after waking up");
541 template <
typename LockType>
void 543 blockedThreads.push_back(
544 ThreadId(loadedContext, loadedContext->generation));
545 loadedContext->wakeupTimeInCycles =
546 Cycles::rdtsc() + Cycles::fromNanoseconds(ns);
Definition: Arachne.cc:23
ThreadId getThreadId()
Definition: Arachne.cc:310
void testDestroy()
Definition: Arachne.cc:660
uint8_t numOccupied
The number of 1 bits in occupied.
Definition: Arachne.h:361
uint64_t occupied
Definition: Arachne.h:359
const Arachne::ThreadId NullThread
Definition: Arachne.h:212
void unlock()
Definition: Arachne.h:164
void join(ThreadId id)
Definition: Arachne.cc:403
volatile uint64_t wakeupTimeInCycles
Definition: Arachne.h:283
bool operator==(const ThreadId &other) const
Definition: Arachne.h:88
void * sp
Definition: Arachne.h:276
Definition: Arachne.h:223
Definition: Arachne.h:189
uint8_t idInCore
Definition: Arachne.h:301
void waitFor(LockType &lock, uint64_t ns)
Definition: Arachne.h:542
void yield()
Definition: Arachne.cc:284
SpinLock joinLock
Definition: Arachne.h:292
void lock()
Definition: Arachne.h:132
bool try_lock()
Definition: Arachne.h:156
ThreadContext * context
The storage where this thread's state is held.
Definition: Arachne.h:66
void init(int *argcp, const char **argv)
Definition: Arachne.cc:582
void waitForTermination()
Definition: Arachne.cc:418
Definition: Arachne.h:245
void setName(std::string name)
Definition: Arachne.h:170
threadInvocation
Definition: Arachne.h:314
bool operator!=(const ThreadId &other) const
Negation of the function above.
Definition: Arachne.h:94
SpinLock(std::string name)
Definition: Arachne.h:126
uint32_t generation
Definition: Arachne.h:69
F mainFunction
The top-level function of the Arachne thread.
Definition: Arachne.h:247
void runThread()
Definition: Arachne.h:261
This structure tracks the live threads on a single core.
Definition: Arachne.h:354
void sleep(uint64_t ns)
Definition: Arachne.cc:296
uint32_t generation
Definition: Arachne.h:288
Definition: Arachne.h:123
ConditionVariable joinCV
Definition: Arachne.h:296
void * stack
Definition: Arachne.h:272
ThreadId createThread(_Callable &&__f, _Args &&...__args)
Definition: Arachne.h:487
Definition: Arachne.h:269
void shutDown()
Definition: Arachne.cc:683
ThreadInvocation(F mainFunction)
Definition: Arachne.h:251
void wait(LockType &lock)
Definition: Arachne.h:515
void setErrorStream(FILE *stream)
Definition: Arachne.cc:721
ThreadId(ThreadContext *context, uint32_t generation)
Definition: Arachne.h:77
void block()
Definition: Arachne.h:109
void signal(ThreadId id)
Definition: Arachne.cc:383
void testInit()
Definition: Arachne.cc:635