Commit f6b5f78b authored by Maged Michael's avatar Maged Michael Committed by Facebook Github Bot 9

Expand DSched interface for managing auxiliary functions

Summary:
Changed DSched interface for managing auxiliary functions to allow separate auxiliary functions for single actions (applicable to the next shared access by a specific thread) and repeating actions (applicable to all subsequent shared accesses).

[Note: I have a dependent diff that depends on both this diff and the diff for dynamic MPMCQueue (/D3462592). I don't think I can submit a diff that depends on multiple diffs that haven't landed yet. So, I'll wait until this one lands.]

Reviewed By: djwatson

Differential Revision: D3792669

fbshipit-source-id: 52654fffda2dc905b19ff91f4459f15da11f7735
parent 18914ab5
...@@ -33,7 +33,8 @@ namespace test { ...@@ -33,7 +33,8 @@ namespace test {
FOLLY_TLS sem_t* DeterministicSchedule::tls_sem; FOLLY_TLS sem_t* DeterministicSchedule::tls_sem;
FOLLY_TLS DeterministicSchedule* DeterministicSchedule::tls_sched; FOLLY_TLS DeterministicSchedule* DeterministicSchedule::tls_sched;
FOLLY_TLS unsigned DeterministicSchedule::tls_threadId; FOLLY_TLS unsigned DeterministicSchedule::tls_threadId;
FOLLY_TLS std::function<void(uint64_t, bool)>* DeterministicSchedule::tls_aux; thread_local AuxAct DeterministicSchedule::tls_aux_act;
AuxChk DeterministicSchedule::aux_chk;
// access is protected by futexLock // access is protected by futexLock
static std::unordered_map<detail::Futex<DeterministicAtomic>*, static std::unordered_map<detail::Futex<DeterministicAtomic>*,
...@@ -46,7 +47,7 @@ DeterministicSchedule::DeterministicSchedule( ...@@ -46,7 +47,7 @@ DeterministicSchedule::DeterministicSchedule(
: scheduler_(scheduler), nextThreadId_(1), step_(0) { : scheduler_(scheduler), nextThreadId_(1), step_(0) {
assert(tls_sem == nullptr); assert(tls_sem == nullptr);
assert(tls_sched == nullptr); assert(tls_sched == nullptr);
assert(tls_aux == nullptr); assert(tls_aux_act == nullptr);
tls_sem = new sem_t; tls_sem = new sem_t;
sem_init(tls_sem, 0, 1); sem_init(tls_sem, 0, 1);
...@@ -171,8 +172,16 @@ int DeterministicSchedule::getcpu(unsigned* cpu, ...@@ -171,8 +172,16 @@ int DeterministicSchedule::getcpu(unsigned* cpu,
return 0; return 0;
} }
void DeterministicSchedule::setAux(std::function<void(uint64_t, bool)>& aux) { void DeterministicSchedule::setAuxAct(AuxAct& aux) {
tls_aux = &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* DeterministicSchedule::beforeThreadCreate() {
...@@ -212,6 +221,7 @@ void DeterministicSchedule::beforeThreadExit() { ...@@ -212,6 +221,7 @@ void DeterministicSchedule::beforeThreadExit() {
delete tls_sem; delete tls_sem;
tls_sem = nullptr; tls_sem = nullptr;
tls_sched = nullptr; tls_sched = nullptr;
tls_aux_act = nullptr;
} }
void DeterministicSchedule::join(std::thread& child) { void DeterministicSchedule::join(std::thread& child) {
...@@ -232,12 +242,13 @@ void DeterministicSchedule::join(std::thread& child) { ...@@ -232,12 +242,13 @@ void DeterministicSchedule::join(std::thread& child) {
void DeterministicSchedule::callAux(bool success) { void DeterministicSchedule::callAux(bool success) {
++step_; ++step_;
auto aux = tls_aux; if (tls_aux_act) {
if (!aux) { tls_aux_act(success);
return; tls_aux_act = nullptr;
}
if (aux_chk) {
aux_chk(step_);
} }
(*aux)(step_, success);
tls_aux = nullptr;
} }
void DeterministicSchedule::post(sem_t* sem) { void DeterministicSchedule::post(sem_t* sem) {
......
...@@ -51,6 +51,10 @@ namespace test { ...@@ -51,6 +51,10 @@ namespace test {
} \ } \
} while (false) } while (false)
/* signatures of user-defined auxiliary functions */
using AuxAct = std::function<void(bool)>;
using AuxChk = std::function<void(uint64_t)>;
/** /**
* DeterministicSchedule coordinates the inter-thread communication of a * DeterministicSchedule coordinates the inter-thread communication of a
* set of threads under test, so that despite concurrency the execution is * set of threads under test, so that despite concurrency the execution is
...@@ -168,18 +172,27 @@ class DeterministicSchedule : boost::noncopyable { ...@@ -168,18 +172,27 @@ class DeterministicSchedule : boost::noncopyable {
static int getcpu(unsigned* cpu, unsigned* node, void* unused); static int getcpu(unsigned* cpu, unsigned* node, void* unused);
/** Sets up a thread-specific function for call immediately after /** Sets up a thread-specific function for call immediately after
* the next shared access for managing auxiliary data and checking * the next shared access by the thread for managing auxiliary
* global invariants. The parameters of the function are: a * data. The function takes a bool parameter that indicates the
* uint64_t that indicates the step number (i.e., the number of * success of the shared access (if it is conditional, true
* shared accesses so far), and a bool that indicates the success * otherwise). The function is cleared after one use. */
* of the shared access (if it is conditional, true otherwise). */ static void setAuxAct(AuxAct& aux);
static void setAux(std::function<void(uint64_t, bool)>& aux);
/** Sets up a function to be called after every subsequent shared
* access (until clearAuxChk() is called) for checking global
* invariants and logging. The function takes a uint64_t parameter
* that indicates the number of shared accesses so far. */
static void setAuxChk(AuxChk& aux);
/** Clears the function set by setAuxChk */
static void clearAuxChk();
private: private:
static FOLLY_TLS sem_t* tls_sem; static FOLLY_TLS sem_t* tls_sem;
static FOLLY_TLS DeterministicSchedule* tls_sched; static FOLLY_TLS DeterministicSchedule* tls_sched;
static FOLLY_TLS unsigned tls_threadId; static FOLLY_TLS unsigned tls_threadId;
static FOLLY_TLS std::function<void(uint64_t, bool)>* tls_aux; static thread_local AuxAct tls_aux_act;
static AuxChk aux_chk;
std::function<int(int)> scheduler_; std::function<int(int)> scheduler_;
std::vector<sem_t*> sems_; std::vector<sem_t*> sems_;
......
...@@ -129,7 +129,6 @@ TEST(DeterministicSchedule, buggyAdd) { ...@@ -129,7 +129,6 @@ TEST(DeterministicSchedule, buggyAdd) {
/// 8. Define TEST using anotated shared data, aux data, and aux functions /// 8. Define TEST using anotated shared data, aux data, and aux functions
using DSched = DeterministicSchedule; using DSched = DeterministicSchedule;
using AuxFn = std::function<void(uint64_t, bool)>;
/** forward declaration of annotated shared class */ /** forward declaration of annotated shared class */
class AnnotatedAtomicCounter; class AnnotatedAtomicCounter;
...@@ -180,17 +179,17 @@ class AnnotatedAtomicCounter { ...@@ -180,17 +179,17 @@ class AnnotatedAtomicCounter {
public: public:
explicit AnnotatedAtomicCounter(int val) : shared_(val) {} explicit AnnotatedAtomicCounter(int val) : shared_(val) {}
void inc(AuxFn& auxfn) { void inc(AuxAct& auxfn) {
DSched::setAux(auxfn); DSched::setAuxAct(auxfn);
/* calls the fine-grained original */ /* calls the fine-grained original */
shared_.inc(); shared_.inc();
} }
void inc_bug(AuxFn auxfn) { void inc_bug(AuxAct auxfn) {
/* duplicates the steps of the multi-access original in order to /* duplicates the steps of the multi-access original in order to
* annotate the second access */ * annotate the second access */
int newval = shared_.counter_.load() + 1; int newval = shared_.counter_.load() + 1;
DSched::setAux(auxfn); DSched::setAuxAct(auxfn);
shared_.counter_.store(newval); shared_.counter_.store(newval);
} }
...@@ -205,7 +204,7 @@ class AnnotatedAtomicCounter { ...@@ -205,7 +204,7 @@ class AnnotatedAtomicCounter {
using Annotated = AnnotatedAtomicCounter; using Annotated = AnnotatedAtomicCounter;
/** aux log & check function */ /** aux log & check function */
void auxCheck(int tid, uint64_t step, Annotated& annotated, AuxData& auxdata) { void auxCheck(int tid, Annotated& annotated, AuxData& auxdata) {
/* read shared data */ /* read shared data */
int val = annotated.load_direct(); int val = annotated.load_direct();
/* read auxiliary data */ /* read auxiliary data */
...@@ -214,21 +213,20 @@ void auxCheck(int tid, uint64_t step, Annotated& annotated, AuxData& auxdata) { ...@@ -214,21 +213,20 @@ void auxCheck(int tid, uint64_t step, Annotated& annotated, AuxData& auxdata) {
sum += v; sum += v;
} }
/* log state */ /* log state */
VLOG(2) << "Step " << step << " -- tid " << tid VLOG(2) << "tid " << tid << " -- shared counter= " << val
<< " -- shared counter= " << val << " -- sum increments= " << sum; << " -- sum increments= " << sum;
/* check invariant */ /* check invariant */
if (val != sum) { if (val != sum) {
LOG(ERROR) << "Failed after step " << step;
LOG(ERROR) << "counter=(" << val << ") expected(" << sum << ")"; LOG(ERROR) << "counter=(" << val << ") expected(" << sum << ")";
CHECK(false); CHECK(false);
} }
} }
/** function generator(s) */ /** function generator(s) */
AuxFn auxAfterInc(int tid, Annotated& annotated, AuxData& auxdata) { AuxAct auxAfterInc(int tid, Annotated& annotated, AuxData& auxdata) {
return [&annotated, &auxdata, tid](uint64_t step, bool success) { return [&annotated, &auxdata, tid](bool success) {
auxUpdateAfterInc(tid, auxdata, success); auxUpdateAfterInc(tid, auxdata, success);
auxCheck(tid, step, annotated, auxdata); auxCheck(tid, annotated, auxdata);
}; };
} }
...@@ -252,7 +250,7 @@ TEST(DSchedCustom, atomic_add) { ...@@ -252,7 +250,7 @@ TEST(DSchedCustom, atomic_add) {
std::vector<std::thread> threads(nthr); std::vector<std::thread> threads(nthr);
for (int tid = 0; tid < nthr; ++tid) { for (int tid = 0; tid < nthr; ++tid) {
threads[tid] = DSched::thread([&, tid]() { threads[tid] = DSched::thread([&, tid]() {
AuxFn auxfn = auxAfterInc(tid, annotated, auxdata); AuxAct auxfn = auxAfterInc(tid, annotated, auxdata);
for (int i = 0; i < niter; ++i) { for (int i = 0; i < niter; ++i) {
if (bug && (tid == 0) && (i % 10 == 0)) { if (bug && (tid == 0) && (i % 10 == 0)) {
annotated.inc_bug(auxfn); annotated.inc_bug(auxfn);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment