Сроки приложения CUDA с использованием событий - PullRequest
4 голосов
/ 05 августа 2011

Я использую следующие две функции для определения времени различных частей (cudaMemcpyHtoD, выполнения ядра, cudaMemcpyDtoH) моего кода (который включает в себя multi-gpus, параллельные ядра на одном и том же графическом процессоре, последовательное выполнение ядер и т. Д.). Как я понимаю, эти функции будут записывать время, прошедшее между событиями, но я предполагаю, что вставка событий в течение времени жизни кода может привести к накладным расходам и неточностям. Я хотел бы услышать критические замечания, общие советы по улучшению этих функций и предостережения в отношении них.

//Create event and start recording
cudaEvent_t *start_event(int device, cudaEvent_t *events, cudaStream_t streamid=0)
{
        cutilSafeCall( cudaSetDevice(device) );
        cutilSafeCall( cudaEventCreate(&events[0]) );
        cutilSafeCall( cudaEventCreate(&events[1]) );
        cudaEventRecord(events[0], streamid);

    return events;
 }

 //Return elapsed time and destroy events
 float end_event(int device, cudaEvent_t *events, cudaStream_t streamid=0)
 {

        float elapsed = 0.0;
        cutilSafeCall( cudaSetDevice(device) );
        cutilSafeCall( cudaEventRecord(events[1], streamid) );
        cutilSafeCall( cudaEventSynchronize(events[1]) );
        cutilSafeCall( cudaEventElapsedTime(&elapsed, events[0], events[1]) );

        cutilSafeCall( cudaEventDestroy( events[0] ) );
        cutilSafeCall( cudaEventDestroy( events[1] ) );

        return elapsed;
 }

Использование:

cudaEvent_t *events;
cudaEvent_t event[2]; //0 for start and 1 for end
...
events = start_event( cuda_device, event, 0 );
<Code to time>
printf("Time taken for the above code... - %f secs\n\n", (end_event(cuda_device, events, 0) / 1000) );

1 Ответ

9 голосов
/ 08 августа 2011

Во-первых, если это для рабочего кода, вы можете захотеть сделать что-то между вторым cudaEventRecord и cudaEventSynchronize ().В противном случае это может снизить способность вашего приложения перекрывать работу графического процессора и процессора.

Далее я бы отделил создание и удаление событий от записи событий.Я не уверен в стоимости, но в общем случае вы можете не захотеть часто вызывать cudaEventCreate и cudaEventDestroy.

Я бы хотел создать такой класс

class EventTimer {
public:
  EventTimer() : mStarted(false), mStopped(false) {
    cudaEventCreate(&mStart);
    cudaEventCreate(&mStop);
  }
  ~EventTimer() {
    cudaEventDestroy(mStart);
    cudaEventDestroy(mStop);
  }
  void start(cudaStream_t s = 0) { cudaEventRecord(mStart, s); 
                                   mStarted = true; mStopped = false; }
  void stop(cudaStream_t s = 0)  { assert(mStarted);
                                   cudaEventRecord(mStop, s); 
                                   mStarted = false; mStopped = true; }
  float elapsed() {
    assert(mStopped);
    if (!mStopped) return 0; 
    cudaEventSynchronize(mStop);
    float elapsed = 0;
    cudaEventElapsedTime(&elapsed, mStart, mStop);
    return elapsed;
  }

private:
  bool mStarted, mStopped;
  cudaEvent_t mStart, mStop;
};

Примечание Iне включает cudaSetDevice () - мне кажется, что следует оставить код, который использует этот класс, чтобы сделать его более гибким.Пользователь должен убедиться, что одно и то же устройство активно при вызове запуска и останова.

PS: NVIDIA не намерена полагаться на CUTIL для производственного кода - оно используется просто для удобства в нашемпримеры и не так тщательно протестированы или оптимизированы, как сами библиотеки CUDA и компиляторы.Я рекомендую вам распаковать такие вещи, как cutilSafeCall (), в свои собственные библиотеки и заголовки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...