Registered Member
|
I think it might be useful to have a tutorial or FAQ on memory management in Eigen. In particular:
What actions trigger dynamic memory allocation? * MatrixXf x = MatrixXf::Zero(rows, cols); * x.setZero(int, int) and friends. (always, or only when needed?) * temporary variables in expressions? * conservative resize functions * writing to a .corner() slice that extends past the current storage? When does storage get freed by Eigen? * Automatically whenever any dynamic array goes out of scope? * Explicitly by the user by resizing an array to 0? Are there any common/subtle ways to accidentally leak memory in Eigen code? Is there a way to check if I'm accidentally triggering dynamic memory allocation in a time critical block of code? * mess around with strace grep? * mtrace? * maybe some global variable RECENT_DYNAMIC_ALLOCATION that you can set to false at the start of your block and check after (but only exists in debug mode)? Do I ever need to worry about the storage cost of Matrix headers, and try to re-use them by messing around with pointers? * No, the templates get almost completely optimized away by the compiler; you almost certainly have better things to worry about. How does Eigen handle column vs. row major storage? * #define... can change the default * Arrays of different storage can be mixed freely * Eigen should write optimized code for both storage types, however: * some computations may be inherently faster if matrices are stored one way rather than another, i.e. computing A*x for very tall A is slightly faster for (row?) major storage of A, and computing y*A for very wide A is slightly faster for (column?) major storage of A. I would be happy to help format a wiki page about this, but I would want to be very careful not to spread misinformation. |
Registered Member
|
Totally agree on the idea of having many more faq / doc pages on specific topics like that, the only reason why we dont have that is lack of time...
* MatrixXf x = MatrixXf::Zero(rows, cols); Yes: since the size of a MatrixXf isnt known at compile time, the only way to create it is on the heap. * x.setZero(int, int) and friends. (always, or only when needed?) Only when the new size is different (greater or smaller) than the old size. * temporary variables in expressions? Only when really necessary, that is, when their size is not known at compile time and not even a reasonable upper bound on their size is known at compile time. What I mean is that: Vector4d.segment(x,y).eval() doesn't cause a malloc, because even though the size 'y' is not known at compile time, it is known that y<=4, so Eigen just reserves space for 4 scalars on the stack. * conservative resize functions Same as above: only when newsize != oldsize. * writing to a .corner() slice that extends past the current storage? This is forbidden. A runtime assertion will fail when you try such a corner() (or block() etc...) call.
* Automatically whenever any dynamic array goes out of scope? Yes * Explicitly by the user by resizing an array to 0? Yes too. Just because resizing to a different size has the effect of resizing the storage.
Really no. However, as always with C/C++ programming, you absolutely need to always have a good memory debugger / simulator at hand. On Unix-like systems, valgrind is a life saver.
If you define EIGEN_NO_MALLOC before #including Eigen headers, Eigen will crash on an assert failure whenever it was about to dynamically allocate memory. Extreme, but useful. For something more fine grained, a good solution is to emit asm comments and study the asm. Or you could edit the file Core/util/Memory.h, grep for EIGEN_NO_MALLOC to see where the hot spots are, and implement your own solution with a global variable. Finally, valgrind is a great tool if what you're after is busting memory leaks and/or counting mallocs. * mess around with strace grep? * mtrace? Never used strace or mtrace, sorry. * maybe some global variable RECENT_DYNAMIC_ALLOCATION that you can set to false at the start of your block and check after (but only exists in debug mode)? As said above, even though we dont have that, it's very simple to implement by editing Memory.h. So far for my needs, valgrind and asm output have been enough.
No. dynamic-size matrices contain just
If you're using dyn-size matrices, they are probably not too small, say at least 8x8, so the two ints are negligible.
For expressions, the templates are *completely* optimized away by a good compiler. For plain matrices that you're explicitly declaring and manipulating for more than a few lines of code, that can't be optimized away, but you're paying an absolutely minimal cost for that.
4th template param to Matrix controls that. Try:
* #define... can change the default Yes, #define EIGEN_DEFAULT_TO_ROW_MAJOR before including Eigen headers. * Arrays of different storage can be mixed freely Yes, true. * Eigen should write optimized code for both storage types, however: Yes. * some computations may be inherently faster if matrices are stored one way rather than another, i.e. computing A*x for very tall A is slightly faster for (row?) major storage of A, and computing y*A for very wide A is slightly faster for (column?) major storage of A. True, i didnt check your particular example (no time sorry) but certain things are inherently faster with a certain stor. order.
You're very welcome to do that, just post back here when you have a draft...
Join us on Eigen's IRC channel: #eigen on irc.freenode.net
Have a serious interest in Eigen? Then join the mailing list! |
Registered Member
|
One remark though: i consider that memory management and storage orders are two independent, even orthogonal topics, that deserve separate pages.
Join us on Eigen's IRC channel: #eigen on irc.freenode.net
Have a serious interest in Eigen? Then join the mailing list! |
Registered Member
|
You asked questions on the IRC channel and I dont have your email address to reply, so, here goes:
No you dont lose any compile time information by using MatrixBase<Derived>. The polymorphism is resolved at compile time, that's why we pass Derived as a template parameter.
This is not needed, as this wouldn't allow anything more than what we can do right now. In MatrixBase, we have enum values like RowsAtCompileTime, ColsAtCompileTime, etc, that provide all that compile time information. See also the enum value IsVectorAtCompileTime. Notice that in the development branch, that stuff is defined in the base class DenseBase. See the file Core/DenseBase.h.
Join us on Eigen's IRC channel: #eigen on irc.freenode.net
Have a serious interest in Eigen? Then join the mailing list! |
Registered Member
|
For future reference, my e-mail address is drewm1980@gmail.com I think I understand what you're saying, but I think I'm thinking of something much more mundane. Suppose my error is that I goofed up and called a function that takes a matrix and a vector with two vectors instead. If the interface is defined with two MatrixBase, will I get a compile time error where I made the bad call, or somewhere inside the badly called function? (I believe it is the latter) BTW, I learned how to call valgrind and verified that my code wasn't leaking any memory (yay!), but based on the number of malloc calls valgrind reports, I believe malloc is indeed getting called implicitly in my innermost loop. Thanks! Drew |
Registered Member
|
Here is a draft of additions to the FAQ:
http://eigen.tuxfamily.org/index.php?title=Talk:FAQ Feel free to make changes, promote to the actual page, move elsewhere, or clobber. A couple things it could use: * Compute timings for tall matrix-vector operations for the four cases {left,right}x{rowMajor,columnMajor} as an example. * A recommended way of generating and viewing the assembly output, including what a malloc looks like in assembly. Thanks! Drew |
Registered Member
|
Well thanks for that. It's already something we can point people to when they ask these questions. But it would need to be greatly expanded/reworked before we could make it official. I mean, this wouldn't all go into the FAQ page (which would then grow too big), i rather see topic-specific pages, like a page on memory management, one on storage orders, etc. Each of them should then have much more information, for example a page on memory management should explain stuff about fixed-size vs. dynamic-size, about the Max-sizes-at-compile-time, about aligned malloc, about stack allocation (alloca()), etc... but your page is at least a good check list of stuff we shouldn't forget mentioning in such a page.
Join us on Eigen's IRC channel: #eigen on irc.freenode.net
Have a serious interest in Eigen? Then join the mailing list! |
Registered Member
|
In Eigen, vectors are just matrices that have only 1 column, or only 1 row. Thus any vector is a Matrix, is a MatrixBase.
If you want we can have a look at your code...
Join us on Eigen's IRC channel: #eigen on irc.freenode.net
Have a serious interest in Eigen? Then join the mailing list! |
Registered users: Bing [Bot], Google [Bot], Sogou [Bot]