Ok… so, I got massif to work on a very simple “hello world” program. Now, let’s try it with something we’re actually interested in.
First, the C++ code:
int main(void) {
using stan::math::var;
using stan::math::matrix_exp_2x2;
using stan::math::set_zero_all_adjoints_nested;
using stan::math::recover_memory_nested;
using stan::math::start_nested;
using Eigen::Matrix;
using Eigen::Dynamic;
using Eigen::MatrixXd;
using std::cout;
using std::vector;
std::default_random_engine generator;
std::uniform_real_distribution<double> unif(1, 10);
// Randomly generate entries of the matrix we will exponentiate.
vector<vector<double> > theta_dbl(100);
for (int i = 0; i < 1000; i++) {
double a = unif(generator),
b = unif(generator),
c = unif(generator),
d = unif(generator);
theta_dbl[i] = {a, b, c, d};
}
MatrixXd J(4, 4);
vector<double> row = {0, 1, 0, 1};
vector<double> col = {0, 0, 1, 1};
int N_tests = 100;
vector<double> results(N_tests);
for (int n_test = 0; n_test < N_tests; n_test++) {
for (int j = 0; j < 1000; j++) {
start_nested();
vector<var> theta = {theta_dbl[j][0], theta_dbl[j][1],
theta_dbl[j][2], theta_dbl[j][2]};
Matrix<var, Dynamic, Dynamic> A_v(2, 2);
A_v << theta[0], theta[1], theta[2], theta[3];
Matrix<var, Dynamic, Dynamic>
exp_A = matrix_exp_2x2(A_v);
// exp_A = matrix_exp_2x2_standard(A_v);
//compute Jacobian
for (int k = 0; k < 4; k++) {
if (k > 0) set_zero_all_adjoints_nested();
grad(exp_A(row[k], col[k]).vi_);
for (int i = 0; i < 4; i++) J(i, k) = theta[i].adj();
}
// cout << J << "\n \n";
recover_memory_nested();
}
}
return 0;
}
}
Then, compile and run massif from the terminal window:
clang++ -g -std=c++11 -I ../math/ -I lib/eigen_3.3.3/ -I lib/cvodes-3.1.0/include/ -I lib/boost_1.66.0/ -I lib/idas-2.1.0/include/ $1
valgrind --tool=massif ./a.out
This returns the following warning message:
==98198== Process terminating with default action of signal 11 (SIGSEGV)
==98198== Access not within mapped region at address 0x0
==98198== at 0x1007A5FA9: _platform_memmove$VARIANT$Haswell (in /usr/lib/system/libsystem_platform.dylib)
==98198== by 0x10003EC00: _ZNSt3__16vectorIdNS_9allocatorIdEEE6assignIPKdEENS_9enable_ifIXaasr21__is_forward_iteratorIT_EE5valuesr16is_constructibleIdNS_15iterator_traitsIS8_E9referenceEEE5valueEvE4typeES8_S8_ (algorithm:1722)
==98198== by 0x1000015C2: main (vector:563)
==98198== If you believe this happened as a result of a stack
==98198== overflow in your program's main thread (unlikely but
==98198== possible), you can try to increase the size of the
==98198== main thread stack using the --main-stacksize= flag.
==98198== The main thread stack size used in this run was 8388608.
Segmentation fault: 11 valgrind --tool=massif ./a.out
even though the executionable itself runs fine.
Looking at the output with:
ms_print massif.out.98198
we get rather long and intricate print. My instinct is to look at total (B)
, the bytes used on both the useful and the extra heap. I get 91,904, when with the hello world
code I got around 80,000. I’m not sure how to interpret these results and whether to trust them.
There’s a lot documentation to dig into, but I’m hopping someone with experience doing these tests can give me some pointers. Thanks!