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