Created
May 20, 2023 01:58
-
-
Save vineethrp/e843e04503a5d10ce8a97073e6ca087e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* All credits: Steven Rostedt <rostedt@goodmis.org> | |
* | |
* Modified version of Steven's program to run multiple deadline spinning | |
* threads * with specified reservation(runtime, deadline=period) and a | |
* sleep value * in seconds which specifies a delay before spinning. | |
*/ | |
#define _GNU_SOURCE | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <linux/unistd.h> | |
#include <sys/syscall.h> | |
#include <pthread.h> | |
#include <errno.h> | |
#ifdef __i386__ | |
#ifndef __NR_sched_setattr | |
#define __NR_sched_setattr (351) | |
#endif | |
#ifndef __NR_sched_getattr | |
#define __NR_sched_getattr (352) | |
#endif | |
#else /* x86_64 */ | |
#ifndef __NR_sched_setattr | |
#define __NR_sched_setattr (314) | |
#endif | |
#ifndef __NR_sched_getattr | |
#define __NR_sched_getattr (315) | |
#endif | |
#endif /* i386 or x86_64 */ | |
#ifndef SCHED_DEADLINE | |
#define SCHED_DEADLINE 6 | |
#endif | |
#ifndef SCHED_FLAG_RECLAIM | |
#define SCHED_FLAG_RECLAIM 2 | |
#endif | |
#define gettid() syscall(__NR_gettid) | |
#define sched_setattr(pid, attr, flags) syscall(__NR_sched_setattr, pid, attr, flags) | |
#define sched_getattr(pid, attr, size, flags) syscall(__NR_sched_getattr, pid, attr, size, flags) | |
typedef unsigned long long u64; | |
typedef unsigned int u32; | |
typedef int s32; | |
static pthread_barrier_t barrier; | |
static void set_thread_prio(pid_t pid, int prio) | |
{ | |
struct sched_param sp = { .sched_priority = prio }; | |
int ret; | |
/* set up our priority */ | |
ret = sched_setscheduler(pid, SCHED_FIFO, &sp); | |
if (ret < 0) | |
perror("sched_setscheduler"); | |
} | |
static void set_prio(int prio) | |
{ | |
return; | |
set_thread_prio(0, prio); | |
} | |
struct sched_attr { | |
u32 size; | |
u32 sched_policy; | |
u64 sched_flags; | |
/* SCHED_NORMAL, SCHED_BATCH */ | |
s32 sched_nice; | |
/* SCHED_FIFO, SCHED_RR */ | |
u32 sched_priority; | |
/* SCHED_DEADLINE */ | |
u64 sched_runtime; | |
u64 sched_deadline; | |
u64 sched_period; | |
}; | |
static volatile int done; | |
static volatile int stats_notify; | |
typedef struct dl_params { | |
int runtime; | |
int deadline; | |
bool reclaim; | |
int sleep; | |
} dl_params_t; | |
#define NSEC_PER_SEC (1000000000ULL) | |
void *run_deadline(void *data) | |
{ | |
struct sched_attr attr; | |
int x = 0; | |
int ret; | |
struct timespec ts = { 0 }, old_ts = { 0 }; | |
dl_params_t *params = (dl_params_t *)data; | |
int tid; | |
tid = gettid(); | |
printf("deadline thread %d\n", tid); | |
ret = sched_getattr(getpid(), &attr, sizeof(attr), 0); | |
if (ret < 0) { | |
perror("sched_getattr"); | |
exit(-1); | |
} | |
attr.sched_policy = SCHED_DEADLINE; | |
if (params->reclaim) | |
attr.sched_flags = SCHED_FLAG_RECLAIM; | |
/* 1 ms out of every 30 ms */ | |
attr.sched_runtime = params->runtime * 1000 * 1000; | |
attr.sched_deadline = params->deadline * 1000 * 1000; | |
attr.sched_period = attr.sched_deadline; | |
printf("Start: " | |
"size=%u " | |
"policy=%d " | |
"flags=%llx " | |
"nice=%d " | |
"prio=%d " | |
"runtime=%lld " | |
"deadline=%lld " | |
"period=%lld\n" | |
, | |
attr.size, attr.sched_policy, | |
attr.sched_flags, attr.sched_nice, | |
attr.sched_priority, | |
attr.sched_runtime, attr.sched_deadline, | |
attr.sched_period); | |
ret = sched_setattr(0, &attr, 0); | |
if (ret < 0) { | |
done = 0; | |
perror("sched_setattr deadline"); | |
exit(-1); | |
} | |
pthread_barrier_wait(&barrier); | |
if (params->sleep) | |
sleep(params->sleep); | |
while (!done) { | |
double util; | |
int old_stats_notify; | |
unsigned long cputime, runtime; | |
unsigned long old_cputime, old_runtime; | |
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts)) { | |
printf("clock_gettime failed!\n"); | |
return NULL; | |
} | |
old_cputime = ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec; | |
if (clock_gettime(CLOCK_MONOTONIC, &ts)) { | |
printf("clock_gettime failed!\n"); | |
return NULL; | |
} | |
old_runtime = ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec; | |
old_stats_notify = stats_notify; | |
x = 0; | |
while (old_stats_notify == stats_notify) | |
x++; | |
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts)) { | |
printf("clock_gettime failed!\n"); | |
return NULL; | |
} | |
cputime = ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec; | |
if (clock_gettime(CLOCK_MONOTONIC, &ts)) { | |
printf("clock_gettime failed!\n"); | |
return NULL; | |
} | |
runtime = ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec; | |
util = (double)(cputime - old_cputime) * 100 / (runtime - old_runtime); | |
printf("TID[%d]: RECLAIM=%d, (r=%dms, d=%dms, p=%dms), Util: %3.2f\n", | |
tid, params->reclaim, params->runtime, params->deadline, params->deadline, util); | |
} | |
ret = sched_getattr(0, &attr, sizeof(attr), 0); | |
if (ret < 0) { | |
perror("sched_getattr"); | |
exit(-1); | |
} | |
printf("Stop: " | |
"size=%u " | |
"policy=%d " | |
"flags=%llx " | |
"nice=%d " | |
"prio=%d " | |
"runtime=%lld " | |
"deadline=%lld " | |
"period=%lld\n" | |
, | |
attr.size, attr.sched_policy, | |
attr.sched_flags, attr.sched_nice, | |
attr.sched_priority, | |
attr.sched_runtime, attr.sched_deadline, | |
attr.sched_period); | |
return NULL; | |
} | |
typedef enum { | |
DL_PARAM_RUNTIME, | |
DL_PARAM_DEADLINE, | |
DL_PARAM_RECLAIM, | |
DL_PARAM_SLEEP, | |
DL_PARAM_MAX, | |
} dl_param_type_t; | |
dl_params_t *parse_dl_params(char *str) | |
{ | |
int i; | |
int runtime, deadline, sleep, reclaim; | |
dl_params_t *param = NULL; | |
char *params[DL_PARAM_MAX]; | |
for (i = DL_PARAM_RUNTIME; i < DL_PARAM_MAX; i++) { | |
params[i] = strtok(str, ","); | |
if (!params[i]) | |
return NULL; | |
str = NULL; | |
} | |
i = DL_PARAM_RUNTIME; | |
runtime = strtol(params[i++], NULL, 0); | |
if (errno) | |
return NULL; | |
deadline = strtol(params[i++], NULL, 0); | |
if (errno) | |
return NULL; | |
reclaim = strtol(params[i++], NULL, 0); | |
if (errno) | |
return NULL; | |
sleep = strtol(params[i++], NULL, 0); | |
if (errno) | |
return NULL; | |
if (!runtime || !deadline || deadline > 1000 || | |
runtime >= deadline || sleep > 30) | |
return NULL; | |
param = (dl_params_t *)malloc(sizeof(dl_params_t)); | |
if (!param) | |
return NULL; | |
param->deadline = deadline; | |
param->runtime = runtime; | |
param->sleep = sleep; | |
param->reclaim = reclaim; | |
return param; | |
} | |
void free_dl_params(dl_params_t *params[], int n) | |
{ | |
for (int i = 0; i < n; i++) | |
free(params[i]); | |
} | |
#define STATS_INTERVAL (2) | |
int main (int argc, char **argv) | |
{ | |
int i; | |
pthread_t thread[10]; | |
dl_params_t *params[10]; | |
int total_sleep = 0; | |
int count = 0; | |
printf("main thread %ld\n", gettid()); | |
if (argc > 11) { | |
printf("Maximum of 10 threads supported!\n"); | |
return -1; | |
} | |
for (i = 0; i < argc - 1; i++) { | |
char str[16]; | |
strncpy(str, argv[i + 1], 16); | |
params[i] = parse_dl_params(str); | |
if (params[i] == NULL) { | |
printf("Invalid format: %s, should be <runtime>,<deadline>,<sleep>!\n", argv[i + 1]); | |
free_dl_params(params, i); | |
return -1; | |
} | |
if (total_sleep < params[i]->sleep) | |
total_sleep = params[i]->sleep; | |
} | |
total_sleep += 10; | |
if (i == 0) { | |
printf("Atleast one thread should be specified!\n"); | |
return -1; | |
} | |
pthread_barrier_init(&barrier, NULL, i + 1); | |
fflush(stdout); | |
for (int j = 0; j < i; j++) | |
pthread_create(&thread[j], NULL, run_deadline, params[j]); | |
set_prio(2); | |
pthread_barrier_wait(&barrier); | |
printf("Sleeping for %d seconds\n", total_sleep); | |
count = 0; | |
while (count < total_sleep) { | |
sleep(STATS_INTERVAL); | |
stats_notify++; | |
count += STATS_INTERVAL; | |
} | |
//sleep(total_sleep); | |
done = 1; | |
for (int j = 0; j < i; j++) | |
pthread_join(thread[j], NULL); | |
free_dl_params(params, i); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment