【问题标题】:Benchmark problems for testing concurency测试并发的基准问题
【发布时间】:2008-11-29 09:22:56
【问题描述】:

对于我现在正在做的一个项目,我需要查看不同concurrent enabled 编程语言的性能(除其他外)。

目前我正在研究比较stackless pythonC++ PThreads,所以重点是这两种语言,但其他语言可能会在以后进行测试。当然比较必须尽可能有代表性和准确,所以我的第一个想法是开始寻找一些标准的并发/多线程基准问题,可惜我做不到找到任何体面或标准的测试/问题/基准。

所以我的问题如下:你有什么好的、简单的或快速的问题来测试编程语言的性能(并在这个过程中暴露它的强项和弱点)?

【问题讨论】:

    标签: performance multithreading concurrency benchmarking


    【解决方案1】:

    您肯定应该测试硬件和编译器而不是语言的并发性能吗?

    我会从并发性方面的简单性和生产力的角度来看待一门语言,以及它在多大程度上“隔离”程序员不犯锁定错误。

    编辑:根据过去作为研究人员设计并行算法的经验,我认为您会发现在大多数情况下,并发性能很大程度上取决于算法的并行化方式以及它如何针对底层硬件。

    此外,众所周知,基准是不平等的;在并行环境中更是如此。例如,“处理”非常大的矩阵的基准测试适合矢量管道处理器,而并行排序可能更适合更通用的多核 CPU。

    这些可能有用:

    Parallel Benchmarks

    NAS Parallel Benchmarks

    【讨论】:

    • 你勾起了我的兴趣!你说你有并行算法研究的经验。当然,您可以给我一些您研究过的有趣问题或算法吗?是的,你是对的,基准本身没有什么意义,这就是为什么我不会花太多时间在他们身上
    • 好久不见!我基本上采用了一种有效的顺序算法,并首先按顺序测量了它的性能,然后针对不断增加的数字进行了测量。 CPU 数量。
    • (与并行版本一样...)
    【解决方案2】:

    嗯,有一些经典,但不同的测试强调不同的功能。一些分布式系统可能更健壮,具有更有效的消息传递等。更高的消息开销会损害可伸缩性,因为扩展到更多机器的正常方法是发送大量小消息。您可以尝试的一些经典问题是分布式的埃拉托色尼筛法或实施不佳的斐波那契数列计算器(即计算系列中的第 8 个数字,第 7 个机器旋转,第 6 个机器旋转)。几乎任何分而治之的算法都可以同时完成。您还可以同时实现 Conway 的生命游戏或热传递。请注意,所有这些算法都有不同的侧重点,因此您可能不会让一个分布式系统在所有这些算法中都做得最好。

    我想说,最容易快速实现的是斐波那契计算器,尽管它过分强调创建线程而很少强调这些线程之间的通信。

    【讨论】:

    • 虽然很容易实现,但我不确定“实现不佳的斐波那契计算器”是否是一个特别好的测试;有点太做作了。
    • 没错,这是人为的。但在我研究分布式计算的时候,它仍然是一个比较流行的演示算法。如果您想要一个强调消息并且不强调其他任何内容的分布式算法,那么总是有 bittorrent。
    【解决方案3】:

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

    不,硬件和编译器与我的测试目的无关。我只是在寻找一些可以测试用一种语言编写的代码与另一种语言的代码竞争的好问题。我真的在测试特定语言中可用的结构来进行并发编程。其中一项标准是性能(按时间衡量)。

    我正在寻找的其他一些测试标准是:

    • 编写正确的代码是多么容易;因为众所周知,并发编程比编写单线程程序更难
    • 用于并发编程的技术是什么:事件驱动、基于参与者、消息解析......
    • 有多少代码必须由程序员自己编写,有多少是自动为他完成的:这也可以用给定的基准问题来测试
    • 什么是抽象级别以及翻译回机器代码时涉及多少开销

    所以实际上,我并不是在寻找性能作为 the 唯一和最佳参数(这确实会将我发送到硬件和编译器而不是语言本身),我实际上是在寻找从程序员的角度来检查哪种语言最适合解决什么样的问题,它的弱点和优势是什么等等......

    请记住,这只是一个小项目,因此测试也应保持较小。 (因此对所有东西都进行严格的测试是不可行的)

    【讨论】:

    • 如果是个小项目,说真的,何必呢?只需选择一种为并行化提供良好支持的语言即可。
    • 因为这是项目的基本思想。它只是一个小型研究项目,之后没有更多的期望(即使用语言)。除了选择最好的语言之外,它是关于表明每种语言都有它的位置。每种语言都有其长处和短处...
    【解决方案4】:

    我决定使用Mandelbrot set(更准确地说是escape time algorithm)对不同的语言进行基准测试。
    它非常适合我,因为可以轻松实现原始算法,并且从中创建多线程变体并不需要太多工作。

    下面是我目前拥有的代码。它仍然是一个单线程变体,但我会在对结果满意后立即更新它。

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

    我已经在 Linux 下使用 gcc 对其进行了测试,但我确信它也可以在其他编译器/操作系统下工作。要让它工作,你必须输入一些命令行参数,如下所示:

    曼德布罗 106 500 255 1

    第一个参数是宽度(x 轴)
    第二个参数是高度(y 轴)
    第三个参数是最大迭代次数(颜色数)
    最后一个是线程数(但当前没有使用)

    根据我的解决方案,上面的示例为我提供了一个很好的 Mandelbrot 集的 ASCII 艺术表示。但是用不同的参数自己尝试一下(第一个是最重要的,因为那将是宽度)

    【讨论】:

      【解决方案5】:

      您可以在下面找到我为测试 pthread 的多线程性能而编写的代码。我没有清理它,也没有进行任何优化;所以代码有点原始

      将计算出的mandelbrot集保存为位图的代码不是我的,你可以找到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);
      }
      

      使用带有以下参数的程序可以获得良好的结果:

      曼德布罗 5120 3840 256 3

      这样您将获得 5 * 1024 宽的图像; 5 * 768 高,256 色(唉,你只会得到 1 或 2 种颜色)和 3 个线程(1 个主线程,除了创建工作线程之外不做任何工作,2 个工作线程)

      【讨论】:

        【解决方案6】:

        自从 2008 年 9 月基准测试游戏转移到四核机器上以来,许多不同编程语言的程序都被重写以利用四核 - for example, the first 10 mandelbrot programs

        【讨论】:

        • 链接已损坏。
        猜你喜欢
        • 1970-01-01
        • 2021-06-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-10-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多