2016-12-14 4 views
2

ソースコードで配布したくないノウハウを含むコードがあります。解決策の1つは、あらかじめコンパイルされたカーネルを用意し、ユーザーのハードウェアに応じて正しいバイナリを選択することです。独自のコードを配布するためにバイナリカーネルを収集する方法

私はオフラインコンパイラを実行する必要があるバイナリと最小限のマシンで、ほとんどのユーザー(AMDとIntel、CUDAコードを使用できるため、AMDとIntel)をカバーする方法はありますか?同じバイナリを使用できるGPUファミリはありますか? CUDAコンパイラは異なるアーキテクチャでコンパイルできますが、OpenCLはどうでしょうか?バイナリ互換性データは十分に文書化されていないようですが、おそらく誰かがこれらのデータを自分で収集しました。

SPIRがあることは分かっていますが、古いハードウェアではサポートされていません。

私の実装の詳細は、誰かがこの質問を見つけて私がしたことがなかった場合です。私は、ファイルにカーネルをコンパイルするツールを作った後、私は、メインアプリケーションに含まれるCの配列にすべてのこれらのバイナリを収集:

const char* binaries[] = { //kernels/HD Graphics 4000 "\x62\x70\x6c\x69\x73\x74\x30\x30\xd4\x01\x02\x03" "\x04\x05\x06\x07\x08\x5f\x10\x0f\x63\x6c\x42\x69" "\x6e\x61\x72\x79\x56\x65\x72\x73\x69\x6f\x6e\x5c" ... "\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x47\xe0" , //here more kernels }; size_t binaries_sizes[] = { 204998, 205907, ... };

そして私は、すべての反復処理し、次のコードを使用しますカーネル(私はおそらくよりよい解決策があるか、正常にビルド最初のカーネルを選択する、試行錯誤より巧妙なものを発明しなかった):

int e3 = -1; int i = 0; while (e3 != CL_SUCCESS) { if (i == lenof(binaries)) { throw Error(); } program = clCreateProgramWithBinary(context, 1, &deviceIds[devIdx], &binaries_sizes[i], (const unsigned char**)&binaries[i], nullptr, &e3); if (e3 != CL_SUCCESS) { ++i; continue; } int e4 = clBuildProgram(program, 1, &deviceIds[devIdx], "", nullptr, nullptr); e3 = e4; ++i; }

答えて

2

残念ながら、あなたの問題のための標準的な解決策はありません。 OpenCLはプラットフォームに依存しないため、この問題に対処する標準的な方法はありません(SPIRとは別)。各ベンダーは内部的に異なるコンパイラツールチェインを決定しますが、同じドライバの複数のバージョン間で、または異なるデバイス間で変更することもできます。

コンパイルしたプラットフォームを特定するために、いくつかのメタデータをカーネルに追加することができます。これにより、試行錯誤の部分が省かれます(つまり、バイナリとbinaries_sizeを保存するのではなく、バイナリデバイスを読み込み、それらの配列を繰り返してロードするバイナリを調べます)。

あなたにとって最適なソリューションは、OpenCLドライバが実際のアーキテクチャ命令セットに「再コンパイル」できる中間表現であるSPIR(または新しいSPIRV)です。 バイナリをSPIRVに保存し、いくつかのコンパイラマジックに関する知識があれば、トランスレータツールを使用してLLVM-IRを取得し、LLVMを使用してAMDやPTXなどの他のプラットフォームにコンパイルすることができますインフラストラクチャ(https://github.com/KhronosGroup/SPIRV-LLVM参照)

関連する問題