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 4. A 12 * TL thread with priority 1 is created, which locks mutex1 and 13 * does workload. A TB1 thread with higher priority 2 is created and try 14 * to lock mutex1 of TL, TB1 will also lock another mutex mutex2. A TB2 thread 15 * with high priority 5 is created and try to lock mutex2 of TB1. Then TB's 16 * priority will boost to TB2's, and TL's priority will boost to TB1's. 17 * There are another 1 thread TP, which is used to check the 18 * priority change of TL, P(TB1)<P(TL)<P(TP)<P(TB2), P(TH) stands for 19 * the priority of TH thread. Main thread has the highest priority 8, 20 * which will control the running steps of those threads, including 21 * creating threads, stopping threads. There is another thread to collect 22 * the sample data with priority 7. 23 * 24 * Steps: 25 * 1. Create n TF threads, n is equal to processors number minus one. TF 26 * will do workload. 27 * 2. Create 1 TP threads and do workload. The thread 28 * will keep running when TL is created. 29 * 3. Create 1 TL thread to lock mutex1. TL will get a chance to 30 * run when TP sleep a wee bit in between. 31 * 4. Create 1 TB1 thread to lock mutex2 and try to lock mutex1, TL's priority will 32 * be boosted to TB1 33 * 5. Create 1 TB2 thread to lock mutex2. TB1's priority will boost to 34 * TB2's priority, then TL's priority will boost to TB1's new priority. 35 * 6. Stop these threads. 36 * 37 */ 38 39#include <pthread.h> 40#include <stdio.h> 41#include <unistd.h> 42#include <string.h> 43#include <stdlib.h> 44#include <time.h> 45#include <sched.h> 46#include <errno.h> 47#include "test.h" 48#include "pitest.h" 49 50int cpus; 51pthread_mutex_t mutex1; 52pthread_mutex_t mutex2; 53volatile int ts_stop = 0; 54volatile double base_time; 55 56struct thread_param 57{ 58 int index; 59 volatile int stop; 60 int sleep_ms; 61 int priority; 62 int policy; 63 const char *name; 64 int cpu; 65 volatile unsigned futex; 66 volatile unsigned should_stall; 67 volatile unsigned progress; 68} tp[] = 69{ 70 { 0, 0, 0, 1, SCHED_FIFO, "TL", 0, 0, 0, 0 }, 71 { 1, 0, 100, 3, SCHED_FIFO, "TP", 0, 0, 0, 0 }, 72 { 2, 0, 0, 4, SCHED_FIFO, "TF", 1, 0, 0, 0 }, 73 { 3, 0, 0, 4, SCHED_FIFO, "TF", 2, 0, 0, 0 }, 74 { 4, 0, 0, 4, SCHED_FIFO, "TF", 3, 0, 0, 0 }, 75 { 5, 0, 0, 4, SCHED_FIFO, "TF", 4, 0, 0, 0 }, 76 { 6, 0, 0, 4, SCHED_FIFO, "TF", 5, 0, 0, 0 }, 77 { 7, 0, 0, 4, SCHED_FIFO, "TF", 6, 0, 0, 0 } 78}; 79 80volatile unsigned do_work_dummy; 81void 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 { 90 for (i = 0; i < top; i++) 91 dummy = i | dummy; 92 (*progress)++; 93 } 94 return; 95} 96 97void *thread_fn(void *param) 98{ 99 struct thread_param *tp = param; 100 struct timespec ts; 101 int rc; 102 unsigned long mask = 1 << tp->cpu; 103 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 test_set_priority(pthread_self(),SCHED_FIFO, tp->priority); 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 if (tp->index == 0) 120 pthread_mutex_lock(&mutex1); 121 while (!tp->stop) 122 { 123 do_work(5, &tp->progress); 124 if (tp->sleep_ms == 0) 125 continue; 126 rc = nanosleep(&ts, NULL); 127 if (rc < 0) { 128 EPRINTF("UNRESOLVED: Thread %s %d: nanosleep returned " 129 "%d %s", tp->name, tp->index, rc, strerror(rc)); 130 exit(UNRESOLVED); 131 } 132 } 133 if (tp->index == 0) 134 pthread_mutex_unlock(&mutex1); 135 136 DPRINTF(stdout, "#EVENT %f Thread %s Stopped\n", 137 seconds_read() - base_time, tp->name); 138 return NULL; 139} 140 141void *thread_sample(void *arg) 142{ 143 char buffer[1024]; 144 struct timespec ts; 145 double period = 300; 146 double newtime; 147 size_t size; 148 int i; 149 int rc; 150 151 test_set_priority(pthread_self(),SCHED_FIFO, 6); 152 DPRINTF(stderr,"Thread Sampler: started\n"); 153 DPRINTF(stdout, "# COLUMNS %d Time TL TP ", 2 + cpus); 154 for (i = 0; i < (cpus - 1); i++) 155 DPRINTF(stdout, "TF%d ", i); 156 DPRINTF(stdout, "\n"); 157 ts.tv_sec = 0; 158 ts.tv_nsec = period * 1000 * 1000; 159 while (!ts_stop) 160 { 161 newtime = seconds_read(); 162 size = snprintf(buffer, 1023, "%f ", newtime - base_time); 163 for (i = 0; i < cpus + 1; i++) 164 size += snprintf(buffer + size, 1023 - size, "%u ", tp[i].progress); 165 DPRINTF(stdout,"%s\n", buffer); 166 rc = nanosleep(&ts, NULL); 167 if (rc < 0) 168 EPRINTF("UNRESOLVED: Thread %s %d: nanosleep returned " 169 "%d %s", tp->name, tp->index, rc, strerror(rc)); 170 } 171 return NULL; 172} 173 174void *thread_tb1(void *arg) 175{ 176 unsigned long timeoutsec; 177 struct timespec boost_time; 178 double t0, t1; 179 int rc; 180 181 test_set_priority(pthread_self(),SCHED_FIFO, 2); 182 DPRINTF(stderr,"Thread TB1: started\n"); 183 DPRINTF(stdout, "#EVENT %f Thread TB1 Started\n", 184 seconds_read() - base_time); 185 186 pthread_mutex_lock(&mutex2); 187 188 timeoutsec = *(unsigned long*) arg; 189 boost_time.tv_sec = time(NULL) + (time_t)timeoutsec; 190 boost_time.tv_nsec = 0; 191 t0 = seconds_read(); 192 rc = pthread_mutex_timedlock(&mutex1, &boost_time); 193 t1 = seconds_read(); 194 195 DPRINTF(stdout, "#EVENT %f TB1 Waited on mutex1 for %.2f s\n", 196 t1 - base_time, t1 - t0); 197 198 if (rc != ETIMEDOUT) { 199 EPRINTF("FAIL: Thread TB1: lock returned %d %s, " 200 "slept %f", rc, strerror(rc), t1 - t0); 201 exit(FAIL); 202 } 203 204 pthread_mutex_unlock(&mutex2); 205 return NULL; 206} 207 208 209void *thread_tb2(void *arg) 210{ 211 unsigned long timeoutsec; 212 struct timespec boost_time; 213 double t0, t1; 214 int rc; 215 216 test_set_priority(pthread_self(),SCHED_FIFO, 5); 217 DPRINTF(stderr,"Thread TB2: started\n"); 218 DPRINTF(stdout, "#EVENT %f Thread TB2 Started\n", 219 seconds_read() - base_time); 220 221 timeoutsec = *(unsigned long*) arg; 222 boost_time.tv_sec = time(NULL) + (time_t)timeoutsec; 223 boost_time.tv_nsec = 0; 224 225 t0 = seconds_read(); 226 rc = pthread_mutex_timedlock(&mutex2, &boost_time); 227 t1 = seconds_read(); 228 229 DPRINTF(stdout, "#EVENT %f Thread TB2 Waited on mutex2 for %.2f s\n", 230 t1 - base_time, t1 - t0); 231 232 if (rc != ETIMEDOUT) { 233 EPRINTF("FAIL: Thread TB2: lock mutex2 returned %d %s, " 234 "slept %f", rc, strerror(rc), t1 - t0); 235 exit(FAIL); 236 } 237 return NULL; 238} 239 240int main(int argc, char **argv) 241{ 242 pthread_mutexattr_t mutex_attr; 243 pthread_attr_t threadattr; 244 pthread_t threads[cpus - 1]; 245 pthread_t threadsample, threadtp, threadtl, threadtb1, threadtb2; 246 247 int multiplier = 1; 248 int i; 249 int rc; 250 251 test_set_priority(pthread_self(),SCHED_FIFO, 8); 252 base_time = seconds_read(); 253 cpus = sysconf(_SC_NPROCESSORS_ONLN); 254 255 /* Initialize mutex1, mutex2 with PTHREAD_PRIO_INHERIT protocol */ 256 mutex_attr_init(&mutex_attr); 257 mutex_init(&mutex1, &mutex_attr); 258 mutex_init(&mutex2, &mutex_attr); 259 260 /* Initialize thread attr */ 261 threadattr_init(&threadattr); 262 263 /* Start the sample thread */ 264 DPRINTF(stderr,"Main Thread: Creating sample thread\n"); 265 rc = pthread_create(&threadsample, &threadattr, thread_sample, NULL); 266 if (rc != 0) { 267 EPRINTF("UNRESOLVED: pthread_create: %d %s", 268 rc, strerror(rc)); 269 exit(UNRESOLVED); 270 } 271 272 /* Start the TF threads */ 273 DPRINTF(stderr,"Main Thread: Creating %d TF threads\n", cpus-1); 274 for (i = 0; i < cpus - 1; i++) 275 { 276 rc = pthread_create(&threads[i], &threadattr, thread_fn, 277 &tp[i + 2]); 278 if (rc != 0) { 279 EPRINTF("UNRESOLVED: pthread_create: %d %s", 280 rc, strerror(rc)); 281 exit(UNRESOLVED); 282 } 283 } 284 sleep(base_time + multiplier * 10 - seconds_read()); 285 286 /* Start TP thread */ 287 DPRINTF(stderr,"Main Thread: Creating TP thread\n"); 288 rc = pthread_create(&threadtp, &threadattr, thread_fn, &tp[1]); 289 if (rc != 0) { 290 EPRINTF("UNRESOLVED: pthread_create: %d %s", 291 rc, strerror(rc)); 292 exit(UNRESOLVED); 293 } 294 sleep(base_time + multiplier * 20 - seconds_read()); 295 296 /* Start TL thread */ 297 DPRINTF(stderr,"Main Thread: Creating TL thread\n"); 298 rc = pthread_create(&threadtl, &threadattr, thread_fn, &tp[0]); 299 if (rc != 0) { 300 EPRINTF("UNRESOLVED: pthread_create: %d %s", 301 rc, strerror(rc)); 302 exit(UNRESOLVED); 303 } 304 sleep(base_time + multiplier * 30 - seconds_read()); 305 306 /* Start TB1 thread (the lowest priority thread) */ 307 int timeout = multiplier * 40; 308 rc = pthread_create(&threadtb1, &threadattr, thread_tb1, 309 &timeout); 310 if (rc != 0) { 311 EPRINTF("UNRESOLVED: pthread_create: %d %s", 312 rc, strerror(rc)); 313 exit(UNRESOLVED); 314 } 315 sleep(base_time + multiplier * 40 - seconds_read()); 316 317 /* Start TB2 thread (boosting thread) */ 318 timeout = multiplier * 20; 319 rc = pthread_create(&threadtb2, &threadattr, thread_tb2, 320 &timeout); 321 if (rc != 0) { 322 EPRINTF("UNRESOLVED: pthread_create: %d %s", 323 rc, strerror(rc)); 324 exit(UNRESOLVED); 325 } 326 sleep(base_time + multiplier * 75 - seconds_read()); 327 328 /* Stop TL thread */ 329 tp[0].stop = 1; 330 sleep(base_time + multiplier * 85 - seconds_read()); 331 332 /* Stop TP thread */ 333 tp[1].stop = 1; 334 sleep(base_time + multiplier * 95 - seconds_read()); 335 336 /* Stop TF threads */ 337 for (i = 2; i < cpus - 1; i++) 338 { 339 tp[i].stop = 1; 340 } 341 342 /* Stop sampler */ 343 ts_stop = 1; 344 DPRINTF(stderr,"Main Thread: stop sampler thread\n"); 345 return 0; 346} 347 348 349