Skip to content

Instantly share code, notes, and snippets.

@vineethrp
Created May 20, 2023 01:58
Show Gist options
  • Save vineethrp/e843e04503a5d10ce8a97073e6ca087e to your computer and use it in GitHub Desktop.
Save vineethrp/e843e04503a5d10ce8a97073e6ca087e to your computer and use it in GitHub Desktop.
/*
* 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