optimisation

optimisation - C - Programmation

Marsh Posté le 13-04-2015 à 08:30:38    

Bonjour,
 
J'ai un petit souci, je ne sais pas comment optimiser cette fonction en C :
 
void  
baseline ( int n , double a [ n ] , double b [ n ] , double c [ n ])
{
       int i , j ;
       for ( j = 0; j < n ; j ++)
       {
                 for ( i = 0; i < n ; i ++)
                 {
                           c [ i ] += b [ n - 1 - i ];
                           if ( i < j )
                           {
                                     c [ i ] += a [ j ];
                           }
                 }
       }
}

 
En fait, je me suis renseigné, en gros il faut remonter le "if" parce qu'il coûte cher, voir pour une optimisation idéale l'éliminer (le code doit toujours rester équivalent à celui de début).
 
 
Merci pour votre aide.
 
Bonne journée.


Message édité par benreghaimehdi le 13-04-2015 à 12:37:32
Reply

Marsh Posté le 13-04-2015 à 08:30:38   

Reply

Marsh Posté le 13-04-2015 à 09:21:07    

Déjà, ta fonction, elle est censée faire quoi ? Parce qu'elle a pas un poil de commentaire, les noms des variables ne sont pas explicites sur leur contenu, et t'utilises même pas la balise code :/
 
Le if dépendant de la 2ème boucle, je vois pas comment le sortir.
 
Si tu dois optimiser ce code, je commencerais par donner des noms de variables compréhensibles et j'ajouterais du commentaire. Ca n’accéléra pas le temps d'exécution, mais ça accéléra celui de sa compréhension :o


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 13-04-2015 à 09:40:27    

Remplace a l'intérieur du deuxième for par:
 

Code :
  1. if ( i < j ) {
  2.   c[i] += a[j] + b[n - 1 - i]
  3. } else {
  4.   c[i] += b[n - 1 - i]
  5. }


 
T'aura déjà un léger gain d'opti avec le += qui sera pas affecté deux fois dans le cas i < j.
 
 
Comme dit rufo sans plus d'info tu pourras pas plus optimiser sans autre information...

Reply

Marsh Posté le 13-04-2015 à 09:53:15    

Merci pour vos reponses.
 
En fait, dans un compte rendu, le prof nous demande seulement d'étudier et d'optimiser la fonction, et de justifier chaque modification du code (le code doit à la fin d'optimisation être le même que le code principal).
 
Il nous demande en fait d'optimiser la fonction, et de vérifier avec  gcc -O2 si le temps d’exécution s'améliore ou pas pour chaque optimisation de la fonction.  
 
 
Cordialement.  

Reply

Marsh Posté le 13-04-2015 à 10:41:58    

Ben, tu pourrais mettre une partie du code en ASM :whistle:


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 13-04-2015 à 10:48:39    

Oui, c'est une solution ( code assembleur ), mais sur le compte rendu on me demande sans assembleur !

Reply

Marsh Posté le 13-04-2015 à 12:36:12    

Bonjour,
 
Je trouve des difficultés sur un travail "Optimisation en C".
Voila ce qu'il faut faire en gros :  
 
Il ya un code à optimiser, que nous appellerons "noyau".  
Il faut étuider les performances en L1, en L2, en L3 et en RAM.
 
Partie I
========
1) Ecrivez un driver permettant de mesurer la performance du noyau
2) Compilez le noyau avec gcc -O2
3) Mesurez la performance du noyau
4) Recommencez avec gcc -O3, gcc -O3 -march=native, icc -O2, icc -O3 et  
icc -O3 -xHost.
 
Partie II
=========
Pour cette partie,vous compilerez avec gcc -O2.
1) Mesurez la performance du noyau
2) Identifiez le goulet d'étranglement (ce qui limite les performances)
3) Proposez une optimisation (au niveau source)
4) Recommencez (rebouclez à l'étape 1) tant que vous arrivez à améliorer  
les performances. Vous pouvez soit repartir du noyau non optimisé, soit  
d'un noyau précédemment optimisé.
 
Partie III
==========
1) Utilisez des directives OpenMP pour paralléliser votre noyau.
2) Utilisez des intrinsics pour écrire/optimiser le code, voir modifiez directement l'assembleur.
 
 
 
J'ai réussi la partie I, mais je bloque sur la partie II et III (Optimisation du noyau)
 
voila le noyau :

Code :
  1. void kernel (int n, double a[n], double b[n], double c[n])
  2. {
  3. int i, j;
  4. for (j=0;j<n;j++)
  5. {
  6.  for(i=0;i<n;i++)
  7.  {
  8.   c[i]+=b[n-1-i];
  9.   if (i<j)
  10.   {
  11.    c[i]+=a[j];
  12.   }
  13.  }
  14. }
  15. }


 
Merci pour vos aides.
 
 
Bien cordialement.

Reply

Marsh Posté le 13-04-2015 à 14:04:10    

Les sujets suivant ont été fusionnés à ce sujet par Gilou

  • optimisation fonction "c"


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 13-04-2015 à 14:41:21    

"Ecrivez un driver permettant de mesurer la performance du noyau " :ouch:  
 
Purée, c'est déjà du sacré niveau. C'est en quel cours qu'on te demande ça et dans quelle école ?


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 13-04-2015 à 14:49:51    

Salut,

 

Il faut chercher au niveau de la complexité algorithmique de ta fonction :
Ici la complexité de ta fonction et de N² et le plus simple pour l'optimiser et de passer ça complexité à Log(N).

 

Pour cela il faut supprimer/modifier le second "for" car c'est celui-ci qui pose problème dans la complexité.

 

Je te laisse chercher un peux avant de donné une réponse toute faire.

 

Bon courage


Message édité par OrcusZ le 13-04-2015 à 14:58:59

---------------
Made you your own sentence without believing that of the others...
Reply

Marsh Posté le 13-04-2015 à 14:49:51   

Reply

Marsh Posté le 13-04-2015 à 15:04:56    

Re,
 
en fait j'ai fait ca :
 
1)  
dans un premier temps :

Code :
  1. for ( i = 0; i < n ; i++){
  2. for ( j = 0; j < n ; j++){


 
 
Cette fonction ajoute à chaque case de C son miroir dans b, n fois. Donc, déjà en une boucle je peux faire toute une partie des opérations :

Code :
  1. for (i = 0; i < n; ++i)
  2. c[ i ] += n * b[ n-1-i ];


 
 
Cela, nous donne le code suivant :

Code :
  1. for (i = 0; i < n ; i ++)
  2. {
  3. c [ i ] += n * b [ n - 1 - i ];
  4. for (j = i+1; j < n ; j ++)
  5. {
  6. c [ i ] += a [ j ];
  7. }
  8. }


 
 
Soit donc en boucle intérieure "pour  j  entre 0 et  n  et  j  supérieur à  i faire,
Donc " pour j entre i (exclus) et n ".
 

Code :
  1. for (i = 0; i < n ; i ++)
  2. {
  3. c [ i ] += n * b [ n - 1 - i ];
  4. for (j = i+1; j < n ; j ++)
  5. {
  6. c [ i ] += a [ j ];
  7. }
  8. }


 
 
Finalement, on tout du long on manipule le meme c[ i ], on peut passer par un registre temporaire :
 

Code :
  1. for ( i = 0; i < n ; i ++)
  2. {
  3. int c_temp = n * b [ n - 1 - i ];
  4. for ( j = i+1; j < n ; j ++)
  5. {
  6. c_temp += a [ j ];
  7. }
  8. c[i] += c_temp;
  9. }


 
 
mais je sais pas si c'est la meilleur optimisation.
 
Merci

Reply

Marsh Posté le 13-04-2015 à 15:48:33    

Salut,

 

C'est l'optimisation la plus simple en tout cas.
En cherchant rapidement je suis tomber sur quasiment la même chose.

 

Tu ai bien en complexité log(N) car tu ne parcours plus deux fois ton tableau.

 

Par contre je comprends pas ton :

Code :
  1. int c_temp = n * b [ n - 1 - i ];
 

Tu n'a pas besoin de changer ce calcul ( il est imposer ).

 

Tu peux encore optimiser ta boucle en faisant du récursif mais c'est toujours un petit peu risquer ( risque de passer en overflow quelques part dans ton programme ).

 

PS : Cherche du coté des algorithmes de recherche ou de trie. Cela pourras te donner des pistes.


Message édité par OrcusZ le 13-04-2015 à 15:50:07

---------------
Made you your own sentence without believing that of the others...
Reply

Marsh Posté le 13-04-2015 à 16:27:14    

Re,
 
Franchement je ne peux pas aller plus loin que cette optimisation, par contre, m'est avis que l'ajout du a peut-être fait autrement, avec une seule boucle! En parcourant le tableau en sens inverse!  
 
J'explique  
 
j=0   rien  
j=1  
c[0]+=a[1]  
j=2  
c[0]+=a[2]  
c[1]+=a[2]  
j=3  
c[0]+=a[3]  
c[1]+=a[3]  
c[2]+=a[3]  
etc.  
 
En gros, je pense qu'il faut partir de la fin  
et puis tout mettre dans une seule boucle.
   

Code :
  1. a_cumul=j=0; 
  2. for (i=n-1;i>0;i--) { 
  3.  a_cumul+=a[i]; 
  4.  c[i]=a_cumul+n*b[j++]; 
  5. c[0]=n*b[j];

 
 
Là j'ai une seule boucle, de quoi laisser le compilo faire sa sauce pour le prefetch.
 
Quelque vous pensez ?
 
Mercii

Reply

Marsh Posté le 13-04-2015 à 16:38:07    

ça à l'air cohérent.
 
Si lorsque tu trace tu obtient toujours le même résultat ( entre ton algo et celui de base ) tu es passé à une complexité de N.
 
Donc tu ne pourra pas faire mieux.
 
Bravo :)


---------------
Made you your own sentence without believing that of the others...
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed