Подтвердить что ты не робот

Когда вызывать cudaDeviceSynchronize?

когда вы вызываете функцию cudaDeviceSynchronize, которая действительно нужна?.

Насколько я понимаю из документации CUDA, ядра CUDA являются асинхронными, поэтому кажется, что после каждого запуска ядра мы должны вызвать cudaDeviceSynchronize. Тем не менее, я пробовал один и тот же код (обучение нейронных сетей) с и без cudaDeviceSynchronize, кроме одного до измерения времени. Я обнаружил, что получаю тот же результат, но с ускорением между 7-12x (в зависимости от размеров матрицы).

Итак, вопрос в том, есть ли какие-либо причины использовать cudaDeviceSynchronize за исключением измерения времени.

Например:

  • Это необходимо, прежде чем копировать данные с GPU на хост с помощью cudaMemcpy?

  • Если я выполняю матричные умножения, такие как

    C = A * B
    D = C * F
    

Должен ли я поставить cudaDeviceSynchronize между обоими?

Из моего эксперимента Кажется, что я этого не делаю.

Почему cudaDeviceSynchronize так сильно замедляет работу программы?

4b9b3361

Ответ 1

Хотя запуск ядра CUDA асинхронен, все задачи, связанные с графическим процессором, размещенные в одном потоке (по умолчанию), выполняются последовательно.

Итак, например,

kernel1<<<X,Y>>>(...); // kernel start execution, CPU continues to next statement
kernel2<<<X,Y>>>(...); // kernel is placed in queue and will start after kernel1 finishes, CPU continues to next statement
cudaMemcpy(...); // CPU blocks until ememory is copied, memory copy starts only after kernel2 finishes

Итак, в вашем примере нет необходимости в cudaDeviceSynchronize. Однако при отладке может оказаться полезным определить, какое из ячеек вызвало ошибку (если есть).

cudaDeviceSynchronize может вызвать некоторое замедление, но 7-12x кажется слишком большим. Может быть, есть некоторая проблема с измерением времени или может быть, что ядра действительно быстрые, а накладные расходы на явную синхронизацию огромны по сравнению с фактическим временем вычисления.

Ответ 2

Одна из ситуаций, когда использование cudaDeviceSynchronize() подходит, будет иметь место при запуске нескольких cudaStream, и вы хотели бы, чтобы они обменивались некоторой информацией. Реальным случаем этого является параллельный отпуск в квантовых моделях Монте-Карло. В этом случае мы хотим убедиться, что каждый поток завершил выполнение некоторого набора инструкций и получил некоторые результаты, прежде чем они начнут передавать сообщения друг другу, или мы закончим передачу информации об мусоре. Причина использования этой команды настолько сильно замедляет работу программы, что cudaDeviceSynchronize() заставляет программу ждать, пока все ранее выпущенные команды во всех потоках на устройстве не закончатся, прежде чем продолжить (из руководства по программированию CUDA C). Как вы сказали, выполнение ядра обычно асинхронно, поэтому, когда устройство GPU выполняет ваше ядро, CPU может продолжать работать над некоторыми другими командами, выдавать больше инструкций устройству и т.д. Вместо ожидания. Однако, когда вы используете эту команду синхронизации, CPU вместо этого принудительно простаивает, пока все работы GPU не завершились, прежде чем делать что-либо еще. Такое поведение полезно при отладке, поскольку у вас может быть segfault, возникающий в кажущиеся "случайными" временами из-за асинхронного выполнения кода устройства (будь то в одном потоке или во многих). cudaDeviceSynchronize() заставит программу гарантировать, что потоки (ядра) ядра /memcpys будут завершены, прежде чем продолжить, что упростит обнаружение случаев незаконного доступа (поскольку отказ будет отображаться во время синхронизации).

Ответ 3

Если вы хотите, чтобы ваш графический процессор начал обрабатывать некоторые данные, вы обычно выполняете вызов ядра. Когда вы это сделаете, ваше устройство (GPU) начнет делать все, что вы ему сказали. Однако, в отличие от обычной последовательной программы на вашем хосте (CPU), вы продолжите выполнение следующих строк кода в вашей программе. cudaDeviceSynchronize заставляет хост (CPU) ждать, пока устройство (GPU) завершит выполнение всех запущенных вами потоков, и, таким образом, ваша программа будет продолжена, как если бы это была обычная последовательная программа.

В небольших простых программах вы обычно используете cudaDeviceSynchronize, когда используете GPU для выполнения вычислений, чтобы избежать несоответствий синхронизации между CPU, запрашивающим результат, и GPU, завершающим вычисление. Для использования cudaDeviceSynchronize значительно упрощается кодирование вашей программы, но есть один главный недостаток: ваш процессор все время простаивает, а графический процессор выполняет вычисления. Поэтому в высокопроизводительных вычислениях вы часто стремитесь к тому, чтобы вычислить ваш процессор, пока он ждет завершения графического процессора.