• 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 3. A
12  * TL thread with lower priority 1 is created, which locks 2 mutex and
13  * does workload. A TB1 thread with high priority 4 is created and try
14  * to lock mutex1 of TL. A TB2 thread with high priority 6 is created and
15  * try to lock mutex2 of TL. TL's priority should boost to TB2's priority.
16  * There are another 2 threads TP1 and TP2, which are used to check the
17  * priority change of TL, P(TP1)<P(TB1)<P(TP2)<P(TB2), P(TH) stands for
18  * the priority of TH thread. Main thread has the highest priority 8,
19  * which will control the running steps of those threads, including
20  * creating threads, stopping threads. There is another thread to collect
21  * the sample data with priority 7.
22  *
23  * Steps:
24  * 1.	Create n TF threads, n is equal to processors number minus one. TF
25  * 	will do workload.
26  * 2.	Create 2 TP threads: TP1 and TP2 and do workload. The 2 threads
27  * 	will keep running when TL is created.
28  * 3.	Create 1 TL thread to lock 2 mutex: mutex1 and mutex2. TL will get
29  * 	a chance to run when TP sleep a wee bit in between.
30  * 4.	Create 1 TB1 thread to lock mutex1. TL's priority will boost to
31  *  	TB1's priority, which will cause TP1 having no chance to run.
32  * 5.	Create 1 TB2 thread to lock mutex2. TL's priority will boost to
33  *  	TB2's priority, which will cause TP1, TP2 having no chance to run.
34  * 6.	Stop these threads.
35  *
36  */
37 
38 #warning "Contains Linux-isms that need fixing."
39 
40 #include <pthread.h>
41 #include <stdio.h>
42 #include <unistd.h>
43 #include <string.h>
44 #include <stdlib.h>
45 #include <time.h>
46 #include <sched.h>
47 #include <errno.h>
48 #include "test.h"
49 #include "pitest.h"
50 
51 int cpus;
52 pthread_mutex_t mutex1;
53 pthread_mutex_t mutex2;
54 volatile int ts_stop = 0;
55 volatile double base_time;
56 
57 struct thread_param {
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, 500, 2, SCHED_FIFO, "TP1", 0, 0, 0, 0}, {
72 	1, 0, 500, 5, SCHED_FIFO, "TP2", 0, 0, 0, 0}, {
73 	2, 0, 0, 3, SCHED_FIFO, "TF", 1, 0, 0, 0}, {
74 	3, 0, 0, 3, SCHED_FIFO, "TF", 2, 0, 0, 0}, {
75 	4, 0, 0, 3, SCHED_FIFO, "TF", 3, 0, 0, 0}, {
76 	5, 0, 0, 3, SCHED_FIFO, "TF", 4, 0, 0, 0}, {
77 	6, 0, 0, 3, SCHED_FIFO, "TF", 5, 0, 0, 0}, {
78 	7, 0, 0, 3, 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 	while (!tp->stop) {
122 		do_work(5, &tp->progress);
123 		if (tp->sleep_ms == 0)
124 			continue;
125 		rc = nanosleep(&ts, NULL);
126 		if (rc < 0) {
127 			EPRINTF("UNRESOLVED: Thread %s %d: nanosleep returned "
128 				"%d %s", tp->name, tp->index, rc, strerror(rc));
129 			exit(UNRESOLVED);
130 		}
131 	}
132 
133 	DPRINTF(stdout, "#EVENT %f Thread %s Stopped\n",
134 		seconds_read() - base_time, tp->name);
135 	return NULL;
136 }
137 
thread_tl(void * param)138 void *thread_tl(void *param)
139 {
140 	struct thread_param *tp = param;
141 	unsigned long mask = 1 << tp->cpu;
142 	int rc;
143 
144 #if __linux__
145 	rc = sched_setaffinity((pid_t) 0, sizeof(mask), &mask);
146 	if (rc < 0) {
147 		EPRINTF
148 		    ("UNRESOLVED: Thread %s index %d: Can't set affinity: %d %s",
149 		     tp->name, tp->index, rc, strerror(rc));
150 		exit(UNRESOLVED);
151 	}
152 #endif
153 
154 	test_set_priority(pthread_self(), SCHED_FIFO, tp->priority);
155 	DPRINTF(stdout, "#EVENT %f Thread TL Started\n",
156 		seconds_read() - base_time);
157 	DPRINTF(stderr, "Thread %s index %d: started\n", tp->name, tp->index);
158 
159 	tp->progress = 0;
160 	pthread_mutex_lock(&mutex1);
161 	pthread_mutex_lock(&mutex2);
162 	while (!tp->stop) {
163 		do_work(5, &tp->progress);
164 	}
165 
166 	pthread_mutex_unlock(&mutex1);
167 	pthread_mutex_unlock(&mutex2);
168 	DPRINTF(stdout, "#EVENT %f Thread TL Stopped\n",
169 		seconds_read() - base_time);
170 	return NULL;
171 }
172 
thread_sample(void * arg)173 void *thread_sample(void *arg)
174 {
175 	char buffer[1024];
176 	struct timespec ts;
177 	double period = 300;
178 	double newtime;
179 	size_t size;
180 	int i;
181 	int rc;
182 
183 	test_set_priority(pthread_self(), SCHED_FIFO, 7);
184 	DPRINTF(stderr, "Thread Sampler: started\n");
185 
186 	DPRINTF(stdout, "# COLUMNS %d Time TL TP1 TP2  ", 3 + cpus);
187 
188 	for (i = 0; i < (cpus - 1); i++)
189 		DPRINTF(stdout, "TF%d ", i);
190 	DPRINTF(stdout, "\n");
191 
192 	ts.tv_sec = 0;
193 	ts.tv_nsec = period * 1000 * 1000;
194 	while (!ts_stop) {
195 		newtime = seconds_read();
196 		size = snprintf(buffer, 1023, "%f ", newtime - base_time);
197 		for (i = 0; i < cpus + 2; i++)
198 			size +=
199 			    snprintf(buffer + size, 1023 - size, "%u ",
200 				     tp[i].progress);
201 		DPRINTF(stdout, "%s\n", buffer);
202 		rc = nanosleep(&ts, NULL);
203 		if (rc < 0)
204 			EPRINTF("UNRESOLVED: Thread %s %d: nanosleep returned "
205 				"%d %s", tp->name, tp->index, rc, strerror(rc));
206 	}
207 	return NULL;
208 }
209 
thread_tb1(void * arg)210 void *thread_tb1(void *arg)
211 {
212 	struct timespec boost_time;
213 	double t0, t1;
214 	int rc;
215 
216 	test_set_priority(pthread_self(), SCHED_FIFO, 4);
217 	DPRINTF(stderr, "Thread TB1: started\n");
218 	DPRINTF(stdout, "#EVENT %f Thread TB1 Started\n",
219 		seconds_read() - base_time);
220 
221 	boost_time.tv_sec = time(NULL) + *(time_t *) arg;
222 	boost_time.tv_nsec = 0;
223 
224 	t0 = seconds_read();
225 	rc = pthread_mutex_timedlock(&mutex1, &boost_time);
226 	t1 = seconds_read();
227 
228 	DPRINTF(stdout, "#EVENT %f Thread TB1 Waited for %.2f s\n",
229 		t1 - base_time, t1 - t0);
230 	if (rc != ETIMEDOUT) {
231 		EPRINTF("FAIL: Thread TB1: lock returned %d %s, "
232 			"slept %f", rc, strerror(rc), t1 - t0);
233 		exit(FAIL);
234 	}
235 	return NULL;
236 }
237 
thread_tb2(void * arg)238 void *thread_tb2(void *arg)
239 {
240 	struct timespec boost_time;
241 	double t0, t1;
242 	int rc;
243 
244 	test_set_priority(pthread_self(), SCHED_FIFO, 6);
245 	DPRINTF(stderr, "Thread TB2: started\n");
246 	DPRINTF(stdout, "#EVENT %f Thread TB2 Started\n",
247 		seconds_read() - base_time);
248 
249 	boost_time.tv_sec = time(NULL) + *(time_t *) arg;
250 	boost_time.tv_nsec = 0;
251 	t0 = seconds_read();
252 	rc = pthread_mutex_timedlock(&mutex2, &boost_time);
253 	t1 = seconds_read();
254 
255 	DPRINTF(stdout, "#EVENT %f Thread TB2 waited %.2f s\n",
256 		t1 - base_time, t1 - t0);
257 
258 	if (rc != ETIMEDOUT) {
259 		EPRINTF("FAIL: Thread TB2: lock returned %d %s, "
260 			"slept %f", rc, strerror(rc), t1 - t0);
261 		exit(FAIL);
262 	}
263 
264 	return NULL;
265 }
266 
main(void)267 int main(void)
268 {
269 	cpus = sysconf(_SC_NPROCESSORS_ONLN);
270 	pthread_mutexattr_t mutex_attr;
271 	pthread_attr_t threadattr;
272 	pthread_t threads[cpus - 1];
273 	pthread_t threadsample, threadtp, threadtl, threadtb1, threadtb2;
274 
275 	time_t multiplier = 1;
276 	int i;
277 	int rc;
278 
279 	test_set_priority(pthread_self(), SCHED_FIFO, 8);
280 	base_time = seconds_read();
281 
282 	/* Initialize mutex1, mutex2 with PTHREAD_PRIO_INHERIT protocol */
283 	mutex_attr_init(&mutex_attr);
284 	mutex_init(&mutex1, &mutex_attr);
285 	mutex_init(&mutex2, &mutex_attr);
286 
287 	/* Initialize thread attr */
288 	threadattr_init(&threadattr);
289 
290 	/* Start the sample thread */
291 	DPRINTF(stderr, "Main Thread: Creating sample thread\n");
292 	rc = pthread_create(&threadsample, &threadattr, thread_sample, NULL);
293 	if (rc != 0) {
294 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
295 		exit(UNRESOLVED);
296 	}
297 
298 	/* Start the TF threads */
299 	DPRINTF(stderr, "Main Thread: Creating %d TF threads\n", cpus - 1);
300 	for (i = 0; i < cpus - 1; i++) {
301 		rc = pthread_create(&threads[i], &threadattr, thread_fn,
302 				    &tp[i + 3]);
303 		if (rc != 0) {
304 			EPRINTF("UNRESOLVED: pthread_create: %d %s",
305 				rc, strerror(rc));
306 			exit(UNRESOLVED);
307 		}
308 	}
309 	sleep(base_time + multiplier * 10 - seconds_read());
310 
311 	/* Start TP1, TP2 thread */
312 	DPRINTF(stderr, "Main Thread: Creating TP1, TP2 thread\n");
313 	for (i = 1; i <= 2; i++) {
314 		rc = pthread_create(&threadtp, &threadattr, thread_fn, &tp[i]);
315 		if (rc != 0) {
316 			EPRINTF("UNRESOLVED: pthread_create: %d %s",
317 				rc, strerror(rc));
318 			exit(UNRESOLVED);
319 		}
320 	}
321 	sleep(base_time + multiplier * 20 - seconds_read());
322 
323 	/* Start TL thread */
324 	DPRINTF(stderr, "Main Thread: Creating TL thread\n");
325 	rc = pthread_create(&threadtl, &threadattr, thread_tl, &tp[0]);
326 	if (rc != 0) {
327 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
328 		exit(UNRESOLVED);
329 	}
330 	sleep(base_time + multiplier * 30 - seconds_read());
331 
332 	/* Start TB1 thread (boosting thread) */
333 	time_t timeout = multiplier * 20;
334 	rc = pthread_create(&threadtb1, &threadattr, thread_tb1, &timeout);
335 	if (rc != 0) {
336 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
337 		exit(UNRESOLVED);
338 	}
339 	sleep(base_time + multiplier * 60 - seconds_read());
340 
341 	/* Start TB2 thread (boosting thread) */
342 	rc = pthread_create(&threadtb2, &threadattr, thread_tb2, &timeout);
343 	if (rc != 0) {
344 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
345 		exit(UNRESOLVED);
346 	}
347 	sleep(base_time + multiplier * 90 - seconds_read());
348 
349 	/* Stop TL thread */
350 	tp[0].stop = 1;
351 	sleep(base_time + multiplier * 100 - seconds_read());
352 
353 	/* Stop TP thread */
354 	tp[1].stop = 1;
355 	sleep(base_time + multiplier * 110 - seconds_read());
356 
357 	tp[2].stop = 1;
358 	sleep(base_time + multiplier * 120 - seconds_read());
359 
360 	/* Stop TF threads */
361 	for (i = 2; i < cpus - 1; i++) {
362 		tp[i].stop = 1;
363 	}
364 
365 	/* Stop sampler */
366 	ts_stop = 1;
367 	DPRINTF(stderr, "Main Thread: stop sampler thread\n");
368 	return 0;
369 }
370