桌面计算机上的OpenCL比macbook 13“慢”

时间:2016-02-07 18:01:45

标签: c++ windows macos performance opencl

我一直在编写一个我在Macbook Pro上首次编写的OpenCL程序,因为我的桌面计算机更强大,我想移植代码并查看是否有任何改进。

运行相同的代码:

Mac:0.055452s

Win7:0.359s

两台计算机的规格如下: Mac:2.6GHz Intel Core i5,8GB 1600MHz DDR3,Intel Iris 1536MB

PC:3.3GHz Intel Core i5-2500k,8GB 1600MHz DDR3,AMD Radeon HD 6900系列

现在您可以看到我的Mac上运行的代码比我的台式PC快了近10倍。

我使用

计时代码
#include<ctime>
clock_t begin = clock();
....// Entire main file
float timeTaken = (float)(clock() - begin) / CLOCKS_PER_SEC;
cout << "Time taken: " << timeTaken << endl;

如果我没弄错的话,PC和GPU上的CPU和GPU都会更强大。我可以使用这台台式电脑在Ultra设置上运行Battlefield 3。

唯一的区别可能是PC上的Visual Studio与另一个编译器编译?我在我的mac上使用了g ++,不确定Visual Studio使用了什么。

这些结果对我没有意义。你们有什么感想?如果你想查看代码,我可以发布github链接

编辑:以下github链接显示代码https://github.com/Batkow/OpenCL/tree/master/OpenCL。 PSO_V2使用教程中使用的编码类型:https://www.fixstars.com/en/opencl/book/OpenCLProgrammingBook/introduction-to-parallelization/

PSO使用此github存储库中的自定义标头简化了编码:https://github.com/HandsOnOpenCL/Exercises-Solutions ..

我使用NVidia Geforce 950M在我的朋友新款i7笔记本电脑上运行了代码,代码执行速度甚至比在我的台式机上还要慢。

我确实意识到代码没有经过优化,因此我对愚蠢的东西提出任何提示,请打电话给它。例如,在三个不同的内核函数中有一个while循环是一种愚蠢的权利吗?我正在努力在内核中实现所有内容并在其中循环,这应该可以提高性能吗?

更新:再次在家中的Windows上运行OpenCL / PSO代码。在while循环之前和之后对代码进行定时可以使WINDOWS的性能更快!

clock_t Win7 = 0.027,Mac = 0.036。使用带有Util :: Timer类Win7的外部.hpp运行:0.026秒,而Mac为0.085秒。

从主文件的开始到while循环(所有初始化)之前的时间,然后使用clock_t和Util :: Timer,Mac的得分比Windows几乎高10倍。所以瓶颈似乎是在设备的初始化?

6 个答案:

答案 0 :(得分:1)

可能是几十件事 - CL内核的关键是什么,以及它在不同类型的GPU上的效果如何。或者使用什么编译器

但是,我认为问题在于你如何衡量时间。 Windows上的clock()测量“wallclock-time”(换句话说“经过时间”),在OSX(以及所有其他理智的操作系统)上,它会报告您的进程的CPU时间。如果OSX在图形处理器上运行[或在单独的进程中],它将不计入CPU时间,其中Windows测量总时间。

在Windows上使用适当的CPU时间测量来测量CPU时间(例如,使用GetProcessTimes)。或者使用c ++ std::chrono来测量两个地方的挂钟时间。

答案 1 :(得分:1)

也许你测量流逝时间的方式存在问题,例如我在不同操作系统的项目中采用了三种不同的方式:

#include <cstdio>
#include <iostream>

#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#elif defined(__linux__)
#include <time.h>
#elif defined(__APPLE__)
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <stddef.h>
#endif
#if defined(_WIN32) || defined(_WIN64)
LARGE_INTEGER frequency;  // ticks per second
LARGE_INTEGER t0, t1, t2; // ticks
LARGE_INTEGER t3, t4;
#elif defined(__linux__)
timespec t0, t1, t2;
timespec t3, t4;
double us;
#elif defined(__APPLE__)
unsigned long t0, t1, t2;
#endif
double elapsedTime;
void refreshTime() {
#if defined(_WIN32) || defined(_WIN64)
  QueryPerformanceFrequency(&frequency); // get ticks per second
  QueryPerformanceCounter(&t1);          // start timer
  t0 = t1;
#elif defined(__linux__)
  clock_gettime(CLOCK_MONOTONIC_RAW, &t1);
  t0 = t1;
#elif defined(__APPLE__)
  t1 = mach_absolute_time();
  t0 = t1;
#endif
}

void watch_report(const char *str) {
#if defined(_WIN32) || defined(_WIN64)
  QueryPerformanceCounter(&t2);
  printf(str, (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart);
  t1 = t2;
  elapsedTime = (t2.QuadPart - t0.QuadPart) * 1000.0 / frequency.QuadPart;
#elif defined(__linux__)
  clock_gettime(CLOCK_MONOTONIC_RAW, &t2);
  time_t sec = t2.tv_sec - t1.tv_sec;
  long nsec;
  if (t2.tv_nsec >= t1.tv_nsec) {
    nsec = t2.tv_nsec - t1.tv_nsec;
  } else {
    nsec = 1000000000 - (t1.tv_nsec - t2.tv_nsec);
    sec -= 1;
  }
  printf(str, (float)sec * 1000.f + (float)nsec / 1000000.f);
  t1 = t2;
  elapsedTime = (float)(t2.tv_sec - t0.tv_sec) * 1000.f +
                (float)(t2.tv_nsec - t0.tv_nsec) / 1000000.f;
#elif defined(__APPLE__)
  uint64_t elapsedNano;
  static mach_timebase_info_data_t sTimebaseInfo;

  if (sTimebaseInfo.denom == 0) {
    (void)mach_timebase_info(&sTimebaseInfo);
  }

  t2 = mach_absolute_time();
  elapsedNano = (t2 - t1) * sTimebaseInfo.numer / sTimebaseInfo.denom;
  printf(str, (float)elapsedNano / 1000000.f);
  t1 = t2;
  elapsedNano = (t2 - t0) * sTimebaseInfo.numer / sTimebaseInfo.denom;
  elapsedTime = (float)elapsedNano / 1000000.f;
#endif
}
/*This Function will work till you press q*/
void someFunction() {
  while (1) {
    char ch = std::cin.get();
    if (ch == 'q')
      break;
  }
}

int main() {
  refreshTime();
  someFunction();
  watch_report("some function was working: \t%9.3f ms\n");
}

答案 2 :(得分:1)

因为clock()函数只计算CPU时钟周期。您的主机代码可能正在调用内核然后进入休眠状态。即使内核正在执行,这个休眠时间也不会被时钟函数计算。所以这意味着时钟函数只考虑主机代码的执行时间而不考虑openCL内核。您需要使用一个计算挂钟时间而不是CPU时钟周期的函数。

答案 3 :(得分:0)

除非直接指定,否则Visual Studio将使用MSVC编译器。

我认为答案隐藏在CPU的几代人中。在你的电脑上它是Sandy Bridge(第二代)和Mac - Haswell(第四代)。这是两代人的差异。

OpenCL是在这几代英特尔处理器(Haswell中过多的硬件支持)中显着发展的事情之一。

只是为了得到证据 - 找一个配有Haswell CPU的桌面的朋友并运行你的测试。桌面Haswell处理器应该击败你的Mac(当然,如果其他硬件规格和整体系统负载匹配)。

答案 4 :(得分:0)

您已发布计时功能,但未发布OpenCL代码。什么都被定时?一个重要因素可能是内核编译时间(clCreateProgramFromSource和clBuildProgram)。您的PC可能正在使用缓存的内核而Mac则不是。衡量OpenCL内核执行时间的正确方法是使用OpenCL事件。

答案 5 :(得分:-1)

您可能获得该结果的另一个可能原因 - 也许您的程序编译为OpenCL ver.2.0。

在Windows上,您的GPU是从2010年开始的,它只支持OpenCL 1.2。

在OSX上,您的Intel GPU支持OpenCL 2.0。