Intel MKL & Open Blas

Auteur·rice·s

Annaig De Walsche

Barbara Bricout

Tristan Mary-Huard

Armand Favrot

Félix Cheysson

Théodore Vanrenterghem

Date de publication

8 août 2024

Nous allons d’abord installer les librairies Intel MKL (processeur Intel nécessaire) & Open Blas. Ces deux librairies d’algèbre linéaire permettent d’optimiser et/ou de paralléliser un certains nombre d’opérations algébriques, notamment le calcul matriciel.

Nous les testons avec un produit matriciel de 10000 x 10000.

size <- 10000
mat <- matrix(rnorm(size**2), size, size)

tic()
get_res <- mat %*% mat
toc()

Avant l’installation les librairies utilisées pour du calcul matriciel en R sont libblas.so.3.10.0 et liblapack.so.3.10.0 (on peut les voir avec la ligne suivante)

sessionInfo()

Installation sur Windows (seulement Intel MKL)

Le plus simple est de télécharger les librairies Intel - MKL sur le seafile d’Agroparistech.

1 - Faire une copie de la version actuelle de BLAS et LAPACK:

Dans le dossier C:\Program Files\R\Your_R_Version\bin\x64, copier Rblas.dll et Rlapack.dll dans un autre dossier à conserver pour pouvoir revenir aux librairies de la base R.

2 - Télécharger les librairies Intel-MKL

En allant sur https://seafile.agroparistech.fr/d/696def33ceb848508cb0/ et en cliquant sur le boutton vert ZIP en haut à droite, vous pouvez télécharger le dossier. Puis le déziper.

3 - Copier les bibliothèques

Lorsque le dossier est décompressé, allez dans \Intel-MKL-Libs\Intel_MKL et copiez tous les fichiers dans votre C:\Program Files\R\Your_R_Version\bin\x64.

4 - Réouverture de R

Vous pouvez fermer votre session R et la rouvrir. Maintenant votre session R devrait fonctionner avec Intel-MKL. Vérifiez si vous avez gagné en efficacité sur votre ordinateur. Attention, le code déjà parallélisé pourrait être moins efficace car ces bibliothèques parallélisent déjà l’algèbre linéaire.

Concrètement on remplace les deux fichiers faisant appel aux librairies BLAS et LAPACK par des fichiers du même nom mais qui en pratique font implicitement appel à mkl. Pensez bien à sauver une copie des fichiers initiaux.

Pour retourner à la base R il suffit d’opérer à l’opération inverse, copie des fichiers Rblas.dll, Rlapack.dll et libiomp5md.dll du dossier C:\Program Files\R\Your_R_Version\bin\x64. Les mettre en sécurité puis copier les librairies des Rblas.dll et Rlapack.dll depuis votre sauvegarde ou https://seafile.agroparistech.fr/d/696def33ceb848508cb0/.

Installation sur Ubuntu 22.04 (Intel MKL et Open Blas)

Intel MKL

sudo apt install intel-mkl

Open Blas

sudo apt install libopenblas-base

Changement de librairie

Pour changer la librairie Blas

sudo update-alternatives --config libblas.so.3-x86_64-linux-gnu

Pour changer la librairie Lapack

sudo update-alternatives --config liblapack.so.3-x86_64-linux-gnu

Dans les deux cas cela ouvre un menu montrant les différentes librairies disponibles.

Comparaison produit matriciel (BLAS)

Une fois installées, vérifier si les librairies sont bien référencées pour le calcul matriciel avec

sessionInfo()
tic()
get_res <- mat %*% mat
toc()
Système d’exploitation Library CPU Base R Intel MKL
Windows 10 Intel MKL Intel Xeon - 16 processeur logiques 15 min 7 secondes
Ubuntu 22.04 Intel MKL Intel i7 - 8 processeur logiques 5 min Moins de 1 min
Ubuntu 22.04 Open Blas Intel i7 - 8 processeur logiques 5 min 9-14 secondes

Benchmark approfondi

Nous allons comparer les performances de toutes ces librairies sur Ubuntu avec un ordinateur à 8 cœurs Intel I7. Pour effectuer ce benchmark nous devons réitérer les fermetures de sessions donc le même code à été lancé séquentiellement.

Set-up

Packages
library(ggplot2)
library(purrr)
library(dplyr)
library(furrr)
library(future)
library(tictoc)
Fonctions de test
test_type <- function(seed, type = 'type'){
  res <- data.frame(seed = rep(0,2), 
                    time = rep(0,2), 
                    type = rep(0,2),
                    matrix_size = rep(0,2))
  matrix_size <- c(200, 2000)
  for(j in 1:2){
      set.seed(seed)
      mat = matrix(rnorm(matrix_size[[j]] ^ 2), ncol = matrix_size[[j]])
      T1 = Sys.time()
      res_tmp = mat %*% mat
      T2 = Sys.time()
      res$seed[[j]] <- seed
      res$time[[j]] <- difftime(T2, T1)
      res$type[[j]] <- type
      res$matrix_size[[j]] <- matrix_size[[j]]
  }
  return(res)
}

compare <- function(seeds,type = 'type'){
  if(type == "base"){
    plan(multisession, workers = availableCores())
    future_map_dfr(seeds,~test_type(.x,type = type))
  }else{
    map_dfr(seeds,~test_type(.x,type = type))
  }
}

my_multiplot <- function(data){
  ggplot(data = data,
       aes(x = time, y = type, fill = type,col = type)) +
  geom_boxplot(alpha = 0.5,show.legend = F) +  
  facet_wrap("matrix_size",scales = "free_x",labeller = label_both)
}
Paramètres
types <- c("base","openblas","lasy_intel_mkl","intel_mkl_high_perf")
seeds <- 1:20
Sélection de la librarie active
type <- types[[1]]
Calculs et sauvegarde
res <- compare(seeds,type)

saveRDS(res, file = paste0('res_algebrica_calculations/res_',type,'.RDS'))
Chargement des résultats
list_of_results <- grep("^res_algebrica_calculations/res_.*.RDS$",
                        dir(recursive = T),
                        value=T)
res_table <- map_dfr(list_of_results,readRDS)
Graph des résultats complets

On peut voir dans ces graphiques que dans l’ensemble OpenBlas et Intel-MKL sont plus efficaces que la base de R. Cependant d’autres remarques sont à faire :

  1. OpenBlas est utilise constamment l’ensemble des cœurs disponibles, ce comportement extrême peu devenir un problème lors des longs calculs où lorsque l’on utilise des librairies plus complexes comme par exemple Rcpp avec laquelle il obtiens des performances largement plus faible que la base.
  2. Nous avons aussi remarqué une certaine variations dans les performances de Intel-MKL sur Ubuntu seulement. Bien que toujours observée plus efficace que la base. Il est fréquent que pour un même calcul le temps soit jusqu’à 4 fois plus long que le minimum. Cette variation semble être fixe pour chaque session R ouverte. Dans ces graph nous appelons “lasy intel mkl” les sessions de faible performances.
my_multiplot(res_table)

Sans la base R
res_table %>% 
  filter(type != "base") %>% 
  my_multiplot()

Références