Мое новое решение, чтобы избежать синхронизации с устройством. Я посмотрел на некоторые методы retreiting timestamps, а результаты выглядят нормально, и я уверен, что сравнения достаточно справедливы. Я сравнивал время CUDA (Event Record и QPC), и разница небольшая, казалось бы, накладные расходы.
CUDA Event Host QPC
4,6 30,0
4,8 30,0
5,0 31,0
5,2 32,0
5,6 34,0
6,1 34,0
6,9 31,0
8,3 47,0
9,2 34,0
12,0 39,0
16,7 46,0
20,5 55,0
32,1 69,0
48,5 111,0
86,0 134,0
182,4 237,0
419,0 473,0
В случае мой вопрос приносит кому-то в надежде найти, как сделать GPGPU бенчмаркинг я оставлю код за демонстрируя свою текущую стратегию бенчмаркинга.
Примеры кода, CUDA
cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
float milliseconds = 0;
cudaEventRecord(start);
...
// Launch my algorithm
...
cudaEventRecord(stop);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&milliseconds, start, stop);
OpenCL
cl_event start_event, end_event;
cl_ulong start = 0, end = 0;
// Enqueue a dummy kernel for the start event.
clEnqueueNDRangeKernel(..., &start_event);
...
// Launch my algorithm
...
// Enqueue a dummy kernel for the end event.
clEnqueueNDRangeKernel(..., &end_event);
clWaitForEvents(1, &end_event);
clGetEventProfilingInfo(start_event, CL_PROFILING_COMMAND_START, sizeof(cl_ulong), &start, NULL);
clGetEventProfilingInfo(end_event, CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &end, NULL);
timeInMS = (double)(end - start)*(double)(1e-06);
DirectCompute
Здесь я следовал предложение от Адама Майлса и заглянул в этот источник.Будет выглядеть примерно так:
ID3D11Device* device = nullptr;
...
// Setup
...
ID3D11QueryPtr disjoint_query;
ID3D11QueryPtr q_start;
ID3D11QueryPtr q_end;
...
if (disjoint_query == NULL)
{
D3D11_QUERY_DESC desc;
desc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
desc.MiscFlags = 0;
device->CreateQuery(&desc, &disjoint_query);
desc.Query = D3D11_QUERY_TIMESTAMP;
device->CreateQuery(&desc, &q_start);
device->CreateQuery(&desc, &q_end);
}
context->Begin(disjoint_query);
context->End(q_start);
...
// Launch my algorithm
...
context->End(q_end);
context->End(disjoint_query);
UINT64 start, end;
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT q_freq;
while (S_OK != context->GetData(q_start, &start, sizeof(UINT64), 0)){};
while (S_OK != context->GetData(q_end, &end, sizeof(UINT64), 0)){};
while (S_OK != context->GetData(disjoint_query, &q_freq, sizeof(D3D11_QUERY_DATA_TIMESTAMP_DISJOINT), 0)){};
timeInMS = (((double)(end - start))/((double)q_freq.Frequency)) * 1000.0;
C/C++/OpenMP
static LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds, Frequency;
static void __inline startTimer()
{
QueryPerformanceFrequency(&Frequency);
QueryPerformanceCounter(&StartingTime);
}
static double __inline stopTimer()
{
QueryPerformanceCounter(&EndingTime);
ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;
ElapsedMicroseconds.QuadPart *= 1000000;
ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;
return (double)ElapsedMicroseconds.QuadPart;
}
Мои примеры кода взяты из контекста, и я пытался сделать некоторые очистке, но ошибки могут присутствовать.
Спасибо! Я собрал код, который использует запросы Timestamp DirectX 11, и, похоже, он работает нормально. Я понял, что мой основной вопрос будет справедливым. До сих пор я использовал API QueryPerformanceCounter (QPC) Windows на хосте, но включил много накладных расходов, не включенных при использовании временных меток устройства. – thorbear
Как вы упомянули в своем первоначальном вопросе, время, необходимое для фактического выдачи вызовов API, на самом деле не является тем, что вас интересует. Если вы не можете быть уверены, что GPU был бездействующим, когда вы вызывали Dispatch (возможно) начал работу сразу (скорее всего, нет), и что работа закончена, прежде чем вы остановите свой таймер (это не будет), тогда использование QPC не даст вам нужную вам информацию. –