2008-11-29 14 views
3

Pour l'un des projets que je suis en train de faire, je dois examiner les performances (entre autres) des différents langages de programmation concurrent enabled.Problèmes de référence pour tester la concurence

En ce moment j'étudie en comparant stackless python et C++ PThreads, ainsi l'accent est sur ces deux langues, mais d'autres langues seront probablement examinées plus tard. Bien sûr, la comparaison doit être aussi représentatif et précis que possible, donc ma première pensée a été de commencer à chercher problèmes de benchmark concurrents/multi-threads, hélas je ne pouvais pas trouver décent ou standard, tests/problèmes/repères.

Donc ma question est la suivante: Avez-vous une suggestion pour un bon problème, facile ou rapide de tester les performances du langage de programmation (et d'exposer ses points forts et faibles dans le processus)?

Répondre

4

Vous devriez certainement tester le matériel et les compilateurs plutôt qu'un langage pour les performances de simultanéité?

Je considérerais un langage du point de vue de la facilité et de la productivité en termes de concurrence et de ce qu'il «isole» le programmeur des erreurs de verrouillage. EDIT: D'après mon expérience en tant que chercheur en conception d'algorithmes parallèles, je pense que vous trouverez dans la plupart des cas que les performances simultanées dépendront en grande partie de la façon dont un algorithme est parallélisé et de la façon dont il cible le matériel sous-jacent.

De plus, les benchmarks sont notoirement inégaux; c'est encore plus vrai dans un environnement parallèle. Par exemple, un benchmark qui «croque» de très grandes matrices serait adapté à un processeur de pipeline vectoriel, tandis qu'un tri parallèle pourrait être mieux adapté à des processeurs multi-cœurs plus généraux.

Ceux-ci pourraient être utiles:

Parallel Benchmarks

NAS Parallel Benchmarks

+0

Vous avez éveillé mon intérêt! Vous dites que vous avez de l'expérience en tant que chercheur en algorithmes parallèles. Vous pouvez sûrement me donner des problèmes ou des algorithmes intéressants sur lesquels vous avez travaillé? Et oui vous avez raison, les benchmarks ont très peu de sens en eux-mêmes, c'est pourquoi je ne vais pas passer beaucoup de temps dessus – sven

+0

Ça fait longtemps! J'ai essentiellement pris un algorithme séquentiel efficace, et mesuré ses performances d'abord séquentiellement et ensuite contre un non croissant. des CPU. –

+0

(comme dans la version parallélisée ...) –

0

Surely you should be testing hardware and compilers rather than a language for concurrency performance?

Non, le matériel et les compilateurs ne sont pas pertinents pour mes fins de test. Je cherche juste quelques bons problèmes qui peuvent tester comment le code, écrit dans une langue, peut rivaliser avec le code d'une autre langue. Je teste vraiment les constructions disponibles dans les langues spécifiques pour faire la programmation simultanée. Et l'un des critères est la performance (mesurée dans le temps).

Certains des autres critères de test que je suis à la recherche sont:

  • comment facile est-il d'écrire du code correct; car comme nous le savons tous, la programmation concurrente est plus difficile que l'écriture de programmes à un seul thread
  • quelle est la technique utilisée pour la programmation simultanée: événementielle, basée sur l'acteur, analyse des messages, ...
  • combien de code doit être écrit par le programmeur lui-même et ce qui est fait automatiquement pour lui: cela peut aussi être testé avec les problèmes de benchmark donnés
  • quel est le niveau d'abstraction code machine

donc en fait, je ne suis pas à la recherche de performance le seul et le meilleur paramètre (qui en effet me faire parvenir le matériel et les compilateurs au lieu de la langue elle-même), je suis en fait à la recherche du point de vue des programmeurs pour vérifier quelle langue est la mieux adaptée pour quel genre de problèmes, ce sont ses faiblesses et ses forces, etc. ...

Sachez qu'il ne s'agit que d'un petit projet et que les tests doivent donc rester également de petite taille. (des tests rigoureux de tout ne sont donc pas faisables)

+0

Si c'est un petit projet, sérieusement, pourquoi s'embêter? Choisissez simplement une langue qui offre un bon support pour la parallélisation. –

+0

Parce que c'est l'idée de base du projet. C'est juste un petit projet de recherche, rien de plus n'est attendu par la suite (c'est-à-dire en utilisant la langue). De plus, il ne s'agit pas de choisir la meilleure langue, mais de montrer que chaque langue a sa place. Chaque langue a ses points forts et faibles ... – sven

1

Eh bien, il y a quelques classiques, mais différents tests mettent l'accent sur différentes caractéristiques. Certains systèmes distribués peuvent être plus robustes, avoir un passage des messages plus efficace, etc. Un surcoût de message plus élevé peut nuire à l'évolutivité, car la manière normale d'augmenter le nombre de machines consiste à envoyer un plus grand nombre de petits messages. Certains problèmes classiques que vous pouvez essayer sont un crible distribué d'Ératosthène ou un calculateur de séquence de fibonacci mal mis en œuvre (à savoir pour calculer le 8ème nombre dans la série, le spin d'une machine pour la 7ème, et un autre pour la 6ème). Pratiquement tout algorithme de division et de conquête peut être fait simultanément. Vous pouvez également faire une mise en œuvre simultanée du jeu de la vie ou du transfert de chaleur de Conway. Notez que tous ces algorithmes ont des focus différents et donc vous n'obtiendrez probablement pas un système distribué en faisant le meilleur dans chacun d'eux. Je dirais que le plus facile à mettre en œuvre rapidement est le calculateur fibonacci mal implémenté, bien qu'il insiste trop sur la création de threads et trop peu sur la communication entre ces threads.

+0

Bien que facile à mettre en œuvre, je ne suis pas sûr qu'un "calculateur de fibonacci mal mis en œuvre" est un test particulièrement bon; c'est un peu trop artificiel. –

+0

C'est vrai, c'est artificiel. Mais c'était encore un algorithme de démonstration assez populaire quand je faisais des recherches sur l'informatique distribuée. Si vous voulez un algorithme distribué qui met l'accent sur les messages et ne met aucun accent sur quoi que ce soit d'autre, il y a toujours bittorrent. – Brian

0

J'ai décidé d'utiliser le Mandelbrot set (le escape time algorithm pour être plus précis) afin d'évaluer les différentes langues.
Cela me va assez bien car l'algorithme original peut facilement être implémenté et la création de la variante multi-thread à partir de ce n'est pas beaucoup de travail.

ci-dessous est le code que j'ai actuellement. Il s'agit toujours d'une variante à un seul thread, mais je la mettrai à jour dès que je serai satisfait du résultat.

#include <cstdlib> //for atoi 
#include <iostream> 
#include <iomanip> //for setw and setfill 
#include <vector> 


int DoThread(const double x, const double y, int maxiter) { 
    double curX,curY,xSquare,ySquare; 
    int i; 

    curX = x + x*x - y*y; 
    curY = y + x*y + x*y; 
    ySquare = curY*curY; 
    xSquare = curX*curX; 

    for (i=0; i<maxiter && ySquare + xSquare < 4;i++) { 
     ySquare = curY*curY; 
     xSquare = curX*curX; 
     curY = y + curX*curY + curX*curY; 
     curX = x - ySquare + xSquare; 
    } 
    return i; 
} 

void SingleThreaded(int horizPixels, int vertPixels, int maxiter, std::vector<std::vector<int> >& result) { 
    for(int x = horizPixels; x > 0; x--) { 
     for(int y = vertPixels; y > 0; y--) { 
      //3.0 -> so we always have -1.5 -> 1.5 as the window; (x - (horizPixels/2) will go from -horizPixels/2 to +horizPixels/2 
      result[x-1][y-1] = DoThread((3.0/horizPixels) * (x - (horizPixels/2)),(3.0/vertPixels) * (y - (vertPixels/2)),maxiter); 
     } 
    } 
} 

int main(int argc, char* argv[]) { 
    //first arg = length along horizontal axis 
    int horizPixels = atoi(argv[1]); 

    //second arg = length along vertical axis 
    int vertPixels = atoi(argv[2]); 

    //third arg = iterations 
    int maxiter = atoi(argv[3]); 

    //fourth arg = threads 
    int threadCount = atoi(argv[4]); 

    std::vector<std::vector<int> > result(horizPixels, std::vector<int>(vertPixels,0)); //create and init 2-dimensional vector 
    SingleThreaded(horizPixels, vertPixels, maxiter, result); 

    //TODO: remove these lines 
    for(int y = 0; y < vertPixels; y++) { 
     for(int x = 0; x < horizPixels; x++) { 
      std::cout << std::setw(2) << std::setfill('0') << std::hex << result[x][y] << " "; 
     } 
     std::cout << std::endl; 
    } 
} 

Je l'ai testé avec gcc sous Linux, mais je suis sûr que cela fonctionne sous d'autres compilateurs/Systèmes d'exploitation ainsi. Pour obtenir de vous travailler devez saisir des arguments de ligne de commande comme ceci:

Mandelbrot 106 500 255 1

le premier argument est la largeur (axe x)
le second argument est la hauteur (axe des y)
le troisième paramètre est le nombre d'itérations maximales (le nombre de couleurs)
les derniers modules est le nombre de fils (mais que l'on est actuellement non utilisé)

sur ma résolution, l'exemple ci-dessus me donne une belle représentation ASCII-art d'un ensemble de Mandelbrot.Mais l'essayer pour vous-même avec différents arguments (le premier sera le plus important, car ce sera la largeur)

0

Ci-dessous vous trouverez le code que je piraté ensemble pour tester les multithread performances de pthreads. Je n'ai pas nettoyé et aucune optimisation n'a été faite; donc le code est un peu brut.

le code pour enregistrer le Mandelbrot calculé défini comme un bitmap est pas à moi, vous pouvez le trouver here

#include <cstdlib> //for atoi 
#include <iostream> 
#include <iomanip> //for setw and setfill 
#include <vector> 

#include "bitmap_Image.h" //for saving the mandelbrot as a bmp 

#include <pthread.h> 

pthread_mutex_t mutexCounter; 
int sharedCounter(0); 
int percent(0); 

int horizPixels(0); 
int vertPixels(0); 
int maxiter(0); 

//doesn't need to be locked 
std::vector<std::vector<int> > result; //create 2 dimensional vector 

void *DoThread(void *null) { 
    double curX,curY,xSquare,ySquare,x,y; 
    int i, intx, inty, counter; 
    counter = 0; 

    do { 
     counter++; 
     pthread_mutex_lock (&mutexCounter); //lock 
      intx = int((sharedCounter/vertPixels) + 0.5); 
      inty = sharedCounter % vertPixels; 
      sharedCounter++; 
     pthread_mutex_unlock (&mutexCounter); //unlock 

     //exit thread when finished 
     if (intx >= horizPixels) { 
      std::cout << "exited thread - I did " << counter << " calculations" << std::endl; 
      pthread_exit((void*) 0); 
     } 

     //set x and y to the correct value now -> in the range like singlethread 
     x = (3.0/horizPixels) * (intx - (horizPixels/1.5)); 
     y = (3.0/vertPixels) * (inty - (vertPixels/2)); 

     curX = x + x*x - y*y; 
     curY = y + x*y + x*y; 
     ySquare = curY*curY; 
     xSquare = curX*curX; 

     for (i=0; i<maxiter && ySquare + xSquare < 4;i++){ 
      ySquare = curY*curY; 
      xSquare = curX*curX; 
      curY = y + curX*curY + curX*curY; 
      curX = x - ySquare + xSquare; 
     } 
     result[intx][inty] = i; 
    } while (true); 
} 

int DoSingleThread(const double x, const double y) { 
    double curX,curY,xSquare,ySquare; 
    int i; 

    curX = x + x*x - y*y; 
    curY = y + x*y + x*y; 
    ySquare = curY*curY; 
    xSquare = curX*curX; 

    for (i=0; i<maxiter && ySquare + xSquare < 4;i++){ 
     ySquare = curY*curY; 
     xSquare = curX*curX; 
     curY = y + curX*curY + curX*curY; 
     curX = x - ySquare + xSquare; 
    } 
    return i; 

} 

void SingleThreaded(std::vector<std::vector<int> >& result) { 
    for(int x = horizPixels - 1; x != -1; x--) { 
     for(int y = vertPixels - 1; y != -1; y--) { 
      //3.0 -> so we always have -1.5 -> 1.5 as the window; (x - (horizPixels/2) will go from -horizPixels/2 to +horizPixels/2 
      result[x][y] = DoSingleThread((3.0/horizPixels) * (x - (horizPixels/1.5)),(3.0/vertPixels) * (y - (vertPixels/2))); 
     } 
    } 
} 

void MultiThreaded(int threadCount, std::vector<std::vector<int> >& result) { 
    /* Initialize and set thread detached attribute */ 
    pthread_t thread[threadCount]; 
    pthread_attr_t attr; 
    pthread_attr_init(&attr); 
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 


    for (int i = 0; i < threadCount - 1; i++) { 
     pthread_create(&thread[i], &attr, DoThread, NULL); 
    } 
    std::cout << "all threads created" << std::endl; 

    for(int i = 0; i < threadCount - 1; i++) { 
     pthread_join(thread[i], NULL); 
    } 
    std::cout << "all threads joined" << std::endl; 
} 

int main(int argc, char* argv[]) { 
    //first arg = length along horizontal axis 
    horizPixels = atoi(argv[1]); 

    //second arg = length along vertical axis 
    vertPixels = atoi(argv[2]); 

    //third arg = iterations 
    maxiter = atoi(argv[3]); 

    //fourth arg = threads 
    int threadCount = atoi(argv[4]); 

    result = std::vector<std::vector<int> >(horizPixels, std::vector<int>(vertPixels,21)); // init 2-dimensional vector 
    if (threadCount <= 1) { 
     SingleThreaded(result); 
    } else { 
     MultiThreaded(threadCount, result); 
    } 


    //TODO: remove these lines 
    bitmapImage image(horizPixels, vertPixels); 
    for(int y = 0; y < vertPixels; y++) { 
     for(int x = 0; x < horizPixels; x++) { 
      image.setPixelRGB(x,y,16777216*result[x][y]/maxiter % 256, 65536*result[x][y]/maxiter % 256, 256*result[x][y]/maxiter % 256); 
      //std::cout << std::setw(2) << std::setfill('0') << std::hex << result[x][y] << " "; 
     } 
     std::cout << std::endl; 
    } 

    image.saveToBitmapFile("~/Desktop/test.bmp",32); 
} 

bons résultats peuvent être obtenus en utilisant le programme avec les arguments suivants:

mandelbrot 5120 3840 256 3

De cette façon, vous obtiendrez une image de 5 * 1024 de large; 5 * 768 de haut avec 256 couleurs (hélas, vous n'obtiendrez que 1 ou 2) et 3 threads (1 thread principal qui ne fonctionne pas sauf créer les threads de travail, et 2 threads de travail)