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