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; 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 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 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 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 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 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