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