• 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. A TB thread with higher priority 4 is created and try
14  * to lock TL's mutex. A TP thread with priority 2 is created to reflect the
15  * priority change of TL. Main thread has the highest priority 6, which will
16  * control the running steps of those threads, including creating threads,
17  * stopping threads. There is another thread to collect the sample data
18  * with priority 5.
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 1 TP thread and do workload. The thread will keep running when
24  * 	TL is created.
25  * 3.	Create 1 TL thread to lock a mutex. TL will get a chance to run
26  *      when TP sleep a wee bit in between.
27  * 4.	Create 1 TB thread to lock the mutex. TL's priority will boost to
28  *  	TB's priority, which will cause TP having no chance to run.
29  * 5.	TL will unlock the mutex,  TL's priority will decrease, so TP and TL
30  * 	will keep working as before.
31  * 5.	Keep running for a while to let TL stabilize.
32  * 6.	Stop these threads.
33  *
34  * NOTE: Most of the code is ported from test-11 written by inkay.
35  */
36 
37 #warning "Contains Linux-isms that need fixing."
38 
39 #include <errno.h>
40 #include <pthread.h>
41 #include <sched.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <time.h>
46 #include <unistd.h>
47 #include "test.h"
48 #include "pitest.h"
49 
50 int cpus;
51 pthread_mutex_t mutex;
52 volatile int ts_stop = 0;
53 volatile double base_time;
54 volatile int unlock_mutex = 0;
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, 200, 2, SCHED_FIFO, "TP", 0, 0, 0, 0}, {
71 	2, 0, 0, 3, SCHED_FIFO, "TF", 1, 0, 0, 0}, {
72 	3, 0, 0, 3, SCHED_FIFO, "TF", 2, 0, 0, 0}, {
73 	4, 0, 0, 3, SCHED_FIFO, "TF", 3, 0, 0, 0}, {
74 	5, 0, 0, 3, SCHED_FIFO, "TF", 4, 0, 0, 0}, {
75 	6, 0, 0, 3, SCHED_FIFO, "TF", 5, 0, 0, 0}, {
76 	7, 0, 0, 3, SCHED_FIFO, "TF", 6, 0, 0, 0}
77 };
78 
79 volatile unsigned do_work_dummy;
do_work(unsigned granularity_top,volatile unsigned * progress)80 void do_work(unsigned granularity_top, volatile unsigned *progress)
81 {
82 	unsigned granularity_cnt, i;
83 	unsigned top = 5 * 1000 * 1000;
84 	unsigned dummy = do_work_dummy;
85 
86 	for (granularity_cnt = 0; granularity_cnt < granularity_top;
87 	     granularity_cnt++) {
88 		for (i = 0; i < top; i++)
89 			dummy = i | dummy;
90 		(*progress)++;
91 	}
92 	return;
93 }
94 
thread_fn(void * param)95 void *thread_fn(void *param)
96 {
97 	struct thread_param *tp = param;
98 	struct timespec ts;
99 	int rc;
100 	unsigned long mask = 1 << tp->cpu;
101 
102 	test_set_priority(pthread_self(), SCHED_FIFO, tp->priority);
103 #if __linux__
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 #endif
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 	while (!tp->stop) {
120 		do_work(5, &tp->progress);
121 		if (tp->sleep_ms == 0)
122 			continue;
123 		rc = nanosleep(&ts, NULL);
124 		if (rc < 0) {
125 			EPRINTF("UNRESOLVED: Thread %s %d: nanosleep returned "
126 				"%d %s", tp->name, tp->index, rc, strerror(rc));
127 			exit(UNRESOLVED);
128 		}
129 	}
130 
131 	DPRINTF(stdout, "#EVENT %f Thread %s stopped\n",
132 		seconds_read() - base_time, tp->name);
133 	return NULL;
134 }
135 
thread_tl(void * param)136 void *thread_tl(void *param)
137 {
138 	struct thread_param *tp = param;
139 	unsigned long mask = 1 << tp->cpu;
140 	int rc;
141 
142 	test_set_priority(pthread_self(), SCHED_FIFO, tp->priority);
143 #if __linux__
144 	rc = sched_setaffinity((pid_t) 0, sizeof(mask), &mask);
145 	if (rc < 0) {
146 		EPRINTF
147 		    ("UNRESOLVED: Thread %s index %d: Can't set affinity: %d %s",
148 		     tp->name, tp->index, rc, strerror(rc));
149 		exit(UNRESOLVED);
150 	}
151 #endif
152 
153 	DPRINTF(stdout, "#EVENT %f Thread TL started\n",
154 		seconds_read() - base_time);
155 	DPRINTF(stderr, "Thread %s index %d: started\n", tp->name, tp->index);
156 
157 	tp->progress = 0;
158 	pthread_mutex_lock(&mutex);
159 	while (!tp->stop) {
160 		do_work(5, &tp->progress);
161 		if (unlock_mutex == 1) {
162 			rc = pthread_mutex_unlock(&mutex);
163 			if (rc == 0) {
164 				unlock_mutex = 0;
165 				DPRINTF(stdout,
166 					"#EVENT %f TL unlock the mutex\n",
167 					seconds_read() - base_time);
168 			} else {
169 				EPRINTF
170 				    ("UNRESOLVED: TL failed to unlock mutex: %d %s",
171 				     rc, strerror(rc));
172 				exit(UNRESOLVED);
173 			}
174 		}
175 	}
176 
177 	DPRINTF(stdout, "#EVENT %f Thread TL stopped\n",
178 		seconds_read() - base_time);
179 	return NULL;
180 }
181 
thread_sample(void * arg)182 void *thread_sample(void *arg)
183 {
184 	char buffer[1024];
185 	struct timespec ts;
186 	double period = 300;
187 	size_t size;
188 	int i;
189 	int rc;
190 
191 	test_set_priority(pthread_self(), SCHED_FIFO, 5);
192 
193 	DPRINTF(stderr, "Thread Sampler: started\n");
194 	DPRINTF(stdout, "# COLUMNS %d Time TL TP ", 2 + cpus);
195 
196 	for (i = 0; i < (cpus - 1); i++)
197 		DPRINTF(stdout, "TF%d ", i);
198 	DPRINTF(stdout, "\n");
199 
200 	ts.tv_sec = 0;
201 	ts.tv_nsec = period * 1000 * 1000;
202 
203 	while (!ts_stop) {
204 		size =
205 		    snprintf(buffer, 1023, "%f ", seconds_read() - base_time);
206 		for (i = 0; i < cpus + 1; i++)
207 			size +=
208 			    snprintf(buffer + size, 1023 - size, "%u ",
209 				     tp[i].progress);
210 		DPRINTF(stdout, "%s\n", buffer);
211 		rc = nanosleep(&ts, NULL);
212 		if (rc < 0)
213 			EPRINTF("UNRESOLVED: Thread %s %d: nanosleep returned "
214 				"%d %s", tp->name, tp->index, rc, strerror(rc));
215 	}
216 	return NULL;
217 }
218 
thread_tb(void * arg)219 void *thread_tb(void *arg)
220 {
221 	int rc;
222 	struct timespec ts;
223 	ts.tv_sec = 2;
224 	ts.tv_nsec = 0;
225 
226 	test_set_priority(pthread_self(), SCHED_FIFO, 4);
227 	DPRINTF(stderr, "Thread TB: started\n");
228 	DPRINTF(stdout, "#EVENT %f Thread TB started,trying to lock\n",
229 		seconds_read() - base_time);
230 
231 	rc = pthread_mutex_lock(&mutex);
232 	if (rc != 0) {
233 		EPRINTF("UNRESOLVED: Thread TB: lock returned %d %s",
234 			rc, strerror(rc));
235 		exit(UNRESOLVED);
236 	}
237 	DPRINTF(stdout, "#EVENT %f Thread TB got lock\n",
238 		seconds_read() - base_time);
239 
240 	nanosleep(&ts, NULL);
241 
242 	rc = pthread_mutex_unlock(&mutex);
243 	if (rc != 0) {
244 		EPRINTF("UNRESOLVED: Thread TB: unlock returned %d %s",
245 			rc, strerror(rc));
246 		exit(UNRESOLVED);
247 	}
248 
249 	DPRINTF(stdout, "#EVENT %f Thread TB unlocked and stopped\n",
250 		seconds_read() - base_time);
251 
252 	return NULL;
253 }
254 
main(void)255 int main(void)
256 {
257 	cpus = sysconf(_SC_NPROCESSORS_ONLN);
258 	pthread_mutexattr_t mutex_attr;
259 	pthread_attr_t threadattr;
260 	pthread_t threads[cpus - 1], threadsample, threadtp, threadtl, threadtb;
261 	time_t multiplier = 1;
262 	int i;
263 	int rc;
264 
265 	test_set_priority(pthread_self(), SCHED_FIFO, 6);
266 	base_time = seconds_read();
267 
268 	/* Initialize a mutex with PTHREAD_PRIO_INHERIT protocol */
269 	mutex_attr_init(&mutex_attr);
270 	mutex_init(&mutex, &mutex_attr);
271 
272 	/* Initialize thread attr */
273 	threadattr_init(&threadattr);
274 
275 	/* Start the sample thread */
276 	DPRINTF(stderr, "Main Thread: Creating sample thread\n");
277 	rc = pthread_create(&threadsample, &threadattr, thread_sample, NULL);
278 	if (rc != 0) {
279 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
280 		exit(UNRESOLVED);
281 	}
282 	/* Start the TF threads */
283 	DPRINTF(stderr, "Main Thread: Creating %d TF threads\n", cpus - 1);
284 	for (i = 0; i < cpus - 1; i++) {
285 		rc = pthread_create(&threads[i], &threadattr, thread_fn,
286 				    &tp[i + 2]);
287 		if (rc != 0) {
288 			EPRINTF("UNRESOLVED: pthread_create: %d %s",
289 				rc, strerror(rc));
290 			exit(UNRESOLVED);
291 		}
292 	}
293 
294 	sleep(base_time + multiplier * 10 - seconds_read());
295 
296 	/* Start TP thread */
297 	DPRINTF(stderr, "Main Thread: Creating TP thread\n");
298 	rc = pthread_create(&threadtp, &threadattr, thread_fn, &tp[1]);
299 	if (rc != 0) {
300 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
301 		exit(UNRESOLVED);
302 	}
303 	sleep(base_time + multiplier * 20 - seconds_read());
304 
305 	/* Start TL thread */
306 	DPRINTF(stderr, "Main Thread: Creating TL thread\n");
307 	rc = pthread_create(&threadtl, &threadattr, thread_tl, &tp[0]);
308 	if (rc != 0) {
309 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
310 		exit(UNRESOLVED);
311 	}
312 	sleep(base_time + multiplier * 30 - seconds_read());
313 
314 	/* Start TB thread (boosting thread) */
315 	rc = pthread_create(&threadtb, &threadattr, thread_tb, NULL);
316 	if (rc != 0) {
317 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
318 		exit(UNRESOLVED);
319 	}
320 	sleep(base_time + multiplier * 40 - seconds_read());
321 	unlock_mutex = 1;
322 	sleep(base_time + multiplier * 50 - seconds_read());
323 
324 	/* Stop TL thread */
325 	tp[0].stop = 1;
326 	sleep(base_time + multiplier * 60 - seconds_read());
327 
328 	/* Stop TP thread */
329 	tp[1].stop = 1;
330 	sleep(base_time + multiplier * 70 - seconds_read());
331 
332 	/* Stop TF threads */
333 	for (i = 2; i < cpus - 1; i++) {
334 		tp[i].stop = 1;
335 	}
336 
337 	/* Stop sampler */
338 	ts_stop = 1;
339 	DPRINTF(stderr, "Main Thread: stop sampler thread\n");
340 	return 0;
341 }
342