Domanda

Per uno dei progetti che sto facendo in questo momento, ho bisogno di guardare le performance (tra le altre cose) di diversi concorrenti abilitati linguaggi di programmazione.

Al momento sto cercando di confrontare python stackless e C ++ PThreads , quindi l'attenzione si concentra su queste due lingue, ma altre lingue verranno probabilmente testate in seguito. Ovviamente il confronto deve essere il più rappresentativo e preciso possibile, quindi il mio primo pensiero è stato quello di iniziare a cercare alcuni problemi di benchmark standard simultanei / multi-thread , purtroppo non ho potuto trovare test / problemi / benchmark decenti o standard.

Quindi la mia domanda è la seguente: Hai un suggerimento per un problema buono, facile o veloce per testare le prestazioni del linguaggio di programmazione (e per esporre i suoi punti forti e deboli nel processo )?

È stato utile?

Soluzione

Da quando il gioco dei benchmark è stato spostato su una macchina quad-core nel settembre 2008, molti programmi in diversi linguaggi di programmazione sono stati riscritti per sfruttare quad-core - ad esempio, i primi 10 programmi mandelbrot .

Altri suggerimenti

Sicuramente dovresti testare hardware e compilatori piuttosto che un linguaggio per le prestazioni della concorrenza?

Guarderei un linguaggio dal punto di vista di quanto sia facile e produttivo in termini di concorrenza e di quanto "isola" il programmatore dal commettere errori di blocco.

EDIT: dall'esperienza passata come ricercatore nella progettazione di algoritmi paralleli, penso che nella maggior parte dei casi riterrete che le prestazioni simultanee dipenderanno in gran parte dal modo in cui un algoritmo è parallelizzato e da come si rivolge all'hardware sottostante.

Inoltre, i benchmark sono notoriamente disuguali; questo è ancora più vero in un ambiente parallelo. Ad esempio, un benchmark che "sgretola" matrici molto grandi sarebbe adatto a un processore a pipeline vettoriale, mentre un ordinamento parallelo potrebbe essere più adatto a CPU multi core più generiche.

Questi potrebbero essere utili:

Benchmark paralleli

Benchmark paralleli NAS

Bene, ci sono alcuni classici, ma test diversi enfatizzano caratteristiche diverse. Alcuni sistemi distribuiti possono essere più robusti, avere un passaggio dei messaggi più efficiente, ecc. Un sovraccarico maggiore dei messaggi può compromettere la scalabilità, poiché il modo normale di scalare su più macchine è inviare un numero maggiore di piccoli messaggi. Alcuni problemi classici che puoi provare sono un setaccio di Eratostene distribuito o un calcolatore di sequenza fibonacci mal implementato (cioè per calcolare l'ottavo numero della serie, la rotazione di una macchina per il 7 e un'altra per il 6). Praticamente qualsiasi algoritmo di divisione e conquista può essere fatto contemporaneamente. Potresti anche fare un'implementazione simultanea del gioco della vita o del trasferimento di calore di Conway. Nota che tutti questi algoritmi hanno focus diversi e quindi probabilmente non otterrai un sistema distribuito che fa il meglio in tutti.

Direi che il più semplice da implementare rapidamente è il calcolatore fibonacci mal implementato, anche se pone troppa enfasi sulla creazione di thread e troppo poca sulla comunicazione tra quei thread.

  

Sicuramente dovresti testare l'hardware   e compilatori piuttosto che una lingua   per le prestazioni della concorrenza?

No, hardware e compilatori sono irrilevanti per i miei scopi di test. Sto solo cercando alcuni buoni problemi che possono verificare quanto bene il codice, scritto in una lingua, possa competere con il codice di un'altra lingua. Sto davvero testando i costrutti disponibili nelle lingue specifiche per eseguire la programmazione simultanea. E uno dei criteri è la prestazione (misurata nel tempo).

Alcuni degli altri criteri di test che sto cercando sono:

  • quanto facile è scrivere il codice corretto; perché, come tutti sappiamo, la programmazione concorrente è più difficile della scrittura di programmi a thread singolo
  • qual è la tecnica utilizzata per la programmazione concorrente: basata sugli eventi, basata sull'attore, analisi dei messaggi, ...
  • quanto codice deve essere scritto dal programmatore stesso e quanto viene fatto automaticamente per lui: questo può anche essere testato con i problemi di benchmark indicati
  • qual è il livello di astrazione e quante spese generali sono coinvolte quando tradotte in codice macchina

Quindi, in realtà, non sto cercando prestazioni come l'unico e il miglior parametro (che in effetti mi manderebbe all'hardware e ai compilatori anziché al linguaggio stesso), sto effettivamente cercando dal punto di vista dei programmatori per verificare quale linguaggio è più adatto per quale tipo di problemi, quali sono i suoi punti deboli e di forza e così via ...

Tenete presente che questo è solo un piccolo progetto e che quindi anche i test devono essere mantenuti piccoli. (test rigorosi di tutto non è quindi fattibile)

Ho deciso di utilizzare il Mandelbrot set (il algoritmo del tempo di fuga per essere più precisi) per confrontare le diverse lingue.
Mi si adatta abbastanza bene dato che l'algoritmo originale può essere facilmente implementato e creare la variante multi-thread da esso non è poi tanto lavoro.

di seguito è il codice che ho attualmente. È ancora una variante a thread singolo, ma la aggiornerò non appena sarò soddisfatto del risultato.

#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;
    }
}

L'ho provato con gcc sotto Linux, ma sono sicuro che funziona anche con altri compilatori / sistemi operativi. Per farlo funzionare devi inserire alcuni argomenti della riga di comando in questo modo:

  

mandelbrot 106 500 255 1

il primo argomento è la larghezza (asse x)
il secondo argomento è l'altezza (asse y)
il terzo argomento è il numero di iterazioni massime (il numero di colori)
l'ultimo è il numero di thread (ma quello attualmente non è utilizzato)

sulla mia risoluzione, l'esempio sopra mi dà una bella rappresentazione in arte ASCII di un set di Mandelbrot. Ma provalo tu stesso con diversi argomenti (il primo sarà il più importante, poiché sarà la larghezza)

Di seguito puoi trovare il codice che ho hackerato insieme per testare le prestazioni multi threaded di pthreads. Non l'ho ripulito e non sono state apportate ottimizzazioni; quindi il codice è un po ' grezzo .

il codice per salvare il set di mandelbrot calcolato come bitmap non è mio, lo puoi trovare qui

#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);
}

si possono ottenere buoni risultati usando il programma con i seguenti argomenti:

  

mandelbrot 5120 3840 256 3

in questo modo otterrai un'immagine larga 5 * 1024; 5 * 768 di altezza con 256 colori (purtroppo otterrai solo 1 o 2) e 3 thread (1 thread principale che non svolge alcuna attività tranne la creazione dei thread di lavoro e 2 thread di lavoro)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top