/* 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; }