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