インテル® FPGA SDK for OpenCL™プロ・エディション: プログラミング・ガイド

ID 683846
日付 4/01/2019
Public
ドキュメント目次

8.7. ハードウェアとエミュレーターの結果の不一致

カーネルをエミュレーションすると、OpenCLシステムは、ハードウェアにコンパイルされたカーネルとは異なる結果を生成することがあります。シミュレーションでカーネルを実行することで、ハードウェアにカーネルをコンパイルする前にさらにカーネルをデバッグすることが可能です。

警告: この結果における不一致は、インテル FPGA SDK for OpenCL Emulatorがハードウェアの計算の一部を正確にモデル化できない場合、またはプログラムが未定義の動作に依存している場合に通常発生します。

エミュレーターとハードウェアの結果の不一致を引き起こす最も一般的な理由は次のとおりです。

  • OpenCLカーネルコードが#pragma ivdepディレクティブを使用している。エミュレーターは、真の依存関係がpragma ivdepディレクティブによって壊されている場合、OpenCLシステムをモデル化しません。ハードウェアをフルコンパイルする際に、これは誤った結果として考えられます。
  • OpenCLカーネルコードが、初期化されていないデータに依存している。初期化されていないデータとは、初期化されていない変数、初期化されていない、または部分的に初期化されたグローバルバッファー、ローカル配列、プライベート配列などです。
  • OpenCLカーネルコードの動作が、正確な浮動小数点演算の結果に依存している。エミュレーターがCPUの浮動小数点計算ハードウェアを使用する一方で、ハードウェアの実行にはFPGAコアとして実装されている浮動小数点コアが使用されます。-fp-relaxedのaocオプションをOpenCLカーネルコードに使用すると、演算の順序が変わり、浮動小数点の計算結果がさらに変動する可能性があります。
    注: OpenCLの標準は、各プラットフォームの浮動小数点計算の最下位ビットが1つ以上異なることを許容します。一方でそれは、どのプラットフォームでも正しいと見なされます。
  • OpenCLカーネルコードの動作が、異なるカーネルのチャネルアクセスの順序に依存している。チャネル動作のエミュレーションには制限があります。特に、カーネルがループの反復ごとにチャネル動作を呼び出さない条件付きのチャネル動作の場合に当てはまります。このような場合にエミュレーターは、ハードウェアとは異なる順序でチャネル動作を実行することがあります。
  • OpenCLカーネルまたはホストコードが、範囲外のグローバルメモリーにアクセスしている。
    重要:
    • 初期化されていないメモリーの読み取りおよび書き込み動作は、プラットフォームに依存します。カーネル内のすべてのアドレスを使用している場合、clCreateBuffer関数呼び出しを割り当てている場合、clEnqueueReadBufferclEnqueueWriteBuffer関数呼び出しを転送している場合は、グローバルメモリーのバッファーサイズを確認してください。
    • Valgrindなどのソフトウェア・メモリー・リーク検出ツールをエミュレーションされたバージョンのOpenCLシステムで使用すると、メモリーに関する問題を分析できます。これらのツールからの警告がないということは、問題がないということを意味するわけではありません。これは単に、ツールが問題を検出できなかったことを意味するだけです。インテルではこのような状況において、OpenCLカーネルまたはホストコードの手動検証を推奨しています。
  • OpenCLカーネルコードが、範囲外のローカルまたはプライベート変数にアクセスしている。例えば、範囲外のローカルまたはプライベート配列にアクセスしている場合や、スコープ外になったプライベート変数にアクセスしている場合です。
    重要: 範囲外の変数へのアクセスは、通常ソフトウェアのスタックにおいて、アクセスされている変数付近の無関係な変数に影響を及ぼすため、これらの問題はソフトウェア用語でスタックの破損問題と呼ばれています。エミュレーションされたOpenCLカーネルは、通常のCPU機能として実装されており、破損する可能性のあるスタックを実際に持っています。ハードウェアをターゲットにしている場合はスタックが存在しないため、スタックの破損問題は必ず別の形で現れます。スタックの破損が疑われる場合は、Valgrindなどのメモリーリーク検証ツールを使用することが可能ですが、スタック関連の問題の特定は通常困難です。インテルでは、スタック関連の問題をデバッグするため、OpenCLカーネルコードを手動で検証することを推奨しています。
  • OpenCLカーネルコードが、シフトされる型よりも大きいシフトを使用している。例えば64ビットの整数を65ビットでシフトしている場合などです。OpenCL specification version 1.0によると、このようなシフトの動作は未定義です。
  • エミュレーションに向けてOpenCLカーネルをコンパイルする際のデフォルトのチャネル深度が、カーネルがハードウェアにコンパイルされる際に生成されるデフォルトのチャネル深度と異なる。このチャネル深度の相違は、カーネルのエミュレーションは問題なく機能する一方で、ハードウェアでの実行はハングアップするという状況を引き起こす可能性があります。チャネル深度の相違を修正する方法については、チャネル深度のエミュレーション を参照してください。
  • 出力されるラインの順序に関しては、printf関数で出力される順序がエミュレーターとハードウェアで異なる場合があります。これは、ハードウェアにおいてprintfデータはグローバル・メモリー・バッファーに格納され、カーネルの実行が完了した際、またはバッファーがフルになった際にのみバッファーからフラッシュされるためです。エミュレーターのprintf関数は、x86 stdoutを使用しています。
  • 型のアップキャストでアライメントされていないロードやストアを実行すると、FPGAとエミュレーターでは異なる結果が生じる可能性があります。この型のロードおよびストアは、C99の仕様では定義されていません。
    次例のような演算では、予期しない結果になる可能性があります。
    int tmp = *((int *) (my_ptr + 5));