Ответ 1
Поскольку CUDA 4.0 был выпущен, вычисления с несколькими GPU типа, о котором вы просите, относительно просты. До этого вам нужно будет использовать многопоточное хост-приложение с одним потоком хоста для каждого графического процессора и какую-то систему межпоточных коммуникаций, чтобы использовать mutliple GPU внутри одного и того же хост-приложения.
Теперь для части выделения памяти вашего хост-кода можно сделать что-то вроде этого:
double *dev_a[2], *dev_b[2], *dev_c[2];
const int Ns[2] = {N/2, N-(N/2)};
// allocate the memory on the GPUs
for(int dev=0; dev<2; dev++) {
cudaSetDevice(dev);
cudaMalloc( (void**)&dev_a[dev], Ns[dev] * sizeof(double) );
cudaMalloc( (void**)&dev_b[dev], Ns[dev] * sizeof(double) );
cudaMalloc( (void**)&dev_c[dev], Ns[dev] * sizeof(double) );
}
(отказ от ответственности: написан в браузере, никогда не компилируется, никогда не тестируется, используется на свой страх и риск).
Основная идея здесь заключается в том, что вы используете cudaSetDevice
для выбора между устройствами, когда выполняете операции предварительного форматирования на устройстве. Поэтому в приведенном выше фрагменте я предположил два графических процессора и выделил память на каждом [(N/2) удвоении на первом устройстве и N- (N/2) на втором].
Передача данных с хоста на устройство может быть простой:
// copy the arrays 'a' and 'b' to the GPUs
for(int dev=0,pos=0; dev<2; pos+=Ns[dev], dev++) {
cudaSetDevice(dev);
cudaMemcpy( dev_a[dev], a+pos, Ns[dev] * sizeof(double), cudaMemcpyHostToDevice);
cudaMemcpy( dev_b[dev], b+pos, Ns[dev] * sizeof(double), cudaMemcpyHostToDevice);
}
(отказ от ответственности: написан в браузере, никогда не компилируется, никогда не тестируется, используется на свой страх и риск).
Раздел запуска ядра вашего кода может выглядеть примерно так:
for(int i=0;i<10000;++i) {
for(int dev=0; dev<2; dev++) {
cudaSetDevice(dev);
add<<<NB,NT>>>( dev_a[dev], dev_b[dev], dev_c[dev], Ns[dev] );
}
}
(отказ от ответственности: написан в браузере, никогда не скомпилирован, никогда не тестировался, используйте на свой страх и риск).
Обратите внимание, что я добавил дополнительный аргумент для вашего вызова ядра, потому что каждый экземпляр ядра может быть вызван с другим количеством элементов массива для обработки. Я оставлю это вам для разработки необходимых изменений.
Но, опять же, основная идея одна и та же: используйте cudaSetDevice
для выбора данного графического процессора, а затем запускайте ядра на нем обычным способом, причем каждое ядро получает свои собственные уникальные аргументы.
Вы можете объединить эти части для создания простого приложения с несколькими GPU. Существует множество других функций, которые можно использовать в последних версиях и оборудовании CUDA для поддержки нескольких приложений GPU (например, для унифицированной адресации, для одноранговых узлов больше), но этого должно быть достаточно, чтобы вы начали. Существует также приложение muLti-GPU в SDK CUDA, на которое вы можете посмотреть больше идей.