Download - ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Transcript
Page 1: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Etude et implementation de l’algorithme

du simplexe standard sur GPUs

Xavier Meyer<[email protected]>

Memoire

presente a la Faculte de sciences de l’Universite de Genevepour l’obtention d’une maıtrise en sciences informatiques

Professeurs responsables :Prof. Bastien Chopard (CUI, UNIGE)

Prof. Paul Albuquerque (hepia, HES-SO//Geneve)

Geneve, le 4 fevrier 2011

Page 2: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Table des matieres

Glossary 5

1 Introduction 11.1 Motivations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Plan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

2 Algorithme du simplexe 42.1 Generalites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42.2 Programmation lineaire . . . . . . . . . . . . . . . . . . . . . . . 42.3 Representation geometrique . . . . . . . . . . . . . . . . . . . . . 5

2.3.1 Representation . . . . . . . . . . . . . . . . . . . . . . . . 52.3.2 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62.3.3 Generalisation . . . . . . . . . . . . . . . . . . . . . . . . 7

2.4 Methode standard . . . . . . . . . . . . . . . . . . . . . . . . . . 82.4.1 Initialisation . . . . . . . . . . . . . . . . . . . . . . . . . 82.4.2 Recherche de l’optimum . . . . . . . . . . . . . . . . . . . 102.4.3 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132.4.4 Cas particuliers . . . . . . . . . . . . . . . . . . . . . . . . 13

2.5 Methode du simplexe revise . . . . . . . . . . . . . . . . . . . . . 172.5.1 Generalites . . . . . . . . . . . . . . . . . . . . . . . . . . 172.5.2 Decomposition du probleme . . . . . . . . . . . . . . . . . 172.5.3 Choix de la variable entrante . . . . . . . . . . . . . . . . 182.5.4 Choix de la variable sortante . . . . . . . . . . . . . . . . 192.5.5 Mise a jour du probleme . . . . . . . . . . . . . . . . . . . 192.5.6 Optimisation importante . . . . . . . . . . . . . . . . . . 19

3 CUDA 213.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213.2 Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

3.2.1 Vue globale . . . . . . . . . . . . . . . . . . . . . . . . . . 223.2.2 Organisation des taches . . . . . . . . . . . . . . . . . . . 223.2.3 Memoires . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

3.3 Modele de programmation . . . . . . . . . . . . . . . . . . . . . . 273.3.1 Generalites . . . . . . . . . . . . . . . . . . . . . . . . . . 273.3.2 Branchements . . . . . . . . . . . . . . . . . . . . . . . . . 283.3.3 Cooperation entre les taches . . . . . . . . . . . . . . . . . 283.3.4 Cycle pour une instruction et latence . . . . . . . . . . . . 303.3.5 Occupation . . . . . . . . . . . . . . . . . . . . . . . . . . 30

2

Page 3: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

4 Implementations 314.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314.2 Choix de la methode du simplexe . . . . . . . . . . . . . . . . . . 31

4.2.1 Generalites . . . . . . . . . . . . . . . . . . . . . . . . . . 314.2.2 Simplexe standard . . . . . . . . . . . . . . . . . . . . . . 324.2.3 Simplexe revise . . . . . . . . . . . . . . . . . . . . . . . . 334.2.4 Choix de la methode . . . . . . . . . . . . . . . . . . . . . 33

4.3 Etude de performance de CUDA . . . . . . . . . . . . . . . . . . 344.3.1 Operations principales . . . . . . . . . . . . . . . . . . . . 344.3.2 Recherche du maximum . . . . . . . . . . . . . . . . . . . 354.3.3 Pivotage . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

4.4 Implementation sur un GPU . . . . . . . . . . . . . . . . . . . . 364.4.1 Generalites . . . . . . . . . . . . . . . . . . . . . . . . . . 364.4.2 Algorithme principal . . . . . . . . . . . . . . . . . . . . . 374.4.3 Recherche d’une solution initiale faisable . . . . . . . . . . 404.4.4 Recherche de la solution optimale . . . . . . . . . . . . . . 414.4.5 Communications CPU - GPU . . . . . . . . . . . . . . . . 41

4.5 Ameliorations de l’implementation . . . . . . . . . . . . . . . . . 454.5.1 Difficultes rencontrees . . . . . . . . . . . . . . . . . . . . 454.5.2 Ameliorations de l’algorithme du simplexe . . . . . . . . . 474.5.3 Optimisations des kernel . . . . . . . . . . . . . . . . . . 50

4.6 Implementation multi-GPU . . . . . . . . . . . . . . . . . . . . . 534.6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 534.6.2 Decoupe du probleme . . . . . . . . . . . . . . . . . . . . 534.6.3 Architecture et communication multi-GPU . . . . . . . . 584.6.4 Algorithme . . . . . . . . . . . . . . . . . . . . . . . . . . 59

5 Modeles de performance 655.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 655.2 Particularite lie a CUDA . . . . . . . . . . . . . . . . . . . . . . . 65

5.2.1 Echanges de donnees CPU-GPU . . . . . . . . . . . . . . 655.2.2 Modeliser un Kernel . . . . . . . . . . . . . . . . . . . . . 66

5.3 Simplexe sur un GPU . . . . . . . . . . . . . . . . . . . . . . . . 685.3.1 Recherche de la variable entrante : steepest edge . . . . . 685.3.2 Recherche de la variable sortante : expand . . . . . . . . . 695.3.3 Mise a jour de la matrice : pivotage . . . . . . . . . . . . 705.3.4 Modele de performance general . . . . . . . . . . . . . . . 71

5.4 Simplexe multi-GPU . . . . . . . . . . . . . . . . . . . . . . . . . 725.4.1 Generalites . . . . . . . . . . . . . . . . . . . . . . . . . . 725.4.2 Recherche de la variable entrante : steepest-edge . . . . . 735.4.3 Recherche de la variable sortante : expand . . . . . . . . . 735.4.4 Mise a jour de la matrice : pivotage . . . . . . . . . . . . 745.4.5 Modele de performance general . . . . . . . . . . . . . . . 74

5.5 Application du modele : mesures theoriques . . . . . . . . . . . . 745.5.1 Generalites . . . . . . . . . . . . . . . . . . . . . . . . . . 745.5.2 Temps par iteration . . . . . . . . . . . . . . . . . . . . . 755.5.3 Temps pour resoudre un probleme . . . . . . . . . . . . . 755.5.4 Speedup . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76

3

Page 4: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

6 Mesures 786.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 786.2 Implementation de reference . . . . . . . . . . . . . . . . . . . . . 786.3 Mesures de fonctionnement . . . . . . . . . . . . . . . . . . . . . 79

6.3.1 Objectif . . . . . . . . . . . . . . . . . . . . . . . . . . . . 796.3.2 Ensemble de donnes . . . . . . . . . . . . . . . . . . . . . 796.3.3 Resultats . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

6.4 Mesures de performance . . . . . . . . . . . . . . . . . . . . . . . 806.4.1 Objectif . . . . . . . . . . . . . . . . . . . . . . . . . . . . 806.4.2 Environnement de mesures . . . . . . . . . . . . . . . . . 806.4.3 Ensemble de donnees . . . . . . . . . . . . . . . . . . . . . 816.4.4 Resultats . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

6.5 Analyse des resultats . . . . . . . . . . . . . . . . . . . . . . . . . 856.5.1 Influence de la densite . . . . . . . . . . . . . . . . . . . . 856.5.2 Comparaison du modele et des resultats . . . . . . . . . . 866.5.3 Gain apporte par l’utilisation de GPUs . . . . . . . . . . 88

7 Conclusion 907.1 Resume du travail realise . . . . . . . . . . . . . . . . . . . . . . 907.2 Discussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91

7.2.1 CUDA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 917.2.2 Simplexe . . . . . . . . . . . . . . . . . . . . . . . . . . . 927.2.3 Choix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 927.2.4 Resultats et modele de performance . . . . . . . . . . . . 93

7.3 Perspectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

4

Page 5: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Glossaire

block Groupe de taches execute sur un streaming multiprocessor (CUDA). 24–27, 29, 30, 35, 42, 48, 61–65, 69

CC Compute Capabilities - version d’un device (CUDA). 22

CLP COIN-OR Linear Programming - implementation du simplexe revise. 73–78, 80, 82, 84

COIN-OR Computational Infrastructure for Operations Research - projet opensource. 73, 84

CUBLAS Basic Linear Algebra Subprograms for CUDA - librairie pour CUDA.32, 35, 42, 65

device unite de calcul graphique (CUDA). 22, 25, 35, 37, 40, 49, 55, 56, 60, 67

expand EXPanding-tolerance ANti-Degeneracy procedure - methode de choixde la variable sortante. 52, 53, 55, 64, 68, 70, 74, 85

FLOPS Floating point operations Per Second - mesure de vitesse d’un systemeinformatique. 21, 75, 87

GPGPU General-Purpose Computing on Graphics Processing Units - calculsur GPU. 2, 3, 21, 33, 60, 70, 83, 86

grid Groupe de blocks (CUDA). 25

kernel Fonction CUDA. 22, 23, 31, 32, 35, 37, 40–42, 48, 49, 60–67, 69, 70, 75,80, 84, 85

latence Temps mis par une lecture en memoire globale (CUDA). 27, 29, 30,48, 49, 62, 63, 65, 66, 84, 87

SIMD Simple Instruction Multiple Data - type de parallelisme. 1, 27

SIMT Simple Instruction Multiple Thread - type de parallelisme. 1, 21, 27, 33,83

SM Streaming multiprocessor - multiprocesseur d’un GPU gerant 8 cœurs. 61–64, 75

speedup Acceleration - ”mesure de parallelisme”. 2, 70, 77, 82, 84, 86

steepest edge methode de choix de la variable entrante. 46, 48, 51–53, 63, 68,74, 77, 85

warp Sous-ensemble de taches (CUDA). 24–30, 43, 48, 61–63, 65

5

Page 6: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Resume

L’algorithme du simplexe est une des methodes les plus utilisees dans le cadrede la recherche operationnelle. La complexite des problemes a resoudre evolueconstamment, de telle sorte que les implementations existantes s’averent par-fois trop lente. En parallele, la technologie evolue et met a notre disposition denouveaux outils. Nous nous interessons, dans ce travail, a l’implementation del’algorithme du simplexe sur unite de calcul graphique. Ces unites de calcul dis-posent d’une architecture particuliere qui permet de paralleliser des operationsmatricielles ou vectorielles principalement. Ces differents sujets sont etudies,afin d’offrir la base necessaire a la comprehension de notre implementation dusimplexe standard sur une ou plusieurs unites de calcul graphique. Les perfor-mances theoriques de cette implementation sont analysees a l’aide d’un modelede performance. Les mesures reelles obtenues lors de notre experience confirmentl’exactitude de notre modele. Pour des problemes de moyenne a grande tailles,ces mesures demontrent des gains importants lorsqu’elles sont comparees a cellesd’une implementation sequentielle reputee de l’algorithme du simplexe revise.

Page 7: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Chapitre 1

Introduction

1.1 Motivations

Le simplexe est un algorithme d’optimisation utilise depuis de nombreusesannees afin de resoudre des problemes de programmation lineaire. Ces problemessont utilises dans la majorite des cas pour modeliser des problemes de rechercheoperationnelle. Le simplexe est souvent employe dans differentes industries pourdes problemes de planifications, distributions, agencements. Par exemple, la pro-duction de petrole ou encore la planification de vols commerciaux sont genera-lement optimises a l’aide de cet algorithme.

Celui-ci a ete concu par George B. Dantzig en 1947. Outre la version stan-dard de l’algorithme, basee sur une evolution de la matrice complete modelisantle probleme, une seconde version appelee simplexe revise a rapidement fait sespreuves. Cette version utilise une decomposition de la matrice initiale dans l’op-tique de diminuer la quantite de calcul necessaire afin de faire evoluer la matricevers une solution optimale. Elle s’est revelee particulierement performante pourles matrices creuses. Cette version adjointe a une utilisation de structures dedonnees speciales pour les matrices creuses a ete la methode majoritairementchoisie pour l’implementation du simplexe.

La complexite croissante des problemes a optimiser ainsi que l’evolution tech-nologique offrent de nouvelles perspectives a l’implementation de cet algorithme.En effet, J. A. J. Hall [8] a fait une etude des differentes possibilites quant a laparallelisation de celui-ci. Parmi ces dernieres, on peut notamment citer cellede Thomadakis et al. [16] dont le but est de paralleliser le simplexe sur unemachine de type SIMD (Singe Instruction Multiple Data). Ceci dans l’optiquede reduire le temps de calcul des problemes ayant des matrices denses ou detaille consequente.

La recente evolution des cartes graphiques en tant qu’unites de calcul offreun bon compromis entre une puissance de calcul accrue et un prix modere.L’architecture de type SIMT 1 (Single Instruction Multiple Threads) des unitesde calcul graphique, optimisee pour les calculs matriciels, semble bien adaptee al’algorithme du simplexe. En effet, ce dernier necessite de nombreuses operationsd’algebre lineaire sur la matrice modelisant le probleme.

Nous nous interesserons a la parallelisation du simplexe sur GPU (Graphic

1. Concept propre a CUDA.

1

Page 8: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Processing Unit). Cette approche innovante n’a ete le sujet que d’une seuleetude a notre connaissance. Seuls J. Bieling et al. [10] ont etudie ce sujet enparallelisant le simplexe revise sur un GPU. Les resultats obtenus lors de cetteetude laisse presager des gains interessants grace a l’utilisation d’un GPU pourdes problemes de moyenne a grande taille.

Le but de ce travail sera de paralleliser l’algorithme du simplexe standardsur des GPUs. Une premiere implementation consistera en une couche uniquede parallelisme sur un GPU. Une fois cette premiere phase fonctionnelle, une se-conde implementation multi-GPU sera mise au point dans l’optique d’ameliorerles performances sur les problemes de grande taille.

Les performances de ces implementations seront etudiees sur de nombreuxproblemes, par exemple : des problemes de grande taille modelisant l’affectationd’avions a des routes commerciales ou la conception d’horaire d’equipages ; quinous sont fournis par la compagnie APM Technologies [2].

1.2 Plan

Nous allons debuter par une etude complete des variantes de l’algorithme dusimplexe. Cet algorithme va tout d’abord etre decrit sous sa forme geometriqueafin d’offrir une premiere approche a son fonctionnement. Ensuite, nous verronsle fonctionnement, du point de vue algorithmique et algebrique, de la methodestandard. A partir de la description de cette methode, nous examinerons lesparticularites de la variante du simplexe revise. Ces deux methodes fonctionnentselon le meme principe, seule l’evolution du probleme est traitee differemment.

Apres cette etude, nous nous interesserons au GPGPU (General-PurposeComputing on Graphics Processing Units), plus precisement a l’architectureCUDA (Compute Unified Device Architecture) proposee par NVIDIA. Les per-formances de cette architecture repose sur deux elements fondamentaux : lamemoire et la decomposition du travail en taches. Ces deux axes vont etreapprofondis de facon a permettre la comprehension des points cruciaux de cemodele de programmation.

Avant de debuter l’implementation de l’algorithme, il sera necessaire de choi-sir une des deux variantes du simplexe. Les avantages et inconvenients de cha-cune seront analyses. Lorsque le choix sera fait, nous comparerons les operationscles composant l’algorithme avec leur equivalent sequentiel. Ceci afin d’estimerquel type de gains nous pourrons attendre de cette implementation. La paralle-lisation de la methode du simplexe sur un GPU sera alors decrite. Afin d’obtenirun algorithme competitif avec ceux existants, cette implementation sera amelio-ree par des methodes trouvees dans la litterature scientifique. A partir de cetteversion amelioree, une version multi-GPU sera mise en place. Nous etudieronsalors les modifications apportees a l’algorithme et a la structure du probleme.

Le modele de performance de nos implementations sera alors etabli. Pourcela, il sera necessaire d’etudier la modelisation de programme sur GPGPUetant donne que l’architecture differe fortement des CPUs conventionnels. Lesresultats theoriques, obtenus grace au modele, nous permettront d’effectuer unepremiere analyse du comportement des implementations face a une variation dela taille des problemes a resoudre. Le speedup theorique sera aussi examine afinde mesurer l’impact qu’aurait l’ajout d’autres unites de calcul.

Nous nous interesserons alors aux resultats reels produits par nos implemen-

2

Page 9: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

tations. Ces resultats seront compares avec une implementation existante quenous aurons selectionnee au prealable. Il faudra donc s’assurer que nos imple-mentations fonctionnent tout aussi bien que celle de reference. Pour cela, ellesseront testees sur un benchmark. Apres cela, les performances des differentesimplementations seront mesurees. A partir des resultats obtenus, leur compor-tement face a des variations de la taille et de la densite des problemes seraanalyse.

Finalement, nous recapitulerons les differentes etapes, choix et resultatsayant ete traites durant ce travail. Suite a ce resume, nous discuterons deselements importants dont l’implementation du simplexe, la programmation surGPGPU, les choix effectues ainsi que le modele de performance et les resultatsobtenus. Pour terminer, nous evoquerons les perspectives qu’ouvrent ce travail.

3

Page 10: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Chapitre 2

Algorithme du simplexe

2.1 Generalites

L’algorithme du simplexe est une des methodes les plus communement uti-lisee pour resoudre les problemes de programmation lineaire. Cette methode aete concue en 1947 par George Dantzig. Par la suite, elle a ete sujette a denombreux travaux de recherche qui ont aboutis sur plusieurs ameliorations enterme de performance et de stabilite. L’etude de cet algorithme est basee sur lestravaux de V. Chvatal [6] ainsi que F. Hillier et G. J. Liberman [9].

Il existe deux versions principales du simplexe. La premiere methode ditestandard ou l’algorithme est applique sur une version non modifiee du probleme.Cette methode est aussi appelee ”full tableau” (tableau complet). La secondemethode est la methode revisee. Cette derniere utilise une decomposition duprobleme de base en sous-matrices. Cette modelisation du probleme, a l’aide dequelques astuces, permet de reduire les calculs a effectuer pour les problemesayant une faible densite de coefficients non nul.

Dans un premier temps, nous verrons ce qu’est un probleme de programma-tion lineaire. Les bases etant posees, nous etudierons l’algorithme du simplexe encommencant par sa representation geometrique. Cette derniere permet d’illus-trer le fonctionnement de l’algorithme. La methode standard sera alors decriteet servira a expliquer les concepts fondamentaux du simplexe. Finalement, nousverrons quelles sont les particularites de l’algorithme du simplexe revise.

2.2 Programmation lineaire

La programmation lineaire est un domaine central de l’optimisation. Lesproblemes de programmation lineaire sont les problemes d’optimisation les plusfaciles a resoudre : les contraintes ainsi que la fonction objectif etant lineaires.La forme normale pour ce type de problemes est la suivante :

Maximiser

n∑

j=1

cjxj

Sujet a

n∑

j=1

aijxj ≤ bi (i = 1, 2, ...,m)

4

Page 11: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

xj ≥ 0 (j = 1, 2, ..., n)

Les contraintes peuvent etre de types plus petit ou egal, plus grand ou egalou encore egal. Ces differents types d’egalites ou d’inegalites peuvent etre trans-poses sans autre en forme normale. Une version plus generale des problemes deprogrammation lineaire ajoute une limite individuelle sur les variables :

Maximiser

n∑

j=1

cjxj

Sujet a

n∑

j=1

aijxj ≤ bi (i = 1, 2, ...,m)

lj ≤ xj ≤ uj (j = 1, 2, ..., n)

ou lj et uj sont les bornes inferieures, respectivement superieures, des va-riables. Ces dernieres peuvent prendre n’importe quelle valeur entre −∞ et +∞.Cependant, dans un premier temps, nous allons uniquement considerer le cas oules differentes variables du probleme ne disposent pas de limites individuelles,ceci afin de simplifier la comprehension de l’algorithme.

D’un point de vue geometrique ce type de probleme definit un polytope,dont les cas particuliers les plus connus sont le polygone dans un espace a deuxdimensions et le polyedre dans un espace a trois dimensions. L’interieur de cepolytope definit l’ensemble de recherche et le but serait donc de trouver le pointse trouvant dans le polytope, qui maximise ou minimise la fonction objectif. Ilest important de remarquer que du fait des contraintes lineaires, le polytope estconvexe et ne peut donc posseder des optima locaux.

Pour finir, voici un exemple type d’un probleme lineaire.

MaximiserZ = 5x1 +4x2 +3x3

Sujet a2x1 +3x2 +x3 ≤ 54x1 +x2 +2x3 ≤ 113x1 +4x2 +2x3 ≤ 8x1, x2, x3 ≥ 0

2.3 Representation geometrique

2.3.1 Representation

Afin de se donner une premiere idee du fonctionnement de l’algorithme,reprenons la representation geometrique d’un probleme de programmation li-neaire. Nous avons donc un polytope dont nous desirons trouver le point maxi-misant (ou minimisant) une fonction objectif.

L’algorithme du simplexe consiste a se placer sur une des intersections dupolytope (un coin, en quelque sorte). Ensuite, il va s’agir de se deplacer le longd’une arete jusqu’a la prochaine intersection. Ce deplacement doit garantir lemaintien ou l’amelioration du resultat de la fonction objectif. De telle sorte queces deplacements ne nous eloignent jamais du point optimal. Cette etape estensuite repetee jusqu’a ce que le point optimal du polytope soit atteint.

5

Page 12: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

2.3.2 Exemple

Afin d’illustrer cette methode de maniere parlante, nous allons reprendre undes exemples decrit dans le livre Introduction to Operations Research [9]. Nousallons desormais appliquer l’algorithme du simplexe sur un polytope de degre2, soit un polygone. Nous avons le probleme de programmation lineaire suivant :

MaximiserZ = 3x1 +5x2

Sujet ax1 ≤ 4

+2x2 ≤ 123x1 +2x2 ≤ 18x1, x2 ≥ 0

La representation geometrique correspond au polygone a la figure 2.1.

Figure 2.1 – Representation geometrique

L’interieur du polygone, la surface grise, represente la zone admissible. N’im-porte quelles valeurs des variables x1 et x2 resultant en un point de cette zoneest donc une solution pour notre probleme.

Nous allons debuter au point (0, 0). Ce point a comme valeur de la fonctionobjectif Z = 0. Afin de determiner si cette solution est optimale, regardons lespoints adjacents. Les points (4, 0) et (0, 6) offrent un gain de la fonction objectif.Nous allons alors choisir la direction de notre deplacement.

6

Page 13: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Le gain potentiel sur Z depend en partie de la valeur des coefficients dela fonction objectif. Etant donne que le coefficient de x2 est le plus grand,nous allons choisir cette direction car elle offre le plus grand gain theorique.Nous sommes desormais au point (0, 6) avec pour valeur de la fonction objectifZ = 30.

Avons-nous atteint le point offrant la solution optimale de notre polygone ?Pour savoir cela, il suffit a nouveau de controler les points adjacents. Il se trouveque le point (2, 6) amene a une amelioration de Z.

Nous voila au point (2, 6) avec Z = 36. Aucune des intersections adjacentesn’amenent a une amelioration de Z. Nous avons donc atteint le point optimal.

Le chemin effectue est decrit par la figure 2.2.

Figure 2.2 – Chemin effectue

2.3.3 Generalisation

A partir de ces observations, il est interessant de determiner une versiongrossiere de notre algorithme (algo. 1).

Algorithm 1 Algorithme du simplexeChoix de l’intersection initiale

Tant que la solution optimale n’est pas atteinte

Choisir une arete se rapprochant du sommet

Se deplacer jusqu’a l’intersection suivante

Cette generalisation nous permet donc d’approcher l’algorithme standard dusimplexe avec une idee globale du fonctionnement de ce dernier.

7

Page 14: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

2.4 Methode standard

2.4.1 Initialisation

Variables de jeu

La premiere etape va etre de modifier legerement le probleme de program-mation lineaire. Le but ici est de transformer les inegalites en egalites. Pourcela, il est necessaire d’ajouter a chaque inequation, une variable dite de jeu.Cette variable est un nombre entier positif. Ces valeurs sont comprises entre 0et +∞. De ce fait, elle permet, comme son nom l’indique, de combler ”l’espace”entre l’inequation et l’equation. Les variables du probleme initial sont appeleesvariables de decision et le probleme modifie est appele forme augmentee.

Reprenons le probleme donne en exemple de la section 2.2 :

MaximiserZ = 5x1 +4x2 +3x3

Sujet a2x1 +3x2 +x3 ≤ 54x1 +x2 +2x3 ≤ 113x1 +4x2 +2x3 ≤ 8x1, x2, x3 ≥ 0

Et ajoutons les variables de jeu x4, x5, x6 :Maximiser

Z = 5x1 +4x2 +3x3

Sujet a2x1 +3x2 +x3 +x4 = 54x1 +x2 +2x3 +x5 = 113x1 +4x2 +2x3 +x6 = 8x1, x2, x3, x4, x5, x6 ≥ 0

Terminologie

Rappelons que le but de l’algorithme du simplexe est de faire evoluer lesvaleurs des variables x de telle sorte a ameliorer (ou maintenir) la valeur dela fonction objectif. Le vecteur compose des valeurs pour chaque variable x estalors appele solution. Une solution est dite faisable si, apres substitution de cettederniere dans le probleme, l’ensemble des equations et des bornes individuellessur les variables ne sont pas violees. Dans le cas contraire, la solution est diteinfaisable.

Le probleme est exprime sous la forme suivante :

Maximiser

n∑

j=1

cjxj

Sujet a

n∑

j=1

aijxj ≤ bi (i = 1, 2, ...,m)

xj ≥ 0 (j = 1, 2, ..., n)

8

Page 15: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Les variables de jeu xn+i (i = 1, 2, ...,m) sont ajoutees et la fonction objectifest denotee par z. Ensuite, la forme augmentee est retranscrite de la manieresuivante :

xn+i = bi−

n∑

j=1

aijxj ≤ bi (i = 1, 2, ...,m)

=

n∑

j=1

cjxj

Cette representation du probleme definit un dictionnaire. Un dictionnaire esten quelque sorte un snapshot a une iteration donnee de l’algorithme. Ce snap-shot est compose des equations contenant les variables de la forme augmenteeainsi que de Z qui represente la valeur de la fonction objectif. Le fait que lesvariables de jeu se trouvent initialement uniquement dans une equation est misen evidence par le fait qu’elles se situent seules dans le membre de gauche desequations.

Un dictionnaire doit capturer l’interdependance entre les variables. Autre-ment dit, une solution liee a un dictionnaire doit etre une solution pour la totalitedes autres dictionnaires et vice versa.

Exemple :

x4 = 5 −2x1 −3x2 −x3

x5 = 11 −4x1 −x2 −2x3

x6 = 8 −3x1 −4x2 −2x3

Z = 5x1 +4x2 +3x3

Finalement, il est interessant de noter une distinction entre deux ensemblesde variables. Le premier est compose de l’ensemble des variables se trouvantdans le membre de gauche d’un dictionnaire. Cet ensemble est appele la baseet de ce fait, les variables de cet ensemble sont dites basiques. La particularitede ces variables reside dans le fait qu’elles ne sont presentes que dans une desequations de notre dictionnaire. Le second ensemble contient les variables ne setrouvant pas dans la base. Ces dernieres sont donc dites non basiques.

Solution initiale

Afin d’appliquer l’algorithme du simplexe, il nous faut donc creer notre pre-mier dictionnaire. Comme nous l’avons vu precedemment, il est assez intuitif etsimple de placer les variables de jeu dans la base. Cependant, le probleme de lasolution initiale demeure. Pour obtenir cette derniere, il suffit, dans un premiertemps, de fixer arbitrairement la valeur des variables non basiques en respec-tant leurs bornes individuelles. Ensuite il s’agit de calculer la valeur des variablesbasiques en substituant les variables non basiques au sein des equations.

Il est important de noter que la solution obtenue lors de cette manipulationpeut alors etre infaisable. Il est dans ce cas necessaire d’utiliser la methode dusimplexe en deux phases. Cette derniere permet de determiner si une solutionfaisable existe pour un probleme donne. Cette methode est decrite dans la section2.4.4. Dans un premier temps, admettons que la solution que nous avons obtenueest faisable.

9

Page 16: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

2.4.2 Recherche de l’optimum

Procede

A ce stade nous disposons donc d’un dictionnaire ainsi que d’une solutionfaisable. Afin de faire evoluer Z, il est necessaire de modifier les valeurs de notresolution tout en garantissant que cette derniere reste faisable.

Pour cela, nous allons dans un premier temps rechercher quelle variable estsusceptible d’ameliorer Z de facon significative. Cette etape correspond, dansla representation geometrique, a la recherche de la direction permettant de serapprocher du point optimal. La recherche de la direction est plus communementappelee choix de la variable entrante, car nous allons ici selectionner une variablenon basique qui va entrer dans la base.

Ensuite, il est necessaire de rechercher le gain maximal, αmax possible surcette variable. Ce gain est limite par l’impact que cette modification a sur lesautres variables. Il faut alors trouver la premiere variable basique a atteindre sesbornes pour un gain α. Geometriquement, cette etape correspond a determinerle deplacement maximal dans la direction trouvee a l’etape precedente ainsique l’intersection limitant cette progression. La recherche de cette variable estappelee choix de la variable sortante car nous cherchons la variable la pluscontraignante au sein de la base afin de la remplacer par la variable entrante.

Finalement, il est necessaire de pivoter les deux variables, de telle sorte aobtenir un nouveau dictionnaire et une nouvelle solution plus proche de la valeuroptimale. Cette etape correspond au deplacement d’un point au point suivantdans la representation geometrique.

Choix de la variable entrante

L’objectif est de trouver la variable non basique offrant le gain potentielle-ment le plus grand. La methode standard de choix de la variable entrante est derechercher la variable possedant le plus grand coefficient positif dans la fonctionobjectif. Pour le dictionnaire :

x4 = 5 −2x1 −3x2 −x3

x5 = 11 −4x1 −x2 −2x3

x6 = 8 −3x1 −4x2 −2x3

Z = 5x1 +4x2 +3x3

il s’agirait donc de la variable x1 car son coefficient (5) est le plus grand descoefficients positifs de la fonction objectif.

Le gain final sur z depend de deux choses : du gain αmax sur la variable ainsique du coefficient de cette derniere dans la fonction objectif. De ce fait, choisirla variable en fonction de ce coefficient pourrait amener un gain important surZ. La solution est declaree optimale dans le cas ou il n’y aurait aucun coefficientpositif non nul dans la fonction objectif.

Cette methode est de complexite O(m). Cependant dans les cas reels elle estrelativement peu efficiente et rarement utilisee. En effet, etant donne qu’elle neprend pas en compte le gain possible sur la variable, il est totalement possible quela valeur de Z augmente faiblement, voire pas du tout. Ceci risque d’augmenterfortement le nombre d’iterations necessaires a l’algorithme pour determiner lavaleur optimale. Il existe de nombreuses methodes afin de determiner la variableentrante. Certaines de ces methodes seront decrites dans la section 4.5.2 .

10

Page 17: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Choix de la variable sortante

Le choix de la variable sortante sert a determiner la variable basique laplus contraignante. Il s’agit de determiner pour chaque variable basique le gainmaximum que cette derniere peut offrir a la variable entrante.

La variable la plus contraignante est celle qui va retourner a sa borne infe-rieure la premiere. Cette variable est celle qui dispose du plus petit ratio positif− s

r, ou s est la constante de l’equation et r le coefficient de la variable entrante

dans cette equation. Le coefficient r doit etre negatif et non nul afin d’eviterd’avoir un gain negatif ainsi que des divisions par 0.

Le ratio obtenu correspond au gain maximal que la variable basique permeta la variable entrante avant de sortir de ses bornes.

Recherchons la variable sortante pour l’exemple de la section precedente.Nous avons choisi comme variable entrante x1.

Pour la premiere equation, ou la variable basique est x4, calculons le ratio :

s = 5, r = −2⇒ ratio1 = −s

r= −

5

−2= 2.5

Pour la seconde equation ayant comme variable basique x5 :

s = 11, r = −4⇒ ratio2 = −s

r= −

11

−4= 2.75

Et finalement la derniere equation qui a pour variable basique x6 :

s = 8, r = −3⇒ ratio3 = −s

r= −

8

−3= 2.667

Le ratio le plus petit est ratio1 = 2.5 et donc la variable sortante sera x4.

Dans le cas ou aucun coefficient r serait negatif et non nul, le probleme se-rait alors non borne. C’est-a-dire que la valeur optimum serait infinie et qu’ilexisterait donc une infinite de solutions possibles. Il suffirait d’imaginer un pro-bleme definissant un rectangle (cas particulier de polygone) dont il manque undes cotes.

La complexite de cette methode est de O(n). Chacun des calculs de cetteetape est obligatoire. Il n’existe donc pas d’heuristiques pour ameliorer ses per-formances (temps de calculs, meilleurs choix). Cependant, nous verrons dans lasection 4.5.2 que cette fonction a une importance cruciale en ce qui concerne lastabilite de l’algorithme.

Pivotage

Une fois les variables entrante et sortante determinees, il est necessaire d’ef-fectuer le pivotage. Ceci consiste a placer la variable entrante dans la base etd’en retirer la variable sortante.

La premiere etape consiste a pivoter la variable entrante et la variable sor-tante. Le pivot est donc le coefficient de la variable entrante dans l’equation oula variable sortante est basique.

La variable entrante va entrer dans la base dans le membre gauche de l’equa-tion. La variable sortante va quitter la base et donc rejoindre le membre droitde l’equation.

11

Page 18: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Cette equation va ensuite etre divisee par le pivot. Cette operation norma-lise le coefficient de la variable entrante afin qu’elle puisse etre dans la base.Neanmoins, avant que cette variable ne soit consideree comme basique, il estnecessaire de substituer cette variable dans les autres equations ainsi que dansla fonction objectif. Ceci afin qu’elle soit uniquement presente dans l’equationou elle est basique.

A l’issue du pivotage, la variable entrante est presente dans l’equation ou lavariable sortante etait basique et uniquement dans cette equation. De meme, lavariable sortante a repris sa place dans les autres equations ainsi que dans lafonction objectif.

Appliquons donc le pivotage a notre exemple, que nous rappelons ici :x4 = 5 −2x1 −3x2 −x3

x5 = 11 −4x1 −x2 −2x3

x6 = 8 −3x1 −4x2 −2x3

Z = 5x1 +4x2 +3x3

La variable entrante est x1 et la variable sortante x4. Commencons par pivoterles deux variables :

2x1 = 5 −3x2 −x3 −x4

x5 = 11 −4x1 −x2 −2x3

x6 = 8 −3x1 −4x2 −2x3

Z = 5x1 +4x2 +3x3

La variable x1 est alors normalisee dans l’equation ou elle va devenir basique,soit la premiere equation :

x1 = 2.5 −1.5x2 −0.5x3 −0.5x4

x5 = 11 −4x1 −x2 −2x3

x6 = 8 −3x1 −4x2 −2x3

Z = 5x1 +4x2 +3x3

Finalement, il suffit de substituer la variable x1 dans les autres equations, ycompris la fonction objectif. Detaillons le procede pour la deuxieme equation :

x5 = 11− 4x1 − x2 − 2x3

x5 = 11− 4(2.5− 1.5x2 − 0.5x3 − 0.5x4)− x2 − 2x3

x5 = (11− 10) + (6− 1)x2 + (2− 2)x3 + 2x4

x5 = 1 + 5x2 + 2x4

En effectuant aussi la substitution dans la troisieme equation ainsi que dans lafonction objectif, nous obtenons au final le dictionnaire suivant :

x1 = 2.5 −1.5x2 −0.5x3 −0.5x4

x5 = 1 +5x2 +2x4

x6 = 0.5 0.5x2 −0.5x3 +1.5x4

Z = 12.5 −3.5x2 +0.5x3 −2.5x4

La solution liee a ce dictionnaire est x1 = 2.5, x2 = 0, x3 = 0, x4 = 0, x5 =1, x6 = 0.5 et z = 12.5. Cependant, la valeur optimale n’est pas encore trouveecar il demeure un coefficient positif dans la fonction objectif.

12

Page 19: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

2.4.3 Exemple

Nous allons donc terminer de resoudre notre exemple. Nous sommes partis dudictionnaire suivant :

x4 = 5 −2x1 −3x2 −x3

x5 = 11 −4x1 −x2 −2x3

x6 = 8 −3x1 −4x2 −2x3

Z = 5x1 +4x2 +3x3

Apres un pivotage sur la variable entrante x1 et la variable sortante x4 (voirsections precedentes) nous avons obtenu ce dictionnaire :

x1 = 2.5 −1.5x2 −0.5x3 −0.5x4

x5 = 1 +5x2 +2x4

x6 = 0.5 0.5x2 −0.5x3 +1.5x4

Z = 12.5 −3.5x2 +0.5x3 −2.5x4

La seule variable entrante eligible est x3 car c’est la seule a posseder uncoefficient positif non nul dans la fonction objectif. Seule la premiere et la troi-sieme equations disposent d’un coefficient negatif non nul dans la colonne de lavariable entrante :

Premiere equation : s = 2.5, r = −0.5⇒ ratio1 = −s

r= −

2.5

−0.5= 5

Troisieme equation :s = 0.5, r = −0.5⇒ ratio3 = −s

r= −

0.5

−0.5= 1

La variable sortante est donc x6 car le plus petit ratio est ratio3.

Apres le pivotage sur la variable entrante x3 et la variable sortante x6, nousobtenons le dictionnaire suivant :

x1 = 2 −2x2 −2x4 +x6

x5 = 1 +5x2 +2x4

x3 = 1 x2 +3x4 −2x6

Z = 13 −3x2 −1x4 −x6

Ce dictionnaire ne comporte plus de variable entrante eligible. Nous avonsdonc trouve la solution optimale. La solution de ce probleme est x1 = 2, x2 =0, x3 = 1, x4 = 0, x5 = 1, x6 = 0 et z = 13.

Nous pouvons finalement verifier notre resultat en prenant la fonction ob-jectif initiale de notre probleme et en y substituant la solution trouvee.Soit, maximiser 5x1 + 4x2 + 3x3 ⇒ 5 · 2 + 4 · 0 + 3 · 1 = 13La valeur obtenue est la meme que celle trouvee a la derniere iteration du sim-plexe. Le resultat est donc correct.

2.4.4 Cas particuliers

Solution initiale infaisable

Le but de cette section est de decrire la methode a appliquer afin de deter-miner s’il existe une solution initiale faisable pour un probleme. Cette methodes’appelle le simplexe en deux phases. Elle consiste a appliquer la methode dusimplexe, dans un premier temps, sur un probleme modifie afin de trouver unesolution faisable. Ce probleme modifie s’appelle probleme auxiliaire et consiste

13

Page 20: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

a minimiser les infaisabilites sur les variables. La seconde phase correspond ala resolution du probleme selon la methode que nous avons vu precedemment apartir de la solution initiale faisable trouvee lors de l’etape precedente.

Il existe differentes methodes pour mettre la main sur une solution faisable.Une premiere methode consiste a ajouter des variables artificielles afin de debu-ter avec une solution initiale faisable. Ces variables ont pour but d’annuler lesinfaisabilites.

Prenons un probleme de programmation lineaire sous sa forme augmentee :

Maximiser

n∑

j=1

cjxj

Sujet a

n∑

j=1

aijxj = bi (i = 1, 2, ...,m)

lj ≤ xj ≤ uj (j = 1, 2, ..., n)

Nous allons donc ajouter les variables artificielles xn+i et donc modifier leprobleme original :

n∑

j=1

aijxj + xn+i = bi (i = 1, 2, ...,m)

lj ≤ xj ≤ uj (j = 1, 2, ..., n+m)

Il est donc desormais necessaire de determiner les bornes ln+i et un+i pour lesvariables artificielles. Pour cela, il suffit de fixer les valeurs des autres variablesxj a une de leurs bornes, ou a 0 si les variables ne sont pas bornees, de telle sorteque les variables soient initialement faisable. Il faut alors utiliser cette solutionpartielle pour calculer la valeur des variables artificielles :

xn+i = bi −∑

aijxj

A l’aide des valeurs calculees precedemment pour xn+i, nous pouvons fixerles bornes de ces variables artificielles. Celles ayant une valeur negative aurontpour bornes ln+i = −∞ et un+i = 0 alors que celles possedant une valeurpositive auront pour bornes ln+i = 0 et un+i =∞.

Les variables artificielles determinent la magnitude de l’infaisabilite pourchaque equation. Il est alors possible de mesurer l’infaisibilite du dictionnairecourant en sommant les variables artificielles :

n∑

i=1

wn+ixn+i

ou wn+i =

{

1 si xn+i < 0−1 si xn+i ≥ 0

L’astuce est alors d’appliquer l’algorithme du simplexe avec cette fonctioncomme fonction objectif. Elle est souvent appelee fonction objectif auxiliaire.Logiquement, si le resultat de la minimisation de cette fonction se trouve etrela valeur optimale, Z = 0, alors l’ensemble des variables artificielles sont nulleset donc le probleme est faisable. Il s’agit donc de resoudre le probleme suivant :

Minimiser∑

wn+ixn+i

Sujet a

n∑

j=1

aijxj + xn+i = bi (i = 1, 2, ...,m)

lj ≤ xj ≤ uj (j = 1, 2, ..., n+m)

14

Page 21: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Si la solution a ce probleme n’est pas 0, alors il n’existe pas de solutionfaisable pour ce probleme et ce dernier est donc infaisable.

Sinon, avant de debuter la seconde phase, il est necessaire de s’occuper desvariables artificielles qui ne sont plus necessaires. Une premiere possibilite estde modifier leurs bornes a ln+i = 0 et un+i = 0. L’inconvenient est que leprobleme va contenir de nombreuses variables inutiles. La seconde possibiliteest donc de supprimer ces variables. Celles qui ne sont pas dans la base peuventetre supprimees sans autre, alors que celles qui y sont requierent des pivotagesne modifiant pas Z afin de les y sortir avant de les supprimer.

Une fois cette operation faite, il suffit alors d’appliquer l’algorithme du sim-plexe a partir du dernier dictionnaire en reprenant la fonction objectif du pro-bleme initial.

L’inconvenient de cette methode reside dans le fait qu’il est necessaire d’ajou-ter une variable artificielle a chaque equation infaisable. La taille du problemepeut de se fait grandement croıtre. Il est possible alors d’utiliser une methodelegerement differente.

Afin de rendre le probleme temporairement faisable, les bornes des variablesinfaisables vont etre elargies de telle sorte a les rendre faisables :

li =

{

li si xi ≥ li−∞ sinon

ui =

{

ui si xi ≤ ui

∞ sinon

Les variables plus petites que leur borne initiale li vont former l’ensemble P

tandis que celles qui sont plus grandes que ui formeront l’ensemble Q. Soit,

Q = {i | xi > ui}P = {i | xi < li}

Il est alors possible de definir les infaisabilites comme la difference entre lesvariables infaisables et leurs bornes initiales la plus proche. La somme des infai-sabilites s’ecrit donc :

i∈P

(li − xi) +∑

i∈Q

(xi − ui)

Afin de simplifier le calcul de cette mesure d’infaisabilite, il est possibled’ignorer les constantes qui n’ont aucune influence sur l’evolution de l’estima-tion de l’infaisabilite globale :

i∈Q

xi −∑

i∈P

xi

Il est desormais possible d’appliquer l’algorithme du simplexe a cette ver-sion modifiee du probleme en utilisant la mesure d’infaisabilite comme fonctionobjectif.

Cependant, il sera necessaire a chaque iteration de verifier les ensembles P

et Q. En effet, si une variable infaisable rentre dans ses bornes initiales et doncdevient faisable, il est necessaire de corriger ses bornes et de mettre a jour lamesure d’infaisabilite. Si a force d’iterations, l’algorithme arrive a rendre toutes

15

Page 22: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

les variables faisables, alors nous avons une solution initiale faisable. Autrement,il n’existe pas de solution faisable.

Il ne reste plus qu’a appliquer la methode du simplexe sur le meme probleme,mais avec la fonction objectif initiale.

Cette methode necessite plus de calculs que la methode precedente du faitde la verification a chaque iteration de l’etat du probleme mais reduit la tailledu probleme auxiliaire de facon significative.

Cycles et iterations degeneratives

Il est possible que l’algorithme cycle sur des iterations degeneratives. Cesdernieres sont des iterations ou la valeur de Z stagne. Les methodes de selectiondes variables entrantes et sortantes peuvent alors creer des cycles ne garan-tissant pas la terminaison de l’algorithme. Il existe deux methodes theoriquespermettant d’eviter les cycles.

La premiere, smallest subscribt rule, consiste a determiner un seuil sur lenombre d’iterations degeneratives a partir duquel l’algorithme est considerecomme etant dans un cycle.

A partir de la, il suffit d’appliquer une version modifiee des fonctions de choixdes variables. Ces fonctions sont basees sur le meme principe que celles que nousavons vu precedemment a l’exception qu’elles vont choisir la variable possedantle plus petit indice parmi les variables eligibles et non pas forcement la variableoffrant le plus grand gain potentiel. Des lors que la valeur de l’objectif change,il suffit de reprendre l’utilisation des fonctions standards.

Cette methode est simple et peu couteuse en calcul mais risque d’engendrerun nombre important d’iterations supplementaires. En effet, l’algorithme vaeffectuer plusieurs cycles en fonction de la taille du seuil avant de determiner qu’ilest probablement dans un cycle. Ensuite, il devra encore effectuer un nombre nonnegligeable d’iterations degeneratives avant de modifier la valeur de l’objectif.

Il existe une autre methode, perturbation method, qui consiste a ajouter unevaleur ǫ a chaque equation de l’algorithme. Le probleme est alors defini commesuit :

Maximiser

n∑

j=1

cjxj

Sujet a

n∑

j=1

aijxj = bi + ǫi (i = 1, 2, ...,m)

lj ≤ xj ≤ uj (j = 1, 2, ..., n)

0 < ǫm ≪ ǫm−1 ≪ ....≪ ǫ1 ≪ 1

Cette methode permet d’eviter les cycles car il n’existe plus reellement d’ite-ration degenerative, etant donne que les differents ǫ biaisent le choix des va-riables.

Bornes individuelles

L’algorithme du simplexe a ete defini uniquement pour des variables posi-tives jusqu’a present. Neanmoins, il est possible que les bornes des variablessoient definies par n’importe quelle valeur reelle, comme nous l’avons vu dansle simplexe a deux phases.

16

Page 23: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Il est alors necessaire de modifier le probleme ou l’algorithme pour resoudrece type de probleme.

Modifier le probleme consiste a ajouter des equations pour limiter chaquevariable possedant des bornes individuelles autres que li = 0 et ui = ∞. Cettesolution, bien que facile a mettre en place, n’est pas du tout efficiente. Rappelonsque chaque nouvelle equation necessite une variable de jeu et potentiellementune variable artificielle. Dans le pire des cas, le probleme de taille initiale

m · (n+m) = mn+m2

deviendrait un probleme de taille(m+ 2n) · (n+ (m+ 2n)) = (m+ 2n) · (3n+m) = m2 + 6n2 + 5mn

La modification de l’algorithme requiert de changer les methodes de choixdes variables afin de prendre en compte les bornes des variables en plus descontraintes des equations. Ces changements ne modifient pas la structure de basede l’algorithme mais necessitent un peu plus de calculs, ce qui reste nettementplus efficient que de modifier le probleme.

2.5 Methode du simplexe revise

2.5.1 Generalites

La methode du simplexe revise est la methode la plus communement imple-mentee grace a ses performances sur les problemes creux. Elle est basee sur lememe principe que celui du simplexe standard. L’ajout des variables de jeux,l’initialisation, la methode du simplexe en deux phases, etc. sont aussi utilisesdans cette methode.

La difference entre ces deux methodes est que la methode du simplexe revisen’utilise pas les dictionnaires. En effet, seulement une petite partie du diction-naire est utilisee a chaque iteration afin de calculer la solution suivante. La partiedu dictionnaire utile est reconstruite a chaque iteration a partir du problemeinitial. Cette reconstruction demande d’effectuer deux resolutions de systemesd’equations lineaires par iteration.

Dans un premier temps, nous allons voir comment le probleme est decom-pose. Ensuite, les methodes de choix des variables ainsi que celles de mise ajour du probleme seront decrites. Finalement, certaines techniques optimisantla resolution des systemes d’equations lineaires seront rapidement citees. Cesdernieres sont d’une importance cruciale, les performances accrues de l’algo-rithme en dependent totalement.

2.5.2 Decomposition du probleme

En utilisant le probleme initial sous sa forme augmentee :

Maximiser

n∑

j=1

cjxj

Sujet a

n∑

j=1

aijxj = bi (i = 1, 2, ...,m)

xj ≥ 0

il est possible d’exprimer un dictionnaire sous la forme d’un systeme d’equations

17

Page 24: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

lineaires a resoudre. Exprimons d’abord ce probleme sous forme de vecteurs etmatrices

Maximiser cxSujet a Ax = b

x ≥ 0

Ax = b exprime donc un systeme d’equations lineaires ou les seules inconnuessont les elements du vecteur xB composes des variables basiques. Nous pouvonsdonc decomposer le probleme en deux sous-ensembles : la partie basique et lapartie non-basique. Soit,

Ax = ABxB +ANxN

Nous pouvons recrire le systeme d’equations sous la forme suivante :ABxB = b−ANxN

AB etant une matrice inversible, il est possible de diviser le systeme d’equationspar cette derniere.

B = AB

xB = B−1b−B−1ANxN

En suivant le meme procede pour la fonction objectif cx nous obtenons :z = cx = cBxB + cNxN

Et apres substitution de xB

z = cBB−1b+ (cN − cBB

−1AN)xN

Finalement, nous pouvons exprimer un dictionnaire a partir du problemeinitial comme suit :

xB = B−1b−B−1ANxN

z = cBB−1b+ (cN − cBB

−1AN)xN

Le vecteur resultant x∗

B = B−1b contient les valeurs des variables basiquesliees a ce dictionnaire.

Maintenant que nous avons vu comment il est possible de trouver un diction-naire a partir du probleme initial, nous allons voir comment trouver les variablesentrante et sortante.

2.5.3 Choix de la variable entrante

Etant donne que nous n’avons pas le dictionnaire en memoire, il est necessairede calculer les coefficients des variables non basiques de la fonction objectif,definis par cN − cBB

−1AN. Ces derniers vont etre calcules en deux etapes.Premierement, nous voulons determiner le vecteur y = cBB

−1. Pour cela, ilfaut resoudre le systeme d’equations yB = cB.

Ensuite, nous pouvons calculer cN − yAN. Il est desormais possible, commedans l’algorithme standard, de selectionner la variable non-basique possedant lecoefficient positif le plus grand parmi ceux que nous venons de calculer.

Cependant, il est judicieux de remarquer que les coefficients de la fonctionobjectif sont calculables de maniere individuelle, cj − ya ou a est la colonnede AN correspondant a cj . Dans ce cas-la, n’importe quelle valeur garantit que

18

Page 25: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

ya < cj est eligible (sans garantie sur le gain produit par le choix de cettevariable).

2.5.4 Choix de la variable sortante

Lors de l’etape precedente, nous avons donc choisi la variable entrante xj

ainsi que sa colonne a. Il nous faut desormais determiner quelle variable basiqueest la plus contraignante. Une fois de plus, nous devons calculer les differentscoefficients necessaires a cette etape etant donne que le dictionnaire courantn’est pas disponible.

Reprenons donc le systeme d’equations lineaires xB = B−1b−B−1ANxN.Nous allons tout d’abord calculer la colonne correspondant a la variable entrante.Cette colonne, d, se trouve dans la matrice B−1AN. Pour trouver sa valeur, iln’est pas necessaire de calculer toute la matrice, il suffit d’utiliser la colonne a,soit d = B−1a. Nous devons donc resoudre le systeme d’equations Bd = a.

Ensuite, nous devons determiner le gain t maximal des variables basiquesx∗

B garantissant que x∗

B − td > 0. La variable sortante est celle qui corresponda la variable du vecteur x∗

B etant la plus contraignante (correspondant au t

maximal).

2.5.5 Mise a jour du probleme

Il est desormais necessaire de mettre a jour le probleme. C’est cette etapequi offre un gain important par rapport a la methode du simplexe standard.Jusqu’a present le choix des variables necessite plus de calculs que la methodestandard etant donne qu’il faut resoudre des systemes d’equations linaires.

Il suffit dans cette etape de placer la valeur de la variable entrante a t etde remplacer les valeurs de x∗

B par x∗

B − td. Finalement, il faut remplacer lacolonne de la variable sortante dans B par celle de la variable entrante.

2.5.6 Optimisation importante

La methode du simplexe revise n’est pas efficiente si les systemes d’equa-tions yB = cB et Bd = a sont calcules entierement a chaque equation car lacomplexite de cette tache augmente au fur et a mesure que B evolue au fil desiterations. Il existe cependant des techniques qui permettent de decomposer lamatrice B en une suite de matrice simple a resoudre.

Factorisation eta de la base

Une de ces techniques s’appelle factorisation eta de la base. Elle decoulede l’observation qu’a chaque etape, la matrice B n’a qu’une colonne qui estmodifiee. Il est donc possible de decrire cette matrice a l’etape k, Bk commeetant Bk = Bk−1Ek ou Ek est la matrice unite dont la colonne de la variableentrante a ete remplacee par le vecteur d calcule precedemment dans l’algorithme( Bk−1d = a).

La matrice Bk peut donc etre factorisee par une suite de matrice E,B1 = E1,B2 = E1E2,BK = E1E2...Ek

Cette factorisation permet alors de resoudre les systemes d’equations yBk = cB

19

Page 26: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

en k etapes, (((yE1)E2)..)Ek = cB. Il s’agit donc de resoudre y∗

kEk = cB, puisy∗

k−1Ek−1 = y∗

k, ..., yE1 = y∗

2.Cette technique est efficiente car il est bien plus facile de resoudre les sys-

temes d’equations contenus dans les matrices E que dans une matrice Bk com-plexe. De plus, les matrices eta sont faciles a stocker car uniquement une deleur colonne est differente de la matrice identite. Il suffit donc de stocker cettecolonne ainsi que sa position dans la matrice eta.

Cette technique s’applique de facon similaire afin de resoudre le systemesd’equations Bd = a, soit resoudre les k matrices eta de la decomposition sui-vante, E1(E2(..(Ekd))) = a.

Decomposition LU

Il est alors possible de tirer profit d’une decomposition en matrices trian-gulaires. Ce type de decomposition consiste a exprimer une matrice comme leproduit d’une matrice triangulaire inferieure et d’une matrice triangulaire supe-rieure : B = LU. Cette decomposition est utilisee afin de resoudre des systemesd’equations lineaires, Bx = LUx = b. Il s’agit alors de resoudre dans un pre-mier temps Ly = b afin de trouver y, puis de resoudre Ux = y afin de trouverx.

Cette technique est interessante lorsque le systeme d’equations doit etre re-solu plusieurs fois car il suffit de substituer progressivement les valeurs dans lamatrice L (de haut en bas) et dans la matrice U (de bas en haut) pour resoudrele systeme d’equations.

Nous allons donc utiliser une decomposition LU afin de resoudre les differentssystemes d’equations lies aux matrices eta qui sont les memes a chaque iteration(mis a part la nouvelle matrice eta liee a la derniere iteration). Nous avons notrematrice basique exprimee sous la formeBk = B0E1E2...Ek ouB0 est la matricede base initiale et nous devons resoudre ((((yB0)E1)E2)..)Ek = cB ainsi queB0(E1(E2(..(Ekd)))) = a.

Commencons par effectuer la decomposition LU de la matrice de base initialeB0. Cette decomposition est exprimee par LmPm...L1P1B0 = Um...U1 (ouP est la matrice de permutation). A l’iteration k, en conjonction avec l’ajoutde matrice eta, nous obtenons alors LmPm...L1P1Bk = Um...U1E1...Ek. Cesmatrices peuvent donc etre memorisees et a chaque iteration, seule la nouvellematrice Ek+1 doit etre ajoutee a leur suite.

Afin de resoudre yBk = cB, il s’agit alors d’effectuer l’operation BTRAN(backward transformation) qui consiste a resoudre les differents systemes d’equa-tions de la fin au debut de la suite de matrice, soit : resoudre dans un premiertemps (((y′Um)Um−1)...)Ek = cB puis a calculer y = (((y′LmPm)...)L1P1).

L’operation FTRAN (forward tranformation) est l’operation inverse et per-met de resoudre Bd = a, soit : calculer a′ = ((LmPm)...)L1P1a puis resoudreUm(Um−1(...(Ekd))) = a′. Cette operation consiste donc a une utilisation dela suite de matrice allant du debut a la fin de cette derniere.

Finalement, il est important de noter que cette structure va croıtre a chaqueiteration. Afin d’eviter que la structure de matrices memorisees devienne tropimportante et que les imprecisions de calcul ne s’accumulent, il est necessaire,periodiquement, de repartir depuis zero. Pour cela, il faut decomposer la matriceBk afin de pouvoir effacer les matrices eta.

20

Page 27: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Chapitre 3

CUDA

3.1 Introduction

Nous allons dans ce chapitre etudier le concept de programmation sur GPU,plus communement appele GPGPU pour General-Purpose Computing on Gra-phics Processing Units. Plus precisement, nous allons nous interesser a CUDA(Compute Unified Device Architecture). CUDA est l’architecture de calcul deve-loppe par NVIDIA pour ses GPU. Les informations utilisees afin de decrire cettearchitecture sont tirees du manuel de programmation [1] fourni par NVIDIA.

Tout comme les CPU, les GPU ont vu leur puissance de calcul grandementcroıtre durant ces dernieres annees. Cependant, le traitement d’images a amenel’architecture des cartes graphiques a tirer profit du parallelisme de donnees etd’instructions. En effet, les images etant memorisees sous forme de matrices,il est generalement necessaire d’appliquer une modification a l’ensemble de lamatrice. Ces modifications peuvent typiquement etre des translations, homo-theties, rotations, des combinaisons de ces operations ou encore d’autres calculsbien plus complexes.

Cette architecture parallele est de type Single Instruction Multiple Threads(SIMT) qui est proche d’une architecture Single Instruction Multiple Data (SIMD).La difference majeure entre ces deux architectures est la gestion avancee detaches permettant des changements de contexte rapides dans l’architecture detype SIMT. Cette derniere est capable d’executer plusieurs taches effectuant lameme operation en meme temps. La derniere famille de carte graphique, tesla,dediee au calcul, approche les performances de supercalculateurs pour un prixcompetitif. Le nombre d’operations pour des nombres reels en simple precisionvarient de 600 a 1000 GFLOPS, pour des nombres reels en double precision, de80 a 512 GFLOPS par GPU selon le modele.

La programmation CUDA se fait en C ou en fortran. Cependant, de nom-breux wrappers permettant le developpement en python, perl, matlab, sont dis-ponibles. Il est important de noter qu’un GPU n’est pas une unite independanteen soi. Il est necessaire de disposer d’une machine standard (CPU) commandantle GPU. Cette machine beneficie de l’acces a la memoire du GPU afin d’echan-ger avec lui des donnees et doit aussi initier l’execution des fonctions de calculs(routines) sur le GPU.

Cette technologie, aidee par une communaute importante, evolue de ma-

21

Page 28: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

niere continue. Afin d’assurer des performances interessantes, NVIDIA fournitun ensemble de librairies pour les operations essentielles telles que celles d’al-gebre lineaire, les transformees de Fourier, la generation de nombres aleatoiresou encore les rendus graphiques.

Dans un premier temps, nous allons etudier l’architecture globale d’un GPU.Nous allons nous interesser a la maniere dont est parallelise un travail sur CUDA,depuis un programme jusqu’a la plus petite unite de calcul, un processeur.

Ensuite, nous verrons un des points cruciaux de cette technologie : la me-moire. En effet, ce type d’architecture depend fortement de l’acces aux donneesainsi que de leur repartition. Nous verrons donc, comment ces dernieres peuventetre memorisees a chaque niveau de l’architecture.

Finalement, nous nous interesserons a plusieurs criteres importants lors dela programmation sur GPU. Il est necessaire de faire attention a certaines reglesafin d’obtenir des performances competitives avec des systemes plus standards(CPU).

3.2 Architecture

3.2.1 Vue globale

L’architecture d’un GPU, plus communement appele device, est relativementcomplexe. De plus, les divers modeles de GPU possedent des architectures le-gerement differentes. Par exemple, la derniere famille de GPU NVIDIA, fermi,dispose d’une organisation differente des processeurs ainsi que quelques amelio-rations au niveau de la memoire.

Chaque famille de GPU dispose d’un identifiant de capacites, appele com-pute capability (CC ). Les GPUs possedant un CC plus petit que 1.3 ne sontpas capables d’effectuer des calculs en double precision. La derniere generation,fermi, est identifiee par un CC de type 2.x car son architecture est plus adapteeau calcul en double precision et qu’elle est capable d’effectuer des controles etcorrections d’erreurs sur la memoire.

Cette etude portera principalement sur l’architecture utilisee dans le cadrede ce travail. Cette architecture est caracterisee par un CC egal a 1.3. Les archi-tectures disposant d’un CC plus petit que 1.3 sont concut de facon similaire. Parla suite, nous distinguerons les differents modeles de GPU et donc d’architectureen utilisant leur CC si necessaire.

La figure 3.1 decrit l’ensemble de l’architecture. Nous pouvons voir qu’ilexiste differents niveaux de memoire. Ces derniers sont representes en orangesur la figure. De meme, les unites de calculs ont leur architecture propre : undevice est compose de multiprocesseurs eux-memes composes de processeurs.

Ces differents niveaux vont etre decrits dans les sections suivantes. Nousdebuterons par la repartition des taches ainsi que par l’organisation des proces-seurs. Il sera ensuite plus aise de comprendre l’architecture de la memoire.

3.2.2 Organisation des taches

Kernel

Le device est l’unite la plus grossiere du systeme et elle est accessible depuisun ordinateur standard. Un programme CUDA, kernel, est execute sur un device.

22

Page 29: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Figure 3.1 – Architecture globale

Ce dernier ne peut executer qu’un seul kernel a la fois, a l’exception du plusrecent modele de GPU, fermi, qui peut en executer plusieurs a la fois.

Un kernel est compose d’une multitude de taches. Ces dernieres sont orga-nisees en unites abstraites, ceci afin de les repartir de facon efficiente sur lesdifferents multiprocesseurs, puis processeurs.

La figure 3.2 represente l’organisation des taches au sein d’un kernel.

Tache

Les taches sont executees sur les processeurs. Comme nous pouvons le remar-quer dans la figure 3.1, les processeurs appartenant a un meme multiprocesseursont controles par une unite d’instructions. Cette derniere va emettre a chaquecycle une instruction que chaque processeur devra effectuer en utilisant les re-gistres a sa disposition. Dans le cas optimal, les taches devraient faire exactementle meme travail a chaque cycle. La difference entre deux taches va se trouverdans les donnees contenues dans les registres. Le choix de donnees differentes estpossible grace a l’identifiant des taches. En effet, chaque tache possede un iden-tifiant propre. Ce dernier rend alors possible la lecture et l’ecriture de donneesparticulieres pour chaque tache.

23

Page 30: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Figure 3.2 – Repartition des taches

Une premiere illustration simple serait une addition de deux vecteurs. Chaquetache aurait pour mission, de charger un element de chacun des vecteurs, de lesadditionner et de placer le resultat dans un troisieme vecteur. En admettantqu’il y ait autant de taches que le vecteur possede d’elements, chaque proces-seur effectuerait exactement les memes instructions, seule l’adresse des donneesdans la memoire serait differente.

Block

Les taches sont alors reparties dans des blocks. L’identifiant des taches estcompose de deux variables idX et idY , de maniere a permettre des organisationsen deux dimensions au sein d’un block. Ceci peut etre fortement utile lors decalculs sur des matrices afin de maintenir une organisation similaire entre lesdonnees et les taches. Le nombre maximal de taches par block est de 512 (1024pour les CC ≥ 2.0 ).

Un block va etre execute sur un multiprocesseur (streaming multiprocessor)compose de 8 processeurs (2x16 pour les CC ≥ 2.0). Les taches vont etre de-composees en groupe de 32 taches, appele warp. Un warp est la plus petite uniteexecutable par un multiprocesseur.

Etant donne que le changement de contexte sur les processeurs est extre-mement rapide, l’idee va etre de tirer profit d’un pipeline compose de 4 tachesminimum par processeur, d’ou la decomposition en warp (8 processeurs fois 4

24

Page 31: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

taches). L’utilisation de pipelines permet d’emettre une nouvelle serie d’instruc-tions pendant qu’un groupe de taches est en train d’effectuer son instruction etd’attendre le resultat.

Par exemple, les instructions d’acces a la memoire sont generalement treslentes et donc attendre l’arrivee des donnees bloquerait le processeur inutile-ment. Un multiprocesseur peut stocker jusqu’a 8 blocks differents a la fois, creantde la sorte un pipeline important. Admettons que nous ayons des blocks de 512taches, nous pourrions avoir dans le pipeline 8 blocks composes de 16 warps,soit 512 taches dans le pipeline de chaque processeur. Ceci permettrait un flotcontinu d’instructions meme si une partie des taches est en attente sur leursdonnees.

Ces differents degres de parallelisme seront traites plus en detail dans lessection 5.2 et 4.5.3.

Grid

Les blocks forment ensuite une grille (grid). Ce niveau d’organisation sup-plementaire est necessaire afin de placer en attente les blocks ne pouvant etreexecutes. Ceci se produit lorsque la totalite des multiprocesseurs sont saturesde blocks. De ce fait, il est uniquement possible de synchroniser des taches ausein d’un meme block.

Un block possede un identifiant en trois dimensions representant sa positiondans la grille. Afin de creer un identifiant unique pour chaque tache, il est alorsnecessaire de combiner la position de la tache dans son block a la position de cedernier dans la grille.

3.2.3 Memoires

Schema

Nous allons desormais voir la decomposition de la memoire dans un device.Chaque niveau de l’architecture dispose d’espaces memoire qu’il peut accederde maniere plus ou moins efficiente. La figure 3.3 decrit les niveaux de memoireen fonction de leur accessibilite.

Memoire globale

La memoire globale est la memoire de base du device. Cet espace permetl’echange de donnees entre un CPU et un GPU. Les donnees necessaires a uncalcul sont placees dans cette espace et les resultats aussi. Cette memoire estaccessible depuis chaque niveau de l’architecture, cependant son acces est lent.

Les instructions de chargement et d’ecriture dans cette memoire necessitentplusieurs centaines de cycles avant d’etre executees. De plus, l’echange de don-nees entre les taches via cette memoire n’est generalement pas utilise ou alorsdans de tres rares cas. En effet, les taches des differents blocks etant asynchrones,il est difficile de gerer les acces a cette memoire et de garantir l’integrite des don-nees.

Il existe cependant certaines solutions permettant de synchroniser les blocks.Ces solutions necessitent d’utiliser des operations atomiques sur la memoireglobale, ce qui est premierement lent et deuxiemement possible uniquement si

25

Page 32: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Figure 3.3 – Decomposition de la memoire

aucun block ne se trouve en attente d’execution. Ce dernier cas risquerait degenerer des deadlocks.

Finalement, il est interessant de citer quelques particularites de la memoireglobale. Il existe deux types speciaux de memoire globale : les textures et l’espacereserve aux constantes. Ces memoires offrent des performances bien meilleuresque la memoire globale car elles disposent de caches permettant des acces bienplus rapides. Leur inconvenient est qu’elles sont accessibles depuis les taches enlecture uniquement. Seules des ecritures dirigees par le CPU sont possibles. Deplus, leur taille est limitee. L’espace reserve aux constantes ne peut depasserquelques kB et les textures sont contraintes a des limites de tailles qui varientselon son nombre de dimensions (voir [1] appendix A).

Memoire partagee

Chaque block dispose d’une memoire partagee afin de communiquer en in-terne. Cette memoire est tres performante lorsqu’elle est utilisee correctement.C’est-a-dire qu’il est necessaire de gerer correctement les acces a cette derniere.Les differentes taches d’un block doivent etre coordonnees correctement afinqu’elles accedent a cette memoire sans effectuer de collisions. Si deux tachestentent d’acceder a la meme adresse memoire, alors les delais d’acces a celle-ci

26

Page 33: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

s’accumuleraient et ralentiraient la totalite des taches du block.Finalement, cet espace de memoire est de taille limitee. Comme son nom

l’indique, elle est partagee par les taches d’un block. Si le calcul necessitait queles taches disposent de beaucoup de memoire partagee, il serait possible que latotalite des warps d’un block ne puisse etre execute parallelement (pipeline).Ceci afin de garantir que chaque tache dispose de suffisamment de memoire. Lepipeline serait alors moins plein, masquant moins bien les instructions d’accesa la memoire.

Memoire locale

Les taches disposent d’une memoire locale se situant dans la memoire globale.Cette memoire est donc lente, mais permet de memoriser un nombre importantde donnees. Dans la majorite des cas, la memoire partagee est utilisee en prioriteen raison de ses performances. Cependant, si une tache necessitait un espacememoire afin de stocker temporairement un nombre important de valeurs, cettememoire pourrait etre utilisee.

Registres

Outre la memoire locale, les taches disposent de registres. Ces derniers sontdonc l’element en bas de la chaıne de memoire. Ils sont tres rapides d’acceset sont bien entendu utilises lors des calculs. Similairement a la memoire par-tagee, chaque block dispose d’un nombre fini de registres. Les taches du blockdoivent donc se partager ces registres. Dans le cas ou les taches necessiteraientun nombre important de registres, la totalite des warps du block ne pourrait pasetre maintenue dans le pipeline. Ceci pour garantir que chaque tache dispose dunombre de registres necessaire a son execution. Leur rapidite d’acces ainsi queleur nombre limite fait des registres une des ressources les plus importantes.

3.3 Modele de programmation

3.3.1 Generalites

Dans cette section nous allons nous pencher sur certains points importants dela programmation sur GPU. Comme nous l’avons vu, l’architecture est complexe.Il est alors necessaire de faire attention a certains points afin d’en optimiserl’utilisation.

Nous nous pencherons dans un premier temps sur le probleme que peuventposer les instructions conditionnelles sur les architectures de type SIMT etSIMD.

Ensuite, nous allons nous pencher sur la cooperation entre les taches. Cettecooperation est principalement necessaire afin d’optimiser les acces a la me-moire. Cependant, elle est aussi necessaire afin d’effectuer certaines operations,typiquement des reductions.

Finalement, nous nous pencherons sur l’occupation des GPUs ainsi que lalatence des operations d’acces a la memoire.

27

Page 34: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

3.3.2 Branchements

Les processeurs d’un multiprocesseur doivent effectuer les memes instruc-tions afin qu’elles puissent s’executer en parallele. Si a la suite d’une instructionconditionnelle une ou plusieurs taches d’un warp avaient des instructions diffe-rentes a executer, les instructions de chaque taches de ce warp s’executeraientde facon sequentielle.

L’idee est alors d’eviter a tout prix les branchements amenant a des ins-tructions differentes. Au cas ou cela ne serait pas possible, il est important deminimiser la taille des codes divergents ainsi que de synchroniser l’ensemble destaches a la fin de la portion de code divergent.

La technique de programmation generalement utilisee est donc de releguerles decisions au CPU et d’utiliser le GPU pour effectuer les calculs parallelisablescomme decrit dans la figure 3.4.

Figure 3.4 – Execution typique de programme GPGPU

3.3.3 Cooperation entre les taches

La cooperation entre les taches est tres importante dans CUDA : les accesa la memoire doivent se faire de facon cooperative afin d’eviter les conflits etd’optimiser les lectures. La cooperation est aussi importante afin d’echanger desdonnees via la memoire partagee. Ceci afin d’eviter des calculs redondants etd’obtenir de bonnes performances pour des methodes de reductions par exemple.

Etudions les acces aux memoires globale et partagee. Il est important dansun premier temps de savoir que les acces a ces memoires se font par moitiede warp, soit 16 taches. Il existe deux types d’acces differents : le premier estun acces consecutif (coalescent 1, soit un acces a une suite d’adresses dans lamemoire et le second un acces aleatoire, soit a des adresses reparties a differents

1. Concept propre a CUDA.

28

Page 35: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

endroits de la memoire. Ces deux types d’acces sont representes dans la figure3.5.

Figure 3.5 – Acces consecutif et aleatoire a la memoire

Il est important d’utiliser le plus souvent possible des acces consecutifs carils sont bien plus rapides que les acces aleatoires. Dans le meilleur des cas, ilest possible de lire en une instruction la totalite des donnees necessaires pourun warp si les adresses sont adjacentes. Un multiprocesseur peut acceder a lamemoire par mot de 128 octets au maximum. La lecture d’un mot de 128 octetspermettrait d’obtenir 16 nombres de double precision en une lecture ou encore32 nombres de simple precision.

Les acces aleatoires sont nettement plus couteux. Si les adresses ne sont pasadjacentes, chaque tache doit executer sa propre instruction de lecture. Ce quiveut dire que 16 instructions sont necessaires afin d’acceder aux donnees pourun demi warp. De plus la taille minimale d’acces aux donnees est de 32 octets.Nous avons donc dans ce cas 16 instructions differentes d’acces a la memoire.Qui plus est, seul un faible pourcentage de ces donnees seront utilisees, ce quin’est pas du tout efficient.

Les performances liees a la memoire partagee sont particulierement depen-dantes des acces consecutifs et sans collisions. Les collisions sur les acces ala memoire font chuter les performances de facon critique car les instructionsconcurrentes sur une adresse memoire s’effectuent sequentiellement. Il est doncnecessaire de preter une attention particuliere a la strategie d’echanges d’infor-mations via la memoire partagee.

29

Page 36: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

3.3.4 Cycle pour une instruction et latence

Chaque instruction dans CUDA necessite un nombre different de cyclesavant d’etre executee. Les instructions arithmetiques sur les nombres flottantsprennent 4 cycles pour les multiplications et additions et 36 pour les divisions,par exemple. Le debit d’instructions pour les nombres flottants en double pre-cision est 8 fois plus lent que pour les nombres en simple precision.

Les instructions d’acces a la memoire globale fonctionnent differemment.Elles coutent dans un premier temps un nombre fixe de cycles afin d’emettrel’instruction de lecture (reciproquement d’ecriture). Cependant a ce cout initialvient s’ajouter une latence de 400 a 600 cycles avant que les donnees soientdisponibles. Lorsqu’une tache d’un block est en attente sur une donnee en coursd’acces, le warp de cette derniere est remis en attente dans une queue. Le sche-duler choisit un autre warp qui peut etre execute afin de masquer au mieux lalatence.

C’est pour cela qu’il est interessant de choisir un nombre important de tachespar block. Plus le nombre de warps est important, plus il est facile de cacherles latences liees aux instructions d’acces a la memoire. Plus un probleme estgrand, plus il est facile de bien repartir les taches sur les differentes unites decalculs afin de cacher les effets de la latence.

3.3.5 Occupation

Ceci nous amene a la notion d’occupation. L’occupation est le nombre dewarps qu’un multiprocesseur peut executer en meme temps. Il est important demaximiser l’occupation afin de garantir que la latence est bien cachee.

L’occupation est definie dans un premier temps par le nombre de taches setrouvant dans un block et donc de warps. Cependant, il est necessaire de rappelerque le nombre de registres disponibles (ou de memoire partagee) par block estpartage par les differentes taches de celui-ci. De ce fait, il est necessaire de faireun compromis entre l’occupation et le nombre de registres par tache.

Dans le guide de programmation de CUDA [1], il est specifie que pour obtenirles meilleurs performances possibles, il est necessaire de maximiser l’occupation.Cependant, nous verrons dans la section 4.5.3 qu’il est parfois preferable dereduire l’occupation pour augmenter le nombre de registres disponibles.

30

Page 37: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Chapitre 4

Implementations

4.1 Introduction

Maintenant que les bases theoriques ont ete etablies, nous allons nous inte-resser a la maniere dont l’algorithme a ete implemente 1.

Nous allons tout d’abord choisir la variante du simplexe qui sera implemen-tee. Le simplexe standard et le simplexe revise vont etre passes en revue de facona definir leurs avantages et inconvenients dans le cadre d’une parallelisation surGPUs.

Une fois la methode du simplexe choisie, nous etudierons les gains de per-formance possibles sur les operations principales necessaires a une iteration dusimplexe. Une version sequentielle des operations sur CPU sera comparee a sonequivalent sur GPU

Nous verrons ensuite comment le simplexe a ete implemente sur un GPU. Lastructure du probleme en memoire sera decrite. L’algorithme utilise ainsi que lesdifferents echanges de messages entre le CPU et le GPU seront alors detailles.

Les problemes principaux rencontres durant cette etape seront enonces. Lesdifferentes ameliorations apportees a la version initiale de l’algorithme serontalors decrites. Nous nous interesserons aussi plus en detail au fonctionnement deskernels. Une technique permettant d’ameliorer les performances de ces dernierssera abordee.

Finalement, l’implementation sur plusieurs GPUs cloturera ce chapitre. Lesdifferentes possibilites de decoupe du probleme seront etudiees. Nous verronsaussi comment les GPUs communiquent entre eux et quelles sont les modifica-tions a apporter a l’algorithme.

4.2 Choix de la methode du simplexe

4.2.1 Generalites

Dans cette partie nous allons etudier les deux methodes du simplexe que nousavons vues dans le chapitre 2. Ces dernieres vont etre analysees dans le cadred’une implementation sur GPU. Cette analyse va porter sur plusieurs points.

1. Les implementations decrites durant ce chapitre sont disponibles sur le site du groupeSPC du departement d’informatique de l’Universite de Geneve [11].

31

Page 38: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Nous allons nous interroger sur la disponibilite de fonctions optimisees neces-saires a notre algorithme. En effet, les implementations sequentielles existantesutilisent des librairies optimisees telles que CBLAS (Basic Linear Algebra Sub-programs for C ). Il est donc necessaire de disposer d’outils competitifs avec cetype de librairies. D’autant plus qu’obtenir des kernels optimises pour CUDArepresente un defi en soi. Les librairies CUDA etant en pleine evolution, il estprobable que de nouvelles fonctionnalites deviennent disponibles par la suite. Dece fait certains arguments cites dans ce memoire pourraient etre desuets dansle futur.

Nous etudierons aussi l’espace pris en memoire par une instance de l’algo-rithme. Les types de memorisations rendues possibles par CUDA seront aussirevus selon l’utilisation faite des donnees.

Un autre point important sera la decoupe du probleme dans le cadre d’uneimplementation sur plusieurs GPUs. En effet, la methode choisie devra per-mettre une separation avantageuse du probleme en plusieurs sous-problemes.Ces sous-problemes devront etre le plus independant possible afin d’eviter descommunications trop nombreuses entre les GPUs.

4.2.2 Simplexe standard

La methode du simplexe standard est basee sur la memorisation du diction-naire complet. Les fonctions principales afin de resoudre ce probleme sont lesrecherches de variables et l’operation de pivotage.

Les operations de recherches peuvent etre parallelisees de maniere efficientesous forme de reduction. Cependant, ces operations seront aussi necessaires dansle cadre du simplexe revise. Ces dernieres ne permettront donc pas de distinguerles deux methodes quant a leur implementation sur GPU.

Le pivotage consiste en une operation d’algebre linaire basique. NVIDIAfournit aux utilisateurs de CUDA une librairie optimisee pour l’algebre lineaireappelee CUBLAS (Basic Linear Algebra Subprograms for CUDA). Les opera-tions fournies par cette librairie sont decomposees en 3 categories : les opera-tions sur les vecteurs, les operations matrice-vecteur et finalement les operationsmatrice-matrice. Les gains lies a cette librairie croissent avec la complexite del’operation. Celle dont nous avons besoin pour le pivotage fait partie de la se-conde categorie (matrice-vecteur). Nous pouvons donc nous attendre a de bonsgains.

La memorisation du probleme est simple : il faut memoriser l’ensemble duprobleme sous la forme d’une matrice. Cette derniere evolue a chaque iteration.Il n’est donc pas possible d’utiliser les textures car elles sont uniquement enlecture depuis les kernels (seul le CPU peut ecrire dedans).

La decoupe du probleme semble aisee au premier abord. Il suffirait de divi-ser la matrice contenant le probleme en plusieurs sous-matrices. Chaque unitedevrait alors effectuer sont choix de variable localement avant d’effectuer unereduction globale entre les GPUs. Ensuite, les donnees requises au pivotage se-raient communiquees a l’ensemble des GPUs. Ces donnees devraient etre dansle pire des cas une ligne et une colonne : la ligne de la variable sortante etla colonne de la variable entrante, parfois appelees ligne pivot, respectivementcolonne pivot.

32

Page 39: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

4.2.3 Simplexe revise

La methode du simplexe revise a pour particularite d’offrir des gains sub-stantiels sur les problemes creux. Les systemes d’equations formes de matricescreuses sont plus faciles a resoudre generalement. De plus, les matrices creusespeuvent etre compressees afin de reduire leur taille. Cette compression consistea memoriser uniquement les coefficients non-nuls.

Les operations necessaires a cette variante du simplexe sont plus complexes.Les operations de recherches des variables sont les memes que dans le cas dusimplexe standard. Par contre, il faut effectuer une decomposition triangulairede la matrice contenant la base. Cette operation n’est pas disponible dans leslibrairies mise a disposition par NVIDIA. Certaines versions de cette operationsont distribuees par la communaute GPGPU. Elles promettent des gains interes-sants, malheureusement dans la majorite des cas, que pour les nombres flottanten simple precision. Le probleme est similaire en ce qui concerne la resolutionde systemes d’equations lineaires, ces deux methodes etant liees.

En ce qui concerne les besoins en memoire de cette methode, le problemeinitial ainsi que la structure de matrices composee de E,P,L,U doivent etrestockes. Les techniques speciales de memorisation de ces matrices, citees dansle chapitre 2, pourraient etre appliquees. Neanmoins, ce type de memorisationpourrait entraıner des chutes de performance. Les operations algebriques sur cetype de structures necessitent des schemas de lectures ne convenant pas force-ment a une architecture SIMT. Utiliser ces structures baisserait les performancesde l’algorithme, ne pas le faire limiterait la taille maximale des problemes.

Certaines parties du probleme pourraient etre memorisees dans les texturesetant donne qu’elles ne sont pas mises a jour depuis les GPUs a chaque iteration.Ceci offrirait un acces rapide en lecture, mais une fois de plus limiterait la taillemaximale du probleme car les textures sont de tailles limitees.

La decoupe du probleme semble fort complexe au premier abord. La structuredes matrices eta devrait etre partagee sur plusieurs GPUs afin de distribuer lecalcul necessaire aux phases BTRAN et FTRAN (voir section 2.5.6). Ces deuxphases necessitent de resoudre des systemes d’equations. Pour ce faire, il fautpouvoir acceder et modifier le systeme d’equations dans son entierete. Ce quisous-entend un nombre important de communications entre les GPUs. Cetteoperation etant necessaire plusieurs fois par iteration, l’ajout de GPUs ne seraitpas forcement efficace.

4.2.4 Choix de la methode

Nous allons ici comparer les deux methodes sur les differents aspects discutesdans les sections precedentes.

Les operations necessaires a une iteration du simplexe standard sont relati-vement simples. L’operation la plus complexe, celle d’algebre lineaire, est dispo-nible et optimisee pour toutes les architectures CUDA. En contre-partie, pour lamethode du simplexe revise, certaines des operations ne sont pas officiellementdisponibles et optimisees. La decomposition de matrices ainsi que la resolutionde systemes d’equations lineaires font parties de ces operations. La methode dusimplexe standard l’emporte ici, car les operations complexes liees a celle-ci sontoptimisees et fonctionnelles.

Du point de vue de la memoire, la methode du simplexe standard necessite

33

Page 40: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

de memoriser la matrice entiere. Il en est de meme pour la methode du simplexerevise initialement. Neanmoins, les matrices eta doivent aussi etre stockees par lasuite. Ces matrices comme nous l’avons vu peuvent etre memorisees de manierea minimiser leur taille au prix sans doute d’une perte de performance. Sur cepoint, l’algorithme du simplexe standard aurait un avantage pour les problemesde grande taille, cependant l’algorithme revise pourrait etre plus performant surles problemes de petite a moyenne taille, grace a l’utilisation de textures.

Le decoupage du probleme en vue d’une implementation sur plusieurs GPUsserait nettement plus aise dans le cadre du simplexe standard. En effet, le pro-bleme est facilement decoupable et les etapes principales d’une iteration peuventetre calculees de maniere independante une fois que la colonne et la ligne pi-vot ont ete communiquees a tous les GPUs. Dans le cadre du simplexe revise,un nombre plus eleve de communications serait necessaire a chaque iterationprincipalement a cause de la resolution des systemes d’equations lineaires.

Le simplexe revise semble avoir certains avantages dans le cadre d’une im-plementation sur un GPU et pour des problemes de taille moderee. Cependant,pour une implementation sur plusieurs GPUs et pour des problemes de grandetaille, le simplexe standard semble plus adapte.

Le but de ce travail portant sur la parallelisation du simplexe afin de re-soudre des problemes de grande taille, la methode du simplexe standard va etrechoisie pour l’implementation. De plus, il existe deja de nombreuses implemen-tations sequentielles du simplexe revise offrant de bonnes performances sur desproblemes de petite taille.

4.3 Etude de performance de CUDA

4.3.1 Operations principales

Nous avons desormais choisi la methode du simplexe a implementer : lesimplexe standard. Avant d’implementer cette methode, nous allons etudier lesgains potentiels apportes par CUDA sur les operations principales presentesdans une iteration de l’algorithme. Ces operations sont la recherche de variablesainsi que le pivotage.

La premiere operation consiste a trouver la variable possedant le plus grandcoefficient dans le cas de la variable entrante. Pour la variable sortante, celaconsiste a determiner celle qui est la plus contraignante, c’est-a-dire celle dontle resultat d’un ratio entre deux coefficients est le plus petit. Ces operationsreviennent donc a trouver le plus petit ou le plus grand element d’un vecteur.Ce type de recherche peut etre parallelise sous forme de reduction. La reductionconsiste a distribuer le travail sur les differentes unites de calcul travaillant enparallele. Chacune devra definir un premier resultat local sur un sous-ensembledes donnees. Ensuite elles devront cooperer afin de reduire les resultats locauxen un resultat global.

La seconde operation est le pivotage. Comme nous l’avons vu dans la sec-tion 2.4.2, cette operation consiste a substituer une variable dans l’ensemble desequations. Autrement dit, il s’agit de supprimer la variable de toutes les equa-tions sauf celle ou elle est basique. Pour cela, il suffit de soustraire l’equationou la variable en question est basique aux autres equations. Afin de supprimerla variable, il est neanmoins necessaire de ponderer cette equation par le coef-

34

Page 41: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

ficient de la variable entrante avant la soustraction. Cette operation equivaut al’operation DGER de la libriairie BLAS, soit :

A = α · x · y′ +A

ou x est la colonne pivot, y l’equation (ligne) pivot et A la matrice contenantles equations.

Les mesures sont effectuees sur le systeme decrit a la section 6.4.2.

4.3.2 Recherche du maximum

La recherche de la variable entrante ainsi que celle de la variable sortanteconsistent a rechercher la valeur la plus grande ou la plus petite dans un vecteur.

Il est necessaire de rappeler une partie de l’architecture de CUDA afin decomprendre son fonctionnement. Les taches peuvent communiquer entre ellesuniquement au sein d’un meme block. De plus, il est necessaire d’utiliser plu-sieurs blocks afin d’obtenir de bonnes performances. Il n’est donc pas possibled’effectuer la reduction en un seul kernel.

Il existe deux possibilites pour resoudre ce probleme. La premiere est d’effec-tuer deux passes du kernel, la premiere passe sur le vecteur initiale et la secondesur les n resultats issus des n blocks. La seconde possibilite est d’utiliser le CPUpour la seconde passe.

Il n’est pas forcement necessaire d’utiliser un nombre de blocks tres eleve pourreussir a remplir suffisamment les pipelines d’un device. De ce fait, la secondepasse se fait generalement sur un nombre faible de valeurs. Utiliser un kernelpour si peu de valeurs ne serait pas efficient. Il est alors plus interessant de fairela seconde passe sur le CPU d’autant plus si le resultat est necessaire sur cedernier pour une decision.

Figure 4.1 – Performance d’une reduction : CPU vs GPU

35

Page 42: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Les mesures de temps necessaires a une recherche de maximum sont repre-sentees dans la figure 4.1. Cette figure demontre que les gains peuvent etreimportants lorsque le vecteur depasse une certaine taille (environ 20’000 va-riables). Les problemes a traiter n’atteindront pas toujours des tailles de cetordre de grandeur.

Les methodes efficaces de recherche de variables seront neanmoins plus com-plexes qu’une simple recherche de la valeur maximum ou minimum. Plusieursoperations seront necessaires avant cela. Cette mesure decrit donc le pire caspossible.

4.3.3 Pivotage

L’operation de pivotage sur GPU est une operation de la librairie CUBLAS,plus precisement l’operation cublasDger. Cette operation est comparee a l’ope-ration equivalente sur CPU en langage C, disponible dans la librairie CBLAS.

Figure 4.2 – Performance d’un pivotage : CPU vs GPU

La figure 4.2 represente le temps necessaire a cette operation pour des taillesde matrices variables. La mise a jour de la matrice sur GPU offre de bons gainspar rapport a son equivalent CPU. Les gains sont deja interessants pour desmatrices de taille modeste. La plus petite taille de matrices testees (1000) estdeja legerement plus rapide sur GPU.

4.4 Implementation sur un GPU

4.4.1 Generalites

Nous allons voir dans cette section comment le simplexe a ete implementesur un GPU.

36

Page 43: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

La methode implementee est celle du simplexe standard (decrite a la section2.4). La methode du simplexe en deux phases (2.4.4) est utilisee. Ceci afin dedeterminer une solution initiale lors de la premiere phase afin de pouvoir recher-cher la solution optimale lors de la seconde phase. Le langage de programmationC++/CUDA a ete utilise pour cela.

L’implementation obtenue est la suite d’une multitude d’ameliorations suc-cessives. En effet, la premiere implementation etait basee sur la methode decritedans le livre ecrit par V. Chvatal [6]. La structure de l’algorithme est demeureela meme que celle decrite dans ce livre. Cependant les methodes de choix desvariables ne sont pas celles qui y sont decrites, car ces dernieres ne sont pascelles qui amenent les meilleures performances.

Suite a cette premiere version, une etude plus approfondie sur les differentesheuristiques existantes pour le simplexe a ete menee. Un ensemble de ces me-thodes a ete selectionne et implemente de telle sorte a ameliorer la stabilite et lesperformances de cette algorithme. En parallele, la structure de donnees utiliseepour memoriser le probleme a subi des modifications visant a reduire sa tailleet les differents kernels ont ete optimises pour approcher des performances depointe de CUDA.

Il serait difficile d’expliquer a la fois l’algorithme ainsi que ses differentesevolutions. Nous allons donc presenter dans cette section la structure de l’algo-rithme final et par la suite, dans la section 4.5, nous nous pencherons plus endetail sur les differentes methodes utilisees ainsi que les raisons ayant motiveesleur utilisation.

Avant de debuter, il est neanmoins interessant de soulever deux points quiont joue un role important dans l’approche qui va etre decrite par la suite.

Le premier point consiste a minimiser les echanges d’informations entre leCPU et le GPU. Ces echanges de donnees sont en effet lents compares a ceuxqui se font sur le GPU. La strategie a donc ete de memoriser la totalite duprobleme dans la memoire du device et de l’y laisser jusqu’a la fin de l’algorithme.Les transferts d’informations sont aussi limites aux variables necessaires auxinstructions de decisions qui sont executees par le CPU.

Le second point necessite une petite analyse de l’algorithme et de sa paralle-lisation. Il existe deux facteurs predominants concernant le temps de calcul d’unprobleme : le nombre d’iterations necessaires pour resoudre un probleme ainsique le temps d’une de ces iterations. Chaque iteration est dependante du resul-tat obtenu dans l’iteration precedente. Il n’est donc pas possible de paralleliserles iterations entre elles. Notre effort va donc etre concentre sur la parallelisationdes differentes operations formant une iteration.

4.4.2 Algorithme principal

L’algorithme principal, decrit dans l’algorithme 2, peut etre decompose enplusieurs parties bien distinctes.

La premiere est la lecture du probleme depuis un fichier et sa mise sousforme normale. Cette etape est etroitement liee a la structure du probleme enmemoire.

Ensuite vient l’algorithme du simplexe en deux phases : la recherche d’unesolution faisable puis la recherche de la solution optimale. Il est important dedifferencier ces deux phases, car la methode choisie pour resoudre la premierephase necessite un peu plus de calculs que la seconde phase.

37

Page 44: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Algorithm 2 Algorithme global

Input: file {MPS file containing the problem}Output: prob {Data structure containing the resulting solution}1: prob← read problem(file)2: probdev ← init device(prob)3: for i = 0 to 2 do4: if not feasible(probdev) then5: solve auxiliary(probdev)6: end if7: solve problem(probdev)8: clean problem(probdev)9: end for

10: prob← get solution(probdev)

Finalement, avant de recuperer les donnees liees a la solution trouvee, uneetape de nettoyage du probleme est necessaire. En effet, au fil des iterationscertaines variables peuvent se trouver tres legerement en dehors de leurs bornes,principalement a cause des erreurs de calcul sur les nombres flottants (voir sec-tion 4.5.1 et 4.5.2). Il est alors necessaire de corriger ces erreurs et de verifier lafaisabilite et l’optimalite de la solution finale.

Lecture et modelisation du probleme

Cette partie est la seule partie completement sequentielle de l’algorithme. Lestandard de fichier MPS [3] decrivant les problemes de programmation lineairea ete utilise afin de garantir une compatibilite avec d’autres algorithmes ainsique les ensembles de donnees existants.

La lecture du fichier s’effectue en deux etapes de telle sorte a offrir de bonnesperformances. La premiere lecture sert a determiner le nombre de variables etle nombre d’equations formant le probleme. Durant cette etape la syntaxe dufichier est verifiee. Une fois cette lecture finie, la structure de donnees contenantle probleme est creee.

Il faut ensuite effectuer la seconde passe qui consiste a remplir cette structurede donnees. Les equations sont alors modifiees afin d’obtenir un dictionnaire.Pour cela le probleme est tout d’abord mis dans sa forme normale. Les variablesde jeu sont ajoutees et les valeurs des variables sont fixees de facon arbitraireafin d’obtenir une premiere solution.

Structure de donnees

La structure de donnees a ete pensee selon plusieurs criteres. Le premierest la taille, pour des questions d’espace memoire bien entendu mais aussi pourminimiser les calculs sur la matrice. En effet, plus cette derniere est petite plusles operations matricielles seront rapides.

L’autre critere est l’ordre dans lequel la matrice est stockee (par colonne oupar ligne). Ceci est lie a l’utilisation de CUDA. En effet, il est important derappeler que pour obtenir de bonnes performances avec CUDA, il est necessaired’effectuer des acces en memoire de type consecutif.

38

Page 45: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Afin de garantir ce type d’acces lors de la recherche de la variable sortante,la matrice est memorisee par colonnes. Neanmoins, cette structure ne favorisepas le choix de la variable entrante. C’est pour cela que la fonction objectif aete separee des autres equations et placee dans un vecteur. Ainsi, tous les accessur les coefficients se font de maniere consecutive dans les deux methodes.

Figure 4.3 – Structure de donnees

La structure de donnees decrite dans la figure 4.3 est composee de la matrice,de taille m × n, contenant les equations (zone bleue, fig. 4.3). La base n’estcependant pas memorisee dans cette matrice. En effet, les colonnes de la baseforment la matrice identite, il est donc inutile de la stocker entierement. Il suffitde memoriser les variables basiques.

C’est pour cela que les variables ont ete scindees en deux sous-ensembles :les n variables basiques (zone verte, fig. 4.3) et les m variables non-basiques(zone violette, fig. 4.3). Chacune des variables xk de ces ensembles dispose deplusieurs informations :

– sa valeur et son indice k (vecteurs valeurs, indices, fig. 4.3)– ses bornes uk et lk (vecteurs bornes lo, up, fig. 4.3)Il est necessaire de memoriser les indices des variables, car elles vont echanger

leur place au fil des iterations (variable entrante ⇐⇒ variable sortante).Finalement, la structure de donnees contient la fonction objectif du probleme

(zone rouge, fig. 4.3). Selon la phase du simplexe, ce sera soit la fonction objectifauxiliaire, soit la fonction du probleme original.

39

Page 46: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

4.4.3 Recherche d’une solution initiale faisable

Cette premiere phase de l’algorithme est utilisee lorsque la solution initialen’est pas faisable. Elle peut aussi etre utilisee apres l’etape de nettoyage de lasolution, survenant a la fin d’un cycle de resolution du probleme (premiere etseconde phase), si jamais la solution finale venait a etre infaisable. La methodeimplementee correspond a la seconde methode decrite a la section 2.4.4. Aucunevariable artificielle n’est ajoutee. Le probleme auxiliaire doit alors posseder cespropres bornes pour chaque variable afin de rendre la solution faisable. La fonc-tion objectif auxiliaire a pour but de ramener les variables dans leurs bornesinitiales.

Algorithm 3 Auxiliary problem (1st phase)

Input: probdev {Data structure containing the problem on the GPU}Output: feasible, infeasible {Feasibility of the problem}1: create auxiliaryProblem(probdev) {GPU}2: while exists(xin) do3: xin ← find entering(probdev) {GPU}4: xout ← find leavingVar(xin, probdev) {GPU}5: if not exists(xout) then6: return infeasible

7: end if8: pivoting(xin, xout, probdev) {GPU}9: update feasability(probdev) {GPU}

10: if feasible(probdev) then11: return feasible

12: end if13: end while14: return infeasible

L’algorithme 3 debute par la creation du probleme auxiliaire sur le device. Lesbornes propres a cette premiere phase doivent etre copiees des bornes initialespour les variables faisables et ajustees pour celles qui sont infaisables. Cetteetape permet de rendre temporairement la solution faisable. La fonction objectifest creee en fonction des variables dont les bornes ont ete modifiees lors de l’etapeprecedente.

Il est alors possible d’executer la methode du simplexe standard sur ce pro-bleme auxiliaire. Le choix des variables entrante et sortante, ainsi que l’operationde pivotage, se font sur le GPU sous forme de kernel. Le travail du CPU consistea appeler ces kernels et a recuperer les resultats des methodes de choix de va-riables. Ces resultats permettent alors au CPU d’effectuer les decisions liees al’algorithme.

Ensuite, il est necessaire de verifier qu’une ou plusieurs des variables ontete ramenees dans leurs bornes initiales a la fin d’une iteration. Cette etapes’effectue aussi sur le GPU. Dans un premier temps, un kernel verifie l’ensembledes variables. Si des variables sont devenues faisables, il est alors necessaire de lesretirer de la fonction objectif afin de ne pas fausser la recherche d’une solutionfaisable.

Dans le cas ou la totalite des variables seraient devenues faisables, la premierephase se termine. Il est cependant possible que la premiere phase trouve une

40

Page 47: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Algorithm 4 Optimum search (2nd phase)

Input: probdev {Data structure containing the problem on the GPU}Output: feasible, infeasible {Feasibility of the problem}1: while exists(xin) do2: xin ← find entering(pdev) {GPU}3: xout ← find leavingVar(xin, pdev) {GPU}4: if not exists(xout) then5: return infeasible

6: end if7: pivoting(xin, xout, pdev) {GPU}8: end while9: return feasible

solution optimale alors que toutes les variables ne sont pas encore faisables.Dans ce cas, il n’existe pas de solution initiale faisable.

4.4.4 Recherche de la solution optimale

La seconde phase du simplexe decrite dans l’algorithme 4 est similaire ala premiere phase. A l’exception qu’il n’y a pas besoin de creer le problemeauxiliaire ainsi que de corriger la fonction objectif. En guise d’illustration, lelisting 4.1 comprend le code simplife correspondant a cet algorithme.

4.4.5 Communications CPU - GPU

Maintenant que nous connaissons le fonctionnement global de l’algorithme,nous allons nous pencher sur les communications entre le CPU et le GPU. Ellesse passent sous la forme de lancement de kernels depuis le CPU ou d’echangesde donnees entre le CPU et le GPU.

Le lancement d’un kernel doit se faire depuis le CPU. Les parametres dukernel sont passes du CPU au GPU durant son appel. Ces parametres sontgeneralement des pointeurs sur des structures de donnees presentes dans la me-moire globale. Cependant, il est possible que ce soit des constantes presentes surle CPU qui sont alors envoyees sur le GPU durant la mise en place du contextedu kernel.

Les echanges de donnees entre le CPU et le GPU sont necessaires afin d’ac-ceder au probleme, ce qui se produit lors de son initialisation ainsi que lors de larecuperation de la solution finale. Ces echanges surviennent aussi a la fin d’unkernel pour recuperer ses resultats en memoire globale

La figure 4.4 represente les echanges de donnees ayant lieu durant une itera-tion de la seconde phase du simplexe.

Pour le choix des variables le programme sur le CPU lance l’execution deskernels sur le GPU. Il leur fournit les parametres contenant les pointeurs sur lastructure du probleme stockes en memoire globale du GPU. Une fois le calcultermine, le CPU recupere les donnees resultant de la reduction effectuee parchaque block du kernel. Le CPU doit donc lire NBlocks variables depuis la me-moire globale du GPU. Ensuite, il doit effectuer la reduction de ces variables.Un exemple simplifie d’appel de kernel se trouve dans le listing 4.2.

41

Page 48: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Listing 4.1 – Optimum search

1 .So lve r : : r e s u l t t So lve r : : SolveSimplex ( ) {r e d r e s u l t t pColResult ;

3 . r ow r e s u l t t expandRowRes ;

5 . // While max i ter not reachedwhile ( counter < MAX ITER) {

7 .

pColResult = kw−>seFindCol (p) ;9 .

// I f t h e r e i s a p o t e n t i a l column11 . i f ( pColResult . index >= 0) {

13 . // Get the p i v o t rowexpandRowRes = kw−>expandFindRow( pColResult . index ,

pColResult . value , deltaK , EXPAND TAU, p) ;15 . deltaK += EXPANDTAU;

17 . i f ( expandRowRes . index == −1){return INFEASIBLE ;

19 . } else i f ( expandRowRes .mode == MUNBOUNDED) {return UNBOUNDED;

21 . } else i f ( expandRowRes .mode == M BASIC TO BOUND) {kw−>nonBasicToBound ( pColResult . index , expandRowRes . alpha

, expandRowRes . absP , p) ;23 . nTobound++;

} else i f ( expandRowRes .mode == M PIVOT) {25 . kw−>updatingBasisWS ( expandRowRes . index , pColResult . index

, expandRowRes . alpha , p) ;kw−>pivotingWS ( expandRowRes . index , pColResult . index , p) ;

27 . }counter++;

29 .

// expand s t a t e , does we need a r e s e t ?31 . i f ( i te rK == EXPANDK) {

i t e rK = 0 ;33 . resetExpand ( ) ;

i f (p−>nIn f > 0)35 . return GOTO PHASE1;

} else {37 . i t e rK++;

}39 . } else {

return SUCCESS;41 . }

}43 . return MAX ITER REACHED;

}

42

Page 49: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Figure 4.4 – Communications CPU - GPU

Pour ce qui est de l’etape de pivotage, le procede est quelque peu plus com-plexe. La premiere partie consiste a effectuer les differents swap de memoirecorrespondant au passage de la variable entrante (non-basique) dans la baseet de la variable sortante (basique) dans l’ensemble des variables non-basiques.La variable entrante prend la place de la variable sortante dans notre structurede donnees et vice-versa. Les bornes, les indices, les valeurs sont interverties.Finalement, le kernel cublasDger est appele afin d’effectuer la mise a jour de lamatrice.

Dans l’implementation finale, les echanges sont plus complexes que la me-thode decrite ci-dessus. Le choix de la variable sortante fait appel a deux ou troiskernels, selon la phase, avant de selectionner la variable adequate. Le pivotagenecessite une preparation de la matrice coutant quelques ecritures et lecturesen memoire globale. La mise a jour de la fonction objectif se fait separementde la matrice d’equations. Il est donc necessaire d’appeler une autre fonction deCUBLAS pour effectuer cette operation.

Cependant ces differences n’ont qu’une faible importance. Si nous analysonsla quantite de donnees echangees, nous pouvons constater que cette derniereest independante de la taille du probleme. Les methodes de choix des variablesnecessitent au maximum l’echange NKernels ×NBlocks variables. NBlocks etantplus petit ou egal a 64 et NKernels est au maximum egal a 4 dans notre im-plementation. Le pivotage requiert un nombre constant d’acces a la memoireglobale portant sur la lecture ou la modification d’une seule variable (variablepivot).

Pour des problemes de grande taille, qui est le cas qui nous interesse parti-culierement, nous devrions avoir des temps de communication CPU-GPU negli-geables compares aux temps d’execution des differents kernels.

43

Page 50: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Listing 4.2 – Kernel call : entering variable research

r e d r e s u l t t KernelWrapper : : pSEValExpandW( int m, int n ,VAR TYPE ∗obj , f l o a t 2 ∗bounds ) {

2 . r e d r e s u l t t gpu r e su l t ;gpu r e su l t . index = −1;

4 . gpu r e su l t . va lue = 0 ;

6 . // I n i t . o f the g r i d and b l o c k s i z eint threads = (m < MAXTHREADS∗2) ? nextPow2 ( (m + 1) / 2) :

MAXTHREADS;8 . int b locks = MIN(n , MAXBLOCKS) ;

10 . // Kernel c a l lpSEValExpand<blocks><<< dimGrid , dimBlock , smemSize >>>(

b locks , m, n , obj , eqs , pitchEqs , x , bounds , r e s u l t ) ;12 .

// Resu l t r e t r i e v i n g14 . cudaMemcpy( hRes , dRes , b locks ∗ s izeof ( r e d r e s u l t t ) ,

cudaMemcpyDeviceToHost ) ;

16 . // CPU reduc t ionfor ( int i =0; i<b locks ; i++) {

18 . SET( r e su l t , MAX ABS R( r e su l t , hRes [ i ] ) ) ;}

20 .

return r e s u l t ;22 .}

44

Page 51: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

4.5 Ameliorations de l’implementation

4.5.1 Difficultes rencontrees

Dans cette section nous allons examiner les differents problemes rencontresdurant l’implementation du simplexe selon le livre de V. Chvatal [6].

Borne individuelle

Le premier probleme rencontre a ete la prise en compte de bornes indivi-duelles sur les variable de decisions. L’algorithme theorique decrit dans le cha-pitre 2 considere que les variables de decisions peuvent prendre n’importe quellevaleur entre zero (compris) et l’infini, soit des valeurs reelles positives. Si lesvariables possedent des bornes individuelles, il est alors necessaire d’adapter leprobleme ou l’algorithme afin de prendre en compte ces nouvelles contraintes.

Ce probleme a deja ete decrit en partie a la section 2.4.4. Comme nousl’avions vu dans cette section, la technique visant a modifier le probleme deprogrammation lineaire ne semble pas efficiente. En effet, cette modification peutamener le probleme a croıtre de facon exponentielle. Il convient alors d’utiliserla seconde technique qui vise a modifier les methodes de choix de variables afinde prendre en compte les contraintes individuelles de ces dernieres.

Lors du choix de la variable entrante, qui est equivalent au choix de la direc-tion dans la representation geometrique, il est necessaire de controler la totalitedes variables pouvant amener une amelioration du resultat de la fonction objec-tif. Dans le cas ou les variables ne possedaient pas de bornes individuelles, celacorrespondait a selectionner les variables dont le coefficient etait positif dans lafonction objectif. Avec les bornes individuelles, il est necessaire de considerertoutes les variables dont le coefficient est non-nul dans la fonction objectif etdont les bornes permettent un gain sur la variable.

Cette modification doit aussi etre appliquee au choix de la variable sortante.En fonction du sens de la direction choisie (signe du coefficient de la variableentrante dans la fonction objectif), il est necessaire desormais d’utiliser la borneindividuelle limitante de chacune des variables se trouvant dans la base afin dedeterminer leur contrainte sur le gain apporte par la variable entrante. Le calculde la contrainte depend desormais de la valeur de la variable basique potentiel-lement sortante xout, du sens de la direction choisie, du signe du coefficient dela variable entrante dans l’equation ou xout est basique et finalement des bornesde xout.

Les calculs supplementaires apportes par ces modifications ne sont pas tropproblematiques. Les difficultes amenees par ces dernieres sont liees a la prise encompte du sens de la direction. Il est donc necessaire de differencier certainesvariables en fonction de leur signe afin de determiner la borne a utiliser. Ce quisous-entend la possibilite d’instructions non synchronisees au sein de warps etdonc de la perte du parallelisme.

Cycles et iterations degeneratives

Un probleme recurrent dans la resolution des problemes de programmationlineaire est l’apparition de cycles comme nous l’avons deja decrit dans la section2.4.4. Les methodes decrites dans cette section fonctionnent correctement, maisne sont generalement pas tres efficiente. La methode du smallest subscript est

45

Page 52: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

simple a implementer mais peut mener a un nombre tres important d’iterationsavant de sortir d’un cycle, tandis que la methode de perturbation est efficientemais necessite une implementation robuste ce qui peut s’averer complexe.

Nous verrons dans la section 4.5.2, une heuristique implementant certainsprincipes de la methode de perturbation afin d’eviter de tomber dans des cycles.

Instabilites numeriques

Les nombres utilises dans l’algorithme du simplexe sont des nombres reels.Lors de l’implementation, il est alors necessaire d’utiliser des nombres a vir-gule flottante. Il est important de rappeler que ces nombres a virgule flottantepossedent une precision limitee en fonction du nombre de bits utilises pour lesrepresenter. Meme en choisissant des nombres en double precision (codes sur 64bits, 8 octets), des erreurs de calculs font leur apparition.

Ces erreurs etant infimes sur une operation arithmetique, sont generalementnegligeables. Cependant dans le cadre du simplexe, les erreurs se propagentd’iteration en iteration, augmentant ainsi progressivement leur magnitude.

Le premier probleme que cela pose, est une perte de precision sur le resultatobtenu a la fin du calcul. Cette perte est dependante du nombre d’iterationseffectuees. Il est donc necessaire, apres un nombre important d’iterations, dereprendre le dictionnaire obtenu du probleme initial et d’y adjoindre la dernieresolution trouvee, afin de repartir sur des bases saines. Cette operation est trescouteuse car elle necessite de recreer la derniere base obtenue. Cependant, elle estrarement necessaire etant donne que le nombre critique d’iterations est rarementatteint. En effet, ce nombre est estime a environ 100’000 iterations

Un autre probleme est lie au nombre zero. Lorsqu’il est sujet a des erreursdues a l’imprecision des nombres a virgule flottante, le nombre zero devient unnombre infiniment petit. Le premier probleme que cela pose est que les calculssur ces nombres tres petits sont generalement beaucoup plus lent que les calculssur des nombres de taille normale. Le second probleme est que le nombre zerojoue un role important dans la selection des variables. En effet, generalementnous recherchons des coefficients non-nuls. Il devient alors important de pouvoirdeterminer si une petite valeur est un zero ou un coefficient de faible valeur.

Il est alors necessaire de fixer des tolerances sur les comparaisons avec lenombre zero. Le choix de ces tolerances est critique. Si elles sont choisies tropgrandes, elles ne nous permettent pas d’atteindre a tous les coups la solutionoptimale car certaines variables de faible valeur ne sont pas selectionnees alorsqu’elles ne sont pourtant pas egales a zero. Au contraire, si elles sont choisies troppetites, alors un zero ayant degenere pourrait etre choisi comme valeur pivot. Unpivotage sur une telle valeur amenerait a un dictionnaire errone. L’algorithmedeviendrait alors instable et produirait des resultats incorrects.

Il est possible de minimiser ce probleme en utilisant l’option de compilation-ftz=true offerte par le compilateur CUDA. Cette derniere permet de flusher lesnombres extremement petits, plus communement appele nombres denormalises.Cette manipulation evite que ces nombres ralentissent nos calculs. Cependant,elle ne permet pas de garantir que l’algorithme evitera des instabilites nume-riques car certaines erreurs sont trop grandes pour etre flushees de cette maniere.

46

Page 53: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

4.5.2 Ameliorations de l’algorithme du simplexe

Nous allons desormais nous interesser aux differentes ameliorations apporteesa l’algorithme theorique vu au chapitre 2. Ces ameliorations ont ete principale-ment trouvee dans la litterature scientifique sur le simplexe. Cette documenta-tion est assez consequente, particulierement en ce qui concerne le simplexe revise.Ceci n’a pas facilite l’implementation des methodes decrites dans les articles se-lectionnes vu qu’il n’etait pas directement adaptable au simplexe standard.

Structure du probleme en memoire

Premierement, la structure du probleme en memoire a ete pensee de tellefacon a garantir des acces consecutifs a la memoire globale comme nous l’avonsvu dans la section 4.4.2.

Les algorithmes implementes pour le choix des variables parcourent la ma-trice par colonnes. La matrice des equations est donc memorisee colonne parcolonne plutot que ligne par ligne. Aussi, la fonction objectif a ete separee de lamatrice des equations afin de garantir des acces consecutifs lors du choix de lavariable entrante.

Ensuite, l’algorithme a ete adapte de telle sorte a ne necessiter la memorisa-tion d’aucunes variables supplementaires aux variables de decision. Les partiesde l’algorithme necessitant une implementation particuliere permettant d’eviterl’ajout de variables sont la premiere phase du simplexe, la gestion des bornesindividuelles et la memorisation de la base (initialement des variables de jeux).

Etant donne qu’uniquement les variables de decision sont memorisees, leprobleme en memoire est de taille :

m · n+ k · (m+ n)

ou m est le nombre d’equations, n le nombre de variables de decisions et k lataille de la structure liee a une variable (valeur, indice, bornes).

Une implementation moins attentive a ces details aurait pu mener a unestructure de forte taille. Les variables de jeu et les variables artificielles aug-mentent le nombre de variables de 2m. Tandis que la modification du problemeafin de prendre en compte les bornes individuelles des variables peut rajou-ter jusqu’a 2n equations dans le pire des cas. Nous pourrions alors avoir unestructure dont la taille serait proche de :

(m+ 2n) · (n+ 2m) + k · (3n+ 3m)

Bien qu’une telle implementation necessite un peu moins de calculs, ellene serait certainement pas plus rapide. Rappelons que le temps de calcul estdependant de la taille de la matrice. Il est donc important de maintenir cettederniere aussi petite que possible.

Normalisation du probleme initial

Afin d’augmenter la stabilite de l’algorithme, la matrice de base est nor-malisee de telle sorte a ce que la valeur des coefficients de la matrice soientcomprises entre -1 et 1. Les equations (lignes) et les variables (colonnes) sontdonc normalisees.

Dans le cas de la normalisation des variables (colonnes), il est necessaire demettre a jour leurs bornes en fonction du facteur de normalisation. A la fin de

47

Page 54: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

l’algorithme, il est alors necessaire d’effectuer l’etape inverse afin de leur rendreleur vraie valeur.

Ces normalisations de la matrice permettent d’eviter que de grands ecartssubsistes entre les variables. Ce type d’ecart augmentent les risques de ne pasatteindre la solution optimale a cause de la perte de precision due aux nombresflottants. Cette normalisation permet aussi de reduire les risques d’instabilitequi pourrait survenir suite a la selection d’un zero degenere pour coefficientpivot.

Choix de la variable entrante

Il existe de nombreuses methodes afin de choisir la variable entrante. Lenombre d’iterations necessaires a l’algorithme afin de resoudre un probleme de-pend entierement de ce choix. Il convient alors de choisir une methode offrantune reduction importante du nombre d’iterations ainsi que des possibilites deparallelisation.

Il existe deux axes de recherche pour les heuristiques visant a effectuer cetteoperation. Le premier axe vise a reduire le temps de calcul de cette derniere enutilisant des recherches partielles [14]. Ces techniques ne reduisent que sensible-ment le nombre d’iterations et sont difficilement parallelisables.

Le second axe englobe les methodes qui tentent de reduire le nombre d’ite-rations necessaires a l’algorithme. A la base, il existe deux methodes differentes.La premiere est de considerer toutes les possibilites de pivots et de selectionnercelui qui offre le meilleur gain. Cette methode, bien que la meilleure theorique-ment, n’est quasiment jamais implementee etant donne la quantite de calculsnecessaires. En effet, cela revient a appliquer la recherche de la variable sortanteen considerant toutes les variables non-basiques comme variable entrante.

La seconde methode s’appelle steepest edge (bord le plus abrupte) [15]. Cettemethode choisit la variable qui offre le plus grand gain de la fonction objectifpar unite de mouvement le long du bord de notre polytope. Les calculs qu’ellenecessite sont importants. Il est necessaire de calculer la norme euclidienne detoutes les colonnes correspondant a une variable entrante potentielle. Ensuite lapente peut etre calculee,

sel =cl

‖ηl‖= min

cj√

1 +∑m

i=1x2ij

∀j ∈ 1..n (4.1)

ou cl est le coefficient de la variable dans la fonction objectif et ηl la colonnede la variable xl. Cette methode, malgre son cout eleve, est souvent utilisee,car elle offre une reduction importante du nombre d’iterations. De plus, elle seprete bien a une parallelisation sur GPU etant donne qu’il s’agit d’effectuer uncalcul consequent sur la majorite des colonnes suivi de la recherche du meilleurresultat.

Il existe plusieurs methodes, principalement concue pour le simplexe revise,basee sur la methode steepest edge qui offrent des reductions d’iterations prochesde celle-ci en utilisant des estimations de la norme euclidienne afin de reduire letemps de calcul (approximate steepest edge, DEVEX [12]). Ces methodes offrentun bon compromis entre les deux, mais ne sont pas aisement parallelisables. Deplus la reduction du nombre d’iterations est moindre que celle resultant del’application du steepest edge.

48

Page 55: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

La methode standard, une methode partielle ainsi que le steepest edge ontete implementees et comparees. De ces trois methodes, la version paralleliseedu steepest edge a offert les meilleures performances (voir section 6.4.4). Malgrel’ajout considerable de calculs que demande cette methode, elle s’est averee plusrapide que les deux autres. Le fait que le nombre d’iterations soit reduit est nonseulement interessant du point de vue des performances mais aussi de celui dela stabilite. En effet, si le nombre d’iterations est reduit alors la propagation deserreurs d’arrondi est moindre.

Choix de la variable sortante

Le choix de la variable sortante est cruciale quant a la stabilite de l’algo-rithme. Elle ne laisse cependant pas beaucoup de choix en ce qui concerne sonimplementation. Il est en effet necessaire de choisir la variable la plus contrai-gnante afin de ne pas rendre des variables basiques infaisables. Neanmoins, lechoix du coefficient pivot, qui se trouve a l’intersection de la variable sortanteet entrante dans la matrice d’equations, est d’une grande importance. En effet,dans les cas ou le choix se porte sur plusieurs variables sortantes, il est alors im-portant de choisir le pivot le plus grand afin de minimiser le risque d’instabilitenumerique.

De plus la recherche de la variable sortante permet d’utiliser la methode deperturbation (voir section 2.4.4) qui sert a eviter de tomber dans des cycles.La procedure proposee par E. Gill et al. [13] offre une methode de choix de lavariable sortante permettant d’eviter les cycles. De plus, cette methode prend encompte la valeur du coefficient pivot dans la mesure du possible afin d’ameliorerla stabilite de l’algorithme.

Cette procedure s’appelle EXPAND pour EXPanding-tolerance ANti-Degen-eracy procedure. Le principe est de tolerer un ecart infime sur la faisabilite denotre solution. A chaque iteration, cette tolerance sur la faisabilite est legerementaugmentee. Cette modification du probleme permet de garantir qu’a chaqueiteration la valeur de la fonction objectif evolue positivement. Si cette dernierene stagne pas, alors il n’est pas possible de tomber dans un cycle, car ceux-cisurviennent lorsque les iterations sont degenerees.

Le choix de la variable sortante se fait en deux passes, voire trois pour lapremiere phase du simplexe. Lors de la premiere passe, les bornes individuellesdes variables sont elargies, a l’iteration k, d’une valeur ǫk. Cette valeur eststrictement croissante au fil des iterations, ǫk−1 < ǫk < ǫk+1. Ensuite, le gainmaximal sur la variable entrante, αmax, que permet la variable basique la pluscontraignante est determine.

La seconde passe utilise les bornes non-elargies afin de determiner la variablesortante. Cette derniere est la variable basique, possedant un gain αj plus petitou egal a αmax et qui presente le coefficient pivot le plus grand parmi ceuxpossibles.

Lors de la premiere phase du simplexe, une passe speciale vient se glisserentre les deux precedemment citees. Cette derniere va essayer de trouver unevariable basique infaisable qui pourrait rentrer dans ses bornes initiales et doncdevenir faisable. Cette variable doit garantir un gain αj sur la variable entranteplus petit que αmax comme lors de la seconde passe. Si une variable basiqueinfaisable correspond au critere precedent et est rendue faisable par ce pivotage,alors cette derniere est selectionnee comme variable sortante. Si aucune variable

49

Page 56: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

ne correspond a ce critere, la seconde passe est appliquee.Bien que la tolerance sur la faisabilite du probleme soit tres faible, il est

tout de meme necessaire d’effectuer une reinitialisation de cette derniere a deuxoccasions. La premiere est apres un nombre consequent d’iterations. Ceci estnecessaire afin de ne pas trop modifier le probleme. Le but est uniquement deperturber legerement ce dernier.

La seconde occasion survient lorsqu’on a trouve une solution infaisable ouoptimale. Il est alors necessaire de reinitialiser la tolerance, afin de garantir que lasolution est toujours infaisable ou optimale apres que les bornes aient retrouveleur valeur initiale. A l’issue de cette operation, la methode du simplexe estrelancee sur le probleme reinitialise. Il est evidement necessaire de fixer unelimite au nombre de fois que cette operation est appliquee.

La reinitialisation consiste a ramener les variables qui sont en dehors de leursbornes initiales a l’interieur de celle-ci, si cette operation est jugee triviale. Cettederniere est determinee comme telle si la variable se trouve en deca d’une cer-taine valeur, fixee au prealable, de sa borne la plus proche. Si ce n’est pas le cas,la variable est alors consideree comme etant infaisable. Quand ce cas survientlors de la seconde phase de l’algorithme du simplexe, il est alors necessaire deretourner a la premiere phase afin de rendre cette variable faisable a nouveau.

4.5.3 Optimisations des kernel

L’optimisation de kernels est dependante de trois facteurs, comme nousl’avons vu dans le chapitre 3. Le premier est de maximiser l’occupation des mul-tiprocesseurs afin de tirer un profit maximal des differentes unites de calculs.Ensuite, il est important de cacher la latence des operations lentes telles que lalecture en fournissant assez de taches afin de remplir les pipelines. Finalement,il est necessaire de garantir un acces correct aux donnees.

Nos kernels ont ete optimises afin de garantir de bonnes performances. Nousallons voir un exemple pour le cas du kernel choisissant la variable entranteselon la methode du steepest edge.

Ce kernel va effectuer un calcul consequent. Il est necessaire pour un certainpourcentage des colonnes (celles dont la variable peut etre elue) de calculer lanorme euclidienne. Tous les coefficients de la colonne doivent etre mis au carrepuis sommes. Chaque colonne est traitee dans un block : premierement chaquetache calcule une somme partielle, puis une reduction a lieu pour sommer lesresultats locaux.

Si on se base sur les observations faites precedemment et selon la documen-tation de NVIDIA [1], il est crucial d’utiliser un nombre important de tachespar block et de garantir une occupation maximale pour cacher la latence. Ce-pendant, comme le souleve V. Volkov [17], ceci n’est pas forcement optimal. Eneffet, rappelons que les registres sont partages par les taches d’un block. Plus il ya de taches dans un block, moins elles disposent de registres pour effectuer leurscalculs. De plus les taches sont forcees d’utiliser une partie de leurs registres pourmemoriser les parametres, leur identifiant et d’autres informations. Ce qui faitque le ratio de registres utilisables pour les calculs diminue proportionnellementau nombre de taches par block.

L’astuce va consister a forcer une tache a utiliser plus de registres. Ceci di-minuera legerement l’occupation, c’est-a-dire qu’un multiprocesseur disposera

50

Page 57: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

de moins de warps dans le pipeline pour cacher la latence. Neanmoins, les per-formances sont meilleures dans ce cas. Les taches disposent de plus de registresutiles et peuvent donc mieux cacher la latence en lancant plusieurs instructionsde lecture successives.

En resume, selon NVIDIA, l’objectif est de viser une occupation de 100%ainsi que de fournir un nombre important de taches pour remplir les pipelines etobtenir de bonnes performances. Cependant, ceci se fait au depend du nombre deregistres utiles par tache. Pour eviter cela, V.Volkov propose de creer un pipelineimplicite dans le code du kernel en effectuant plusieurs lectures successives. Cecirequiert d’utiliser plus de registres par tache au depend de l’occupation.

Nous allons comparer les performances de deux kernels differents : le premier,SE1, est base sur les observations de V. Volkov et va donc utiliser plus deregistres par tache que le second, SE2, qui suit les directives de NVIDIA enmaximisant l’occupation du kernel.

Commencons par le kernel SE2, dont le pseudo-code se trouve dans le lis-ting 4.3. Ce kernel lit premierement un coefficient depuis la memoire globale.Cette variable est referencee par le tableau eqs[...] et stockee dans la variablecoeff. Une fois lue, cette derniere est mise au carre puis sommee. La tache lanceune instruction de lecture, passe dans le pipeline en attente que la lecture soiteffectuee et finalement fait le calcul. Et ainsi de suite.

Listing 4.3 – Kernel 2 : latency not hidden

[ . . . ]2 . while ( i < m) {

c o e f f = eqs [ INDEX( i , j ) ] ;4 . mySum += c o e f f ∗ c o e f f ;

i++;6 . }

[ . . . ]

Dans le code simplifie du kernel SE1 decrit par le listing 4.4, on peut remar-quer que la tache utilise plusieurs registres pour lire les donnees successivement.En effet, les instructions de lecture ne sont pas bloquantes. De ce fait, ce kernelva emettre quatre instructions de lectures concurrentes ce qui permet de cacherimplicitement la latence.

Listing 4.4 – Kernel 1 : latency hidden

1 . [ . . . ]while ( i+3 < m) {

3 . c o e f f 1 = eqs [ INDEX( i , j ) ] ;c o e f f 2 = eqs [ INDEX( i +1, j ) ] ;

5 . c o e f f 3 = eqs [ INDEX( i +2, j ) ] ;c o e f f 4 = eqs [ INDEX( i +3, j ) ] ;

7 . mySum += co e f f 1 ∗ c o e f f 1 ;mySum += co e f f 2 ∗ c o e f f 2 ;

9 . mySum += co e f f 3 ∗ c o e f f 3 ;mySum += co e f f 4 ∗ c o e f f 4 ;

11 . i +=4;}

13 . [ . . . ]

51

Page 58: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

La figure 4.5 demontre la bande passante utilisee par les kernels en fonctionde la taille du probleme. Les performances du kernel SE1 en terme de bandepassante sont meilleures ce qui confirme la theorie de V. Volkov. Cette simplemodification offre un gain de bande passante de plus de 10% pour quasi toutesles tailles de matrices. Il est possible d’apporter plusieurs ameliorations de cetype a un kernel afin d’atteindre au plus vite les performances de pointes d’undevice.

Figure 4.5 – Optimisation du kernel steepest edge

52

Page 59: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

4.6 Implementation multi-GPU

4.6.1 Introduction

A partir de l’implementation sur un GPU que nous venons de decrire, nousallons etudier et realiser l’implementation du simplexe sur plusieurs GPUs. Cecinecessite dans un premier temps de separer la structure du probleme en me-moire en plusieurs sous-structures permettant de paralleliser le calcul tout enminimisant les communications entre les differents GPUs.

Nous verrons ensuite comment les GPUs font pour communiquer. Ces der-niers ne pouvant pas directement interagir entre eux, il est necessaire d’utiliserles CPUs pour faire le relais.

Finalement, nous verrons quelles sont les modifications a apporter a notreimplementation sur un GPU du point de vue algorithmique.

4.6.2 Decoupe du probleme

La methode du simplexe standard se prete volontiers a la parallelisation.Les differentes etapes, le choix des variables ainsi que le pivotage, peuvent etrefaites sur des ensembles partiels de la matrice sans probleme. Il est neanmoinsnecessaire pour certaines de ces etapes de reduire les resultats locaux avantd’obtenir le resultat final.

Afin de determiner sur quelle partie du probleme chaque GPU va travailler, ilest necessaire d’etudier les alternatives de decoupes du probleme. Ces decoupespossedent chacune leurs avantages et inconvenients. En effet, il est possible dedecouper le probleme de maniere a assurer une bonne scalabilite au depend dunombre de communications necessaires par exemple. Inversement, il est possiblede viser une decoupe evitant de nombreux echanges de messages mais dont lesperformances ne seront garanties que pour un nombre restreint de GPUs.

Le choix de la decoupe devient alors dependant de l’environnement sur lequell’algorithme va etre parallelise. Les clusters de GPUs, a l’exception de quelquesrares cas, disposent de quelques dizaines de GPUs (ordre de grandeur 20 a 50).Dans notre cas, nous disposons d’une NVIDIA tesla S1070 qui est composee dequatre GPUs. Nous allons chercher une decoupe du probleme offrant de bonnesperformances pour un nombre limite d’unites de calcul.

Il est aussi interessant de remarquer que generalement les problemes de pro-grammation lineaire disposent d’un nombre plus eleve de variables que d’equa-tions : soit n >> m. Cependant, si la tendance etait inverse, il serait possibled’utiliser la dualite des problemes de programmation lineaire afin d’obtenir unematrice correspondant a nos attentes (voir Linear Programming [6]).

Selon la decoupe envisagee, la taille et la forme de la matrice aura une grandeinfluence sur la quantite de donnees a echanger. C’est pour cela que certainesdecoupes ne favorisent pas un nombre tres eleve de GPUs. En effet, celle-cinecessite une quantite de communications qui demeure constante malgre l’ajoutde GPUs. Nous allons voir plus en detail dans les sections suivantes commentces differents criteres influent sur les differents types de decoupe.

Decoupe horizontale

La premiere decoupe du probleme est une approche horizontale. Nous allonsdonc separer le probleme en sous-ensembles d’equations comme decrit dans la

53

Page 60: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

figure 4.6. Du point de vue des variables et de leurs informations respectives : lesvariables basiques sont distribuees alors que les variables non-basiques doiventetre copiees sur chaque GPU. Il en est de meme pour la fonction objectif.

Figure 4.6 – Decoupe horizontale

Pour la recherche de la variable entrante, il est necessaire d’appliquer lamethode du steepest edge qui doit effectuer la norme des colonnes dont la variableest eligible pour etre entrante. Avec cette decoupe, chaque GPU doit calculerune somme local pour chaque variable qu’il doit par la suite communiquer auxautres GPUs. Chaque GPU doit donc communiquer n informations afin que lechoix de la variable entrante puisse etre fait.

La recherche de la variable sortante necessite que chaque GPU fasse unereduction locale pour chaque etape de la methode expand. A la suite de chacunede ces reductions locales, il faut calculer le resultat final a partir du resultatlocal de chaque GPU. Il est donc necessaire d’avoir autant de synchronisationqu’il y a d’etapes a expand, soit deux ou trois selon la phase. Chaque GPU necommunique qu’une variable a la suite de sa reduction locale.

Il est neanmoins important de souligner que le nombre de donnees utiliseeslors de la recherche de la variable sortante est relativement faible, uniquement mvariables sont verifiees. Sur un seul GPU, il faudrait deja que m soit tres grandafin d’atteindre de bonnes performances. Le fait de paralleliser cette methoden’ajoute donc pas grand chose en terme de performances.

Afin d’effectuer le pivotage, chaque GPU doit posseder la colonne ainsi quela ligne du coefficient pivot. Avec cette decoupe, il est donc necessaire que leGPU qui dispose de la variable sortante communique aux autres la ligne pivot

54

Page 61: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

ainsi que les informations concernant la variable sortante. Ces informations sontnecessaires afin d’effectuer le swap entre la variable entrante et la variable sor-tante. Il faut donc communiquer environ m donnees afin de preparer le pivotage.Une fois les donnees partagees, chaque GPU peut effectuer le pivotage de faconindependante.

Decoupe verticale

La decoupe verticale decrite dans la figure 4.7 est semblable a l’horizon-tale dans l’approche. Nous allons donc separer les coefficients de la matriced’equations en plusieurs sous-ensembles de variables. Les variables non-basiqueset leurs informations seront partagees, tandis que les variables basiques serontcopiees dans chaque GPU. Dans cette decoupe, la fonction objectif est partagee.

Figure 4.7 – Decoupe verticale

Pour la recherche de la variable entrante, chaque GPU peut effectuer lamethode du steepest edge localement et selectionner une variable. Il est alorsnecessaire par la suite d’effectuer une reduction de ces resultats locaux afind’obtenir la variable entrante finale. Il est donc necessaire pour chaque GPU decommuniquer une seule variable a la fin de son calcul local.

La recherche de la variable sortante ne va s’effectuer que sur un seul GPU. Eneffet, cette recherche ne necessite que les variables basiques ainsi que la colonnede la variable entrante. Cette derniere n’etant pas partagee, seul un GPU peuteffectuer la selection de cette variable. Neanmoins, comme nous l’avons faitremarquer dans la decoupe horizontale, chaque etape de la methode expand

55

Page 62: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

consiste a faire une reduction sur m variables. Afin de tirer profit de plusieursGPUs m devrait etre tres grand.

Finalement, la preparation du pivotage necessite que le GPU, ou la variableentrante se situe, communique les informations de cette derniere ainsi que sacolonne aux autres GPUs. Apres quoi chaque GPU peut effectuer le pivotagede facon independante. Cette etape necessite qu’un GPU communique approxi-mativement n informations aux autres.

Decoupe mixte (tuiles)

Cette decoupe est un peu plus complexe que les deux precedentes. Le butest ici de decomposer la matrice des equations en k× l tuiles comme le decrit lafigure 4.8. Chaque GPU va disposer d’une sous-matrice ainsi que des variablesqui lui sont associees, soit un sous-ensemble des variables basiques et un sous-ensemble des variables non-basiques. La fonction objectif est decoupee de lameme maniere que les equations de la matrice.

Figure 4.8 – Decoupe en tuiles

Cette decoupe est en quelque sorte un melange des deux decoupes que nousavons vu precedemment. Il est donc necessaire de copier plusieurs fois chaquesous-ensemble de variables ainsi que chaque partie de la fonction objectif. En cequi concerne les methodes du simplexe, il faudra appliquer les communicationsnecessaires aux deux autres decoupes.

Pour la recherche de la variable entrante, chaque GPU va appliquer la me-thode steepest edge localement. Suite a quoi, les GPUs, dont la sous-matrice

56

Page 63: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

appartient a une colonne de tuiles, participent a une seconde reduction neces-sitant l’envoi de n

lvariables. Cette etape est equivalente a celle de la decoupe

horizontale. Finalement, la reduction finale est effectuee sur le resultat de l’etapeprecedente. Cette etape correspond a celle de la decoupe verticale : chaque GPUdevra communiquer une variable afin d’effectuer la reduction.

La recherche de la variable sortante va s’effectuer sur les k GPUs contenantla colonne de la variable entrante. Pour chaque etape de la methode expand, lesGPUs en question vont effectuer une recherche locale avant de communiquer leurresultat afin de determiner le resultat final. Cette etape correspond entierementa celle de la decoupe horizontale.

Finalement, la preparation du pivotage necessite deux envois de coefficients.Le premier est l’envoi de la colonne de la variable entrante. Les k GPUs la posse-dant doivent communiquer les coefficients aux autres GPUs possedant le memesous-ensemble de variables basiques. En resume, la colonne pivot est diffuseehorizontalement du point de vue des tuiles. Il en va de meme concernant lescoefficients de la ligne de la variable sortante. Les l GPUs possedant ces coeffi-cients doivent les communiquer aux GPUs possedant le meme sous-ensemble devariables non-basiques. Ce qui correspond a une diffusion verticale de la lignepivot.

Analyse et choix

Nous allons maintenant analyser les avantages et les inconvenients des diffe-rentes decoupes vues precedemment.

Premierement, une analyse globale permet de distinguer les methodes de de-coupes horizontale et verticale, de la decoupe en tuiles. Les deux premieres de-coupes sont interessantes pour un nombre restreint de GPUs. En effet, la matriceetant decoupee selon un axe uniquement, les sous-matrices deviendraient forte-ment oblongue pour un nombre important de GPUs et les donnees redondantesprendraient un espace considerable par rapport a la taille de la sous-matrice atraiter. Par contre, la decoupe en tuiles offre une bonne scalabilite. Les matricesgardent une proportion semblable a la matrice initiale.

Nous allons donc dans en premier temps comparer les deux methodes dedecoupes sur un axe afin de determiner si une des deux se prete mieux a notrealgorithme. Rappelons que les problemes disposent generalement de plus devariables que d’equations (m << n).

Le choix de la variable entrante necessite moins de communications dans lecas de la decoupe verticale. Cette derniere necessite que chaque GPU commu-nique un resultat alors que la decoupe horizontale en necessite n.

Le choix de la variable sortante est uniquement parallelise dans le cas dela decoupe horizontale. Cependant, comme nous l’avons vu, la methode expandn’est effectuee que sur m variables. Ce nombre de donnees est relativement faibleet donc ne necessite pas de parallelisation, a moins d’avoir un probleme de tresgrande taille. L’ajout de synchronisation et d’echanges de donnees lies a uneparallelisation pourrait rendre cette operation plus longue que dans le cas d’uneexecution sur un seul GPU.

La preparation du pivotage necessite dans les deux cas l’echange d’une ligne,respectivement colonne de la matrice. Etant donne la structure habituelle desproblemes, la decoupe verticale est legerement gagnante etant donne que le

57

Page 64: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

nombre de variables a communiquer est cense etre moindre que pour la decoupehorizontale.

La decoupe verticale semble plus adaptee que la decoupe horizontale du pointde vue de la parallelisation des differentes methodes. De plus, la structure desproblemes se prete mieux a une decoupe de ce type.

Maintenant que nous avons determine quelle methode est plus adaptee entrela verticale et l’horizontale, revenons a la decoupe en tuile. Cette derniere disposed’une partie des inconvenients de la decoupe horizontale. En effet, le choix dela variable sortante est aussi parallelise et le nombre de communications sembleplus important que dans le cas de la decoupe verticale. Cependant, pour desproblemes de tres grande taille, necessitant un nombre consequent de GPUs,ces inconvenients tendent a s’effacer.

Il en ressort que la decoupe verticale est adaptee a un nombre restreint deGPUs tandis que la decoupe en tuile est plus scalable et pourrait tirer profitd’un nombre plus consequent de GPUs. Etant donne que nous disposons uni-quement de quatre GPUs, nous allons paralleliser notre algorithme en utilisantune decoupe verticale.

4.6.3 Architecture et communication multi-GPU

Les GPUs ne pouvant pas communiquer entre eux, il est necessaire d’utiliserles CPUs pour etablir la communication ainsi que pour synchroniser les GPUs.Chaque device doit etre dirige par une tache CPU differente. Il est donc neces-saire d’etablir un degre de parallelisme supplementaire par le biais des CPUs.

Pour ce faire, nous disposons de deux possibilites : MPI ou POSIX. MPI(message passing interface) est un standard de communication pour les appli-cations parallele alors que POSIX (portable operating system interface) est unestandardisation des API de bases fournies par un systeme d’exploitation. MPIoffre une methode de communication simple et robuste, ce qui est fort appre-cie dans le cas d’un reseau de communication complexe. Cependant, le choixde decoupe que nous avons fait a l’etape precedente est base sur un nombrereduit de GPUs. Nous allons continuer dans cette direction en choisissant d’uti-liser POSIX. Ce choix offre un controle plus fin sur la technique d’echange demessages.

Dans notre cas, les differents GPUs sont geres par un systeme CPU multi-cœur (voir section 6.4.2). Ces processeurs disposent donc de la meme memoire

CPU globale qui leur permettra de communiquer entre eux. Etant donne quePOSIX fournit les primitives necessaires a la synchronisation de taches (bar-rieres) ainsi qu’a la gestion de sections critiques (semaphores), nous disposonsdonc de la totalite des outils qu’il nous faut.

La technique de communication que nous allons mettre en place consiste acreer une zone de memoire partagee entre les taches CPUs afin qu’elles puissenty echanger les donnees necessaires aux differentes etapes de notre algorithme.Afin d’eviter les conflits sur cette memoire, les processeurs disposent chacund’une zone de memoire en ecriture. Les lectures sont alors synchronisees a l’aidede barrieres.

58

Page 65: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

4.6.4 Algorithme

Le but de cette section est de s’interesser principalement aux modificationsinduites par l’implementation multi-GPU.

Initialisation

L’algorithme 5 decrit la phase d’initialisation de l’algorithme multi-GPU. Latache CPU principale lit le probleme dans un premier temps, tout comme dansl’implementation sur un GPU. Par la suite, elle cree la structure de donneesqui sera partagee entre les differents CPUs afin de permettre la communicationpar la suite. Les differentes taches CPU sont alors creees, comme decrit dans lelisting 4.5. Ces dernieres recoivent le pointeur sur le probleme complet ainsi quesur la zone de memoire partagee.

Algorithm 5 Multi-GPUs : Initialisation des taches

Input: file {MPS file containing the problem}1: prob← read problem(file)2: shared← init shared(prob)3: for id = 1 to nGPU do4: init GPU(id, prob, share)5: end for

Algorithme principal

L’algorithme 6 decrit le cœur de l’algorithme que chaque GPU doit effectuer.Chaque tache dediee a un GPU doit determiner le sous-probleme sur lequel ilva travailler. Le device est alors initialise et ce sous-probleme est charge dans lamemoire globale du GPU. La suite de cet algorithme est sensiblement la memeque dans l’implementation sur un GPU. La seule exception est la methode per-mettant de detecter l’infaisabilite du probleme. Cette derniere necessite une col-laboration des differents GPUs car les variables non-basiques sont partagees surceux-ci. Cette etape se fait d’abord localement sur chaque GPU et les resultatslocaux sont ensuite partages dans la zone memoire dediee aux echanges.

Algorithm 6 Multi-GPUs : Algorithme principal

Input: id {GPU Id}Input: prob {Data structure containing the problem (CPU)}1: problocal ← init problem(id, prob)2: localProbdev ← init device(problocal)3: for i = 0 to 2 do4: if not feasible(localProbdev) then5: solve auxiliary(localProbdev)6: end if7: solve problem(localProbdev)8: reset problem(localProbdev)9: end for

10: problocal ← get solution(localProbdev)

59

Page 66: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Listing 4.5 – Task initialisation

1 .void MultiGPU : : s o l v e ( bool maximize , bool debug ) {cpu s e t t ∗ cpusetp ;

3 . cpusetp = CPU ALLOC(1024) ;

5 . i f ( ! maximize )p−>changeToMinimize ( ) ;

7 .

s o l v e r s = new So lve r [mGPU.nbGPU ] ;9 . for ( int i =0; i<mGPU.nbGPU; i++){

s o l v e r s [ i ] = So lve r (maximize , p , &mGPU) ;11 . s o l v e r s [ i ] . s o l v e ( i , debug ) ;

CPU ZERO( cpusetp ) ;13 . CPU SET( i +2, cpusetp ) ;

p t h r e a d s e t a f f i n i t y np ( s o l v e r s [ i ] . getPThread ( ) , s izeof (cpu s e t t ) , cpusetp ) ;

15 . }

17 . for ( int i =0; i<mGPU.nbGPU; i++){pth r ead j o in ( s o l v e r s [ i ] . getPThread ( ) , NULL) ;

19 . }

21 . CPU FREE( cpusetp ) ;

23 . de l e t e [ ] s o l v e r s ;}

60

Page 67: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Premiere phase : recherche d’une solution faisable

Si necessaire, la premiere phase du simplexe (decrite dans l’algorithme 7) estappliquee afin de determiner si une solution faisable existe. Chaque tache creeson probleme auxiliaire local. Cette etape ne necessite pas de communicationsentre les differentes taches CPU.

Ensuite, comme le decrit le listing 4.6, il est necessaire de determiner loca-lement quelle est la variable potentiellement entrante. Cette variable est placeedans la memoire partagee. Apres une synchronisation, chaque tache CPU vaelire une meme variable entrante parmi les differentes variables proposees dansla memoire partagee.

La tache ayant propose la variable entrante va alors determiner la variablesortante. Si cette derniere existe, la tache va alors la placer en memoire partageeainsi que les informations necessaires au pivotage des autres sous-problemes.Ces informations comprennent la colonne pivot ainsi que les informations dela variable entrante. Les informations de celle-ci sont necessaires etant donnequ’elle va devenir basique et que l’ensemble des variables basiques n’est paspartage mais copie dans chaque GPU.

Apres la synchronisation chaque GPU peut alors effectuer son pivotage al’aide des donnees dernierement placees en memoire partagee.

Finalement, chaque tache met a jour la faisabilite de son sous-probleme et ve-rifie s’il est devenu faisable suite a cette mise a jour. Le resultat de cette derniereetape est alors partage dans l’emplacement dedie. Les taches se synchronisentet verifient alors la faisabilite globale du probleme auxiliaire.

Seconde phase : recherche de l’optimum

La recherche de l’optimum fonctionne de la meme facon que la premierephase. La seule difference, comme on peut le constater dans l’algorithme 8, estqu’il n’y a pas besoin de creer le probleme auxiliaire ainsi que de verifier lafaisabilite.

61

Page 68: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Algorithm 7 Multi-GPU : Auxiliary problem (1st phase)

Input: localProbdev {Data structure containing the local problem (GPU)}Input: shared {Shared data structure used for communication (CPU)}Output: feasible, infeasible {Feasibility of the problem}1: create auxiliaryProblem(localProbdev) {GPU}2: while exists(xin) do3: // xin

4: localXin ← find localEntering(localProbdev) {GPU}5: share in(shared, localXin) {msg size : 1}6: synchronize()7: xin ← find globalEntering(shared)8: // xout

9: if localXin == xin) then10: xout ← find leavingVar(xin, localProbdev) {GPU}11: if not exists(xout) then12: return infeasible

13: end if14: share out(shared, xout) {msg size : 1}15: share pivoting(shared, column, variable) {msg size : m + 1}16: end if17: synchronize()18: // pivoting19: init pivoting(shared)20: pivoting(xin, xout, localProbdev) {GPU}21: // feasability check22: localFeas← update feasability(localProbdev) {GPU}23: share feas(shared, localFeas) {msg size : 1}24: synchronize()25: if feasible(shared) then26: return feasible

27: end if28: end while29: return infeasible

62

Page 69: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Listing 4.6 – Multi-GPU communication : entering variable search

r e d r e s u l t t So lve r : : f indCo l ( int &colDev ) {2 . r e d r e s u l t t myCol ;

r e d r e s u l t t re sCo l ;4 .

// Get the p i v o t column6 . myCol = kw . seFindCol(&lP ) ;

8 . // Put r e s u l t in shared CPU memorySET(mGPU−>exSE [ dev i c e ] , myCol ) ;

10 .

// Synchro b a r r i e r12 . p th r e ad ba r r i e r wa i t (&mGPU−>ba r r i e r ) ;

14 . colDev = −1;re sCo l . index = −1;

16 . re sCo l . va lue = 0 . 0 ;

18 . // Reductionfor ( int i =0; i<mGPU−>nbGPU; i++){

20 . i f ( f abs ( re sCo l . va lue ) < f abs (mGPU−>exSE [ i ] . va lue ) ) {re sCo l . index = mGPU−>exSE [ i ] . index ;

22 . re sCo l . va lue = mGPU−>exSE [ i ] . va lue ;colDev = i ;

24 . }}

26 . return re sCo l ;}

63

Page 70: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Algorithm 8 Multi-GPU : Optimum search (2nd phase)

Input: localProbdev {Data structure containing the local problem (GPU)}Input: shared {Shared data structure used for communication (CPU)}Output: feasible, infeasible {Feasibility of the problem}1: while exists(xin) do2: // xin

3: localXin ← find localEntering(localPdev) {GPU}4: share in(shared, localXin) {msg size : 1}5: synchronize()6: xin ← find globalEntering(shared)7: // xout

8: if isLocal(xin) then9: xout ← find leavingVar(xin, localPdev) {GPU}

10: if not exists(xout) then11: return infeasible

12: end if13: share out(shared, xout) {msg size : 1}14: share pivoting(shared, column, variable) {msg size : m + 1}15: end if16: synchronize()17: // pivoting18: init pivoting(shared)19: pivoting(xin, xout, localPdev) {GPU}20: end while21: return feasible

64

Page 71: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Chapitre 5

Modeles de performance

5.1 Introduction

Dans ce chapitre, nous allons etudier les performances theoriques des diffe-rentes implementations vues au chapitre precedent. Pour cela des modeles deperformances vont etre etablis pour chacune des implementations. Ces modelesmathematiques ont pour but de simuler le comportement d’une implementation.Ceci est fort utile lors de la parallelisation d’un algorithme car il est ainsi pos-sible d’estimer les gains apportes par l’ajout d’unites de calcul supplementaires,ou encore d’analyser la scalabilite de l’implementation en question.

Dans un premier temps, nous allons nous interesser a la modelisation d’unkernel. L’interaction avec les kernels se decompose generalement en deux phases.Une phase d’echange entre le CPU et le GPU afin de placer ou recuperer lesdonnees et une phase de calcul parallele sur le device.

Ensuite, nous etablirons les modeles des differentes operations presentes dansl’implementation du simplexe sur un GPU. Afin de garantir un modele compre-hensible, nous allons nous baser sur la seconde phase du simplexe. Les operationsdans cette phase sont le choix des variables ainsi que le pivotage. Une fois queles differents modeles seront definis, nous pourrons alors etablir le modele globalde l’algorithme.

Finalement, nous allons decrire le modele de l’implementation multi-GPU.Pour ce faire, les modeles de l’implementation sur un GPU seront recuperes etadaptes en fonction de la decoupe verticale du probleme vue en section 4.6.2.

5.2 Particularite lie a CUDA

5.2.1 Echanges de donnees CPU-GPU

Une implementation GPGPU est basee sur une interaction entre un CPU etun GPU. Le CPU effectue les decisions lies a l’algorithme et ordonne l’executiondes calculs paralleles sur le GPU. Afin d’effectuer les decisions, le CPU doitlire dans la memoire globale du GPU les informations resultant des calculsprealablement executes. Il lui est aussi necessaire de fournir dans cette memememoire les informations necessaires a l’execution des kernels.

Les GPUs communiquent avec les CPUs par des bus PCI (8x ou 16x pour les

65

Page 72: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

tesla S1070 ). Ces echanges sont relativement lents compares aux autres opera-tions d’acces aux donnees d’un GPU. En effet, la bande passante maximale pourun GPU de type tesla S1070 lors d’acces a sa memoire globale est de l’ordre de100GB/s. Alors que la bande passante maximal d’un bus PCI 8x est de 2GB/s(respectivement 4GB/s pour un bus PCI 16x).

De ce fait, il sera necessaire d’etre particulierement attentif a ce type d’echangesde donnees dans les modeles de performance.

5.2.2 Modeliser un Kernel

Generalites

Comme nous l’avons precedemment vu dans le chapitre 3, l’architectureCUDA est relativement complexe. Chaque kernel est decompose en plusieursblocks s’executant en parallele sur differents multiprocesseurs. Il est importantde prendre correctement en compte ces differents niveaux de parallelisme ainsique les pipelines qui leur sont dedies.

Il est cependant difficile d’etablir un modele comprenant l’ensemble des sub-tilites de l’architecture CUDA. Un tel modele serait trop complexe et doncincomprehensible. Nous allons nous baser sur l’approche decrite par K. Kishoreet al. [7] qui etablit un modele comprehensible. De plus, leur modele obtient desresultats proches des performances reelles.

Niveaux de parallelisme

Un kernel peut etre decompose en une phase d’initialisation suivie d’unephase de calcul. La phase d’initialisation est assez rapide. Elle consiste a mettreen place le contexte d’execution du kernel. Cette derniere etant constante et tresrapide, il n’est pas interessant de l’inclure dans notre modele.

La phase de calcul est plus complexe et son temps d’execution depend dutravail a effectuer. Elle sera donc au cœur de notre modele. Le parallelisme d’unkernel se situe a plusieurs niveaux.

Le premier niveau consiste en la decomposition du travail total en sous-parties, les blocks. Ces derniers sont alors repartis sur les differents multipro-cesseurs. Le temps d’execution d’un kernel est donc lie au nombre de blocksNB par multiprocesseur (Symetric Multiprocessor, SM ), ainsi que du nombrede ceux-ci par GPU, NSM.

Le second niveau consiste a partager le travail d’un block sur les differentscœurs du multiprocesseur. Pour ce faire, un block est decompose en groupe detaches, les warps. Un warp contient plusieurs sous-groupes de taches qui sontexecutes en parallele sur les cœurs du multiprocesseur. Le temps d’executiond’un block est donc dependant du nombre de warp par block Nw, du nombre detaches par warp Nt ainsi que du nombre de cœurs par multiprocesseur NC.

Le troisieme et dernier niveau de parallelisme est un pipeline. Ce pipelinepermet une execution pseudo-parallele de chaque sous-groupe de taches se trou-vant dans un warp. Le gain apporte par ce pipeline est exprime par sa profondeurD.

66

Page 73: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Travail fourni par une tache

Maintenant que nous avons vu les differents niveaux de parallelisme, il estnecessaire de determiner le travail qu’une tache doit fournir. Ce travail dependdu nombre et du type d’instructions que la tache doit effectuer. Chaque instruc-tion coute un nombre de cycles different comme nous l’avons vu dans la section3.3.4. Par exemple, une addition de nombres flottants (simple precision) coute4 cycles alors qu’une division coute environ 36 cycles.

Ensuite, il est necessaire de differencier les instructions d’acces a la memoireglobale des instructions arithmetiques. En effet, les instructions d’acces a lamemoire globale coutent 4 cycles initialement auxquels sont ajoutes entre 400et 600 cycles de latence avant que les donnees soient disponibles. Durant cettelatence, des instructions arithmetiques (independantes des donnees qui sont enattente d’acces) peuvent etre executees afin de cacher cette derniere.

L’ordonnanceur s’emploie a cacher la latence des acces memoire autant quepossible. Une partie est deja cachee par le pipeline de taches dans un warp.L’ordonnanceur effectue ensuite des rotations de warps afin de ne pas gaspillerde temps lorsque les taches sont bloquees sur des donnees qui sont en attented’acces.

Il existe ensuite deux possibilites pour estimer le travail total d’une tache. Lapremiere consiste a considerer que la structure du code des kernels ne permetpas aux instructions arithmetiques d’etre cachees par la latence d’acces a lamemoire. Dans ce cas, il est necessaire d’effectuer la somme des deux typesd’instructions (arithmetique et acces a la memoire). La seconde possibilite estla situation inverse. En admettant que les instructions arithmetiques se trouventetre cachees par la latence d’acces aux donnees, il faut alors considerer le travailtotal comme etant le maximum des deux types d’instructions. Ceci car ces deuxtypes d’instructions se font en parallele.

Le choix de la variante appropriee est difficile a determiner. Il depend denombreux facteurs dont la dependance entre les deux types d’instructions, maisaussi l’efficacite des pipelines. Cette derniere est d’autant plus difficile a estimeretant donne qu’elle depend de la strategie mis en place par l’ordonnanceur.

Le nombre de cycles pour une tache CT peut alors etre defini comme lasomme, respectivement le maximum, des instructions d’acces a la memoire etdes instructions arithmetiques. De plus, nous allons prendre la tache necessitantle plus de calculs parmi l’ensemble des taches du kernel afin d’etablir le worstcase scenario.

Modele de performance global

Afin d’etablir le modele de performance global pour un kernel, il est ne-cessaire d’etablir le travail qu’un SM (Streaming Multiprocessor) doit effectuer.En effet, chaque SM dispose du meme nombre de blocks a traiter, et donc ilsdevraient tous terminer en meme temps leur execution.

Le travail d’un cœur Ccore peut s’exprimer, en cycles, par :

Ccore = NB ·Nw ·Nt ·CT ·1

NC ·D(5.1)

soit, le produit entre le nombre de blocks par SM NB, le nombre de warps parblock Nw, le nombre de taches par warp Nt et le nombre de cycles par tache

67

Page 74: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

CT. Le tout divise par le nombre de cœurs par SM NC et par la profondeur Ddu pipeline existant lors du traitement d’un warp.

Finalement, le temps pour un kernel TK depend de la frequence F d’uncœur :

TK =Ccore

F(5.2)

5.3 Simplexe sur un GPU

5.3.1 Recherche de la variable entrante : steepest edge

La premiere operation consequente de l’algorithme 4 (section 4.4.4) consistea trouver la variable entrante. Cette operation est principalement executee dansun kernel mis a part la phase finale qui se fait sur le CPU.

La methode du steepest edge consiste a trouver la variable donc le ratio sejest le plus petit. Rappelons que ce ratio se calcule de la maniere suivante :

sej =cj

‖ηj‖2 + 1∀j ∈ 1..n (5.3)

ou cj est le coefficient de la variable dans la fonction objectif et ηj la colonnede la matrice correspondant a la variable non-basique xj . Toutes les variablesnon-basiques ne sont pas eligibles pour entrer dans la base. Certaines se trouventdeja a leur valeur optimale. Ce calcul doit donc uniquement se faire sur un ratioα des colonnes.

Le kernel divise cette tache en allouant a chaque block un sous-ensemble decolonnes a calculer. Dans l’implementation, le nombre de blocks est defini enfonction du nombre de colonnes a traiter, jusqu’a un maximum d’environ deuxblocks par SM. Cependant afin de simplifier le modele, le nombre de blocks parSM sera toujours de deux, NB = 2.

Un block calcule une colonne a la fois. Pour ce faire, chaque tache du blockdoit calculer une partie de la norme ‖ηj‖

2. Une fois que chaque tache a calculesa norme locale, l’ensemble de celles-ci collaborent afin de reduire leur sommepartielle en une somme globale. La somme finale se trouve sur la tache 0, cettederniere calcule sej et le memorise si c’est le plus petit resultat trouve jusqu’apresent.

Le nombre d’element est donc le suivant :

Nel =m

NTaskPerBlock

(5.4)

Nel elements doivent etre calcules avant d’effectuer la reduction. Cette dernierenecessite NRed = log2(NTaskPerBlock) etapes pour sommer les normes partielles.

Dans le pire des cas une tache doit lire Nel valeurs depuis la memoire globaleainsi que le coefficient cj , soit :

Cmem =(Nel + 1) · Cload

Nw

(5.5)

ou Cload equivaut a la latence d’une lecture. Nw intervient dans le denominateurafin de modeliser la rotation des warps mise en place par l’ordonnanceur afin decacher la latence.

68

Page 75: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Cette tache doit ensuite multiplier et sommer chacune des valeurs, effectuerla reduction, diviser cj par le resultat de la reduction et controler si le resultatobtenu est le meilleur jusqu’a present. Soit :

Ccalc = Nel · (Cadd + Cmul) +NRed · Cadd + Cdiv + Ccmp (5.6)

ou Cins est le nombre de cycles que prend l’instruction ins.Le nombre de colonnes par block est defini par :

Ncol =α · n

NB ·NSM

(5.7)

Un block doit donc traiter Ncol colonnes et memoriser le resultat obtenu a lafin. Le nombre final de cycles par tache est exprime par :

CT = max(Ncol · Cmem + Cstore, Ncol · Ccalc) (5.8)

ou par la somme de ces deux termes selon le type de modelisation utilise. Il nenous reste plus qu’a appliquer les formules 5.1 et 5.2 pour obtenir le temps pource kernel.

Au temps du kernel TKse, il est encore necessaire d’ajouter le temps TCPUse

de lecture des resultats depuis le CPU ainsi que de la recherche sur ces der-niers. Le nombre de resultats a lire est egal au nombre total de blocks, NBtot =NB ·NSM. Soit,

TCPUse = NBtot · (BPPCI +CcmpCPU

FCPU

) (5.9)

ou BPPCI est la bande passante de la connexion PCI entre le GPU et leCPU.

Cependant, lorsque m et n sont grand, NBtot qui est constant devient negli-geable par rapport a ceux-ci. Il en est de meme pour TCPUse car le temps decalcul du kernel est nettement plus long que cette operation.

5.3.2 Recherche de la variable sortante : expand

La seconde operation de l’algorithme 4 (section 4.4.4) est la recherche de lavariable sortante. Ce choix necessite nettement moins de calculs que les deuxautres operations. En effet, cette derniere est de complexite O(m) alors que larecherche de la variable entrante et le pivotage sont de complexite O(mn). Nousallons tout de meme etablir son modele etant donne qu’il nous sera utile pourle modele de l’implementation multi-GPU.

Le choix de la variable sortante se fait par la methode expand. Cette methodeconsiste a effectuer deux (ou trois pour la phase 1) passes sur la colonne de lavariable sortante. Chaque passe consiste a calculer pour chaque equation lacontrainte de gain sur la variable entrante. Ceci consiste, grossierement, a lireplusieurs valeurs de la memoire globale ainsi qu’a calculer la contrainte. Quelquesadditions et une division sont necessaires pour cela. Il faut finalement reduire leresultat local de chaque tache en un resultat final.

Le schema de partage des donnees ressemble en partie au kernel precedent.Nous avons deux blocks maximum par SM, soit NB = 2. Le nombre total de

69

Page 76: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

blocks est donc NBtot = NB ·NSM. Ce qui fait que le nombre d’elements parblock est le suivant :

Nel =m

NTaskPerBlock ·NBtot

(5.10)

Le nombre d’etapes necessaires a la reduction est le meme que dans le kernelprecedent, soit NRed = log2(NTaskPerBlock).

Chaque tache doit lire pour chaque variable lui etant attribuee (Nel) : lavaleur de la variable, ses bornes et le coefficient pivot potentiel. Les operationsd’acces a la memoire n’etant pas bloquantes, il est necessaire d’attendre une foisle temps de latence d’un acces. Une fois la meilleure valeur etablie pour le block,apres la reduction, la tache 0 doit memoriser le resultat. La latence est reduitepar la rotation de warps geree par l’ordonnanceur, soit :

Cmem =(Nel · Cload + Cstore)

Nw

(5.11)

La tache doit definir pour chacune de ses Nel variables la contrainte quecelles-ci imposent au gain de la variable entrante. Ensuite, les tache doiventcooperer pour definir la variable la plus contraignante. Soit le nombre d’instruc-tions suivant :

Ccalc = Nel · (2 · (Cadd + Ccmp) + Cdiv) +NRed · Ccmp (5.12)

Et donc le nombre de cycles pour une tache est le suivant,

CT = max(Ccalc, Cmem) (5.13)

Afin d’obtenir TKexp, il suffit une fois de plus d’appliquer les equations 5.1et 5.2. Etant donne que le nombre de blocks est le meme que dans le kernelprecedent, il n’est pas non plus necessaire de definir le temps pris par le CPUTCPUexp. En effet, des que m devient grand NBtot devient negligeable.

5.3.3 Mise a jour de la matrice : pivotage

La troisieme et derniere operation de l’algorithme 4 (section 4.4.4) est le pi-votage. Afin d’effectuer cette operation, il faut tout d’abord echanger la variablebasique et la variable non-basique. Ensuite, le CPU doit acceder a quelques don-nees du GPU afin de preparer la mise a jour de la matrice. Celle-ci consiste aeffectuer la multiplication matricielle d’un vecteur de taille m par un vecteurde taille n et de sommer la matrice resultante de taille n ×m a notre matriced’equations.

Les quelques swap sur le GPU et echanges de donnees entre le CPU et le GPUsont constants, faibles et independants de m et n. Ils sont donc negligeables dansle modele. Par contre l’operation de mise a jour est de complexite O(mn). Unkernel disponible dans la librairie CUBLAS permet d’effectuer cette operationde maniere optimisee.

Les codes source de cette librairie ne sont pas facilement disponibles. Nousallons donc estimer le fonctionnement de ce kernel. Pour ce faire, nous allonsmodeliser le cas optimal ou tous les acces aux donnees se font sans collisions etou la latence est masquee de facon optimale.

Le travail d’une tache va etre de lire trois valeurs : un coefficient pour chaquevecteur, soit vi et wj . Le coefficient correspondant dans la matrice d’equations

70

Page 77: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

aij sera aussi recupere. Ensuite, les deux coefficients des vecteurs vont etremultiplies et le resultat sera somme au coefficient, soit rij = aij + vi · wj . Leresultat rij doit finalement etre ecrit dans la memoire globale.

Afin de cacher au mieux la latence des lectures et ecritures, il est necessairede fournir autant d’elements a calculer que possible a une tache. En effet, nouspouvons profiter du fait que les instructions de lecture et ecriture ne sont pasbloquantes. Cependant, la prochaine instruction necessitant la donnee en coursd’acces l’est. Ce qui fait que si une tache traite un seul element de la matrice, ily aura deux latences a attendre : celle de la lecture des informations et celle del’ecriture, soit :

Cmem =2 · Cload

Nw

(5.14)

Tandis que si une tache traite une multitude d’elements, disons k elements,alors la tache va effectuer k iterations contenant les lectures et l’ecriture. Achaque iteration, mis a part la derniere, les lectures de l’iteration i se ferontjuste apres l’ecriture de l’iteration i − 1 cachant ainsi la latence de l’ecriture.Nous avons donc k−1 iterations necessitant d’attendre une fois la latence vu queles lectures et l’ecriture sont couplees. Pour la derniere iteration, il est necessaired’attendre deux fois la latence vu que les operations ne peuvent etre couplees.Soit :

Cmem =(k + 1) · Cload

Nw

(5.15)

Lorsque k >> 1, nous avons environ k latences pour k iterations, soit une seulelatence par element a traiter.

Nous allons utiliser la meme technique de repartition des donnees que dansles cas precedents, soit NB = 2 et NBtot = NB ·NSM. Ce qui nous amene aunombre suivant d’elements a traiter par tache :

Nel =m · n

NTaskPerBlock ·NBtot

(5.16)

Le nombre de cycles necessaires pour acceder aux donnees est exprime parl’equation 5.15 avec k = Nel. Afin d’effectuer le calcul, il est necessaire d’effec-tuer un produit et une addition par element a traiter, soit :

Ccalc = Nel · (Cadd + Cmul) (5.17)

Le nombre total de cycles pour une tache est alors le suivant :

CT = max

(

(Nel + 1) · Cload

Nw

, Ccalc

)

(5.18)

Finalement, afin d’obtenir TKpivo, il est necessaire d’appliquer les equations5.1 et 5.2. Comme nous l’avons mentionne prealablement, TCPUpivo est negli-geable.

5.3.4 Modele de performance general

Les differentes operations de l’algorithme 4 (section 4.4.4) sont desormaisdefinies. Il ne nous reste plus qu’a effectuer la somme des temps pour chaquekernel afin d’obtenir une estimation du temps que prendrait une iteration. Soit :

Titeration = TKse +TKexp +TKpivo (5.19)

71

Page 78: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Le modele pour la resolution d’un probleme necessite une initialisation duGPU et de sa memoire, suivi de plusieurs iterations et finalement de la lecturede la solution, soit :

Tprob = Tinit + r ·Titeration +Tsolution (5.20)

La complexite de Tinit est de l’ordre de O(mn) car il est necessaire de liretoutes les donnees depuis un fichier, puis de les placer dans la memoire globaledu GPU. A cela vient s’ajouter un temps d’initialisation du device.

La lecture de la solution consiste a lire la valeur des n variables de decision.Etant donne sa faible complexite, O(n), Tsolution est negligeable compare aTinit et Titeration.

Le nombre d’iterations r est difficile a determiner. Il depend de la methodede choix de la variable entrante, de la complexite du probleme et de sa taille.V. Chvatal [6] cite neanmoins des etudes sur le nombre d’iterations necessairespour resoudre un probleme. Ces differents travaux etablissent que la croissancedu nombre d’iterations est proportionnelle a celle de m. L’impact d’une aug-mentation de n pour un m fixe serait proportionnel a log(n). La phase de calculr ·Titeration serait donc de complexite O(n · log(n) ·m2).

Tinit est alors negligeable par rapport a la phase de calcul lorsque m estgrand. Cependant, lorsque m est petit, l’impact de l’initialisation est importanta cause du temps de preparation d’un device qui prend entre 0.2[s] et 0.4[s].

Le temps pris pour l’initialisation sera estime a Tinit = 0.3[s] etant donneque pour de petits m et n la lecture du probleme est negligeable par rapportau temps d’initialisation du device. Pour de grands n et m, le temps de calculr · Titeration est alors nettement plus important que le temps de la lecture duprobleme ce qui nous permet une fois de plus de le negliger.

5.4 Simplexe multi-GPU

5.4.1 Generalites

Le principe de cette section est de reprendre le modele vu dans la sectionprecedente et de l’adapter a la decoupe du probleme decrite dans la section4.6.2.

La decoupe nous permet d’utiliser les memes kernels que dans l’implementa-tion sur un GPU. Leur modele de performance ne sera donc pas modifie, seul lenombre de donnees a traiter va varier en fonction du nombre de GPUs, NGPU .Vu que nous avons choisi d’appliquer une decoupe verticale du probleme, unsous-probleme sera de taille msp × nsp ou msp = m et nsp = n

NGPU.

Pour determiner les differences propres a l’implementation sur plusieursGPUs, nous allons nous baser sur l’algorithme 8. Premierement, nous pouvonsobserver que dans cet algorithme tous les GPUs ne font pas exactement le memetravail. Afin de modeliser cela correctement, le travail le plus consequent dechaque etape sera modelise.

Ensuite, a chaque kernel de l’algorithme que nous avons modelise precedem-ment vient s’ajouter une phase de synchronisation et d’echange de donnees entreCPUs et entre CPU-GPU. Il est necessaire de modeliser ces phases car dans lamajorite des cas leur complexite depend de la taille du probleme ou du nombrede GPUs.

72

Page 79: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Les echanges de donnees effectues par les CPUs vont etre modelises selon labande passante des differents bus utilises par le CPU. Lorsque le CPU accederaaux donnees du GPU, la bande passante sera celle du bus PCI. Tandis quelorsqu’il modifiera la memoire partagee entre les CPUs, la bande passante dubus de la RAM (Random Access Memory) sera utilisee.

Ces differentes modelisations vont etre le sujet des prochaines sections.

5.4.2 Recherche de la variable entrante : steepest-edge

Cette etape est composee du temps TKse que nous savons deja calculer ainsique du temps de synchronisation TSse, soit :

Tse = TKse +TSse (5.21)

Le temps de synchronisation et d’echange de donnees TSse depend pourcette phase du nombre de GPUs, NGPU . En effet, chaque GPU va etablir leresultat local pour la methode steepest edge et placer la meilleure valeur ob-tenue en memoire partagee. Apres la synchronisation, chaque GPU va lire lesNGPU donnees et definir quelle est la variable entrante. Cette reduction se faitlocalement sur chaque GPU etant donne que le nombre de GPUs est faible.

Le temps de synchronisation ainsi que celui d’ecriture d’une variable en me-moire partagee sont constants et a priori faibles. Il n’est donc pas necessaire deles inclure dans le modele. Par contre les temps de lecture et de reduction localesont importants a incorporer dans le modele, car ils sont dependants de NGPU .Soit,

TSse =N2

GPU · sizedoubleBPRAM

(5.22)

Le nombre de GPU est au carre, car la bande passante de la RAM estpartagee par les differents CPUs devant recuperer ces donnees.

5.4.3 Recherche de la variable sortante : expand

La recherche de la variable sortante etait negligeable dans le cas de l’imple-mentation sur un GPU, comme nous l’avons vu. Cependant, il est desormaisimportant de prendre en compte cette operation. Plus le nombre de GPUs seraimportant, plus cette methode sera longue comparee aux autres etant donne quesa complexite est O(m). De plus, la phase de synchronisation et d’echanges demessages necessitent que le GPU, qui determine la variable sortante, partage lacolonne pivot avec les autres GPUs.

Le temps le plus long est defini par celui du GPU qui va effectuer la methodeexpand, soit :

Texp = TKexp +TSexp (5.23)

Le calcul de TKexp est deja defini dans la section precedente. Il ne reste plusqu’a definir TSexp. Ce dernier consiste dans un premier temps a la lecture dela colonne pivot se trouvant sur le GPU, depuis le CPU, ainsi que les informa-tions liees a la variable sortante. Ces informations sont neanmoins negligeablescar elles sont constantes et de petites tailles. Une fois que la colonne pivot estrecuperee, elle doit etre placee en memoire partagee. Afin de signaler que sontravail est termine, le CPU effectuera ensuite l’etape de synchronisation (quenous pouvons negliger), soit :

73

Page 80: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

TSExp = msp · sizedouble ·

(

1

BPPCI

+1

BPRAM

)

(5.24)

5.4.4 Mise a jour de la matrice : pivotage

La mise a jour de la matrice consiste a preparer la matrice pour le pivotageavant de l’effectuer. Le kernel de pivotage est le meme que dans l’implementa-tion sur un GPU. Il est donc uniquement necessaire de determiner le temps desynchronisation et d’echange de donnees TSpivo et de l’ajouter, soit :

Tpivo = TKpivo +TSpivo (5.25)

Avant d’effectuer le pivotage, les GPUs ne possedant pas encore la colonnepivot doivent la lire depuis la memoire partagee et la charger dans la memoireglobale du GPU, soit :

TSpivo = msp · sizedouble ·

(

(NGPU − 1)

BPRAM

+1

BPPCI

)

(5.26)

Le nombre de GPUs, NGPU apparaıt dans cette equation car tous ces der-niers, sauf celui qui a determine la variable sortante, font un acces a la memoirepartagee. Il est alors necessaire de faire le rapport entre la bande passante de laRAM et le nombre de taches CPU y accedant.

5.4.5 Modele de performance general

Le modele de performance general est semblable a celui de l’implementationsur un GPU. Le temps d’execution d’une iteration equivaut a la somme dutemps pris par chaque operation, soit :

Titeration = Tse +Texp +Tpivo (5.27)

Le temps pour resoudre un probleme demeure le meme que celui que nousavons defini au prealable dans l’equation 5.20.

5.5 Application du modele : mesures theoriques

5.5.1 Generalites

Afin d’obtenir des graphes simulant le temps que prendront nos implemen-tations, il est necessaire de determiner les valeurs liees au materiel utilise (voirsection 6.4.2) ainsi qu’aux kernels. Pour les caracteristiques des GPUs, le manuelde reference de CUDA [1] detaille toutes les informations liees a un GPU. Lesbandes passantes des bus PCI et RAM sont definies par leur standard respectifen fonction de la version de ces derniers.

Les kernels developpes pour nos implementations ont un nombre de tachespar block fixe a 128. Le ratio de variables non-basiques eligibles pour le choix dela variable entrante est fixe arbitrairement a 80%, soit α = 0.8. Le ratio α seracependant fixe de maniere empirique par la suite (section 6.5.2).

74

Page 81: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

5.5.2 Temps par iteration

Dans un premier temps, nous allons modeliser le temps d’execution pour uneiteration sur un GPU afin de comparer le travail de chaque kernel.

Figure 5.1 – Modele : temps d’execution pour une iteration sur un GPU

La figure 5.1 contient le temps par iteration de chaque kernel ainsi que letemps total pour une iteration. Les kernels prenant le plus de temps sont ceuxeffectuant le pivotage ainsi que la recherche de la variable entrante. Commenous l’avions prevu lors de la modelisation, le kernel expand prend un tempsnegligeable compare a celui des deux autres.

5.5.3 Temps pour resoudre un probleme

Nous allons desormais nous interesser a la modelisation du temps necessairea un ou plusieurs GPUs pour resoudre un probleme entier. Le nombre de GPUsa ete choisi afin de demontrer l’utilisation d’une, deux ou quatre tesla s1070,chaque tesla etant composee de quatre GPUs.

Le gain en performance decrit par la figure 5.2 semble etre proportionnel aunombre de GPUs ce qui laisse presager un assez bon speedup pour des problemesde taille considerable. L’allure des courbes obtenues correspond relativementbien a la complexite theorique de l’algorithme O(log(n)nm2) definie a la section5.3.4.

75

Page 82: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Figure 5.2 – Modele : temps d’execution pour un probleme sur plusieurs GPUs

5.5.4 Speedup

Afin de mieux analyser le gain en performance relatif au nombre de GPUsutilises, nous allons reprendre les modelisations precedemment etablies pourmodeliser la courbe de speedup theorique de notre implementation.

La mesure du speedup (figure 5.3) confirme que le choix de la decoupe verti-cale du probleme convient bien a un nombre limite d’unites de calcul. En effet,au-dela d’un certain seuil l’ajout de GPUs a tendance a reduire le gain. Sur despetits problemes les gains sont faibles. Cependant des que leur taille devientconsequente, le speedup theorique est presque optimal jusqu’a une trentaine deGPUs. Ce qui correspond a la taille moyenne d’un cluster de GPGPU.

76

Page 83: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Figure 5.3 – Modele : speedup theorique

77

Page 84: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Chapitre 6

Mesures

6.1 Introduction

Nous allons maintenant nous interesser a la performance reelle de nos imple-mentations.

Il va etre necessaire de mesurer ces performances selon plusieurs criteres.Le premier est le bon fonctionnement de l’implementation. En effet, certainsproblemes de programmation lineaire peuvent s’averer complexe a resoudre acause des cycles et de la precision de calcul limitee sur les nombres flottants.Il est donc important de garantir que l’implementation de l’algorithme et desdifferentes methodes sont robustes.

Le second critere est le gain apporte par la parallelisation de l’algorithme.Pour cela, il va etre necessaire de trouver une implementation sequentielle etperformante afin de l’utiliser comme reference pour la comparaison. Differentesimplementations vont etre passees en revue et le fonctionnement de celle choisiesera brievement etudie.

Une fois que ces differents criteres seront mesures, il sera possible d’analyserles resultats obtenus. Pour ce faire, les performances theoriques determinees dansle chapitre 5 seront comparees a celles caracterisees par les mesures obtenues aucours de chapitre. Nous tacherons de determiner pour quel type de problemesnos implementations fonctionnent le mieux.

6.2 Implementation de reference

Il existe de nombreuses implementations du simplexe. La majorite de cesimplementations sont basees sur l’algorithme du simplexe revise.

Parmi ces dernieres, on peut compter CPLEX et MINOS qui sont des im-plementations commerciales. CPLEX est le produit d’IBM et montre de tresbonnes performances.

Il existe aussi plusieurs implementations libres qui approchent des perfor-mances des deux precedemment citees. GLPK (GNU Linear Programming Kit)est une librairie qui fait partie du projet GNU et est basee sur une partie dulangage AMPL (un langage de modelisation pour problemes mathematiques). Ily a aussi LP SOLVE qui est une implementation aboutie et qui dispose de nom-breuses fonctionnalites. Ces deux solvers offrent aussi la possibilite de resoudre

78

Page 85: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

des problemes mixte entier-reel.L’implementation choisie comme reference est CLP (COIN-OR Linear Pro-

gramming). Elle fait partie du projet COIN-OR (COmputational INfrastructurefor Operations Research). Ce projet a pour mission d’offrir a la communauteopen source des logiciels lies a la recherche operationnel. CLP est l’implemen-tation open source approchant au mieux des performances des implementationscommerciales citees precedemment.

CLP est base sur l’algorithme du simplexe revise. Afin de tirer un profit maxi-mal de la densite faible en coefficients non-nuls des problemes de programmationlineaire, il utilise des structures de donnees ne memorisant que les coefficientsnon-nuls du probleme.

6.3 Mesures de fonctionnement

6.3.1 Objectif

Avant de comparer nos implementations avec CLP, il est necessaire de contro-ler qu’elles permettent de traiter les memes problemes que ce dernier. En effet,une implementation basique de l’algorithme du simplexe ne permet pas de trai-ter tous les problemes.

Differents cas peuvent subvenir empechant l’obtention de la valeur optimum.Les principales difficultes rencontrees par l’algorithme sont les cycles et les im-precisions numeriques (qui n’apparaissent que lors du passage a la pratique).Certains problemes, les cas de bord, contiennent un grand nombre de ce typede difficultes.

6.3.2 Ensemble de donnes

Afin de bien tester l’implementation, il est necessaire de disposer d’un en-semble de donnees consequent et varie.

L’ensemble de problemes lineaires disponible sur le depot Netlib [4] corres-pond bien a ces criteres. Il est generalement utilise comme banc de tests parla majorite des implementations du simplexe. Il est compose de 77 problemesde tailles petite a moyenne. Ces problemes representent toutes les variantes debornes individuelles sur les variables (fixee, libre, plus petite que ou encore plusgrande que).

Une partie des problemes provient de problemes reels (production-allocation,scheduling) difficiles a resoudre. Le reste est compose de problemes concus pourgenerer des situations de cycles ou d’instabilite numerique.

En plus de cet ensemble de donnees, plusieurs problemes de scheduling nousont ete fournis par la compagnie APM Technologies [2]. L’ensemble des pro-blemes a notre disposition offre une bonne base pour tester la majorite desdifficultes pouvant etre rencontrees par des implementations du simplexe.

6.3.3 Resultats

La derniere version de l’implementation arrive a resoudre la totalite desproblemes de l’ensemble de donnees Netlib ainsi que les differents problemesfournis par APM Technologies. La precision sur les resultats obtenus sont del’ordre de 10−6.

79

Page 86: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Il est interessant de relever que sur ce premier echantillon de problemesnotre implementation necessite moins d’iterations pour resoudre les problemes.Neanmoins, elle est plus lente que CLP, notamment a cause de l’initialisationdu GPU. Ceci est facilement explicable par la petite taille des problemes ainsique par leur faible densite et indique que les GPUs doivent etre utilises pourdes problemes de grande taille.

Il est aussi important de souligner qu’afin d’obtenir de tels resultats de nom-breuses modifications ont du etre apportees a l’implementation initiale. En ef-fet, cette derniere ne resolvait que 50% des problemes approximativement. Lamethode expand [13] et une attention particuliere aux effets des imprecisionsnumeriques ont fortement aide a stabiliser l’algorithme.

6.4 Mesures de performance

6.4.1 Objectif

Maintenant que nous avons determine que les deux implementations per-mettent d’obtenir les memes resultats, nous allons nous interesser a leur perfor-mance.

La premiere performance que nous allons mesurer est le temps d’executionpris pour resoudre des problemes de tailles variables. A partir de ces mesures,nous etablirons aussi le temps d’execution moyen par iteration.

Ceci est important car le CLP n’utilise pas la meme methode de choix de lavariable entrante que nos implementations. De ce fait, le nombre total d’itera-tions peut etre fortement different. La prochaine mesure sera donc une comparai-son du nombre moyen d’iterations que met le CLP pour resoudre des problemes,compare a celui de notre implementation utilisant la methode steepest edge, puisla methode standard.

Finalement, nous allons nous interesser aux differences entre l’algorithme dusimplexe revise et du simplexe standard. Le premier est repute pour etre parti-culierement performant sur des problemes de faible densite (matrices creuses),alors que le second est cense etre performant sur des problemes denses. Pour cefaire, nous allons evaluer le temps pris par les implementations pour resoudredes problemes de taille fixe mais de densite variable.

6.4.2 Environnement de mesures

Les performances sont dependantes du materiel sur lequel les mesures ontete effectuees. Afin de determiner notre environnement de mesures, nous allonsenumerer les caracteristiques cles du systeme dont nous disposons. Le systemeest compose d’un serveur et d’une tesla S1070. Les deux sont interconnectes pardeux connections PCI16x.Le serveur contient :

– 2 Intel Xeon X5570 - 2.93GHz (quad core)– 24 Gb de DDR3– Disque dur SSD de 250Gb PCI8x

Sur un rack 1U tesla S1070 se trouve 4 GPUs dont les caracteristiques sont lessuivantes :

– 30 Streaming Multiprocessors

80

Page 87: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

– 8 cœurs par SM a environ 1.4GHz– 4GB de GDDR3, soit max. 100GB/s de bande passante pour un kernel– 1000 GFLOPS en simple precision, 80GFLOPS en double precision

6.4.3 Ensemble de donnees

L’ensemble de donnees pour cette partie des mesures est tres particulier.Il doit contenir un nombre consequent de problemes de taille et de densite va-riables. Aucun ensemble de donnees correspondant a ces criteres n’est disponiblea notre connaissance.

Cependant, il existe differentes methodes pour generer des problemes li-neaire. L’inconvenient de ce type de methode est que les problemes en resul-tant disposent tous des memes caracteristiques. En effet, pour une meme tailleet une meme densite, deux problemes generes de la sorte necessitent approxi-mativement le meme nombre d’iterations et amene a une valeur optimale tresproche.

Malgre cet inconvenient, nous allons utiliser une de ces techniques car ellenous permet d’obtenir des problemes dont la taille et la densite peuvent etrespecifiees. De plus, les problemes generes disposent tous d’une solution faisable.ce qui est pratique.

La technique en question consiste a determiner les taillesm et n de la matrice.Il suffit ensuite de generer des coefficients entre 0 et 1 pour les variables desequations avec une probabilite d equivalente a la densite voulue. Ensuite, lescoefficients de la fonction objectif sont places a -1 pour les variables disposantde coefficients non-nuls dans leur colonne. Les autres ont leur coefficient de lafonction objectif place a 1. Finalement, le membre droit de l’equation est fixearbitrairement a 1.

6.4.4 Resultats

Taille de probleme variable

Le temps d’execution pour une iteration en fonction de la taille du problemea ete mesure. La densite maximale des problemes a ete fixee a 5% dans le butd’obtenir des performances interessantes avec CLP. Le temps moyen par itera-tion a ete obtenu en effectuant la division entre le temps total d’execution desdifferentes implementations et leur nombre d’iterations necessaires a la resolu-tion du probleme.

La figure 6.1 demontre que CLP obtient de bonnes performances pour despetits problemes de densite faible. La tendance est inversee pour les implemen-tations sur GPUs. Les temps d’initialisation ainsi que les echanges de messagesentre GPUs les rendent peu efficients pour des problemes de petite taille. Tandisque pour ceux de grandes tailles, elles sont bien plus rapides que le CLP.

La seconde mesure est celle du temps pris par la resolution d’un problemeen fonction de sa taille. La densite a ete fixee cette fois a 30% afin d’avoirune premiere impression de son influence sur CLP. Afin de bien souligner cela,seules les mesures pour lesquelles l’implementation a reussi a resoudre tous lesproblemes dans un temps donnes sont affichees. Ce temps a ete fixe a 30 minutesmaximum pour CLP.

81

Page 88: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Figure 6.1 – Mesures : temps pour une iteration (d < 5%)

Figure 6.2 – Mesures : temps pour un probleme (d < 30%)

On peut constater dans la figure 6.2 que des que la densite augmente, CLPprend un temps considerable pour resoudre des problemes, meme ceux ayantune taille relativement petite (en deca de m = 500). Une densite plus grandeque 20% et un probleme de taille 750 necessitent deja un temps tres importantpour CLP (plus de 30 minutes).

82

Page 89: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

L’implementation sur un GPU offre de bonnes performances sur les pro-blemes de petite a moyenne tailles. A partir d’un certain seuil le temps pourresoudre un probleme croıt de facon fortement exponentielle. L’ajout de GPUsameliore les performances de maniere considerable pour les problemes de grandetaille. On peut remarquer que pour m = 5000, le speedup semble etre prochedu speedup optimal.

Nombre d’iterations

Nous allons desormais determiner l’impact qu’a la methode de choix de lavariable entrante sur le temps de resolution d’un probleme. Pour ce faire, nousallons comparer le nombre d’iterations mis par CLP et par le simplexe sur GPUpour resoudre un probleme. L’implementation sur GPU sera executee une fois enutilisant la methode standard (choix du plus grand coefficient dans la fonctionobjectif) et une fois avec la methode steepest edge. CLP utilise une methodemodifiee du steepest edge basee sur une approximation de la norme (voir section4.5.2).

Figure 6.3 – Mesures : nombre d’iterations pour un probleme

Sur notre ensemble de donnees, la methode standard semble avoir une crois-sance quadratique. Du moins, elle semble differer fortement des analyses decritespar V. Chvatal [6] qui proposait une croissance lineaire dependante de m voireune croissance semblable a m · log(n).

La figure 6.3 semble plutot decrire des fonctions quadratiques pour la me-thode standard et celle de CLP. Ce dernier dispose de moins de mesures a causede son long temps d’execution pour les problemes de grande taille.

Bien que la courbe de la methode du steepest edge semble presque lineaire,une approximation de type p ·mq semble obtenir des resultats semblables avecp = 1

30et q = 1.7, soit une fonction avec une croissance faiblement exponentielle.

83

Page 90: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Malgre le cout eleve en calculs de la methode steepest-edge, sa reduction dunombre d’iterations necessaires a resoudre un probleme justifie son utilisation.Rappelons que dans les implementations sequentielles les methodes de choix dela variable entrante sont tirees de cette methode. Cependant, la quantite decalculs qu’elle demande est reduite en utilisant des approximations. Tandis quedans notre cas, les calculs qu’elle necessite se parallelise tres bien, ce qui la rendtres interessante.

Densite variable

On va s’interesser ici au comportement des algorithmes du simplexe standardet du simplexe revise en fonction de la densite du probleme a traiter. Nous allonsmesurer le temps d’execution par iteration que mettent les implementations CLP(methode revise) et GPU (methode standard) pour resoudre des problemes detaille 500× 2000 dont la densite varie entre 1% et 99%.

Figure 6.4 – Mesures : temps pour une iteration (densite variable, taille fixe)

On peut constater dans la figure 6.4 que l’implementation sur GPU necessiteun temps quasi constant en fonction de la densite. Tandis que les performancesde CLP sont fortement influencees par la densite du probleme. Ces dernieressont bonnes pour des densites en deca de 3%. Il est interessant de remarquerque le temps mis par CLP augmente de maniere rapide pour des densites pluspetites que 20% apres quoi la croissance diminue fortement.

84

Page 91: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

6.5 Analyse des resultats

6.5.1 Influence de la densite

D’apres les mesures obtenues, nous pouvons confirmer que l’algorithme dusimplexe revise offre des performances interessantes pour des problemes de tresfaibles densites. Cependant ces performances chutent rapidement des que la den-site croıt un peu. Cela s’explique premierement par l’utilisation de structure dedonnees ne memorisant que les coefficients non-nuls. La taille de cette structureest dependante de la densite. Lorsque celle-ci devient importante, la structuredevient trop lourde a gerer, ce qui diminue les performances.

Le second probleme est lie a la resolution des systemes d’equations. En effet,cette operation est facile lorsqu’une matrice possede peu de coefficients non-nuls. Neanmoins pour des matrices remplies de donnees, cette tache devientrapidement tres complexe.

En ce qui concerne le simplexe standard, le travail effectue est independantde la densite car la matrice est entierement recalculee a chaque iteration. Lesperformances de l’implementation de ce dernier sont donc constants face a unevariation de la densite.

Finalement, il demeure encore une observation interessante au sujet de l’evo-lution de la densite d’un probleme. En effet, selon le type de probleme et lastructure des equations, il est fort probable qu’au fil des iterations la densited’un probleme croisse de facon significative. Afin d’illustrer cette theorie nousavons mesure l’evolution de la densite de trois problemes lineaires du depotNetlib durant leur resolution par l’implementation sur GPU.

Figure 6.5 – Evolution de la densite au fil des iterations

La figure 6.5 confirme notre theorie. Il est cependant important de noter quela magnitude de la croissance est dependante du probleme. Theoriquement, ladensite pourrait meme decroıtre. Le cas le plus simple illustrant ceci serait un

85

Page 92: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

probleme dont chaque equation contiendrait la meme variable avec le meme co-efficient. Une simple soustraction de cette variable dans chacune des equationssuffirait a diminuer fortement la densite. Les implementations reputees du sim-plexe effectuent neanmoins une phase de pre-traitement [5] servant a detecter cegenre de cas afin de simplifier le probleme initial avant d’appliquer le simplexe.

Cette derniere observation joue un role important sur le comportement duCLP. Le temps d’execution par iteration de celui-ci n’est de ce fait pas constant.Il peut croıtre de facon importante au fil des iterations selon l’evolution de ladensite du probleme.

6.5.2 Comparaison du modele et des resultats

Nous allons desormais comparer les resultats obtenus a ceux derives du mo-dele defini au chapitre 5.

Premierement, nous allons verifier si le modele obtient des resultats prochesde ceux mesures. Pour ce faire, nous allons comparer les courbes obtenues lorsde la modelisation du temps pris par une iteration au temps reel mesure.

Afin de determiner quelle methode de modelisation s’approche le plus de noskernels, nous allons etudier les deux cas possibles de modelisation : celui parsommation des instructions arithmetiques aux instructions d’acces a la memoireet celui base sur la selection du maximum de ces deux types d’instructions.

Figure 6.6 – Comparaison du modele et des mesures (temps par iteration)

La figure 6.6 confirme que le modele semble bien correspondre a la realite,particulierement la simulation utilisant la somme des instructions. Neanmoinsil demeure certaines differences entre le modele et les mesures.

La premiere difference est l’allure de la courbe de la mesure reelle pourdes problemes de petites tailles. Cette mesure est obtenue par la division dutemps total et du nombre d’iterations. De ce fait, le temps d’initialisation Tinit

86

Page 93: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

est aussi divise par le nombre d’iterations qui est relativement faible pour despetits problemes. Ceci n’est bien entendu pas reproduit par le modele, ce quiexplique la difference entre les deux courbes.

La seconde difference se situe dans la croissance de la courbe. Rappelons quelors de la modelisation, nous avons fixe de facon arbitraire le ratio α de variablesnon-basiques eligibles pour entrer dans la base. Il est donc possible de modifiercelui-ci afin d’influencer la croissance de la courbe.

La derniere difference, sans compter les differents nombres negliges dansle modele, demeure dans la modelisation du nombre d’iterations necessaires aresoudre un probleme. Comme nous l’avons vu dans la section 6.4.4, la fonctionliee a la croissance du nombre d’iterations est plus semblable a k = q ·mp quel · log(n) ·m ou q, p, l sont des constantes a definir.

Nous allons essayer de faire correspondre le modele a la realite en faisantvarier ces differents parametres. Pour qu’ils soient tous bien representes par lemodele, nous allons comparer les mesures et la simulation du temps necessairepour resoudre un probleme avec 1 GPU ainsi qu’avec 4 GPUs.

Figure 6.7 – Fitting du modele aux mesures

Le resultat obtenu (figure 6.7) en appliquant notre modele avec q = 1

29,

p = 1.71 et α = 0.7 semble correspondre a l’implementation, tout aussi bien pour1 GPU que pour 4 GPUs. Le modele pour 4 GPUs semble toutefois un petit peuplus rapide que la realite. Cela est toutefois explicable etant donne que les bandespassantes des differentes memoires ont ete modelisees selon leur performance depointe. Il faut aussi prendre en compte que le temps de synchronisation entreles CPUs n’a pas ete ajoute.

Afin de confirmer ces observations, les coefficients de correlation entre chaquemesure et son modele respectif ont ete calcules. La totalite de ses coefficients

87

Page 94: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

se trouvent etre superieur a 0.999. Rappelons qu’un coefficient de correlationproche de 0 signifie que les variables (modele / mesure) sont lineairement inde-pendante et, inversement, qu’un coefficient de correlation proche de 1 signifieque les variables sont lineairement dependante.

6.5.3 Gain apporte par l’utilisation de GPUs

Au vu des resultats obtenus, il est clair que l’implementation du simplexestandard sur GPU offre de meilleures performances que des versions sequentiellesde l’algorithme du simplexe revise sur certain type de problemes. Cette categoriede problemes semblent etre definie en grande partie en fonction du nombre decoefficients non-nuls contenus dans un probleme. Ce nombre de coefficients estdependant de la densite et la taille du probleme, soit : d · m · n (ou d est ladensite).

Passe un certain seuil de coefficients non-nuls, notre implementation devientplus efficace. Par exemple, prenons le cas d’un probleme fourni par APM Tech-nologies. Ce probleme est de taille consequente (m = 2500 et n = 144000) maisdispose neanmoins d’une tres faible densite, d = 0.004. Malgre la faible densitedu probleme, notre implementation sur 4 GPUs est approximativement 12 foisplus rapide que CLP.

On pourrait se demander si d’autres GPUs amelioreraient encore ce resul-tat. D’apres le speedup theorique decrit a la section 5.5.4, les gains devraientencore croıtre suite a l’ajout d’autres GPUs. Afin de confirmer cela, nous al-lons nous interesser au speedup reel obtenu en comparant les mesures de notreimplementation sur un GPU a celle sur plusieurs GPUs.

Figure 6.8 – Speedup reel pour differentes tailles de problemes

En comparant la figure 6.8 a la figure 5.3, on peut constater que notre modele

88

Page 95: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

est optimiste, surtout pour les problemes de petite taille. Pour les problemes demoyenne et grande tailles, le speedup reel semble correspondre reltaivement biena celui modelise. Ceci laisse presager que notre implementation apporterait desgains encore plus importants si d’autres GPUs etaient disponibles jusqu’a raisond’environ 10 a 20 GPUs pour des problemes de grande taille.

89

Page 96: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Chapitre 7

Conclusion

7.1 Resume du travail realise

L’objectif de ce travail etait d’etudier et d’implementer l’algorithme du sim-plexe sur GPGPU (General-Purpose Computing on Graphics Processing Units).Cet algorithme dispose deja de nombreuses implementations sequentielles. Ce-pendant, la majorite de ces dernieres offrent uniquement de bonnes performancespour la resolution de problemes de petite a moyenne tailles dont la densite estfaible. C’est pour cela que nous nous sommes interesses a paralleliser cet algo-rithme a l’aide de GPGPU.

Nous avons debute par l’etude des deux elements cles de ce travail. Le premierest l’algorithme du simplexe. La methode standard ainsi que la methode reviseont ete decrites et illustrees a l’aide d’exemples. Cet algorithme a ete decomposeen trois etapes principales, soit : la recherche de la variable entrante, suivie decelle de la variable sortante et finalement de la mise a jour du probleme.

Nous nous sommes ensuite interesses au second element, les GPGPU, etplus particulierement a l’architecture CUDA (Compute Unified Device Archi-tecture), proposee par NVIDIA. Cette architecture de type SIMT (Simple In-sutrction Multiple Threads) a ete decrite de telle maniere a mettre en evidenceses deux caracteristiques principales : ses differents niveaux de memoire et ladecomposition du travail en taches. Ceci nous a permis d’aborder les principesde programmation cruciaux sur GPUs.

A partir de la, nous avons compare les deux methodes du simplexe. Ceci afinde definir laquelle serait la plus adaptee pour une implementation sur GPUs.Nous avons choisi la methode du simplexe standard car cette derniere semblaitmieux profiter d’une parallelisation sur plusieurs GPUs. Avant de se lancer danssa mise en place, les performances de CUDA sur les operations principales dusimplexe ont ete comparees a leur equivalent CPU. Les operations de recherchede variables semblent offrir peu de gains alors que la mise a jour de la matricegarantit des gains importants.

Ces gains etant encourageants, l’algorithme du simplexe standard a ete paral-lelise sur un GPU. La structure de memoire mise en place, ainsi que l’algorithmeutilise ont ete decrits. La premiere version obtenue n’etait pas aussi robuste queles logiciels existants. Afin de corriger ce probleme, elle a ete amelioree par desmethodes de choix de variables trouvees dans la litterature scientifique. A par-

90

Page 97: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

tir de cette version, nous avons etudie les possibilites de partage des donneeset du travail, dans l’optique d’une parallelisation multi-GPU. La decoupe ver-ticale du probleme a ete choisie parce qu’elle necessite peu de communicationssupplementaires et qu’elle offre de bonnes performances pour un nombre limitede GPUs. L’algorithme et les particularites necessaires a sa mise en place ontensuite ete examines.

Un modele de performance a ete etabli a partir de ces deux versions del’algorithme : celle sur un GPU et celle sur plusieurs GPUs. Pour cela, il a etenecessaire de decortiquer et d’estimer le fonctionnement d’une application GPU.Le modele obtenu nous a permis d’estimer le temps necessaire pour resoudre uneiteration ou un probleme entier et par la suite le comportement de nos paralleli-sations face a une croissance de la taille des problemes. Nous nous sommes aussiinteresses a l’impact qu’aurait l’ajout d’autres unites de calcul en etablissant lespeedup theorique. Les resultats obtenus a ces differentes etapes promettent desgains interessants en performance suite a l’ajout de GPUs.

Les performances reelles des implementations 1 ont ete finalement analysees.Dans un premier temps, il nous a fallu choisir une version de reference du sim-plexe afin de comparer nos resultats. Parmi les implementations sequentiellesexistantes, nous avons choisi CLP parce qu’il fait partie d’un vaste projet opensource de logiciels de recherche operationnelle, COIN-OR. De plus, ses perfor-mances et sa robustesse sont proches des versions commerciales.

La robustesse de nos implementations a ete controlee, avec succes, sur l’en-semble des problemes lineaires du depot Netlib [4] ainsi que sur des problemesreels lie a l’aviation (conception d’horaire d’equipage et affectation d’avionsaux routes) fournis par la societe APM Technologies [2]. Cet ensemble de don-nees est generalement utilise comme benchmark pour ce type de logiciel. Nousavons alors mesure les performances de CLP ainsi que celles de nos versions.Les resultats obtenus pour nos versions ont permis de confirmer le modele eta-bli precedemment. Et surtout, la comparaison de ceux-ci aux resultats de CLPa mis en evidence des gains de performance tres important pour des problemesde moyenne a grande taille.

7.2 Discussion

7.2.1 CUDA

Au premier abord, la mise en place de programmes pour ce type d’archi-tecture peut sembler evidente. Il suffit en effet de decouper le calcul total ensous-operations. Ceci est generalement facile pour des calculs vectoriels ou ma-triciels. Cependant, il existe une grande difference entre un kernel fonctionnelet un kernel optimise.

L’architecture CUDA est relativement complexe comme nous l’avons vu du-rant son etude. Et de ce fait, il n’est pas aise de tirer profit au mieux de sesperformances de pointes. Les differentes optimisations possibles dependent dela taille des problemes a traiter, de l’organisation des acces memoire et de lacollaboration entre les taches. Par exemple, nous avons vu dans la section 4.5.3une strategie afin d’atteindre plus rapidement les performances de pics.

1. Les implementations sont disponibles sur le site du groupe SPC du departement d’in-formatique de l’Universite de Geneve [11].

91

Page 98: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Cette complexite s’est une fois de plus manifestee lors de la modelisation del’algorithme (voir section 5.2). Durant cette modelisation, nous avons du estimerles differents mecanismes mis en place par l’ordonnanceur dans le but de cacherla latence des acces memoire.

Les kernels necessitent donc une attention particuliere afin d’obtenir une ap-plication optimisee. Pour une meme operation, il pourrait meme etre imaginablede disposer de plusieurs kernels optimises pour des tailles ou configurations deproblemes specifiques.

7.2.2 Simplexe

L’algorithme du simplexe tel que decrit par V. Chvatal [6] est relativementsimple a mettre en place. La version obtenue par l’application de cette descrip-tion n’est cependant pas tres performante ni robuste. Les problemes de per-formances sont lies a des choix de variables faciles a mettre en place, mais neprenant pas en compte tous les criteres impliques, tandis que ceux de stabilitessont lies aux problemes d’imprecisions numeriques. En effet, ces erreurs sur lesoperations flottantes deteriorent le probleme d’iteration en iteration. De ce fait,il est necessaire de prendre des precautions afin de limiter leur influence sur lesmethodes de choix de variables. Dans le pire des cas, le choix d’un faux pivotamenerait a une version erronee de la matrice.

Il est donc important de rechercher et de mettre en place des heuristiquespermettant d’ameliorer les performances et la stabilite. C’est ce que nous avonsfait dans la section 4.5.2 en utilisant la methode du steepest edge afin de se-lectionner la variable entrante et expand afin de choisir la variable sortante.Ces deux methodes ont amene des ameliorations drastiques des performancesde l’algorithme. Celui-ci est passe d’un taux inferieur a 50% de reussite sur lebenchmark a un sans faute suite a l’ajout de expand ainsi que d’un mecanismede tolerance des imprecisions numeriques. La mesure du nombre total d’itera-tions necessaires pour resoudre un probleme (voir section 6.4.4) demontre bienl’avantage apporte par l’implementation du steepest edge ou d’une methode si-milaire.

Plusieurs approches sont possibles pour implementer differents elements del’algorithme. Par exemple, la memorisation de la base ou encore la techniquede la recherche d’une solution initiale peuvent etre mises en place de manieresimple en utilisant plus de memoire, ou au contraire de maniere plus complexeafin de reduire l’utilisation de cette derniere. La premiere option peut amenera une structure de donnees de grande taille (voir section 2.4.4 et 4.5.2), ce quiaurait un impact sur les performances, etant donne que l’operation de mise ajour de la matrice est dependante de cette taille. Tandis que la seconde optionnecessite la mise en place de methodes plus complexes et plus couteuses afin demaintenir une taille proche de celle du probleme initial. Ces gains se traduisentpar la possibilite de traiter des problemes plus grands et plus rapidement, carla mise a jour de la matrice demande beaucoup moins de travail.

7.2.3 Choix

Nous allons discuter ici des differents choix effectues au cours de l’implemen-tation.

92

Page 99: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

La premiere decision a ete de selectionner l’algorithme du simplexe standardplutot que sa version revisee. Les comportements des differentes implementa-tions ont confirme ce choix. En effet, l’analyse des mesures a la section 6.4.4demontre que le simplexe revise subit de lourdes pertes en performance des quele probleme devient de taille trop consequente, ou que sa densite depasse uncertain seuil. Alors que notre implementation du simplexe standard n’est pasdependant de la densite du probleme et que sa reaction face a une croissance dela taille du probleme semble plus douce. Nos resultats compares a ceux obtenuspar J. Bieling et al. [10] lors de leur implementation du simplexe revise sur GPUsemblent competitifs pour des problemes de taille moyenne. Cependant, il estdifficile d’affirmer ces observations. En effet, leur implementation est limitee aun GPU et donc la taille des problemes qu’ils peuvent traiter est limitee par lataille de sa memoire.

Nous avons ensuite choisi d’utiliser la decoupe du probleme en bandes verti-cales afin de partager le calcul sur plusieurs GPUs. Cette decision a ete faite enprenant en compte le nombre de GPUs disponibles dans la majorite des clustersGPGPU. Ces derniers ne disposent pas d’un grand nombre de GPUs, rarementplus de quelques dizaines. Les speedups theorique et pratique obtenus aux sec-tions 5.5.4 et 6.5.3 demontrent que pour des problemes de tailles moyenne etgrande, l’ajout d’unites de calcul supplementaires apporte des gains proches dela valeur optimale.

Il est neanmoins interessant de soulever que dans le cadre d’un cluster com-pose d’un nombre important de GPUs, il serait plus interessant d’utiliser ladecoupe du probleme en tuiles. De plus, l’utilisation de MPI offrirait des gainssupplementaires. En effet, l’implementation faite avec POSIX n’effectue pas dereduction au niveau des echanges inter-CPUs. Nous avons donc une complexitede l’ordre O(x ·NGPU ) ou x est la taille du message. Alors que l’utilisation deMPI diminuerait cela a O(x · log2(NGPU )). Ceci n’est pas derangeant pour unnombre faible de GPUs, mais pourrait le devenir dans le cas oppose.

7.2.4 Resultats et modele de performance

Le modele de performance etabli dans le chapitre 5 a ete confronte auxmesures reelles dans la section 6.5.2. La courbe issue du modele a ete ajusteede telle sorte a correspondre aux resultats obtenus lors de l’utilisation de 1 a4 GPUs avec succes. Le modele de performance est donc fidele aux mesuresreelles. Ce qui nous permet d’anticiper theoriquement des modifications d’ordremateriel liees aux performances des GPUs par exemple.

La comparaison des deux methodes du simplexe nous a amene a analyser demaniere approfondie l’influence de la densite dans la section 6.4.4. La methoderevisee s’est montree particulierement sensible a cette derniere. Tandis que notreimplementation est restee constante face aux variations de la densite.

De plus, nous avons determine dans la section 6.5.1 qu’il y a de fortes pro-babilites pour que la densite d’un probleme croisse durant sa resolution. Cesdernieres observations liees aux mesures obtenues a la section 6.4.4, nous per-mettent de determiner que notre implementation est beaucoup plus efficientedans le cas ou le nombre de coefficients non-nuls du probleme depasse un cer-tain seuil. Ce seuil est donc dependant de la taille du probleme et de la densite,soit de d · m · n. Par exemple, pour m = 500 et n = 2500 le seuil de densitesemble etre fixe a environ d = 0.03.

93

Page 100: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

7.3 Perspectives

La technologie des GPGPU est assez recente. Nous pouvons donc nous at-tendre a diverses ameliorations d’ordre logiciel ou materielle durant les annees avenir. Les librairies evoluent constamment. Soit elles offrent de nouvelles fonc-tionnalites, soit elles ameliorent les performances de celles qui existent deja. Lesoutils de developpement pourraient beneficier d’ameliorations afin de faciliterle debug et le profiling de kernels. Du point de vue materiel, a l’heure ou cememoire est ecrit, une nouvelle famille de GPUs a ete mise sur le marche parNVIDIA. Cette famille, fermi, dispose d’une structure differente au niveau desstreaming multiprocessors dans le but d’offrir de meilleurs performances pour lesnombres flottants en double precision. Les performances de pics sont annoncesa 500GFLOPS pour les nombres en double precision, contre 80GFLOPS pourles GPUs utilises lors de nos mesures. Cette famille de GPUs dispose de cachessur la memoire globale afin de diminuer la latence des acces a celle-ci.

Notre implementation offre de tres bonnes performances pour une certainecategorie de problemes. Neanmoins, il pourrait etre interessant de paralleliserl’algorithme du simplexe revise sur un GPU afin d’offrir aussi de meilleuresperformances pour les problemes de petite a moyenne taille. Ce travail a dejaete en partie fait par J. Bieling et al. [10], cependant leur implementation n’apas ete faite a l’aide de CUDA et sa robustesse n’a, a priori, pas ete testee.Prenons par exemple la structure typique des problemes que doivent resoudreAPM Technologies. Ces problemes contiennent generalement un nombre tresfaible d’equations pour un nombre consequent de variables, par exemplem = 150et n = 50000. Ils ne sont donc pas tres grands et generalement leur densite estinferieure a 1%. Ces problemes pourraient donc beneficier de l’algorithme dusimplexe revise sur GPU.

Finalement, il existe une methode autre que le simplexe pour resoudre lesproblemes lineaires, et qui a beaucoup evoluee durant ces dernieres annees. Lamethode du point interieur [18] consiste, comme son nom l’indique, a parcourirle polytope lie au probleme, non pas par ses bords, mais par son corps. Cettemethode est reputee pour obtenir de bons resultats sur des problemes de grandetaille ou contenant de nombreux cycles. Elle necessite un nombre important decalculs matriciels. Il pourrait donc etre interessant d’etudier une parallelisationde cette derniere sur GPU.

94

Page 101: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

Bibliographie

[1] NVIDIA CUDA Compute Unified Device Architecture : ProgrammingGuide, 2008. Version 2.0.

[2] APM technologies sa. http ://www.apmtechnologies.com/, 2010.

[3] MPS file format. http ://lpsolve.sourceforge.net/5.5/mps-format.htm,2010.

[4] The netlib repository. http ://www.netlib.org, 2010.

[5] G. Mitra A.L. Brearley and H.P. Williams. Analysis of mathematical pro-gramming problems prior to applying the simplex algorithm. In Mathema-tical Programming 8 (1975) 54-83, volume 8, pages 54–83. North-HollandPublishing Company, 1975.

[6] Vasek Chvatal. Linear Programming. W.H. Freeman, 1983.

[7] Kishore Kothapalli et al. A performance prediction model for the CUDAGPGPU platform. Technical report, International Institute of InformationTechnology, Hyderabad, 2009.

[8] J. A. J. Hall. Towards a practical parallelisation of the simplex method,2007.

[9] Frederick S Hillier and Gerald J. Lierberman. Introduction to OperationsResearch. 9 edition, 2010.

[10] Peter Martini Jakob Bieling, Patrick Peschlow. An efficient GPU imple-mentation of the revised simplex method. In IEEE Xplore.

[11] X. Meyer. Code source : implementation du simplexe standard sur GPUs.http ://spc.unige.ch/open source, 2011.

[12] Ping-Qi Pan. A largest-distance pivot rule for the simplex algorithm. Eu-ropean Journal for Operational Research, 187 :393–402, 2008.

[13] Michael A. Saunders Philip E. Gill, Walter Murray and Margaret H. Wright.A pratical anti-cycling procedure for linearly constrained optimization. Ma-thematical Programming, 45 :437–474, 1989.

[14] Wei Li Pingqi Pan and Jun Cao. Partial pricing rule simplex methodwith deficient basis. NUMERICAL MATHEMATICS, 15 :22–30, 2006. AJournal of Chinese Universities.

[15] Artur Swietanowski. A new steepest edge approximation for the simplexmethod for linear programming. Computational Optimization and Appli-cations, 10 :271–281, 1998.

[16] Michael E. Thomadakis and Jyh-Char Liu. An efficient steepest-edge sim-plex algorithm for SIMD computers, 1996.

95

Page 102: ´Etude et implémentation de l'algorithme du simplexe standard sur ...

[17] Vasily Volkov. Better performance at lower occupancy, 2010.

[18] Stephen J. Wright. Primal-dual interior-point methods. SIAM, 1998.

96