set.seed(37);

serveur = function(N=100, arrival_rate=.2, processing_rate=1, debug=FALSE, E0=.5, E1=1) {
    Arrival = cumsum(rexp(n=N, rate=arrival_rate));  
    Service = rexp(n=N, rate =processing_rate); # rep(N,x=1); rgamma(N, shape=.1,rate=.1)
    Remaining = rep(N, x=NA);
    Completion = rep(N, x=NA)
    t = 0;
    CurrentTask = NA;
    NextArrival = 1;
    E_tot= 0;
    while (TRUE) {
        if(debug) print(t)
        if(debug) print(Arrival);
        if(debug) print(Service);
        if(debug) 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(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 ;
            #Ici une tache est en train d'etre executé nous augmentons donc l'energie de E1 * dt
            E_tot = E_tot +E1*dt
            if(Remaining[CurrentTask] <= 0) {
                Completion[CurrentTask] = t;
                Remaining[CurrentTask] = NA;
            }
            CurrentTask = NA;
        }else{
          #Ici il n'y a pas de tache qui est executé alors nous augmenter l'energie de E0 *dt
          E_tot =E_tot + E0 * dt
        }
        #   et currentTask (politique d'ordonnancement: FIFO)
        WaitingList=(1:N)[!is.na(Remaining)];
        if(length(WaitingList)>0) {
            CurrentTask = head(WaitingList,n=1);
        }
    }
    if(debug) print(Completion)
    return(data.frame(
        Arrival_rate=arrival_rate,
        Processing_rate=processing_rate,
        Arrival = Arrival,
        Service = Service,
        Completion = Completion,
        Energie = E_tot/t
        ))
        
}

serveur3 = function(N=100, arrival_rate=.2, processing_rate=1, processing_rate2=2, debug=FALSE, E0=.5, E1=1, E2=.25, E3=4) {
    Arrival = cumsum(rexp(n=N, rate=arrival_rate));
    Service = rexp(n=N, rate =processing_rate); # rep(N,x=1); rgamma(N, shape=.1,rate=.1)
    Service2 =rexp(n=N, rate =processing_rate2);
    Remaining = rep(N, x=NA);
    Remaining2 = rep(N, x=NA);
    Completion = rep(N, x=NA);
    t = 0;
    CurrentTask = NA;
    CurrentTask2 = NA;
    NextArrival = 1;
    E_tot= 0;
    while (TRUE) {
        if(debug) print(t)
        if(debug) print(Arrival);
        if(debug) print(Service);
        if(debug) print(Remaining);
        dtA = NA;
        dtC = NA;
        dtC1 = 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(CurrentTask2)){
            dtC1 = Remaining2[CurrentTask2]; # temps jusqu'à la prochaine terminaison
        }
        if(is.na(dtA) & is.na(dtC) & is.na(dtC1)) {
            break;
        }
        dt = min(dtA,dtC,dtC1,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];
            Remaining2[NextArrival] = Service2[NextArrival];
            NextArrival = NextArrival + 1;
        }
        
       
        
         #Serveur 1
        if(!is.na(CurrentTask)) {
            Remaining[CurrentTask] = Remaining[CurrentTask] - dt ;
            #Ici une tache est en train d'etre executé nous augmentons donc l'energie de E1 * dt
            E_tot = E_tot +E1*dt
            if(Remaining[CurrentTask] <= 0) {
                Completion[CurrentTask] = t;
                Remaining[CurrentTask] = NA;
            }
            CurrentTask = NA;
        }else{
          #Ici il n'y a pas de tache qui est executé alors nous augmenter l'energie de E0 *dt
          E_tot =E_tot + E0 * dt
        }
        
        
        #Serveur 2
         if(!is.na(CurrentTask2)) {
            Remaining2[CurrentTask2] = Remaining2[CurrentTask2] - dt ;
            #Ici une tache est en train d'etre executé nous augmentons donc l'energie de E3 * dt
            E_tot = E_tot +E3*dt
            if(Remaining2[CurrentTask2] <= 0) {
                Completion[CurrentTask2] = t;
                Remaining2[CurrentTask2] = NA;
            }
            CurrentTask2 = NA;
        }else{
          #Ici il n'y a pas de tache qui est executé alors nous augmenter l'energie de E2 *dt
          E_tot =E_tot + E2 * dt
        }
        
        
        #   et currentTask (politique d'ordonnancement: FIFO)
        WaitingList=(1:N)[!is.na(Remaining)];
        if(length(WaitingList)>0) {
            CurrentTask = head(WaitingList,n=1);
            Remaining2[CurrentTask]=NA; # Nous enlevons cette tche du remaining de l'autre serveur.
        }
        
        WaitingList2=(1:N)[!is.na(Remaining2)];
        if(length(WaitingList2)>0) {
            CurrentTask2 = head(WaitingList2,n=1);
            Remaining[CurrentTask2]=NA;  # Nous enlevons cette tche du remaining de l'autre serveur.
        }
        
    }
    if(debug) print(Completion)
    return(data.frame(
        Arrival_rate=arrival_rate,
        Processing_rate=processing_rate,
        Arrival = Arrival,
        Service = Service,
        Completion = Completion,
        Energie = E_tot/t
        ))
        
}

#+begin_src R :results output :session *R* :exports both
df1 = data.frame()
for (r in  seq(from=.1, to=.9, by=.1)) {
    df1 = rbind(df1,data.frame(serveur(N=2000, arrival_rate=r, processing_rate=1, debug=FALSE, E0=.5,E1=1), Serveur="1"));
}

for (r in  seq(from=.1, to=.9, by=.1)) {
    df1 = rbind(df1,data.frame(serveur(N=2000, arrival_rate=r, processing_rate=2, debug=FALSE, E0=.25,E1=4), Serveur="2"));
}

for (r in  seq(from=.1, to=.9, by=.1)) {
    df1 = rbind(df1,data.frame(serveur3(N=2000, arrival_rate=r, processing_rate=1, processing_rate2 = 2, debug=FALSE, E0=.5,E1=1, E2=.25,E3=4), Serveur="3"));
}



#+begin_src R :results output :session *R* :exports both
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
df2 = df1 %>% group_by(Arrival_rate, Serveur) %>%
    summarize(Energie = mean(Energie),
              Response = mean(Completion - Arrival), 
              Response_se = sd(Completion - Arrival)/sqrt(n()))

#+begin_src R :results output graphics :file (org-babel-temp-file "figure" ".png") :exports both :width 600 :height 400 :session *R* 
library(ggplot2)


ggplot(df2, aes(x=Arrival_rate, y=Response, group=Serveur, color=Serveur)) + geom_line() +
    geom_errorbar(aes(ymin = Response - 2*Response_se,
                      ymax = Response + 2*Response_se))

ggplot(df1, aes(x=Arrival_rate, y=Energie, group=Serveur, color=Serveur)) + geom_line()

ggplot(df1, aes(x=Arrival_rate, y=Energie, group=Serveur, color=Serveur)) + geom_line() + coord_cartesian(x=c(0.1825,0.185), y=c(0.57,0.6))

ggplot(df1, aes(x=Arrival_rate, y=Energie, group=Serveur, color=Serveur)) + geom_line() + coord_cartesian(x=c(0.605,0.610), y=c(1.350,1.4))

Question 1

Dans le premier graphique nous pouvons voir le temps de reponse des serveurs en fonction de notre Lambda 0:1. Nous voyons ainsi que le serveur 2 est toujours plus rapide que le serveur 1.

Le croisement de la consommation energetique entre le serveur 1 et le serveur 2 est a lambda = 0.184 avant S2 est moins energetique, après S2 est plus energetique. Pour estimer cette valeur nous avons utilisé une fonction : coord_cartesian pour pouvoir zoomer

Mais en revanche pour des Lambda assez bas nous voyons que notre serveur 2 consomme moins, ceci s’explique car quand le serveur 2 fait tourner aucune tâche il consomme deux fois moins que le serveur 1. Donc quand le serveur 2 fait tourner peu de tâche il devient moins energetique

Pour conclure sur le serveur a choisir il faut savoir ce qu’on attend de notre serveur. Est-ce qu’il vas faire tourner des tâches tout le temps, ou alors quelque tâche de temps à autre ? Ou alors nous voulons un temps de réponse très rapide ?

Question 2

Concernant le seveur 3 nous avons choisi d’utiliser la méthode de doubler les attributs du serveur et de ne laisser qu’un seul champ “Arrival”. Quand un des deux serveur prend une nouvelle tâche ilfaut l’enlever du “Remaining” de l’autre serveur pour eviter de faire tourner cette dernière deux fois. Cette méthode est énergetique car nous faisons tourner les 2 serveurs mais lorsque nous avons un lambda grand nous commencons a voir sur le graphique que l’energie moyenne diminue.

Le croisement de cette consommation énergetique moyenne entre le serveur 2 et le serveur 3 est a lambda = 0.607 avant S3 est plus energetique, après S3 est moins energetique. Nous avons utilisé la même fonction que précedement.