Debug: Difference between revisions
Jump to navigation
Jump to search
Line 6: | Line 6: | ||
=== debug(), debugonce() and isdebugged() functions === | === debug(), debugonce() and isdebugged() functions === | ||
=== trace() and browser(), findLineNum() and setBreakpoint() === | |||
* [https://www.rdocumentation.org/packages/base/versions/3.6.2/topics/trace trace(what, tracer, exit, at, print, signature, where = topenv(parent.frame()), edit = FALSE)] | |||
* [https://www.rdocumentation.org/packages/base/versions/3.6.2/topics/browser browser(text = "", condition = NULL, expr = TRUE, skipCalls = 0L)] | |||
* as.list(body(myFun)). | |||
* [https://www.rdocumentation.org/packages/utils/versions/3.6.2/topics/findLineNum findLineNum() and setBreakpoint()] if we use '''source()''' to get the functions. Or [https://zhanxw.com/blog/2011/05/r代码除错-how-to-debug-r-code/ eval(parse(text=x))]. | |||
More complicated than '''debug()'''. To insert a browser() function, we don't need to modify the original function. | |||
[https://stackoverflow.com/a/8980282 browser() debug statement R] | |||
<pre> | |||
myFun <- function() { | |||
x <- 8:1 | |||
y <- 1:8 | |||
plot(y~x) | |||
lines(y~x) | |||
text(x,y, letters[1:8], pos=3) | |||
} | |||
as.list(body(myFun)) | |||
# [[1]] | |||
# `{` | |||
# | |||
# [[2]] | |||
# x <- 8:1 | |||
# | |||
# [[3]] | |||
# y <- 1:8 | |||
# | |||
# [[4]] | |||
# plot(y ~ x) | |||
# | |||
# ... More ... | |||
trace(myFun, browser, at = 4) | |||
myFun() | |||
untrace(myFun) | |||
</pre> | |||
There are several examples in ?trace(). | |||
<pre> | |||
## Very simple use. Not useful | |||
trace(sum) | |||
hist(rnorm(100)) # shows about 3-4 calls to sum() | |||
untrace(sum) | |||
## Show how pt() is called from inside power.t.test(): | |||
trace(pt) ## would show ~20 calls, but we want to see more: | |||
trace(pt, tracer = quote(cat(sprintf("tracing pt(*, ncp = %.15g)\n", ncp))), | |||
print = FALSE) # <- not showing typical extra | |||
power.t.test(20, 1, power=0.8, sd=NULL) ##--> showing the ncp root finding: | |||
untrace(pt) | |||
f <- function(x, y) { | |||
y <- pmax(y, 0.001) | |||
if (x > 0) x ^ y else stop("x must be positive") | |||
} | |||
## arrange to call the browser on entering and exiting | |||
## function f | |||
trace("f", quote(browser(skipCalls = 4)), | |||
exit = quote(browser(skipCalls = 4))) | |||
trace("f", quote(if(any(y < 0)) yOrig <- y), | |||
exit = quote(if(exists("yOrig")) browser(skipCalls = 4)), | |||
print = FALSE) | |||
## Enter the browser just before stop() is called. First, find | |||
## the step numbers | |||
untrace(f) # (as it has changed f's body !) | |||
as.list(body(f)) | |||
as.list(body(f)[[3]]) # -> stop(..) is [[4]] | |||
trace("f", quote(browser(skipCalls = 4)), at = list(c(3,4))) | |||
f(-1,2) | |||
## trace a utility function, with recover so we | |||
## can browse in the calling functions as well. | |||
trace("as.matrix", recover) | |||
## turn off the tracing (that happened above) | |||
untrace(c("f", "as.matrix")) | |||
</pre> | |||
=== How to quit debugging === | === How to quit debugging === |
Revision as of 16:17, 8 September 2020
R
How to debug an R code
- How to Easily and Efficiently Conquer Errors in Your Code
- Chapter 11 Debugging R code from the book What They Forgot to Teach You About R
- Debugging in R – How to Easily Overcome Errors in Your Code?. Examples are provided.
debug(), debugonce() and isdebugged() functions
trace() and browser(), findLineNum() and setBreakpoint()
- trace(what, tracer, exit, at, print, signature, where = topenv(parent.frame()), edit = FALSE)
- browser(text = "", condition = NULL, expr = TRUE, skipCalls = 0L)
- as.list(body(myFun)).
- findLineNum() and setBreakpoint() if we use source() to get the functions. Or eval(parse(text=x)).
More complicated than debug(). To insert a browser() function, we don't need to modify the original function.
myFun <- function() { x <- 8:1 y <- 1:8 plot(y~x) lines(y~x) text(x,y, letters[1:8], pos=3) } as.list(body(myFun)) # [[1]] # `{` # # [[2]] # x <- 8:1 # # [[3]] # y <- 1:8 # # [[4]] # plot(y ~ x) # # ... More ... trace(myFun, browser, at = 4) myFun() untrace(myFun)
There are several examples in ?trace().
## Very simple use. Not useful trace(sum) hist(rnorm(100)) # shows about 3-4 calls to sum() untrace(sum) ## Show how pt() is called from inside power.t.test(): trace(pt) ## would show ~20 calls, but we want to see more: trace(pt, tracer = quote(cat(sprintf("tracing pt(*, ncp = %.15g)\n", ncp))), print = FALSE) # <- not showing typical extra power.t.test(20, 1, power=0.8, sd=NULL) ##--> showing the ncp root finding: untrace(pt) f <- function(x, y) { y <- pmax(y, 0.001) if (x > 0) x ^ y else stop("x must be positive") } ## arrange to call the browser on entering and exiting ## function f trace("f", quote(browser(skipCalls = 4)), exit = quote(browser(skipCalls = 4))) trace("f", quote(if(any(y < 0)) yOrig <- y), exit = quote(if(exists("yOrig")) browser(skipCalls = 4)), print = FALSE) ## Enter the browser just before stop() is called. First, find ## the step numbers untrace(f) # (as it has changed f's body !) as.list(body(f)) as.list(body(f)[[3]]) # -> stop(..) is [[4]] trace("f", quote(browser(skipCalls = 4)), at = list(c(3,4))) f(-1,2) ## trace a utility function, with recover so we ## can browse in the calling functions as well. trace("as.matrix", recover) ## turn off the tracing (that happened above) untrace(c("f", "as.matrix"))
How to quit debugging
press Q and then ENTER
list or undebug all debugged functions
https://stackoverflow.com/a/12807637
Using assign() in functions
For example, insert the following line to your function
assign(envir=globalenv(), "GlobalVar", localvar)
options(error)
options( error = rlang::entrace, rlang_backtrace_on_error = "branch")
Debug lapply()/sapply()
- https://stackoverflow.com/questions/1395622/debugging-lapply-sapply-calls
- https://stat.ethz.ch/R-manual/R-devel/library/utils/html/recover.html. Use options(error=NULL) to turn it off.
Debugging with RStudio
- https://www.rstudio.com/resources/videos/debugging-techniques-in-rstudio/
- https://github.com/ajmcoqui/debuggingRStudio/blob/master/RStudio_Debugging_Cheatsheet.pdf
- https://support.rstudio.com/hc/en-us/articles/205612627-Debugging-with-RStudio
Debug R source code
Build R with debug information
- R -> Build R from its source on Windows
- http://www.stats.uwo.ca/faculty/murdoch/software/debuggingR/ (defunct)
- http://www.stats.uwo.ca/faculty/murdoch/software/debuggingR/gdb.shtml (defunct)
- Build R with debug information (see the discussion here). Cf output messages from running ./configure and make using the default options.
$ ./configure --help $ ./configure --enable-R-shlib --with-valgrind-instrumentation=2 \ --with-system-valgrind-headers \ CFLAGS='-g -O0 -fPIC' \ FFLAGS='-g -O0 -fPIC' \ CXXFLAGS='-g -O0 -fPIC' \ FCFLAGS='-g -O0 -fPIC' $ make -j4 $ sudo make install
- My note of debugging cor() function
- Using gdb to debug R packages with native code (Video) The steps to debug is given below.
# Make sure to create a file <src/Makevars> with something like: CFLAGS=-ggdb -O0 # Or more generally # CFLAGS=-Wall -Wextra -pedantic -O0 -ggdb # CXXFLAGS=-Wall -Wextra -pedantic -O0 -ggdb # FFLAGS=-Wall -Wextra -pedantic -O0 -ggdb $ tree nidemo $ R CMD INSTALL nidemo $ cat bug.R $ R -f bug.R $ R -d gdb (gdb) r > library(nidemo) > Ctrl+C (gdb) b nid_buggy_freq (gdb) c # continue > buggy_freq("nidemo/DESCRIPTION") # stop at breakpoint 1 (gdb) list (gdb) n # step through (gdb) # press RETURN a few times until you see the bug (gdb) d 1 # delete the first break point (gdb) b Rf_error # R's C entry point for the error function (gdb) c > buggy_freq("nidemo/DESCRIPTION") (gdb) bt 5 # last 5 stack frames (gdb) frame 2 (gdb) list (gdb) p freq_data (gdb) p ans (gdb) call Rf_PrintValues(ans) (gdb) call Rf_PrintValues(fname) (gdb) q # Edit buggy.c $ R CMD INSTALL nidemo # re-install the package $ R -f bug.R $ R -d gdb (gdb) run > source("bug.R") # error happened (gdb) bt 5 # show the last 5 frames (gdb) frame 2 (gdb) list (gdb) frame 1 (gdb) list (gdb) p file (gdb) p fh (gdb) q # Edit buggy.c $ R CMD INSTALL nidemo $ R -f bug.R
- Compiled code from "R packages" by Hadley Wickham
- Debugging C/C++ code from Bioconductor (case study)
- Same idea for the Rcpp situation. See What are productive ways to debug Rcpp compiled code loaded in R (on OS X Mavericks)?
.Call
- Writing R Extensions manual.
- R’s C interface from Advanced R by Hadley Wickham
Registering native routines
https://cran.rstudio.com/doc/manuals/r-release/R-exts.html#Registering-native-routines
Pay attention to the prefix argument .fixes (eg .fixes = "C_") in useDynLib() function in the NAMESPACE file.
Example of debugging cor() function
Note that R's cor() function called a C function cor().
stats::cor .... .Call(C_cor, x, y, na.method, method == "kendall")
A step-by-step screenshot of debugging using the GNU debugger gdb can be found on my Github repository https://github.com/arraytools/r-debug.