Top > Programming > OpenCL > OpenCLSharp > Tutorial > 2_GetOpenCLPlatformInfo
Last-modified: Sat, 07 Sep 2013 20:28:31 JST
Counter:5569 Today:1 Yesterday:4 Online:11
このエントリーをはてなブックマークに追加

OpenCLプラットフォームの情報を取得する

About

「OpenCLプラットフォームの有無を確認する」から続く内容です。 OpenCL のプラットフォームバージョンによっては、利用できない機能や変更された機能などがあります。またプラットフォームがどのデバイスを利用して処理を実行するのかを確認することも必要です。ここではプラットフォームやそのプラットフォームが利用するデバイスの情報を取得して確認します。

プラットフォームの数とプラットフォームへの参照(≒ID)を取得する

「OpenCLプラットフォームの有無を確認する」では、対象の実行環境下での OpenCL プラットフォームの数を取得するために、'clGetPlatformIDs' 関数を利用しましたが、今回は 'clGetPlatformIDs' 関数を利用してプラットフォーム情報への参照(≒ ID )を取得します。

            int errcode;
            uint platformCount;

            //OpenCLが実行可能なプラットフォームが存在するかどうかを検査します。
            errcode = clGetPlatformIDs(0, null, out platformCount);
            if (errcode != CL_SUCCESS)
                throw new Exception("Error at clGetPlatformIDs : " + errcode);

            //プラットフォームのIDを取得します。
            IntPtr[] platforms = new IntPtr[platformCount];
            clGetPlatformIDs(platformCount, platforms, out platformCount);

プラットフォーム情報の取得

プラットフォームの情報の取得には clGetPlatformInfo 関数を利用します。'clGetPlatformInfo' 関数は、対象のプラットフォームの情報を取得するための関数です。引数は順に次のようになっています。

  1. 対象のプラットフォーム
  2. 取得する情報の値
  3. 取得する情報の値の大きさ
  4. 取得する情報を受け取るインスタンス
  5. out 取得する情報の値の大きさ

ここで'対象のプラットフォーム'は、先に clGetPlatformIDs 関数によって取得したものです。少々分かりにくいですが、情報を取得する手順は、(1)取得する情報の大きさを取得する、(2)実際に情報を取得する、という手順になっています。ここではプラットフォームの情報と、プラットフォームのバージョンを取得して確認します。

    public const int CL_PLATFORM_PROFILE = 0x0900;

    [DllImport(OpenCL)]
    public static extern int clGetPlatformInfo
        (IntPtr platform,
        int param_name,
        uint param_value_size,
        StringBuilder param_value,
        out IntPtr param_value_size_ret);

    foreach (IntPtr platform in platforms)
    {
        uint valueSize;
        StringBuilder value = new StringBuilder();
                    
        //[1]プラットフォームの情報を取得します。
        //データサイズを取得します
        errcode = clGetPlatformInfo(platform, CL_PLATFORM_PROFILE, 0, null, out valueSize);
        if (errcode != CL_SUCCESS)
            throw new Exception("Error at clGetPlatformInfo : " + errcode);
        //データを取得します
        errcode = clGetPlatformInfo(platform, CL_PLATFORM_PROFILE, valueSize, value, out valueSize);
        Console.WriteLine("Platform Profile   : " + value);

        //[2]OpenCLプラットフォームのバージョンを取得します。
        //データサイズを取得します
        errcode = clGetPlatformInfo(platform, CL_PLATFORM_VERSION, 0, null, out valueSize);
        if (errcode != CL_SUCCESS)
            throw new Exception("Error at clGetPlatformInfo : " + errcode);
        //データを取得します
        errcode = clGetPlatformInfo(platform, CL_PLATFORM_VERSION, valueSize, value, out valueSize);
        Console.WriteLine("Platform Version   : " + value);
        …
    }

筆者の実行環境下では、出力結果は次のようになりました。詳細は割愛しますが、プラットフォームは OpenCL の(そのバージョンにおける)完全な機能を提供していて、バージョンは1.2であることが分かります。また提供元は AMD であることもここで確認できます。Profile の値には 'FULL_PROFILE' の他に、一部の機能のみがサポートされていることを示す 'EMBEDDED_PROFILE' もあります。

Platform Profile   : FULL_PROFILE
Platform Version   : OpenCL 1.2 AMD-APP (1084.4)

デバイスの数とデバイスへの参照(≒ID)を取得する

対象の OpenCL プラットフォームが、どのデバイスによって動作するのかを確認します。デバイスの取得には clGetDeviceIDs 関数を利用します。デバイス情報の取得は OpenCL のプラットフォーム情報を取得したのと同じように、まず OpenCL が利用できるデバイスがどれだけあるかを取得して、次にそのデバイスへの参照を取得します。引数は順に(対象のプラットフォーム, デバイスの種類, デバイスの数, デバイスへの参照, out OpenCL が利用できるデバイスの数)となっています。

OpenCL が利用できるデバイスの数が分かったら、'clGetDeviceIDs' 関数を利用してデバイスへの参照を取得します。これはプラットフォームの取得と同じような手順です。

    [DllImport(OpenCL)]
    public static extern int clGetDeviceIDs
        (IntPtr platform,
        uint device_type,
        uint num_entries,
        IntPtr[] devices,
        out uint num_devices);

    //[3]デバイスの情報を取得します。
    //デバイスの数を取得します。
    uint deviceCount;
    errcode = clGetDeviceIDs(platform, CL_DEVICE_TYPE_DEFAULT, 0, null, out deviceCount);
    if (errcode != CL_SUCCESS)
        throw new Exception("Error at clGetDeviceIDs  : " + errcode);
    //デバイスのIDを取得します。
    IntPtr[] devices = new IntPtr[deviceCount];
    errcode = clGetDeviceIDs
                  (platform, CL_DEVICE_TYPE_DEFAULT, deviceCount, devices, out deviceCount);

デバイスの情報を取得する

デバイスの情報の取得には clGetDeviceInfo 関数を利用します。基本的な扱い方はプラットフォーム情報の取得と同様です。'clGetDeviceInfo' 関数は、対象のデバイスの情報を取得するための関数です。引数は順に次にようになっています。

  1. 対象のデバイス
  2. 取得する情報の値
  3. 取得する情報の値の大きさ
  4. 取得する情報を受け取るインスタンス
  5. out 取得する情報の値の大きさ

ここで'対象のプラットフォーム'は、先に clGetDeviceIDs 関数によって取得したものです。情報を取得する手順は clGetPlatformInfo と同様に、(1)取得する情報の大きさを取得する、(2)実際に情報を取得する、というようになっています。ここではデバイスのベンダー(開発メーカ)と、デバイスの名前を取得して確認します。

    public const int CL_DEVICE_NAME = 0x102B;
    public const int CL_DEVICE_VENDOR = 0x102C;

    [DllImport(OpenCL)]
    public static extern int clGetDeviceInfo
        (IntPtr device,
        int param_name,
        uint param_value_size,
        StringBuilder param_value,
        out IntPtr param_value_size_ret);

    foreach (IntPtr device in devices)
    {
        //デバイスの提供元を取得します。
        errcode = clGetDeviceInfo(device, CL_DEVICE_VENDOR, 0, null, out valueSize);
        if (errcode != CL_SUCCESS)
            throw new Exception("Error at clGetDeviceInfo  : " + errcode);
        clGetDeviceInfo(device, CL_DEVICE_VENDOR, valueSize, value, out valueSize);
        Console.WriteLine(" - Device Vendor   : " + value);

        //デバイスの情報(名前)を取得します。
        errcode = clGetDeviceInfo(device, CL_DEVICE_NAME, 0, null, out valueSize);
        if (errcode != CL_SUCCESS)
            throw new Exception("Error at clGetDeviceInfo  : " + errcode);
        clGetDeviceInfo(device, CL_DEVICE_NAME, valueSize, value, out valueSize);
        Console.WriteLine(" - Device Name     : " + value);
    }

出力結果は次のようになります。筆者の OpenCL プラットフォームでは、AMD(Advanced Micro Devices) 社の、Cypress というデバイスを利用することが確認できます。

- Device venvor  : Advanced Micro Devices, Inc.
- Device name    : Cypress

補足情報

サンプルプログラムだけでは把握できない内容を、ここで補足します。

OpenCL に定義される定数値について

ここであつかう、CL_SUCCESS や CL_PRATFORM_PROFILE などといった、OpenCL に定義される定数の種類とその値は、OpenCL のヘッダファイル "cl.h" などから確認することができます。ヘッダファイルの内容や、ヘッダファイルが配置される場所は、インストールされる OpenCL の開発環境などに依存します。例えば AMD(Radeon-ATI) 系の場合、[ローカルディスク(C:) > Program Files(x86) > AMD APP > CL] などに配置されます。

他に Web に掲載されている情報を参照するという手段があります。物理エンジン 'Bullet' のリファレンスなどから確認するのが分かりやすいと思います。

void*、StringBuilder、valueSize について

DLLImport によって OpenCL.dll に実装される関数を C# から利用できるように定義するとき、引数の型が "void*" とされるものを、ここでは "StringBuilder" 型としています。例えば、clGetPlatformInfo 関数などがこれに該当します。clGetPlatformInfo のリファレンスを参照すると、void* 型ではあるものの、指定した引数( param_value )には、char[] 型の値が入ることが分かります。ここではなぜ DLLImport によって関数を定義するときに、該当する引数の型を char[] にしていないのか、について解説します。

C (言語)の char 型と、C# の char 型の違いに注目します。C の char は 8bit ですが、C# の char は 16bit です。C# で 8bit の値を扱うときには byte 型を用います。したがって、DLLImport によって clGetPlatformInfo などの関数を定義するとき、char[] 型を用いることができません。ここでは結果的に StringBuilder を利用していますが、もしも元の定義である char[] の形式で揃えるときには、byte[] 型で関数を定義し、データを受け取るようにします。

サンプルプログラムで、変数 valueSize が一度も具体的には利用されていない理由もここにあります。byte[] 型でデータを受け取るとき、byte[] 型の配列の長さを指定することと、byte[] 型で受け取った文字列を出力するときとに、valueSize すなわち、"配列の長さ = char[] の長さ = 値の大きさ"の情報が必要になります。しかしながら、ここでは StringBuilder を利用しているので、valueSize の役目が目立たないわけです。

ここで StringBuilder を利用する理由は、byte[] でデータを受取ってそこから文字列を取得するよりも、手続きが少ないためです。詳細の解説については割愛しますが、C (アンマネージ)における char* (LPSTR) に対応する型は、C# (マネージ)では、StringBuilder とされています。これについては、参考になりそうなリンクをいくつか紹介しておきます。

ちなみに、StringBuilder で引き数を定義する場合も、byte[] で引数を定義する場合も、参照渡しであるために、outキーワードは不要です。