summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2019-06-02 20:07:04 +0800
committerGitHub <[email protected]>2019-06-02 20:07:04 +0800
commitadf7265401df3259ff90868cfcc9baaad66d172d (patch)
tree2782ee1cedad5c9dd4a25fa886f5fd49c883962f
parent78f4fa1228d508f4aceecfe03fd233478f56da54 (diff)
parent117f22a385f0118eac2aa6ef8fedf4b29062e973 (diff)
Merge pull request #430 from OpportunityLiu/dev
支持 nvcc -gencode 选项
-rw-r--r--.gitignore1
-rw-r--r--tests/projects/cuda/console/xmake.lua14
-rw-r--r--xmake/includes/add_cugencodes.lua148
-rw-r--r--xmake/modules/lib/detect/find_cudadevices.lua271
-rw-r--r--xmake/scripts/find_cudadevices.cu207
5 files changed, 633 insertions, 8 deletions
diff --git a/.gitignore b/.gitignore
index abfbe8941..9dd2d123e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,3 +41,4 @@ core/.config.mak
winenv
xmake-ppa
!xmake/actions/build
+.vscode/* \ No newline at end of file
diff --git a/tests/projects/cuda/console/xmake.lua b/tests/projects/cuda/console/xmake.lua
index b50beb03c..430ad7b6d 100644
--- a/tests/projects/cuda/console/xmake.lua
+++ b/tests/projects/cuda/console/xmake.lua
@@ -1,3 +1,6 @@
+
+includes('add_cugencodes.lua')
+
-- define target
target("cuda_console")
@@ -11,14 +14,9 @@ target("cuda_console")
add_files("src/*.cu")
-- generate SASS code for each SM architecture
- for _, sm in ipairs({"30", "35", "37", "50", "52", "60", "61", "70"}) do
- add_cuflags("-gencode arch=compute_" .. sm .. ",code=sm_" .. sm)
- add_ldflags("-gencode arch=compute_" .. sm .. ",code=sm_" .. sm)
- end
+ add_cugencodes("sm_30", "sm_35", "sm_37", "sm_50", "sm_52", "sm_60", "sm_61", "sm_70")
-- generate PTX code from the highest SM architecture to guarantee forward-compatibility
- sm = "70"
- add_cuflags("-gencode arch=compute_" .. sm .. ",code=compute_" .. sm)
- add_ldflags("-gencode arch=compute_" .. sm .. ",code=compute_" .. sm)
-
+ add_cugencodes("compute_70")
+
diff --git a/xmake/includes/add_cugencodes.lua b/xmake/includes/add_cugencodes.lua
new file mode 100644
index 000000000..574c7bcb9
--- /dev/null
+++ b/xmake/includes/add_cugencodes.lua
@@ -0,0 +1,148 @@
+--!A cross-platform build utility based on Lua
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015 - 2019, TBOOX Open Source Group.
+--
+-- @author OpportunityLiu
+-- @file add_cugencodes.lua
+--
+
+-- add cuda `-gencode` flags to target
+--
+-- the gpu arch format syntax
+-- - compute_xx --> `-gencode arch=compute_xx,code=compute_xx`
+-- - sm_xx --> `-gencode arch=compute_xx,code=sm_xx`
+-- - sm_xx,sm_yy --> `-gencode arch=compute_xx,code=[sm_xx,sm_yy]`
+-- - compute_xx,sm_yy --> `-gencode arch=compute_xx,code=sm_yy`
+-- - compute_xx,sm_yy,sm_zz --> `-gencode arch=compute_xx,code=[sm_yy,sm_zz]`
+-- - native --> match the fastest cuda device on current host,
+-- eg. for a Tesla P100, `-gencode arch=compute_60,code=sm_60` will be added,
+-- if no available device is found, no `-gencode` flags will be added
+-- @seealso xmake/modules/lib/detect/find_cudadevices
+--
+-- e.g.
+-- includes("add_cugencodes.lua")
+-- target("test")
+-- set_kind("binary")
+-- add_files("src/*.cu")
+-- add_cugencodes("native", "compute_50,sm_50", "compute_70")
+--
+
+
+-- define rule
+rule("cuda.add_gencodes")
+ before_load(function (target)
+
+ local function set (list)
+ local result = {}
+ for _, l in ipairs(list) do result[l] = true end
+ return result
+ end
+
+ -- sm_20 and compute_20 is supported until CUDA 8
+ local knownVArchs = set { 20, 30, 32, 35, 37, 50, 52, 53, 60, 61, 62, 70, 72, 75, }
+ local knownRArchs = set { 20, 30, 32, 35, 37, 50, 52, 53, 60, 61, 62, 70, 72, 75, }
+
+ local function nf_cugencode(archs)
+ if type(archs) ~= 'string' then
+ return nil
+ end
+
+ archs = archs:trim():lower()
+
+ if archs == 'native' then
+ import("lib.detect.find_cudadevices")
+ local device = find_cudadevices({ skip_compute_mode_prohibited = true, order_by_flops = true })[1]
+ if device then
+ return nf_cugencode('sm_' .. device.major .. device.minor)
+ end
+ return nil
+ end
+
+ local vArch = nil
+ local rArchs = {}
+
+ local function parse_arch(value, prefix, knowList)
+ if not value:startswith(prefix) then
+ return nil
+ end
+ local arch = tonumber(value:sub(#prefix + 1)) or tonumber(value:sub(#prefix + 2))
+ if arch == nil then
+ raise("Unknown architecture: " .. value)
+ end
+ if not knowList[arch] then
+ if arch <= table.maxn(knowList) then
+ raise("Unknown architecture: " .. prefix .. "_" .. arch)
+ else
+ utils.warning("Unknown architecture: " .. prefix .. "_" .. arch)
+ end
+ end
+ return arch
+ end
+
+ for _, v in ipairs(archs:split(',')) do
+ local arch = v:trim()
+ local tempRArch = parse_arch(arch, 'sm', knownRArchs)
+ if tempRArch then
+ table.insert(rArchs, tempRArch)
+ end
+
+ local tempVArch = parse_arch(arch, 'compute', knownVArchs)
+ if tempVArch then
+ if vArch ~= nil then
+ raise("More than one virtual architecture is defined in one gpu gencode option: compute_" .. vArch .. " and compute_" .. tempVArch)
+ end
+ vArch = tempVArch
+ end
+
+ if not (tempRArch or tempVArch) then
+ raise("Unknown architecture: " .. arch)
+ end
+ end
+
+ if vArch == nil and #rArchs == 0 then
+ return nil
+ end
+
+ if #rArchs == 0 then
+ return '-gencode arch=compute_' .. vArch .. ',code=compute_' .. vArch
+ end
+
+ rArchs = table.unique(rArchs)
+ vArch = vArch or math.min(unpack(rArchs))
+
+ if #rArchs == 1 then
+ return '-gencode arch=compute_' .. vArch .. ',code=sm_' .. rArchs[1]
+ else
+ return '-gencode arch=compute_' .. vArch .. ',code=[sm_' .. table.concat(rArchs, ',sm_') .. ']'
+ end
+ end
+
+ for _, v in ipairs(target:values("cuda.gencode")) do
+ local flag = nf_cugencode(v)
+ if flag then
+ target:add('cuflags', flag)
+ target:add('ldflags', flag)
+ end
+ end
+ end)
+rule_end()
+
+-- add cuda gencode to target
+function add_cugencodes(...)
+ -- apply rule
+ add_rules("cuda.add_gencodes")
+ add_values("cuda.gencode", ...)
+end
+
diff --git a/xmake/modules/lib/detect/find_cudadevices.lua b/xmake/modules/lib/detect/find_cudadevices.lua
new file mode 100644
index 000000000..c009319aa
--- /dev/null
+++ b/xmake/modules/lib/detect/find_cudadevices.lua
@@ -0,0 +1,271 @@
+--!A cross-platform build utility based on Lua
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015 - 2019, TBOOX Open Source Group.
+--
+-- @author OpportunityLiu
+-- @file find_cudadevices.lua
+--
+
+-- imports
+import("core.base.option")
+import("core.platform.platform")
+import("lib.detect.cache")
+
+-- a magic string to filter output
+local _PRINT_SUFFIX = "<find_cudadevices>"
+
+-- filter stdout and stderr with _PRINT_SUFFIX
+function _get_lines(str)
+ local result = {}
+ for _, l in ipairs(str:split('\n')) do
+ if l:startswith(_PRINT_SUFFIX) then
+ table.insert(result, l:sub(#_PRINT_SUFFIX + 1))
+ end
+ end
+ return result
+end
+
+
+-- parse a single value
+-- format:
+-- 1. a number: `2048`
+-- 2. an array: `(65536, 2048, 2048)`
+-- 3. bool value: `true` or `false`
+-- 4. string: `"string"`
+function _parse_value(value)
+ local num = tonumber(value)
+ if num then return num end
+
+ if value:lower() == "true" then return true end
+ if value:lower() == "false" then return false end
+
+ if value:startswith('"') and value:endswith('"') then
+ return value:sub(2, -2)
+ end
+
+ if value:startswith('(') and value:endswith(')') then
+ local values = value:sub(2, -2):split(',')
+ local result = {}
+ for _, v in ipairs(values) do
+ table.insert(result, _parse_value(v:trim()))
+ end
+ return result
+ end
+
+ raise("don't know how to parse value: %s", value)
+end
+
+
+-- parse single line
+-- format:
+-- key = value
+function _parse_line(line, device)
+ local key = line:match("%s+(%g+) = .+")
+ local value = line:match("%s+%g+ = (.+)")
+ if key and value then
+ key = key:trim()
+ value = value:trim()
+ assert(not device[key], 'duplicate key: ' .. key)
+ device[key] = _parse_value(value)
+ end
+end
+
+
+-- parse filtered lines
+function _parse_result(lines, verbose)
+ if #lines == 0 then
+ -- not a failure, returns {} rather than nil
+ utils.warning("no cuda devices was found")
+ return {}
+ end
+
+ local devices = {}
+ local currentDevice = nil
+ for _, l in ipairs(lines) do
+ if verbose then
+ cprint("${dim}> %s", l)
+ end
+ local devId = tonumber(l:match("%s*DEVICE #(%d+)"))
+ if devId then
+ currentDevice = { ['$id'] = devId }
+ table.insert(devices, currentDevice)
+ elseif currentDevice then
+ _parse_line(l, currentDevice)
+ end
+ end
+ return devices
+end
+
+
+-- find devices
+function _find_devices(verbose)
+ local nvcc = platform.tool("cu")
+ if nvcc == nil then
+ raise('nvcc not found')
+ end
+
+ if verbose then
+ cprint("${dim}checking for cuda devices")
+ end
+
+ local sourcefile = path.join(os.programdir(), 'scripts', 'find_cudadevices.cu')
+ local outfile = os.tmpfile()
+
+ local compileerrors = nil
+ local results, errors = try { function ()
+ return os.iorunv(nvcc, { sourcefile, '-run', '-o', outfile , '-DPRINT_SUFFIX="' .. _PRINT_SUFFIX .. '"' })
+ end, catch {function (errs) compileerrors = tostring(errs) end} }
+
+ if compileerrors ~=nil then
+ if not option.get("diagnosis") then
+ compileerrors = compileerrors:split('\n')[1]
+ end
+ utils.warning("failed to find cuda devices: " .. compileerrors)
+ return nil
+ end
+
+ -- clean up
+ os.rm(outfile)
+ os.rm(outfile .. '.*')
+
+ local results_lines = _get_lines(results)
+ local errors_lines = _get_lines(errors)
+
+ if #errors_lines ~= 0 then
+ utils.warning("failed to find cuda devices: " .. table.concat(errors_lines, '\n'))
+ return nil
+ end
+
+ -- print raw result only with -D flags
+ local devices = _parse_result(results_lines, option.get("diagnosis"))
+ if verbose then
+ for _, v in ipairs(devices) do
+ cprint("${dim}> found device #%d: ${green bright}%s${reset dim} with compute ${bright}%d.%d${reset dim} capability", v['$id'], v.name, v.major, v.minor)
+ end
+ end
+ return devices
+end
+
+
+-- get devices array form cache or via _find_devices
+function _get_devices(opt)
+ -- init cachekey
+ local cachekey = "find_cudadevices"
+ if opt.cachekey then
+ cachekey = cachekey .. "_" .. opt.cachekey
+ end
+
+ -- check cache
+ local cachedata = cache.load(cachekey)
+ if cachedata.succeed and not opt.force then
+ return cachedata.data
+ end
+
+ local verbose = opt.verbose or option.get("verbose") or option.get("diagnosis")
+ local devices = _find_devices(verbose)
+
+ if devices then
+ cachedata = { succeed = true, data = devices }
+ else
+ cachedata = { succeed = false }
+ devices = {}
+ end
+
+ -- fill cache
+ cache.save(cachekey, cachedata)
+ return devices
+end
+
+function _skip_compute_mode_prohibited(devices)
+ local results = {}
+ local cudaComputeModeProhibited = 2
+ for _, dev in ipairs(devices) do
+ if dev.computeMode ~= cudaComputeModeProhibited then
+ table.insert(results, dev)
+ end
+ end
+ return results
+end
+
+function _min_sm_arch(devices, min_sm_arch)
+ local results = {}
+ for _, dev in ipairs(devices) do
+ if dev.major * 10 + dev.minor >= min_sm_arch then
+ table.insert(results, dev)
+ end
+ end
+ return results
+end
+
+function _order_by_flops(devices)
+ local nGpuArchCoresPerSM = {
+ [30] = 192
+ , [32] = 192
+ , [35] = 192
+ , [37] = 192
+ , [50] = 128
+ , [52] = 128
+ , [53] = 128
+ , [60] = 64
+ , [61] = 128
+ , [62] = 128
+ , [70] = 64
+ , [72] = 64
+ , [75] = 64
+ }
+
+ for _, dev in ipairs(devices) do
+ local sm_per_multiproc = 0
+ if dev.major == 9999 and dev.minor == 9999 then
+ sm_per_multiproc = 1
+ else
+ sm_per_multiproc = nGpuArchCoresPerSM[dev.major * 10 + dev.minor] or 64;
+ end
+ dev['$flops'] = dev.multiProcessorCount * sm_per_multiproc * dev.clockRate
+ end
+
+ table.sort(devices, function (a,b) return a['$flops'] > b['$flops'] end)
+ return devices
+end
+
+-- find cuda devices of the host
+--
+-- @param opt the options
+-- e.g. { verbose = false, force = false, cachekey = "xxxx", min_sm_arch = 35, skip_compute_mode_prohibited = false, order_by_flops = true }
+--
+-- @return { { ['$id'] = 0, name = "GeForce GTX 960M", major = 5, minor = 0, ... }, ... }
+-- for all keys, see https://docs.nvidia.com/cuda/cuda-runtime-api/structcudaDeviceProp.html#structcudaDeviceProp
+-- keys might be differ as your cuda version varies
+--
+function main(opt)
+ -- init options
+ opt = opt or {}
+
+ -- get devices
+ local devices = _get_devices(opt)
+
+ -- apply filters
+ if opt.min_sm_arch then
+ devices = _min_sm_arch(devices, opt.min_sm_arch)
+ end
+ if opt.skip_compute_mode_prohibited then
+ devices = _skip_compute_mode_prohibited(devices)
+ end
+ if opt.order_by_flops then
+ devices = _order_by_flops(devices)
+ end
+
+ return devices
+end
diff --git a/xmake/scripts/find_cudadevices.cu b/xmake/scripts/find_cudadevices.cu
new file mode 100644
index 000000000..56d64ff2b
--- /dev/null
+++ b/xmake/scripts/find_cudadevices.cu
@@ -0,0 +1,207 @@
+#include <cuda_runtime.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef PRINT_SUFFIX
+#define PRINT_SUFFIX "<find_cudadevices>"
+#endif
+
+#define MY_CUDA_VER (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__)
+
+inline void check(cudaError_t result)
+{
+ if (result)
+ {
+ fprintf(stderr, PRINT_SUFFIX "%s (%s)", cudaGetErrorName(result), cudaGetErrorString(result));
+ cudaDeviceReset();
+ // Make sure we call CUDA Device Reset before exiting
+ exit(0);
+ }
+}
+
+inline void print_value(size_t value)
+{
+ // in case we don't have '%zu'
+ printf("%llu", (unsigned long long)value);
+}
+
+inline void print_value(bool value)
+{
+ printf(value ? "true" : "false");
+}
+
+inline void print_value(int value)
+{
+ printf("%d", value);
+}
+
+template <typename T, size_t len>
+inline void print_value(const T (&value)[len])
+{
+ printf("(");
+ for (size_t i = 0; i < len - 1; i++)
+ {
+ print_value(value[i]);
+ printf(", ");
+ }
+ print_value(value[len - 1]);
+ printf(")");
+}
+
+inline void print_value(unsigned int value)
+{
+ printf("%u", value);
+}
+
+inline void print_value(const void *value)
+{
+ printf("\"%s\"", (const char *)value);
+}
+
+template <size_t len>
+inline void print_value(const char (&value)[len])
+{
+ printf("\"");
+ for (size_t i = 0; i < len; i++)
+ printf("%02hhx", value[i]);
+ printf("\"");
+}
+
+template <>
+inline void print_value<16>(const char (&value)[16])
+{
+ // speicalized for uuid
+ printf("\"%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\"",
+ value[0], value[1], value[2], value[3],
+ value[4], value[5], value[6], value[7],
+ value[8], value[9], value[10], value[11],
+ value[12], value[13], value[14], value[15]);
+}
+
+#if MY_CUDA_VER >= 1000
+inline void print_value(const cudaUUID_t &value)
+{
+ print_value(value.bytes);
+}
+#endif
+
+template <typename T>
+inline void print_property(const char *name, const T &value)
+{
+ printf(PRINT_SUFFIX " %s = ", name);
+ print_value(value);
+ printf("\n");
+}
+
+inline void print_device(int id)
+{
+ cudaDeviceProp deviceProp;
+ check(cudaGetDeviceProperties(&deviceProp, id));
+
+#define PRINT_PROPERTY(name) print_property(#name, deviceProp.name)
+#define PRINT_BOOL_PROPERTY(name) print_property(#name, static_cast<bool>(deviceProp.name))
+#define PRINT_STR_PROPERTY(name) print_property(#name, static_cast<const void *>(deviceProp.name))
+ // cuda 8.0
+ PRINT_STR_PROPERTY(name);
+ PRINT_PROPERTY(totalGlobalMem);
+ PRINT_PROPERTY(sharedMemPerBlock);
+ PRINT_PROPERTY(regsPerBlock);
+ PRINT_PROPERTY(warpSize);
+ PRINT_PROPERTY(memPitch);
+ PRINT_PROPERTY(maxThreadsPerBlock);
+ PRINT_PROPERTY(maxThreadsDim);
+ PRINT_PROPERTY(maxGridSize);
+ PRINT_PROPERTY(clockRate);
+ PRINT_PROPERTY(totalConstMem);
+ PRINT_PROPERTY(major);
+ PRINT_PROPERTY(minor);
+ PRINT_PROPERTY(textureAlignment);
+ PRINT_PROPERTY(texturePitchAlignment);
+ PRINT_BOOL_PROPERTY(deviceOverlap);
+ PRINT_PROPERTY(multiProcessorCount);
+ PRINT_BOOL_PROPERTY(kernelExecTimeoutEnabled);
+ PRINT_BOOL_PROPERTY(integrated);
+ PRINT_BOOL_PROPERTY(canMapHostMemory);
+ PRINT_PROPERTY(computeMode);
+ PRINT_PROPERTY(maxTexture1D);
+ PRINT_PROPERTY(maxTexture1DMipmap);
+ PRINT_PROPERTY(maxTexture1DLinear);
+ PRINT_PROPERTY(maxTexture2D);
+ PRINT_PROPERTY(maxTexture2DMipmap);
+ PRINT_PROPERTY(maxTexture2DLinear);
+ PRINT_PROPERTY(maxTexture2DGather);
+ PRINT_PROPERTY(maxTexture3D);
+ PRINT_PROPERTY(maxTexture3DAlt);
+ PRINT_PROPERTY(maxTextureCubemap);
+ PRINT_PROPERTY(maxTexture1DLayered);
+ PRINT_PROPERTY(maxTexture2DLayered);
+ PRINT_PROPERTY(maxTextureCubemapLayered);
+ PRINT_PROPERTY(maxSurface1D);
+ PRINT_PROPERTY(maxSurface2D);
+ PRINT_PROPERTY(maxSurface3D);
+ PRINT_PROPERTY(maxSurface1DLayered);
+ PRINT_PROPERTY(maxSurface2DLayered);
+ PRINT_PROPERTY(maxSurfaceCubemap);
+ PRINT_PROPERTY(maxSurfaceCubemapLayered);
+ PRINT_PROPERTY(surfaceAlignment);
+ PRINT_BOOL_PROPERTY(concurrentKernels);
+ PRINT_BOOL_PROPERTY(ECCEnabled);
+ PRINT_PROPERTY(pciBusID);
+ PRINT_PROPERTY(pciDeviceID);
+ PRINT_PROPERTY(pciDomainID);
+ PRINT_BOOL_PROPERTY(tccDriver);
+ PRINT_PROPERTY(asyncEngineCount);
+ PRINT_BOOL_PROPERTY(unifiedAddressing);
+ PRINT_PROPERTY(memoryClockRate);
+ PRINT_PROPERTY(memoryBusWidth);
+ PRINT_PROPERTY(l2CacheSize);
+ PRINT_PROPERTY(maxThreadsPerMultiProcessor);
+ PRINT_BOOL_PROPERTY(streamPrioritiesSupported);
+ PRINT_BOOL_PROPERTY(globalL1CacheSupported);
+ PRINT_BOOL_PROPERTY(localL1CacheSupported);
+ PRINT_PROPERTY(sharedMemPerMultiprocessor);
+ PRINT_PROPERTY(regsPerMultiprocessor);
+ PRINT_BOOL_PROPERTY(isMultiGpuBoard);
+ PRINT_PROPERTY(multiGpuBoardGroupID);
+ PRINT_PROPERTY(singleToDoublePrecisionPerfRatio);
+ PRINT_BOOL_PROPERTY(pageableMemoryAccess);
+ PRINT_BOOL_PROPERTY(concurrentManagedAccess);
+ PRINT_BOOL_PROPERTY(managedMemory);
+
+#if MY_CUDA_VER >= 900
+ // Added in cuda 9.0
+ PRINT_BOOL_PROPERTY(computePreemptionSupported);
+ PRINT_BOOL_PROPERTY(canUseHostPointerForRegisteredMem);
+ PRINT_BOOL_PROPERTY(cooperativeLaunch);
+ PRINT_BOOL_PROPERTY(cooperativeMultiDeviceLaunch);
+ PRINT_PROPERTY(sharedMemPerBlockOptin);
+#endif
+
+#if MY_CUDA_VER >= 902
+ // Added in cuda 9.2
+ PRINT_BOOL_PROPERTY(pageableMemoryAccessUsesHostPageTables);
+ PRINT_BOOL_PROPERTY(directManagedMemAccessFromHost);
+#endif
+
+#if MY_CUDA_VER >= 1000
+ // Added in cuda 10.0
+ PRINT_PROPERTY(uuid);
+ PRINT_PROPERTY(luid);
+ PRINT_PROPERTY(luidDeviceNodeMask);
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+ printf("\n");
+ fprintf(stderr, "\n");
+
+ int count = 0;
+ check(cudaGetDeviceCount(&count));
+ for (int i = 0; i < count; i++)
+ {
+ printf(PRINT_SUFFIX "DEVICE #%d\n", i);
+ print_device(i);
+ }
+ return 0;
+}