Fix -Wsign-compare
[folly.git] / folly / test / DeterministicSchedule.cpp
index 7f77262c72c92e292a6ec64064abea0f477f27e1..a0ab43800b8c51a454f6ac39379d59be7d55075d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Facebook, Inc.
+ * Copyright 2014 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "DeterministicSchedule.h"
+#include <folly/test/DeterministicSchedule.h>
 #include <algorithm>
 #include <list>
 #include <mutex>
@@ -25,8 +25,8 @@
 
 namespace folly { namespace test {
 
-__thread sem_t* DeterministicSchedule::tls_sem;
-__thread DeterministicSchedule* DeterministicSchedule::tls_sched;
+FOLLY_TLS sem_t* DeterministicSchedule::tls_sem;
+FOLLY_TLS DeterministicSchedule* DeterministicSchedule::tls_sched;
 
 // access is protected by futexLock
 static std::unordered_map<detail::Futex<DeterministicAtomic>*,
@@ -58,7 +58,7 @@ DeterministicSchedule::~DeterministicSchedule() {
 std::function<int(int)>
 DeterministicSchedule::uniform(long seed) {
   auto rand = std::make_shared<std::ranlux48>(seed);
-  return [rand](int numActive) {
+  return [rand](size_t numActive) {
     auto dist = std::uniform_int_distribution<int>(0, numActive - 1);
     return dist(*rand);
   };
@@ -73,7 +73,7 @@ struct UniformSubset {
   {
   }
 
-  int operator()(int numActive) {
+  size_t operator()(size_t numActive) {
     adjustPermSize(numActive);
     if (stepsLeft_-- == 0) {
       stepsLeft_ = stepsBetweenSelect_ - 1;
@@ -84,17 +84,17 @@ struct UniformSubset {
 
  private:
   std::function<int(int)> uniform_;
-  const int subsetSize_;
+  const size_t subsetSize_;
   const int stepsBetweenSelect_;
 
   int stepsLeft_;
   // only the first subsetSize_ is properly randomized
   std::vector<int> perm_;
 
-  void adjustPermSize(int numActive) {
+  void adjustPermSize(size_t numActive) {
     if (perm_.size() > numActive) {
       perm_.erase(std::remove_if(perm_.begin(), perm_.end(),
-              [=](int x){ return x >= numActive; }), perm_.end());
+              [=](size_t x){ return x >= numActive; }), perm_.end());
     } else {
       while (perm_.size() < numActive) {
         perm_.push_back(perm_.size());
@@ -104,7 +104,7 @@ struct UniformSubset {
   }
 
   void shufflePrefix() {
-    for (int i = 0; i < std::min(int(perm_.size() - 1), subsetSize_); ++i) {
+    for (size_t i = 0; i < std::min(perm_.size() - 1, subsetSize_); ++i) {
       int j = uniform_(perm_.size() - i) + i;
       std::swap(perm_[i], perm_[j]);
     }
@@ -114,7 +114,7 @@ struct UniformSubset {
 std::function<int(int)>
 DeterministicSchedule::uniformSubset(long seed, int n, int m) {
   auto gen = std::make_shared<UniformSubset>(seed, n, m);
-  return [=](int numActive) { return (*gen)(numActive); };
+  return [=](size_t numActive) { return (*gen)(numActive); };
 }
 
 void
@@ -134,6 +134,14 @@ DeterministicSchedule::afterSharedAccess() {
   sem_post(sched->sems_[sched->scheduler_(sched->sems_.size())]);
 }
 
+int
+DeterministicSchedule::getRandNumber(int n) {
+  if (tls_sched) {
+    return tls_sched->scheduler_(n);
+  }
+  return std::rand() % n;
+}
+
 sem_t*
 DeterministicSchedule::beforeThreadCreate() {
   sem_t* s = new sem_t;
@@ -221,34 +229,62 @@ DeterministicSchedule::wait(sem_t* sem) {
 namespace folly { namespace detail {
 
 using namespace test;
+using namespace std::chrono;
+
+template <>
+FutexResult
+Futex<DeterministicAtomic>::futexWaitImpl(
+        uint32_t expected,
+        time_point<system_clock>* absSystemTimeout,
+        time_point<steady_clock>* absSteadyTimeout,
+        uint32_t waitMask) {
+  bool hasTimeout = absSystemTimeout != nullptr || absSteadyTimeout != nullptr;
+  bool awoken = false;
+  FutexResult result = FutexResult::AWOKEN;
+  int futexErrno = 0;
 
-template<>
-bool Futex<DeterministicAtomic>::futexWait(uint32_t expected,
-                                           uint32_t waitMask) {
-  bool rv;
   DeterministicSchedule::beforeSharedAccess();
   futexLock.lock();
-  if (data != expected) {
-    rv = false;
-  } else {
+  if (data == expected) {
     auto& queue = futexQueues[this];
-    bool done = false;
-    queue.push_back(std::make_pair(waitMask, &done));
-    while (!done) {
+    queue.push_back(std::make_pair(waitMask, &awoken));
+    auto ours = queue.end();
+    ours--;
+    while (!awoken) {
       futexLock.unlock();
       DeterministicSchedule::afterSharedAccess();
       DeterministicSchedule::beforeSharedAccess();
       futexLock.lock();
+
+      // Simulate spurious wake-ups, timeouts each time with
+      // a 10% probability if we haven't been woken up already
+      if (!awoken && hasTimeout &&
+          DeterministicSchedule::getRandNumber(100) < 10) {
+        assert(futexQueues.count(this) != 0 &&
+               &futexQueues[this] == &queue);
+        queue.erase(ours);
+        if (queue.empty()) {
+          futexQueues.erase(this);
+        }
+        // Simulate ETIMEDOUT 90% of the time and other failures
+        // remaining time
+        result =
+          DeterministicSchedule::getRandNumber(100) >= 10
+              ? FutexResult::TIMEDOUT : FutexResult::INTERRUPTED;
+        break;
+      }
     }
-    rv = true;
+  } else {
+    result = FutexResult::VALUE_CHANGED;
   }
   futexLock.unlock();
   DeterministicSchedule::afterSharedAccess();
-  return rv;
+  return result;
 }
 
 template<>
-int Futex<DeterministicAtomic>::futexWake(int count, uint32_t wakeMask) {
+int
+Futex<DeterministicAtomic>::futexWake(int count, uint32_t wakeMask) {
   int rv = 0;
   DeterministicSchedule::beforeSharedAccess();
   futexLock.lock();
@@ -272,4 +308,40 @@ int Futex<DeterministicAtomic>::futexWake(int count, uint32_t wakeMask) {
   return rv;
 }
 
+
+template<>
+CacheLocality const& CacheLocality::system<test::DeterministicAtomic>() {
+  static CacheLocality cache(CacheLocality::uniform(16));
+  return cache;
+}
+
+template<>
+test::DeterministicAtomic<size_t>
+    SequentialThreadId<test::DeterministicAtomic>::prevId(0);
+
+template<>
+FOLLY_TLS size_t
+    SequentialThreadId<test::DeterministicAtomic>::currentId(0);
+
+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 &SequentialThreadId<test::DeterministicAtomic>::getcpu;
+}
+
 }}