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