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