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. 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 with
     18  * 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.	Set TB's prioirty to 1, TL's priority will decrease. So TP and TL
     30  * 	will keep working as before.
     31  * 6.	Stop these threads.
     32  *
     33  * NOTE: Most of the code is ported from test-11 written by inkay.
     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 volatile int ts_stop = 0;
     52 volatile double base_time;
     53 
     54 struct thread_param {
     55 	int index;
     56 	volatile int stop;
     57 	int sleep_ms;
     58 	int priority;
     59 	int policy;
     60 	const char *name;
     61 	int cpu;
     62 	volatile unsigned futex;
     63 	volatile unsigned should_stall;
     64 	volatile unsigned progress;
     65 } tp[] = {
     66 	{
     67 	0, 0, 0, 1, SCHED_FIFO, "TL", 0, 0, 0, 0}, {
     68 	1, 0, 200, 2, SCHED_FIFO, "TP", 0, 0, 0, 0}, {
     69 	2, 0, 0, 3, SCHED_FIFO, "TF", 1, 0, 0, 0}, {
     70 	3, 0, 0, 3, SCHED_FIFO, "TF", 2, 0, 0, 0}, {
     71 	4, 0, 0, 3, SCHED_FIFO, "TF", 3, 0, 0, 0}, {
     72 	5, 0, 0, 3, SCHED_FIFO, "TF", 4, 0, 0, 0}, {
     73 	6, 0, 0, 3, SCHED_FIFO, "TF", 5, 0, 0, 0}, {
     74 	7, 0, 0, 3, SCHED_FIFO, "TF", 6, 0, 0, 0}
     75 };
     76 
     77 volatile unsigned do_work_dummy;
     78 void do_work(unsigned granularity_top, volatile unsigned *progress)
     79 {
     80 	unsigned granularity_cnt, i;
     81 	unsigned top = 5 * 1000 * 1000;
     82 	unsigned dummy = do_work_dummy;
     83 
     84 	for (granularity_cnt = 0; granularity_cnt < granularity_top;
     85 	     granularity_cnt++) {
     86 		for (i = 0; i < top; i++)
     87 			dummy = i | dummy;
     88 		(*progress)++;
     89 	}
     90 	return;
     91 }
     92 
     93 void *thread_fn(void *param)
     94 {
     95 	struct thread_param *tp = param;
     96 	struct timespec ts;
     97 	int rc;
     98 	unsigned long mask = 1 << tp->cpu;
     99 
    100 #if __linux__
    101 	rc = sched_setaffinity(0, sizeof(mask), &mask);
    102 	if (rc < 0) {
    103 		EPRINTF("UNRESOLVED: Thread %s index %d: Can't set affinity: "
    104 			"%d %s", tp->name, tp->index, rc, strerror(rc));
    105 		exit(UNRESOLVED);
    106 	}
    107 #endif
    108 	test_set_priority(pthread_self(), SCHED_FIFO, tp->priority);
    109 	DPRINTF(stderr, "Thread %s index %d: started\n", tp->name, tp->index);
    110 	DPRINTF(stdout, "#EVENT %f Thread %s Started\n",
    111 		seconds_read() - base_time, tp->name);
    112 
    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", tp->name, tp->index, rc, strerror(rc));
    124 			exit(UNRESOLVED);
    125 		}
    126 	}
    127 
    128 	DPRINTF(stdout, "#EVENT %f Thread %s Started\n",
    129 		seconds_read() - base_time, tp->name);
    130 	return NULL;
    131 }
    132 
    133 void *thread_tl(void *param)
    134 {
    135 	struct thread_param *tp = param;
    136 	unsigned long mask = 1 << tp->cpu;
    137 	int rc;
    138 
    139 #if __linux__
    140 	rc = sched_setaffinity((pid_t) 0, sizeof(mask), &mask);
    141 	if (rc < 0) {
    142 		EPRINTF
    143 		    ("UNRESOLVED: Thread %s index %d: Can't set affinity: %d %s",
    144 		     tp->name, tp->index, rc, strerror(rc));
    145 		exit(UNRESOLVED);
    146 	}
    147 #endif
    148 
    149 	test_set_priority(pthread_self(), SCHED_FIFO, tp->priority);
    150 
    151 	DPRINTF(stderr, "Thread %s index %d: started\n", tp->name, tp->index);
    152 	DPRINTF(stdout, "#EVENT %f Thread %s Started\n",
    153 		seconds_read() - base_time, tp->name);
    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 %s Stopted\n",
    161 		seconds_read() - base_time, tp->name);
    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 	size_t size;
    171 	int i;
    172 	int rc;
    173 
    174 	test_set_priority(pthread_self(), SCHED_FIFO, 5);
    175 	DPRINTF(stderr, "Thread Sampler: started\n");
    176 	DPRINTF(stdout, "# COLUMNS %d Time TP TL ", 2 + cpus);
    177 	for (i = 0; i < (cpus - 1); i++)
    178 		DPRINTF(stdout, "TF%d ", i);
    179 	DPRINTF(stdout, "\n");
    180 	ts.tv_sec = 0;
    181 	ts.tv_nsec = period * 1000 * 1000;
    182 
    183 	while (!ts_stop) {
    184 		size =
    185 		    snprintf(buffer, 1023, "%f ", seconds_read() - 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 t0, t1;
    203 	int rc;
    204 
    205 	test_set_priority(pthread_self(), SCHED_FIFO, 4);
    206 	DPRINTF(stderr, "Thread TB: started\n");
    207 
    208 	DPRINTF(stdout, "#EVENT %f TB Started, waiting for mutex for %lu s\n",
    209 		seconds_read() - base_time, *(time_t *) arg);
    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 TB Thread Waited for %.2f s\n",
    218 		seconds_read() - base_time, t1 - t0);
    219 
    220 	if (rc != ETIMEDOUT && rc != 0) {
    221 		EPRINTF("FAIL: Thread TB: lock returned %d %s, "
    222 			"slept %f", rc, strerror(rc), t1 - t0);
    223 		exit(FAIL);
    224 	}
    225 
    226 	DPRINTF(stdout, "#EVENT %f TB Stopped\n", seconds_read() - base_time);
    227 	return NULL;
    228 }
    229 
    230 int main(int argc, char **argv)
    231 {
    232 	cpus = sysconf(_SC_NPROCESSORS_ONLN);
    233 	pthread_mutexattr_t mutex_attr;
    234 	pthread_attr_t threadattr;
    235 	pthread_t threads[cpus - 1], threadsample, threadtp, threadtl, threadtb;
    236 
    237 	time_t multiplier = 1;
    238 	int i;
    239 	int rc;
    240 
    241 	test_set_priority(pthread_self(), SCHED_FIFO, 6);
    242 	base_time = seconds_read();
    243 
    244 	/* Initialize a mutex with PTHREAD_PRIO_INHERIT protocol */
    245 	mutex_attr_init(&mutex_attr);
    246 	mutex_init(&mutex, &mutex_attr);
    247 
    248 	/* Initialize thread attr */
    249 	threadattr_init(&threadattr);
    250 
    251 	/* Start the sample thread */
    252 	DPRINTF(stderr, "Main Thread: Creating sample thread\n");
    253 	rc = pthread_create(&threadsample, &threadattr, thread_sample, NULL);
    254 	if (rc != 0) {
    255 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
    256 		exit(UNRESOLVED);
    257 	}
    258 
    259 	/* Start the TF threads */
    260 	DPRINTF(stderr, "Main Thread: Creating %d TF threads\n", cpus - 1);
    261 	for (i = 0; i < cpus - 1; i++) {
    262 		rc = pthread_create(&threads[i], &threadattr, thread_fn,
    263 				    &tp[i + 2]);
    264 		if (rc != 0) {
    265 			EPRINTF("UNRESOLVED: pthread_create: %d %s",
    266 				rc, strerror(rc));
    267 			exit(UNRESOLVED);
    268 		}
    269 	}
    270 
    271 	sleep(base_time + multiplier * 10 - seconds_read());
    272 
    273 	/* Start TP thread */
    274 	DPRINTF(stderr, "Main Thread: Creating TP thread\n");
    275 	rc = pthread_create(&threadtp, &threadattr, thread_fn, &tp[1]);
    276 	if (rc != 0) {
    277 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
    278 		exit(UNRESOLVED);
    279 	}
    280 	sleep(base_time + multiplier * 20 - seconds_read());
    281 
    282 	/* Start TL thread */
    283 	DPRINTF(stderr, "Main Thread: Creating TL thread\n");
    284 	rc = pthread_create(&threadtl, &threadattr, thread_tl, &tp[0]);
    285 	if (rc != 0) {
    286 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
    287 		exit(UNRESOLVED);
    288 	}
    289 	sleep(base_time + multiplier * 30 - seconds_read());
    290 
    291 	/* Start TB thread (boosting thread) */
    292 	unsigned long timeout = multiplier * 20;
    293 	rc = pthread_create(&threadtb, &threadattr, thread_tb, &timeout);
    294 	if (rc != 0) {
    295 		EPRINTF("UNRESOLVED: pthread_create: %d %s", rc, strerror(rc));
    296 		exit(UNRESOLVED);
    297 	}
    298 	sleep(base_time + multiplier * 40 - seconds_read());
    299 
    300 	/* Decrease TB's priority */
    301 	DPRINTF(stderr, "Main Thread: decrease TB's priority to 1\n");
    302 	test_set_priority(threadtb, SCHED_FIFO, 1);
    303 	DPRINTF(stdout, "#EVENT %f TB's priority decreased\n",
    304 		seconds_read() - base_time);
    305 	sleep(base_time + multiplier * 60 - seconds_read());
    306 
    307 	/* Stop TL thread */
    308 	tp[0].stop = 1;
    309 	sleep(base_time + multiplier * 70 - seconds_read());
    310 
    311 	/* Stop TP thread */
    312 	tp[1].stop = 1;
    313 	sleep(base_time + multiplier * 80 - seconds_read());
    314 
    315 	/* Stop TF threads */
    316 	for (i = 2; i < cpus - 1; i++) {
    317 		tp[i].stop = 1;
    318 	}
    319 
    320 	/* Stop sampler */
    321 	ts_stop = 1;
    322 	DPRINTF(stderr, "Main Thread: stop sampler thread\n");
    323 	return 0;
    324 }
    325