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