From 832479bd63a69702d47901cac94c290a47b2acf8 Mon Sep 17 00:00:00 2001 From: Maged Michael Date: Tue, 2 Aug 2016 17:23:18 -0700 Subject: [PATCH] Test of DeterministicSchedule support for global invariants and auxiliary vari Summary: Depends on D3648146 Atomic counter test with: - Buggy path triggered by an env var - Auxiliary data - A global invariant - A function to be called with shared accesses to update auxiliary data and check the global invariant. Reviewed By: djwatson Differential Revision: D3648195 fbshipit-source-id: 18620a887f114abf31ba1261c38287139a1591a7 --- folly/test/DeterministicScheduleTest.cpp | 89 ++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/folly/test/DeterministicScheduleTest.cpp b/folly/test/DeterministicScheduleTest.cpp index a7ded406..36654856 100644 --- a/folly/test/DeterministicScheduleTest.cpp +++ b/folly/test/DeterministicScheduleTest.cpp @@ -107,6 +107,95 @@ TEST(DeterministicSchedule, buggyAdd) { } // for bug } // TEST +/// Testing support for auxiliary variables and global invariants + +/** auxiliary variables for atomic counter test */ +struct AtomicCounterAux { + std::vector local_; + + explicit AtomicCounterAux(int nthr) { + local_.resize(nthr, 0); + } +}; + +/** auxiliary function for checking global invariants and logging + * steps of atomic counter test */ +void checkAtomicCounter( + int tid, + uint64_t step, + DeterministicAtomic& shared, + AtomicCounterAux& aux) { + /* read shared data */ + int val = shared.load_direct(); + /* read auxiliary variables */ + int sum = 0; + for (int v : aux.local_) { + sum += v; + } + /* log state */ + VLOG(2) << "Step " << step << " -- tid " << tid << " -- shared counter " + << val << " -- sum increments " << sum; + /* check invariant */ + if (val != sum) { + LOG(ERROR) << "Failed after step " << step; + LOG(ERROR) << "counter=(" << val << ") expected(" << sum << ")"; + CHECK(false); + } +} + +std::function auxAtomicCounter( + DeterministicAtomic& shared, + AtomicCounterAux& aux, + int tid) { + return [&shared, &aux, tid](uint64_t step, bool success) { + // update auxiliary data + if (success) { + aux.local_[tid]++; + } + // check invariants + checkAtomicCounter(tid, step, shared, aux); + }; +} + +DEFINE_bool(bug, false, "Introduce bug"); +DEFINE_int64(seed, 0, "Seed for random number generator"); +DEFINE_int32(num_threads, 2, "Number of threads"); +DEFINE_int32(num_iterations, 10, "Number of iterations"); + +TEST(DSchedCustom, atomic_add) { + bool bug = FLAGS_bug; + long seed = FLAGS_seed; + int nthr = FLAGS_num_threads; + int niter = FLAGS_num_iterations; + + CHECK_GT(nthr, 0); + + DeterministicAtomic counter{0}; + AtomicCounterAux auxData(nthr); + DeterministicSchedule sched(DeterministicSchedule::uniform(seed)); + + std::vector threads(nthr); + for (int tid = 0; tid < nthr; ++tid) { + threads[tid] = DeterministicSchedule::thread([&, tid]() { + auto auxFn = auxAtomicCounter(counter, auxData, tid); + for (int i = 0; i < niter; ++i) { + if (bug && (tid == 0) && (i % 10 == 0)) { + int newval = counter.load() + 1; + DeterministicSchedule::setAux(auxFn); + counter.store(newval); + } else { + DeterministicSchedule::setAux(auxFn); + counter.fetch_add(1); + } + } + }); + } + for (auto& t : threads) { + DeterministicSchedule::join(t); + } + EXPECT_EQ(counter.load_direct(), nthr * niter); +} + int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); gflags::ParseCommandLineFlags(&argc, &argv, true); -- 2.34.1