• 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 with
18  * 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.	Set TB's prioirty to 1, TL's priority will decrease. So TP and TL
30  * 	will keep working as before.
31  * 6.	Stop these threads.
32  *
33  * NOTE: Most of the code is ported from test-11 written by inkay.
34  */
35 
36 #warning "Contains Linux-isms that need fixing."
37 
38 #include <errno.h>
39 #include <pthread.h>
40 #include <sched.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <time.h>
45 #include <unistd.h>
46 #include "test.h"
47 #include "pitest.h"
48 
49 int cpus;
50 pthread_mutex_t mutex;
51 volatile int ts_stop = 0;
52 volatile double base_time;
53 
54 struct thread_param {
55 	int index;
56 	volatile int stop;
57 	int sleep_ms;
58 	int priority;
59 	int policy;
60 	const char *name;
61 	int cpu;
62 	volatile unsigned futex;
63 	volatile unsigned should_stall;
64 	volatile unsigned progress;
65 } tp[] = {
66 	{
67 	0, 0, 0, 1, SCHED_FIFO, "TL", 0, 0, 0, 0}, {
68 	1, 0, 200, 2, SCHED_FIFO, "TP", 0, 0, 0, 0}, {
69 	2, 0, 0, 3, SCHED_FIFO, "TF", 1, 0, 0, 0}, {
70 	3, 0, 0, 3, SCHED_FIFO, "TF", 2, 0, 0, 0}, {
71 	4, 0, 0, 3, SCHED_FIFO, "TF", 3, 0, 0, 0}, {
72 	5, 0, 0, 3, SCHED_FIFO, "TF", 4, 0, 0, 0}, {
73 	6, 0, 0, 3, SCHED_FIFO, "TF", 5, 0, 0, 0}, {
74 	7, 0, 0, 3, SCHED_FIFO, "TF", 6, 0, 0, 0}
75 };
76 
77 volatile unsigned do_work_dummy;
do_work(unsigned granularity_top,volatile unsigned * progress)78 void do_work(unsigned granularity_top, volatile unsigned *progress)
79 {
80 	unsigned granularity_cnt, i;
81 	unsigned top = 5 * 1000 * 1000;
82 	unsigned dummy = do_work_dummy;
83 
84 	for (granularity_cnt = 0; granularity_cnt < granularity_top;
85 	     granularity_cnt++) {
86 		for (i = 0; i < top; i++)
87 			dummy = i | dummy;
88 		(*progress)++;
89 	}
90 	return;
91 }
92 
thread_fn(void * param)93 void *thread_fn(void *param)
94 {
95 	struct thread_param *tp = param;
96 	struct timespec ts;
97 	int rc;
98 	unsigned long mask = 1 << tp->cpu;
99 
100 #if __linux__
101 	rc = sched_setaffinity(0, sizeof(mask), &mask);
102 	if (rc < 0) {
103 		EPRINTF("UNRESOLVED: Thread %s index %d: Can't set affinity: "
104 			"%d %s", tp->name, tp->index, rc, strerror(rc));
105 		exit(UNRESOLVED);
106 	}
107 #endif
108 	test_set_priority(pthread_self(), SCHED_FIFO, tp->priority);
109 	DPRINTF(stderr, "Thread %s index %d: started\n", tp->name, tp->index);
110 	DPRINTF(stdout, "#EVENT %f Thread %s Started\n",
111 		seconds_read() - base_time, tp->name);
112 
113 	tp->progress = 0;
114 	ts.tv_sec = 0;
115 	ts.tv_nsec = tp->sleep_ms * 1000 * 1000;
116 	while (!tp->stop) {
117 		do_work(5, &tp->progress);
118 		if (tp->sleep_ms == 0)
119 			continue;
120 		rc = nanosleep(&ts, NULL);
121 		if (rc < 0) {
122 			EPRINTF("UNRESOLVED: Thread %s %d: nanosleep returned "
123 				"%d %s", tp->name, tp->index, rc, strerror(rc));
124 			exit(UNRESOLVED);
125 		}
126 	}
127 
128 	DPRINTF(stdout, "#EVENT %f Thread %s Started\n",
129 		seconds_read() - base_time, tp->name);
130 	return NULL;
131 }
132 
thread_tl(void * param)133 void *thread_tl(void *param)
134 {
135 	struct thread_param *tp = param;
136 	unsigned long mask = 1 << tp->cpu;
137 	int rc;
138 
139 #if __linux__
140 	rc = sched_setaffinity((pid_t) 0, sizeof(mask), &mask);
141 	if (rc < 0) {
142 		EPRINTF
143 		    ("UNRESOLVED: Thread %s index %d: Can't set affinity: %d %s",
144 		     tp->name, tp->index, rc, strerror(rc));
145 		exit(UNRESOLVED);
146 	}
147 #endif
148 
149 	test_set_priority(pthread_self(), SCHED_FIFO, tp->priority);
150 
151 	DPRINTF(stderr, "Thread %s index %d: started\n", tp->name, tp->index);
152 	DPRINTF(stdout, "#EVENT %f Thread %s Started\n",
153 		seconds_read() - base_time, tp->name);
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 %s Stopted\n",
161 		seconds_read() - base_time, tp->name);
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 = 250;
170 	size_t size;
171 	int i;
172 	int rc;
173 
174 	test_set_priority(pthread_self(), SCHED_FIFO, 5);
175 	DPRINTF(stderr, "Thread Sampler: started\n");
176 	DPRINTF(stdout, "# COLUMNS %d Time TP TL ", 2 + cpus);
177 	for (i = 0; i < (cpus - 1); i++)
178 		DPRINTF(stdout, "TF%d ", i);
179 	DPRINTF(stdout, "\n");
180 	ts.tv_sec = 0;
181 	ts.tv_nsec = period * 1000 * 1000;
182 
183 	while (!ts_stop) {
184 		size =
185 		    snprintf(buffer, 1023, "%f ", seconds_read() - base_time);
186 		for (i = 0; i < cpus + 1; 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_tb(void * arg)199 void *thread_tb(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 	DPRINTF(stderr, "Thread TB: started\n");
207 
208 	DPRINTF(stdout, "#EVENT %f TB Started, waiting for mutex for %lu s\n",
209 		seconds_read() - base_time, *(time_t *) arg);
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 TB Thread Waited for %.2f s\n",
218 		seconds_read() - base_time, t1 - t0);
219 
220 	if (rc != ETIMEDOUT && rc != 0) {
221 		EPRINTF("FAIL: Thread TB: lock returned %d %s, "
222 			"slept %f", rc, strerror(rc), t1 - t0);
223 		exit(FAIL);
224 	}
225 
226 	DPRINTF(stdout, "#EVENT %f TB Stopped\n", seconds_read() - base_time);
227 	return NULL;
228 }
229 
main(int argc,char ** argv)230 int main(int argc, char **argv)
231 {
232 	cpus = sysconf(_SC_NPROCESSORS_ONLN);
233 	pthread_mutexattr_t mutex_attr;
234 	pthread_attr_t threadattr;
235 	pthread_t threads[cpus - 1], threadsample, threadtp, threadtl, threadtb;
236 
237 	time_t multiplier = 1;
238 	int i;
239 	int rc;
240 
241 	test_set_priority(pthread_self(), SCHED_FIFO, 6);
242 	base_time = seconds_read();
243 
244 	/* Initialize a mutex with PTHREAD_PRIO_INHERIT protocol */
245 	mutex_attr_init(&mutex_attr);
246 	mutex_init(&mutex, &mutex_attr);
247 
248 	/* Initialize thread attr */
249 	threadattr_init(&threadattr);
250 
251 	/* Start the sample thread */
252 	DPRINTF(stderr, "Main Thread: Creating sample thread\n");
253 	rc = pthread_create(&threadsample, &threadattr, thread_sample, NULL);
254 	if (rc != 0) {
255 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
256 		exit(UNRESOLVED);
257 	}
258 
259 	/* Start the TF threads */
260 	DPRINTF(stderr, "Main Thread: Creating %d TF threads\n", cpus - 1);
261 	for (i = 0; i < cpus - 1; i++) {
262 		rc = pthread_create(&threads[i], &threadattr, thread_fn,
263 				    &tp[i + 2]);
264 		if (rc != 0) {
265 			EPRINTF("UNRESOLVED: pthread_create: %d %s",
266 				rc, strerror(rc));
267 			exit(UNRESOLVED);
268 		}
269 	}
270 
271 	sleep(base_time + multiplier * 10 - seconds_read());
272 
273 	/* Start TP thread */
274 	DPRINTF(stderr, "Main Thread: Creating TP thread\n");
275 	rc = pthread_create(&threadtp, &threadattr, thread_fn, &tp[1]);
276 	if (rc != 0) {
277 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
278 		exit(UNRESOLVED);
279 	}
280 	sleep(base_time + multiplier * 20 - seconds_read());
281 
282 	/* Start TL thread */
283 	DPRINTF(stderr, "Main Thread: Creating TL thread\n");
284 	rc = pthread_create(&threadtl, &threadattr, thread_tl, &tp[0]);
285 	if (rc != 0) {
286 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
287 		exit(UNRESOLVED);
288 	}
289 	sleep(base_time + multiplier * 30 - seconds_read());
290 
291 	/* Start TB thread (boosting thread) */
292 	unsigned long timeout = multiplier * 20;
293 	rc = pthread_create(&threadtb, &threadattr, thread_tb, &timeout);
294 	if (rc != 0) {
295 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
296 		exit(UNRESOLVED);
297 	}
298 	sleep(base_time + multiplier * 40 - seconds_read());
299 
300 	/* Decrease TB's priority */
301 	DPRINTF(stderr, "Main Thread: decrease TB's priority to 1\n");
302 	test_set_priority(threadtb, SCHED_FIFO, 1);
303 	DPRINTF(stdout, "#EVENT %f TB's priority decreased\n",
304 		seconds_read() - base_time);
305 	sleep(base_time + multiplier * 60 - seconds_read());
306 
307 	/* Stop TL thread */
308 	tp[0].stop = 1;
309 	sleep(base_time + multiplier * 70 - seconds_read());
310 
311 	/* Stop TP thread */
312 	tp[1].stop = 1;
313 	sleep(base_time + multiplier * 80 - seconds_read());
314 
315 	/* Stop TF threads */
316 	for (i = 2; i < cpus - 1; i++) {
317 		tp[i].stop = 1;
318 	}
319 
320 	/* Stop sampler */
321 	ts_stop = 1;
322 	DPRINTF(stderr, "Main Thread: stop sampler thread\n");
323 	return 0;
324 }
325