测量 OpenCL 应用程序的运行时间

Measuring Elapsed Time for an OpenCL Application

我知道这个问题被问过好几次了,但在我的应用程序中,关键是要有合适的时间,所以我可能想再试一次:

我计算内核的时间 方法是这样的,首先是 CPU 时钟时间 clock_t;

clock_t start = clock(); // Or std::chrono::system_clock::now() for WALL CLOCK TIME
openCLFunction();
clock_t end = clock; // Or std::chrono::system_clock::now() for WALL CLOCK TIME
double time_elapsed = start-end;

还有我的 openCLFunction():

{
//some OpenCLKernelfunction
clFlush(queue);
clFinish(queue);
}

两种方法的结果有很大的不同,说实话我不知道哪个是正确的,因为它们是以毫秒为单位的。我可以相信 CPU 时钟时间吗?有没有一种不关心结果的确定的测量方法?(请注意,我调用了两个函数来完成我的内核函数。)

您可能应该使用内核分析。

cl_command_queue_properties properties[] {CL_QUEUE_PROPERTIES, CL_QUEUE_PROFILING_ENABLE, 0};
cl_command_queue queue = clCreateCommandQueueWithProperties(context, device, properties, &err);

/*Later...*/
cl_event event;
clEnqueueNDRangeKernel(queue, kernel, /*...*/, &event);
clWaitForEvents(1, &event);
cl_ulong start, end;
clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_START, sizeof(cl_ulong), &start, nullptr);
clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &end, nullptr);

std::chrono::nanoseconds duration{end - start};

在该代码的末尾,duration 包含从开始到结束之间经过的纳秒数(根据设备的能力报告精确度;请注意,许多设备不具有亚微秒精度)和内核执行结束。

有(至少)3 种方法来计时 OpenCL/CUDA 执行:

  1. 使用 CPU 计时器 + 队列刷新
  2. OpenCL/CUDA 事件的使用
  3. 使用外部分析器工具(例如 AMD 提供的任何工具或 nVIDIA 卡的 nvprof)

你的第一个例子属于第一类,但是 - 你似乎没有刷新 OpenCL 函数使用的队列(我假设这是一个将内核排入队列的函数)。所以 - 除非以某种方式强制执行是同步的,否则您要测量的是将内核排入队列并在此之前或之后执行任何 CPU-side 工作所需的时间。这可以解释 clFlush/clFinish 方法的差异。

造成差异的另一个原因可能是 setup/tear-down 工作(例如内存分配或 运行 时间内部开销),您的第二种方法需要时间,而您的第一种方法没有。

最后要注意的是,由于测量不准确或使用它们所需的开销不同,这三种方法都会产生略有不同的结果。但是,如果您的内核很小,这些差异可能不会那么小:根据我的经验,在 CUDA 和 nVIDIA Maxwell 和 Pascal 卡上,探查器提供的内核执行时间与事件测量时间可能相差数十微秒。这一事实的教训是: 1. 在相关且可能的情况下尝试测量更多数据,并根据数据量进行归一化。 2. 在进行比较时,在衡量执行时间的方式上保持一致。