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