You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

146 lines
4.3 KiB

  1. /* How expensive is
  2. * - Obtaining a read-only lock for the first obtainer.
  3. * - Obtaining it for the second one?
  4. * - The third one? */
  5. #include <assert.h>
  6. #include <pthread.h>
  7. #include <stdio.h>
  8. #include <sys/time.h>
  9. float tdiff (struct timeval *start, struct timeval *end) {
  10. return 1e6*(end->tv_sec-start->tv_sec) +(end->tv_usec - start->tv_usec);
  11. }
  12. /* My own rwlock implementation. */
  13. struct brwl {
  14. int mutex;
  15. int state; // 0 for unlocked, -1 for a writer, otherwise many readers
  16. };
  17. static inline int xchg(volatile int *ptr, int x)
  18. {
  19. __asm__("xchgl %0,%1" :"=r" (x) :"m" (*(ptr)), "0" (x) :"memory");
  20. return x;
  21. }
  22. static inline void sfence (void) {
  23. asm volatile ("sfence":::"memory");
  24. }
  25. static inline void brwl_rlock_fence (struct brwl *l) {
  26. while (xchg(&l->mutex, 1)) ;
  27. l->state++;
  28. sfence();
  29. l->mutex=0;
  30. }
  31. static inline void brwl_rlock_xchg (struct brwl *l) {
  32. while (xchg(&l->mutex, 1)) ;
  33. l->state++;
  34. xchg(&l->mutex, 0);
  35. }
  36. // Something wrong with the compiler for longs
  37. static inline long
  38. fetch_and_add (volatile long *p, long incr)
  39. {
  40. long result = incr;
  41. __asm__ __volatile__ ("lock; xaddl %0, %1" :
  42. "+r" (result), "+m" (*p) : : "memory");
  43. return result;
  44. }
  45. static inline int
  46. fetch_and_add_i (volatile int *p, int incr)
  47. {
  48. int result = incr;
  49. __asm__ __volatile__ ("lock; xadd %0, %1" :
  50. "+r" (result), "+m" (*p) : : "memory");
  51. return result;
  52. }
  53. // Something wrong with the compiler for longs
  54. /* Returns nonzero if the comparison succeeded. */
  55. static inline long
  56. compare_and_swap_full(volatile long *addr,
  57. long old, long new_val)
  58. {
  59. char result;
  60. __asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1"
  61. : "+m"(*(addr)), "=q"(result)
  62. : "r" (new_val), "a"(old) : "memory");
  63. return (int) result;
  64. }
  65. /* Returns nonzero if the comparison succeeded. */
  66. // Atomically compare *addr to old_val, and replace *addr by new_val
  67. // if the first comparison succeeds. Returns nonzero if the comparison
  68. // succeeded and *addr was updated.
  69. static inline int
  70. compare_and_swap_full_i(volatile int *addr,
  71. int old, int new_val)
  72. {
  73. char result;
  74. __asm__ __volatile__("lock; cmpxchg %2, %0; setz %1"
  75. : "+m"(*(addr)), "=q"(result)
  76. : "r" (new_val), "a"(old) : "memory");
  77. return (int) result;
  78. }
  79. enum {K=100000};
  80. pthread_rwlock_t rwlocks[K];
  81. struct brwl blocks[K];
  82. pthread_mutex_t mlocks[K];
  83. long lvals[K];
  84. int ivals[K];
  85. #define TIME(s, i, init, body) ({ \
  86. int j_tmp; \
  87. printf("%-24s", s); \
  88. for (j_tmp=0; j_tmp<3; j_tmp++) { \
  89. struct timeval start,end; \
  90. int i; \
  91. for (i=0; i<K; i++) { \
  92. init; \
  93. } \
  94. gettimeofday(&start, 0); \
  95. for (i=0; i<K; i++) { \
  96. body; \
  97. } \
  98. gettimeofday(&end, 0); \
  99. printf(" %9.3fus", tdiff(&start,&end)/K); \
  100. } \
  101. printf("\n"); \
  102. })
  103. int main (int argc __attribute__((__unused__)), char *argv[] __attribute__((__unused__))) {
  104. TIME("pthread_mutex_lock", i,
  105. ({ int r = pthread_mutex_init(&mlocks[i], NULL); assert(r==0); }),
  106. ({ int r = pthread_mutex_lock(&mlocks[i]); assert(r==0); }));
  107. TIME("pthread_mutex_unlock", i,
  108. ({ int r = pthread_mutex_init(&mlocks[i], NULL); assert(r==0); r = pthread_mutex_lock(&mlocks[i]); assert(r==0); }),
  109. ({ int r = pthread_mutex_unlock(&mlocks[i]); assert(r==0); }));
  110. TIME("pthread_rwlock_tryrdlock", i,
  111. ({ int r = pthread_rwlock_init(&rwlocks[i], NULL); assert(r==0); }),
  112. ({ int r = pthread_rwlock_tryrdlock(&rwlocks[i]); assert(r==0); }));
  113. TIME("pthread_rwlock_rdlock", i,
  114. ({ int r = pthread_rwlock_init(&rwlocks[i], NULL); assert(r==0); }),
  115. ({ int r = pthread_rwlock_rdlock(&rwlocks[i]); assert(r==0); }));
  116. TIME("brwl_rlock_xchg", i,
  117. (blocks[i].state=0, blocks[i].mutex=0),
  118. brwl_rlock_xchg(&blocks[i]));
  119. TIME("brwl_rlock_fence", i,
  120. (blocks[i].state=0, blocks[i].mutex=0),
  121. brwl_rlock_fence(&blocks[i]));
  122. int fa=0;
  123. TIME("fetchadd", i,
  124. (void)0,
  125. fetch_and_add_i(&fa, i));
  126. TIME("compare_and_swap", i,
  127. ivals[i]=0,
  128. ({ int r=compare_and_swap_full_i(&ivals[i], 0, 1); assert(r==1); }));
  129. return 0;
  130. }