I'm using RcppEigen to write some C++ functions for my R code, and I'd like to optimize their compilation as much as possible. When I've used Eigen in the past, I've gotten a significant boost from -O3 and -fopenmp. Following Dirk's advice, I edited ~/.R/Makevars so that my Eigen code would be compiled with these flags:
CPPFLAGS=-O3 -fopenmp
This works--when I check what's happening during compilation (ps ax | grep cpp) I see:
27097 pts/6 R+ 0:00 /usr/libexec/gcc/x86_64-redhat-linux/4.4.7/cc1plus -quiet -I/usr/include/R -I/home/sf/R/x86_64-redhat-linux-gnu-library/3.0/Rcpp/include -I/home/sf/R/x86_64-redhat-linux-gnu-library/3.0/RcppEigen/include -D_GNU_SOURCE -D_REENTRANT -DNDEBUG -D_FORTIFY_SOURCE=2 file69b757e053ad.cpp -quiet -dumpbase file69b757e053ad.cpp -m64 -mtune=generic -auxbase-strip file69b757e053ad.o -g -O3 -O2 -Wall -fopenmp -fpic -fexceptions -fstack-protector --param ssp-buffer-size=4 -o -
The flags I wanted are there, -O3 and -fopenmp. But I also see -O2 there, which is presumably the system-wide default (I verified this by removing ~/.R/Makevars and indeed, -O2 is there but -O3 and -fopenmp are not.)
So the question: how do I get rid of the -O2? Or, does it actually matter? The g++ man page says:
-O3 Optimize yet more. -O3 turns on all optimizations specified by -O2 and also
turns on the -finline-functions, -funswitch-loops, -fpredictive-commoning, -fgcse-
after-reload, -ftree-vectorize and -fipa-cp-clone options.
So maybe it's fine to have both -O2 and -O3?
I think you need CXXFLAGS not CPPFLAGS in your ~/.R/Makevars
I set Makevars in the following repo to benchmark various C++ compiler flags in R/Rcpp
https://github.com/jackwasey/optimization-comparison
I use a function from https://github.com/jimhester/covr to do that programmatically, if that's of use to you.
Also, did you see the following? R: C++ Optimization flag when using the inline package
Related
My compile flags are
-mthumb -mlittle-endian -x c++ -gdwarf-2 -g3 -fomit-frame-pointer -fnothrow-opt
-ffreestanding -fverbose-asm -std=c++11 -c -fno-rtti -ffunction-sections -fdata-sections
-fno-exceptions`
Note the -gdwarf-2 -g3
However, many of the variables I attempt to read are read as
optimized out
-g adds debugging information, but it does not discourage code optimisations, so you've only asked for half the job.
Add on -O0 or -Og and have a read of the manual page on debugging options.
You've also specifically turned on one optimisation (-fomit-frame-pointer); remove that.
We have a complex hierarchical make file system where the CXXFLAGS is appended in several places (several separate makefiles of individual libraries).
There's one master file that seems to be getting included in every other make file. So I specified the -fno-omit-frame-pointer flag there.
When I compile, I see the above flag and after that I see -O2. My question is, if the -O2 flag sets -fomit-frame-pointer, will the latest setting take effect?
With gcc/g++ you can use the -Q --help=optimizers flags to find out the exact set of optimizations that are enabled.
With my version of gcc I get:
$ gcc -Q --help=optimizers -O2 | fgrep omit-frame-pointer
-fomit-frame-pointer [enabled]
and
$ gcc -Q --help=optimizers -fno-omit-frame-pointer -O2 | fgrep omit-frame-pointer
-fomit-frame-pointer [disabled]
So -O2 doesn't seem to overwrite the previous -fno-omit-frame-pointer.
Anyway check your environment.
I am on a complex project built in python2.7 that uses the PyDSTool package for analysis of dynamical system. PyDSTool provides two C-based integrators - Radau and Dopri - which I want to use to integrate my system of equations whose source is coded in a bunch of C/C++ files.
I have little control on the package, and when I instantiate the integrator, I can only add headers *.H files, source files (*.C, *.CPP) and pass the directories to include in the search path of the compiler as well as libraries to link to.
Since a consistent part of the code is based on C++11 I am passing to the compiler also the argument -std=C++11.
Eventually, /PyDSTool/Generators/mixins.py launch a setup command (line 185) which in turn runs the command build_ext from distutils to which all the above flags are appended.
For the sake of clarity: the flags that I am appending are:
compile options: '-I/usr/lib64/python2.7/site-packages/numpy/core/include -I/home/maurizio/Dropbox/StabilityAnalysis_tmp -I/usr/local/pydstool/PyDSTool/integrator -I/usr/include/python2_7 -I/usr/include/numpy -I/home/maurizio/Dropbox/Ongoing_Projects/pycustommodules -I/home/maurizio/Dropbox/Ongoing_Projects/c_libraries -I/home/maurizio/Dropbox/Ongoing_Projects/c_libraries/models -I/home/maurizio/Dropbox/Ongoing_Projects/DePitta_PNAS/Software/Stability_Analysis/ -I/usr/lib64/python2.7/site-packages/numpy/core/include -I/usr/include/python2.7 -c'
extra options: '-std=c++11 -w -Wno-return-type -Wall -lpython2.7 -lm -lgsl -lgslcblas -D__DOPRI__'
The resulting compilation command as issued by PyDSTool reads:
error: Command "gcc -pthread -fno-strict-aliasing -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/usr/lib64/python2.7/site-packages/numpy/core/include -I/home/maurizio/Dropbox/StabilityAnalysis_tmp -I/usr/local/pydstool/PyDSTool/integrator -I/usr/include/python2_7 -I/usr/include/numpy -I/home/maurizio/Dropbox/Ongoing_Projects/pycustommodules -I/home/maurizio/Dropbox/Ongoing_Projects/c_libraries -I/home/maurizio/Dropbox/Ongoing_Projects/c_libraries/models -I/home/maurizio/Dropbox/Ongoing_Projects/DePitta_PNAS/Software/Stability_Analysis/ -I/usr/lib64/python2.7/site-packages/numpy/core/include -I/usr/include/python2.7 -c /home/maurizio/Dropbox/StabilityAnalysis_tmp/dop853_temp/ei_network_vf.c -o /home/maurizio/Dropbox/StabilityAnalysis_tmp/dop853_temp/home/maurizio/Dropbox/StabilityAnalysis_tmp/dop853_temp/ei_network_vf.o -std=c++11 -w -Wno-return-type -Wall -lpython2.7 -lm -lgsl -lgslcblas -D__DOPRI__" failed with exit status 1
Once looking into the build.log file automatically generated by PyDSTool, it turns out that the exit status is due to the fact that the compiler does not see the C++ libraries that are in several routines/libs used by my code, e.g.
/usr/include/blitz/blitz.h:45:18: fatal error: string: No such file or directory
#include <string>
^
Compilation Terminated
Now, it is not a problem of my code, because if I compile my code as a standalone in python or through scipy.weave with the same compile and extra options pasted above, it works. It is a problem of making PyDSTool build the code within the integrator. As I am NOT practical with distutils and all gcc options I hope there is some expert here that could provide me with some insight. I suspect in fact that I am missing some options or whatever to pass to the compiler.
Just for the sake of completeness. The issue I pointed out above does not have an easy workaround. PyDSTool C-based integrators (i.e. Radau and Dopri) cannot be compiled with source code for the equations in C++ but only in C. So either you recast your code in plain C or try to edit PyDSTool integrators and recast them in C++. The first option is likely the only one currently possible (at least to some non-experts as who is writing).
I have a rather complex multithreaded code, which I compile using gcc 4.8.1. When compiling with
g++ -c file.cc -march=native -mfpmath=sse -mpreferred-stack-boundary=4
--param inline-unit-growth=50 -ggdb3 -Wall -Wextra -Winit-self
-O2 -fPIC -funroll-loops -fforce-addr -rdynamic
the code produced crashes with segfault (which I was unable to debug, but the address of a struct all of a sudden differs from what it was when constructed, in particular, is no longer aligned to 32bytes as required by the code but only to 8bytes).
When compiling with -O1 instead, the code works fine. I then added all the optimisation flags that make the difference between -O1 and -O2. (To this end, I created two files O1-opts and O2-opts via
g++ -march=native -mfpmath=sse -mpreferred-stack-boundary=4
--param inline-unit-growth=50 -ggdb3 -Wall -Wextra -Winit-self
-O1 -fPIC -funroll-loops -fforce-addr -rdynamic
-Q --help=optimizers > O1-opts
g++ -march=native -mfpmath=sse -mpreferred-stack-boundary=4
--param inline-unit-growth=50 -ggdb3 -Wall -Wextra -Winit-self
-O2 -fPIC -funroll-loops -fforce-addr -rdynamic
-Q --help=optimizers > O2-opts
when diff O1-opts O2-opts provides the option differences). When adding all the option differences to -O1, the code generated still does not crash. This puzzles me. So my question is: shouldn't this give exactly the same result as with -O2? (and also: what is the likely cause of my problem?)
The point is that the -O2 option not only sets different flags, but also enables additional optimizations in contrast to -O1.
The FAQ section of the GCC Wiki has an appropriate entry for this.
I have this standalone C++ code
that I'm trying to wrap in an R
package.
My problem is that I absolutely
want it to be compiled with the
-O3 flag on.
So in the src/Makevars file
I put:
PKG_CPPFLAGS = -I../inst/include
PKG_CXXFLAGS = -O3
CXX_STD = CXX11
and still when I install my package on my
machine, I see:
g++ -std=c++0x -I/usr/share/R/include -DNDEBUG -I../inst/include -O3 -fpic -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security -D_FORTIFY_SOURCE=2 -g -c mycppfunctions.cpp -o mycppfunctions.o
g++ -std=c++0x -shared -Wl,-Bsymbolic-functions -Wl,-z,relro -o mycppfunctions.so mycppfunctions.o -L/usr/lib/R/lib -lR
(the dreaded -O2 flag appears to the right)
so my question is: how can I overwrite the
cpp flags used when g++ is invoked by R CMD?
Edit:
Recently, in another package, I found a way to do
something similar for a F77 code (also in an R package).
Basically, by adding this to the Makevars:
PKG_FFLAGS = $(FPICFLAGS) $(SHLIB_FFLAGS)
all: $(SHLIB)
otherf77foo.o: otherf77foo.f
$(F77) $(PGK_FFLAGS) -O3 -pipe -g -c -o otherf77foo.o otherf77foo.f
but I don't know how to do the same for a cpp code...
Edit2:
So, doing this is totally possible. Dirk Eddelbuettel question 'b)' from his answer below
guided me to the solution. So, all I had to do was to
place this in the src/Makevars file:
mycppfoo.o: mycppfoo.cpp
g++ -std=c++0x -I/usr/share/R/include -DNDEBUG -I../inst/include -fpic -g -O3 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security -D_FORTIFY_SOURCE=2 -g -c mycppfoo.cpp -o mycppfoo.o
g++ -std=c++0x -shared -Wl,-Bsymbolic-functions -Wl,-z,relro -o mycppfoo.so mycppfoo.o -L/usr/lib/R/lib -lR
and my problem was solved!
You can't (as per a comment by Simon Urbanek on r-devel a while back).
But it should not matter as AFAIK the right-most value wins. And R puts its values to the left, and lets you add your values (eg via CXX_FLAGS from, say, ~/.R/Makevars or PKG_CXXFLAGS from the src/Makevars in your package) to the right.
So just override with -O3 and it should be -O3.
For what it is worth, my current values in ~/.R/Makevars are:
CFLAGS += -O3 -Wall -pipe -pedantic -std=gnu99
CXXFLAGS += -O3 -Wall -pipe -Wno-unused -pedantic
and you could of course throw in -mnative or your specific CPU identifier.
Lastly, if you really wanted you could edit /etc/R/Makeconf but you'd have to do that
after each upgrade of the R package. And as I argue here you do not need to as the scheme suggested here should work.
Edit: In response to your edit:
a) The clear recommendation on r-devel (please check the archives) is that you should avoid Makefile logic if you can. IIRC this echoed in the Writing R Extension manual.
b) You declared a rule to build an .o (object) file from an .f (source) file. Did you try doing the same with cpp instead of f?
Lastly, you have not explained exactly why the world is coming to an end if your file is built with -O2 rather than -O3. You should understand that as an author of source, you can't fully control with which compiler options (let alone compiler versions) people will build your package.
newedit: Okay I'm a fool. It solved the problem for Rcpp (which I don't care about), but it doesn't work for the github.com/ohdsi/cyclops.git package that I do care about. That one still gets -O2 stuck right-most. This is ridiculous. Control over command-line parameters might be the single most important piece of this entire operation. R needs a better build system.
edit: Of course after days of trouble, I figure it out right after posting. My problem was that I was using the CXX_STD = CXX11 flag. Apparently with this flag you need to use CXX11FLAGS += .... So if your Makevars file contains CXX11FLAGS += -O0 -Wall it will correctly put this to the right of the -O2 flag if you're using C++11.
No matter what I do I can't get -O0 to show up on the right. I have the following in my ~/.R/Makevars:
CFLAGS += -O0 -Wall
CXXFLAGS += -O0 -Wall
CPPFLAGS += -O0 -Wall
PKG_CFLAGS += -O0 -Wall
PKG_CXXFLAGS += -O0 -Wall
PKG_CPPFLAGS += -O0 -Wall
I have installed Rcpp from source (as a test...I'm not interested in it directly) using
install.packages(getwd(), repos = NULL, type = "source")
and that did correctly use -O0.
With my current configuration, I end up getting three different -O0's to the left and final -O2 on the right. Has anyone else run into this problem?
The software I'm installing is at github.com/ohdsi/cyclops.git, though I'm not sure what that would be important.