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