| /* |
| Check that a thread which yields with pause (rep;nop) makes less |
| progress against a pure spinner. |
| */ |
| #include <pthread.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| |
| static pthread_mutex_t m_go = PTHREAD_MUTEX_INITIALIZER; |
| static pthread_cond_t c_go = PTHREAD_COND_INITIALIZER; |
| static pthread_cond_t c_running = PTHREAD_COND_INITIALIZER; |
| |
| static volatile int alive, running; |
| |
| static int spin; |
| static int rep_nop; |
| |
| static void *spinner(void *v) |
| { |
| pthread_mutex_lock(&m_go); |
| while(!alive) |
| pthread_cond_wait(&c_go, &m_go); |
| running++; |
| pthread_cond_signal(&c_running); |
| pthread_mutex_unlock(&m_go); |
| |
| while(alive) |
| spin++; |
| |
| return 0; |
| } |
| |
| static void *rep_nopper(void *v) |
| { |
| pthread_mutex_lock(&m_go); |
| while(!alive) |
| pthread_cond_wait(&c_go, &m_go); |
| running++; |
| pthread_cond_signal(&c_running); |
| pthread_mutex_unlock(&m_go); |
| |
| while(alive) { |
| rep_nop++; |
| // This gives a hint to a P4, telling it to pause |
| // (ie. we're in a spin-wait loop) |
| asm volatile ("rep; nop" : : : "memory"); |
| } |
| |
| return 0; |
| } |
| |
| int main() |
| { |
| pthread_t a, b; |
| |
| pthread_create(&a, NULL, spinner, NULL); |
| pthread_create(&b, NULL, rep_nopper, NULL); |
| |
| /* make sure both threads start at the same time */ |
| pthread_mutex_lock(&m_go); |
| alive = 1; |
| pthread_cond_broadcast(&c_go); |
| |
| /* make sure they both get started */ |
| while(running < 2) |
| pthread_cond_wait(&c_running, &m_go); |
| pthread_mutex_unlock(&m_go); |
| |
| sleep(2); |
| |
| alive = 0; |
| pthread_join(a, NULL); |
| pthread_join(b, NULL); |
| |
| if (0) |
| printf("spin=%d rep_nop=%d rep_nop:spin ratio: %g\n", |
| spin, rep_nop, (float)rep_nop / spin); |
| |
| if (spin > rep_nop) |
| printf("PASS\n"); |
| else |
| printf("FAIL spin=%d rep_nop=%d rep_nop:spin ratio: %g\n", |
| spin, rep_nop, (float)rep_nop / spin); |
| |
| return 0; |
| } |