Question 1 : Comparaison de la performance de S1 et de S2

Intuition :

Espérance du temps de réponse : Pour ce qui est du temps de réponse des serveurs, on suppose que S1 aura une espérance plus faible que S2. Son temps de service est plus faible, c’est donc logique. On peut aussi s’attendre à voir des temps de réponse croissant extrêmement rapidement lorsque les capacités de chaque serveurs sont dépassées : un taux d’inter-arrivées supérieur à 1 pour S1 et supérieur à 2 pour S2.

Espérance de la consommation énergétique : Cet aspect est plus difficile à estimer. En fonctionnement continu, le premier serveur fonctionnera de manière moins coûteuse que le second. En revanche, le mode veille du second serveur consomme moins de ressource. En liant ca au fait qu’il soit plus rapide, et passe donc plus de temps dans un état de veille, on peut s’attendre à ce que la consommation énergétique soit plus intéressante sur le second serveur pour des petits taux d’inter-arrivées.

set.seed(123)
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
simul = function(N=100, arrival_rate=.5, processing_rate=1, server="server1", energy0=.5, energy1=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;
    uptime = 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(is.na(CurrentTask) & length(WaitingList)>0) {
            CurrentTask = head(WaitingList,n=1);
            uptime = uptime + Remaining[CurrentTask]
        }
    }
    return(data.frame(
        Arrival_rate=arrival_rate,
        Processing_rate=processing_rate,
        Arrival = Arrival,
        Service = Service,
        Completion = Completion,
        Server = server,
        Energy_consumed = (uptime * energy1 + (t - uptime) * energy0) / t
        ))
        
}

df = data.frame()
for (r in  seq(from=.1, to=2.9, by=.1)) {
    df = rbind(df,simul(N=1000, arrival_rate=r, processing_rate=1, server = "server1", energy0 = .5, energy1 = 1));
}
for (r in  seq(from=.1, to=2.9, by=.1)) {
    df = rbind(df,simul(N=1000, arrival_rate=r, processing_rate=2, server = "server2", energy0 = .25, energy1 = 4));
}

df2 = df %>% group_by(Arrival_rate, Server) %>%
    summarize(Response = mean(Completion - Arrival), 
              Response_se = sd(Completion - Arrival)/sqrt(n()),
              Mean_energy = mean(Energy_consumed))

ggplot(df2, aes(x=Arrival_rate, y=Response, color=Server)) + geom_line() +
    geom_ribbon(aes(ymin = Response - 2*Response_se, ymax = Response + 2*Response_se,
                    fill=Server), alpha = 0.3, linetype=0)

–1–

On peut voir sur cette courbe que le temps de traitement du serveur 1 explose lorsqu’on dépasse un taux d’inter-arrivées de 1. Pour le serveur 2, le temps de réponse croit moins rapidement après 2 mais est tout de même fortement croissant. De plus, on observe bien ce qui était prévu : le serveur 2 a un temps de réponse toujours inférieur au serveur 1.

ggplot(df2, aes(x=Arrival_rate, y=Mean_energy, color=Server)) + geom_line() + coord_cartesian(xlim = c(0,1), ylim = c(0,3))

–2–

La consommation énergétique du premier serveur reste basse à mesure que le taux d’inter-arrivées augmente. Sa consommation maximale étant de 1, il est effectivement logique qu’il reste plus bas que le second, qui peut avoir une consommation allant jusqu’à 4. On observe bien que le second serveur consomme peu pour de faibles taux d’arrivés dû à son faible coût en lorsqu’il est en veille (en attente de requête).

ggplot(df2, aes(x=Arrival_rate, y=Mean_energy, color=Server)) + geom_line() + 
  coord_cartesian(ylim=c(.45,.75), xlim=c(.1,.25))

–3–

En zoomant sur la courbe, on remarque que c’est environ à un taux d’inter-arrivées de 0.16 que la tendance s’inverse. Avant, le serveur 1 est plus gourmand en énergie, mais après il devient de plus en plus rentable.

Question 2 : Etude du serveur S3

Intuition

Espérance du temps de réponse : Ce serveur devrait avoir pour le temps de réponse une espérance meilleure que celle du second serveur. En effet, les capacités cumulées des deux premières machines devraient permettre de résister à un taux d’inter-arrivées s’approchant de 3. Pour un petit taux cependant, le comportement serait très similaire au serveur S1.

Espérance de la consommation d’énergie : Pour un taux d’inter-arrivées faible, le serveur devrait avoir une consommation légèrement supérieure à celle du S1. En effet, le second serveur serait en veille, augmentant la consommation moyenne. Ensuite, il est difficile de faire une estimation : le serveur 2 entrant plus souvent en jeu au fur et à mesure que la cadence d’arrivée des messages augmente, on suppose que la consommation va croître plus rapidement que celle du second serveur.

set.seed(123)
simulV2 = function(N=100, arrival_rate=.5, server="server3", processing_rate_1=1, energy0_1=.5, energy1_1=1,
                 processing_rate_2=1, energy0_2=.5, energy1_2=1) {
    Arrival = cumsum(rexp(n=N, rate=arrival_rate));  
    Service_1 = rexp(n=N, rate =processing_rate_1); # rep(N,x=1); rgamma(N, shape=.1,rate=.1)
    Service_2 = rexp(n=N, rate =processing_rate_2);
    Remaining = rep(N, x=NA);
    Completion = rep(N, x=NA)
    t = 0;
    uptime_1 = 0;
    uptime_2 = 0;
    CurrentTask_1 = NA;
    CurrentTask_2 = NA;
    NextArrival = 1;
    NextWaiting = 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_1) || !is.na(CurrentTask_2)) {
            dtC = min(Remaining[CurrentTask_1], Remaining[CurrentTask_2], na.rm = T); # 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;
        #   le remaining 
        if(!is.na(CurrentTask_1)) {
            Remaining[CurrentTask_1] = Remaining[CurrentTask_1] - dt
            if(Remaining[CurrentTask_1] <= 0) {
                Completion[CurrentTask_1] = t;
                Remaining[CurrentTask_1] = NA;
                CurrentTask_1 = NA;
            }
        }
        if(!is.na(CurrentTask_2)) {
            Remaining[CurrentTask_2] = Remaining[CurrentTask_2] - dt
            if(Remaining[CurrentTask_2] <= 0) {
                Completion[CurrentTask_2] = t;
                Remaining[CurrentTask_2] = NA;
                CurrentTask_2 = NA;
            }
        }
        #   les arrivées
        if((NextArrival <= N) & (Arrival[NextArrival] <= t)) {
            Remaining[NextArrival] = Arrival[NextArrival]
            NextArrival = NextArrival + 1;
        }
        #   et currentTask (politique d'ordonnancement: FIFO)
        
        if(!is.na(Remaining[NextWaiting])) {
            if (is.na(CurrentTask_1)) {
                CurrentTask_1 = NextWaiting;
                Remaining[CurrentTask_1] = rexp(1, processing_rate_1)
                NextWaiting = NextWaiting + 1
                uptime_1 = uptime_1 + Remaining[CurrentTask_1]
            }
            else if (is.na(CurrentTask_2)) {
                CurrentTask_2 = NextWaiting;
                Remaining[CurrentTask_2] = rexp(1, processing_rate_2)
                NextWaiting = NextWaiting + 1
                uptime_2 = uptime_2 + Remaining[CurrentTask_2]
            }
        }
    }
    return(data.frame(
        Arrival_rate=arrival_rate,
        Processing_rate=processing_rate_1 + processing_rate_2,
        Arrival = Arrival,
        Service = (Service_1 + Service_2)/2,
        Completion = Completion,
        Server = server,
        Energy_consumed = ((uptime_1 * energy1_1 + (t - uptime_1) * energy0_1) +
                             (uptime_2 * energy1_2 + (t - uptime_2) * energy0_2)) / t
        ))
        
}

for (r in  seq(from=.1, to=3.9, by=.1)) {
    df = rbind(df,simulV2(N=1000, arrival_rate=r, server = "server3", processing_rate_1=1, energy0_1 = .5, energy1_1 = 1,
                          processing_rate_2 = 2, energy0_2 = .25, energy1_2 = 4));
}

df2 = df %>% group_by(Arrival_rate, Server) %>%
    summarize(Response = mean(Completion - Arrival), 
              Response_se = sd(Completion - Arrival)/sqrt(n()),
              Mean_energy = mean(Energy_consumed))

ggplot(df2, aes(x=Arrival_rate, y=Response, color=Server)) + geom_line() +
    geom_ribbon(aes(ymin = Response - 2*Response_se, ymax = Response + 2*Response_se,
                    fill=Server), alpha = 0.3, linetype=0)

–1–

On remarque globalement ce qu’on avait estimé : le temps de réponse commence à se dégrader considérablement vers un taux d’inter-arrivées de 3, et le serveur 3 est plus efficace que les deux autres.

ggplot(df2, aes(x=Arrival_rate, y=Mean_energy, color=Server)) + geom_line()

–2–

En accord avec notre intuition, à un bas taux d’inter-arrivées le serveur 3 suit globalement la dépense énergétique du serveur 1 tout en étant un peu au-dessus. Ensuite, on remarque une consommation comparable à celle du serveur 2 jusqu’à ce que le serveur 2 atteigne sa capacité énergétique maximale.

ggplot(df2, aes(x=Arrival_rate, y=Mean_energy, color=Server)) + geom_line() + 
  coord_cartesian(ylim=c(.7,1.4), xlim=c(.25,.65))

ggplot(df2, aes(x=Arrival_rate, y=Mean_energy, color=Server)) + geom_line() + 
  coord_cartesian(ylim=c(3.75,4.25), xlim=c(2.25,2.55))

Graphiquement, on voit que le serveur 3 est plus économe en énergie pour un lambda situé entre ~0.45 et ~2.4. Ensuite le serveur 2 atteint sa limite de consommation d’énergie et le serveur 3 devient plus coûteux.