Development (original) (raw)
Guidelines
Developers without write access to the adcomp repository can contribute with code or documentation by forking the project and sending a pull request once the code has been changed.
Recommended workflow (fork and pull request)
- Let your own master branch be an exact copy of the official master branch:
git remote add official https://github.com/kaskr/adcomp.git
Synchronize frequently:
git checkout master
git pull official master
- Never commit directly to your master. Work on a local branch and send pull requests only for the local branch:
git checkout -b local_branch
Do work, commit and push to you github account:git push origin local_branch
Send pull request for 'local_branch'. - Once your pull request is accepted, synchronize the master branch:
git checkout master
git pull official master
And delete you local branchgit branch -d local_branch
Remember to delete it on github:git push origin --delete local_branch
For developers with write access to the adcomp repository:
- The master branch should be stable and never get into a broken state. Therefore: Never push changes directly to the master branch. Development must be performed on a separate branch (named by e.g. developers name or the topic of change) which is pushed to the adcomp repository.
- When code is ready, send request to review and merge into the master branch.
- The following tests must be performed before changes can be merged (to ensure nothing is broken on any platforms):
cd tmb_examples;make clean;make
must pass.- The file REPORT.md must be inspected for inaccuracies and performance regressions.
runExample(all=TRUE)
must pass.- Above should be tested with both gcc and clang on linux.
- Tests should also be run on Windows and OSX.
Conventions
- Text files should have Unix line endings. Check with
file
command from command line that output looks like e.g.sdv_multi.cpp: ASCII C program text
withoutCR+LF
. - Text files should not be executable.
Code formatting
Automated code formatting is recommended for new files
- For internal C++ use
clang-format-3.6 -i -style="{BasedOnStyle: Google, Standard: Cpp03}" file.cpp - For C++ model templates use
clang-format-3.6 -i -style="{BasedOnStyle: Google, Standard: Cpp03, BreakBeforeBraces: Linux}" file.cpp - For R code use
library(formatR)
tidy_source("file.R", arrow=TRUE)
Distributing code
Probably the easiest way to distribute TMB code is to use R's package functionality. You can get a test package working following these steps (with mypkg
replaced by the name of your package):
package.skeleton("mypkg")
- Copy model.cpp to mypkg/src
- Add
Depends: TMB
LinkingTo: TMB, RcppEigen
to the filemypkg/DESCRIPTION
to ensure that TMB is loaded when mypkg is loaded, and that the TMB source code is found when compiling mypkg. - Add
useDynLib(mypkg)
to the filemypkg/NAMESPACE
to ensure that the compiled code is loaded when you load the package. - Pass
DLL="mypkg"
to allMakeADFun
calls.
TMB uses some features that are against the CRAN polices (e.g. calling abort()
to step into the debugger). In order to pass CRAN checks a few workarounds may be required:
- Edit model.cpp to avoid CRAN warning
Found no calls to: ‘R_registerRoutines’, ‘R_useDynamicSymbols’
:
#define TMB_LIB_INIT R_init_mypkg
#include <TMB.hpp>
In addition this enables 'C-callables' tmb_forward
and tmb_reverse
required by tmbstan
.
- To avoid notes such as
Found ‘_ZSt4cout’, possibly from ‘std::cout’ (C++)
use the CRAN version of TMB when checking the package. - To avoid the warning
Found ‘_abort’, possibly from ‘abort’
make sure the preprocessor flag-DTMB_SAFEBOUNDS
does not appear during compilation (if you use your own Makefile passsafebounds=FALSE
tocompile
). - To avoid the warning
Found non-API call to R: ‘R_RunExitFinalizers’
make sure the preprocessor flag-DTMB_SAFEUNLOAD
does not appear during compilation (if you use your own Makefile passsafeunload=FALSE
tocompile
).
Other notes:
- While developing you can add a file
mypkg/src/Makevars
with compiler and preprocessor flags - see the relevant section in the R Extensions manual ;PKG_CXXFLAGS="-O0 -g"
can be used for debugging.
Locating regressions and bugs
Suppose you update TMB and suddenly your model runs slow or has other issues. To find the commit that caused the problem, we can apply 'git bisect'.
- Clone a fresh adcomp folder and
cd adcomp
. - Copy a selfcontained test example e.g. 'mymodel.R' and 'mymodel.cpp' to this folder.
- Make R-script 'bisect.R' containing:
Re-install TMB and re-compile model:
system("make install")
library(TMB)
system("rm -f *.o *.so")
compile("mymodel.cpp")
Run model under restricted permissions
status <- system("ulimit -t 20; R --vanilla < mymodel.R")
if(status != 0) stop("Fail")
Here 'ulimit -t 20' interrupts the model run if it takes more than 20 sec. Alternatively 'ulimit -v 100000' would trigger interruption if the model uses more than 100Mb.
4. Make an executable shell script 'bisect.sh' containing:
#/bin/bash
R --vanilla < bisect.R
5. Verify that the script fails now and that it worked e.g. 40 commits ago:
git checkout master
./bisect.sh
git checkout HEAD4040
./bisect.sh
6. Now we can start bisecting:
git checkout master
git bisect start
git bisect bad HEAD
git bisect good HEAD
git bisect run ./bisect.sh
The first bad commit will be displayed.