• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #warning "Contains Linux-isms that need fixing."
40 
41 #include <errno.h>
42 #include <pthread.h>
43 #include <sched.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <time.h>
48 #include <unistd.h>
49 #include "test.h"
50 #include "pitest.h"
51 
52 int cpus;
53 pthread_mutex_t mutex1;
54 pthread_mutex_t mutex2;
55 volatile int ts_stop = 0;
56 volatile double base_time;
57 
58 struct thread_param {
59 	int index;
60 	volatile int stop;
61 	int sleep_ms;
62 	int priority;
63 	int policy;
64 	const char *name;
65 	int cpu;
66 	volatile unsigned futex;
67 	volatile unsigned should_stall;
68 	volatile unsigned progress;
69 } tp[] = {
70 	{
71 	0, 0, 0, 1, SCHED_FIFO, "TL", 0, 0, 0, 0}, {
72 	1, 0, 100, 4, SCHED_FIFO, "TP", 0, 0, 0, 0}, {
73 	2, 0, 0, 2, SCHED_FIFO, "TF", 1, 0, 0, 0}, {
74 	3, 0, 0, 2, SCHED_FIFO, "TF", 2, 0, 0, 0}, {
75 	4, 0, 0, 2, SCHED_FIFO, "TF", 3, 0, 0, 0}, {
76 	5, 0, 0, 2, SCHED_FIFO, "TF", 4, 0, 0, 0}, {
77 	6, 0, 0, 2, SCHED_FIFO, "TF", 5, 0, 0, 0}, {
78 	7, 0, 0, 2, SCHED_FIFO, "TF", 6, 0, 0, 0}
79 };
80 
81 volatile unsigned do_work_dummy;
do_work(unsigned granularity_top,volatile unsigned * progress)82 void do_work(unsigned granularity_top, volatile unsigned *progress)
83 {
84 	unsigned granularity_cnt, i;
85 	unsigned top = 5 * 1000 * 1000;
86 	unsigned dummy = do_work_dummy;
87 
88 	for (granularity_cnt = 0; granularity_cnt < granularity_top;
89 	     granularity_cnt++) {
90 		for (i = 0; i < top; i++)
91 			dummy = i | dummy;
92 		(*progress)++;
93 	}
94 	return;
95 }
96 
thread_fn(void * param)97 void *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 #if __linux__
105 	rc = sched_setaffinity(0, sizeof(mask), &mask);
106 	if (rc < 0) {
107 		EPRINTF("UNRESOLVED: Thread %s index %d: Can't set affinity: "
108 			"%d %s", tp->name, tp->index, rc, strerror(rc));
109 		exit(UNRESOLVED);
110 	}
111 #endif
112 	test_set_priority(pthread_self(), SCHED_FIFO, tp->priority);
113 
114 	DPRINTF(stdout, "#EVENT %f Thread %s Started\n",
115 		seconds_read() - base_time, tp->name);
116 	DPRINTF(stderr, "Thread %s index %d: started\n", tp->name, tp->index);
117 
118 	tp->progress = 0;
119 	ts.tv_sec = 0;
120 	ts.tv_nsec = tp->sleep_ms * 1000 * 1000;
121 	if (tp->index == 0)
122 		pthread_mutex_lock(&mutex1);
123 	while (!tp->stop) {
124 		do_work(5, &tp->progress);
125 		if (tp->sleep_ms == 0)
126 			continue;
127 		rc = nanosleep(&ts, NULL);
128 		if (rc < 0) {
129 			EPRINTF("UNRESOLVED: Thread %s %d: nanosleep returned "
130 				"%d %s", tp->name, tp->index, rc, strerror(rc));
131 			exit(UNRESOLVED);
132 		}
133 	}
134 	if (tp->index == 0)
135 		pthread_mutex_unlock(&mutex1);
136 
137 	DPRINTF(stdout, "#EVENT %f Thread %s Stopped\n",
138 		seconds_read() - base_time, tp->name);
139 	return NULL;
140 }
141 
thread_sample(void * arg)142 void *thread_sample(void *arg)
143 {
144 	char buffer[1024];
145 	struct timespec ts;
146 	double period = 300;
147 	double newtime;
148 	size_t size;
149 	int i;
150 	int rc;
151 
152 	test_set_priority(pthread_self(), SCHED_FIFO, 6);
153 	DPRINTF(stderr, "Thread Sampler: started\n");
154 	DPRINTF(stdout, "# COLUMNS %d Time TL TP ", 2 + cpus);
155 	for (i = 0; i < (cpus - 1); i++)
156 		DPRINTF(stdout, "TF%d ", i);
157 	DPRINTF(stdout, "\n");
158 	ts.tv_sec = 0;
159 	ts.tv_nsec = period * 1000 * 1000;
160 	while (!ts_stop) {
161 		newtime = seconds_read();
162 		size = snprintf(buffer, 1023, "%f ", newtime - base_time);
163 		for (i = 0; i < cpus + 1; i++)
164 			size +=
165 			    snprintf(buffer + size, 1023 - size, "%u ",
166 				     tp[i].progress);
167 		DPRINTF(stdout, "%s\n", buffer);
168 		rc = nanosleep(&ts, NULL);
169 		if (rc < 0)
170 			EPRINTF("UNRESOLVED: Thread %s %d: nanosleep returned "
171 				"%d %s", tp->name, tp->index, rc, strerror(rc));
172 	}
173 	return NULL;
174 }
175 
thread_tb1(void * arg)176 void *thread_tb1(void *arg)
177 {
178 	struct timespec boost_time;
179 	double t0, t1;
180 	int rc;
181 
182 	test_set_priority(pthread_self(), SCHED_FIFO, 3);
183 	DPRINTF(stderr, "Thread TB1: started\n");
184 	DPRINTF(stdout, "#EVENT %f Thread TB1 Started\n",
185 		seconds_read() - base_time);
186 
187 	pthread_mutex_lock(&mutex2);
188 
189 	boost_time.tv_sec = time(NULL) + *(time_t *) arg;
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 
thread_tb2(void * arg)208 void *thread_tb2(void *arg)
209 {
210 	struct timespec boost_time;
211 	double t0, t1;
212 	int rc;
213 
214 	test_set_priority(pthread_self(), SCHED_FIFO, 5);
215 	DPRINTF(stderr, "Thread TB2: started\n");
216 	DPRINTF(stdout, "#EVENT %f Thread TB2 Started\n",
217 		seconds_read() - base_time);
218 
219 	boost_time.tv_sec = time(NULL) + *(time_t *) arg;
220 	boost_time.tv_nsec = 0;
221 
222 	t0 = seconds_read();
223 	rc = pthread_mutex_timedlock(&mutex2, &boost_time);
224 	t1 = seconds_read();
225 
226 	DPRINTF(stdout, "#EVENT %f Thread TB2 Waited on mutex2 for %.2f s\n",
227 		t1 - base_time, t1 - t0);
228 
229 	if (rc != ETIMEDOUT) {
230 		EPRINTF("FAIL: Thread TB2: lock mutex2 returned %d %s, "
231 			"slept %f", rc, strerror(rc), t1 - t0);
232 		exit(FAIL);
233 	}
234 	return NULL;
235 }
236 
main(int argc,char ** argv)237 int main(int argc, char **argv)
238 {
239 	cpus = sysconf(_SC_NPROCESSORS_ONLN);
240 	pthread_mutexattr_t mutex_attr;
241 	pthread_attr_t threadattr;
242 	pthread_t threads[cpus - 1];
243 	pthread_t threadsample, threadtp, threadtl, threadtb1, threadtb2;
244 
245 	time_t multiplier = 1;
246 	int i;
247 	int rc;
248 
249 	test_set_priority(pthread_self(), SCHED_FIFO, 8);
250 	base_time = seconds_read();
251 
252 	/* Initialize mutex1, mutex2 with PTHREAD_PRIO_INHERIT protocol */
253 	mutex_attr_init(&mutex_attr);
254 	mutex_init(&mutex1, &mutex_attr);
255 	mutex_init(&mutex2, &mutex_attr);
256 
257 	/* Initialize thread attr */
258 	threadattr_init(&threadattr);
259 
260 	/* Start the sample thread */
261 	DPRINTF(stderr, "Main Thread: Creating sample thread\n");
262 	rc = pthread_create(&threadsample, &threadattr, thread_sample, NULL);
263 	if (rc != 0) {
264 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
265 		exit(UNRESOLVED);
266 	}
267 
268 	/* Start the TF threads */
269 	DPRINTF(stderr, "Main Thread: Creating %d TF threads\n", cpus - 1);
270 	for (i = 0; i < cpus - 1; i++) {
271 		rc = pthread_create(&threads[i], &threadattr, thread_fn,
272 				    &tp[i + 2]);
273 		if (rc != 0) {
274 			EPRINTF("UNRESOLVED: pthread_create: %d %s",
275 				rc, strerror(rc));
276 			exit(UNRESOLVED);
277 		}
278 	}
279 	sleep(base_time + multiplier * 10 - seconds_read());
280 
281 	/* Start TP thread */
282 	DPRINTF(stderr, "Main Thread: Creating TP thread\n");
283 	rc = pthread_create(&threadtp, &threadattr, thread_fn, &tp[1]);
284 	if (rc != 0) {
285 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
286 		exit(UNRESOLVED);
287 	}
288 	sleep(base_time + multiplier * 20 - seconds_read());
289 
290 	/* Start TL thread */
291 	DPRINTF(stderr, "Main Thread: Creating TL thread\n");
292 	rc = pthread_create(&threadtl, &threadattr, thread_fn, &tp[0]);
293 	if (rc != 0) {
294 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
295 		exit(UNRESOLVED);
296 	}
297 	sleep(base_time + multiplier * 30 - seconds_read());
298 
299 	/* Start TB1 thread (the lowest priority thread) */
300 	time_t timeout = multiplier * 40;
301 	rc = pthread_create(&threadtb1, &threadattr, thread_tb1, &timeout);
302 	if (rc != 0) {
303 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
304 		exit(UNRESOLVED);
305 	}
306 	sleep(base_time + multiplier * 40 - seconds_read());
307 
308 	/* Start TB2 thread (boosting thread) */
309 	timeout = multiplier * 20;
310 	rc = pthread_create(&threadtb2, &threadattr, thread_tb2, &timeout);
311 	if (rc != 0) {
312 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
313 		exit(UNRESOLVED);
314 	}
315 	sleep(base_time + multiplier * 75 - seconds_read());
316 
317 	/* Stop TL thread */
318 	tp[0].stop = 1;
319 	sleep(base_time + multiplier * 85 - seconds_read());
320 
321 	/* Stop TP thread */
322 	tp[1].stop = 1;
323 	sleep(base_time + multiplier * 95 - seconds_read());
324 
325 	/* Stop TF threads */
326 	for (i = 2; i < cpus - 1; i++) {
327 		tp[i].stop = 1;
328 	}
329 
330 	/* Stop sampler */
331 	ts_stop = 1;
332 	DPRINTF(stderr, "Main Thread: stop sampler thread\n");
333 	return 0;
334 }
335