proxygen
DeterministicScheduleTest.cpp File Reference

Go to the source code of this file.

Classes

struct  AnnotatedAtomicCounter< T >
 
class  AtomicCounter< T, Atom >
 
struct  AuxData
 
struct  AuxData::PerThread
 
struct  AnnotatedAtomicCounter< T >
 

Macros

#define AUX_THR(x)   (aux_->t_[tid_].x)
 
#define AUX_UPDATE()   (aux_->lastUpdate_ = aux_->step_ + 1)
 
#define AUX_ACT(act)
 

Typedefs

using DSched = DeterministicSchedule
 
template<typename T >
using Base = AtomicCounter< T, DeterministicAtomic >
 
using Annotated = AnnotatedAtomicCounter< int >
 

Functions

 TEST (DeterministicSchedule, uniform)
 
 TEST (DeterministicSchedule, uniformSubset)
 
 TEST (DeterministicSchedule, buggyAdd)
 
 DEFINE_int64 (seed, 0,"Seed for random number generators")
 
 DEFINE_int64 (max_steps, 1000000,"Max. number of shared steps for the test")
 
 DEFINE_int64 (num_reps, 1,"Number of test repetitions")
 
 DEFINE_int64 (num_ops, 1000,"Number of increments per repetition")
 
 DEFINE_int64 (liveness_thresh, 1000000,"Liveness threshold")
 
 DEFINE_int64 (log_begin, 0,"Step number to start logging. No logging if <= 0")
 
 DEFINE_int64 (log_length, 1000,"Length of step by step log (if log_begin > 0)")
 
 DEFINE_int64 (log_freq, 100000,"Log every so many steps")
 
 DEFINE_int32 (num_threads, 1,"Number of producers")
 
 DEFINE_bool (bug, false,"Introduce bug")
 
 TEST (DeterministicSchedule, global_invariants)
 
int main (int argc, char **argv)
 

Variables

static AuxDataaux_
 
static FOLLY_TLS uint32_t tid_
 

Macro Definition Documentation

#define AUX_ACT (   act)
Value:
do { \
AUX_THR(func_) = __func__; \
AUX_THR(line_) = __LINE__; \
AuxAct auxfn([&](bool success) { \
if (success) { \
} \
if (true) { \
act \
} \
}); \
DeterministicSchedule::setAuxAct(auxfn); \
} while (0)
#define AUX_THR(x)
if(FOLLY_USE_SYMBOLIZER) add_library(folly_exception_tracer_base ExceptionTracer.cpp StackTrace.cpp) apply_folly_compile_options_to_target(folly_exception_tracer_base) target_link_libraries(folly_exception_tracer_base PUBLIC folly) add_library(folly_exception_tracer ExceptionStackTraceLib.cpp ExceptionTracerLib.cpp) apply_folly_compile_options_to_target(folly_exception_tracer) target_link_libraries(folly_exception_tracer PUBLIC folly_exception_tracer_base) add_library(folly_exception_counter ExceptionCounterLib.cpp) apply_folly_compile_options_to_target(folly_exception_counter) target_link_libraries(folly_exception_counter PUBLIC folly_exception_tracer) install(FILES ExceptionAbi.h ExceptionCounterLib.h ExceptionTracer.h ExceptionTracerLib.h StackTrace.h DESTINATION $
Definition: CMakeLists.txt:1
std::function< void(bool)> AuxAct

Macro for inline definition of auxiliary actions

Definition at line 238 of file DeterministicScheduleTest.cpp.

Referenced by AnnotatedAtomicCounter< T >::inc(), and AnnotatedAtomicCounter< T >::incBug().

#define AUX_THR (   x)    (aux_->t_[tid_].x)
#define AUX_UPDATE ( )    (aux_->lastUpdate_ = aux_->step_ + 1)

Definition at line 235 of file DeterministicScheduleTest.cpp.

Typedef Documentation

Definition at line 337 of file DeterministicScheduleTest.cpp.

template<typename T >
using Base = AtomicCounter<T, DeterministicAtomic>

Alias for original class

Examples:
/facebook/proxygen/proxygen/folly/folly/container/Iterator.h.

Definition at line 254 of file DeterministicScheduleTest.cpp.

Definition at line 166 of file DeterministicScheduleTest.cpp.

Function Documentation

DEFINE_bool ( bug  ,
false  ,
"Introduce bug"   
)
DEFINE_int32 ( num_threads  ,
,
"Number of producers"   
)
DEFINE_int64 ( seed  ,
,
"Seed for random number generators"   
)
DEFINE_int64 ( max_steps  ,
1000000  ,
"Max. number of shared steps for the test  
)
DEFINE_int64 ( num_reps  ,
,
"Number of test repetitions"   
)
DEFINE_int64 ( num_ops  ,
1000  ,
"Number of increments per repetition"   
)
DEFINE_int64 ( liveness_thresh  ,
1000000  ,
"Liveness threshold"   
)
DEFINE_int64 ( log_begin  ,
,
"Step number to start logging. No logging if <= 0"   
)
DEFINE_int64 ( log_length  ,
1000  ,
"Length of step by step log (if log_begin > 0)"   
)
DEFINE_int64 ( log_freq  ,
100000  ,
"Log every so many steps"   
)
int main ( int  argc,
char **  argv 
)

Definition at line 370 of file DeterministicScheduleTest.cpp.

References testing::InitGoogleTest(), and RUN_ALL_TESTS().

370  {
372  gflags::ParseCommandLineFlags(&argc, &argv, true);
373  return RUN_ALL_TESTS();
374 }
int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_
Definition: gtest.h:2232
char ** argv
GTEST_API_ void InitGoogleTest(int *argc, char **argv)
Definition: gtest.cc:5370
TEST ( DeterministicSchedule  ,
uniform   
)

Definition at line 24 of file DeterministicScheduleTest.cpp.

References EXPECT_TRUE, i, and folly::test::DeterministicSchedule::uniform().

24  {
25  auto p = DeterministicSchedule::uniform(0);
26  int buckets[10] = {};
27  for (int i = 0; i < 100000; ++i) {
28  buckets[p(10)]++;
29  }
30  for (int i = 0; i < 10; ++i) {
31  EXPECT_TRUE(buckets[i] > 9000);
32  }
33 }
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
TEST ( DeterministicSchedule  ,
uniformSubset   
)

Definition at line 35 of file DeterministicScheduleTest.cpp.

References EXPECT_EQ, EXPECT_TRUE, i, seen, folly::test::DeterministicSchedule::uniformSubset(), and x.

35  {
36  auto ps = DeterministicSchedule::uniformSubset(0, 3, 100);
37  int buckets[10] = {};
38  std::set<int> seen;
39  for (int i = 0; i < 100000; ++i) {
40  if (i > 0 && (i % 100) == 0) {
41  EXPECT_EQ(seen.size(), 3);
42  seen.clear();
43  }
44  int x = ps(10);
45  seen.insert(x);
46  EXPECT_TRUE(seen.size() <= 3);
47  buckets[x]++;
48  }
49  for (int i = 0; i < 10; ++i) {
50  EXPECT_TRUE(buckets[i] > 9000);
51  }
52 }
Definition: InvokeTest.cpp:58
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
const int x
std::unordered_set< std::pair< const IValidator *, const dynamic * > > seen
Definition: JSONSchema.cpp:92
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
TEST ( DeterministicSchedule  ,
buggyAdd   
)

Definition at line 54 of file DeterministicScheduleTest.cpp.

References EXPECT_EQ, FOLLY_TEST_DSCHED_VLOG, folly::test::DeterministicSchedule::join(), folly::test::DeterministicMutex::lock(), m, folly::pushmi::detail::t, folly::test::DeterministicSchedule::thread(), threads, folly::test::DeterministicMutex::try_lock(), folly::test::DeterministicSchedule::uniform(), and folly::test::DeterministicMutex::unlock().

54  {
55  for (bool bug : {false, true}) {
56  DeterministicSchedule sched(DeterministicSchedule::uniform(0));
57  if (bug) {
58  FOLLY_TEST_DSCHED_VLOG("Test with race condition");
59  } else {
60  FOLLY_TEST_DSCHED_VLOG("Test without race condition");
61  }
63  // The use of DeterinisticAtomic is not needed here, but it makes
64  // it easier to understand the sequence of events in logs.
66  DeterministicAtomic<int> baseline{0};
67  int numThreads = 10;
68  std::vector<std::thread> threads(numThreads);
69  for (int t = 0; t < numThreads; ++t) {
70  threads[t] = DeterministicSchedule::thread([&, t] {
71  baseline.fetch_add(1);
72  // Atomic increment of test protected by mutex m
73  do {
74  // Some threads use lock() others use try_lock()
75  if ((t & 1) == 0) {
76  m.lock();
77  } else {
78  if (!m.try_lock()) {
79  continue;
80  }
81  }
82  int newval = test.load() + 1;
83  if (bug) {
84  // Break the atomicity of the increment operation
85  m.unlock();
86  m.lock();
87  }
88  test.store(newval);
89  m.unlock();
90  break;
91  } while (true);
92  }); // thread lambda
93  } // for t
94  for (auto& t : threads) {
96  }
97  if (!bug) {
98  EXPECT_EQ(test.load(), baseline.load());
99  } else {
100  if (test.load() == baseline.load()) {
101  FOLLY_TEST_DSCHED_VLOG("Didn't catch the bug");
102  } else {
103  FOLLY_TEST_DSCHED_VLOG("Caught the bug");
104  }
105  }
106  } // for bug
107 }
#define FOLLY_TEST_DSCHED_VLOG(...)
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
std::vector< std::thread::id > threads
static map< string, int > m
#define join
TEST ( DeterministicSchedule  ,
global_invariants   
)

Definition at line 339 of file DeterministicScheduleTest.cpp.

References aux_, AnnotatedAtomicCounter< T >::clearAuxChk(), AnnotatedAtomicCounter< T >::doAuxLog(), EXPECT_EQ, i, AnnotatedAtomicCounter< T >::inc(), AnnotatedAtomicCounter< T >::incBug(), folly::test::DeterministicSchedule::join(), AnnotatedAtomicCounter< T >::loadDirect(), AnnotatedAtomicCounter< T >::setAuxChk(), AuxData::step_, folly::pushmi::detail::t, folly::test::DeterministicSchedule::thread(), threads, tid_, and folly::test::DeterministicSchedule::uniform().

339  {
340  CHECK_GT(FLAGS_num_threads, 0);
341 
342  DSched sched(DSched::uniform(FLAGS_seed));
343  for (int i = 0; i < FLAGS_num_reps; ++i) {
344  aux_ = new AuxData(FLAGS_num_threads);
345  Annotated annotated(0);
346  annotated.setAuxChk();
347 
348  std::vector<std::thread> threads(FLAGS_num_threads);
349  for (int tid = 0; tid < FLAGS_num_threads; ++tid) {
350  threads[tid] = DSched::thread([&, tid]() {
351  tid_ = tid;
352  for (int j = tid; j < FLAGS_num_ops; j += FLAGS_num_threads) {
353  (FLAGS_bug) ? annotated.incBug() : annotated.inc();
354  }
355  });
356  }
357  for (auto& t : threads) {
358  DSched::join(t);
359  }
360  std::cerr << "====== rep " << i << " completed in step " << aux_->step_
361  << std::endl;
362  annotated.doAuxLog(aux_->step_);
363  std::cerr << std::endl;
364  EXPECT_EQ(annotated.loadDirect(), FLAGS_num_ops);
365  annotated.clearAuxChk();
366  delete aux_;
367  }
368 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
static AuxData * aux_
static std::thread thread(Func &&func, Args &&...args)
std::vector< std::thread::id > threads
static std::function< size_t(size_t)> uniform(uint64_t seed)
static void join(std::thread &child)
static FOLLY_TLS uint32_t tid_

Variable Documentation

AuxData* aux_
static

Definition at line 218 of file DeterministicScheduleTest.cpp.

Referenced by TEST().

FOLLY_TLS uint32_t tid_
static