OpenACC has some pragmas and runtime routines, which can be used to basically achieve the same thing.
For example, there is #pragma acc wait and acc_wait() or #pragma acc update [...] and acc_update_[...]().
I started to mostly use the runtime routines in my C++ code.
Is there a difference? Should I prefer one over the other or is it just a matter of style and personal preference?
In general, the pragma's are preferred since they will be ignored by other compilers and when compiling without OpenACC enabled. The runtime API calls would need to be guarded by a macro, like "#ifdef _OPENACC" to maintain portability.
Though, if you don't mind adding the macro guards or loosing portability, then it's mostly a matter of style. Functionally, they are equivalent.
Related
I am working on a numerical solver written in Fortran which uses MPI for parallelization on large clusters (up to about 500 processes). Currently we are including mpi via
#include "mpif.h"
which, from my understanding, is deprecated and strongly discouraged. In an effort to modernize and clean up our mpi communications, we would like to switch to using the more modern mpi_f08 module. The issue we are facing is that we need to maintain the possibility of compiling a version based on the old mpi header in order to not break the coupling with another solver. I'd much appreciate some advice on how to elegantly maintain this compatibility.
Question #1: What would be an elegant way to either include the header or use the module depending on a preprocessor flag without having #ifdef statements scattered throughout the code?
My thought so far would to define a module
module mpi_module
#ifdef MPI_LEGACY
#include "mpif.h"
#else
use mpi_f08
#endif
end module
and use this module everywhere where the mpi header file is currently included. Is this a viable approach or would this have any unwanted effects which I'm currently overlooking?
Question #2: What would be an elegant way to switch between integers and the new derived types from mpi_f08 depending on the preprocessor flag? (Again, without scattering #ifdef statements throughout the code)
My initial thought on this would be to use something like
#ifdef MPI_LEGACY
#define _mpiOp_ integer
#else
#define _mpiOp_ type(MPI_Op)
#endif
so that I can simply replace
integer :: OP
by
_mpiOp_ :: OP
to obtain compatibility with both ways of including MPI. I'm also not quite happy with this solution yet, since, in my understanding, you can not put these kinds of preprocessor definitions into a module. Thus, you'd end up with a module plus a header file which you necessarily have to remember to include together each time. Again, I'm grateful for any potential flaws with this approach and any alternatives that you can point out.
Sorry for the long post, but I wanted to make my thoughts as clear as possible. I'm looking forward to your input!
The old and the new way are way too different. Not only you have a use statement instead of an include statement and a derived instead of an integer for an Op. Many routines will have different signatures and use different types.
So I am afraid the answer is that there is no elegant way. You are making a conglomerate of two things that are way too different to be elegantly combined.
As has been mentioned in the comments, the first step to get more modern is to do use mpi instead of include "mpif.h". This already enables the compiler to catch many kinds of bugs when the routines are called incorrectly. Tje extent, to which these checks will be possible, will depend on the details of the MPI library configuration. Namely, the extent of generic interfaces generated instead of just external statements.
If you have to combine your code with another code that uses the old way, it makes good sense to first do use mpi, see how it goes, and think whether it makes sense to go further.
This question already has answers here:
Is #pragma once a safe include guard?
(15 answers)
Closed 5 years ago.
Modern C and C++ compilers support the non-standard #pragma once, preprocessor directive, which serve a similar purpose to the classic header guards:
#ifndef hopefully_unique_identifier_that_doesnt_hurt_the_code
#define hopefully_unique_identifier_that_doesnt_hurt_the_code
// some code here
#endif
One problem, I'm aware of, with the classic approach is that once you've included a header, you have to #undef the header guard macro to include it again (doing so, to me, is a major code-smell, but that's beside the point here). The same problem arises with the #pragma once approach, but without the possibility of allowing the header to be included more than once.
Another problem with the classic-approach is that you may, accidentally, define the same macro in unrelated places, thus either not including the header as expected or doing some other nasty stuff, that I can't imagine. This is reasonably easy to avoid in practice, by keeping to certain conventions such as basing the macros to UUID-like objects (i.e. random strings) or (the less optimal approach), basing them on the name of the file, they are defined in.
I have only rarely experienced any of these, potential problems, in real life, so I don't really consider them to be major problems.
The only potential real life problem I can think of with #pragma once, is that it's not a standard thing -- you're relying on something that may not be available everywhere, even if it is present, in practice, everywhere (*).
So, what potential problems exist with #pragma once, besides the ones I've already mentioned? Am I having too much faith in having it available, in practice, everywhere?
(*) Some minor compiler that only a handful of people use, excluded.
One problem I have encountered with using #pragma once was when including the same file that is located at multiple locations. With #pragma once it is deemed different, not with #ifndef/#define guard.
I have worked with a decent set of compilers so far:
GCC
Clang/LLVM
IBM XLC
Intel C++ Compiler
The only compiler that does not support #pragma once is the IBM XLC compiler, that that one does not even support C++11, so I am not interested. If you need to work with the IBM XLC Compiler on Blue Gene/Q, then you cannot use #pragma once.
A long time ago, certain compilers did not understand the include guard idiom and would repeatedly open the header file only to find that the preprocessor reduced the content to nothing. With these compilers, using #pragma once would give compile time benefit. However, this has been implemented in major compilers, such that this makes no difference nowadays.
Perhaps you have some special compiler for your embedded system. That one might be unable to use #pragma once.
In general I prefer #pragma once because when you duplicate a header file in order to do incremental refactoring by duplication or extending a class, you cannot forget to change the name of the include guard macro.
Therefore I do not know of any hard problem you have with #pragma once, except for certain compilers.
In using #pragma once you are giving up portability. You are no longer writing C or C++, but something allowed as a compiler extension.
That could cause you headaches if your code ever targets a different platform.
It's for this reason that I never use it.
Given that the name and location of a file is unique, I use that as my include guard. Furthermore because I have in the past targetted very old preprocessors, I use as a habit
#if !defined(foo)
#define foo 1
/*code*/
#endif
which has worked on every platform I've encountered since 1996.
I have researched it online, someone said they are avoid to include the same file more then one time, but i still not clear enough the difference and the meaning of same file.
Thank you advance.
#pragma once is not part of the standard and may not work on all operating systems or compilers
#ifndef is the preferred method of only including a file only once on most OS
Other than that #pragma once is less prone to making mistakes that can be caused by forgetting to change header guards if you copy and paste code etc and it is less code to type.
In theory, #pragma once is platform specific and #ifndef style include guards are the only Standard compliant way to ensure header uniqueness through the preprocessor.
However, in practice, all major compilers (gcc, Clang, Visual C++, Intel) support it on all major platforms (Linux, Windows, MacOSX). Maybe some older or obscure compiler/platform combinations give you trouble, but in practice it just works. But caveat emptor!
The major advantage of using #pragma once is that it is a lot easier to do refactorings, since you don't have to either keep all the include guard names in sync with the file system (one common style guide obligation of defining header guards) or to use a pseudo-random string ID as include guard.
You can use #pragma once when you are addressing a specific compiler, #pragma once is non-standards and is specific to some specific C compilers whereas #ifndef/#define/#endif works on almost every C compiler. #pragma once reduces possibilities for bugs.
From wiki:
In the C and C++ programming languages, #pragma once is a non-standard
but widely supported preprocessor directive designed to cause the
current source file to be included only once in a single compilation.
Thus, #pragma once serves the same purpose as #include guards, but
with several advantages, including: less code, avoidance of name
clashes, and sometimes improved compile speed.1
For those that develop software for multiple platforms, how do you handle the potential that compilers might do certain things better than other compilers.
Say you develop for OS X, Windows, Linux and you are using Clang/LLVM, VS and GCC.
So if someone compiles your app on OS X and they are using GCC and another person compiles on OS X using the Intel Compilers and you could optimized sections of the code for the Intel compilers if the person has them.
Would you just check a Preprocessor directive?
#ifdef __GCC_
// do it this way
#endif
#ifdef __INTEL__
// do it this way
#endif
#ifdef __GCC_WITH C++_V11_Support__
// do it this way
#endif
#idfef __WINDOWS_VISUAL_STUDIO
// do it this way
#endif
Or is there a better way?
How does one find a list of what directive a compiler offers for checking compiler version, etc
Don't choose the implementation based on predefined macros. Let the build system control it.
This lets you build and compare multiple implementations against each other during unit testing.
Typically, optimization follows the traditional 80/20 or 90/10 rule of "20% of the code takes 80% of the time to run" (and "20% of the code takes 80% of the time to develop"). Substitute 80/20 for 90/10 if you like - it's nearly always somewhere between those two...
So, the first stage of "do we optimize for a particular compiler" is to figure out what parts of your code are slow, and if you can make it any better in a generic way that works on all compilers (e.g. passing const reference rather than a copy of a large object). Once you have exhausted all generic improvements to the code, you may want to look at compiler specific optimizations - but that really requires that you gain enough that it really is worth the extra maintenance of having code that is different between the different compilers.
In general, I would very much avoid the "things are different in different compilers".
Generally speaking, compilers are written to optimize common code, not something specialized written specific for the compiler. So generally you should just focus on writing clean code, using the fastest algorithms. However some compilers are hintable, for instance gcc, through attributes using these attributes lets the compiler do its job better.
For instance using the noreturn attribute will allow gcc to discard function return code, thereby minimizing code size. I guess a lot of compilers have similar hinting schemes.
One could then do;
#ifdef GCC
#define NO_RETURN __attribute(...)
#else
#define NO_RETURN
#endif
And use NO_RETURN in your code.
Is there a way to get my hands on the intermediate source code produced by the OpenMP pragmas?
I would like to see how each kind of pragmas is translated.
Cheers.
OpenMp pragmas is part of a C / C++ compiler's implementation. Therefore before using it, you need to ensure that your compiler will support the pragmas ! If they are not supported, then they are ignored, so you may get no errors at compilation, but multi-thread wont work. In any case, as mentioned above, since they are part of the compiler's implementation, the best intermediate result that you can get is a lower level code. OpenMp is language extension + libraries, macros etc opposed to Pthreads that arms you purely with libraries !