Ce devoir maison a pour objectif de comparer le performances de trois politiques d’ordonnancements, suivant un taux d’arrivée modélisé par trois lois différentes.
# Adding libraries
library(ggplot2)
library(dplyr);
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
# setting random things
set.seed(37);
# functions to generate graphs
trace_simple = function(x_data, y_data){
plot(x_data, y_data);
}
trace_response_time= function(data){
# d'après le stub
data %>% group_by(lambda) %>% summarise(resp_mean = mean(Completion-Arrival), se = sd(Completion-Arrival)/sqrt(n())) %>%
ggplot(aes(x=lambda, y=resp_mean)) + geom_point() + geom_line(color='red') + geom_errorbar(aes(ymin =resp_mean-2*se, ymax=resp_mean+2*se))
}
trace_completion_time = function(data){
# on perd en visibilité quand N >>
ggplot(data, aes(xmin = Completion-Service, xmax= Completion, ymin=Idx, ymax=Idx+1)) + geom_rect()
}
Paramètres : - Le nombre de jobs : N = 1000 - Le taux d’arrivée dans le système : lambda (variable) - Le taux de service du système : mu = 1
N = 1000;
mu = 1;
simul_fifo = function(N = 1000, lambda = 0.1, Service = Service, mu = 1){
Arrival = cumsum(rexp(n=N, rate = lambda)); # exponential
Service = Service;
Remaining = rep(N, x=NA);
Completion = rep(N, x=NA);
t = 0;
CurrentTask = NA;
NextArrival = 1;
while (TRUE) {
dtA = NA;
dtC = NA;
if(length(Arrival[Arrival>t])>0) {
dtA = head(Arrival[Arrival>t],n=1)-t # temps jusqu'à la prochaine arrivée
}
if(!is.na(CurrentTask)) {
dtC = Remaining[CurrentTask]; # temps jusqu'à la prochaine terminaison
}
if(is.na(dtA) & is.na(dtC)) {
break;
}
dt = min(dtA,dtC,na.rm=T)
# Mettre à jour comme il faut:
# la date
t = t + dt;
# les arrivées
if((NextArrival <=N) & (Arrival[NextArrival] <= t)) { ## je met un <= et pas un == car 3-2.9!=0.1 ...
Remaining[NextArrival] = Service[NextArrival];
NextArrival = NextArrival + 1;
}
# le remaining
if(!is.na(CurrentTask)) {
Remaining[CurrentTask] = Remaining[CurrentTask] - dt ;
if(Remaining[CurrentTask] <= 0) {
Completion[CurrentTask] = t;
Remaining[CurrentTask] = NA;
}
CurrentTask = NA;
}
# et currentTask (politique d'ordonnancement: FIFO)
WaitingList=(1:N)[!is.na(Remaining)];
if(length(WaitingList)>0) {
CurrentTask = head(WaitingList,n=1);
}
}
# print(Completion);
return(data.frame(Arrival, Completion, lambda, Idx = 1:N, Service, mu = mu, lambda = lambda));
}
# setting service
Service = runif(n=N, min = 0.5, max = 1.5);
# executing simulation
lambda = seq(from=0.05 , to= .9, by = .1);
df = data.frame();
for(l in lambda){
df = rbind(df, simul_fifo(N, lambda=l, Service = Service));
}
# plotting
trace_completion_time(df);
trace_response_time(df);
Service = rexp(n=N, rate = 1);
# executing simulation
lambda = seq(from=0.05 , to= .9, by = .1);
df = data.frame();
for(l in lambda){
df = rbind(df, simul_fifo(N, lambda=l, Service = Service));
}
# plotting
trace_completion_time(df);
trace_response_time(df);
Service = rgamma(n=N, 0.1, 0.1);
# executing simulation
lambda = seq(from=0.05 , to= .9, by = .1);
df = data.frame();
for(l in lambda){
df = rbind(df, simul_fifo(N, lambda=l, Service = Service));
}
# plotting
trace_completion_time(df);
trace_response_time(df);
simul_spt = function(N = 1000, lambda = 0.1, Service = Service){
Arrival = cumsum(rexp(n=N, rate = lambda)); # exponential
Service = Service;
Remaining = rep(N, x=NA);
Completion = rep(N, x=NA);
t = 0;
CurrentTask = NA;
NextArrival = 1;
while (TRUE) {
dtA = NA;
dtC = NA;
if(length(Arrival[Arrival>t])>0) {
dtA = head(Arrival[Arrival>t],n=1)-t # temps jusqu'à la prochaine arrivée
}
if(!is.na(CurrentTask)) {
dtC = Remaining[CurrentTask]; # temps jusqu'à la prochaine terminaison
}
if(is.na(dtA) & is.na(dtC)) {
break;
}
dt = min(dtA,dtC,na.rm=T)
# Mettre à jour comme il faut:
# la date
t = t + dt;
# les arrivées
if((NextArrival <=N) & (Arrival[NextArrival] <= t)) { ## je met un <= et pas un == car 3-2.9!=0.1 ...
Remaining[NextArrival] = Service[NextArrival];
NextArrival = NextArrival + 1;
}
# le remaining
if(!is.na(CurrentTask)) {
Remaining[CurrentTask] = Remaining[CurrentTask] - dt ;
if(Remaining[CurrentTask] <= 0) {
Completion[CurrentTask] = t;
Remaining[CurrentTask] = NA;
}
CurrentTask = NA;
}
# et currentTask (politique d'ordonnancement: SPT)
WaitingList=(1:N)[!is.na(Remaining)];
if(length(WaitingList)>0) {
# here we choose the task that has the mininal time to complete
# old : CurrentTask = head(WaitingList,n=1);
CurrentTask = head(WaitingList,n=1);
for(job in WaitingList){
CurrentTask = min(CurrentTask, job);
}
#print("Choosed job duration is (currenttask is)");
#print(CurrentTask);
}
}
# print(Completion);
return(data.frame(Arrival, Completion, lambda, Idx = 1:N, Service));
# TODO
# return(data.frame(lambda=lambda, mu=mu, idx = 1:N, arrival = Arrival, completion = Completion, service = Service))
}
Service = runif(n=N, min = 0.5, max = 1.5);
# executing simulation
lambda = seq(from=0.05 , to= .9, by = .1);
df = data.frame();
for(l in lambda){
df = rbind(df, simul_spt(N=100, lambda=l, Service = Service));
}
# plotting
trace_completion_time(df);
trace_response_time(df);
Nous ne saurions expliquer ce pic à lambda ~ 0.55.
Service = rexp(n=N, rate = 1);
# executing simulation
lambda = seq(from=0.05 , to= .9, by = .1);
df = data.frame();
for(l in lambda){
df = rbind(df, simul_spt(N, lambda=l, Service = Service));
}
# plotting
trace_completion_time(df);
trace_response_time(df);
Service = rgamma(n=N, 0.1, 0.1);
# executing simulation
lambda = seq(from=0.05 , to= .9, by = .1);
df = data.frame();
for(l in lambda){
df = rbind(df, simul_spt(N=100, lambda=l, Service = Service));
}
# plotting
trace_completion_time(df);
trace_response_time(df);
simul_lifop = function(N = 1000, lambda = 0.1, Service = Service){
preemption_number = 0;
Arrival = cumsum(rexp(n=N, rate = lambda)); # exponential
#print(Arrival);
Service = Service;
Remaining = rep(N, x=NA);
#print("Remaining :")
#print(Remaining);
Completion = rep(N, x=NA);
t = 0;
CurrentTask = NA;
NextArrival = 1;
while (TRUE) {
#print(t);
#print(Arrival);
#print(Service);
#print(Remaining);
dtA = NA;
dtC = NA;
if(length(Arrival[Arrival>t])>0) {
dtA = head(Arrival[Arrival>t],n=1)-t # temps jusqu'à la prochaine arrivée
}
if(!is.na(CurrentTask)) {
dtC = Remaining[CurrentTask]; # temps jusqu'à la prochaine terminaison
}
# if t + remaining[currentask] < arrival (de next task) then préempter else continuer ??
#print(dtA);
#print(dtC);
if(is.na(dtA) & is.na(dtC)) {
#print("one value is na");
break;
}
dt = min(dtA,dtC,na.rm=T);
if(!is.na(dtA) & !is.na(dtC)){
if(dtC > dtA){
#print("current task has been preempted");
preemption_number = preemption_number + 1;
Remaining[CurrentTask] = t - dtA;
}
}
# Mettre à jour comme il faut:
# la date
t = t + dt;
# les arrivées
if((NextArrival <=N) & (Arrival[NextArrival] <= t)) {
Remaining[NextArrival] = Service[NextArrival];
NextArrival = NextArrival + 1;
}
# le remaining
if(!is.na(CurrentTask)) {
Remaining[CurrentTask] = Remaining[CurrentTask] - dt ;
if(Remaining[CurrentTask] <= 0) {
Completion[CurrentTask] = t;
Remaining[CurrentTask] = NA;
}
CurrentTask = NA;
}
# et currentTask
WaitingList=(1:N)[!is.na(Remaining)];
if(length(WaitingList)>0) {
CurrentTask = tail(WaitingList,n=1); # tail for LIFO
}
}
# print(Completion);
#message("Preemption number : ", preemption_number);
return(data.frame(Arrival, Completion, lambda, Idx = 1:N, Service, mu=mu));
}
Service = runif(n=N, min = 0.5, max = 1.5);
# executing simulation
lambda = seq(from=0.05 , to= .9, by = .1);
df = data.frame();
for(l in lambda){
df = rbind(df, simul_lifop(N=1000, lambda=l, Service = Service));
}
# plotting
trace_completion_time(df);
trace_response_time(df);
Contrairement aux deux précédentes politiques, le temps moyen de réponse croît plus rapidement lorsque lambda augmente.
Service = rexp(n=N, rate = 1);
# executing simulation
lambda = seq(from=0.05 , to= .9, by = .1);
df = data.frame();
for(l in lambda){
df = rbind(df, simul_lifop(N, lambda=l, Service = Service));
}
# plotting
trace_completion_time(df);
trace_response_time(df);
Service = rgamma(n=N, 0.1, 0.1);
# executing simulation
lambda = seq(from=0.05 , to= .9, by = .1);
df = data.frame();
for(l in lambda){
df = rbind(df, simul_lifop(N=100, lambda=l, Service = Service));
}
# plotting
trace_completion_time(df);
On remarque que certaines tâches ne sont exécutées très tardivement…
# plotting
trace_response_time(df);
Oula. Si ce n’est pas causé par une mauvaise implantation de LIFO-préempté (cela comforte notre première remarque), et même si l’amplitude est importante, la temps moyen de réponse semble être assez stationnaire (on pourrait faire une “régression linéaire” pour le vérifier), et “n’explose” pas comme sur les autres politiques pour la même loi.
On remarque que plus lambda est grand, plus l’intervalle de confiance (représentée par les barres sur ggplot) devient important.
D’après les graphiques générés pour les deux premières politiques (FIFO et SPT), il est assez difficile de montrer quelle politique est la plus performante, mais on remarque que le temps de réponse croît légèrement moins vite pour SPT.
Dans le cas du LIFO préempté, le temps moyen de réponse augmente rapidement, mais à tendance à se stabiliser lorsque le taux d’arrivé augmente.
Note : dans certains graphes de montrant le temps de complétion, on ne voit pas/peu les points car N est assez important. Il faut alors le réduire.