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
spinner(void * v)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
rep_nopper(void * v)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
main()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