Лучшие практики синхронизации cuBLAS

Я прочитал два сообщения о переполнении стека, а именно функции ядра cubas автоматически синхронизируются с хостом? и CUDA Dynamic параллелизм; потоковую синхронизацию с устройства, и они рекомендуют использовать некоторые API синхронизации, например, cudaDeviceSynchronize() после вызова функций cuBLAS. Я не уверен, что имеет смысл использовать такую ​​функцию общего назначения.

Не лучше ли поступить следующим образом? [Поправьте меня если я ошибаюсь]:

cublasHandle_t cublas_handle;
cudaStream_t stream;
// Initialize the matrices
CUBLAS_CALL(
  cublasDgemm(cublas_handle, CUBLAS_OP_N, CUBLAS_OP_N, M, M, 
    M, &alpha, d_A, M, d_B, M, &beta, d_C, M));
// cublasDgemm is non-blocking!
cublasGetStream(cublas_handle, &stream);
cudaStreamSynchronize(stream);
// Now it is safe to copy the result (d_C) from the device
// to the host and use it

С другой стороны, cudaDeviceSynchronize можно использовать предпочтительно, если для выполнения параллельных операций cuBLAS использовалось множество потоков/дескрипторов. Каковы «лучшие методы» синхронизации дескрипторов cuBLAS? Можно ли рассматривать дескрипторы cuBLAS как обертки для потоков в том смысле, что они служат той же цели с точки зрения синхронизации?


person Pantelis Sopasakis    schedule 10.04.2014    source источник
comment
По какой причине вам не нравится cudaDeviceSynchronize? Кроме того, в вашем примере вы не устанавливаете поток перед вызовом cuBLAS. Наконец, зачем вводить потоки в игру? Только для одного потока будет ли pdrform потоковой синхронизации отличаться от синхронизации устройства?   -  person Vitality    schedule 10.04.2014
comment
@JackOLantern Я читал, что cudaDeviceSynchronize в целом замедляет выполнение, поэтому я подумал, что лучше этого избегать. Кроме того, cudaStreamSynchronize сообщает устройству, что именно синхронизировать. Возможно, это не имеет никакого значения, я просто хотел узнать, как лучше всего распараллеливать операции cuBLAS.   -  person Pantelis Sopasakis    schedule 10.04.2014
comment
@JackOLantern Кроме того, возможно, существуют другие вещи, которые делают другие вещи, и нет смысла их ждать. В этом смысле cudaStreamSynchronize(stream) должен быть лучшим вариантом, я думаю.   -  person Pantelis Sopasakis    schedule 10.04.2014
comment
Мы только что попробовали это, с управляемой памятью и cudaStreamSynchronize( stream ) было недостаточно. Только когда мы сделали cudaDeviceSynchronize`, мы смогли получить стабильные результаты (никаких гонок после вызова Dgemm). Может быть, управляемая память требует полной синхронизации?   -  person alfC    schedule 02.05.2021


Ответы (2)


Если вы используете один поток, не имеет значения, синхронизируете ли вы этот поток или используете cudaDeviceSynchronize(). С точки зрения производительности и эффекта он должен быть точно таким же. Обратите внимание, что при использовании событий для измерения времени в части вашего кода (например, вызов cublas) всегда рекомендуется вызывать cudaDeviceSynchronize() для получения значимых измерений. По моему опыту, это не требует значительных накладных расходов и, кроме того, с ним безопаснее синхронизировать ядра.

Если ваше приложение использует несколько потоков, имеет смысл синхронизироваться только с нужным вам потоком. Я считаю, что этот вопрос будет вам полезен. Кроме того, вы можете прочитать руководство по программированию на CUDA C, раздел 3.2.5.5. .

person Nicolas Bert Johnson    schedule 17.10.2014

В вашем примере неясно, нужно ли вам вообще использовать явную синхронизацию или почему вам нужно ее использовать.

Операции CUDA, отправленные в один и тот же поток, сериализуются. Если вы запускаете ядро ​​или вызов cublas, а затем следуете за этим вызовом ядра или cublas операцией cudaMemcpy (или cubasGetVector/Matrix и т. д.), гарантировано, что операция копирования не запустится до тех пор, пока все предыдущая активность CUDA, отправленная в тот же поток, завершена.

Лучшей практикой для общих случаев является вообще не использовать явную синхронизацию. Поместите действия, которые должны быть последовательно зависимы, в один и тот же поток. Разместите действия, которые не зависят друг от друга, в отдельные потоки.

Есть много кодов cuda, использующих cubas и другие, которые вообще не используют явную синхронизацию. Ваш пример в этом особо не нуждается. Обратите внимание, что в первом ответе, который вы связали, talonmies сказал:

вам нужно вызвать блокирующую процедуру API, такую ​​​​как синхронная передача памяти или...

В вашем примере это именно то, что вы сделали бы. Вы бы вызвали передачу памяти, либо выданную тому же потоку (например, cudaMemcpyAsync), либо передачу блокировки по умолчанию (например, cudaMemcpy), и она будет работать нормально. Нет необходимости в явной синхронизации.

Вы можете прочитать соответствующий раздел руководства по программированию

person Robert Crovella    schedule 10.04.2014