Skip to content

Software Optimization

Cours

TP noté à rendre pour le 25 mars

Objectif

L'objectif de ce travail pratique est d'analyser un code de calcul (en chimie quantique), de tester son efficacité en séquentiel et en parallèle, d'optimiser celle-ci (sans en modifier le code) et de proposer des pistes d'amélioration (séquentiel et parallèle.

Le code

Le code est un code de chimie quantique: DivCon. Celui permet de calculer des énergies de systèmes moléculaires en semi-empirique (méthodes de type NDDO: MNDO, AM1, PM3) selon une approche dite "standard" (= par diagonalisation de la matrice de Fock) ou en croissance linéaire (par la méthode Divide & Conquer).

Ce code vous est fourni sous forme d'un source (divcon.tgz) qu'il va falloir compiler puis tester.

Extraction du code

Tout d'abord, il faut extraire le code:

cd $HOME
mkdir MonNom_MonPrenom     # vous devez creer un repertoire a votre nom
cd MonNom_MonPrenom        
tar xzvf ~/TP-note/divcon.tgz      # extraction de l'archive source dans VOTRE repertoire
ls -l

La dernière commande vous permet de lister les fichiers dans le répertoire courant. Vous devriez obtenir une ligne contenant:

drwxr-xr-x 7 guest users 4096 Feb 14 06:57 divcon-source/

Compilation séquentielle

Pour compiler le code, il faut éditer le fichier Makefile dans le répertoire source.

cd divcon-source
vi Makefile

Les valeurs par défaut sont les suivantes:

#############################

# uncomment the correct CPFLAGS
# and comment the other one

#############################
# CPFLAGS for serial compilation:

CPFLAGS = -I../include
# CPFLAGS for parallel compilation:

#CPFLAGS = -DMPI_IS_ON -DMPI_NOMC -I../include
#############################

# Fortran compiler

FC = gfortran
# Fortran compiler flags

FFLAGS  = -O
# Link compiler flags

LDFLAGS = -O

# additional libraries (if needed for linking)

LIBS    =

Ces valeurs permettent de compiler le programme avec le compilateur GNU (gfortran) en séquentiel (serial).

Pour compiler avec le compilateur intel, il faut tout d'abord indiquer à l'environnement Linux où trouver le compilateur Intel. Cela s'effectue avec la commande:

source /opt/intel-12.sh

Puis en changer la valeur de FC:

FC = ifort

Pour changer les valeurs de FFLAGS/LDFLAGS, se reporter aux options de compilations:

ifort -help

La compilation du code s'effectue simplement à l'aide de la commande make:

make

Lorsque l'étape de compilation est terminée, un exécutable doit apparaître dans le répertoire source/:

ls -l source/divcon
 -rwxr-xr-x 1 guest users 2294058 Mar  2 06:03 source/divcon*

Compilation parallèle

Pour compiler en parallèle, il faut faire appel à un compilateur spécifique puis modifier les variables du Makefile.

Pour GNU:

source /opt/amber13-gnu.sh

Pour Intel:

source /opt/amber13-intel.sh

Variables du Makefile:

CPFLAGS = -DMPI_IS_ON -DMPI_NOMC -I../include
FC = mpif90

Test du programme

Fichier d'entrée

DivCon lit un fichier d'entrée contenant les options du calcul ainsi que les spécifications du système moléculaire dont l'énergie est à calculer.

Le fichier d'entrée s'appelle obligatoirement divcon.in. Sa structure est la suivante:

  • ligne 1: options du calcul (méthode, charge totale, algorithme, etc.)

  • ligne 2: ligne blanche

  • ligne 3, 4, ...: spécification du système moléculaire sous la forme (par ligne): numéro de l'atome, type de l'atome, coordonnée x, coordonnée y, coordonnée z, mot-clé RES si l'atome est le premier atome d'un nouveau résidu (ou d'une nouvelle molécule)

  • dernières lignes:

    • END_COORD spécifie la fin de la définition du système moléculaire
    • CLUSTER...END_CLUSTER spécifie les options de l'algorithme Divide & Conquer si besoin

Le programme Divcon peut être testé selon 2 options différentes: soit en utilisant un algorithme dit "standard" en mécanique quantique (diagonalisation de la matrice de Fock complète à chaque étape du SCF), soit en utilisant un algorithme à croissance linéaire: Divide & Conquer qui est basé sur une technique de décomposition de domaine.

Un fichier exemple pour un calcul standard sur 10 molécules d'eau est:

CHARGE=0 STANDARD   CARTESIAN DIRECT PM3 RESIDUE

1 O -6.586 -10.119 -10.923 RES
2 H -6.667 -11.033 -11.194
3 H -7.000 -9.622 -11.629
4 O -3.877 -9.779 -11.005 RES
5 H -4.818 -9.764 -10.830
6 H -3.563 -10.566 -10.559
7 O -7.976 -9.613 -13.680 RES
8 H -8.903 -9.679 -13.451
9 H -7.823 -8.675 -13.795
10 O -8.454 -8.341 -9.042 RES
11 H -9.230 -8.821 -8.752
12 H -7.803 -9.020 -9.216
13 O -7.575 -13.082 -11.658 RES
14 H -7.182 -12.765 -12.471
15 H -7.214 -13.961 -11.543
16 O -6.182 -11.719 -13.688 RES
17 H -6.781 -10.995 -13.871
18 H -5.634 -11.781 -14.470
19 O -6.990 -10.492 -7.562 RES
20 H -7.722 -9.983 -7.213
21 H -7.387 -11.309 -7.864
22 O -7.983 -12.858 -8.808 RES
23 H -7.606 -13.731 -8.921
24 H -8.081 -12.522 -9.699
25 O -6.120 -6.253 -10.220 RES
26 H -5.767 -6.850 -10.880
27 H -7.004 -6.579 -10.050
28 O -3.946 -8.051 -13.177 RES
29 H -4.565 -8.389 -13.824
30 H -3.963 -8.695 -12.469
END_COORD

Un fichier exemple pour un calcul Divide & Conquer sur 10 molécules d'eau vaut:

CHARGE=0 CLUSTER   CARTESIAN DIRECT PM3 RESIDUE

1 O -6.586 -10.119 -10.923 RES
2 H -6.667 -11.033 -11.194
3 H -7.000 -9.622 -11.629
4 O -3.877 -9.779 -11.005 RES
5 H -4.818 -9.764 -10.830
6 H -3.563 -10.566 -10.559
7 O -7.976 -9.613 -13.680 RES
8 H -8.903 -9.679 -13.451
9 H -7.823 -8.675 -13.795
10 O -8.454 -8.341 -9.042 RES
11 H -9.230 -8.821 -8.752
12 H -7.803 -9.020 -9.216
13 O -7.575 -13.082 -11.658 RES
14 H -7.182 -12.765 -12.471
15 H -7.214 -13.961 -11.543
16 O -6.182 -11.719 -13.688 RES
17 H -6.781 -10.995 -13.871
18 H -5.634 -11.781 -14.470
19 O -6.990 -10.492 -7.562 RES
20 H -7.722 -9.983 -7.213
21 H -7.387 -11.309 -7.864
22 O -7.983 -12.858 -8.808 RES
23 H -7.606 -13.731 -8.921
24 H -8.081 -12.522 -9.699
25 O -6.120 -6.253 -10.220 RES
26 H -5.767 -6.850 -10.880
27 H -7.004 -6.579 -10.050
28 O -3.946 -8.051 -13.177 RES
29 H -4.565 -8.389 -13.824
30 H -3.963 -8.695 -12.469
END_COORD
CLUSTER
    NCORE = 1
    DBUFF1 = 6.0
    DBUFF2 = 0.0
END_CLUSTER

Des fichiers d'entrée sont disponibles dans le répertoire ~guest/TP-note/inputs.

Execution du programme

Le programme DivCon lit à l'exécution un fichier divcon.in et écrit ses résultats dans un fichier nommé divcon.out.

Deux scripts d'exécution sont fournies dans le répertoire ~/TP-note:

  • run-serial.sh permet d'exécuter DivCon en séquentiel

  • run-parallel.sh permet d'exécuter DivCon en parallèle

Chaque script permet de définir un fichier d'entrée et un fichier de sortie. Un répertoire temporaire est créé. Dans ce répertoire temporaire:

  • le fichier d'entrée (variable IN dans le script) est recopié dans divcon.in

  • le programme DivCon est exécuté en séquentiel ou en parallèle

  • le fichier divcon.out est recopié dans le fichier de sortie spécifié (variable OUT) Dans ces scripts, la variable DIVCONEXE permet de spécifier où est placé l'exécutable divcon.exe dans l'arborescence des fichiers.

Queue de calcul

Les scripts run-serial.sh et run-parallel.sh peuvent être exécutés directement ou en les soumettant à une queue de calcul.

Il est conseillé de soumettre dans la queue de calcul pour pouvoir bénéficier de l'exclusivité d'un noeud de calcul.

Les commandes à connaître sont qsub, qstat, qdel:

Commande Objet
qsub soumission d'un job à la queue de calcul
qstat état courant de la queue
qdel effacement d'un job de la queue de calcul

Pour soumettre un job:

qsub run-serial.sh

L'exécution de cette commande renvoie un numéro de job.

Pour voir l'état de ses jobs:

qstat

Pour connaître tous les jobs tournant sur la machine:

qstat -u '*'

Pour tuer un job en particulier: qdel NUMERONUMERO est le JOB_ID fournit par qstat.

Questions

Vous écrirez un rapport permettant d'identifier les performances du programme DivCon en séquentiel et en parallèle. Sans en modifier le code source mais en jouant sur les options de compilation, vous en tirerez une performance maximale. Enfin, vous proposerez des voies d'amélioration de ce programme (en séquentiel et en parallèle).

Parmi les éléments qui devront figurer dans le rapport, on attend:

  • en séquentiel:
    • une figure (et une interprêtation) montrant la variation des temps de calcul en fonction de la taille des clusters d'eau définies dans le répertoire inputs. Dans quel(s) cas l'algorithme Divide & Conquer est-il préférable?
    • un profiling du programme (N.B.: il peut être différent en fonction de la taille des systèmes) avec repérage des goulots d'étranglement
    • une optimisation de la compilation du code séquentiel (N.B.: veillez à conserver la cohérence des résultats). Vous prendrez soin dans le rapport de montrer les différentes options de compilation que vous aurez testé et leur amélioration éventuelle sur les temps de calcul.
  • en parallèle:
    • une figure montrant la variation du speed-up en fonction du nombre de processeurs employés (+ une interprêtation selon les lois d'Amdahl et de Gustavson)
    • un profiling du programme avec repérage des goulots d'étranglement