On utilise la fonction suivante pour modéliser le comportement d’un serveur (file d’attente M/M/1 en mode FIFO). La valeur \(\lambda\) correspond au taux d’inter-arrivés et \(\mu\) le taux des temps de service.
mm1_sim <- function(lambda,mu,n, norm_power, sleep_power){
# Dates d'arrivée dans le système
Arrival = c(0,cumsum(rexp(n=n-1,rate=lambda)))
# Temps de traitement des tâches
Service = rexp(n=n,rate=mu)
# Dates de fin de traitement
Completion = rep(NA,times = n)
#==#==#==#==#==#==#==#==#==#
# Temps restant à la tâche n
Remaining = Service
# Traitement en cours
CurrClient = NA
LastClient = 0
# Prochain à arriver
NextArrival = 1
t = 0; # Temps courant
InstPower = 0
while(TRUE){
# Temps jusqu'à la prochaine arrivée
dtA = ifelse(NextArrival > n, NA, Arrival[NextArrival] - t)
# Temps jusqu'à la prochaine terminaison
dtC = ifelse(is.na(CurrClient),NA,Remaining[CurrClient])
# On s'arrête lorsque tout est fini, et qu'il n'y a plus d'arrivée attendue
if (is.na(dtA) & is.na(dtC)) {break;}
# Le prochain événement dans le temps est dans dt "secondes"
dt = min(dtA,dtC,na.rm = TRUE);
# Puissance instantanée pour l'inter-temps
if (is.na(CurrClient)){
InstPower = InstPower + (dt * sleep_power) # Traitement en cours
} else {
InstPower = InstPower + (dt * norm_power) # Serveur en veille
}
# On passe au prochain événement
# Soit une arrivée, soit une terminaison, soit les deux
t = t + dt
# Tâche en cours
if (!is.na(CurrClient)){
Remaining[CurrClient] = Remaining[CurrClient] - dt
#Tâche finie
if (Remaining[CurrClient]<=0) {
Completion[CurrClient] = t
#LastClient = CurrClient
CurrClient = NA
}
}
# Arrivée d'une tâche
if (NextArrival <= n && Arrival[NextArrival] <= t){
NextArrival = NextArrival + 1
}
# Sélection du prochain client, si il est arrivé
if (is.na(CurrClient) && LastClient < n && Arrival[LastClient+1] <= t) {
CurrClient = LastClient + 1
LastClient = LastClient + 1
}
}
InstPower = InstPower/t
#==#==#==#==#==#==#==#==#==#==#
return(data.frame(lambda,mu,Arrival,Completion, InstPower))
}
On réalise la simulation sur l’intervalle [0.05,1] avec un pas de 0.05. On donne 1000 tâches à effectuer au serveur.
#-- Temps de services pour les serveurs S1 et S2
mu_1 = 1
mu_2 = 2
#-- Profils énergétiques
V_1 = 0.5 # Veille sur S1
V_2 = 0.25 # Veille sur S2
E_1 = 1 # Traitement sur S1
E_2 = 4 # Traitement sur S2
#-- Durée de la simulation
n = 1000
#==#==#==#==#==#==#==#==#==#==#==#
lambdas = seq.default(from=0.05,to=1.0,by=0.05)
df <- data.frame()
for (lambda in lambdas){
df <- rbind(df,mm1_sim(lambda = lambda,mu = mu_1,n = n,norm_power = E_1,sleep_power = V_1))
df <- rbind(df,mm1_sim(lambda = lambda,mu = mu_2,n = n, norm_power= E_2, sleep_power = V_2))
}
df <- (df %>% mutate(Response = Completion - Arrival))
df <- (df %>% group_by(lambda,mu,InstPower) %>% summarise(resp_avg = mean(Response),resp_sd = sd(Response)/sqrt(n)))
ggplot(data = df, aes(x = lambda, y = resp_avg,group = factor(mu), color = factor(mu))) + geom_line(size = 0.5) + geom_smooth(method = 'loess') + xlab(label = expression(paste(lambda," Arrival Rate"))) + ylab("Response Time") + labs(color = "Server")
ggplot(data = df, aes(x = lambda, y = InstPower, group = factor(mu), color = factor(mu))) + labs(color = "Server") + geom_line() + geom_smooth(method = 'loess') + xlab(label = expression(paste(lambda," Arrival Rate"))) + ylab("Power Consumption")
lambdas = seq.default(from=0.15,to=0.20,by=0.001)
n = 10000
df <- data.frame()
for (lambda in lambdas){
df <- rbind(df,mm1_sim(lambda = lambda,mu = mu_1,n = n,norm_power = E_1,sleep_power = V_1))
df <- rbind(df,mm1_sim(lambda = lambda,mu = mu_2,n = n, norm_power= E_2, sleep_power = V_2))
}
df <- (df %>% mutate(Response = Completion - Arrival))
df <- (df %>% group_by(lambda,mu,InstPower) %>% summarise(resp_avg = mean(Response),resp_sd = sd(Response)/sqrt(n)))
ggplot(data = df, aes(x = lambda, y = InstPower, group = factor(mu), color = factor(mu))) + geom_line() + geom_smooth(method = 'loess') + xlab(label = expression(paste(lambda," Arrival Rate"))) + ylab("Power Consumption")
On peut voir que la valeur \(\lambda\) charnière se situe un peu après 0.18. On a donc \(\lambda_{pivot} = 0.18 \pm 0.1\)
On utilise la fonction suivante pour modéliser le comportement de deux serveurs fonctionnant en parallèle.
# - Simulation file MM1
# - pour 2 serveurs
# - avec calcul de puissance instantanée
mm1_sim_parallel <- function(lambda,mu_1,mu_2,n, norm_power_1, sleep_power_1,norm_power_2,sleep_power_2){
# Dates d'arrivée dans le système
Arrival = c(0,cumsum(rexp(n=n-1,rate=lambda)))
# Temps de traitement des tâches
Service_1 = rexp(n=n,rate=mu_1) # Pour le serveur 1
Service_2 = rexp(n=n,rate=mu_2) # Pour le serveur 2
# Dates de fin de traitement
Completion = rep(NA,times = n)
#==#==#==#==#==#==#==#==#==#
# Temps restant à la tâche n
Remaining_1 = Service_1 # Si la tâche n tourne sur le serveur 1
Remaining_2 = Service_2 # Si la tâche n tourne sur le serveur 2
# Traitement en cours
CurrClient_1 = NA
CurrClient_2 = NA
LastClient = 0
# Prochain à arriver
NextArrival = 1
# Temps courant
t = 0
InstPower = 0
while(TRUE){
# Temps jusqu'à la prochaine arrivée
dtA = ifelse(NextArrival > n, NA, Arrival[NextArrival] - t)
# Temps jusqu'à la prochaine terminaison
if (is.na(CurrClient_1)) {
if (is.na(CurrClient_2)){
dtC = NA # Aucun des deux serveurs ne fonctionne, pas de terminaison prévue
} else {
dtC = Remaining_2[CurrClient_2] # Prochaine terminaison sur le serveur 2
}
} else {
if (is.na(CurrClient_2)){
dtC = Remaining_1[CurrClient_1] # Prochaine terminaison sur le serveur 1
} else {
dtC = min(Remaining_1[CurrClient_1],Remaining_2[CurrClient_2]) # Prochaine terminaison sur 1 ou 2
}
}
# On s'arrête lorsque tout est fini, et qu'il n'y a plus d'arrivée attendue
if (is.na(dtA) & is.na(dtC)) {break}
# Le prochain événement dans le temps est dans "dt" secondes
dt = min(dtA,dtC,na.rm = TRUE)
# Puissance instantanée pour l'inter-temps
# Serveur 1
if (is.na(CurrClient_1)){
InstPower = InstPower + (dt * sleep_power_1) # Traitement en cours sur 1
} else {
InstPower = InstPower + (dt * norm_power_1) # Serveur 1 en veille
}
# Serveur 2
if (is.na(CurrClient_2)){
InstPower = InstPower + (dt * sleep_power_2) # Traitement en cours sur 2
} else {
InstPower = InstPower + (dt * norm_power_2) # Serveur 2 en veille
}
# On passe au prochain événement
# Soit une arrivée, soit une terminaison, soit les deux
t = t + dt
# Tâche en cours sur le premier serveur
if (!is.na(CurrClient_1)){
Remaining_1[CurrClient_1] = Remaining_1[CurrClient_1] - dt
#Tâche finie
if (Remaining_1[CurrClient_1]<=0) {
Completion[CurrClient_1] = t
CurrClient_1 = NA
}
}
# Tâche en cours sur le deuxième serveur
if (!is.na(CurrClient_2)){
Remaining_2[CurrClient_2] = Remaining_2[CurrClient_2] - dt
#Tâche finie
if (Remaining_2[CurrClient_2]<=0) {
Completion[CurrClient_2] = t
CurrClient_2 = NA
}
}
# Arrivée d'une tâche
if (NextArrival <= n && Arrival[NextArrival] <= t){
NextArrival = NextArrival + 1
}
# Sélection du prochain client pour le serveur 1, si il est arrivé
if (is.na(CurrClient_1) && LastClient < n && Arrival[LastClient+1] <= t) {
LastClient = LastClient + 1
CurrClient_1 = LastClient
}
# Sélection du prochain client pour le serveur 2, si il est arrivé
if (is.na(CurrClient_2) && LastClient < n && Arrival[LastClient+1] <= t) {
LastClient = LastClient + 1
CurrClient_2 = LastClient
}
}
InstPower = InstPower/t
#==#==#==#==#==#==#==#==#==#==#
return(data.frame(lambda,mu = mu_1+mu_2,Arrival,Completion,InstPower))
}
lambdas = seq.default(from=0.05,to=3.0,by=0.1)
df <- data.frame()
for (lambda in lambdas){
df <- rbind(df,mm1_sim(lambda = lambda,mu = mu_1,n = n,norm_power = E_1,sleep_power = V_1))
df <- rbind(df,mm1_sim(lambda = lambda,mu = mu_2,n = n, norm_power= E_2, sleep_power = V_2))
df <- rbind(df,mm1_sim_parallel(lambda=lambda, mu_1=mu_1,mu_2=mu_2,n=n,norm_power_1 = E_1,norm_power_2 = E_2,sleep_power_1 = V_1, sleep_power_2 = V_2))
}
df <- (df %>% mutate(Response = Completion - Arrival))
df <- (df %>% group_by(lambda,mu,InstPower) %>% summarise(resp_avg = mean(Response),resp_sd = sd(Response)/sqrt(n)))
ggplot(data = df, aes(x = lambda, y = resp_avg,group = factor(mu), color = factor(mu))) + geom_line(size = 0.5) + geom_smooth(method = 'loess') + xlab(label = expression(paste(lambda," Arrival Rate"))) + ylab("Response Time") + labs(color = "Server")
ggplot(data = df, aes(x = lambda, y = InstPower, group = factor(mu), color = factor(mu))) + geom_line() + geom_smooth(method = 'loess') + xlab(label = expression(paste(lambda," Arrival Rate"))) + ylab("Power Consumption") + labs(color = "Server")