views:

368

answers:

3

Hi,

I am developing a Graph-class, based on boost-graph-library.
A Graph-object contains a boost-graph, so to say an adjacency_list, and a map. When monitoring the total memory usage of my program, it consumes quite a lot (checked with pmap).
Now, I would like to know, how much of the memory is exactly consumed by a filled object of this Graph-class? With filled I mean when the adjacency_list is full of vertices and edges.
I found out, that using sizeof() doesn't bring me far. Using valgrind is also not an alternative as there is quite some memory allocation done previously and this makes the usage of valgrind impractical for this purpose. I'm also not interested in what other parts of the program cost in memory, I want to focus on one single object.

Thank you.

+1  A: 

I have never used adjacency_list so this is just an idea which although works with STL containers.

So using adjacency_list says BGL uses containers from the STL such as std::vector, std::list, and std::set to represent the set of vertices and the adjacency structure. OK, then you just have to give your adjacent list std::vector, std::list, and std::set which have their own allocator type. Adding your own allocator to STL containers is an easy task. Having done all this you just have to get from your allocators the size of memory that has been allocated while filling the adjacency_list.

So the idea is to build the adjacent list out of STL containers (which seems possible after a quick look at the BGL documentaiton) which have own allocator types.

Update 1 Actually you haven't told why you need to know how much bytes your graph consumes. If you just need to get this number only once you probably have to write you program with and without filling the graph. Then run for example UNIX95= ps -u $USER -o vsz,args and find out the difference. Roughly you will get the size of you graph.

If you need to get this values regularly in your application and if you are not able to implement the whole solution using allocators you need to start with a few small steps.

  1. Read about allocators: C++ Standard Allocator, An Introduction and Implementation Allocators(STL)
  2. Try to implement std::vector with your own allocator as an exercise
  3. Try to add counting bytes to your allocator
  4. Try to build the Boost graph with allocator Customizing the Adjacency List Storage
  5. Do something to count bytes in std::string members of your containers. By default they will not use the allocator of their container. So either instead use fixed-size strings or manage somehow insert a container's allocator in this string members. Again, take a look at Adding your own allocator to STL containers

By the way if you don't want to reinvent the C++ allocator you can just use something like that:

template <typename T> class your_allocator {    
public:
// here you need to put everything that is required by C++ standard
// and calls finally send to std_allocator_    
private:
    std::allocator<T> std_allocator_;    
};
skwllsp
I understand what you want to tell there in general, but I'm unable for the moment to bring this to reality. I have never dealt with this topic and therefore would need a complete example that also tells how the allocated memory is actually counted.
Shadow
Updated my answer, added another step
skwllsp
+3  A: 

If you are able to control the creation and filling of the object such that no other allocations are performed during that time, then one way to do this is to override new and delete operators with your own versions that simply count the total allocation size and store it in a global variable. Grab the total size at the beginning and the end, and the difference should be a reasonable approximation of the size used (not counting heap overhead).

Mark Wilkins
A: 

I managed now to shrink everything down so far, that I can think of profiling with valgrind.
I then used "--tool=massif" to check heap-memory-consumption. I used the following code to create an instance of my Graph-class

    typedef Graph<VertexProperties, EdgeProperties> MyGraph;
    MyGraph* G;
    G = new MyGraph(*vertex_props);

The constructor is built in such a way, that it recieves a list of VertexProperties-pairs which equal to the edges and then stores everything via the adjacency_list.
The massif-profile then returned me the following results. For simplicity, I posted them in a pastebin: http://dpaste.com/hold/174033/
You can see there the diagram for the overall execution and the peak is reached at snapshot 83 with 235.4MiB.
My question is now, is this the overall maximum amount of memory on the heap consumed by my program? What about the approx. 1GB of memory usage that pmap returns me for my program? How do those values come together?
And most importantly, when looking at the details for snapshot 83, is says:

  1. 32.76% (80,842,846B) for std::string::_Rep::_S_create(....)
  2. 15.94% (39,341,760B) for std::_Rb_tree >
  3. 11.91% (29,389,824B) for main (new_allocator.h:92)

Am I getting it right, that 1. tells me that approx. 80MB are consumed for std::string and 2. tells me, that my Graph takes up approx. 40MB?
What does 3. then tell me?

Thank you.

Shadow
1. As for pmap. As far as I understand pmap reports everything. If you use Linux you can find out the size of the heap of your process looking at /proc/<your-process-id>/status. Field "VmData"
skwllsp
2. `tells me, that my Graph takes up approx. 40MB?` If you use std::strings in your graph than probably your graph in fact takes up 40Mb plus some of 80 megabytes reported for std::string. It is because inside std::string allocates memory from heap for holding strings.
skwllsp
Thank you skwsllp.I use a class VertexProperties, which basically has 2 std::string attributes. So is this very well possible and correct?<br>I now decided to induce a memleak by simply not deleting a dynamicaly created Graph-instance and valgrind --leakcheck=full --show-reachable=yes tells me that:<br>indirectly lost: 83,349,510 bytes in 1,814,747 blocks.<br>I have not allocated any other memory dynamically, so I assume this comes from my graph?!
Shadow
`So is this very well possible and correct?` Sorry don't understood your question.`I have not allocated any other memory dynamically, so I assume this comes from my graph?` If there has not been this leak before then, correct, it comes from your graph.
skwllsp