/*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2013-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*/
#include <folly/test/DeterministicSchedule.h>
+
+#include <assert.h>
+
#include <algorithm>
#include <list>
#include <mutex>
#include <random>
-#include <utility>
#include <unordered_map>
-#include <assert.h>
+#include <utility>
+
+#include <folly/Random.h>
namespace folly {
namespace test {
FOLLY_TLS sem_t* DeterministicSchedule::tls_sem;
FOLLY_TLS DeterministicSchedule* DeterministicSchedule::tls_sched;
FOLLY_TLS unsigned DeterministicSchedule::tls_threadId;
+thread_local AuxAct DeterministicSchedule::tls_aux_act;
+AuxChk DeterministicSchedule::aux_chk;
// access is protected by futexLock
static std::unordered_map<detail::Futex<DeterministicAtomic>*,
static std::mutex futexLock;
DeterministicSchedule::DeterministicSchedule(
- const std::function<int(int)>& scheduler)
- : scheduler_(scheduler), nextThreadId_(1) {
+ const std::function<size_t(size_t)>& scheduler)
+ : scheduler_(scheduler), nextThreadId_(1), step_(0) {
assert(tls_sem == nullptr);
assert(tls_sched == nullptr);
+ assert(tls_aux_act == nullptr);
tls_sem = new sem_t;
sem_init(tls_sem, 0, 1);
beforeThreadExit();
}
-std::function<int(int)> DeterministicSchedule::uniform(long seed) {
+std::function<size_t(size_t)> DeterministicSchedule::uniform(uint64_t seed) {
auto rand = std::make_shared<std::ranlux48>(seed);
return [rand](size_t numActive) {
- auto dist = std::uniform_int_distribution<int>(0, numActive - 1);
+ auto dist = std::uniform_int_distribution<size_t>(0, numActive - 1);
return dist(*rand);
};
}
struct UniformSubset {
- UniformSubset(long seed, int subsetSize, int stepsBetweenSelect)
+ UniformSubset(uint64_t seed, size_t subsetSize, size_t stepsBetweenSelect)
: uniform_(DeterministicSchedule::uniform(seed)),
subsetSize_(subsetSize),
stepsBetweenSelect_(stepsBetweenSelect),
}
private:
- std::function<int(int)> uniform_;
+ std::function<size_t(size_t)> uniform_;
const size_t subsetSize_;
- const int stepsBetweenSelect_;
+ const size_t stepsBetweenSelect_;
- int stepsLeft_;
+ size_t stepsLeft_;
// only the first subsetSize_ is properly randomized
- std::vector<int> perm_;
+ std::vector<size_t> perm_;
void adjustPermSize(size_t numActive) {
if (perm_.size() > numActive) {
void shufflePrefix() {
for (size_t i = 0; i < std::min(perm_.size() - 1, subsetSize_); ++i) {
- int j = uniform_(perm_.size() - i) + i;
+ size_t j = uniform_(perm_.size() - i) + i;
std::swap(perm_[i], perm_[j]);
}
}
};
-std::function<int(int)> DeterministicSchedule::uniformSubset(long seed,
- int n,
- int m) {
+std::function<size_t(size_t)>
+DeterministicSchedule::uniformSubset(uint64_t seed, size_t n, size_t m) {
auto gen = std::make_shared<UniformSubset>(seed, n, m);
return [=](size_t numActive) { return (*gen)(numActive); };
}
if (!sched) {
return;
}
+ sem_post(sched->sems_[sched->scheduler_(sched->sems_.size())]);
+}
+void DeterministicSchedule::afterSharedAccess(bool success) {
+ auto sched = tls_sched;
+ if (!sched) {
+ return;
+ }
+ sched->callAux(success);
sem_post(sched->sems_[sched->scheduler_(sched->sems_.size())]);
}
-int DeterministicSchedule::getRandNumber(int n) {
+size_t DeterministicSchedule::getRandNumber(size_t n) {
if (tls_sched) {
return tls_sched->scheduler_(n);
}
- return std::rand() % n;
+ return Random::rand32() % n;
}
int DeterministicSchedule::getcpu(unsigned* cpu,
return 0;
}
+void DeterministicSchedule::setAuxAct(AuxAct& aux) {
+ tls_aux_act = aux;
+}
+
+void DeterministicSchedule::setAuxChk(AuxChk& aux) {
+ aux_chk = aux;
+}
+
+void DeterministicSchedule::clearAuxChk() {
+ aux_chk = nullptr;
+}
+
sem_t* DeterministicSchedule::beforeThreadCreate() {
sem_t* s = new sem_t;
sem_init(s, 0, 0);
delete tls_sem;
tls_sem = nullptr;
tls_sched = nullptr;
+ tls_aux_act = nullptr;
}
void DeterministicSchedule::join(std::thread& child) {
child.join();
}
+void DeterministicSchedule::callAux(bool success) {
+ ++step_;
+ if (tls_aux_act) {
+ tls_aux_act(success);
+ tls_aux_act = nullptr;
+ }
+ if (aux_chk) {
+ aux_chk(step_);
+ }
+}
+
void DeterministicSchedule::post(sem_t* sem) {
beforeSharedAccess();
sem_post(sem);
// we're not busy waiting because this is a deterministic schedule
}
}
-}
-}
+} // namespace test
+} // namespace folly
namespace folly {
namespace detail {
template <>
FutexResult Futex<DeterministicAtomic>::futexWaitImpl(
uint32_t expected,
- time_point<system_clock>* absSystemTimeout,
- time_point<steady_clock>* absSteadyTimeout,
+ system_clock::time_point const* absSystemTimeout,
+ steady_clock::time_point const* absSteadyTimeout,
uint32_t waitMask) {
bool hasTimeout = absSystemTimeout != nullptr || absSteadyTimeout != nullptr;
bool awoken = false;
<< ", .., " << std::hex << waitMask
<< ") beginning..");
futexLock.lock();
- if (data == expected) {
+ if (this->data == expected) {
auto& queue = futexQueues[this];
queue.emplace_back(waitMask, &awoken);
auto ours = queue.end();
DeterministicSchedule::afterSharedAccess();
return rv;
}
+} // namespace detail
template <>
CacheLocality const& CacheLocality::system<test::DeterministicAtomic>() {
}
template <>
-const AccessSpreader<test::DeterministicAtomic>
- AccessSpreader<test::DeterministicAtomic>::stripeByCore(
- CacheLocality::system<>().numCachesByLevel.front());
-
-template <>
-const AccessSpreader<test::DeterministicAtomic>
- AccessSpreader<test::DeterministicAtomic>::stripeByChip(
- CacheLocality::system<>().numCachesByLevel.back());
-
-template <>
-AccessSpreaderArray<test::DeterministicAtomic, 128>
- AccessSpreaderArray<test::DeterministicAtomic, 128>::sharedInstance = {};
-
-template <>
-Getcpu::Func AccessSpreader<test::DeterministicAtomic>::pickGetcpuFunc(
- size_t /* numStripes */) {
- return &DeterministicSchedule::getcpu;
-}
-}
+Getcpu::Func AccessSpreader<test::DeterministicAtomic>::pickGetcpuFunc() {
+ return &detail::DeterministicSchedule::getcpu;
}
+} // namespace folly