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.

181 lines
5.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. #include <pthread.h>
  10. float tdiff (struct timeval *start, struct timeval *end) {
  11. return 1e6*(end->tv_sec-start->tv_sec) +(end->tv_usec - start->tv_usec);
  12. }
  13. /* My own rwlock implementation. */
  14. struct brwl {
  15. int mutex;
  16. int state; // 0 for unlocked, -1 for a writer, otherwise many readers
  17. };
  18. static inline int xchg(volatile int *ptr, int x)
  19. {
  20. __asm__("xchgl %0,%1" :"=r" (x) :"m" (*(ptr)), "0" (x) :"memory");
  21. return x;
  22. }
  23. static inline void sfence (void) {
  24. asm volatile ("sfence":::"memory");
  25. }
  26. static inline void brwl_rlock_fence (struct brwl *l) {
  27. while (xchg(&l->mutex, 1)) ;
  28. l->state++;
  29. sfence();
  30. l->mutex=0;
  31. }
  32. static inline void brwl_rlock_xchg (struct brwl *l) {
  33. while (xchg(&l->mutex, 1)) ;
  34. l->state++;
  35. xchg(&l->mutex, 0);
  36. }
  37. // Something wrong with the compiler for longs
  38. static inline long
  39. fetch_and_add (volatile long *p, long incr)
  40. {
  41. long result = incr;
  42. __asm__ __volatile__ ("lock; xaddl %0, %1" :
  43. "+r" (result), "+m" (*p) : : "memory");
  44. return result;
  45. }
  46. static inline int
  47. fetch_and_add_i (volatile int *p, int incr)
  48. {
  49. int result = incr;
  50. __asm__ __volatile__ ("lock; xadd %0, %1" :
  51. "+r" (result), "+m" (*p) : : "memory");
  52. return result;
  53. }
  54. static inline int
  55. gcc_fetch_and_add_i (volatile int *p, int incr)
  56. {
  57. return __sync_fetch_and_add(p, incr);
  58. }
  59. static inline long
  60. gcc_fetch_and_add_l (volatile long *p, long incr)
  61. {
  62. return __sync_fetch_and_add(p, incr);
  63. }
  64. // Something wrong with the compiler for longs
  65. /* Returns nonzero if the comparison succeeded. */
  66. static inline long
  67. compare_and_swap_full(volatile long *addr,
  68. long old, long new_val)
  69. {
  70. char result;
  71. __asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1"
  72. : "+m"(*(addr)), "=q"(result)
  73. : "r" (new_val), "a"(old) : "memory");
  74. return (int) result;
  75. }
  76. /* Returns nonzero if the comparison succeeded. */
  77. // Atomically compare *addr to old_val, and replace *addr by new_val
  78. // if the first comparison succeeds. Returns nonzero if the comparison
  79. // succeeded and *addr was updated.
  80. static inline int
  81. compare_and_swap_full_i(volatile int *addr,
  82. int old, int new_val)
  83. {
  84. char result;
  85. __asm__ __volatile__("lock; cmpxchg %2, %0; setz %1"
  86. : "+m"(*(addr)), "=q"(result)
  87. : "r" (new_val), "a"(old) : "memory");
  88. return (int) result;
  89. }
  90. enum {K=100000};
  91. pthread_rwlock_t rwlocks[K];
  92. struct brwl blocks[K];
  93. pthread_mutex_t mlocks[K];
  94. long lvals[K];
  95. int ivals[K];
  96. #define TIME(s, i, init, body) ({ \
  97. int j_tmp; \
  98. printf("%-24s", s); \
  99. for (j_tmp=0; j_tmp<3; j_tmp++) { \
  100. struct timeval start,end; \
  101. int i; \
  102. for (i=0; i<K; i++) { \
  103. init; \
  104. } \
  105. gettimeofday(&start, 0); \
  106. for (i=0; i<K; i++) { \
  107. body; \
  108. } \
  109. gettimeofday(&end, 0); \
  110. printf(" %9.3fus", tdiff(&start,&end)/K); \
  111. } \
  112. printf("\n"); \
  113. })
  114. int main (int argc __attribute__((__unused__)), char *argv[] __attribute__((__unused__))) {
  115. printf("sizeof (pthread_mutex_t) %lu\n", sizeof (pthread_mutex_t));
  116. printf("sizeof (pthread_cond_t) %lu\n", sizeof (pthread_cond_t));
  117. TIME("pthread_mutex_lock_errorcheck", i,
  118. ({ int r; pthread_mutexattr_t mattr;
  119. r = pthread_mutexattr_init(&mattr); assert(r == 0);
  120. r = pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ERRORCHECK_NP); assert(r == 0);
  121. r = pthread_mutex_init(&mlocks[i], &mattr); assert(r==0);
  122. r = pthread_mutexattr_destroy(&mattr); assert(r == 0); }),
  123. ({ int r = pthread_mutex_lock(&mlocks[i]); assert(r==0); }));
  124. TIME("pthread_mutex_lock", i,
  125. ({ int r = pthread_mutex_init(&mlocks[i], NULL); assert(r==0); }),
  126. ({ int r = pthread_mutex_lock(&mlocks[i]); assert(r==0); }));
  127. TIME("pthread_mutex_unlock", i,
  128. ({ int r = pthread_mutex_init(&mlocks[i], NULL); assert(r==0); r = pthread_mutex_lock(&mlocks[i]); assert(r==0); }),
  129. ({ int r = pthread_mutex_unlock(&mlocks[i]); assert(r==0); }));
  130. TIME("pthread_rwlock_tryrdlock", i,
  131. ({ int r = pthread_rwlock_init(&rwlocks[i], NULL); assert(r==0); }),
  132. ({ int r = pthread_rwlock_tryrdlock(&rwlocks[i]); assert(r==0); }));
  133. TIME("pthread_rwlock_rdlock", i,
  134. ({ int r = pthread_rwlock_init(&rwlocks[i], NULL); assert(r==0); }),
  135. ({ int r = pthread_rwlock_rdlock(&rwlocks[i]); assert(r==0); }));
  136. TIME("brwl_rlock_xchg", i,
  137. (blocks[i].state=0, blocks[i].mutex=0),
  138. brwl_rlock_xchg(&blocks[i]));
  139. TIME("brwl_rlock_fence", i,
  140. (blocks[i].state=0, blocks[i].mutex=0),
  141. brwl_rlock_fence(&blocks[i]));
  142. int fa=0;
  143. TIME("fetchadd", i,
  144. (void)0,
  145. fetch_and_add_i(&fa, i));
  146. // printf("fa=%d\n", fa);
  147. fa=0;
  148. TIME("gcc_fetchadd", i,
  149. (void)0,
  150. gcc_fetch_and_add_i(&fa, i));
  151. // printf("fa=%d\n", fa);
  152. long fal = 0;
  153. TIME("gcc_fetchaddlong", i,
  154. (void)0,
  155. gcc_fetch_and_add_l(&fal, i));
  156. // printf("fa=%d\n", fa);
  157. TIME("compare_and_swap", i,
  158. ivals[i]=0,
  159. ({ int r=compare_and_swap_full_i(&ivals[i], 0, 1); assert(r==1); }));
  160. return 0;
  161. }