1 /* 2 * Copyright (c) 2003, Intel Corporation. All rights reserved. 3 * Created by: crystal.xiong REMOVE-THIS AT intel DOT com 4 * This file is licensed under the GPL license. For the full content 5 * of this license, see the COPYING file at the top level of this 6 * source tree. 7 */ 8 9 /* There are n TF threads, n is equal to the processors in the system minus 10 * one. TFs are used to keep busy these CPUs, which have priority 3. A 11 * TL thread with lower priority 1 is created, which locks a mutex and 12 * does workload. A TB thread with higher priority 4 is created and try 13 * to lock TL's mutex. A TP thread with priority 2 is created to reflect the 14 * priority change of TL. Main thread has the highest priority 6, which will 15 * control the running steps of those threads, including creating threads, 16 * stopping threads. There is another thread to collect the sample data with 17 * priority 5. 18 * 19 * Steps: 20 * 1. Create n TF threads, n is equal to processors number minus one. TF 21 * will do workload. 22 * 2. Create 1 TP thread and do workload. The thread will keep running when 23 * TL is created. 24 * 3. Create 1 TL thread to lock a mutex. TL will get a chance to run 25 * when TP sleep a wee bit in between. 26 * 4. Create 1 TB thread to lock the mutex. TL's priority will boost to 27 * TB's priority, which will cause TP having no chance to run. 28 * 5. TB timeout from the lock, TL's priority will decrease, so TP and TL 29 * will keep working as before. 30 * 5. Keep running for a while to let TL stabilize. 31 * 6. Stop these threads. 32 * 33 * Thanks Inaky.Perez-Gonzalez's suggestion and code 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 52 volatile int ts_stop = 0; 53 volatile double base_time; 54 55 struct thread_param { 56 int index; 57 volatile int stop; 58 int sleep_ms; 59 int priority; 60 int policy; 61 const char *name; 62 int cpu; 63 volatile unsigned futex; 64 volatile unsigned should_stall; 65 volatile unsigned progress; 66 } tp[] = { 67 { 68 0, 0, 0, 1, SCHED_FIFO, "TL", 0, 0, 0, 0}, { 69 1, 0, 50, 2, SCHED_FIFO, "TP", 0, 0, 0, 0}, { 70 2, 0, 0, 3, SCHED_FIFO, "TF", 1, 0, 0, 0}, { 71 3, 0, 0, 3, SCHED_FIFO, "TF", 2, 0, 0, 0}, { 72 4, 0, 0, 3, SCHED_FIFO, "TF", 3, 0, 0, 0}, { 73 5, 0, 0, 3, SCHED_FIFO, "TF", 4, 0, 0, 0}, { 74 6, 0, 0, 3, SCHED_FIFO, "TF", 5, 0, 0, 0}, { 75 7, 0, 0, 3, SCHED_FIFO, "TF", 6, 0, 0, 0} 76 }; 77 78 volatile unsigned do_work_dummy; 79 void do_work(unsigned granularity_top, volatile unsigned *progress) 80 { 81 unsigned granularity_cnt, i; 82 unsigned top = 5 * 1000 * 1000; 83 unsigned dummy = do_work_dummy; 84 85 for (granularity_cnt = 0; granularity_cnt < granularity_top; 86 granularity_cnt++) { 87 for (i = 0; i < top; i++) 88 dummy = i | dummy; 89 (*progress)++; 90 } 91 return; 92 } 93 94 void *thread_fn(void *param) 95 { 96 struct thread_param *tp = param; 97 struct timespec ts; 98 int rc; 99 unsigned long mask = 1 << tp->cpu; 100 101 #if __linux__ 102 rc = sched_setaffinity(0, sizeof(mask), &mask); 103 if (rc < 0) { 104 EPRINTF("UNRESOLVED: Thread %s index %d: Can't set affinity: " 105 "%d %s", tp->name, tp->index, rc, strerror(rc)); 106 exit(UNRESOLVED); 107 } 108 #endif 109 test_set_priority(pthread_self(), SCHED_FIFO, tp->priority); 110 111 DPRINTF(stdout, "#EVENT %f %s Thread Started\n", 112 seconds_read() - base_time, tp->name); 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 \n", tp->name, tp->index, rc, 124 strerror(rc)); 125 exit(UNRESOLVED); 126 } 127 } 128 129 DPRINTF(stdout, "#EVENT %f %s Thread 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 if (rc < 0) { 145 EPRINTF 146 ("UNRESOLVED: Thread %s index %d: Can't set affinity: %d %s", 147 tp->name, tp->index, rc, strerror(rc)); 148 exit(UNRESOLVED); 149 } 150 151 DPRINTF(stdout, "#EVENT %f Thread TL Started\n", 152 seconds_read() - base_time); 153 tp->progress = 0; 154 pthread_mutex_lock(&mutex); 155 while (!tp->stop) { 156 do_work(5, &tp->progress); 157 } 158 pthread_mutex_unlock(&mutex); 159 160 DPRINTF(stdout, "#EVENT %f Thread TL Stopped\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 = 250; 170 double newtime; 171 size_t size; 172 int i; 173 int rc; 174 175 test_set_priority(pthread_self(), SCHED_FIFO, 5); 176 DPRINTF(stderr, "Thread Sampler: started \n"); 177 DPRINTF(stdout, "# COLUMNS %d Time TL TP ", 2 + 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 + 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 seconds, t0, t1; 203 int rc; 204 205 test_set_priority(pthread_self(), SCHED_FIFO, 4); 206 207 DPRINTF(stdout, "#EVENT %f TB Starts\n", seconds_read() - base_time); 208 209 boost_time.tv_sec = time(NULL) + *((time_t *) arg); 210 boost_time.tv_nsec = 0; 211 212 t0 = seconds_read(); 213 rc = pthread_mutex_timedlock(&mutex, &boost_time); 214 t1 = seconds_read(); 215 seconds = t1 - t0; 216 217 DPRINTF(stdout, "#EVENT %f TB Waited for %.2f s\n", 218 t1 - base_time, seconds); 219 220 if (rc != ETIMEDOUT) { 221 EPRINTF("FAIL: Thread TB: lock returned %d %s, ", rc, 222 strerror(rc)); 223 exit(FAIL); 224 } 225 DPRINTF(stderr, "Thread TB: DONE. lock returned %d %s, " 226 "slept %f \n", rc, strerror(rc), seconds) 227 228 return NULL; 229 } 230 231 int main(int argc, char **argv) 232 { 233 pthread_mutexattr_t mutex_attr; 234 pthread_attr_t threadattr; 235 pthread_t threads[cpus - 1], threadsample, threadtp, threadtl, threadtb; 236 237 int multiplier = 1; 238 int i; 239 int rc; 240 241 test_set_priority(pthread_self(), SCHED_FIFO, 6); 242 cpus = sysconf(_SC_NPROCESSORS_ONLN); 243 base_time = seconds_read(); 244 245 /* Initialize a mutex with PTHREAD_PRIO_INHERIT protocol */ 246 mutex_attr_init(&mutex_attr); 247 mutex_init(&mutex, &mutex_attr); 248 249 /* Initialize thread attr */ 250 threadattr_init(&threadattr); 251 252 /* Start the sample thread */ 253 DPRINTF(stderr, "Main Thread: start sample thread \n"); 254 rc = pthread_create(&threadsample, &threadattr, thread_sample, NULL); 255 if (rc != 0) { 256 EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc)); 257 exit(UNRESOLVED); 258 } 259 260 /* Start the TF threads */ 261 DPRINTF(stderr, "Main Thread: start %d TF thread\n", cpus - 1); 262 for (i = 0; i < cpus - 1; i++) { 263 rc = pthread_create(&threads[i], &threadattr, thread_fn, 264 &tp[i + 2]); 265 if (rc != 0) { 266 EPRINTF("UNRESOLVED: pthread_create: %d %s", 267 rc, strerror(rc)); 268 exit(UNRESOLVED); 269 } 270 } 271 sleep(base_time + multiplier * 10 - seconds_read()); 272 273 /* Start TP thread */ 274 275 DPRINTF(stderr, "Main Thread: start TP thread\n"); 276 rc = pthread_create(&threadtp, &threadattr, thread_fn, &tp[1]); 277 if (rc != 0) { 278 EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc)); 279 exit(UNRESOLVED); 280 } 281 sleep(base_time + multiplier * 20 - seconds_read()); 282 283 /* Start TL thread */ 284 DPRINTF(stderr, "Main Thread: start TL thread\n"); 285 rc = pthread_create(&threadtl, &threadattr, thread_tl, &tp[0]); 286 if (rc != 0) { 287 EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc)); 288 exit(UNRESOLVED); 289 } 290 sleep(base_time + multiplier * 30 - seconds_read()); 291 292 /* Start TB thread (boosting thread) */ 293 DPRINTF(stderr, "Main Thread: start TB thread\n"); 294 time_t timeout = multiplier * 20; 295 rc = pthread_create(&threadtb, &threadattr, thread_tb, &timeout); 296 if (rc != 0) { 297 EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc)); 298 exit(UNRESOLVED); 299 } 300 sleep(base_time + multiplier * 60 - seconds_read()); 301 302 /* Stop TL thread */ 303 304 DPRINTF(stderr, "Main Thread: stop TL thread\n"); 305 tp[0].stop = 1; 306 sleep(base_time + multiplier * 70 - seconds_read()); 307 308 /* Stop TP thread */ 309 DPRINTF(stderr, "Main Thread: stop TP thread\n"); 310 tp[1].stop = 1; 311 sleep(base_time + multiplier * 80 - seconds_read()); 312 313 /* Stop TF threads */ 314 DPRINTF(stderr, "Main Thread: stop TF threads\n"); 315 for (i = 2; i < cpus - 1; i++) { 316 tp[i].stop = 1; 317 } 318 319 /* Stop sampler */ 320 ts_stop = 1; 321 DPRINTF(stderr, "Main Thread: stop sampler thread \n"); 322 return 0; 323 } 324