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(int argc,char ** argv)267 int main(int argc, char **argv)
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