Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to debug (line-by-line) Rcpp generated code in Windows?

Tags:

r

rcpp

I am trying to debug Rcpp compiled code at run-time. I have been trying to get this to work unsuccessfully, for a very long time. A very similar question was asked here: Debugging (line by line) of Rcpp-generated DLL under Windows which asks the same question, but both the question and the answer are far beyond my understanding.

Here is what I have:

Windows 7 Pro SP1
R 3.5
Rstudio 1.1.463 with Rcpp.
Rbuild Tools from Rstudio. (c++ compiler)

Procedure: In Rstudio File->New File->C++ File (creates a sample file with a timesTwo function.)

I added a new function in this file:

// [[Rcpp::export]]
NumericVector timesTwo2(NumericVector x) {
  for(int ii = 0; ii <= x.size(); ii++)
  {
    x.at(ii) = x.at(ii) * 2;
  }
  return x;
}

I checked Source on Save and saved the file as RcppTest.cpp which sources or complies the file successfully.

Run code in Rstudio:

data = c(1:10)
data
[1]  1  2  3  4  5  6  7  8  9 10
timesTwo2(data)
Error in timesTwo2(data) : Index out of bounds: [index=10; extent=10].

The error is because in the for loop is <= x.size() so the result is a run-time error.

The question is how can get a debug output about this error that reasonably tells me what happened? At the very least I would like to know the line in the code that triggered the exception and with which parameters. Furthermore, I would really like to execute the code line-by-line to just before the exception so I can monitor exactly what is happening.

I can install any additional programs or apply any other settings as long as I can find precise details on how to do it. For now I am starting from scratch just to get it working. Thank you.

Update: I found this site: Debugging Rcpp c++ code using gdb I installed the latest gcc 8.1 with gdb

I found the CXXFLAGS in the makeconf file located in C:\Program Files\R\R-3.5.1\etc\x64 Then I started the Rgui as suggested, but when I try Rcpp:::sourceCpp I get an error:

> library(Rcpp)
> Rcpp::sourceCpp('Rcpptest.cpp')
C:/PROGRA~1/R/R-35~1.1/etc/x64/Makeconf:230: warning: overriding recipe for target '.m.o'
C:/PROGRA~1/R/R-35~1.1/etc/x64/Makeconf:223: warning: ignoring old recipe for target '.m.o'
c:/Rtools/mingw_64/bin/g++  -I"C:/PROGRA~1/R/R-35~1.1/include" -DNDEBUG   -I"C:/Users/Michael/Documents/R/win-library/3.5/Rcpp/include" -I"C:/PROGRA~1/R/R-35~1.1/bin/x64"        -ggdb -O0 -Wall -gdwarf-2 -mtune=generic -c Rcpptest.cpp -o Rcpptest.o
process_begin: CreateProcess(NULL, c:/Rtools/mingw_64/bin/g++ -IC:/PROGRA~1/R/R-35~1.1/include -DNDEBUG -IC:/Users/Michael/Documents/R/win-library/3.5/Rcpp/include -IC:/PROGRA~1/R/R-35~1.1/bin/x64 -ggdb -O0 -Wall -gdwarf-2 -mtune=generic -c Rcpptest.cpp -o Rcpptest.o, ...) failed.
make (e=2): The system cannot find the file specified.

make: *** [C:/PROGRA~1/R/R-35~1.1/etc/x64/Makeconf:215: Rcpptest.o] Error 2
Error in Rcpp::sourceCpp("Rcpptest.cpp") : 
  Error 1 occurred building shared library.

WARNING: The tools required to build C++ code for R were not found.

Please download and install the appropriate version of Rtools:

http://cran.r-project.org/bin/windows/Rtools/

It looks like it is loading the new CXXFLAGS and it is using DEBUG, but it seems that it still cannot compile. Anybody know why from the error?

I tried running Rstudio the same way as Rgui and it started with many threads showing in the gdb window, but everything in Rstudio ran exactly as before with no additional debug information from Rstudio or gdb.

Update 2: As the error above states that Rgui did not have Rtools for compiling so I installed the Rtools from the provide link. It installed in C:\Rtools while Rstudio installed in C:\RBuildTools. So I now have 3 compilers, Rtools, RbuildTools and gcc with gdb. It compiles now, but still gives the same error as I did in Rstudio. I would like to at least get better error output, like the line and value passed. The instruction say Rgui should have a spot for a break-point, but I cannot find such an option.

Update 3 I was finally able to set up and run a Linux install (Ubuntu 16.04.05). First here are my CXXFLAGS:

$ R CMD config CXXFLAGS
-g -O0 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g

I had to create a .R folder in my home directory and a Makevar file in it with just the line

CXXFLAGS = -g -O0 -Wall -pedantic -fstack-protector-strong -D_FORTIFY_SOURCE=2

This alone took hours as nowhere did it actually say make the folder and file.

Then I executed the commands as Ralf posted, at the break point:

> timesTwo2(d1)

Thread 1 "R" hit Breakpoint 1, timesTwo2 (x=...) at RcppTest.cpp:19
19  NumericVector timesTwo2(NumericVector x) {
(gdb) n
20    for (int ii = 0; ii <= x.size(); ii++)
(gdb) n
22      x.at(ii) = x.at(ii) * 2;
(gdb) display ii
1: ii = 0
(gdb) n
20    for (int ii = 0; ii <= x.size(); ii++)
1: ii = 0
(gdb) n
22      x.at(ii) = x.at(ii) * 2;
1: ii = 1
(gdb) n
20    for (int ii = 0; ii <= x.size(); ii++)
1: ii = 1
(gdb) display x.at(ii)
2: x.at(ii) = <error: Attempt to take address of value not located in memory.>
(gdb) n
22      x.at(ii) = x.at(ii) * 2;
1: ii = 2
2: x.at(ii) = <error: Attempt to take address of value not located in memory.>
(gdb) 

And finally at n = 10:

1: ii = 10
2: x.at(ii) = <error: Attempt to take address of value not located in memory.>
(gdb) n
0x00007ffff792d762 in Rf_applyClosure () from /usr/lib/R/lib/libR.so
(gdb) 

This is definitely the furthest I have come to debugging, but this is a very basic function and the debug output and even the error output was not very useful. It gave me the line it was executing and it could display ii, but I could not display the array value or the entire array. Is it possible to create a more specific break point such that it only breaks when ii == 10? Ideally I would like this in Rstudio or some other GUI that can display the entire vector. Still doing more testing.

like image 642
MichaelE Avatar asked Dec 04 '18 22:12

MichaelE


People also ask

How do I debug an app Line by line?

It also allows you to pause the app at any point to examine its state, and to then step through your code line by line to watch every detail as it happens. In Visual Studio, you enter debugging mode by using F5 (or the Debug > Start Debugging menu command or the Start Debugging button in the Debug Toolbar).

What is the RCPP C++ library?

Rcpp supports implementing R functions in C++ for high performance computing and to easily interface R with external libraries. The RStudio IDE has a number of features that support working with Rcpp, including:

How to debug an app in Visual Studio Code?

Press F5 or the Start Debugging button in the Debug Toolbar, located above the code editor. The app starts and there are no exceptions shown to us by the debugger. However, the output you see in the console window is not what you expect. Here is the expected output:

What does it mean to debug a program?

Debugging means to run your code step by step in a debugging tool like Visual Studio, to find the exact point where you made a programming mistake. You then understand what corrections you need to make in your code, and debugging tools often allow you to make temporary changes so you can continue running the program.


1 Answers

The usual approach R -d gdb, which I also suggested in my original answer below, does not work on Windows:

--debugger=name
-d name

(UNIX only) Run R through debugger name. For most debuggers (the exceptions are valgrind and recent versions of gdb), further command line options are disregarded, and should instead be given when starting the R executable from inside the debugger.

https://cran.r-project.org/doc/manuals/r-release/R-intro.html#Invoking-R-from-the-command-line

Alternative:

  1. Start R in debugger: gdb.exe Rgui.exe
  2. Set break point: break TimesTwo2
  3. Run R: run
  4. Source file: Rcpp::sourceCpp("debug.cpp")
  5. Use next, print, display to step through the code.

An alternative to step 1. would be to start R, get the PID with Sys.getpid(), attach debugger with gdb -p <pid>. You will than have to use continue instead of run.


I don't have a Windows machine right now, so the following was done on Linux. I hope it is transferable, though. Let's start with a simple cpp file (debug.cpp in my case) that contains your code:

#include <Rcpp.h>
using Rcpp::NumericVector;

// [[Rcpp::export]]
NumericVector timesTwo2(NumericVector x) {
  for(int ii = 0; ii <= x.size(); ii++)
  {
    x.at(ii) = x.at(ii) * 2;
  }
  return x;
}

/*** R
data = c(1:10)
data
timesTwo2(data)
*/

I can reproduce the error by calling R on the command line:

$ R -e "Rcpp::sourceCpp('debug.cpp')"

R version 3.5.1 (2018-07-02) -- "Feather Spray"
[...]

> Rcpp::sourceCpp('debug.cpp')

> data = c(1:10)

> data
 [1]  1  2  3  4  5  6  7  8  9 10

> timesTwo2(data)
Error in timesTwo2(data) : Index out of bounds: [index=10; extent=10].
Calls: <Anonymous> ... source -> withVisible -> eval -> eval -> timesTwo2 -> .Call
Execution halted

Next we can start R with gdb as debugger (c.f. Writing R Extensions as Dirk said):

$ R -d gdb -e "Rcpp::sourceCpp('debug.cpp')"
GNU gdb (Debian 8.2-1) 8.2
[...]
(gdb) break timesTwo2
Function "timesTwo2" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (timesTwo2) pending.
(gdb) run
[...]
> Rcpp::sourceCpp('debug.cpp')
[Thread 0xb40d3b40 (LWP 31793) exited]
[Detaching after fork from child process 31795]

> data = c(1:10)

> data
 [1]  1  2  3  4  5  6  7  8  9 10

> timesTwo2(data)

Thread 1 "R" hit Breakpoint 1, 0xb34f3310 in timesTwo2(Rcpp::Vector<14, Rcpp::PreserveStorage>)@plt ()
   from /tmp/RtmphgrjLg/sourceCpp-i686-pc-linux-gnu-1.0.0/sourcecpp_7c2d7f56744b/sourceCpp_2.so
(gdb)

At this point you can single step through the program using next (or just n) and output variables using print (or just p). A useful command is also display:

Thread 1 "R" hit Breakpoint 1, timesTwo2 (x=...) at debug.cpp:5
5   NumericVector timesTwo2(NumericVector x) {
(gdb) n
6     for(int ii = 0; ii <= x.size(); ii++)
(gdb) n
8       x.at(ii) = x.at(ii) * 2;
(gdb) display ii
2: ii = 0
(gdb) n
8       x.at(ii) = x.at(ii) * 2;
2: ii = 0

[...]

2: ii = 9
(gdb) 
46          inline proxy ref(R_xlen_t i) { return start[i] ; }
2: ii = 9
(gdb) 
6     for(int ii = 0; ii <= x.size(); ii++)
2: ii = 10
(gdb) 
8       x.at(ii) = x.at(ii) * 2;
2: ii = 10
(gdb) 
Error in timesTwo2(data) : Index out of bounds: [index=10; extent=10].
Calls: <Anonymous> ... source -> withVisible -> eval -> eval -> timesTwo2 -> .Call
Execution halted
[Detaching after fork from child process 32698]
[Inferior 1 (process 32654) exited with code 01]

BTW, I used the following compile flags:

$ R CMD config CXXFLAGS
-g -O2 -Wall -pedantic -fstack-protector-strong -D_FORTIFY_SOURCE=2

You might want to switch to -O0.

like image 182
Ralf Stubner Avatar answered Oct 03 '22 12:10

Ralf Stubner