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