A working memory profiling solution?

Dear All,

I’ve spent the last 2 days by trying to find a working memory profiling
solution for either 1.9.x or 2.0 that can show the memory usage by
methods. Similar to the process time output.

As I read, ruby-prof needs a patched MRI to do memory profiling. But
I couldn’t set it up like this:

rvm install 1.9.3-p125 --patch gcdata --name gcdata
gem-ruby-1.9.3-p125-gcdata install ruby-prof

require “ruby-prof”

RubyProf.measure_mode = RubyProf::MEMORY
RubyProf.start
# code to profile
10000.times { “hello”.chars.to_a.shuffle.join }
r = RubyProf.stop
RubyProf::FlatPrinter.new®.print

I’ve read that 1.9.2 and above there’s a bug in ruby-prof that keeps it
from doing a memory or allocation profiling. Can’t come up with the link
though.

I’ve checked memprof, but it’s still 1.8.x only.

Tested memory-profiler gem too, but it doesn’t give a good output:
https://github.com/phluid61/memory-profiler-gem

Could you be kind to direct me to a working solution?

Thanks.

On Mon, Jun 24, 2013 at 6:59 PM, Andras H.
[email protected]wrote:

Dear All,

I’ve spent the last 2 days by trying to find a working memory profiling
solution for either 1.9.x or 2.0 that can show the memory usage by
methods.

How exactly do you imagine “memory usage by methods” to be measured?
Are
you just interested in learning how much memory is allocated
(temporarily)
from withing a method or do you have a memory leak?

Similar to the process time output.

I usually found “ruby -r profile” helpful. You can also use module
Benchmark for measuring timing of specific parts of code. You can even
use
Benchmark.measure { … } around a specific piece and you’ll get CPU,
system and wall clock time in an instance of class Benchmark::Tms,

    # code to profile
    10000.times { "hello".chars.to_a.shuffle.join }

This will allocate objects just temporarily and drop them pretty soon
again
=> no leak. CPU wise on my box:

irb(main):007:0> Benchmark.measure { 10000.times {
“hello”.chars.to_a.shuffle.join } }
=> 0.063000 0.000000 0.063000 ( 0.066000)

For memory leak detection I once created a small tool with ObjectSpace
which just counts instances per class and outputs deltas. You might
find
it in the archives of this forum.

Kind regards

robert

Robert K. wrote in post #1113449:

How exactly do you imagine “memory usage by methods” to be measured?
Are you just interested in learning how much memory is allocated (temporarily)
from withing a method or do you have a memory leak?

I’m interested in figuring out the memory peaks of specific code pieces.
Even if memory gets freed up at some point, I’d still like to know the
amount that was used just right before to be able to calculate the
amount that would be used by concurrent processes.

And also to see the history of memory usage by methods compared to each
other so that I know which part of the code I should rewrite to make it
more memory efficient.

I usually found “ruby -r profile” helpful. You can also use module
Benchmark for measuring timing of specific parts of code. You can even
use
Benchmark.measure { … } around a specific piece and you’ll get CPU,
system and wall clock time in an instance of class Benchmark::Tms,

I use these tools and they work great. Only they’ve got nothing to do
with memory consumption.

For memory leak detection I once created a small tool with ObjectSpace
which just counts instances per class and outputs deltas. You might
find
it in the archives of this forum.

If I understand you correctly, you say I can only see the counted sum of
these objects? But I reckon I still won’t be able to calculate memory
usage by this.

ruby-prof would have similar with its RubyProf::ALLOCATIONS I believe,
unfortunately I can’t get it to work. But anyway, your solution can be
more than nothing. I’ll check it out later on. Though I’m still keen to
find a solution for what I described above.

Thanks.

On Mon, Jun 24, 2013 at 8:01 PM, Andras H.
[email protected]wrote:

For that wouldn’t it be sufficient to monitor memory usage of the
process
over time?

And also to see the history of memory usage by methods compared to each
other so that I know which part of the code I should rewrite to make it
more memory efficient.

Considering a call stack of, say, 10 levels how would you attribute
memory
usage to methods? Would you sum it up along the hierarchy? How would
you
consider different invocations of the same method at different points in
time? Assuming you could count the bytes allocated during a call of
method
x: now, since that figure tells you nothing about the allocation pattern
you do not really gain information with regard to the complete memory
usage. For example, you could allocate 10,000 objects in a loop one per
iteration and forget them immediately OR you allocate them, stuff them
in
an Array and loose them only at method exit. In the latter case you may
need more memory since GC cannot collect earlier. Considering that,
total
memory of the process may be a better metric.

If you consider memory usage at method exit vs. method entry a method
which
allocates lots of objects that it releases shortly after might be
actually
much worse for the program in terms of CPU and GC activity than another
method which steadily allocates objects which are returned in a
collection
although the latter looks much worse with this statistics.

I usually found “ruby -r profile” helpful. You can also use module
Benchmark for measuring timing of specific parts of code. You can even
use
Benchmark.measure { … } around a specific piece and you’ll get CPU,
system and wall clock time in an instance of class Benchmark::Tms,

I use these tools and they work great. Only they’ve got nothing to do
with memory consumption.

Didn’t you also ask for “process time output”?

For memory leak detection I once created a small tool with ObjectSpace

which just counts instances per class and outputs deltas. You might
find
it in the archives of this forum.

If I understand you correctly, you say I can only see the counted sum of
these objects? But I reckon I still won’t be able to calculate memory
usage by this.

You could create metrics though which might not be bytes but
nevertheless
relevant: you count the number of instance variables. With that you
have a
measurement of the relative size of instances of different classes. For
String you could use e.g. bytesize / 4 (or how many bytes a reference
takes
up). That would still not give you exact bytes but the information
about
relative sizes would be enough for optimization - if you actually have a
memory issue.

Advantage of this approach would be that it would not need any
modifications of the runtime - and it would be fun to hack. :slight_smile:

ruby-prof would have similar with its RubyProf::ALLOCATIONS I believe,
unfortunately I can’t get it to work. But anyway, your solution can be
more than nothing. I’ll check it out later on. Though I’m still keen to
find a solution for what I described above.

I think for a real solution you would need something like JProfiler,
which
records allocation sites and call stacks so you can identify paths
through
code with the worst allocation behavior. You could create something
like
this by exchanging implementation of Class#new and counting as suggested
above. In combination with #caller you can even get the call stack.
The
only problem here is to subtract the measurement code from the
statistic…
:slight_smile:

Kind regards

robert

It just came to me how I could easily describe what I want. It’s the
peak memory usage that I’m looking for.

So if a profiling tool could print a top-like list in hierarchy showing
the total peak value and the ones in percentage belonging to each method
(maybe with the delta of the entry - exit memory state for finding
leaks), that I would call perfect.

I just mentioned process time as an example, but I might have written it
in a confusing way.

I’ll check out your code cause I’m interested in it and sounds very
useful. Will probably report back here about it in a day or so.

Matthew K. wrote in post #1113479:

On 25 June 2013 02:59, Andras H. [email protected] wrote:

Tested memory-profiler gem too, but it doesn’t give a good output:
https://github.com/phluid61/memory-profiler-gem

Hi, just out of interest, what do you mean by “good output”, and how
does it fall short? This is the first I’ve heard of someone (besides
me) using it in the wild, and I’m keen to make it more useful.
Keeping in mind, all the gem does (and really can do, without a major
rewrite) is periodically inspect the object space and count instances
(and to some degree estimate their sizes, at least relatively.)

First of all I have to apologize for making it sound as if your solution
had any defect. That is not true at all and it’s very useful. What I
meant only by “good output” is “the output that I’m looking for”.

Just as I wrote it in my other recent reply, I’m looking for a way to
determine the peak (highest) memory usage of a code part in a program.

About your solution: I spent much time looking for something that’s easy
to setup and the credit must surely go to you on that. Very easy by
installing a single gem without patching the interpreter. I like your
idea of how it works. I find it a very useful piece of stuff for
developing, so Thank You for providing it!

On 6/24/13, Andras H. [email protected] wrote:

gem-ruby-1.9.3-p125-gcdata install ruby-prof

require “ruby-prof”

RubyProf.measure_mode = RubyProf::MEMORY
RubyProf.start
# code to profile
10000.times { “hello”.chars.to_a.shuffle.join }
r = RubyProf.stop
RubyProf::FlatPrinter.new®.print

What doesn’t work about it?

On 25 June 2013 02:59, Andras H. [email protected] wrote:

Tested memory-profiler gem too, but it doesn’t give a good output:
https://github.com/phluid61/memory-profiler-gem

Hi, just out of interest, what do you mean by “good output”, and how
does it fall short? This is the first I’ve heard of someone (besides
me) using it in the wild, and I’m keen to make it more useful.
Keeping in mind, all the gem does (and really can do, without a major
rewrite) is periodically inspect the object space and count instances
(and to some degree estimate their sizes, at least relatively.)

Roger P. wrote in post #1114319:

What doesn’t work about it?

So I’ve made the run again with a solution finally below:

See info here:
https://github.com/ruby-prof/ruby-prof/issues/86
https://github.com/skaes/rvm-patchsets

Solution: patch the MRI using RVM:

rvm reinstall 1.9.3 --patch railsexpress
gem-ruby-1.9.3-p448 install ruby-prof

Now the output of my test code looks like:

$ ruby-1.9.3-p448 test.rb
Thread ID: 14925700
Fiber ID: 17378400
Total: 3842.242188
Sort by: self_time

%self total self wait child calls name
56.94 2187.766 2187.766 0.000 0.000 20000 String#chars
32.79 1259.953 1259.953 0.000 0.000 10000 Array#join
10.17 390.812 390.812 0.000 0.000 10000 Array#shuffle
0.07 3842.242 2.852 0.000 3839.391 1 Global#[No
method]
0.01 1563.102 0.336 0.000 1562.766 10000
Enumerable#to_a
0.01 3839.391 0.336 0.000 3839.055 1 Integer#times
0.00 1562.766 0.188 0.000 1562.578 10000
Enumerator#each

  • indicates recursively called methods

Roger P. wrote in post #1114319:

On 6/24/13, Andras H. [email protected] wrote:

gem-ruby-1.9.3-p125-gcdata install ruby-prof

require “ruby-prof”

RubyProf.measure_mode = RubyProf::MEMORY
RubyProf.start
# code to profile
10000.times { “hello”.chars.to_a.shuffle.join }
r = RubyProf.stop
RubyProf::FlatPrinter.new®.print

What doesn’t work about it?

I get an output like below doing the above:

$ ruby-1.9.3-p125-gcdata test.rb
Thread ID: 15804340
Fiber ID: 15659960
Total: 0.000000
Sort by: self_time

%self total self wait child calls name
NaN 0.000 0.000 0.000 0.000 10000 Array#join
NaN 0.000 0.000 0.000 0.000 10000 Array#shuffle
NaN 0.000 0.000 0.000 0.000 10000
Enumerator#each
NaN 0.000 0.000 0.000 0.000 10000
Enumerable#to_a
NaN 0.000 0.000 0.000 0.000 20000 String#chars
NaN 0.000 0.000 0.000 0.000 1 Integer#times
NaN 0.000 0.000 0.000 0.000 1 Global#[No
method]

  • indicates recursively called methods