Main Content

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

CUDA 生成コードのパフォーマンス解析

この例では、関数 gpuPerformanceAnalyzer を使用して、CUDA® 生成コードのパフォーマンスを解析して最適化する方法を示します。

関数 gpuPerformanceAnalyzer は、生成されたコード内の CPU と GPU のアクティビティに関するメトリクスを収集するソフトウェアインザループ (SIL) 実行を行います。関数は、CUDA 生成コードのパフォーマンス ボトルネックを可視化し、特定し、緩和するために使用できる時系列のタイムライン プロットを含むレポートを提供します。

この例では、GPU Coder の "霧の修正" の例で使用するためのパフォーマンス アナライザー レポートを生成します。詳細については、霧の修正を参照してください。

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

  • CUDA 対応 NVIDIA® GPU。

  • NVIDIA CUDA Toolkit およびドライバー。サポートされているコンパイラおよびライブラリのバージョンの詳細については、サードパーティ ハードウェアを参照してください。

  • コンパイラおよびライブラリの環境変数。環境変数の設定については、前提条件となる製品の設定を参照してください。

  • GPU パフォーマンス カウンターにアクセスする権限。CUDA Toolkit v10.1 以降では、NVIDIA はパフォーマンス カウンターへのアクセスを管理者ユーザーのみに制限します。GPU パフォーマンス カウンターをすべてのユーザーに対して有効にするには、Permission issue with Performance Counters (NVIDIA) に記載されている手順を参照してください。

GPU 環境の検証

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

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

coder.gpuEnvConfig オブジェクトの Quiet プロパティが true に設定されている場合、関数 coder.checkGpuInstall は警告メッセージまたはエラー メッセージのみを返します。

霧修正のアルゴリズム

霧のかかった入力イメージを改善するために、アルゴリズムでは霧の除去とコントラストの強調を実行します。図は、これら両方の演算手順を示しています。

この例では、霧のかかった RGB イメージを入力として受け取ります。霧の除去を実行するために、アルゴリズムではイメージのダーク チャネルを推定し、ダーク チャネルに基づいて大気光マップを計算し、フィルターを使用して大気光マップを調整します。復元段階で、入力イメージから調整済みの大気光マップを差し引くことにより、霧が取り除かれたイメージを作成します。

次に、アルゴリズムはイメージ内の強度値の範囲を評価し、コントラスト ストレッチを使用して値の範囲を拡大し、特徴をより明確に際立たせることでコントラストを強化します。

FogRectificationAlgorithm.png

type fog_rectification.m
function [out] = fog_rectification(input) %#codegen
%

%   Copyright 2017-2023 The MathWorks, Inc.

coder.gpu.kernelfun;

% restoreOut is used to store the output of restoration
restoreOut = zeros(size(input),"double");

% Changing the precision level of input image to double
input = double(input)./255;

%% Dark channel Estimation from input
darkChannel = min(input,[],3);

% diff_im is used as input and output variable for anisotropic diffusion
diff_im = 0.9*darkChannel;
num_iter = 3;

% 2D convolution mask for Anisotropic diffusion
hN = [0.0625 0.1250 0.0625; 0.1250 0.2500 0.1250; 0.0625 0.1250 0.0625];
hN = double(hN);

%% Refine dark channel using Anisotropic diffusion.
for t = 1:num_iter
    diff_im = conv2(diff_im,hN,"same");
end

%% Reduction with min
diff_im = min(darkChannel,diff_im);

diff_im = 0.6*diff_im ;

%% Parallel element-wise math to compute
%  Restoration with inverse Koschmieder's law
factor = 1.0./(1.0-(diff_im));
restoreOut(:,:,1) = (input(:,:,1)-diff_im).*factor;
restoreOut(:,:,2) = (input(:,:,2)-diff_im).*factor;
restoreOut(:,:,3) = (input(:,:,3)-diff_im).*factor;
restoreOut = uint8(255.*restoreOut);

%%
% Stretching performs the histogram stretching of the image.
% im is the input color image and p is cdf limit.
% out is the contrast stretched image and cdf is the cumulative prob.
% density function and T is the stretching function.

% RGB to grayscale conversion
im_gray = im2gray(restoreOut);
[row,col] = size(im_gray);

% histogram calculation
[count,~] = imhist(im_gray);
prob = count'/(row*col);

% cumulative Sum calculation
cdf = cumsum(prob(:));

% Utilize gpucoder.reduce to find less than particular probability.
% This is equal to "i1 = length(find(cdf <= (p/100)));", but is more GPU
% friendly.

% lessThanP is the preprocess function that returns 1 if the input value
% from cdf is less than the defined threshold and returns 0 otherwise.
% gpucoder.reduce then sums up the returned values to get the final count.
i1 = gpucoder.reduce(cdf,@plus,"preprocess", @lessThanP);
i2 = 255 - gpucoder.reduce(cdf,@plus,"preprocess", @greaterThanP);

o1 = floor(255*.10);
o2 = floor(255*.90);

t1 = (o1/i1)*[0:i1];
t2 = (((o2-o1)/(i2-i1))*[i1+1:i2])-(((o2-o1)/(i2-i1))*i1)+o1;
t3 = (((255-o2)/(255-i2))*[i2+1:255])-(((255-o2)/(255-i2))*i2)+o2;

T = (floor([t1 t2 t3]));

restoreOut(restoreOut == 0) = 1;

u1 = (restoreOut(:,:,1));
u2 = (restoreOut(:,:,2));
u3 = (restoreOut(:,:,3));

% replacing the value from look up table
out1 = T(u1);
out2 = T(u2);
out3 = T(u3);

out = zeros([size(out1),3], "uint8");
out(:,:,1) = uint8(out1);
out(:,:,2) = uint8(out2);
out(:,:,3) = uint8(out3);
end

function out = lessThanP(input)
p = 5/100;
out = uint32(0);
if input <= p
    out = uint32(1);
end
end

function out = greaterThanP(input)
p = 5/100;
out = uint32(0);
if input >= 1 - p
    out = uint32(1);
end
end

GPU パフォーマンス アナライザー レポートの生成

関数 gpuPerformanceAnalyzer を使用して生成コードのパフォーマンスを解析するには、入力引数 dll を使用し、ダイナミック ライブラリ ビルド タイプでコード構成オブジェクトを作成します。関数 gpuPerformanceAnalyzer は Embedded Coder™ 構成オブジェクトのみを受け入れるため、coder.EmbeddedCodeConfig 構成オブジェクトを作成するオプションを有効にします。

cfg = coder.gpuConfig("dll","ecoder",true);

既定の反復回数 2 で gpuPerformanceAnalyzer を実行します。

inputImage = imread("foggyInput.png");
inputs  = {inputImage};
designFileName = "fog_rectification";

gpuPerformanceAnalyzer(designFileName, inputs, ...
    "Config", cfg, "NumIterations", 2);
### Starting GPU code generation
Code generation successful: View report

### GPU code generation finished
### Starting application profiling
### Starting SIL execution for 'fog_rectification'
    To terminate execution: clear fog_rectification_sil
### Application stopped
### Stopping SIL execution for 'fog_rectification'
### Application profiling finished
### Starting profiling data processing
### Profiling data processing finished
### Showing profiling data

codegen を使用したパフォーマンス アナライザー レポートの生成

codegen コマンドの -gpuprofile オプションを使用すると、GPU プロファイリングを有効にして、GPU パフォーマンス アナライザー レポートを作成することができます。

次に例を示します。

codegen -config cfg -gpuprofile fog_rectification.m -args inputs

コード生成が完了すると、ソフトウェアは実行可能ファイル fog_rectification_sil を生成します。SIL 実行可能ファイルを実行します。

fog_rectification_sil(inputImage);

MATLAB コマンド ウィンドウで clear fog_rectification_sil のリンクをクリックします。GPU パフォーマンス アナライザー レポートは、SIL 実行可能ファイルを終了した後、利用可能になります。次に例を示します。

### Application stopped
### Stopping SIL execution for 'fog_rectification'
### Starting profiling data processing
### Profiling data processing finished
    Open GPU Performance Analyzer report: open('/home/test/gpucoder-ex87489778/codegen/dll/fog_rectification/html/gpuProfiler.mldatx')

GPU パフォーマンス アナライザー レポート

GPU パフォーマンス アナライザー レポートには、GPU と CPU のアクティビティ、イベント、パフォーマンス メトリクスが時系列のタイムライン プロットで一覧表示されます。これらは、CUDA 生成コードのパフォーマンス ボトルネックを可視化し、特定し、対処するために使用できます。

これらの数値は代表的なものです。実際の値はハードウェア設定によって異なります。この例のプロファイリングは、6 コアの 3.5GHz Intel® Xeon® CPU および NVIDIA TITAN XP GPU を搭載したマシンで MATLAB® R2023b を使用して行われました。

プロファイリング タイムライン

プロファイリング タイムラインには、実行時間がしきい値を上回るすべてのイベントの完全なトレースが表示されます。次のイメージは、しきい値が 0.0 ms に設定されている場合のプロファイリング トレースのスニペットを示しています。

マウス ホイールまたは同等のタッチパッド オプションを使用して、タイムラインのズーム レベルを制御できます。あるいは、パネル上部にあるタイムラインの概要を使用して、ズーム レベルを制御したり、タイムライン プロットを操作したりすることもできます。

各イベントのツールヒントは、CPU と GPU 上での選択されたイベントの開始時間、終了時間、および持続時間を示します。ツールヒントは、CPU でカーネルが起動されてから GPU で実際にカーネルが実行されるまでの経過時間も示します。

各イベントで右クリック コンテキスト メニューを使用して、CPU イベントと対応する GPU イベントの間でトレースを追加します。右クリック メニューを使用して、コード ペイン上のイベントに対応する CUDA 生成コードを表示することもできます。

イベント統計

イベント統計ペインには、選択したイベントの追加情報が表示されます。たとえば、fog_rectification_kernel1 は次の統計を示します。

2023-06-22_13-49-57.png

洞察

洞察ペインには、GPU と CPU のアクティビティの概要を示す円グラフが含まれます。円グラフは、プロファイリング タイムラインのズーム レベルに応じて変化します。次のイメージは、洞察のスニペットを示しています。タイムラインで選択された領域内で、GPU 使用率がわずか 13% であることを示しています。

2023-06-22_14-15-34.png

コードのトレース

コード ペインを使用して、MATLAB コードから CUDA コードへのトレース、または CUDA コードから MATLAB コードへのトレースを行うことができます。追跡可能なコードは、トレース元が青色、トレース先がオレンジ色でマークされます。移動しながら、追跡可能なコードをポイントすると、ペインでそのコードが紫色で強調表示され、対応するもう一方のコードがトレースされます。コード セクションを選択すると、ペインではコードが黄色で強調表示されます。コードは、"Esc" を押すか、別のコードを選択するまで、選択されたままになります。トレース元を変更するには、もう一方のコードを選択します。

トレースを調べるには、プロファイリング タイムラインの CPU 行で fog_rectification_kernel2 イベントを右クリックし、[生成されたコードの表示] を選択します。このアクションにより、fog_rectification.cu ファイル内のカーネル呼び出しステートメント fog_rectification_kernel2<<< >>> が強調表示されます。

CUDA コードで、1142 行目で始まる fog_rectification_loop_0 for ループをポイントし、for ループ全体が表示されるまで下にスクロールします。

次の記号は、強調表示された CUDA コードに表示されていないトレースが 1 つあることを示しています。対応する MATLAB コードが MATLAB コード ペインの別のウィンドウに表示されます。

2023-06-22_18-36-35.png

MATLAB コード ペインで、for ループに対応する MATLAB コードが表示されるまで下にスクロールします。

選択をクリアするには、"Esc" を押すか、別のコードを選択します。

対応するソース内または生成コード内の複数の場所をコードがトレースする場合:

  • トレースしているコードの上で一時停止すると、コード ペインの上部にトレースの数が表示されます。

  • 一部のトレースが表示されていない場合は、表示されていないトレースの数を示す記号が表示されます。

2023-06-22_18-41-07.png

  • トレースするコードをコード ペインで選択した場合、表示するトレースをコード ペインの上部で選択することができます。

2023-06-22_18-42-09.png

呼び出しツリー

このセクションでは、CPU から呼び出される GPU イベントを一覧表示します。呼び出しツリーの各イベントには、呼び出し元関数の実行時間が割合として一覧表示されます。このメトリクスは、生成されたコードのパフォーマンス ボトルネックを特定するのに役立ちます。呼び出しツリーで対応するイベントをクリックして、プロファイリング タイムラインの特定のイベントに移動することもできます。

フィルター

このセクションでは、レポートのフィルター処理オプションを提供します。

  • ビュー モード — アプリケーション全体 (初期化と終了を含む) または設計関数 (初期化と終了なし) のプロファイリング結果を表示します。

  • イベントしきい値 — 指定されたしきい値より短いイベントをスキップします。

  • メモリの割り当て/解放 — GPU デバイスのメモリ割り当てと割り当て解除に関連するイベントを CPU アクティビティ バーに表示します。

  • メモリ転送 — ホストからデバイス、およびデバイスからホストへのメモリ転送を表示します。

  • カーネル — CPU カーネルの起動と GPU カーネルのアクティビティを表示します。

  • その他 — 同期や GPU の待機など、その他の GPU 関連イベントを表示します。

霧修正のパフォーマンス改善

パフォーマンス アナライザーのレポートから、実行時間のかなりの部分がメモリの割り当てと割り当て解除に費やされていることがわかります。パフォーマンスを改善するには、GPU メモリ マネージャーをオンにして、解析を再度実行します。

GPU メモリ マネージャーは、大きな GPU メモリ プールのコレクションを作成し、これらのプール内のメモリ ブロックのチャンクの割り当ておよび割り当て解除を管理します。大きなメモリ プールを作成することにより、メモリ マネージャーは CUDA のメモリ API に対する呼び出し回数を減らして、実行時のパフォーマンスを向上させます。

cfg.GpuConfig.EnableMemoryManager = true;
gpuPerformanceAnalyzer(designFileName, inputs, ...
    'Config', cfg, 'NumIterations', 2, 'OutFolder',"improvedAlg");
### Starting GPU code generation
Code generation successful: View report

### GPU code generation finished
### Starting application profiling
### Starting SIL execution for 'fog_rectification'
    To terminate execution: clear fog_rectification_sil
### Application stopped
### Stopping SIL execution for 'fog_rectification'
### Application profiling finished
### Starting profiling data processing
### Profiling data processing finished
### Showing profiling data

参考

関数

オブジェクト

関連するトピック