• Stars
    star
    438
  • Rank 97,105 (Top 2 %)
  • Language
    C
  • License
    MIT License
  • Created about 10 years ago
  • Updated over 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Add ObjectSpace::AllocationTracer module.

ObjectSpace::AllocationTracer

This module allows to trace object allocation.

This feature is similar to https://github.com/SamSaffron/memory_profiler and https://github.com/srawlins/allocation_stats. But this feature focused on `age' of objects.

This gem was separated from gc_tracer.gem.

Build Status

Installation

Add this line to your application's Gemfile:

gem 'allocation_tracer'

And then execute:

$ bundle

Or install it yourself as:

$ gem install allocation_tracer

Usage

Allocation tracing

You can trace allocation and aggregate information. Information includes:

  • count - how many objects are created.
  • total_age - total age of objects which created here
  • max_age - age of longest living object created here
  • min_age - age of shortest living object created here

Age of Object can be calculated by this formula: [current GC count] - [birth time GC count]

For example:

require 'allocation_tracer'
require 'pp'

pp ObjectSpace::AllocationTracer.trace{
  50_000.times{|i|
    i.to_s
    i.to_s
    i.to_s
  }
}

will show

{["test.rb", 6]=>[50000, 0, 47440, 0, 1, 0],
 ["test.rb", 7]=>[50000, 4, 47452, 0, 6, 0],
 ["test.rb", 8]=>[50000, 7, 47456, 0, 6, 0]}

In this case,

  • 50,000 objects are created at `test.rb:6' and
    • 0 old objects created.
    • 47,440 is total age of objects created at this line (average age of object created at this line is 47440/50000 = 0.9488).
    • 0 is minimum age
    • 1 is maximum age.
    • 0 total memory consumption without RVALUE

You can also specify `type' in GC::Tracer.setup_allocation_tracing() to specify what should be keys to aggregate like that.

require 'allocation_tracer'
require 'pp'

ObjectSpace::AllocationTracer.setup(%i{path line type})

result = ObjectSpace::AllocationTracer.trace do
  50_000.times{|i|
    a = [i.to_s]
    b = {i.to_s => nil}
    c = (i.to_s .. i.to_s)
  }
end

pp result

and you will get:

{["test.rb", 8, :T_STRING]=>[50000, 15, 49165, 0, 16, 0],
 ["test.rb", 8, :T_ARRAY]=>[50000, 12, 49134, 0, 16, 0],
 ["test.rb", 9, :T_STRING]=>[100000, 27, 98263, 0, 16, 0],
 ["test.rb", 9, :T_HASH]=>[50000, 16, 49147, 0, 16, 8998848],
 ["test.rb", 10, :T_STRING]=>[100000, 36, 98322, 0, 16, 0],
 ["test.rb", 10, :T_STRUCT]=>[50000, 16, 49147, 0, 16, 0]}

Interestingly, you can not see array creations in a middle of block:

require 'allocation_tracer'
require 'pp'

ObjectSpace::AllocationTracer.setup(%i{path line type})

result = ObjectSpace::AllocationTracer.trace do
  50_000.times{|i|
    [i.to_s]
    nil
  }
end

pp result

and it prints:

{["test.rb", 8, :T_STRING]=>[25015, 5, 16299, 0, 2, 0]}

There are only string creation. This is because unused array creation is ommitted by optimizer.

Simply you can require `allocation_tracer/trace' to start allocation tracer and output the aggregated information into stdout at the end of program.

require 'allocation_tracer/trace'

# Run your program here
50_000.times{|i|
  i.to_s
  i.to_s
  i.to_s
}

and you will see:

path    line    count   old_count       total_age       min_age max_age total_memsize
...rubygems/core_ext/kernel_require.rb 55     18       1       23      1       6       358
...lib/allocation_tracer/lib/allocation_tracer/trace.rb       6       2      012      6       6       0
test.rb 0       1       0       0       0       0       0
test.rb 5       50000   4       41492   0       5       0
test.rb 6       50000   3       41490   0       5       0
test.rb 7       50000   7       41497   0       5       0

(tab separated columns)

Total Allocations / Free

Allocation tracer collects the total number of allocations and frees during the trace block. After the block finishes executing, you can examine the total number of allocations / frees per object type like this:

require 'allocation_tracer'

ObjectSpace::AllocationTracer.trace do
  1000.times {
    ["foo", {}]
  }
end
p allocated: ObjectSpace::AllocationTracer.allocated_count_table
p freed: ObjectSpace::AllocationTracer.freed_count_table

The output of the script will look like this:

{:allocated=>{:T_NONE=>0, :T_OBJECT=>0, :T_CLASS=>0, :T_MODULE=>0, :T_FLOAT=>0, :T_STRING=>1000, :T_REGEXP=>0, :T_ARRAY=>1000, :T_HASH=>1000, :T_STRUCT=>0, :T_BIGNUM=>0, :T_FILE=>0, :T_DATA=>0, :T_MATCH=>0, :T_COMPLEX=>0, :T_RATIONAL=>0, :unknown=>0, :T_NIL=>0, :T_TRUE=>0, :T_FALSE=>0, :T_SYMBOL=>0, :T_FIXNUM=>0, :T_UNDEF=>0, :T_NODE=>0, :T_ICLASS=>0, :T_ZOMBIE=>0}}
{:freed=>{:T_NONE=>0, :T_OBJECT=>0, :T_CLASS=>0, :T_MODULE=>0, :T_FLOAT=>0, :T_STRING=>1871, :T_REGEXP=>41, :T_ARRAY=>226, :T_HASH=>7, :T_STRUCT=>41, :T_BIGNUM=>0, :T_FILE=>50, :T_DATA=>25, :T_MATCH=>47, :T_COMPLEX=>0, :T_RATIONAL=>0, :unknown=>0, :T_NIL=>0, :T_TRUE=>0, :T_FALSE=>0, :T_SYMBOL=>0, :T_FIXNUM=>0, :T_UNDEF=>0, :T_NODE=>932, :T_ICLASS=>0, :T_ZOMBIE=>0}}

Lifetime table

You can collect lifetime statistics with ObjectSpace::AllocationTracer.lifetime_table method.

require 'pp'
require 'allocation_tracer'

ObjectSpace::AllocationTracer.lifetime_table_setup true
result = ObjectSpace::AllocationTracer.trace do
  100000.times{
    Object.new
    ''
  }
end
pp ObjectSpace::AllocationTracer.lifetime_table

will show

{:T_OBJECT=>[3434, 96563, 0, 0, 1, 0, 0, 2],
 :T_STRING=>[3435, 96556, 2, 1, 1, 1, 1, 1, 2]}

This output means that the age of 3434 T_OBJECT objects are 0, 96563 objects are 1 and 2 objects are 7. Also the age of 3435 T_STRING objects are 0, 96556 objects are 1 and so on.

Note that these numbers includes living objects and dead objects. For dead objects, age means lifetime. For living objects, age means current age.

Rack middleware

You can use AllocationTracer via rack middleware.

require 'rack'
require 'sinatra'
require 'rack/allocation_tracer'

use Rack::AllocationTracerMiddleware

get '/' do
  'foo'
end

When you access to http://host/allocation_tracer/ then you can see a table of allocation tracer.

You can access the following pages.

The following pages are demonstration Rails app on Heroku environment.

Source code of this demo app is https://github.com/ko1/tracer_demo_rails_app. You only need to modify like https://github.com/ko1/tracer_demo_rails_app/blob/master/config.ru to use it on Rails.

Development

Compile the code:

$ rake compile

Run the tests:

$ rake spec

Contributing

  1. Fork it ( http://github.com/ko1/allocation_tracer/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

Author

Koichi Sasada from Heroku, Inc.

More Repositories

1

pretty_backtrace

Pretty your exception backtrace.
Ruby
646
star
2

rubyhackchallenge

Ruby
451
star
3

gc_tracer

Add GC::Tracer module.
C
308
star
4

yomikomu

Dump compiled iseq by binary (kakidasu) and load binary (yomidasu)
Ruby
179
star
5

nakayoshi_fork

Ruby
81
star
6

uc_ja

書籍『アンダースタンディング コンピュテーション』のサポートリポジトリです。
73
star
7

ractor-tvar

C
65
star
8

rspec-debug

Launch [debugger](https://github.com/ruby/debug) if spec is failed.
Ruby
35
star
9

rstfilter

Show Ruby script with execution results.
Ruby
34
star
10

kv

kv: A page viewer written in Ruby
Ruby
27
star
11

ruby-ptrace

ptrace wrapper for ruby
C
23
star
12

calleree

Calleree helps to analyze Ruby's caller-callee relationships.
C
18
star
13

vscode-ruby-rstfilter

Ruby's rstfilter extension
TypeScript
17
star
14

iseq_collector

iseq_collector gem
Ruby
16
star
15

prsnt

プレゼントを提供するためのウェブアプリケーション
Ruby
8
star
16

build-ruby

Build Ruby from source code.
Ruby
6
star
17

programming-elixir-1-6-ja

[プログラミングElixir(第2版)](https://www.ohmsha.co.jp/book/9784274226373/) サポートページ
6
star
18

simplepaste

SimplePaste web application
Ruby
5
star
19

finalize_block

This gem provide `finalize_block` method.
Ruby
4
star
20

many_examples

MaNy project examples
Ruby
3
star
21

ractor

to keep namespace
Ruby
3
star
22

ptask

Parallel task scheduler
C
2
star
23

tokyo11

Tokyo RubyKaigi 11
HTML
2
star
24

turtlefs

TurtleFS is Delay simulation file system using FUSE.
C
1
star
25

calcard

calcard
HTML
1
star
26

sample

1
star
27

ractor-lvar

Ractor::LVar
Ruby
1
star
28

pam_gh_user

1
star
29

mmapped_string

MmappedString
Ruby
1
star