homer512 icon

Shared mutex benchmark

homer512 | PRO | 08/17/17 05:28:40 PM UTC | 0 ⭐ | 634 👁️ | Never ⏰ | []
C++ |

3.55 KB

|

None

|

0 👍

/

0 👎

#include <omp.h>
// using omp_get_max_threads
 
#include <cmath>
// using std::fabsf, HUGE_VALF
#include <chrono>
// using std::chrono::*
#include <random>
// using std::default_random_engine, std::seedq, std::uniform_*_distribution
#include <iostream>
// using std::cout
 
#include <boost/thread/mutex.hpp>
// using boost::mutex
#include <boost/thread/shared_mutex.hpp>
// using boost::shared_mutex
#include <boost/thread/lock_guard.hpp>
// using boost::lock_guard
#include <boost/thread/shared_lock_guard.hpp>
// using boost::shared_lock_guard
 
 
namespace {
 
#ifdef USE_RWLOCK
  using mutex_type = boost::shared_mutex;
  using read_lock_type = boost::shared_lock_guard<mutex_type>;
#else
  using mutex_type = boost::mutex;
  using read_lock_type = boost::lock_guard<mutex_type>;
#endif
  using write_lock_type = boost::lock_guard<mutex_type>;
 
  enum class Direction { up, down, left, right };
 
  struct Vector2f
  {
    float x, y;
    constexpr Vector2f(float x=0.f, float y=0.f) noexcept
    : x(x), y(y)
    {}
  };
 
  struct UnitState
  {
    Vector2f position, velocity;
    Direction facing;
 
    constexpr UnitState() noexcept
    : position(), velocity(), facing(Direction::up)
    {}
  };
 
  class GameUnit
  {
    mutable mutex_type mutex;
    UnitState state;
    float maxSpeed;
    
  public:
    GameUnit() noexcept
    : mutex(), state(), maxSpeed(HUGE_VALF)
    {}
    UnitState getFullState() const
    {
      read_lock_type lock(mutex);
      return state;
    }
    void updatePosition(float x, float y, Direction facing)
    {
      write_lock_type lock(mutex);
      if(std::fabs(state.position.x - x) > maxSpeed
         || std::fabs(state.position.y - y) > maxSpeed)
        return;
      state.position.x = x;
      state.position.y = y;
      state.facing = facing;
    }
  };
  
}
 
 
int main()
{
  using clock_t = std::chrono::steady_clock;
  constexpr int maxReadsToWrites = 1000;
  constexpr std::chrono::seconds seconds(10);
  const clock_t::duration clock_seconds =
    std::chrono::duration_cast<clock_t::duration>(seconds);
  const int maxThreads = omp_get_max_threads();
  std::seed_seq seed;
  std::uniform_real_distribution<float> floatDistr;
  for(int readsToWrites = 1; readsToWrites <= maxReadsToWrites; readsToWrites *= 10) {
    std::uniform_int_distribution<int> intDistr(0, readsToWrites);
    for(int threads = 1; threads <= maxThreads; threads *= 2) {
      GameUnit unit;
      double opsPerSec = 0.;
      const clock_t::time_point startTime = clock_t::now();
#     pragma omp parallel num_threads(threads)
      {
        std::default_random_engine rnd;
#       pragma omp critical
        rnd = std::default_random_engine(seed);
        long long localOps = 0;
        clock_t::duration dt;
        Vector2f pos;
        for(localOps = 0; (dt = clock_t::now() - startTime) < clock_seconds;
            ++localOps) {
          if(intDistr(rnd))
            pos = unit.getFullState().position;
          else {
            pos.x += floatDistr(rnd);
            pos.y += floatDistr(rnd);
            unit.updatePosition(pos.x, pos.y, Direction::up);
          }
        }
        const double localOpsPerSec = localOps /
          (std::chrono::duration_cast<std::chrono::nanoseconds>(dt).count()
           * 1e-9);
#       pragma omp critical
        opsPerSec += localOpsPerSec;
      }
      std::cout << readsToWrites << " reads per write "
                << threads << " threads "
                << opsPerSec << " operations per second\n";
    }
  }
}

Comments