Chris_M_Thomasson

More realistic test wrt my read/write mutex... in Relacy!

Feb 18th, 2019
282
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.14 KB | None | 0 0
  1. // Experimental Read-Write Mutex Test
  2. // More "realistic" test, in Relacy...
  3. // By: Chris M. Thomasson
  4. //_______________________________________________
  5.  
  6.  
  7. //#define RL_DEBUGBREAK_ON_ASSERT
  8. //#define RL_MSVC_OUTPUT
  9. //#define RL_FORCE_SEQ_CST
  10. //#define RL_GC
  11.  
  12.  
  13. #include <relacy/relacy_std.hpp>
  14. #include <iostream>
  15.  
  16.  
  17. // Simple macro based redirection of the verbose std membars.
  18. #define CT_MB_ACQ std::memory_order_acquire
  19. #define CT_MB_REL std::memory_order_release
  20. #define CT_MB_RLX std::memory_order_relaxed
  21. #define CT_MB_ACQ_REL std::memory_order_acq_rel
  22. #define CT_MB_SEQ_CST std::memory_order_seq_cst
  23. #define CT_MB(mp_0) std::atomic_thread_fence(mp_0)
  24.  
  25.  
  26. #define READERS 4
  27. #define WRITERS 2
  28. #define THREADS (READERS + WRITERS)
  29. #define ITERS 3
  30.  
  31.  
  32.  
  33.  
  34. ////////////////
  35.  
  36.  
  37. // bare bones mutex/condvar based semaphore
  38. struct ct_slow_semaphore
  39. {
  40. VAR_T(unsigned long) m_state;
  41. std::mutex m_mutex;
  42. std::condition_variable m_cond;
  43.  
  44. ct_slow_semaphore(unsigned long state) : m_state(state) {}
  45.  
  46. void inc()
  47. {
  48. m_mutex.lock($);
  49. ++VAR(m_state);
  50. m_mutex.unlock($);
  51. m_cond.notify_one($);
  52. }
  53.  
  54. void add(unsigned long addend)
  55. {
  56. m_mutex.lock($);
  57. VAR(m_state) += addend;
  58. m_mutex.unlock($);
  59. m_cond.notify_all($);
  60. }
  61.  
  62. void dec()
  63. {
  64. m_mutex.lock($);
  65. while (VAR(m_state) == 0) m_cond.wait(m_mutex, $);
  66. --VAR(m_state);
  67. m_mutex.unlock($);
  68. }
  69. };
  70.  
  71.  
  72.  
  73.  
  74. // bin-sema
  75. struct ct_auto_reset_event
  76. {
  77. bool m_state;
  78. std::mutex m_mutex;
  79. std::condition_variable m_cond;
  80.  
  81. ct_auto_reset_event() : m_state(false) {}
  82.  
  83. void signal()
  84. {
  85. m_mutex.lock($);
  86. m_state = true;
  87. m_cond.notify_one($);
  88. m_mutex.unlock($);
  89. }
  90.  
  91. void wait()
  92. {
  93. m_mutex.lock($);
  94. while (m_state == false) m_cond.wait(m_mutex, $);
  95. m_state = false; // auto-reset
  96. m_mutex.unlock($);
  97. }
  98. };
  99.  
  100.  
  101.  
  102.  
  103. // just a layer over an auto-reset event
  104. struct ct_fast_mutex
  105. {
  106. std::atomic<unsigned int> m_state;
  107. ct_auto_reset_event m_waitset;
  108.  
  109. ct_fast_mutex() : m_state(0) {}
  110.  
  111. void lock()
  112. {
  113. if (m_state.exchange(1, std::memory_order_acquire))
  114. {
  115. while (m_state.exchange(2, std::memory_order_acquire))
  116. {
  117. m_waitset.wait();
  118. }
  119. }
  120. }
  121.  
  122. void unlock()
  123. {
  124. if (m_state.exchange(0, std::memory_order_release) == 2)
  125. {
  126. m_waitset.signal();
  127. }
  128. }
  129. };
  130.  
  131.  
  132.  
  133. // Chris M. Thomassons Experimental Read/Write Mutex
  134. // Yeah, it is pretty damn fat wrt the state, however
  135. // it has some interesting properties...
  136. // The state can be compressed a bit...
  137. // btw, it has no loops...
  138. // Take a look at the lock_shared and unlock_shared functions
  139.  
  140. #define RWMUTEX_COUNT_MAX LONG_MAX
  141.  
  142. struct ct_rwmutex
  143. {
  144. // shared state
  145. std::atomic<long> m_wrstate;
  146. std::atomic<long> m_count;
  147. std::atomic<long> m_rdwake;
  148.  
  149. ct_slow_semaphore m_rdwset;
  150. ct_slow_semaphore m_wrwset;
  151. ct_fast_mutex m_wrlock;
  152.  
  153.  
  154. ct_rwmutex() :
  155. m_wrstate(1),
  156. m_count(RWMUTEX_COUNT_MAX),
  157. m_rdwake(0),
  158. m_rdwset(0),
  159. m_wrwset(0) {
  160. }
  161.  
  162.  
  163. // READ, pretty slim...
  164. void lock_shared()
  165. {
  166. if (m_count.fetch_add(-1, std::memory_order_acquire) < 1)
  167. {
  168. m_rdwset.dec();
  169. }
  170. }
  171.  
  172. void unlock_shared()
  173. {
  174. if (m_count.fetch_add(1, std::memory_order_release) < 0)
  175. {
  176. if (m_rdwake.fetch_add(-1, std::memory_order_acq_rel) == 1)
  177. {
  178. m_wrwset.inc();
  179. }
  180. }
  181. }
  182.  
  183.  
  184. // WRITE, more hefty
  185. void lock()
  186. {
  187. m_wrlock.lock();
  188.  
  189. long count = m_count.fetch_add(-RWMUTEX_COUNT_MAX, std::memory_order_acquire);
  190.  
  191. if (count < RWMUTEX_COUNT_MAX)
  192. {
  193. long rdwake = m_rdwake.fetch_add(RWMUTEX_COUNT_MAX - count, std::memory_order_acquire);
  194.  
  195. if (rdwake + RWMUTEX_COUNT_MAX - count)
  196. {
  197. m_wrwset.dec();
  198. }
  199. }
  200. }
  201.  
  202. // write unlock
  203. void unlock()
  204. {
  205. long count = m_count.fetch_add(RWMUTEX_COUNT_MAX, std::memory_order_release);
  206.  
  207. if (count < 0)
  208. {
  209. m_rdwset.add(-count);
  210. }
  211.  
  212. m_wrlock.unlock();
  213. }
  214. };
  215.  
  216.  
  217.  
  218. ////////////////
  219.  
  220.  
  221. struct ct_simple_stack
  222. {
  223. struct node
  224. {
  225. VAR_T(node*) m_next;
  226. VAR_T(unsigned int) m_tid;
  227.  
  228. node(unsigned int tid) : m_tid(tid) {}
  229. };
  230.  
  231. VAR_T(node*) m_head;
  232.  
  233. ct_simple_stack() : m_head(nullptr) {}
  234.  
  235. void push(node* n)
  236. {
  237. VAR(n->m_next) = VAR(m_head);
  238. VAR(m_head) = n;
  239. }
  240.  
  241. node* pop()
  242. {
  243. node* n = VAR(m_head);
  244.  
  245. if (n)
  246. {
  247. VAR(m_head) = VAR(n->m_next);
  248. }
  249.  
  250. return n;
  251. }
  252.  
  253.  
  254. node* flush()
  255. {
  256. node* n = VAR(m_head);
  257. VAR(m_head) = nullptr;
  258. return n;
  259. }
  260.  
  261. };
  262.  
  263.  
  264. void ct_destroy_nodes(ct_simple_stack& s)
  265. {
  266. ct_simple_stack::node* n = s.flush();
  267.  
  268. while (n)
  269. {
  270. ct_simple_stack::node* next = VAR(n->m_next);
  271. delete n;
  272. n = next;
  273. }
  274. }
  275.  
  276.  
  277.  
  278. // Relacy Stack Test...
  279. struct ct_fast_mutex_test
  280. : rl::test_suite<ct_fast_mutex_test, THREADS>
  281. {
  282. ct_rwmutex g_rwmutex;
  283. ct_simple_stack g_stack;
  284.  
  285. void before()
  286. {
  287.  
  288. }
  289.  
  290. void after()
  291. {
  292. ct_destroy_nodes(g_stack);
  293. }
  294.  
  295. // reader
  296. void reader(unsigned int tidx)
  297. {
  298. g_rwmutex.lock_shared();
  299.  
  300. for (unsigned int i = 0; i < ITERS; ++i)
  301. {
  302. ct_simple_stack::node* h = VAR(g_stack.m_head);
  303.  
  304. while (h)
  305. {
  306. ct_simple_stack::node* next = VAR(h->m_next);
  307.  
  308. if (i % 512 == 0)
  309. {
  310. rl::yield(1, $);
  311. }
  312.  
  313. h = next;
  314. }
  315. }
  316.  
  317. g_rwmutex.unlock_shared();
  318. }
  319.  
  320.  
  321. // writer
  322. void writer(unsigned int tidx)
  323. {
  324. g_rwmutex.lock();
  325. g_stack.push(new ct_simple_stack::node(tidx));
  326. g_stack.push(new ct_simple_stack::node(tidx));
  327. g_rwmutex.unlock();
  328.  
  329. g_rwmutex.lock();
  330. ct_simple_stack::node* n = g_stack.pop();
  331. g_rwmutex.unlock();
  332.  
  333. if (n)
  334. {
  335. // destroy
  336. delete n;
  337. }
  338. }
  339.  
  340.  
  341. void thread(unsigned int tidx)
  342. {
  343. if (tidx < READERS)
  344. {
  345. reader(tidx);
  346. }
  347.  
  348. else
  349. {
  350. writer(tidx);
  351. }
  352. }
  353. };
  354.  
  355.  
  356.  
  357. // Test away... Or fly? Humm...
  358. int main()
  359. {
  360. {
  361. rl::test_params p;
  362.  
  363. p.iteration_count = 10000000;
  364. //p.execution_depth_limit = 33333;
  365. //p.search_type = rl::sched_bound;
  366. //p.search_type = rl::fair_full_search_scheduler_type;
  367. //p.search_type = rl::fair_context_bound_scheduler_type;
  368.  
  369. rl::simulate<ct_fast_mutex_test>(p);
  370. }
  371.  
  372. return 0;
  373. }
Advertisement
Add Comment
Please, Sign In to add comment