Skip to content
Snippets Groups Projects
Commit fc2b04e8 authored by Steven Hübner's avatar Steven Hübner
Browse files

add missing task set variant

parent 152248f4
Branches main
No related tags found
No related merge requests found
Showing
with 1810 additions and 0 deletions
# ##############################################################################
# User variables
# user variables can be specified in the environment or in the local make.conf file
-include make.conf
# Where is the LITMUS^RT userspace library source tree?
# By default, we assume that it resides in a sibling directory named 'liblitmus'.
LIBLITMUS ?= ../../../liblitmus
# Include default configuration from liblitmus.
# IMPORTANT: Liblitmus must have been built before this file exists.
include ${LIBLITMUS}/inc/config.makefile
# all sources
vpath %.c src/
# local include files
CPPFLAGS += -Iinclude/
# ##############################################################################
# Targets
all = g1 gn_task1 gn_task2 gn_task3 gn_task4
.PHONY: all clean
all: ${all}
clean: rm -f ${all} *.o *.d
obj-g1 = g1.o
g1: ${obj-g1}
obj-gn_task1 = gn_task1.o
gn_task1: ${obj-gn_task1}
obj-gn_task2 = gn_task2.o
gn_task2: ${obj-gn_task2}
obj-gn_task3 = gn_task3.o
gn_task3: ${obj-gn_task3}
obj-gn_task4 = gn_task4.o
gn_task4: ${obj-gn_task4}
# dependency discovery
include ${LIBLITMUS}/inc/depend.makefile
\ No newline at end of file
#include <sys/time.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <time.h>
#include <string.h>
#include <assert.h>
#include <inttypes.h>
#include <sys/mman.h>
#include <errno.h>
#include "litmus.h"
#include "common.h"
#define noinline __attribute__((__noinline__))
/* the way cputime() relates to */
#define SCALE 0.95 // 0.92 better?
// this was determined by trial-and-error (on a VM!)
#define NUMS 4096
static int num[NUMS];
static int nr_of_pages = 0;
static int page_size;
static void *base = NULL;
static int cycles_ms = 1;
long long timeInMilliseconds(void) {
struct timeval tv;
gettimeofday(&tv,NULL);
return (((long long)tv.tv_sec)*1000)+(tv.tv_usec/1000);
}
void noinline be_busy(double time, int (*func)(void)) {
double start = cputime();
time *= 0.001 * SCALE;
while (cputime() - start < time) {
//printf("cputime(): %f, time: %f\n", cputime(), time);
// busywaiting?
if(func && (*func)())
break;
}
}
noinline int loop(int count)
{
int i, j = 0;
/* touch some numbers and do some math */
for (i = 0; i < count; i++) {
int index = i % NUMS;
j += num[index]++;
if (j > num[index])
num[index] = (j / 2) + 1;
}
return j;
}
#define loop_once() loop(NUMS)
int loop_once_with_mem(void)
{
int i, j = 0;
int rand;
int *num;
/* choose a random page */
if (nr_of_pages > 1)
rand = lrand48() % (nr_of_pages - 1);
else
rand = 0;
/* touch the randomly selected page */
num = base + (rand * page_size);
for (i = 0; i < page_size / sizeof(int); i++) {
j += num[i]++;
if (j > num[i])
num[i] = (j / 2) + 1;
}
return j;
}
int loop_for(double exec_time, double emergency_exit)
{
int tmp = 0;
if (cycles_ms) {
double count = cycles_ms * exec_time * 1000;
tmp += loop(count);
} else {
double last_loop = 0, loop_start;
double start = cputime();
double now = cputime();
while (now + last_loop < start + exec_time) {
loop_start = now;
if (nr_of_pages)
tmp += loop_once_with_mem();
else
tmp += loop_once();
now = cputime();
last_loop = now - loop_start;
if (emergency_exit && wctime() > emergency_exit) {
/* Oops --- this should only be possible if the
* execution time tracking is broken in the LITMUS^RT
* kernel or the user specified infeasible parameters.
*/
fprintf(stderr, "!!! rtspin/%d emergency exit!\n",
getpid());
fprintf(stderr, "Reached experiment timeout while "
"spinning.\n");
break;
}
}
}
return tmp;
}
int calibrate_ms(int ms)
{
int right = NUMS;
int left = 0;
int middle;
double start;
double now;
double dms = 0.001 * ms;
/*look for initial loop count values for binary search*/
for (;;)
{
printf("Probe %d loops for %d ms:\n", right, ms);
start = wctime();
loop(right);
now = wctime();
if ((now - start) >= dms)
break;
left = right;
right += right;
}
middle = (left + right) / 2;
/*binary search for a loop count value for expected calibration time*/
while (left < middle)
{
start = wctime();
loop(middle);
now = wctime();
printf("%d loops elapsed in %4.20f s\n", middle, now - start);
if ((now - start) < dms)
left = middle;
else if ((now - start) == dms)
return middle;
else
right = middle;
middle = (left + right) / 2;
}
return middle;
}
void _job(double exec_time, double program_end, int lock_od, double cs_length)
{
double chunk1, chunk2;
if (lock_od >= 0) {
/* simulate critical section somewhere in the middle */
chunk1 = drand48() * (exec_time - cs_length);
chunk2 = exec_time - cs_length - chunk1;
/* non-critical section */
loop_for(chunk1, program_end + 1);
/* critical section */
litmus_lock(lock_od);
loop_for(cs_length, program_end + 1);
litmus_unlock(lock_od);
/* non-critical section */
loop_for(chunk2, program_end + 2);
} else {
loop_for(exec_time, program_end + 1);
}
}
\ No newline at end of file
/**
* @file litmus.h
* Public API for LITMUS^RT
*/
/**
* @mainpage
* The LITMUS^RT patch is a (soft) real-time extension of the Linux kernel with a
* focus on multiprocessor real-time scheduling and synchronization. The Linux
* kernel is modified to support the sporadic task model and modular scheduler
* plugins. Clustered, partitioned, and global scheduling are included, and
* semi-partitioned scheduling is supported as well.
*
* \b liblitmus is the userspace API for LITMUS^RT. It consists of functions to
* control scheduling protocols and parameters, mutexes as well as functionality
* to create test suites.
*
* Example test programs can be found in \b bin/base_task.c and
* \b bin/base_task_mt.c . Several test suites are given in the \b tests
* directory.
*/
#ifndef LITMUS_H
#define LITMUS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/types.h>
#include <stdint.h>
/* Include kernel header.
* This is required for the rt_param
* and control_page structures.
*/
//#include "litmus/rt_param.h"
#define __user
#include "litmus/ctrlpage.h"
#undef __user
#include "asm/cycles.h" /* for null_call() */
#include "migration.h"
/**
* @private
* The numeric ID of the LITMUS^RT scheduling class.
*/
#define SCHED_LITMUS 7
/**
* Initialise a real-time task param struct
* @param param Pointer to the struct to initialise
*/
void init_rt_task_param(struct rt_task* param);
/**
* Set real-time task parameters for given process
* @param pid PID of process
* @param param Real-time task parameter struct
* @return 0 on success
*/
int set_rt_task_param(pid_t pid, struct rt_task* param);
/**
* Get real-time task parameters for given process
* @param pid PID of process
* @param param Real-time task parameter struct to fill
* @return 0 on success
*/
int get_rt_task_param(pid_t pid, struct rt_task* param);
/**
* Create a new reservation/container (not supported by all plugins).
* @param rtype The type of reservation to create.
* @param config optional reservation-specific configuration (may be NULL)
* @return 0 on success
*/
int reservation_create(int rtype, void *config);
/**
* Convert a partition number to a CPU identifier
* @param partition Partition number
* @return CPU identifier for given partition
*
* Release-master-aware functions for getting the first
* CPU in a particular cluster or partition. Use these
* to set rt_task::cpu for cluster/partitioned scheduling.
*
* \deprecated{Use domain_to_first_cpu() in new code.}
*/
int partition_to_cpu(int partition);
/**
* For given cluster, return the identifier for the first associated CPU
* @param cluster Identifier of the cluster
* @param cluster_size Size for this cluster
* @return Identifier for the first associated CPU
*
* \deprecated{Use domain_to_first_cpu() in new code.}
*/
int cluster_to_first_cpu(int cluster, int cluster_size);
/* The following three functions are convenience functions for setting up
* real-time tasks. Default behaviors set by init_rt_task_params() are used.
* Also sets affinity masks for clustered/partitions functions. Time units in
* nanoseconds. */
/**
* Set up a sporadic task with global scheduling
* @param e_ns Execution time in nanoseconds
* @param p_ns Period in nanoseconds
* @return 0 on success
*/
int sporadic_global(lt_t e_ns, lt_t p_ns);
/**
* Set up a sporadic task with partitioned scheduling
* @param e_ns Execution time in nanoseconds
* @param p_ns Period in nanoseconds
* @param partition Identifier for partition to add this task to
* @return 0 on success
*/
int sporadic_partitioned(lt_t e_ns, lt_t p_ns, int partition);
/**
* Set up a sporadic task with clustered scheduling
* @param e_ns Execution time in nanoseconds
* @param p_ns Period in nanoseconds
* @param cluster Cluster to add this task to
* @return 0 on success
*/
int sporadic_clustered(lt_t e_ns, lt_t p_ns, int cluster);
/* simple time unit conversion macros */
/** Convert seconds to nanoseconds
* @param s Time units in seconds */
#define s2ns(s) ((s)*1000000000LL)
/** Convert seconds to microseconds
* @param s Time units in seconds */
#define s2us(s) ((s)*1000000LL)
/** Convert seconds to milliseconds
* @param s Time units in seconds */
#define s2ms(s) ((s)*1000LL)
/** Convert milliseconds to nanoseconds
* @param ms Time units in milliseconds */
#define ms2ns(ms) ((ms)*1000000LL)
/** Convert milliseconds to microseconds
* @param ms Time units in milliseconds */
#define ms2us(ms) ((ms)*1000LL)
/** Convert microseconds to nanoseconds
* @param us Time units in microseconds */
#define us2ns(us) ((us)*1000LL)
/** Convert nanoseconds to seconds (truncating)
* @param ns Time units in nanoseconds */
#define ns2s(ns) ((ns)/1000000000LL)
/** Convert nanoseconds to milliseconds (truncating)
* @param ns Time units in nanoseconds */
#define ns2ms(ns) ((ns)/1000000LL)
/**
* Locking protocols for allocated shared objects
*/
typedef enum {
FMLP_SEM = 0, /**< Fifo-based Multiprocessor Locking Protocol */
SRP_SEM = 1, /**< Stack Resource Protocol */
MPCP_SEM = 2, /**< Multiprocessor Priority Ceiling Protocol */
MPCP_VS_SEM = 3, /**< Multiprocessor Priority Ceiling Protocol with
Virtual Spinning */
DPCP_SEM = 4, /**< Distributed Priority Ceiling Protocol */
PCP_SEM = 5, /**< Priority Ceiling Protocol */
DFLP_SEM = 6, /**< Distributed FIFO Locking Protocol */
} obj_type_t;
/**
* For given protocol name, return semaphore object type id
* @param name String representation of protocol name
* @return Object type ID as integer
*/
int lock_protocol_for_name(const char* name);
/**
* For given semaphore object type id, return the name of the protocol
* @param id Semaphore object type ID
* @return Name of the locking protocol
*/
const char* name_for_lock_protocol(int id);
/**
* @private
* Do a syscall for opening a generic lock
*/
int od_openx(int fd, obj_type_t type, int obj_id, void* config);
/**
* Close a lock, given its object descriptor
* @param od Object descriptor for lock to close
* @return 0 Iff the lock was successfully closed
*/
int od_close(int od);
/**
* @private
* Generic lock opening method
*/
static inline int od_open(int fd, obj_type_t type, int obj_id)
{
return od_openx(fd, type, obj_id, 0);
}
/**
* public:
* Open a lock, mark it used by the invoking thread
* @param protocol Desired locking protocol
* @param lock_id Name of the lock, user-specified numerical id
* @param name_space Path to a shared file
* @param config_param Any extra info needed by the protocol (like CPU for SRP
* or PCP), may be NULL
* @return Object descriptor for this lock
*/
int litmus_open_lock(obj_type_t protocol, int lock_id, const char* name_space,
void *config_param);
/**
* Obtain lock
* @param od Object descriptor obtained by litmus_open_lock()
* @return 0 iff the lock was opened successfully
*/
int litmus_lock(int od);
/**
* Release lock
* @param od Object descriptor obtained by litmus_open_lock()
* @return 0 iff the lock was released successfully
*/
int litmus_unlock(int od);
/***** job control *****/
/**
* @todo Doxygen
*/
int get_job_no(unsigned int* job_no);
/**
* @todo Doxygen
*/
int wait_for_job_release(unsigned int job_no);
/**
* Sleep until next period
* @return 0 on success
*/
int sleep_next_period(void);
/**
* Initialises real-time properties for the entire program
* @return 0 on success
*/
int init_litmus(void);
/**
* Initialises real-time properties for current thread
* @return 0 on success
*/
int init_rt_thread(void);
/**
* Cleans up real-time properties for the entire program
*/
void exit_litmus(void);
/* per-task modes */
enum rt_task_mode_t {
BACKGROUND_TASK = 0,
LITMUS_RT_TASK = 1
};
/**
* Set the task mode for current thread
* @param target_mode Desired mode, see enum rt_task_mode_t for valid values
* @return 0 iff taskmode was set correctly
*/
int task_mode(int target_mode);
/**
* @todo Document
*/
void show_rt_param(struct rt_task* tp);
/**
* @todo Document
*/
task_class_t str2class(const char* str);
/**
* Enter non-preemtpive section for current thread
*/
void enter_np(void);
/**
* Exit non-preemtpive section for current thread
*/
void exit_np(void);
/**
* Find out whether task should have preempted
* @return 1 iff the task was requested to preempt while running non-preemptive
*/
int requested_to_preempt(void);
/***** Task System support *****/
/**
* Wait until task master releases all real-time tasks
* @return 0 Iff task was successfully released
*/
int wait_for_ts_release(void);
/**
* Release all tasks in the task system
* @param when Time of the synchronous release (w.r.t. CLOCK_MONOTONIC)
* @return Number of tasks released
*
* Used by a task master to release all threads after each of them has been
* set up.
*/
int release_ts(lt_t *when);
/**
* Obtain the number of currently waiting tasks
* @return The number of waiting tasks
*/
int get_nr_ts_release_waiters(void);
/**
* @todo Document
*/
int read_litmus_stats(int *ready, int *total);
/**
* Sleep for given time
* @param timeout Sleep time in nanoseconds
* @return 0 on success
*/
int lt_sleep(lt_t timeout);
/**
* Sleep until the given point in time.
* @param wake_up_time Point in time when to wake up (w.r.t. CLOCK_MONOTONIC,
* in nanoseconds).
*/
void lt_sleep_until(lt_t wake_up_time);
/** Get the current time used by the LITMUS^RT scheduler.
* This is just CLOCK_MONOTONIC and hence the same
* as monotime(), but the result is given in nanoseconds
* as a value of type lt_t.
* @return CLOCK_MONOTONIC time in nanoseconds
*/
lt_t litmus_clock(void);
/**
* Obtain CPU time consumed so far
* @return CPU time in seconds
*/
double cputime(void);
/**
* Obtain wall-clock time
* @return Wall-clock time in seconds
*/
double wctime(void);
/**
* Obtain CLOCK_MONOTONIC time
* @return CLOCK_MONOTONIC time in seconds
*/
double monotime(void);
/**
* Sleep until the given point in time.
* @param wake_up_time Point in time when to wake up (w.r.t. CLOCK_MONOTONIC)
*/
void sleep_until_mono(double wake_up_time);
/**
* Sleep until the given point in time.
* @param wake_up_time Point in time when to wake up (w.r.t. CLOCK_REALTIME)
*/
void sleep_until_wc(double wake_up_time);
/***** semaphore allocation ******/
/**
* Allocate a semaphore following the FMLP protocol
* @param fd File descriptor to associate lock with
* @param name Name of the lock, user-chosen integer
* @return Object descriptor for given lock
*/
static inline int open_fmlp_sem(int fd, int name)
{
return od_open(fd, FMLP_SEM, name);
}
/**
* Allocate a semaphore following the SRP protocol
* @param fd File descriptor to associate lock with
* @param name Name of the lock, user-chosen integer
* @return Object descriptor for given lock
*/
static inline int open_srp_sem(int fd, int name)
{
return od_open(fd, SRP_SEM, name);
}
/**
* Allocate a semaphore following the PCP protocol
* @param fd File descriptor to associate lock with
* @param name Name of the lock, user-chosen integer
* @param cpu CPU to associate this lock with
* @return Object descriptor for given lock
*/
static inline int open_pcp_sem(int fd, int name, int cpu)
{
return od_openx(fd, PCP_SEM, name, &cpu);
}
/**
* Allocate a semaphore following the MPCP protocol
* @param fd File descriptor to associate lock with
* @param name Name of the lock, user-chosen integer
* @return Object descriptor for given lock
*/
static inline int open_mpcp_sem(int fd, int name)
{
return od_open(fd, MPCP_SEM, name);
}
/**
* Allocate a semaphore following the DPCP protocol
* @param fd File descriptor to associate lock with
* @param name Name of the lock, user-chosen integer
* @param cpu CPU to associate this lock with
* @return Object descriptor for given lock
*/
static inline int open_dpcp_sem(int fd, int name, int cpu)
{
return od_openx(fd, DPCP_SEM, name, &cpu);
}
/**
* Allocate a semaphore following the DFLP protocol
* @param fd File descriptor to associate lock with
* @param name Name of the lock, user-chosen integer
* @param cpu CPU to associate this lock with
* @return Object descriptor for given lock
*/
static inline int open_dflp_sem(int fd, int name, int cpu)
{
return od_openx(fd, DFLP_SEM, name, &cpu);
}
/**
* Get budget information from the scheduler (in nanoseconds).
* @param expended pointer to time value in wich the total
* amount of already used-up budget will be stored.
* @param remaining pointer to time value in wich the total
* amount of remaining budget will be stored.
*/
int get_current_budget(lt_t *expended, lt_t *remaining);
/**
* Do nothing as a syscall
* @param timestamp Cyclecount before calling
* Can be used for syscall overhead measuring */
int null_call(cycles_t *timestamp);
/**
* Get control page:
* @return Pointer to the current tasks control page
*
* Atm it is used only by preemption migration overhead code,
* but it is very general and can be used for different purposes
*/
struct control_page* get_ctrl_page(void);
#ifdef __cplusplus
}
#endif
#endif
/*
* Definition of the scheduler plugin interface.
*
*/
#ifndef _LINUX_RT_PARAM_H_
#define _LINUX_RT_PARAM_H_
/* Litmus time type. */
typedef unsigned long long lt_t;
static inline int lt_after(lt_t a, lt_t b)
{
return ((long long) b) - ((long long) a) < 0;
}
#define lt_before(a, b) lt_after(b, a)
static inline int lt_after_eq(lt_t a, lt_t b)
{
return ((long long) a) - ((long long) b) >= 0;
}
#define lt_before_eq(a, b) lt_after_eq(b, a)
/* different types of clients */
typedef enum {
RT_CLASS_HARD,
RT_CLASS_SOFT,
RT_CLASS_BEST_EFFORT
} task_class_t;
typedef enum {
NO_ENFORCEMENT, /* job may overrun unhindered */
QUANTUM_ENFORCEMENT, /* budgets are only checked on quantum boundaries */
PRECISE_ENFORCEMENT /* budgets are enforced with hrtimers */
} budget_policy_t;
/* Release behaviors for jobs. PERIODIC and EARLY jobs
must end by calling sys_complete_job() (or equivalent)
to set up their next release and deadline. */
typedef enum {
/* Jobs are released sporadically (provided job precedence
constraints are met). */
TASK_SPORADIC,
/* Jobs are released periodically (provided job precedence
constraints are met). */
TASK_PERIODIC,
/* Jobs are released immediately after meeting precedence
constraints. Beware this can peg your CPUs if used in
the wrong applications. Only supported by EDF schedulers. */
TASK_EARLY
} release_policy_t;
/* We use the common priority interpretation "lower index == higher priority",
* which is commonly used in fixed-priority schedulability analysis papers.
* So, a numerically lower priority value implies higher scheduling priority,
* with priority 1 being the highest priority. Priority 0 is reserved for
* priority boosting. LITMUS_MAX_PRIORITY denotes the maximum priority value
* range.
*/
#define LITMUS_MAX_PRIORITY 512
#define LITMUS_HIGHEST_PRIORITY 1
#define LITMUS_LOWEST_PRIORITY (LITMUS_MAX_PRIORITY - 1)
#define LITMUS_NO_PRIORITY UINT_MAX
/* Provide generic comparison macros for userspace,
* in case that we change this later. */
#define litmus_higher_fixed_prio(a, b) (a < b)
#define litmus_lower_fixed_prio(a, b) (a > b)
#define litmus_is_valid_fixed_prio(p) \
((p) >= LITMUS_HIGHEST_PRIORITY && \
(p) <= LITMUS_LOWEST_PRIORITY)
/* reservation support */
typedef enum {
PERIODIC_POLLING = 10,
SPORADIC_POLLING,
TABLE_DRIVEN,
} reservation_type_t;
struct lt_interval {
lt_t start;
lt_t end;
};
#ifndef __KERNEL__
#define __user
#endif
struct reservation_config {
unsigned int id;
lt_t priority;
int cpu;
union {
struct {
lt_t period;
lt_t budget;
lt_t relative_deadline;
lt_t offset;
} polling_params;
struct {
lt_t major_cycle_length;
unsigned int num_intervals;
struct lt_interval __user *intervals;
} table_driven_params;
};
};
/* regular sporadic task support */
struct rt_task {
lt_t exec_cost;
lt_t period;
lt_t relative_deadline;
lt_t phase;
unsigned int cpu;
unsigned int priority;
task_class_t cls;
budget_policy_t budget_policy; /* ignored by pfair */
release_policy_t release_policy;
};
/* don't export internal data structures to user space (liblitmus) */
#ifdef __KERNEL__
struct _rt_domain;
struct bheap_node;
struct release_heap;
struct rt_job {
/* Time instant the the job was or will be released. */
lt_t release;
/* What is the current deadline? */
lt_t deadline;
/* How much service has this job received so far? */
lt_t exec_time;
/* By how much did the prior job miss its deadline by?
* Value differs from tardiness in that lateness may
* be negative (when job finishes before its deadline).
*/
long long lateness;
/* Which job is this. This is used to let user space
* specify which job to wait for, which is important if jobs
* overrun. If we just call sys_sleep_next_period() then we
* will unintentionally miss jobs after an overrun.
*
* Increase this sequence number when a job is released.
*/
unsigned int job_no;
#ifdef CONFIG_SCHED_TASK_TRACE
/* Keep track of the last time the job suspended.
* -> used for tracing sporadic tasks. */
lt_t last_suspension;
#endif
};
struct pfair_param;
/* RT task parameters for scheduling extensions
* These parameters are inherited during clone and therefore must
* be explicitly set up before the task set is launched.
*/
struct rt_param {
/* do we need to check for srp blocking? */
unsigned int srp_non_recurse:1;
/* is the task present? (true if it can be scheduled) */
unsigned int present:1;
/* has the task completed? */
unsigned int completed:1;
#ifdef CONFIG_LITMUS_LOCKING
/* Is the task being priority-boosted by a locking protocol? */
unsigned int priority_boosted:1;
/* If so, when did this start? */
lt_t boost_start_time;
/* How many LITMUS^RT locks does the task currently hold/wait for? */
unsigned int num_locks_held;
/* How many PCP/SRP locks does the task currently hold/wait for? */
unsigned int num_local_locks_held;
#endif
/* user controlled parameters */
struct rt_task task_params;
/* timing parameters */
struct rt_job job_params;
/* Special handling for periodic tasks executing
* clock_nanosleep(CLOCK_MONOTONIC, ...).
*/
lt_t nanosleep_wakeup;
unsigned int doing_abs_nanosleep:1;
/* Should the next job be released at some time other than
* just period time units after the last release?
*/
unsigned int sporadic_release:1;
lt_t sporadic_release_time;
/* task representing the current "inherited" task
* priority, assigned by inherit_priority and
* return priority in the scheduler plugins.
* could point to self if PI does not result in
* an increased task priority.
*/
struct task_struct* inh_task;
#ifdef CONFIG_NP_SECTION
/* For the FMLP under PSN-EDF, it is required to make the task
* non-preemptive from kernel space. In order not to interfere with
* user space, this counter indicates the kernel space np setting.
* kernel_np > 0 => task is non-preemptive
*/
unsigned int kernel_np;
#endif
/* This field can be used by plugins to store where the task
* is currently scheduled. It is the responsibility of the
* plugin to avoid race conditions.
*
* This used by GSN-EDF and PFAIR.
*/
volatile int scheduled_on;
/* Is the stack of the task currently in use? This is updated by
* the LITMUS core.
*
* Be careful to avoid deadlocks!
*/
volatile int stack_in_use;
/* This field can be used by plugins to store where the task
* is currently linked. It is the responsibility of the plugin
* to avoid race conditions.
*
* Used by GSN-EDF.
*/
volatile int linked_on;
/* PFAIR/PD^2 state. Allocated on demand. */
union {
void *plugin_state;
struct pfair_param *pfair;
};
/* Fields saved before BE->RT transition.
*/
int old_policy;
int old_prio;
/* ready queue for this task */
struct _rt_domain* domain;
/* heap element for this task
*
* Warning: Don't statically allocate this node. The heap
* implementation swaps these between tasks, thus after
* dequeuing from a heap you may end up with a different node
* then the one you had when enqueuing the task. For the same
* reason, don't obtain and store references to this node
* other than this pointer (which is updated by the heap
* implementation).
*/
struct bheap_node* heap_node;
struct release_heap* rel_heap;
/* Used by rt_domain to queue task in release list.
*/
struct list_head list;
/* Pointer to the page shared between userspace and kernel. */
struct control_page * ctrl_page;
};
#endif
#endif
/*
* Definition of the scheduler plugin interface.
*
*/
#ifndef _LINUX_RT_PARAM_H_
#define _LINUX_RT_PARAM_H_
/* Litmus time type. */
typedef unsigned long long lt_t;
static inline int lt_after(lt_t a, lt_t b)
{
return ((long long) b) - ((long long) a) < 0;
}
#define lt_before(a, b) lt_after(b, a)
static inline int lt_after_eq(lt_t a, lt_t b)
{
return ((long long) a) - ((long long) b) >= 0;
}
#define lt_before_eq(a, b) lt_after_eq(b, a)
/* different types of clients */
typedef enum {
RT_CLASS_HARD,
RT_CLASS_SOFT,
RT_CLASS_BEST_EFFORT
} task_class_t;
typedef enum {
NO_ENFORCEMENT, /* job may overrun unhindered */
QUANTUM_ENFORCEMENT, /* budgets are only checked on quantum boundaries */
PRECISE_ENFORCEMENT /* budgets are enforced with hrtimers */
} budget_policy_t;
/* Release behaviors for jobs. PERIODIC and EARLY jobs
must end by calling sys_complete_job() (or equivalent)
to set up their next release and deadline. */
typedef enum {
/* Jobs are released sporadically (provided job precedence
constraints are met). */
TASK_SPORADIC,
/* Jobs are released periodically (provided job precedence
constraints are met). */
TASK_PERIODIC,
/* Jobs are released immediately after meeting precedence
constraints. Beware this can peg your CPUs if used in
the wrong applications. Only supported by EDF schedulers. */
TASK_EARLY
} release_policy_t;
/* We use the common priority interpretation "lower index == higher priority",
* which is commonly used in fixed-priority schedulability analysis papers.
* So, a numerically lower priority value implies higher scheduling priority,
* with priority 1 being the highest priority. Priority 0 is reserved for
* priority boosting. LITMUS_MAX_PRIORITY denotes the maximum priority value
* range.
*/
#define LITMUS_MAX_PRIORITY 512
#define LITMUS_HIGHEST_PRIORITY 1
#define LITMUS_LOWEST_PRIORITY (LITMUS_MAX_PRIORITY - 1)
#define LITMUS_NO_PRIORITY UINT_MAX
/* Provide generic comparison macros for userspace,
* in case that we change this later. */
#define litmus_higher_fixed_prio(a, b) (a < b)
#define litmus_lower_fixed_prio(a, b) (a > b)
#define litmus_is_valid_fixed_prio(p) \
((p) >= LITMUS_HIGHEST_PRIORITY && \
(p) <= LITMUS_LOWEST_PRIORITY)
/* reservation support */
typedef enum {
PERIODIC_POLLING = 10,
SPORADIC_POLLING,
TABLE_DRIVEN,
} reservation_type_t;
struct lt_interval {
lt_t start;
lt_t end;
};
#ifndef __KERNEL__
#define __user
#endif
struct reservation_config {
unsigned int id;
lt_t priority;
int cpu;
union {
struct {
lt_t period;
lt_t budget;
lt_t relative_deadline;
lt_t offset;
} polling_params;
struct {
lt_t major_cycle_length;
unsigned int num_intervals;
struct lt_interval __user *intervals;
} table_driven_params;
};
};
/* regular sporadic task support */
struct rt_task {
lt_t exec_cost;
lt_t period;
lt_t relative_deadline;
lt_t phase;
unsigned int cpu;
unsigned int priority;
task_class_t cls;
budget_policy_t budget_policy; /* ignored by pfair */
release_policy_t release_policy;
// ---new params for stationary gang sched---
volatile int gang;
volatile struct gang* gang_ptr; // a pointer like that speeds up several things no?
/* used by gst_gng. tells the scheduler quickly if a
* task is already actively being considered to be scheduled. */
volatile int tobe_scheduled;
// volatile in is_scheduled;
};
/* don't export internal data structures to user space (liblitmus) */
#ifdef __KERNEL__
struct _rt_domain;
struct bheap_node;
struct release_heap;
struct rt_job {
/* Time instant the the job was or will be released. */
lt_t release;
/* What is the current deadline? */
lt_t deadline;
/* How much service has this job received so far? */
lt_t exec_time;
/* By how much did the prior job miss its deadline by?
* Value differs from tardiness in that lateness may
* be negative (when job finishes before its deadline).
*/
long long lateness;
/* Which job is this. This is used to let user space
* specify which job to wait for, which is important if jobs
* overrun. If we just call sys_sleep_next_period() then we
* will unintentionally miss jobs after an overrun.
*
* Increase this sequence number when a job is released.
*/
unsigned int job_no;
#ifdef CONFIG_SCHED_TASK_TRACE
/* Keep track of the last time the job suspended.
* -> used for tracing sporadic tasks. */
lt_t last_suspension;
#endif
};
struct pfair_param;
/* RT task parameters for scheduling extensions
* These parameters are inherited during clone and therefore must
* be explicitly set up before the task set is launched.
*/
struct rt_param {
/* do we need to check for srp blocking? */
unsigned int srp_non_recurse:1;
/* is the task present? (true if it can be scheduled) */
unsigned int present:1;
/* has the task completed? */
unsigned int completed:1;
#ifdef CONFIG_LITMUS_LOCKING
/* Is the task being priority-boosted by a locking protocol? */
unsigned int priority_boosted:1;
/* If so, when did this start? */
lt_t boost_start_time;
/* How many LITMUS^RT locks does the task currently hold/wait for? */
unsigned int num_locks_held;
/* How many PCP/SRP locks does the task currently hold/wait for? */
unsigned int num_local_locks_held;
#endif
/* user controlled parameters */
struct rt_task task_params;
/* timing parameters */
struct rt_job job_params;
/* Special handling for periodic tasks executing
* clock_nanosleep(CLOCK_MONOTONIC, ...).
*/
lt_t nanosleep_wakeup;
unsigned int doing_abs_nanosleep:1;
/* Should the next job be released at some time other than
* just period time units after the last release?
*/
unsigned int sporadic_release:1;
lt_t sporadic_release_time;
/* task representing the current "inherited" task
* priority, assigned by inherit_priority and
* return priority in the scheduler plugins.
* could point to self if PI does not result in
* an increased task priority.
*/
struct task_struct* inh_task;
#ifdef CONFIG_NP_SECTION
/* For the FMLP under PSN-EDF, it is required to make the task
* non-preemptive from kernel space. In order not to interfere with
* user space, this counter indicates the kernel space np setting.
* kernel_np > 0 => task is non-preemptive
*/
unsigned int kernel_np;
#endif
/* This field can be used by plugins to store where the task
* is currently scheduled. It is the responsibility of the
* plugin to avoid race conditions.
*
* This used by GSN-EDF and PFAIR.
*/
volatile int scheduled_on;
/* Is the stack of the task currently in use? This is updated by
* the LITMUS core.
*
* Be careful to avoid deadlocks!
*/
volatile int stack_in_use;
/* This field can be used by plugins to store where the task
* is currently linked. It is the responsibility of the plugin
* to avoid race conditions.
*
* Used by GSN-EDF.
*/
volatile int linked_on;
/* PFAIR/PD^2 state. Allocated on demand. */
union {
void *plugin_state;
struct pfair_param *pfair;
};
/* Fields saved before BE->RT transition.
*/
int old_policy;
int old_prio;
/* ready queue for this task */
struct _rt_domain* domain;
/* heap element for this task
*
* Warning: Don't statically allocate this node. The heap
* implementation swaps these between tasks, thus after
* dequeuing from a heap you may end up with a different node
* then the one you had when enqueuing the task. For the same
* reason, don't obtain and store references to this node
* other than this pointer (which is updated by the heap
* implementation).
*/
struct bheap_node* heap_node;
struct release_heap* rel_heap;
/* Used by rt_domain to queue task in release list.
*/
struct list_head list;
/* Pointer to the page shared between userspace and kernel. */
struct control_page * ctrl_page;
};
#endif
#endif
#define TIME_UNIT 0.1
#define PERIOD_COUNT 10 // how many jobs to schedule
#define GANG_PERIOD 90 * TIME_UNIT
#define DURATION (1000000 * GANG_PERIOD * 0.001) // full runtime regardless of job count (in seconds)
\ No newline at end of file
cd "`dirname "$0"`"
sudo echo ""
sudo ./g1;
\ No newline at end of file
cd "`dirname "$0"`"
sudo echo "."
sudo ./gn_task1 &
sudo ./gn_task2 &
sudo ./gn_task3 &
sudo ./gn_task4;
\ No newline at end of file
cd "`dirname "$0"`"
sudo echo ""
sudo ./run_gang_1.sh &
sudo ./run_solo_tasks.sh;
\ No newline at end of file
#include <stdio.h>
#include <stdlib.h>
/* Include gettid() */
#include <sys/types.h>
/* Include threading support. */
#include <pthread.h>
/* include the main liblitmus header */
#include <rt_param_m.h>
#include <litmus_no_rt_param.h>
#include <task_set3.h>
#include <job_funcs.h>
#define CALL( exp ) do { \
int ret; \
ret = exp; \
if (ret != 0) \
fprintf(stderr, "%s failed: %m\n", #exp); \
else \
fprintf(stderr, "%s ok.\n", #exp); \
} while(0)
#define PERIOD GANG_PERIOD
#define DEADLINE PERIOD // implicit deadline
#define PHASE 0
#define GANG 1
#define PRIORITY 3
static int costs[] = { 35 * TIME_UNIT,
10 * TIME_UNIT,
10 * TIME_UNIT };
static int parts[] = { 0, 1, 2 };
/* 3 threads for 3 gang members
*/
#define NUM_THREADS 3
/* The information passed to each thread. Could be anything. */
struct thread_context {
int id;
};
/* The real-time thread program. Doesn't have to be the same for
* all threads. Here, we only have one that will invoke job().
*/
void* rt_thread1(void *tcontext);
void* rt_thread2(void *tcontext);
void* rt_thread3(void *tcontext);
static void (*rt_threads[]) = { rt_thread1,
rt_thread2,
rt_thread3 };
static double start;
static int a;
static noinline int busy1(void) {
if(a % NUM_THREADS == 0) {
a++;
}
return 0;
/*
double wait_time_start = wctime();
while(a % NUM_THREADS != 0) {
if(wctime() - wait_time_start > BUSY_WAIT_TIMEOUT) {
}
}
a++;
return 0;
*/
}
static noinline int busy2(void) {
if(a % NUM_THREADS == 1)
a++;
return 0;
}
static noinline int busy3(void) {
if(a % NUM_THREADS == 2)
a++;
return 0;
}
static int job(int exec_cost, int (*func)(void)) {
if(wctime() - start > DURATION)
return 1;
//loop_for(EXEC_COST * 100, 0);
be_busy(exec_cost, func);
//start = wctime();
//loop_for(EXEC_COST, 0);
return 0;
}
#define job1(cost) job(cost, busy1)
#define job2(cost) job(cost, busy2)
#define job3(cost) job(cost, busy3)
int main(int argc, char** argv) {
int i;
struct thread_context ctx[NUM_THREADS];
pthread_t task[NUM_THREADS];
/* The task is in background mode upon startup. */
/*****
* 1) Command line paramter parsing would be done here.
*/
/*****
* 2) Work environment (e.g., global data structures, file data, etc.) would
* be setup here.
*/
a = 0;
/*****
* 3) Initialize LITMUS^RT.
* Task parameters will be specified per thread.
*/
init_litmus();
/*****
* 4) Launch threads.
*/
for (i = 0; i < NUM_THREADS; i++) {
ctx[i].id = i;
pthread_create(task + i, NULL, rt_threads[i], (void *) (ctx + i));
}
/*****
* 5) Wait for RT threads to terminate.
*/
for (i = 0; i < NUM_THREADS; i++)
pthread_join(task[i], NULL);
/*****
* 6) Clean up, maybe print results and stats, and exit.
*/
return 0;
}
#define std_init() int do_exit = 0; \
struct thread_context *ctx = (struct thread_context *) tcontext; \
struct rt_task params; \
init_rt_task_param(&params); \
params.exec_cost = ms2ns(costs[ctx->id]); \
params.period = ms2ns(PERIOD); \
params.relative_deadline = ms2ns(DEADLINE); \
params.phase = ms2ns(PHASE); \
params.gang = GANG; \
params.cpu = domain_to_first_cpu(parts[ctx->id]); \
params.priority = PRIORITY; \
CALL(set_rt_task_param(gettid(), &params)); \
CALL(be_migrate_to_domain(parts[ctx->id])); \
CALL(task_mode(LITMUS_RT_TASK)); \
CALL(wait_for_ts_release()); \
start = wctime()
#define std_exit() CALL(task_mode(BACKGROUND_TASK))
void* rt_thread1(void *tcontext)
{
std_init();
// Do real-time stuff
do {
do_exit = job1(costs[ctx->id]);
//printf("%d\n", do_exit);
sleep_next_period();
} while(!do_exit);
std_exit();
return 0;
}
void* rt_thread2(void *tcontext)
{
std_init();
// Do real-time stuff
do {
do_exit = job2(costs[ctx->id]);
//printf("%d\n", do_exit);
sleep_next_period();
} while(!do_exit);
std_exit();
return 0;
}
void* rt_thread3(void *tcontext)
{
std_init();
// Do real-time stuff
do {
do_exit = job3(costs[ctx->id]);
//printf("%d\n", do_exit);
sleep_next_period();
} while(!do_exit);
//printf("a has reached %d\n", a);
std_exit();
return 0;
}
\ No newline at end of file
#include <stdio.h>
#include <stdlib.h>
/* include the main liblitmus header */
#include <rt_param_m.h>
#include <litmus_no_rt_param.h>
#include <task_set3.h>
#include <job_funcs.h>
#define CALL( exp ) do { \
int ret; \
ret = exp; \
if (ret != 0) \
fprintf(stderr, "%s failed: %m\n", #exp); \
else \
fprintf(stderr, "%s ok.\n", #exp); \
} while(0)
#define PERIOD 50 * TIME_UNIT
#define DEADLINE PERIOD // implicit deadline
#define PHASE 0
#define EXEC_COST 10 * TIME_UNIT
#define GANG -1
#define PARTITION 0
#define PRIORITY 1
int i = 0;
double start;
int job(void) {
if(wctime() - start > DURATION)
return 1;
be_busy(EXEC_COST, NULL);
return 0;
}
int main(int argc, char** argv)
{
int do_exit;
struct rt_task params;
init_rt_task_param(&params);
params.exec_cost = ms2ns(EXEC_COST);
params.period = ms2ns(PERIOD);
params.relative_deadline = ms2ns(DEADLINE);
params.phase = ms2ns(PHASE);
params.gang = GANG;
params.cpu = domain_to_first_cpu(PARTITION);
params.priority = PRIORITY;
CALL(init_litmus());
CALL(set_rt_task_param(gettid(), &params));
CALL(be_migrate_to_domain(PARTITION));
CALL(task_mode(LITMUS_RT_TASK));
CALL(wait_for_ts_release());
start = wctime();
// Do real-time stuff
do {
do_exit = job();
//printf("%d\n", do_exit);
sleep_next_period();
} while(!do_exit);
CALL(task_mode(BACKGROUND_TASK));
return 0;
}
\ No newline at end of file
#include <stdio.h>
#include <stdlib.h>
/* include the main liblitmus header */
#include <rt_param_m.h>
#include <litmus_no_rt_param.h>
#include <task_set3.h>
#include <job_funcs.h>
#define CALL( exp ) do { \
int ret; \
ret = exp; \
if (ret != 0) \
fprintf(stderr, "%s failed: %m\n", #exp); \
else \
fprintf(stderr, "%s ok.\n", #exp); \
} while(0)
#define PERIOD 20 * TIME_UNIT
#define DEADLINE PERIOD // implicit deadline
#define PHASE 10 * TIME_UNIT
#define EXEC_COST 10 * TIME_UNIT
#define GANG -1
#define PARTITION 1
#define PRIORITY 5
int i = 0;
double start;
int job(void) {
if(wctime() - start > DURATION)
return 1;
be_busy(EXEC_COST, NULL);
return 0;
}
int main(int argc, char** argv)
{
int do_exit;
struct rt_task params;
init_rt_task_param(&params);
params.exec_cost = ms2ns(EXEC_COST);
params.period = ms2ns(PERIOD);
params.relative_deadline = ms2ns(DEADLINE);
params.phase = ms2ns(PHASE);
params.gang = GANG;
params.cpu = domain_to_first_cpu(PARTITION);
params.priority = PRIORITY;
CALL(init_litmus());
CALL(set_rt_task_param(gettid(), &params));
CALL(be_migrate_to_domain(PARTITION));
CALL(task_mode(LITMUS_RT_TASK));
CALL(wait_for_ts_release());
start = wctime();
// Do real-time stuff
do {
do_exit = job();
//printf("%d\n", do_exit);
sleep_next_period();
} while(!do_exit);
CALL(task_mode(BACKGROUND_TASK));
return 0;
}
\ No newline at end of file
#include <stdio.h>
#include <stdlib.h>
/* include the main liblitmus header */
#include <rt_param_m.h>
#include <litmus_no_rt_param.h>
#include <task_set3.h>
#include <job_funcs.h>
#define CALL( exp ) do { \
int ret; \
ret = exp; \
if (ret != 0) \
fprintf(stderr, "%s failed: %m\n", #exp); \
else \
fprintf(stderr, "%s ok.\n", #exp); \
} while(0)
#define PERIOD 90 * TIME_UNIT
#define DEADLINE PERIOD // implicit deadline
#define PHASE 10 * TIME_UNIT
#define EXEC_COST 20 * TIME_UNIT
#define GANG -1
#define PARTITION 2
#define PRIORITY 2
int i = 0;
double start;
int job(void) {
if(wctime() - start > DURATION)
return 1;
be_busy(EXEC_COST, NULL);
return 0;
}
int main(int argc, char** argv)
{
int do_exit;
struct rt_task params;
init_rt_task_param(&params);
params.exec_cost = ms2ns(EXEC_COST);
params.period = ms2ns(PERIOD);
params.relative_deadline = ms2ns(DEADLINE);
params.phase = ms2ns(PHASE);
params.gang = GANG;
params.cpu = domain_to_first_cpu(PARTITION);
params.priority = PRIORITY;
CALL(init_litmus());
CALL(set_rt_task_param(gettid(), &params));
CALL(be_migrate_to_domain(PARTITION));
CALL(task_mode(LITMUS_RT_TASK));
CALL(wait_for_ts_release());
start = wctime();
// Do real-time stuff
do {
do_exit = job();
//printf("%d\n", do_exit);
sleep_next_period();
} while(!do_exit);
CALL(task_mode(BACKGROUND_TASK));
return 0;
}
\ No newline at end of file
#include <stdio.h>
#include <stdlib.h>
/* include the main liblitmus header */
#include <rt_param_m.h>
#include <litmus_no_rt_param.h>
#include <task_set3.h>
#include <job_funcs.h>
#define CALL( exp ) do { \
int ret; \
ret = exp; \
if (ret != 0) \
fprintf(stderr, "%s failed: %m\n", #exp); \
else \
fprintf(stderr, "%s ok.\n", #exp); \
} while(0)
#define PERIOD 90 * TIME_UNIT
#define DEADLINE PERIOD // implicit deadline
#define PHASE 10 * TIME_UNIT
#define EXEC_COST 25 * TIME_UNIT
#define GANG -1
#define PARTITION 2
#define PRIORITY 4
int i = 0;
double start;
int job(void) {
if(wctime() - start > DURATION)
return 1;
be_busy(EXEC_COST, NULL);
return 0;
}
int main(int argc, char** argv)
{
int do_exit;
struct rt_task params;
init_rt_task_param(&params);
params.exec_cost = ms2ns(EXEC_COST);
params.period = ms2ns(PERIOD);
params.relative_deadline = ms2ns(DEADLINE);
params.phase = ms2ns(PHASE);
params.gang = GANG;
params.cpu = domain_to_first_cpu(PARTITION);
params.priority = PRIORITY;
CALL(init_litmus());
CALL(set_rt_task_param(gettid(), &params));
CALL(be_migrate_to_domain(PARTITION));
CALL(task_mode(LITMUS_RT_TASK));
CALL(wait_for_ts_release());
start = wctime();
// Do real-time stuff
do {
do_exit = job();
//printf("%d\n", do_exit);
sleep_next_period();
} while(!do_exit);
CALL(task_mode(BACKGROUND_TASK));
return 0;
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment