Я написал программу CUDA SGEMM, и когда я захотел проверить скорость с помощью многопоточной реализации ЦП, она не смогла работать в многопоточном режиме. Я изолировал реализацию ЦП в отдельном файле, собрал ее и запустил, и проблем не возникло. Код в .cc и изолированном .cu (одинаковый):
void sgemm_cpu_multi_threading(
float* A, float* B, float* C,
float alpha, float beta, const int M, const int N, const int K
) {
#pragma omp parallel for num_threads(8)
for (int m = 0; m < M; m++) {
printf("%d thread(s) can be used\n", omp_get_num_threads());
for (int n = 0; n < N; n++) {
float psum = 0.0;
for (int k = 0; k < K; k++) {
psum += A[m * K + k] * B[k * N + n];
}
C[m * N + n] = C[m * N + n] * beta + psum * alpha;
}
}
}
int main() {
omp_set_num_threads(OMP_THREADS); // OMP_THREADS=8
// ...
sgemm_cpu_multi_threading(A, B, C, alpha, beta, M, N, K);
// ...
}
В программе CUDA printf всегда выводит «можно использовать 1 поток», и выполнение действительно сериализуется. В то время как изолированный чистый исполняемый файл cxx сообщает мне, что «можно использовать 8 потоков». Мой CMakeLists.txt (CUDA). Для изолированного проекта cxx я удаляю только строки, относящиеся к CUDA.
cmake_minimum_required(VERSION 3.10)
project(SGEMM CUDA CXX)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release")
endif ()
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall -fopenmp")
SET(COMPILE_CUDA True)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CUDA_ARCHITECTURES 75)
find_package(OpenMP REQUIRED)
if (OPENMP_FOUND)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
endif ()
include_directories(
${CMAKE_SOURCE_DIR}/../
)
add_executable(matmul ./matmul.cu)
target_link_libraries(matmul pthread OpenMP::OpenMP_CXX)
Может кто-нибудь сказать мне, что здесь происходит? Почему я не могу правильно использовать многопоточность OpenMP в программе CUDA? Кстати, если вы хотите знать, A, B, C можно распределить с помощью .cc или new, и это не повлияет на тот факт, что я не могу не запускать программу с более чем одним потоком, даже если функция процессора должна быть разделен с помощью nvcc, скомпилирован и запущен на процессоре.
вы можете найти пример того, как создать код OpenMP с помощью nvcc в примерах CUDA (хотя и не с помощью cmake).
Всегда полезно проверить фактические команды компиляции, используемые с make VERBOSE=1. Это показывает, что -fopenmp не передается nvcc. В условии if (OPENMP_FOUND) вы меняете только параметры для языков CXX и C, а не для языка CUDA. set (CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcompiler ${OpenMP_CXX_FLAGS}"), кажется, работает для меня с точки зрения добавления -Xcompiler -fopenmp к команде компиляции. Хотя это может быть хрупким, поскольку зависит от того, OpenMP_CXX_FLAGS является ли флаг единым. Менее хрупкое решение потребовало бы дополнительных манипуляций с веревками.
-Xcompiler.
Отвечает ли это на ваш вопрос? Используете openMP в коде хоста cuda?
@RobertCrovella Спасибо, оказывается, проблема в настройке CMake. Я удалил CMAKE_CXX_FLAGS и CMAKE_C_FLAGS и вместо этого добавил set (CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} ${OpenMP_CXX_FLAGS}"), многопоточность omp может поддерживаться даже без -Xcompiler и -fopenmp (думаю, ${OpenMP_CXX_FLAGS} включает некоторые из них?)





Как упоминал @RobertCrovella, мой код скомпилирован неправильно, и CMAKE_CUDA_FLAGS установлен неправильно. Решение довольно простое, используйте:
find_package(OpenMP REQUIRED)
if (OPENMP_FOUND)
set (CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} ${OpenMP_CXX_FLAGS}")
endif ()
вместо установки флагов c и cxx в CMake. Я проверил содержимое ${OpenMP_CXX_FLAGS} через message, там написано -fopenmp (и ничего больше), поэтому не нужно писать -fopenmp еще раз. Кроме того, я могу скомпилировать код без -Xcompiler, и он работает правильно. Если проблема не исчезнет, можно попробовать добавить этот флаг. Спасибо за комментарии @RobertCrovella и @paleonix.
возможно, вы неправильно скомпилировали данные. при компиляции кодов CUDA с
nvcc, использующих OpenMP, обычно необходимо передать определенные параметры компиляции вnvcc, включая, например (если в Linux)-Xcompiler -fopenmp. Я понятия не имею, делает ли это ваш Cmake или нет, но я бы определенно отметил этот вопросcmake.