OpenCLでは並列計算をしてくれるハードウェアのことをデバイスといいます。
例外はあるもののこれはまずGPUのことだと考えて間違い有りません(実はCPUでもいいのですが)。
デバイス=GPUです。
GPUで並列計算するためには、下準備としてPCに付いているGPUを列挙する必要があります。
今回はGPU、OpenCLの用語で言うとデバイスを列挙、情報を表示する方法をメモします。
プラットフォームからデバイスを取得
前回出てきたプラットフォームは、GPUのメーカーを表すようなものでした。
今回扱うデバイスは、そのメーカーの作ったGPUのことです。
プラットフォームから、デバイスを取得できるのです(生産者から製品を)。
それにはclGetDeviceIDs関数を使います。
参考
cl_int clGetDeviceIDs(
cl_platform_id platform,
cl_device_type device_type,
cl_uint num_entries,
cl_device_id *devices,
cl_uint *num_devices
)
platformは取得するデバイスのプラットフォームです。
device_typeは取得するデバイスの種類。具体的には以下の5つから選びます。
cl_device_type |
値 |
解説 |
CL_DEVICE_TYPE_CPU |
(1 << 1) |
CPUです。 |
CL_DEVICE_TYPE_GPU |
(1 << 2) |
GPUです。 |
CL_DEVICE_TYPE_ACCELERATOR |
(1 << 3) |
IBM CELL(PS3に使われている)などです。 |
CL_DEVICE_TYPE_DEFAULT |
(1 << 0) |
デフォルトのデバイスです。 |
CL_DEVICE_TYPE_ALL |
0xFFFFFFFF |
使用可能な全てのOpenCLデバイスです。 |
num_entriesは結果を格納する引数devicesの配列の長さです。もしdevicesがNULLでなかったら、この引数は0より大きくなければいけません。
devicesはこの関数の結果を格納します。もしこの値がNULLなら、この引数は無視されます。
num_devicesは使用可能なデバイスの数を返します。この値がNULLならば、この引数は無視されます。
戻り値
名前 |
値 |
解説 |
CL_SUCCESS |
0 |
関数が成功しました。 |
CL_INVALID_PLATFORM |
-32 |
platformが無効な値です。 |
CL_INVALID_DEVICE_TYPE |
-31 |
device_typeが無効な値です。 |
CL_INVALID_VALUE |
-30 |
num_entriesが0なのにdevicesがNULLではありません。あるいは、num_devicesとdevicesが両方共NULLです。 |
CL_DEVICE_NOT_FOUND |
-1 |
device_typeで指定されたタイプのデバイスが存在しません。 |
CL_OUT_OF_RESOURCES |
-5 |
デバイスでリソースを確保するのに失敗しました。 |
CL_OUT_OF_HOST_MEMORY |
-6 |
メモリが足りません。 |
デバイスの列挙
では早速clGetDeviceIDs()を使ってみましょう。
システムにインストールされたGPU(正確にはデバイス)を列挙します。
Program.cs
using System;
class Program
{
static void Main()
{
foreach (var platform in getPlatforms())
{
foreach (var device in getDevices(platform, DeviceType.Default))
{
Console.WriteLine(device);
}
}
}
private static IntPtr[] getDevices(IntPtr platform, DeviceType deviceType)
{
int deviceCount;
OpenCLFunctions.clGetDeviceIDs(platform, deviceType, 0, null, out deviceCount);
IntPtr[] result = new IntPtr[deviceCount];
OpenCLFunctions.clGetDeviceIDs(platform, deviceType, deviceCount, result, out deviceCount);
return result;
}
private static IntPtr[] getPlatforms()
{
int platformCount;
OpenCLFunctions.clGetPlatformIDs(0, null, out platformCount);
IntPtr[] result = new IntPtr[platformCount];
OpenCLFunctions.clGetPlatformIDs(platformCount, result, out platformCount);
return result;
}
}
OpenCLFunctions.cs
using System;
using System.Runtime.InteropServices;
static class OpenCLFunctions
{
[DllImport("OpenCL.dll")]
public static extern int clGetPlatformIDs(int entryCount, IntPtr[] platforms, out int platformCount);
[DllImport("OpenCL.dll")]
public static extern int clGetDeviceIDs(
IntPtr platform,
DeviceType deviceType,
int entryCount,
IntPtr[] devices,
out int deviceCount
);
}
enum DeviceType:long
{
Default = (1 << 0),
Cpu = (1 << 1),
Gpu = (1 << 2),
Accelerator = (1 << 3),
All = 0xFFFFFFFF
}
実行結果は、私の環境ではこうなりました:
82646520
108450576
うーん意味不明ですね。
これが意味するのはシステムにGPUが2つ付いているということです。
他の環境では数字は一つしか表示されないかもしれません。
しかし数字が表示されるだけというのはなんとも無機質です。
GPUの名前が表示されたらいいのですが…
デバイスの情報
デバイスのIDからその名前や各種情報を取得する関数があります。
それがclGetDeviceInfo()関数です。
参考
cl_int clGetDeviceInfo(
cl_device_id device,
cl_device_info param_name,
size_t param_value_size,
void *param_value,
size_t *param_value_size_ret
)
deviceは情報を取得するデバイスです。clGetDeviceIDs関数によって返された値を使います。
param_nameは情報のタイプを表す列挙型です。膨大な種類があります。詳細は以下の表に。
param_value_sizeはparam_valueにセットするメモリのサイズです。
param_valueはこの関数の結果を格納するメモリです。
param_value_size_retは情報の実際のサイズです。NULLならば無視されます。
cl_device_info |
型 |
値 |
|
CL_DEVICE_ADDRESS_BITS |
cl_uint |
0x100D |
|
CL_DEVICE_AVAILABLE |
cl_bool |
0x1027 |
|
CL_DEVICE_COMPILER_AVAILABLE |
cl_bool |
0x1028 |
|
CL_DEVICE_DOUBLE_FP_CONFIG |
cl_device_fp_config |
0x1032 |
|
CL_DEVICE_ENDIAN_LITTLE |
cl_bool |
0x1026 |
|
CL_DEVICE_ERROR_CORRECTION_SUPPORT |
cl_bool |
0x1024 |
|
CL_DEVICE_EXECUTION_CAPABILITIES |
cl_device_exec_capabilities |
0x1029 |
|
CL_DEVICE_EXTENSIONS |
char[] |
0x1030 |
|
CL_DEVICE_GLOBAL_MEM_CACHE_SIZE |
cl_ulong |
0x101E |
|
CL_DEVICE_GLOBAL_MEM_CACHE_TYPE |
cl_device_mem_cache_type |
0x101C |
|
CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE |
cl_uint |
0x101D |
|
CL_DEVICE_GLOBAL_MEM_SIZE |
cl_ulong |
0x101F |
|
CL_DEVICE_HALF_FP_CONFIG |
cl_device_fp_config |
0x1033 |
|
CL_DEVICE_HOST_UNIFIED_MEMORY |
cl_bool |
0x1035 |
|
CL_DEVICE_IMAGE_SUPPORT |
cl_bool |
0x1016 |
|
CL_DEVICE_IMAGE2D_MAX_HEIGHT |
size_t |
0x1012 |
|
CL_DEVICE_IMAGE2D_MAX_WIDTH |
size_t |
0x1011 |
|
CL_DEVICE_IMAGE3D_MAX_DEPTH |
size_t |
0x1015 |
|
CL_DEVICE_IMAGE3D_MAX_HEIGHT |
size_t |
0x1014 |
|
CL_DEVICE_IMAGE3D_MAX_WIDTH |
size_t |
0x1013 |
|
CL_DEVICE_LOCAL_MEM_SIZE |
cl_ulong |
0x1023 |
|
CL_DEVICE_LOCAL_MEM_TYPE |
cl_device_local_mem_type |
0x1022 |
|
CL_DEVICE_MAX_CLOCK_FREQUENCY |
cl_uint |
0x100C |
|
CL_DEVICE_MAX_COMPUTE_UNITS |
cl_uint |
0x1002 |
|
CL_DEVICE_MAX_CONSTANT_ARGS |
cl_uint |
0x1021 |
|
CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE |
cl_ulong |
0x1020 |
|
CL_DEVICE_MAX_MEM_ALLOC_SIZE |
cl_ulong |
0x1010 |
|
CL_DEVICE_MAX_PARAMETER_SIZE |
size_t |
0x1017 |
|
CL_DEVICE_MAX_READ_IMAGE_ARGS |
cl_uint |
0x100E |
|
CL_DEVICE_MAX_SAMPLERS |
cl_uint |
0x1018 |
|
CL_DEVICE_MAX_WORK_GROUP_SIZE |
size_t |
0x1004 |
|
CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS |
cl_uint |
0x1003 |
|
CL_DEVICE_MAX_WORK_ITEM_SIZES |
size_t[] |
0x1005 |
|
CL_DEVICE_MAX_WRITE_IMAGE_ARGS |
cl_uint |
0x100F |
|
CL_DEVICE_MEM_BASE_ADDR_ALIGN |
cl_uint |
0x1019 |
|
CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE |
cl_uint |
0x101A |
|
CL_DEVICE_NAME |
char[] |
0x102B |
|
CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR |
cl_uint |
0x1036 |
|
CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT |
cl_uint |
0x1037 |
|
CL_DEVICE_NATIVE_VECTOR_WIDTH_INT |
cl_uint |
0x1038 |
|
CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG |
cl_uint |
0x1039 |
|
CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT |
cl_uint |
0x103A |
|
CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE |
cl_uint |
0x103B |
|
CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF |
cl_uint |
0x103C |
|
CL_DEVICE_OPENCL_C_VERSION |
char[] |
0x103D |
|
CL_DEVICE_PLATFORM |
cl_platform_id |
0x1031 |
|
CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR |
cl_uint |
0x1006 |
|
CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT |
cl_uint |
0x1007 |
|
CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT |
cl_uint |
0x1008 |
|
CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG |
cl_uint |
0x1009 |
|
CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT |
cl_uint |
0x100A |
|
CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE |
cl_uint |
0x100B |
|
CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF |
cl_uint |
0x1034 |
|
CL_DEVICE_PROFILE |
char[] |
0x102E |
|
CL_DEVICE_PROFILING_TIMER_RESOLUTION |
size_t |
0x1025 |
|
CL_DEVICE_QUEUE_PROPERTIES |
cl_command_queue_properties |
0x102A |
|
CL_DEVICE_SINGLE_FP_CONFIG |
cl_device_fp_config |
0x101B |
|
CL_DEVICE_TYPE |
cl_device_type |
0x1000 |
|
CL_DEVICE_VENDOR |
char[] |
0x102C |
|
CL_DEVICE_VENDOR_ID |
cl_uint |
0x1001 |
|
CL_DEVICE_VERSION |
char[] |
0x102F |
|
CL_DRIVER_VERSION |
char[] |
0x102D |
|
戻り値
名前 |
値 |
解説 |
CL_SUCCESS |
0 |
関数は成功しました |
CL_INVALID_DEVICE |
-33 |
deviceが無効な値です。 |
CL_INVALID_VALUE |
-30 |
param_nameが無効な値であるか、param_value_sizeが小さすぎ、param_valueがNULLではありません。 |
CL_OUT_OF_RESOURCES |
-5 |
デバイスでリソースを確保するのに失敗しました。 |
CL_OUT_OF_HOST_MEMORY |
-6 |
メモリが足りません。 |
デバイス名の列挙
先程はデバイスのIDを列挙しました。
ここではデバイスの名前を列挙します。
Program.cs
using System;
class Program
{
static void Main()
{
foreach (var platform in getPlatforms())
{
foreach (var device in getDevices(platform, DeviceType.Default))
{
Console.WriteLine(getDeviceInfo(device, DeviceInfoString.Name));
}
}
}
private static string getDeviceInfo(IntPtr device, DeviceInfoString deviceInfoName)
{
int valueSize;
OpenCLFunctions.clGetDeviceInfo(device, deviceInfoName, 0, null, out valueSize);
System.Text.StringBuilder result = new System.Text.StringBuilder(valueSize);
OpenCLFunctions.clGetDeviceInfo(device, deviceInfoName, valueSize, result, out valueSize);
return result.ToString();
}
private static IntPtr[] getDevices(IntPtr platform, DeviceType deviceType)
{
int deviceCount;
OpenCLFunctions.clGetDeviceIDs(platform, deviceType, 0, null, out deviceCount);
IntPtr[] result = new IntPtr[deviceCount];
OpenCLFunctions.clGetDeviceIDs(platform, deviceType, deviceCount, result, out deviceCount);
return result;
}
private static IntPtr[] getPlatforms()
{
int platformCount;
OpenCLFunctions.clGetPlatformIDs(0, null, out platformCount);
IntPtr[] result = new IntPtr[platformCount];
OpenCLFunctions.clGetPlatformIDs(platformCount, result, out platformCount);
return result;
}
}
OpenCLFunctions.cs
using System;
using System.Runtime.InteropServices;
static class OpenCLFunctions
{
[DllImport("OpenCL.dll")]
public static extern int clGetPlatformIDs(int entryCount, IntPtr[] platforms, out int platformCount);
[DllImport("OpenCL.dll")]
public static extern int clGetDeviceIDs(
IntPtr platform,
DeviceType deviceType,
int entryCount,
IntPtr[] devices,
out int deviceCount
);
[DllImport("OpenCL.dll")]
public static extern int clGetDeviceInfo(
IntPtr device,
DeviceInfoString paramName,
int paramValueSize,
System.Text.StringBuilder paramValue,
out int paramValueSizeReturn
);
}
enum DeviceType:long
{
Default = (1 << 0),
Cpu = (1 << 1),
Gpu = (1 << 2),
Accelerator = (1 << 3),
All = 0xFFFFFFFF
}
enum DeviceInfoString
{
Name = 0x102B,
Vendor = 0x102C,
DriverVersion = 0x102D,
Profile = 0x102E,
Version = 0x102F,
Extensions = 0x1030
}
このプログラムはPCに付いているGPUの名前を列挙します。
環境によって実行結果は異なります。
私の環境ではこうなりました:
GeForce GTX 260
Juniper
GeForce GTX 260というのはNVIDIA社製のGPUの名前です。
JuniperというのはAMDのGPU、Radeon HD 5700シリーズの通称です。