Контрольные задачи для тестирования параллелизма - PullRequest
4 голосов
/ 29 ноября 2008

Для одного из проектов, которые я делаю сейчас, мне нужно посмотреть на производительность (помимо прочего) различных одновременных включенных языков программирования.

В данный момент я пытаюсь сравнить Python без стеков и C ++ PThreads , поэтому основное внимание уделяется этим двум языкам, но другие языки, вероятно, будут протестированы позже. Конечно, сравнение должно быть настолько репрезентативным и точным, насколько это возможно, поэтому моей первой мыслью было начать искать какие-то стандартные проблемы параллельных / многопоточных тестов , увы я не смог найти ни одной достойный или стандартный, тесты / проблемы / тесты.

Итак, мой вопрос заключается в следующем: У вас есть предложение по хорошей, простой или быстрой задаче, чтобы проверить производительность языка программирования (и выявить его сильные и слабые стороны в процессе)

Ответы [ 6 ]

4 голосов
/ 29 ноября 2008

Конечно, вы должны тестировать аппаратное обеспечение и компиляторы, а не язык для производительности параллелизма?

Я бы посмотрел на язык с точки зрения того, насколько он прост и продуктивен с точки зрения параллелизма и насколько он «изолирует» программиста от ошибок блокировки.

РЕДАКТИРОВАТЬ: исходя из прошлого опыта исследователя, разрабатывающего параллельные алгоритмы, я думаю, вы обнаружите, что в большинстве случаев параллельная производительность будет в значительной степени зависеть от того, как распараллеливается алгоритм и как он нацелен на базовое оборудование.

Кроме того, показатели общеизвестно неравны; это тем более в параллельной среде. Например, эталонный тест, который "хрустит" очень большие матрицы, будет подходить для векторного конвейерного процессора, тогда как параллельная сортировка может быть лучше приспособлена для многоядерных процессоров более общего назначения.

Это может быть полезно:

Параллельные тесты

Параллельные тесты NAS

1 голос
/ 29 ноября 2008

Ну, классики немного, но разные тесты подчеркивают разные особенности. Некоторые распределенные системы могут быть более устойчивыми, иметь более эффективную передачу сообщений и т. Д. Более высокая нагрузка на сообщения может отрицательно сказаться на масштабируемости, поскольку обычный способ масштабирования до большего числа машин - отправка большего количества небольших сообщений. Некоторые классические проблемы, которые вы можете попробовать, - это распределенное сито Эратосфена или плохо реализованный калькулятор последовательности Фибоначчи (то есть для вычисления 8-го числа в серии, вращения машины для 7-го и другого для 6-го). Практически любой алгоритм «разделяй и властвуй» может быть выполнен одновременно. Вы также можете выполнить параллельную реализацию игры Конвея о жизни или теплопередаче. Обратите внимание, что все эти алгоритмы имеют различную направленность, и, следовательно, вы, вероятно, не добьетесь того, чтобы одна распределенная система работала наилучшим образом во всех из них.

Я бы сказал, что самый простой для реализации - это плохо реализованный калькулятор Фибоначчи, хотя он уделяет слишком много внимания созданию потоков и слишком мало - обмену данными между этими потоками.

0 голосов
/ 21 марта 2009

С тех пор, как в сентябре 2008 года игра-тест перешла на четырехъядерный компьютер, многие программы на разных языках программирования были переписаны для использования четырехъядерного процессора - , например, первые 10 программ Мандельброта .

0 голосов
/ 02 декабря 2008

Ниже вы можете найти код, который я взломал, чтобы проверить многопоточную производительность pthreads. Я не убрал это, и никакие оптимизации не были сделаны; поэтому код немного raw .

код для сохранения вычисленного Мандельброта, установленный как растровое изображение, не мой, вы можете найти его здесь

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

хорошие результаты можно получить с помощью программы со следующими аргументами:

Мандельброт 5120 3840 256 3

таким образом вы получите изображение шириной 5 * 1024; Высота 5 * 768 с 256 цветами (увы, вы получите только 1 или 2) и 3 потока (1 основной поток, который не выполняет никакой работы, кроме создания рабочих потоков, и 2 рабочих потока)

0 голосов
/ 29 ноября 2008

Я решил использовать набор Мандельброта (точнее, алгоритм времени выхода ) для сравнения различных языков.
Он подходит мне очень хорошо, так как оригинальный алгоритм может быть легко реализован, и создание многопоточного варианта не так уж много работы.

ниже - код, который у меня есть. Это все еще однопоточный вариант, но я обновлю его, как только я буду удовлетворен результатом.

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

Я тестировал его с gcc под Linux, но уверен, что он работает и под другими компиляторами / операционными системами. Чтобы заставить его работать, вы должны ввести несколько аргументов командной строки, например:

Мандельброт 106 500 255 1

первый аргумент - ширина (ось X)
второй аргумент - высота (ось Y)
третий аргумент - количество максимальных итераций (количество цветов)
последние включения - это количество потоков (но это не используется)

в моем разрешении, приведенный выше пример дает мне хорошее представление ASCII-набора Мандельброта. Но попробуйте сами с другими аргументами (первый будет самым важным, так как это будет ширина)

0 голосов
/ 29 ноября 2008

Конечно, вы должны тестировать оборудование и компиляторы, а не язык для выполнения параллелизма?

Нет, оборудование и компиляторы не имеют значения для моих целей тестирования. Я просто ищу хорошие проблемы, которые могут проверить, насколько хорошо код, написанный на одном языке, может конкурировать с кодом с другого языка. Я действительно тестирую конструкции, доступные на определенных языках, для параллельного программирования. И одним из критериев является производительность (измеряется во времени).

Некоторые другие критерии теста, которые я ищу:

  • как легко написать правильный код; потому что, как мы все знаем, параллельное программирование сложнее, чем написание однопоточных программ
  • Какой метод используется для параллельного программирования: управляемый событиями, актерский, анализ сообщений, ...
  • сколько кода должно быть написано самим программистом и сколько сделано для него автоматически: это также может быть проверено с данными задачами теста
  • каков уровень абстракции и сколько накладных расходов при переводе обратно в машинный код

Так что, на самом деле, я не ищу производительность как единственный и лучший параметр (который действительно отправил бы меня на аппаратное обеспечение и компиляторы вместо самого языка), я на самом деле смотрю из точка зрения программистов, чтобы проверить, какой язык лучше всего подходит для каких типов проблем, каковы его слабые и сильные стороны и так далее ...

Имейте в виду, что это всего лишь небольшой проект, и поэтому тесты также должны быть небольшими. (поэтому тщательное тестирование всего неосуществимо)

...