Main Content

このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。

GPU コード生成: マンデルブロ集合

この例では、GPU Coder™ を使用して簡単な MATLAB® 関数から CUDA® コードを生成する方法を説明します。標準の MATLAB コマンドを使用したマンデルブロ集合の実装は、エントリポイント関数として機能します。この例では、codegen コマンドを使用して、GPU で実行される MEX 関数を生成します。この MEX 関数を実行して実行時エラーをチェックすることができます。

サードパーティの必要条件

必須

この例では、CUDA MEX を生成します。以下のサードパーティ要件が適用されます。

  • CUDA 対応 NVIDIA® GPU および互換性のあるドライバー。

オプション

スタティック ライブラリ、ダイナミック ライブラリ、または実行可能ファイルなどの MEX 以外のビルドについて、この例では以下の要件も適用されます。

GPU 環境の検証

この例を実行するのに必要なコンパイラおよびライブラリが正しく設定されていることを検証するために、関数 coder.checkGpuInstall を使用します。

envCfg = coder.gpuEnvConfig('host');
envCfg.BasicCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);

マンデルブロ集合

マンデルブロ集合とは、値 $z_0$ で構成された複素平面の領域であり、この値は

$$z_{k+1} = {z_k}^2 + z_0, k = 0,1,...$$

で定義された軌跡が $k\rightarrow\infty$ のときに有限の範囲内にとどまるときの値です。マンデルブロ集合の全体的な幾何形状を図に示しています。この図には、集合の境界の外側周辺における詳しい構造を十分に示すための解像度がありません。

入力領域の定義

メインのカージオイドとその左側にある $p/q$ 球状部との谷間にある、マンデルブロ集合の大きく拡大された部分を指定する一連の範囲を選択します。これらの 2 つの範囲間に、$Re\{x\}$$Im\{y\}$1000x1000 のグリッドを作成します。次に、マンデルブロ アルゴリズムを各グリッド位置で反復します。完全な解像度のイメージをレンダリングするには 500 回の反復回数で十分です。

maxIterations = 500;
gridSize = 1000;
xlim = [-0.748766713922161, -0.748766707771757];
ylim = [ 0.123640844894862,  0.123640851045266];

x = linspace( xlim(1), xlim(2), gridSize );
y = linspace( ylim(1), ylim(2), gridSize );
[xGrid,yGrid] = meshgrid( x, y );

マンデルブロ エントリポイント関数

エントリポイント関数 mandelbrot_count.m には、電子書籍『Experiments with MATLAB』(Cleve Moler 著) で提供されているコードに基づくマンデルブロ集合のベクトル化された実装が含まれています。%#codegen 命令は、MATLAB のコード生成エラー チェックをオンにします。GPU Coder は coder.gpu.kernelfun プラグマを検出すると、この関数内のすべての計算を並列化し、その計算を GPU にマッピングしようとします。

type mandelbrot_count
function count = mandelbrot_count(maxIterations, xGrid, yGrid) %#codegen

% Copyright 2016-2019 The MathWorks, Inc. 

z0 = xGrid + 1i*yGrid;
count = ones(size(z0));

% Map computation to GPU.
coder.gpu.kernelfun;

z = z0;
for n = 0:maxIterations
    z = z.*z + z0;
    inside = abs(z)<=2;
    count = count + inside;
end
count = log(count);

mandelbrot_count の機能のテスト

前に生成した xGrid 値と yGrid 値を指定して関数 mandelbrot_count を実行し、その結果をプロットします。

count = mandelbrot_count(maxIterations, xGrid, yGrid);

figure(2), imagesc( x, y, count );
colormap( [jet();flipud( jet() );0 0 0] );
title('Mandelbrot Set on MATLAB');
axis off

関数の CUDA MEX の生成

関数 mandelbrot_count の CUDA MEX を生成するには、GPU コード構成オブジェクトを作成し、codegen コマンドを実行します。CPU と GPU ではアーキテクチャが異なるため、数値検証が常に一致するとは限りません。このシナリオは、single データ型を MATLAB コードで使用し、これらの single データ型の値に対して累積演算を実行する場合に当てはまります。このマンデルブロの例のように、double データ型であっても数値誤差の原因になり得ます。この不一致が発生する 1 つの原因は、GPU の浮動小数点単位では融合浮動小数点積和演算 (FMAD) 命令が使用され、CPU ではこれらの命令が使用されないためです。nvcc コンパイラに渡される fmad=false オプションにより、この FMAD 最適化はオフになります。

cfg = coder.gpuConfig('mex');
cfg.GpuConfig.CompilerFlags = '--fmad=false';
codegen -config cfg -args {maxIterations,xGrid,yGrid} mandelbrot_count
Code generation successful: To view the report, open('codegen/mex/mandelbrot_count/html/report.mldatx').

MEX 関数の実行

MEX 関数を生成した後に、その関数に元の MATLAB エントリポイント関数と同じ機能があることを検証します。生成された mandelbrot_count_mex を実行し、結果をプロットします。

countGPU = mandelbrot_count_mex(maxIterations, xGrid, yGrid);

figure(2), imagesc( x, y, countGPU );
colormap( [jet();flipud( jet() );0 0 0] );
title('Mandelbrot Set on GPU');
axis off

まとめ

マンデルブロ集合を実装する簡単な MATLAB 関数の CUDA コードを生成しました。実装は、coder.gpu.kernelfun プラグマを使用し、codegen コマンドを呼び出して MEX 関数を生成することにより実現しました。NVIDIA コンパイラで実行される FMAD 最適化を無効にするために、追加のコンパイラ フラグ FMAD=false を nvcc コンパイラに渡しました。