Skip to content

Instantly share code, notes, and snippets.

@joelagnel
Created January 26, 2023 18:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joelagnel/a830380f532c1d21262914a06adc3718 to your computer and use it in GitHub Desktop.
Save joelagnel/a830380f532c1d21262914a06adc3718 to your computer and use it in GitHub Desktop.
A test to check RT throttling
// Author: Steven Rostedt
//
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <time.h>
#include <sched.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
static char *argv0;
static char *get_this_name(void)
{
static char *this_name;
char *arg;
char *p;
if (this_name)
return this_name;
arg = argv0;
p = arg+strlen(arg);
while (p >= arg && *p != '/')
p--;
p++;
this_name = p;
return p;
}
static void usage(void)
{
char *p = get_this_name();
printf("usage: %s timeout (in seconds)\n"
"\n",p);
exit(-1);
}
static void __vdie(const char *fmt, va_list ap, int err)
{
int ret = errno;
char *p = get_this_name();
if (err && errno)
perror(p);
else
ret = -1;
fprintf(stderr, " ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
exit(ret);
}
void die(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
__vdie(fmt, ap, 0);
va_end(ap);
}
void pdie(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
__vdie(fmt, ap, 1);
va_end(ap);
}
static void set_prio(int prio)
{
struct sched_param param = {
.sched_priority = prio,
};
sched_setscheduler(0, SCHED_FIFO, &param);
}
#define barrier() asm volatile ("" ::: "memory")
static int done;
void *start_task(void *d)
{
unsigned long long *slice = d;
struct timespec tv;
set_prio(5);
tv.tv_sec = *slice / 1000000000ULL;
tv.tv_nsec = *slice - tv.tv_sec * 1000000000ULL;
nanosleep(&tv, NULL);
while (!done)
barrier();
return NULL;
}
#define sec2usec(sec) (sec * 1000000ULL)
#define sec2nano(sec) (sec * 1000000000ULL)
#define inc_cpu(cpu, cpus) ((cpu) < ((cpus) - 1) ? (cpu) + 1 : 0)
static unsigned long long get_time(void)
{
struct timeval tv;
unsigned long long time;
gettimeofday(&tv, NULL);
time = sec2usec(tv.tv_sec);
time += tv.tv_usec;
return time;
}
void *start_single_task(void *data)
{
unsigned long long now;
cpu_set_t *start_cpu_set;
cpu_set_t *cpu_set;
size_t cpu_size;
int next_cpu = -1;
int cpus;
int cpu;
cpus = sysconf(_SC_NPROCESSORS_CONF);
cpu_size = CPU_ALLOC_SIZE(cpus);
start_cpu_set = CPU_ALLOC(cpus);
cpu_set = CPU_ALLOC(cpus);
CPU_ZERO_S(cpu_size, cpu_set);
sched_getaffinity(0, cpu_size, start_cpu_set);
while (!done) {
for (cpu = inc_cpu(next_cpu, cpus); cpu != next_cpu;
cpu = inc_cpu(cpu, cpus)) {
if (CPU_SET_S(cpu, cpu_size, start_cpu_set)) {
CPU_CLR_S(next_cpu, cpu_size, cpu_set);
next_cpu = cpu;
CPU_SET_S(next_cpu, cpu_size, cpu_set);
printf("Pin to %d\n", cpu);
sched_setaffinity(0, cpu_size, cpu_set);
break;
}
}
now = get_time();
now += sec2usec(1) / 2;
while (get_time() < now)
barrier();
}
return NULL;
}
static void run_single_thread(int secs)
{
pthread_t threads;
if (pthread_create(&threads, NULL, start_single_task, NULL))
pdie("pthread_create");
sleep(secs);
done = 1;
pthread_join(threads, NULL);
}
static void __create_threads(int cpus, int secs)
{
unsigned long long slice[cpus];
unsigned long long time;
pthread_t threads[cpus];
int i;
time = sec2nano(1) / cpus;
if (!time)
time = 1;
for (i=0; i < cpus; i++) {
slice[i] = time * i;
if (pthread_create(&threads[i], NULL, start_task,
(void *)&slice[i]))
pdie("pthread_create");
}
sleep(secs);
done = 1;
for (i = 0; i < cpus; i++)
pthread_join(threads[i], NULL);
}
static void create_threads(int secs)
{
int cpus;
cpus = sysconf(_SC_NPROCESSORS_ONLN);
if (cpus <= 0)
pdie("Can't determine the number of CPUs");
__create_threads(cpus, secs);
}
int main (int argc, char **argv)
{
bool single;
int secs;
int c;
argv0 = argv[0];
while ((c = getopt(argc, argv, "sh")) >= 0) {
switch (c) {
case 's':
single = true;
break;
case 'h':
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc < 1)
usage();
secs = atoi(argv[0]);
if (secs <= 0)
die("Invalid timeout '%d'\n", secs);
set_prio(10);
if (single)
run_single_thread(secs);
else
create_threads(secs);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment