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
18 * with 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. TL will unlock the mutex, TL's priority will decrease, so TP and TL
30 * will keep working as before.
31 * 5. Keep running for a while to let TL stabilize.
32 * 6. Stop these threads.
33 *
34 * NOTE: Most of the code is ported from test-11 written by inkay.
35 */
36
37 #warning "Contains Linux-isms that need fixing."
38
39 #include <errno.h>
40 #include <pthread.h>
41 #include <sched.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <time.h>
46 #include <unistd.h>
47 #include "test.h"
48 #include "pitest.h"
49
50 int cpus;
51 pthread_mutex_t mutex;
52 volatile int ts_stop = 0;
53 volatile double base_time;
54 volatile int unlock_mutex = 0;
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, 200, 2, SCHED_FIFO, "TP", 0, 0, 0, 0}, {
71 2, 0, 0, 3, SCHED_FIFO, "TF", 1, 0, 0, 0}, {
72 3, 0, 0, 3, SCHED_FIFO, "TF", 2, 0, 0, 0}, {
73 4, 0, 0, 3, SCHED_FIFO, "TF", 3, 0, 0, 0}, {
74 5, 0, 0, 3, SCHED_FIFO, "TF", 4, 0, 0, 0}, {
75 6, 0, 0, 3, SCHED_FIFO, "TF", 5, 0, 0, 0}, {
76 7, 0, 0, 3, SCHED_FIFO, "TF", 6, 0, 0, 0}
77 };
78
79 volatile unsigned do_work_dummy;
do_work(unsigned granularity_top,volatile unsigned * progress)80 void do_work(unsigned granularity_top, volatile unsigned *progress)
81 {
82 unsigned granularity_cnt, i;
83 unsigned top = 5 * 1000 * 1000;
84 unsigned dummy = do_work_dummy;
85
86 for (granularity_cnt = 0; granularity_cnt < granularity_top;
87 granularity_cnt++) {
88 for (i = 0; i < top; i++)
89 dummy = i | dummy;
90 (*progress)++;
91 }
92 return;
93 }
94
thread_fn(void * param)95 void *thread_fn(void *param)
96 {
97 struct thread_param *tp = param;
98 struct timespec ts;
99 int rc;
100 unsigned long mask = 1 << tp->cpu;
101
102 test_set_priority(pthread_self(), SCHED_FIFO, tp->priority);
103 #if __linux__
104 rc = sched_setaffinity(0, sizeof(mask), &mask);
105 if (rc < 0) {
106 EPRINTF("UNRESOLVED: Thread %s index %d: Can't set affinity: "
107 "%d %s", tp->name, tp->index, rc, strerror(rc));
108 exit(UNRESOLVED);
109 }
110 #endif
111
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
116 tp->progress = 0;
117 ts.tv_sec = 0;
118 ts.tv_nsec = tp->sleep_ms * 1000 * 1000;
119 while (!tp->stop) {
120 do_work(5, &tp->progress);
121 if (tp->sleep_ms == 0)
122 continue;
123 rc = nanosleep(&ts, NULL);
124 if (rc < 0) {
125 EPRINTF("UNRESOLVED: Thread %s %d: nanosleep returned "
126 "%d %s", tp->name, tp->index, rc, strerror(rc));
127 exit(UNRESOLVED);
128 }
129 }
130
131 DPRINTF(stdout, "#EVENT %f Thread %s stopped\n",
132 seconds_read() - base_time, tp->name);
133 return NULL;
134 }
135
thread_tl(void * param)136 void *thread_tl(void *param)
137 {
138 struct thread_param *tp = param;
139 unsigned long mask = 1 << tp->cpu;
140 int rc;
141
142 test_set_priority(pthread_self(), SCHED_FIFO, tp->priority);
143 #if __linux__
144 rc = sched_setaffinity((pid_t) 0, sizeof(mask), &mask);
145 if (rc < 0) {
146 EPRINTF
147 ("UNRESOLVED: Thread %s index %d: Can't set affinity: %d %s",
148 tp->name, tp->index, rc, strerror(rc));
149 exit(UNRESOLVED);
150 }
151 #endif
152
153 DPRINTF(stdout, "#EVENT %f Thread TL started\n",
154 seconds_read() - base_time);
155 DPRINTF(stderr, "Thread %s index %d: started\n", tp->name, tp->index);
156
157 tp->progress = 0;
158 pthread_mutex_lock(&mutex);
159 while (!tp->stop) {
160 do_work(5, &tp->progress);
161 if (unlock_mutex == 1) {
162 rc = pthread_mutex_unlock(&mutex);
163 if (rc == 0) {
164 unlock_mutex = 0;
165 DPRINTF(stdout,
166 "#EVENT %f TL unlock the mutex\n",
167 seconds_read() - base_time);
168 } else {
169 EPRINTF
170 ("UNRESOLVED: TL failed to unlock mutex: %d %s",
171 rc, strerror(rc));
172 exit(UNRESOLVED);
173 }
174 }
175 }
176
177 DPRINTF(stdout, "#EVENT %f Thread TL stopped\n",
178 seconds_read() - base_time);
179 return NULL;
180 }
181
thread_sample(void * arg)182 void *thread_sample(void *arg)
183 {
184 char buffer[1024];
185 struct timespec ts;
186 double period = 300;
187 size_t size;
188 int i;
189 int rc;
190
191 test_set_priority(pthread_self(), SCHED_FIFO, 5);
192
193 DPRINTF(stderr, "Thread Sampler: started\n");
194 DPRINTF(stdout, "# COLUMNS %d Time TL TP ", 2 + cpus);
195
196 for (i = 0; i < (cpus - 1); i++)
197 DPRINTF(stdout, "TF%d ", i);
198 DPRINTF(stdout, "\n");
199
200 ts.tv_sec = 0;
201 ts.tv_nsec = period * 1000 * 1000;
202
203 while (!ts_stop) {
204 size =
205 snprintf(buffer, 1023, "%f ", seconds_read() - base_time);
206 for (i = 0; i < cpus + 1; i++)
207 size +=
208 snprintf(buffer + size, 1023 - size, "%u ",
209 tp[i].progress);
210 DPRINTF(stdout, "%s\n", buffer);
211 rc = nanosleep(&ts, NULL);
212 if (rc < 0)
213 EPRINTF("UNRESOLVED: Thread %s %d: nanosleep returned "
214 "%d %s", tp->name, tp->index, rc, strerror(rc));
215 }
216 return NULL;
217 }
218
thread_tb(void * arg)219 void *thread_tb(void *arg)
220 {
221 int rc;
222 struct timespec ts;
223 ts.tv_sec = 2;
224 ts.tv_nsec = 0;
225
226 test_set_priority(pthread_self(), SCHED_FIFO, 4);
227 DPRINTF(stderr, "Thread TB: started\n");
228 DPRINTF(stdout, "#EVENT %f Thread TB started,trying to lock\n",
229 seconds_read() - base_time);
230
231 rc = pthread_mutex_lock(&mutex);
232 if (rc != 0) {
233 EPRINTF("UNRESOLVED: Thread TB: lock returned %d %s",
234 rc, strerror(rc));
235 exit(UNRESOLVED);
236 }
237 DPRINTF(stdout, "#EVENT %f Thread TB got lock\n",
238 seconds_read() - base_time);
239
240 nanosleep(&ts, NULL);
241
242 rc = pthread_mutex_unlock(&mutex);
243 if (rc != 0) {
244 EPRINTF("UNRESOLVED: Thread TB: unlock returned %d %s",
245 rc, strerror(rc));
246 exit(UNRESOLVED);
247 }
248
249 DPRINTF(stdout, "#EVENT %f Thread TB unlocked and stopped\n",
250 seconds_read() - base_time);
251
252 return NULL;
253 }
254
main(int argc,char ** argv)255 int main(int argc, char **argv)
256 {
257 cpus = sysconf(_SC_NPROCESSORS_ONLN);
258 pthread_mutexattr_t mutex_attr;
259 pthread_attr_t threadattr;
260 pthread_t threads[cpus - 1], threadsample, threadtp, threadtl, threadtb;
261 time_t multiplier = 1;
262 int i;
263 int rc;
264
265 test_set_priority(pthread_self(), SCHED_FIFO, 6);
266 base_time = seconds_read();
267
268 /* Initialize a mutex with PTHREAD_PRIO_INHERIT protocol */
269 mutex_attr_init(&mutex_attr);
270 mutex_init(&mutex, &mutex_attr);
271
272 /* Initialize thread attr */
273 threadattr_init(&threadattr);
274
275 /* Start the sample thread */
276 DPRINTF(stderr, "Main Thread: Creating sample thread\n");
277 rc = pthread_create(&threadsample, &threadattr, thread_sample, NULL);
278 if (rc != 0) {
279 EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
280 exit(UNRESOLVED);
281 }
282 /* Start the TF threads */
283 DPRINTF(stderr, "Main Thread: Creating %d TF threads\n", cpus - 1);
284 for (i = 0; i < cpus - 1; i++) {
285 rc = pthread_create(&threads[i], &threadattr, thread_fn,
286 &tp[i + 2]);
287 if (rc != 0) {
288 EPRINTF("UNRESOLVED: pthread_create: %d %s",
289 rc, strerror(rc));
290 exit(UNRESOLVED);
291 }
292 }
293
294 sleep(base_time + multiplier * 10 - seconds_read());
295
296 /* Start TP thread */
297 DPRINTF(stderr, "Main Thread: Creating TP thread\n");
298 rc = pthread_create(&threadtp, &threadattr, thread_fn, &tp[1]);
299 if (rc != 0) {
300 EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
301 exit(UNRESOLVED);
302 }
303 sleep(base_time + multiplier * 20 - seconds_read());
304
305 /* Start TL thread */
306 DPRINTF(stderr, "Main Thread: Creating TL thread\n");
307 rc = pthread_create(&threadtl, &threadattr, thread_tl, &tp[0]);
308 if (rc != 0) {
309 EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
310 exit(UNRESOLVED);
311 }
312 sleep(base_time + multiplier * 30 - seconds_read());
313
314 /* Start TB thread (boosting thread) */
315 rc = pthread_create(&threadtb, &threadattr, thread_tb, NULL);
316 if (rc != 0) {
317 EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
318 exit(UNRESOLVED);
319 }
320 sleep(base_time + multiplier * 40 - seconds_read());
321 unlock_mutex = 1;
322 sleep(base_time + multiplier * 50 - seconds_read());
323
324 /* Stop TL thread */
325 tp[0].stop = 1;
326 sleep(base_time + multiplier * 60 - seconds_read());
327
328 /* Stop TP thread */
329 tp[1].stop = 1;
330 sleep(base_time + multiplier * 70 - seconds_read());
331
332 /* Stop TF threads */
333 for (i = 2; i < cpus - 1; i++) {
334 tp[i].stop = 1;
335 }
336
337 /* Stop sampler */
338 ts_stop = 1;
339 DPRINTF(stderr, "Main Thread: stop sampler thread\n");
340 return 0;
341 }
342