rbkit 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.bundle/config +3 -0
- data/.gitignore +16 -0
- data/Gemfile +7 -0
- data/README.md +91 -0
- data/Rakefile +7 -0
- data/docs/debugging.md +27 -0
- data/docs/design.md +3 -0
- data/experiments/benchmark.rb +37 -0
- data/experiments/mspack_to_file.rb +10 -0
- data/experiments/no_growth.rb +20 -0
- data/experiments/object_dump.rb +21 -0
- data/experiments/rbkit_client.rb +25 -0
- data/experiments/rbkit_command_test.rb +54 -0
- data/experiments/using_new_client.rb +22 -0
- data/experiments/using_object_tracer.rb +11 -0
- data/experiments/using_rbkit.rb +19 -0
- data/experiments/zmq_client.rb +46 -0
- data/experiments/zmq_server.rb +52 -0
- data/ext/extconf.rb +18 -0
- data/ext/rbkit_message_aggregator.c +66 -0
- data/ext/rbkit_message_aggregator.h +13 -0
- data/ext/rbkit_object_graph.c +154 -0
- data/ext/rbkit_object_graph.h +39 -0
- data/ext/rbkit_tracer.c +583 -0
- data/ext/rbkit_tracer.h +35 -0
- data/lib/rbkit.rb +101 -0
- data/lib/rbkit/timer.rb +18 -0
- data/lib/rbkit/version.rb +3 -0
- data/rbkit.gemspec +33 -0
- data/schema/tracing_info.md +8 -0
- data/spec/spec_helper.rb +15 -0
- metadata +120 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9c98d007ffcab15624f4463ba9220cfe0b02635f
|
4
|
+
data.tar.gz: 4de1af44a5313d96dc359dac2e5929616c8362af
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3b867812d99bcc5b41da934789e26f0053419757928db46d9f23f0faaac30757ef1eec6083d3b28e21277d99f5b8d4cf0e566fffc89c80b790005916492689f4
|
7
|
+
data.tar.gz: 001c0549d008515fc411499c94b4fe72768d801e1040ff44ab39e1ee0e79f7830de0aa3816be738a90a66aff728b2c34c9630a3e27231a163aee06af8200a09f
|
data/.bundle/config
ADDED
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
Rbkit
|
2
|
+
=====
|
3
|
+
|
4
|
+
`rbkit` is a Ruby gem that plugs into your ruby process, taps profiling data
|
5
|
+
in realtime and sends it across the wire to the [rbkit-client](https://github.com/code-mancers/rbkit-client)
|
6
|
+
as packed messages.
|
7
|
+
|
8
|
+
## Usage
|
9
|
+
|
10
|
+
Rbkit is not ready for production yet. To use the development version of Rbkit
|
11
|
+
in your Ruby project, follow the instructions under `Development` section and
|
12
|
+
then follow these steps :
|
13
|
+
|
14
|
+
#### Add `rbkit` to Gemfile
|
15
|
+
|
16
|
+
Add the following to the project's Gemfiles
|
17
|
+
|
18
|
+
```
|
19
|
+
gem 'rbkit', path: <RBKIT_PATH>`
|
20
|
+
```
|
21
|
+
and run `bundle install`
|
22
|
+
|
23
|
+
#### Inject `rbkit` into code
|
24
|
+
|
25
|
+
Wherever you want to start profiling, add the following :
|
26
|
+
```
|
27
|
+
require 'rbkit'
|
28
|
+
Rbkit.start_profiling
|
29
|
+
```
|
30
|
+
If using Rails, and you want to measure everything from the boot process,
|
31
|
+
a good place to put this would be at the end of `config/boot.rb`.
|
32
|
+
|
33
|
+
## Development
|
34
|
+
|
35
|
+
#### Install zmq and msgpack
|
36
|
+
|
37
|
+
On OSX - Using `homebrew` following command should suffice:
|
38
|
+
|
39
|
+
```
|
40
|
+
~> brew install zeromq
|
41
|
+
~> brew install msgpack
|
42
|
+
```
|
43
|
+
|
44
|
+
On Linux - we recommend to download these libraries
|
45
|
+
from their respective home pages and manually compiling
|
46
|
+
and installing.
|
47
|
+
|
48
|
+
At some point, we will bundle these two C libraries during gem installations
|
49
|
+
but for now, this has to suffice.
|
50
|
+
|
51
|
+
#### Clone the repo
|
52
|
+
|
53
|
+
`git clone git@github.com:code-mancers/rbkit.git`
|
54
|
+
|
55
|
+
We'll call this `<RBKIT_PATH>`.
|
56
|
+
|
57
|
+
#### Set RBKIT_DEV environment flag
|
58
|
+
|
59
|
+
Set the environment variable `RBKIT_DEV` to true.
|
60
|
+
If using bash, put `export RBKIT_DEV=true` in your `~/.bashrc`.
|
61
|
+
|
62
|
+
This compiles the C extension with debug flag and also sets a macro named
|
63
|
+
`RBKIT_DEV` inside the C extension.
|
64
|
+
|
65
|
+
#### Compile the C extension
|
66
|
+
|
67
|
+
Two ways to do this :
|
68
|
+
|
69
|
+
##### Using rake-compiler
|
70
|
+
|
71
|
+
```
|
72
|
+
cd <RBKIT_PATH>
|
73
|
+
bundle install
|
74
|
+
bundle exec rake compile
|
75
|
+
|
76
|
+
```
|
77
|
+
|
78
|
+
##### Or do it manually
|
79
|
+
|
80
|
+
```
|
81
|
+
cd <RBKIT_PATH/ext>
|
82
|
+
ruby extconf.rb
|
83
|
+
make
|
84
|
+
# Create a symlink at `lib/rbkit_tracer.bundle`
|
85
|
+
# that points to `ext/rbkit_tracer.bundle`
|
86
|
+
# (in order to use `rbkit` gem in Gemfiles using `path` option)
|
87
|
+
```
|
88
|
+
|
89
|
+
## TODO
|
90
|
+
|
91
|
+
TODOs are tracked as github issues.
|
data/Rakefile
ADDED
data/docs/debugging.md
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
### How to debug a extension coming from C extension ###
|
2
|
+
|
3
|
+
1. Build a Ruby which is compiled with debug symbols:
|
4
|
+
|
5
|
+
./configure --prefix="$HOME/.rbenv/versions/debug_ruby" --enable-shared --disable-install-doc debugflags="-g" --with-opt-dir="$(brew --prefix openssl):$(brew --prefix libyaml):$(brew --prefix gdbm):$(brew --prefix libffi)"
|
6
|
+
|
7
|
+
I used above configure command to compile a debug symbol enabled Ruby.
|
8
|
+
|
9
|
+
2. Build your extension with debug enabled.
|
10
|
+
|
11
|
+
1. delete existing Makefile and object/bundle/so files.
|
12
|
+
2. export CFLAGS=-g
|
13
|
+
3. ruby extconf.rb
|
14
|
+
4. make
|
15
|
+
|
16
|
+
3. Run your program that makes use of C extension with:
|
17
|
+
|
18
|
+
~> lldb /Users/gnufied/.rbenv/versions/debug_ruby/bin/ruby -> needs absolute path
|
19
|
+
lldb> process launch -- experiments/using_rbkit.rb
|
20
|
+
|
21
|
+
4. LLDB is slightly different from `GDB` and more information about it can be found on,
|
22
|
+
http://lldb.llvm.org/tutorial.html . I specially found following commands useful:
|
23
|
+
|
24
|
+
1. expr
|
25
|
+
2. frame variable
|
26
|
+
3. frame variable <variable_name>
|
27
|
+
|
data/docs/design.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
$:<< File.join(File.dirname(__FILE__), "../lib")
|
2
|
+
$:<< File.join(File.dirname(__FILE__), "../ext")
|
3
|
+
|
4
|
+
require 'benchmark'
|
5
|
+
require 'rbkit'
|
6
|
+
|
7
|
+
|
8
|
+
def do_stuff
|
9
|
+
hash = {}
|
10
|
+
10_00_000.times do |i|
|
11
|
+
hash[:"key#{i}"] = "value#{i}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Benchmark.bm do |bm|
|
16
|
+
bm.report('Running code without Rbkit :') do
|
17
|
+
do_stuff
|
18
|
+
end
|
19
|
+
|
20
|
+
Rbkit.start_profiling
|
21
|
+
bm.report('Running code with Rbkit tracing :') do
|
22
|
+
do_stuff
|
23
|
+
end
|
24
|
+
|
25
|
+
bm.report('Time taken for objectspace snapshot :') do
|
26
|
+
Rbkit.send_objectspace_dump
|
27
|
+
end
|
28
|
+
|
29
|
+
bm.report('Running code after objectspace snapshot :') do
|
30
|
+
do_stuff
|
31
|
+
end
|
32
|
+
|
33
|
+
Rbkit.stop_server
|
34
|
+
bm.report('Running code after disabling rbkit :') do
|
35
|
+
do_stuff
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
$:<< File.join(File.dirname(__FILE__), "../lib")
|
2
|
+
$:<< File.join(File.dirname(__FILE__), "../ext")
|
3
|
+
|
4
|
+
require 'rbkit'
|
5
|
+
|
6
|
+
Rbkit.start_profiling(5555)
|
7
|
+
|
8
|
+
class Foo
|
9
|
+
def initialize(name)
|
10
|
+
@name = name
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
stuff = {}
|
15
|
+
100.times do |i|
|
16
|
+
foo = Foo.new("hemant-#{i}")
|
17
|
+
stuff["name#{i}"] = "hemant-#{i}"
|
18
|
+
end
|
19
|
+
|
20
|
+
gets
|
@@ -0,0 +1,21 @@
|
|
1
|
+
$:<< File.join(File.dirname(__FILE__), "../lib")
|
2
|
+
$:<< File.join(File.dirname(__FILE__), "../ext")
|
3
|
+
|
4
|
+
require 'rbkit'
|
5
|
+
|
6
|
+
Rbkit.start_profiling(5555)
|
7
|
+
|
8
|
+
class Foo
|
9
|
+
def initialize(name)
|
10
|
+
@name = name
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
stuff = {}
|
15
|
+
100.times do |i|
|
16
|
+
sleep 0.01
|
17
|
+
foo = Foo.new("hemant-#{i}")
|
18
|
+
stuff["name#{i}"] = "hemant-#{i}"
|
19
|
+
end
|
20
|
+
|
21
|
+
Rbkit.dump_objects
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# To use this client install following gems
|
3
|
+
# gem install msgpack
|
4
|
+
# gem install rbczmq
|
5
|
+
|
6
|
+
require 'zmq'
|
7
|
+
require 'pp'
|
8
|
+
require "msgpack"
|
9
|
+
|
10
|
+
# PUB / SUB topology
|
11
|
+
|
12
|
+
Thread.abort_on_exception = true
|
13
|
+
fl = File.open("foo.dat", "w")
|
14
|
+
|
15
|
+
ctx = ZMQ::Context.new
|
16
|
+
socket = ctx.socket(:SUB)
|
17
|
+
socket.verbose = true
|
18
|
+
socket.subscribe("")
|
19
|
+
socket.connect("tcp://localhost:5555")
|
20
|
+
loop do
|
21
|
+
message = socket.recv
|
22
|
+
unpacked_message = MessagePack.unpack(message)
|
23
|
+
p unpacked_message
|
24
|
+
end
|
25
|
+
fl.close()
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'zmq'
|
2
|
+
require 'msgpack'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
Thread.abort_on_exception = true
|
6
|
+
|
7
|
+
|
8
|
+
commands = [
|
9
|
+
'start_memory_profile',
|
10
|
+
'stop_memory_profile',
|
11
|
+
'objectspace_snapshot',
|
12
|
+
'trigger_gc'
|
13
|
+
]
|
14
|
+
|
15
|
+
output_file = File.open("/tmp/rbkit.log", "w")
|
16
|
+
puts "Writing output to file #{output_file.path}"
|
17
|
+
ctx = ZMQ::Context.new
|
18
|
+
|
19
|
+
puts "Enter IPv4 address of Rbkit server. (Blank for localhost) :"
|
20
|
+
server_ip = gets.strip
|
21
|
+
server_ip = "127.0.0.1" if server_ip.empty?
|
22
|
+
|
23
|
+
Thread.new do
|
24
|
+
request_socket = ctx.socket(:REQ)
|
25
|
+
request_socket.connect("tcp://#{server_ip}:5556")
|
26
|
+
loop do
|
27
|
+
puts "Available commands :"
|
28
|
+
commands.each_with_index do |c, i|
|
29
|
+
puts "#{i+1}. #{c}"
|
30
|
+
end
|
31
|
+
command = commands[gets.strip.to_i - 1] rescue ''
|
32
|
+
unless command.empty?
|
33
|
+
request_socket.send(command)
|
34
|
+
puts "sent #{command}"
|
35
|
+
response = request_socket.recv()
|
36
|
+
puts "received #{response}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
socket = ctx.socket(:SUB)
|
42
|
+
socket.subscribe("")
|
43
|
+
socket.connect("tcp://#{server_ip}:5555")
|
44
|
+
|
45
|
+
begin
|
46
|
+
loop do
|
47
|
+
message = socket.recv
|
48
|
+
unpacked_message = MessagePack.unpack(message)
|
49
|
+
PP.pp(unpacked_message, output_file)
|
50
|
+
output_file.flush
|
51
|
+
end
|
52
|
+
ensure
|
53
|
+
output_file.close
|
54
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'zmq'
|
2
|
+
require 'pp'
|
3
|
+
require "msgpack"
|
4
|
+
|
5
|
+
Thread.abort_on_exception = true
|
6
|
+
|
7
|
+
ctx = ZMQ::Context.new
|
8
|
+
socket = ctx.socket(:SUB)
|
9
|
+
socket.subscribe("")
|
10
|
+
socket.connect("tcp://127.0.0.1:5555")
|
11
|
+
|
12
|
+
request_socket = ctx.socket(:REQ)
|
13
|
+
request_socket.connect("tcp://127.0.0.1:5556")
|
14
|
+
request_socket.send("start_memory_profile")
|
15
|
+
response = request_socket.recv()
|
16
|
+
puts "received #{response}"
|
17
|
+
|
18
|
+
loop do
|
19
|
+
message = socket.recv
|
20
|
+
unpacked_message = MessagePack.unpack(message)
|
21
|
+
p unpacked_message
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
$:<< File.join(File.dirname(__FILE__), "../lib")
|
2
|
+
$:<< File.join(File.dirname(__FILE__), "../ext")
|
3
|
+
|
4
|
+
require 'rbkit'
|
5
|
+
|
6
|
+
Rbkit.start_profiling(5555)
|
7
|
+
|
8
|
+
class Foo
|
9
|
+
def initialize(name)
|
10
|
+
@name = name
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
stuff = {}
|
15
|
+
10_00_0000.times do |i|
|
16
|
+
sleep 0.01
|
17
|
+
foo = Foo.new("hemant-#{i}")
|
18
|
+
stuff["name#{i}"] = "hemant-#{i}"
|
19
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "zmq"
|
2
|
+
require "pp"
|
3
|
+
|
4
|
+
$ctx = ZMQ::Context.new
|
5
|
+
|
6
|
+
ENDPOINT = "tcp://127.0.0.1:5555"
|
7
|
+
Thread.abort_on_exception = true
|
8
|
+
|
9
|
+
class Client
|
10
|
+
@@publish_topic = "bar"
|
11
|
+
|
12
|
+
def start_publisher
|
13
|
+
pub_socket = $ctx.socket(:PUB)
|
14
|
+
pub_socket.verbose = true
|
15
|
+
pub_socket.connect(ENDPOINT)
|
16
|
+
loop do
|
17
|
+
pub_socket.send("#{@@publish_topic} client#{Time.now}")
|
18
|
+
sleep(1)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def start_subscriber
|
23
|
+
sub_socket = $ctx.socket(:SUB)
|
24
|
+
# sub_socket.verbose = true
|
25
|
+
sub_socket.subscribe("foo")
|
26
|
+
sub_socket.connect(ENDPOINT)
|
27
|
+
loop do
|
28
|
+
data = sub_socket.recv
|
29
|
+
puts "********** Received from server #{data}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
client = Client.new()
|
36
|
+
threads = []
|
37
|
+
|
38
|
+
threads << Thread.new do
|
39
|
+
client.start_publisher
|
40
|
+
end
|
41
|
+
|
42
|
+
threads << Thread.new do
|
43
|
+
client.start_subscriber
|
44
|
+
end
|
45
|
+
|
46
|
+
threads.each { |thr| thr.join }
|