1
2/*
3 *  Copyright (c) 2003, Intel Corporation. All rights reserved.
4 *  Created by:  crystal.xiong REMOVE-THIS AT intel DOT com
5 *  This file is licensed under the GPL license.  For the full content
6 *  of this license, see the COPYING file at the top level of this
7 *  source tree.
8 */
9
10/* There are n TF threads, n is equal to the processors in the system minus
11 * one. TFs are used to keep busy these CPUs, which have priority 4. A
12 * TL thread with priority 1 is created, which locks mutex1 and
13 * does workload. A TB1 thread with higher priority 2 is created and try
14 * to lock mutex1 of TL, TB1 will also lock another mutex mutex2. A TB2 thread
15 * with high priority 5 is created and try to lock mutex2 of TB1. Then TB's
16 * priority will boost to TB2's, and TL's priority will boost to TB1's.
17 * There are another 1 thread TP, which is used to check the
18 * priority change of TL, P(TB1)<P(TL)<P(TP)<P(TB2), P(TH) stands for
19 * the priority of TH thread. Main thread has the highest priority 8,
20 * which will control the running steps of those threads, including
21 * creating threads, stopping threads. There is another thread to collect
22 * the sample data with priority 7.
23 *
24 * Steps:
25 * 1.	Create n TF threads, n is equal to processors number minus one. TF
26 * 	will do workload.
27 * 2.	Create 1 TP threads and do workload. The thread
28 * 	will keep running when TL is created.
29 * 3.	Create 1 TL thread to lock mutex1. TL will get a chance to
30 * 	run when TP sleep a wee bit in between.
31 * 4.	Create 1 TB1 thread to lock mutex2 and try to lock mutex1, TL's priority will
32 *	be boosted to TB1
33 * 5.	Create 1 TB2 thread to lock mutex2. TB1's priority will boost to
34 *  	TB2's priority, then TL's priority will boost to TB1's new priority.
35 * 6.	Stop these threads.
36 *
37 */
38
39#include <pthread.h>
40#include <stdio.h>
41#include <unistd.h>
42#include <string.h>
43#include <stdlib.h>
44#include <time.h>
45#include <sched.h>
46#include <errno.h>
47#include "test.h"
48#include "pitest.h"
49
50int cpus;
51pthread_mutex_t mutex1;
52pthread_mutex_t mutex2;
53volatile int ts_stop = 0;
54volatile double base_time;
55
56struct thread_param
57{
58	int index;
59	volatile int stop;
60	int sleep_ms;
61	int priority;
62	int policy;
63	const char *name;
64	int cpu;
65	volatile unsigned futex;
66	volatile unsigned should_stall;
67	volatile unsigned progress;
68} tp[] =
69{
70	{ 0,   0,   0, 1, SCHED_FIFO, "TL",  0, 0, 0, 0 },
71	{ 1,   0, 100, 3, SCHED_FIFO, "TP",  0, 0, 0, 0 },
72	{ 2,   0,   0, 4, SCHED_FIFO, "TF",  1, 0, 0, 0 },
73	{ 3,   0,   0, 4, SCHED_FIFO, "TF",  2, 0, 0, 0 },
74	{ 4,   0,   0, 4, SCHED_FIFO, "TF",  3, 0, 0, 0 },
75	{ 5,   0,   0, 4, SCHED_FIFO, "TF",  4, 0, 0, 0 },
76	{ 6,   0,   0, 4, SCHED_FIFO, "TF",  5, 0, 0, 0 },
77	{ 7,   0,   0, 4, SCHED_FIFO, "TF",  6, 0, 0, 0 }
78};
79
80volatile unsigned do_work_dummy;
81void do_work(unsigned granularity_top, volatile unsigned *progress)
82{
83	unsigned granularity_cnt, i;
84	unsigned top = 5 * 1000 * 1000;
85	unsigned dummy = do_work_dummy;
86
87	for (granularity_cnt = 0; granularity_cnt < granularity_top;
88	     granularity_cnt++)
89	{
90		for (i = 0; i < top; i++)
91			dummy = i | dummy;
92		(*progress)++;
93	}
94	return;
95}
96
97void *thread_fn(void *param)
98{
99	struct thread_param *tp = param;
100	struct timespec ts;
101	int rc;
102	unsigned long mask = 1 << tp->cpu;
103
104	rc = sched_setaffinity(0, sizeof(mask), &mask);
105	if (rc < 0) {
106		EPRINTF("UNRESOLVED: Thread %s index %d: Can't set affinity: "
107			"%d %s", tp->name, tp->index, rc, strerror(rc));
108		exit(UNRESOLVED);
109	}
110	test_set_priority(pthread_self(),SCHED_FIFO, tp->priority);
111
112	DPRINTF(stdout, "#EVENT %f Thread %s Started\n",
113		seconds_read() - base_time, tp->name);
114	DPRINTF(stderr,"Thread %s index %d: started\n", tp->name, tp->index);
115
116	tp->progress = 0;
117	ts.tv_sec = 0;
118	ts.tv_nsec = tp->sleep_ms * 1000 * 1000;
119	if (tp->index == 0)
120		pthread_mutex_lock(&mutex1);
121	while (!tp->stop)
122	{
123		do_work(5, &tp->progress);
124		if (tp->sleep_ms == 0)
125			continue;
126		rc = nanosleep(&ts, NULL);
127		if (rc < 0) {
128			EPRINTF("UNRESOLVED: Thread %s %d: nanosleep returned "
129				"%d %s", tp->name, tp->index, rc, strerror(rc));
130			exit(UNRESOLVED);
131		}
132	}
133	if (tp->index == 0)
134		pthread_mutex_unlock(&mutex1);
135
136	DPRINTF(stdout, "#EVENT %f Thread %s Stopped\n",
137		seconds_read() - base_time, tp->name);
138	return NULL;
139}
140
141void *thread_sample(void *arg)
142{
143	char buffer[1024];
144	struct timespec ts;
145	double period = 300;
146	double newtime;
147	size_t size;
148	int i;
149	int rc;
150
151	test_set_priority(pthread_self(),SCHED_FIFO, 6);
152	DPRINTF(stderr,"Thread Sampler: started\n");
153	DPRINTF(stdout, "# COLUMNS %d Time TL TP ", 2 + cpus);
154	for (i = 0; i < (cpus - 1); i++)
155		DPRINTF(stdout, "TF%d ", i);
156	DPRINTF(stdout, "\n");
157	ts.tv_sec = 0;
158	ts.tv_nsec = period * 1000 * 1000;
159	while (!ts_stop)
160	{
161		newtime = seconds_read();
162		size = snprintf(buffer, 1023, "%f ", newtime - base_time);
163		for (i = 0; i < cpus + 1; i++)
164			size += snprintf(buffer + size, 1023 - size, "%u ", tp[i].progress);
165		DPRINTF(stdout,"%s\n", buffer);
166		rc = nanosleep(&ts, NULL);
167		if (rc < 0)
168			EPRINTF("UNRESOLVED: Thread %s %d: nanosleep returned "
169				"%d %s", tp->name, tp->index, rc, strerror(rc));
170	}
171	return NULL;
172}
173
174void *thread_tb1(void *arg)
175{
176	unsigned long timeoutsec;
177	struct timespec boost_time;
178	double t0, t1;
179	int rc;
180
181	test_set_priority(pthread_self(),SCHED_FIFO, 2);
182	DPRINTF(stderr,"Thread TB1: started\n");
183	DPRINTF(stdout, "#EVENT %f Thread TB1 Started\n",
184		seconds_read() - base_time);
185
186	pthread_mutex_lock(&mutex2);
187
188	timeoutsec = *(unsigned long*) arg;
189	boost_time.tv_sec = time(NULL) + (time_t)timeoutsec;
190	boost_time.tv_nsec = 0;
191	t0 = seconds_read();
192	rc = pthread_mutex_timedlock(&mutex1, &boost_time);
193	t1 = seconds_read();
194
195	DPRINTF(stdout, "#EVENT %f TB1 Waited on mutex1 for %.2f s\n",
196		t1 - base_time, t1 - t0);
197
198	if (rc != ETIMEDOUT) {
199		EPRINTF("FAIL: Thread TB1: lock returned %d %s, "
200			"slept %f", rc, strerror(rc), t1 - t0);
201		exit(FAIL);
202	}
203
204	pthread_mutex_unlock(&mutex2);
205	return NULL;
206}
207
208
209void *thread_tb2(void *arg)
210{
211	unsigned long timeoutsec;
212	struct timespec boost_time;
213	double t0, t1;
214	int rc;
215
216	test_set_priority(pthread_self(),SCHED_FIFO, 5);
217	DPRINTF(stderr,"Thread TB2: started\n");
218	DPRINTF(stdout, "#EVENT %f Thread TB2 Started\n",
219		seconds_read() - base_time);
220
221	timeoutsec = *(unsigned long*) arg;
222	boost_time.tv_sec = time(NULL) + (time_t)timeoutsec;
223	boost_time.tv_nsec = 0;
224
225	t0 = seconds_read();
226	rc = pthread_mutex_timedlock(&mutex2, &boost_time);
227	t1 = seconds_read();
228
229	DPRINTF(stdout, "#EVENT %f Thread TB2 Waited on mutex2 for %.2f s\n",
230		t1 - base_time, t1 - t0);
231
232	if (rc != ETIMEDOUT) {
233		EPRINTF("FAIL: Thread TB2: lock mutex2 returned %d %s, "
234			"slept %f", rc, strerror(rc), t1 - t0);
235		exit(FAIL);
236	}
237	return NULL;
238}
239
240int main(int argc, char **argv)
241{
242	pthread_mutexattr_t mutex_attr;
243	pthread_attr_t	threadattr;
244	pthread_t threads[cpus - 1];
245	pthread_t threadsample, threadtp, threadtl, threadtb1, threadtb2;
246
247	int multiplier = 1;
248	int i;
249	int rc;
250
251	test_set_priority(pthread_self(),SCHED_FIFO, 8);
252	base_time = seconds_read();
253	cpus = sysconf(_SC_NPROCESSORS_ONLN);
254
255	/* Initialize mutex1, mutex2 with PTHREAD_PRIO_INHERIT protocol */
256	mutex_attr_init(&mutex_attr);
257	mutex_init(&mutex1, &mutex_attr);
258	mutex_init(&mutex2, &mutex_attr);
259
260	/* Initialize thread attr */
261	threadattr_init(&threadattr);
262
263	/* Start the sample thread */
264	DPRINTF(stderr,"Main Thread: Creating sample thread\n");
265	rc = pthread_create(&threadsample, &threadattr, thread_sample, NULL);
266        if (rc != 0) {
267                EPRINTF("UNRESOLVED: pthread_create: %d %s",
268                        rc, strerror(rc));
269                exit(UNRESOLVED);
270        }
271
272	/* Start the TF threads */
273	DPRINTF(stderr,"Main Thread: Creating %d TF threads\n", cpus-1);
274	for (i = 0; i < cpus - 1; i++)
275	{
276		rc = pthread_create(&threads[i], &threadattr, thread_fn,
277				    &tp[i + 2]);
278	        if (rc != 0) {
279	                EPRINTF("UNRESOLVED: pthread_create: %d %s",
280	                        rc, strerror(rc));
281	                exit(UNRESOLVED);
282	        }
283	}
284	sleep(base_time + multiplier * 10 - seconds_read());
285
286	/* Start TP thread */
287	DPRINTF(stderr,"Main Thread: Creating TP thread\n");
288	rc = pthread_create(&threadtp, &threadattr, thread_fn, &tp[1]);
289       	if (rc != 0) {
290               	EPRINTF("UNRESOLVED: pthread_create: %d %s",
291                       	rc, strerror(rc));
292               	exit(UNRESOLVED);
293        }
294	sleep(base_time + multiplier * 20 - seconds_read());
295
296	/* Start TL thread */
297	DPRINTF(stderr,"Main Thread: Creating TL thread\n");
298	rc = pthread_create(&threadtl, &threadattr, thread_fn, &tp[0]);
299        if (rc != 0) {
300                EPRINTF("UNRESOLVED: pthread_create: %d %s",
301                        rc, strerror(rc));
302                exit(UNRESOLVED);
303        }
304	sleep(base_time + multiplier * 30 - seconds_read());
305
306	/* Start TB1 thread (the lowest priority thread) */
307	int timeout = multiplier * 40;
308	rc = pthread_create(&threadtb1, &threadattr, thread_tb1,
309			    &timeout);
310        if (rc != 0) {
311                EPRINTF("UNRESOLVED: pthread_create: %d %s",
312                        rc, strerror(rc));
313                exit(UNRESOLVED);
314        }
315	sleep(base_time + multiplier * 40 - seconds_read());
316
317	/* Start TB2 thread (boosting thread) */
318	timeout = multiplier * 20;
319	rc = pthread_create(&threadtb2, &threadattr, thread_tb2,
320			    &timeout);
321        if (rc != 0) {
322                EPRINTF("UNRESOLVED: pthread_create: %d %s",
323                        rc, strerror(rc));
324                exit(UNRESOLVED);
325        }
326	sleep(base_time + multiplier * 75 - seconds_read());
327
328	/* Stop TL thread */
329	tp[0].stop = 1;
330	sleep(base_time + multiplier * 85 - seconds_read());
331
332	/* Stop TP thread */
333	tp[1].stop = 1;
334	sleep(base_time + multiplier * 95 - seconds_read());
335
336	/* Stop TF threads */
337	for (i = 2; i < cpus - 1; i++)
338	{
339		tp[i].stop = 1;
340	}
341
342	/* Stop sampler */
343	ts_stop = 1;
344	DPRINTF(stderr,"Main Thread: stop sampler thread\n");
345	return 0;
346}
347
348
349