はじめに
本稿では、CUDA環境におけるFFT(高速フーリエ変換)処理のために用いられるcuFFTライブラリの 주요関数について、その使用方法を具体的なコード例とともに解説する。
cufftExecC2C()使用例
実装手順:
- 入力データと出力用配列を確保し、GPUメモリ上に配置する;
- 入力データを初期化し、ホストメモリからGPUメモリへ転送する;
- cuFFTプランを生成し、
cufftExecC2C()関数を用いてFFT変換を実行する;- cuFFTプランを解放する;
- 計算結果をGPUメモリからホストメモリへ転送し、値を出力する;
- 確保したメモリを解放する;
一次元フーリエ変換(FFT)の実装:
#include <stdio.h>
#include <stdlib.h>
#include <cufft.h>
int main() {
// 配列の次元数を設定
const int arraySize = 8;
const int bufferSize = sizeof(cufftComplex) * arraySize;
// 入力・出力用ポインタを宣言
cufftComplex *inputBuffer;
cufftComplex *outputBuffer;
// GPUメモリを確保
cudaMalloc((void**)&inputBuffer, bufferSize);
cudaMalloc((void**)&outputBuffer, bufferSize);
// ホスト側の一時配列を初期化
cufftComplex *tempArray = (cufftComplex*)malloc(bufferSize);
for (int idx = 0; idx < arraySize; ++idx) {
tempArray[idx].x = static_cast<float>(idx);
tempArray[idx].y = 0.0f;
}
// ホストからデバイスへデータをコピー
cudaMemcpy(inputBuffer, tempArray, bufferSize, cudaMemcpyHostToDevice);
// cuFFTプランを生成(一次元変換)
cufftHandle fftPlan;
cufftPlan1d(&fftPlan, arraySize, CUFFT_C2C, 1);
// 順変換を実行
cufftExecC2C(fftPlan, inputBuffer, outputBuffer, CUFFT_FORWARD);
// プランを破棄
cufftDestroy(fftPlan);
// 計算結果をデバイスからホストへコピー
cudaMemcpy(tempArray, outputBuffer, bufferSize, cudaMemcpyDeviceToHost);
// 結果を出力
printf("変換結果:\n");
for (int idx = 0; idx < arraySize; ++idx) {
printf("[%d] 実部: %f, 虚部: %f\n", idx, tempArray[idx].x, tempArray[idx].y);
}
// メモリを解放
cudaFree(inputBuffer);
cudaFree(outputBuffer);
free(tempArray);
return 0;
}
二次元フーリエ変換(FFT)の実装:
#include <stdio.h>
#include <stdlib.h>
#include <cufft.h>
int main() {
// 行列の高さと幅を定義
const int height = 4;
const int width = 4;
const int totalElements = height * width;
const int bufferSize = sizeof(cufftComplex) * totalElements;
// 入力・出力用ポインタを宣言
cufftComplex *devInput;
cufftComplex *devOutput;
// GPUメモリを確保
cudaMalloc((void**)&devInput, bufferSize);
cudaMalloc((void**)&devOutput, bufferSize);
// ホスト側の一時配列を初期化
cufftComplex *hostBuffer = (cufftComplex*)malloc(bufferSize);
for (int row = 0; row < height; ++row) {
for (int col = 0; col < width; ++col) {
const int linearIdx = row * width + col;
hostBuffer[linearIdx].x = static_cast<float>(row + col);
hostBuffer[linearIdx].y = 0.0f;
}
}
// ホストからデバイスへデータをコピー
cudaMemcpy(devInput, hostBuffer, bufferSize, cudaMemcpyHostToDevice);
// cuFFTプランを生成(二次元変換)
cufftHandle fftPlan;
cufftPlan2d(&fftPlan, height, width, CUFFT_C2C);
// 順変換を実行
cufftExecC2C(fftPlan, devInput, devOutput, CUFFT_FORWARD);
// プランを破棄
cufftDestroy(fftPlan);
// 計算結果をデバイスからホストへコピー
cudaMemcpy(hostBuffer, devOutput, bufferSize, cudaMemcpyDeviceToHost);
// 結果を出力(二次元配列形式)
printf("変換結果:\n");
for (int row = 0; row < height; ++row) {
for (int col = 0; col < width; ++col) {
const int linearIdx = row * width + col;
printf("(%f, %f)\t", hostBuffer[linearIdx].x, hostBuffer[linearIdx].y);
}
printf("\n");
}
// メモリを解放
cudaFree(devInput);
cudaFree(devOutput);
free(hostBuffer);
return 0;
}
三次元フーリエ変換(FFT)の実装:
#include <stdio.h>
#include <stdlib.h>
#include <cufft.h>
int main() {
// 三次元配列の 각 차원을 정의
const int dimX = 4;
const int dimY = 4;
const int dimZ = 4;
const int elementCount = dimX * dimY * dimZ;
const int bufferSize = sizeof(cufftComplex) * elementCount;
// 入力・出力用ポインタを宣言
cufftComplex *gpuBufferIn;
cufftComplex *gpuBufferOut;
// GPUメモリを確保
cudaMalloc((void**)&gpuBufferIn, bufferSize);
cudaMalloc((void**)&gpuBufferOut, bufferSize);
// ホスト側の一時配列を初期化
cufftComplex *cpuTemp = (cufftComplex*)malloc(bufferSize);
for (int x = 0; x < dimX; ++x) {
for (int y = 0; y < dimY; ++y) {
for (int z = 0; z < dimZ; ++z) {
const int idx = (x * dimY + y) * dimZ + z;
cpuTemp[idx].x = static_cast<float>(x + y + z);
cpuTemp[idx].y = 0.0f;
}
}
}
// ホストからデバイスへデータをコピー
cudaMemcpy(gpuBufferIn, cpuTemp, bufferSize, cudaMemcpyHostToDevice);
// cuFFTプランを生成(三次元変換)
cufftHandle fftPlan;
cufftPlan3d(&fftPlan, dimX, dimY, dimZ, CUFFT_C2C);
// 順変換を実行
cufftExecC2C(fftPlan, gpuBufferIn, gpuBufferOut, CUFFT_FORWARD);
// プランを破棄
cufftDestroy(fftPlan);
// 計算結果をデバイスからホストへコピー
cudaMemcpy(cpuTemp, gpuBufferOut, bufferSize, cudaMemcpyDeviceToHost);
// 結果を出力(三次元配列形式)
printf("変換結果:\n");
for (int x = 0; x < dimX; ++x) {
for (int y = 0; y < dimY; ++y) {
for (int z = 0; z < dimZ; ++z) {
const int idx = (x * dimY + y) * dimZ + z;
printf("(%f, %f)\t", cpuTemp[idx].x, cpuTemp[idx].y);
}
printf("\n");
}
printf("---\n");
}
// メモリを解放
cudaFree(gpuBufferIn);
cudaFree(gpuBufferOut);
free(cpuTemp);
return 0;
}