Vous modifierez le code précédent pour étudier les performances d’une file implémentant la politique SRPT (Shortest Remaining Processing Time First), c’est à dire qui exécute en priorité la tâche pour laquelle il reste le moins de travail à effectuer. Comme pour la politique LIFO, il existe plusieurs variantes à cette politique:
-SRPT_pmtn: qui s’assure qu’à chaque instant, elle traite la tâche pour la quelle il reste le moins de travail à effectuer. En conséquence, elle s’interromps à chaque fois qu’une nouvelle tâche arrive dans le système et éventuellement sélectionne cette tâche si son temps de service (sa quantité de travail) est plus petite que la quantité de travail restant de la tâche en cours d’exécution.
-SPT_pmtn: fonctionne comme la précédente mais base sa décision d’ordonnancement sur le temps de service de la tâche et pas sur la quantité de travail restant.
-SPT: fait la même chose que les précédentes mais ne s’interromps pas quand une nouvelle tâche entre dans le système. Cette stratégie non préemptive revient donc à exécuter systématiquement (et d’une seule traite) la tâche dont le temps de service est le plus petit au moment de la décision d’ordonnancement.
set.seed(10)
library(plyr)
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 3.1.2
Service <- function(n=1,typeservice,x,y) {
# genere un temps de service
switch(typeservice,
det = rep(1,n),
uni = runif(n,x,y),
gamma = rgamma(n,shape=x,scale=y),
exp = rexp(n,x)
)
}
SRPT <- function(n,lambda,typeservice,x,y,policy,ServTime) {
# simulates a M/GI/1 LIFO queue with different preemption policy
# parameters:
# n : total number of jobs
# lambda : arrival rate
# typeservice : service law (det uni gamma exp)
# x ,y : parameters of the service law
# policy: npmtn, pmtn, pmtn_restart, pmtn_reset
# return value:
# vector with response time of each task assuming the queue is initially empty
A <- rexp(n,lambda) # inter arrival
t1 <- cumsum(A) # arrival dates
t2 <- rep(NA,n) # completion dates
S <- ServTime# initial service times
#### Variables that define the state of the queue
t = 0 # current time
remaining = rep(NA,n) # how much work remains to do for each task
running = NA # index of the currently running task
waiting = c() # stack with tasks which have arrived and have not been completed yet
next_arrival = 1 # index of the next task to arrive
#### A few useful local functions
run_task = function() { #runs the last task of the waiting list
tab<-c()
nbWaiting=length(waiting)
if(nbWaiting>0) {
if (policy=="spt_pmtn"|| policy=="spt"){ # Ces deux politiques se base sur la même chose : le temps de service (le plus petit)
for (i in 1:nbWaiting){
tab<-c(tab,S[waiting[i]]) #concaténe tab et le temps de service du iéme tache en attente
}
running<<-waiting[which.min(tab)] #récupére la plus petit tache (en temps de service)
}
if (policy=="srpt_pmtn"){ #Dans le cas de SRPT préemptif, il faut se baser sur le temps de travail restant
for (i in 1:nbWaiting){
tab<-c(tab,min(S[waiting[i]],remaining[waiting[i]],na.rm=TRUE)) # min entre le temps de service et le temps travail restant
}
running<<-waiting[which.min(tab)]
}
remaining[running] <<- switch(policy,
srpt_pmtn = min(S[running],remaining[running],na.rm=T),
spt = S[running],
spt_pmtn = min(S[running],remaining[running],na.rm=T)
)
waiting <<- waiting[-(which.min(tab))]
}
}
push_task = function() { # insert the next_arrival-th task to the waiting list
# and run it if there is preemption
if(policy != "spt") {
if(!is.na(running)) {waiting <<- c(waiting,running)}
running <<- NA
}
waiting <<- c(waiting,next_arrival)
next_arrival <<- next_arrival+1
if(is.na(running)) { run_task() }
}
#### Main simulation loop
while(TRUE) {
# Look for next event
dt = NA
if(next_arrival <=n) { dt = min(dt,(t1[next_arrival]-t), na.rm=T) }
if(!is.na(running)) { dt = min(dt,remaining[running], na.rm=T) }
if(is.na(dt)) { break }
# Update state
t=t+dt
if(!is.na(running)) {
remaining[running] = remaining[running] - dt
if(remaining[running]<=0) {
t2[running] = t
running = NA
run_task()
}
}
if((next_arrival<=n) & (t==t1[next_arrival])) {
push_task()
}
}
df <- data.frame(N=n,TEMPS = (t2 - t1),ID=c(1:n), S=S,LAMBDA = lambda, LOI = typeservice, POLICY = policy, LABEL = as.factor(paste(typeservice, "(", x, ",", y, ")", sep = "")))
return (df)
}
Vous évaluerez les performances (en terme de temps de réponse moyen) de ces différentes stratégies et les comparerez à celle de la politique FIFO.
FileFIFO <- function(n,lambda,typeservice,x,y,ServTime) {
# genere une trajectoire de temps de reponse pour une file M/GI/1 FIFO
# parametres :
# n : taille de la trajectoire
# lambda : debit d'arrivee
# typeservice : type de service (det uni gamma exp)
# x ,y : parametres de la loi de service
# ServTime : vecteur de temps de service
# valeur de retour :
# vecteur de n valeurs successives du temps de
# réponse dans une M/GI/1 FIFO initialement vide
# generation des arrivees et des temps de service
A <- rexp(n,lambda)
t1 <- cumsum(A)
S <- ServTime
# initialisation des structures (pour éviter une allocation dynamique et gagner du temps)
t2 <- seq(0,0,length.out=n)
# Par curiosité comptons également le nombre de fois où le système se vide
sys_vide = 1
# initialisation du premier terme
t2[1] <- t1[1]+ S[1]
# calcul de la trajectoire equation de recurrence de Lindley
for (i in 2:n) {
t2[i] <- S[i] + max(t1[i], t2[i-1])
if(t1[i]>t2[i-1]) {
sys_vide = sys_vide + 1
}
}
df <- data.frame(N=n,TEMPS = (t2 - t1), ID=c(1:n) ,S=S, LAMBDA = lambda, LOI = typeservice, POLICY = "fifo", LABEL = as.factor(paste(typeservice, "(", x, ",", y, ")", sep = "")))
return (df)
}
#data frame resultat aux différent appel a SRPT
r <- data.frame()
#définition du temps de service pour l'ensemble des politiques
ServTime=Service(n=20000,"exp",1,0)
#lambda à tester.
lambda_values = c(0.01,.15,.25,.35,.45,.55,.65,.75,.85)
# Loi exponentielle, FIFO.
for (i in lambda_values) {
r <- rbind(r, FileFIFO(n=20000, i,"exp",1,0,ServTime))
}
# Loi exponentielle, mode non préemptif en fonction du temps de service .
for (i in lambda_values) {
r <- rbind(r, SRPT(n=20000, i,"exp",1,0, policy="spt_pmtn",ServTime))
}
# Loi exponentielle, mode non préemptif.
for (i in lambda_values) {
r <- rbind(r, SRPT(n=20000, i,"exp",1,0, policy="spt",ServTime))
}
# Loi exponentielle, mode préemptif en fonction de remaining restant.
for (i in lambda_values){
r <- rbind(r, SRPT(n=20000, i,"exp",1,0, policy="srpt_pmtn",ServTime))
}
rf <- ddply(r, c("LAMBDA", "POLICY"), summarize, TempsMoyen = mean(TEMPS),
vari = var(TEMPS),ecart = 2*sd(TEMPS)/sqrt(length(TEMPS)))
ggplot(rf, aes(x = LAMBDA, y = TempsMoyen , ymin = TempsMoyen - ecart, ymax = TempsMoyen + ecart, color =POLICY)) + geom_point() + geom_line()+geom_errorbar() + geom_vline(xintercept = 1)+geom_vline(yintercept = 0) + xlab("Lambda") + ylab("Temps de service moyen ") +labs(name = "Type :", colour = " Type :")
Aprés cette simulation, on peut tout d’abord remarquer que la courbe rouge (FIFO) a son temps de service moyen toujours au autres (SRPT)
La politique SPT commence à augmenter avant les autres politiques. la politique SRPT_pmtn est un peu plus faible au niveau du temps de service moyen car on se base sur le temps de travail restant.
Vous étudierez également la distribution du temps de réponse et en particulier les valeurs extrêmes comme le temps de réponse maximum).
On va etudier le temps de traitement et le temps de service
Avec FileFifo :
r <- data.frame()
lambda_values = c(0.01,.15,.25,.35,.45,.55,.65,.75,.85)
TimeServ=Service(n=150,"exp",1,0)
for (i in lambda_values){
r <- FileFIFO(n=150, i,"exp",1,0,TimeServ)
}
ggplot(r) +
geom_bar(aes(x = factor(ID), y = TEMPS),stat="identity", position="identity",fill="blue") +
geom_bar(aes(x = factor(ID), y = S),stat="identity", position="identity",fill="yellow") +
xlab("job ID") +
ylab("duréé") +
ggtitle("temps de service et traitement avec FIFO")
Avec spt_pmtn :
r <- data.frame()
TimeServ=Service(n=150,"exp",1,0)
lambda_values = c(0.01,.15,.25,.35,.45,.55,.65,.75,.85)
for (i in lambda_values) {
r <- SRPT(n=150, i,"exp",1,0, policy="spt_pmtn",TimeServ)
}
ggplot(r) +
geom_bar(aes(x = factor(ID), y = TEMPS),stat="identity", position="identity",fill="blue") +
geom_bar(aes(x = factor(ID), y = S),stat="identity", position="identity",fill="yellow",alpha=.8) +
xlab("job ID") +
ylab("durée") +
ggtitle("temps de service et traitement avec SPT_pmtn")
Avec SRPT_PMTN :
r <- data.frame()
TimeServ=Service(n=150,"exp",1,0)
lambda_values = c(0.01,.15,.25,.35,.45,.55,.65,.75,.85)
for (i in lambda_values) {
r <- SRPT(n=150, i,"exp",1,0, policy="srpt_pmtn",TimeServ)
}
ggplot(r) +
geom_bar(aes(x = factor(ID), y = TEMPS),stat="identity", position="identity",fill="blue") +
geom_bar(aes(x = factor(ID), y = S),stat="identity", position="identity",fill="yellow",alpha=.8) +
xlab("job ID") +
ylab("durée") +
ggtitle("temps de service et traitement avec SRPT_PMTN")
avec SPT :
r <- data.frame()
TimeServ=Service(n=150,"exp",1,0)
lambda_values = c(0.01,.15,.25,.35,.45,.55,.65,.75,.85)
for (i in lambda_values) {
r <- SRPT(n=150, i,"exp",1,0, policy="spt",TimeServ)
}
ggplot(r) +
geom_bar(aes(x = factor(ID), y = TEMPS),stat="identity", position="identity",fill="blue") +
geom_bar(aes(x = factor(ID), y = S),stat="identity", position="identity",fill="yellow",alpha=.8) +
xlab("job ID") +
ylab("durée") +
ggtitle("temps de service et traitement avec SPT")
En bleu, c’est le temps de service et en jaune c’est le temps de traitement (t2-t1) On remarque que le temps de service n’affecte pas le temps de traitement pour FIFO Par contre pour les 3 autres politiques, le temps de traitement est affecté par le temps de service car cette politique est basé dessus.