Skip to content

Instantly share code, notes, and snippets.

@Pacifist117
Created March 18, 2013 22:54
Show Gist options
  • Save Pacifist117/5191661 to your computer and use it in GitHub Desktop.
Save Pacifist117/5191661 to your computer and use it in GitHub Desktop.
/*
* Tests context switching times based on a semaphore in the RTAI kernel.
* Author: Rob Lyerly
*
* This test has been modified to increase scalability in this way:
*
* - The number of threads is correlated to the number of cores, each core gets two threads
* - Each core gets one mutex and a locker and unlocker thread
* - This version does not require a barrier
* - The "threads" variable does NOT include main
*
* Author: Kevin Burns
*/
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sched.h>
#include <sys/sysinfo.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <librttest.h>
#include "barrier.h"
#include <librttest.h>
#include "blocktime_mutex.h"
#define THREAD_PRIORITY 99
/* Integer to affine a task to all CPUs */
#define ALL_CPUS 0x00ffffff
#define NUM_CORES 24
/* Memory buffer used to record statistics */
static long** statistics;
/* Variables used to synchronize/time/perform the context switch */
static sem mutexes[NUM_CORES]; //Kevin: made single pointer rather than double
/* Thread parameters used to setup the thread */
typedef struct _threadparam {
int numLoops;
int threadnum;
int numThreads;
} thread_param;
#define DEBUG 1
void debug_msg(char * msg) {
#if DEBUG==1
printf("%s\n",msg);
#endif
}
static void* unlock_thread(void* param) {
int i = 0;
thread_param * my_param = (thread_param *)param;
printf("top of unlock_thread for %d\n",my_param->threadnum);
//for (i=0;i<my_param->numLoops;i++) {
for (i=0;i<10;i++) {
//while (!librt_sem_trywait(&mutexes[(my_param->threadnum)/2])) {
//do nothing
//}
//get before time here
printf("unlocking in thread: %d\n",my_param->threadnum);
librt_sem_post(&mutexes[(my_param->threadnum-1)/2]);
sleep(1);
}
return NULL;
}
static void* lock_thread(void* param) {
int i = 0;
thread_param * my_param = (thread_param *)param;
printf("top of lock_thread for %d\n",my_param->threadnum);
//for (i=0;i<my_param->numLoops;i++) {
for (i=0;i<10;i++) {
//while (librt_sem_trywait(&mutexes[(my_param->threadnum-1)/2])) {
//do nothing
//}
printf("locking lock %d in thread: %d\n",(my_param->threadnum)/2,my_param->threadnum);
librt_sem_wait(&mutexes[(my_param->threadnum)/2]);
//get time after here
}
return NULL;
}
int switchtest(int threads, int loops, int affinity, int policy, char* fn) {
thread_param* param;
int i = 0, j = 0, ret = 0;
int argc;
char * argv;
//Initialize the RT parameters
if (rt_init("", parse_args, argc, &argv))
printf("rt_init failed\n");
else
printf("rt_init succeeded\n");
//Allocate the statistics buffer
//The stats buffer will include the difference between unlock and lock for each thread pair
statistics = (long**)calloc(threads, sizeof(long));
for(i = 0; i < threads; i++)
statistics[i] = (long*)calloc(loops, sizeof(long));
//Start the requested number of threads
param = (thread_param*)calloc(2*(threads), sizeof(thread_param));
//mutexes = (mutex**)calloc(threads - 1, sizeof(mutex*)); //array of mutexes
//before = (RTIME*)calloc(2*threads), sizeof(RTIME));
task t = taskset_init((2*threads));
//Kevin TODO 2) Create mutexes and lock them
//fill thread parameters -- merge with 3)?
for(i = 0; i < (2*threads); i++) {
param[i].numLoops = loops;
param[i].threadnum = i;
param[i].numThreads = threads;
}
for(i = 0; i < threads; i++) {
librt_sem_init(&mutexes[i]);
librt_sem_wait(&mutexes[i]);
}
debug_msg("2) mutexes are created and locked");
char taskname_lock[7];
char taskname_unlock[7];
int cpus = 0;
//Kevin 3) Spawn RT threads
for (i = 0; i < (2*threads); i++, t++) {
//Set up lockers first
sprintf(taskname_lock, "%d",i);
t->func = lock_thread;
t->arg = (void *)&(param[i]);
t->prio = THREAD_PRIORITY;
t->name = taskname_lock;
t->stack_size = 0;
t->max_msg_size = 0;
t->policy = SCHED_FIFO;
#if KERN_RTAI
t->cpus_allowed = 1 << (i/2);
#else
cpus = 1 << (i/2);
CPU_SET(cpus,&t->cpus_allowed);
#endif
if ((ret = task_create(t)) < 0) {
printf("task%d failed", i);
exit(ret);
} else {
debug_msg("creating task");
}
//increment counters
i++;
t++;
//Set up unlockers now
sprintf(taskname_unlock, "%d",i); //Kevin: taskname is the last iteration of i for every thread, do I even need it?
t->func = unlock_thread;
t->arg = (void *)&(param[i]);
t->prio = THREAD_PRIORITY;
t->name = taskname_unlock;
t->stack_size = 0;
t->max_msg_size = 0;
t->policy = SCHED_FIFO;
//cpus_allowed stays the same
if ((ret = task_create(t)) < 0) {
printf("task%d failed", i);
exit(ret);
} else {
debug_msg("creating task");
}
}
debug_msg("3) threads are spawned");
munlockall();
task_join_all();
debug_msg("threads joined");
//Write statistics to file
char filename[40];
char thread_string[5];
sprintf(thread_string, "%d", (threads));
strcpy(filename, "/data/");
strcat(filename, fn);
strcat(filename, thread_string);
strcat(filename, ".dat");
FILE* fp = fopen(filename, "a");
for(i = 0; i < threads; i++) {
for(j = 0; j < loops; j++) {
fprintf(fp, "%ld\n", statistics[i][j]);
}
}
fclose(fp);
for(i = 0; i < threads; i++) {
free(statistics[i]);
librt_sem_destroy(&mutexes[i]);
}
free(statistics);
//free(thread);
free(param);
//free(mutexes);
//free(before);
//pthread_barrier_destroy(&barrier);
debug_msg("switchtest ended");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment