1 /* 2 Check that a thread which yields with pause (rep;nop) makes less 3 progress against a pure spinner. 4 */ 5 #include <pthread.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <unistd.h> 9 10 static pthread_mutex_t m_go = PTHREAD_MUTEX_INITIALIZER; 11 static pthread_cond_t c_go = PTHREAD_COND_INITIALIZER; 12 static pthread_cond_t c_running = PTHREAD_COND_INITIALIZER; 13 14 static volatile int alive, running; 15 16 static int spin; 17 static int rep_nop; 18 19 static void *spinner(void *v) 20 { 21 pthread_mutex_lock(&m_go); 22 while(!alive) 23 pthread_cond_wait(&c_go, &m_go); 24 running++; 25 pthread_cond_signal(&c_running); 26 pthread_mutex_unlock(&m_go); 27 28 while(alive) 29 spin++; 30 31 return 0; 32 } 33 34 static void *rep_nopper(void *v) 35 { 36 pthread_mutex_lock(&m_go); 37 while(!alive) 38 pthread_cond_wait(&c_go, &m_go); 39 running++; 40 pthread_cond_signal(&c_running); 41 pthread_mutex_unlock(&m_go); 42 43 while(alive) { 44 rep_nop++; 45 // This gives a hint to a P4, telling it to pause 46 // (ie. we're in a spin-wait loop) 47 asm volatile ("rep; nop" : : : "memory"); 48 } 49 50 return 0; 51 } 52 53 int main() 54 { 55 pthread_t a, b; 56 57 pthread_create(&a, NULL, spinner, NULL); 58 pthread_create(&b, NULL, rep_nopper, NULL); 59 60 /* make sure both threads start at the same time */ 61 pthread_mutex_lock(&m_go); 62 alive = 1; 63 pthread_cond_broadcast(&c_go); 64 65 /* make sure they both get started */ 66 while(running < 2) 67 pthread_cond_wait(&c_running, &m_go); 68 pthread_mutex_unlock(&m_go); 69 70 sleep(2); 71 72 alive = 0; 73 pthread_join(a, NULL); 74 pthread_join(b, NULL); 75 76 if (0) 77 printf("spin=%d rep_nop=%d rep_nop:spin ratio: %g\n", 78 spin, rep_nop, (float)rep_nop / spin); 79 80 if (spin > rep_nop) 81 printf("PASS\n"); 82 else 83 printf("FAIL spin=%d rep_nop=%d rep_nop:spin ratio: %g\n", 84 spin, rep_nop, (float)rep_nop / spin); 85 86 return 0; 87 } 88