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