Check OpenCL vendor ID at kernel-compile-time? - c-preprocessor

In an OpenCL kernel, I want to do one thing if targeting NVIDIA GPUs, and another thing otherwise, i.e.
#if MAGIC_HERE
asm("some ptx code");
#else
// some OpenCL C code which does the same thing, sort of
#endif
What should I put instead of MAGIC_HERE?

2 options:
use one of the nvidia-specific extensions, that is always present on Nvidia GPUs but not on GPUs from other vendors, for example MAGIC_HERE=cl_nv_pragma_unroll:
#if cl_nv_pragma_unroll
// NVIDIA-only code
#else
// Non-NVIDIA code
#endif
embed #define MAGIC_HERE into the runtime-compiled OpenCL C code string in C++, if and only if cl_device.getInfo<CL_DEVICE_VENDOR>() contains NVIDIA

Related

Determine the operating system variable in a C preprocessor directive

I am posting yet another programming task that I can't solve. Suppose we write OS-specific preprocessor directives like:
#if OS == Linux
/* Linux-specific instructions */
...
#else
#if OS == Darwin
/* Mac OSX-specific instructions */
...
#else
/* Program code for other OS */
...
#endif
#endif
We are not allowed to use #define OS Linux; instead the variable OS should be set with the compiler (or alternatively in a makefile). There should also be a shell-command which can automatically define OS. How can we set OS-Variable using the compiler or the shell?
Kind regards
The C preprocessor can only compare integer values, not strings or any other type. When you write #if OS == Linux, the preprocessor first expands the macros OS and Linux (and any macros in their expansions, etc.). Once it's finished expanding, it treats the whole line (after #if itself) as a preprocessor expression and evaluates it. Like with the C language proper, the directive is true if the value is nonzero, and boolean operators like == evaluate to 1 if true and 0 if false.
So for #if OS == Linux to work, you have to choose a numerical value for Linux (and a different value for all the other operating systems). Then you need to assign OS to the same value. For example, if suppose you have a header operating_systems.h containing
#define Linux 1
#define Darwin 2
#define Windows 3
then you can use #define OS 1 or #define OS (7 - 6) or #define OS Linux or any equivalent method to make #if OS == Linux true.
Note that if Linux and Darwin are undefined and you define OS to either Linux or Darwin, then both OS == Linux and OS == Darwin will be true, because undefined macro names in preprocessor expressions have the value 0. This kind of “enum-like” conditional is error-prone since undefined values (or values from the wrong “enum” series) will not be caught, so it isn't a good idea.
This is quite an unusual way to select between operating systems. Usually, system selection is based on whether certain macros are defined or not. For example, all compilers for Linux should define __linux__, all compilers for macOS should define __APPLE__, etc. To find out what macros are predefined, consult the documentation of your compiler or operating system (including applicable standards, e.g. POSIX), or ask your compiler (e.g. cpp -dM /dev/null).
So typical OS-specific code looks like this:
#if defined(__APPLE__)
// macOS or iOS code
#elif defined(__unix__)
// code for Unix-like systems
# if defined(__linux__)
// additional code for Linux
# endif
#elif defined(_WIN32) || defined(_WIN64)
// code for Windows
#else
#error "Unknown operating system"
#endif
If you need to select additional information during the build which can't be determined by the compiler alone, most compilers have a way to predefine additional macros. On Unix-like compilers (including GCC, Clang and many others), you do this by passing -DMACRO_NAME or -DMACRO_NAME=expansion on the command line. For example, if you compile with
gcc -DPROTOCOL_VERSION=3
then you can write code like this:
#if PROTOCOL_VERSION == 1
#error "Protocol version 1 is no longer supported."
#elif PROTOCOL_VERSION == 2
// code for version 2
#elif PROTOCOL_VERSION == 3
// code for version 3
#else
#error "An unsupported protocol version was requrested"
#endif
(This example assumes your code is only capable of supporting a single protocol version.)

How to check that microprocessor is Altera Nios?

I writes some C-program code for Altera/Nios II microprocessor (uP). This code will be different with Altera Arm 9 microprocessor. So I need to write 2 different code pieces for different uP-s. How can I check in execution time which uP is present. Or more simple, current uP is Nios or not.
As the two processors are from different architectures, you will not be able to check which processor is running at run-time. You could do it at compile time, as you will have a specific define flag set by your toolchain (see https://sourceforge.net/p/predef/wiki/Architectures/). For Arm it should be __arm__ or similar, depending on the toolchain you are using for the HPS.
#ifdef __arm__
<specific code for HPS>
#else
<specific code for NIOS>
#endif /* __arm__ */
You can also look at the toolchain's defines using the c pre-processor command (cpp):
<toolchain>-cpp -dM /dev/null
Note: for Arm processor, the MIDR register could be used to know which type you are running and this one could be accessed at runtime. But when building for NIOS II, you would have a compilation error. So you need to use the preprocessor to call specific Arm register name and to remove the code when building for NiosII.
Presumably it will be compiled with a different compiler? These compilers will (very likely) have a #define of some sort which you can use to build different code for each one.
You can make the compiler dump all its default preprocessor defines using:
echo | ./nios2-elf-gcc.exe -dM -E -
This will in particular emit:
#define nios2 1

Include Headers OpenCL (32bit vs 64bit)

Im a programming OpenCL via pyopenCL on a Ubuntu 16.04.3 64bit,
on Nvidia's Tesla K10.G2.8GB.
So far, anything runs smoothly as long as I don't include header files into my OpenCL kernel. As soon, as I put #include <stdlib.h> on top of my header file, the compilation of my openCL kernels fails with different files missing, amongst them being
gnu/stubs-32.h
sys/cdefs.h
Searching for that problem, brings up answers like
Error "gnu/stubs-32.h: No such file or directory" while compiling Nachos source code
or
https://askubuntu.com/questions/470796/fatal-error-sys-cdefs-h-no-such-file-or-directory
baiscally suggesting to install libc6-dev-i386 or gcc-multilib and g++-multilib, supposing that the underlying problem is a 64bit/32bit problem. My question is, are my OpenCL binaries for the GPU compiled as 32bit binaries (how can I check?)?
If yes:
Are there other caveats, when I want to compile 32bit binaries on a 64bit OS?
Furthermore: Can I use 64bit floats, when my kernel is compiled in 32bit?
(e.g., will #pragma OPENCL EXTENSION cl_khr_fp64 : enable still work?)
If no:
Do I have to manually locate / copy all the needed header files and include them by hand?
Also: Some of my co-workers even doubt, that including standard C headers into OpenCL kernels is possible due to missing linkers. Any light on that is also appreciated.
Standard C library and other system headers cannot be included
into OpenCL C code, basically because they are only compatible
with the current system (a host), whereas an OpenCL C code could
run on a different device with a different architecture (a GPU in
your case).
As a replacement for standard C functions, OpenCL C defines a set
of built-in functions, which are available without any #include:
printf, large number of math functions, atomics, image-related
functions, etc.
See the "OpenCL Specification: 6.12 Built-in Functions" for a
complete list:
https://www.khronos.org/registry/OpenCL/specs/opencl-1.2.pdf
That doesn't mean you can't create a header with OpenCL C code
and #include it into an OpenCL C program. This works fine:
// foo.h
void foo() {
printf("hello world!");
}
// kernel.cl
#include "foo.h"
__kernel void use_foo() {
foo();
}

How to tell if program is running on x86/x64 or ARM Linux platforms

In a c program I want to do different things. This program will run on x86/x64 based GNU/Linux system as well as ARM based one e.g. on a PC or RaspberryPI.
Is there predefined macros in GCC to tell the platform?
something like
#ifdef _X64_
/do x64 stuff
#elif _ARM_
//do arm stuff
#endif
Or maybe that is the wrong approach? I will be using Makefileto compile and I could get away with my own defines.
What would be the best/safest approach?
This has already been answered on these posts:
GCC predefined macros for architecture X, Detecting CPU architecture compile-time
You can have them here:
http://sourceforge.net/p/predef/wiki/Architectures/
Your approach should only be used for small portions of code or functions but it should work.
Edit:
Basically, because links can become invalid:
__arm__ should work on ARM.
__x86_64__ should work on x64 architecture.
And yes, you can do:
#ifdef __x86_64__
// do x64 stuff
#elif __arm__
// do arm stuff
#endif

Detecting users OS in terminal application, in C

How do I determine a user's OS in terminal application, in C?
For example, in the code below, what should I replace windows and linux with?
/* pseudo code */
if(windows)
{system(cls)}
else if(linux)
{system(clear)}
else{...}
I should mention that I am a beginner at C, and need something like this so my code can work on windows and/or linux, without making separate source for each.
Typically, this is done with macros in the build system (since you have to BUILD the code for each system anyway.
e.g. gcc -DLINUX myfile.c
and then in myfile.c
#ifdef LINUX
... do stuff for linux ...
#else if defined(WINDOWS)
... do something for windows ...
#else if ... and so on.
...
#endif
(Most of the time, you can find some way that doesn't actually require the addition of a -D<something> on the command line, by using predefined macros for the tools you are using to compile for that architecture).
Alternatively, you ca do the same thing, but much quicker and better (but not 100% portable) by printing the ANSI escape sequence for "clear screen":
putstr("\033" "2J");
yes, that's two strings, because if you write "\0332J" the compile will use the character 0332, not character 033, followed by the digit 2. So two strings next to each other will do the trick.
I believe you can avoid runtime check by specializing your 'functions' during compilation. So, how about this then:
#ifdef WIN32
CLEAR = cls
#elif __linux__
CLEAR = clear
#endif
Predefs vary from compiler to compiler, so here's a good list to have: http://sourceforge.net/p/predef/wiki/OperatingSystems/
It is probably better to detect the environment at compile time rather than runtime. With compiled languages like C you aren't going to have the same compiler output running on different platforms as you would with a lanugage such as Java so you don't need to do this kind of check at runtime.
This is the header I use to work out what platform my code is being compiled on. It will define different macros depending on the OS (as well as other things).
Something like this in use:
#if defined(UTIL_PLATFORM_WINDOWS)
printf("windows\n");
#elif defined(UTIL_PLATFORM_UNIXLIKE)
printf("Unix\n");
#endif

Resources