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
data/ext/rbkit_tracer.h
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#ifndef RBKIT_TRACER_H
|
2
|
+
#define RBKIT_TRACER_H
|
3
|
+
|
4
|
+
#include "ruby/ruby.h"
|
5
|
+
#include "ruby/debug.h"
|
6
|
+
#include <stdio.h>
|
7
|
+
#include <assert.h>
|
8
|
+
#include "zmq.h"
|
9
|
+
#include "msgpack.h"
|
10
|
+
|
11
|
+
// Structure is used to store profiling data
|
12
|
+
struct gc_hooks {
|
13
|
+
VALUE hooks[3];
|
14
|
+
VALUE enabled;
|
15
|
+
void (*funcs[3])(void *data, int event_index);
|
16
|
+
void *args[3];
|
17
|
+
void *data;
|
18
|
+
st_table *object_table;
|
19
|
+
st_table *str_table;
|
20
|
+
VALUE newobj_trace;
|
21
|
+
VALUE freeobj_trace;
|
22
|
+
int keep_remains;
|
23
|
+
msgpack_sbuffer *sbuf;
|
24
|
+
msgpack_packer *msgpacker;
|
25
|
+
};
|
26
|
+
|
27
|
+
char * tracer_string_recv(void *socket);
|
28
|
+
int tracer_string_send(void *socket, const char *message);
|
29
|
+
void pack_value_object(msgpack_packer *packer, VALUE value);
|
30
|
+
void pack_string(msgpack_packer *packer, char *string);
|
31
|
+
void pack_timestamp(msgpack_packer *packer);
|
32
|
+
void pack_event_header(msgpack_packer *packer, const char *event_type, int map_size);
|
33
|
+
void pack_pointer(msgpack_packer *packer, VALUE object_id);
|
34
|
+
|
35
|
+
#endif
|
data/lib/rbkit.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require "rbkit_tracer"
|
2
|
+
require "rbkit/timer"
|
3
|
+
require "objspace"
|
4
|
+
|
5
|
+
# Class implements user friendly interface in pure Ruby for profiler.
|
6
|
+
module Rbkit
|
7
|
+
class Profiler
|
8
|
+
attr_accessor :pub_port, :request_port
|
9
|
+
|
10
|
+
def initialize(pub_port, request_port)
|
11
|
+
@pub_port = pub_port
|
12
|
+
@request_port = request_port
|
13
|
+
@profiler_thread = nil
|
14
|
+
@stop_thread = false
|
15
|
+
@server_running = false
|
16
|
+
@gc_stats_timer = Rbkit::Timer.new(5) do
|
17
|
+
data = GC.stat
|
18
|
+
no_of_allocated_pages = data[:heap_length]
|
19
|
+
max_objects_per_page = GC::INTERNAL_CONSTANTS[:HEAP_OBJ_LIMIT]
|
20
|
+
size_of_one_obj = GC::INTERNAL_CONSTANTS[:RVALUE_SIZE]
|
21
|
+
data[:total_heap_size] = no_of_allocated_pages * max_objects_per_page *
|
22
|
+
size_of_one_obj
|
23
|
+
data[:total_memsize] = ObjectSpace.memsize_of_all
|
24
|
+
Rbkit.send_hash_as_event(data, "gc_stats")
|
25
|
+
end
|
26
|
+
@message_dispatch_timer = Rbkit::Timer.new(1) do
|
27
|
+
Rbkit.send_messages
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def start_server(enable_profiling: false)
|
32
|
+
return if @server_running
|
33
|
+
@profiler_thread = Thread.new do
|
34
|
+
Rbkit.start_stat_server(pub_port, request_port)
|
35
|
+
Rbkit.start_stat_tracing if enable_profiling
|
36
|
+
loop do
|
37
|
+
break if @stop_thread
|
38
|
+
incoming_request = Rbkit.poll_for_request
|
39
|
+
process_incoming_request(incoming_request)
|
40
|
+
@gc_stats_timer.run
|
41
|
+
@message_dispatch_timer.run
|
42
|
+
# Let us sleep this thread for a bit, so as other things can run.
|
43
|
+
sleep(0.05)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
@server_running = true
|
47
|
+
end
|
48
|
+
|
49
|
+
def process_incoming_request(incoming_request)
|
50
|
+
case incoming_request
|
51
|
+
when "start_memory_profile"
|
52
|
+
Rbkit.start_stat_tracing
|
53
|
+
when "stop_memory_profile"
|
54
|
+
Rbkit.stop_stat_tracing
|
55
|
+
when "trigger_gc"
|
56
|
+
GC.start
|
57
|
+
when "objectspace_snapshot"
|
58
|
+
Rbkit.send_objectspace_dump
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def stop_server
|
63
|
+
return if !@server_running
|
64
|
+
Rbkit.stop_stat_server
|
65
|
+
@server_running = false
|
66
|
+
end
|
67
|
+
|
68
|
+
def make_clean_exit
|
69
|
+
@stop_thread = true
|
70
|
+
stop_server
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
########### Rbkit API ###########
|
75
|
+
|
76
|
+
# Starts the server and enables memory profiling tracepoints
|
77
|
+
def self.start_profiling(pub_port = nil, request_port = nil)
|
78
|
+
@profiler = Rbkit::Profiler.new(pub_port, request_port)
|
79
|
+
@profiler.start_server(enable_profiling: true)
|
80
|
+
at_exit do
|
81
|
+
self.stop_server
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Just starts the server and waits for instructions.
|
86
|
+
# The client needs to connect to the request_port and send
|
87
|
+
# commands over the wire. The client also needs to connect
|
88
|
+
# to the pub_port and subscribe to the responses from the server.
|
89
|
+
def self.start_server(pub_port = nil, request_port = nil)
|
90
|
+
@profiler = Rbkit::Profiler.new(pub_port, request_port)
|
91
|
+
@profiler.start_server
|
92
|
+
at_exit do
|
93
|
+
self.stop_server
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Stops profiling and brings down the rbkit server if it's running
|
98
|
+
def self.stop_server
|
99
|
+
@profiler.make_clean_exit
|
100
|
+
end
|
101
|
+
end
|
data/lib/rbkit/timer.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Rbkit
|
2
|
+
class Timer
|
3
|
+
attr_accessor :last_fired_at, :interval
|
4
|
+
|
5
|
+
def initialize(interval, &timer_block)
|
6
|
+
@interval = interval
|
7
|
+
@timer_block = timer_block
|
8
|
+
@last_fired_at = Time.now
|
9
|
+
end
|
10
|
+
|
11
|
+
def run
|
12
|
+
if Time.now - last_fired_at > interval
|
13
|
+
@timer_block.call
|
14
|
+
@last_fired_at = Time.now
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/rbkit.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
GEM_NAME = "rbkit"
|
4
|
+
|
5
|
+
lib = File.expand_path("../lib", __FILE__)
|
6
|
+
$: << lib unless $:.include?(lib)
|
7
|
+
|
8
|
+
require "rbkit/version"
|
9
|
+
|
10
|
+
Gem::Specification.new do |s|
|
11
|
+
s.name = GEM_NAME
|
12
|
+
s.version = Rbkit::VERSION
|
13
|
+
|
14
|
+
if s.respond_to? :required_rubygems_version=
|
15
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0")
|
16
|
+
end
|
17
|
+
s.authors = ["Hemant Kumar", "Emil Soman", "Kashyap"]
|
18
|
+
s.description = %q{Something small for process management}
|
19
|
+
s.email = %q{hemant@codemancers.com emil@codemancers.com kashyap@codemancers.com}
|
20
|
+
|
21
|
+
s.files = `git ls-files`.split("\n")
|
22
|
+
s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
|
23
|
+
s.extensions = 'ext/extconf.rb'
|
24
|
+
s.require_paths = ["lib"]
|
25
|
+
|
26
|
+
s.homepage = %q{http://rbkit.codemancers.com}
|
27
|
+
s.licenses = ["MIT"]
|
28
|
+
s.require_paths = ["lib"]
|
29
|
+
s.summary = %q{Ruby profiler for rest of us}
|
30
|
+
s.add_development_dependency("rspec")
|
31
|
+
s.add_development_dependency("rake")
|
32
|
+
s.add_development_dependency("simplecov")
|
33
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "pry"
|
2
|
+
require "simplecov"
|
3
|
+
SimpleCov.start do
|
4
|
+
add_filter "/spec/"
|
5
|
+
end
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.run_all_when_everything_filtered = true
|
9
|
+
config.filter_run :focus
|
10
|
+
# Run specs in random order to surface order dependencies. If you find an
|
11
|
+
# order dependency and want to debug it, you can fix the order by providing
|
12
|
+
# the seed, which is printed after each run.
|
13
|
+
# --seed 1234
|
14
|
+
config.order = 'random'
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rbkit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Hemant Kumar
|
8
|
+
- Emil Soman
|
9
|
+
- Kashyap
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2014-09-21 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - ">="
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '0'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: rake
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: simplecov
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
type: :development
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
description: Something small for process management
|
58
|
+
email: hemant@codemancers.com emil@codemancers.com kashyap@codemancers.com
|
59
|
+
executables: []
|
60
|
+
extensions:
|
61
|
+
- ext/extconf.rb
|
62
|
+
extra_rdoc_files: []
|
63
|
+
files:
|
64
|
+
- ".bundle/config"
|
65
|
+
- ".gitignore"
|
66
|
+
- Gemfile
|
67
|
+
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- docs/debugging.md
|
70
|
+
- docs/design.md
|
71
|
+
- experiments/benchmark.rb
|
72
|
+
- experiments/mspack_to_file.rb
|
73
|
+
- experiments/no_growth.rb
|
74
|
+
- experiments/object_dump.rb
|
75
|
+
- experiments/rbkit_client.rb
|
76
|
+
- experiments/rbkit_command_test.rb
|
77
|
+
- experiments/using_new_client.rb
|
78
|
+
- experiments/using_object_tracer.rb
|
79
|
+
- experiments/using_rbkit.rb
|
80
|
+
- experiments/zmq_client.rb
|
81
|
+
- experiments/zmq_server.rb
|
82
|
+
- ext/extconf.rb
|
83
|
+
- ext/rbkit_message_aggregator.c
|
84
|
+
- ext/rbkit_message_aggregator.h
|
85
|
+
- ext/rbkit_object_graph.c
|
86
|
+
- ext/rbkit_object_graph.h
|
87
|
+
- ext/rbkit_tracer.c
|
88
|
+
- ext/rbkit_tracer.h
|
89
|
+
- lib/rbkit.rb
|
90
|
+
- lib/rbkit/timer.rb
|
91
|
+
- lib/rbkit/version.rb
|
92
|
+
- rbkit.gemspec
|
93
|
+
- schema/tracing_info.md
|
94
|
+
- spec/spec_helper.rb
|
95
|
+
homepage: http://rbkit.codemancers.com
|
96
|
+
licenses:
|
97
|
+
- MIT
|
98
|
+
metadata: {}
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
requirements: []
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 2.2.2
|
116
|
+
signing_key:
|
117
|
+
specification_version: 4
|
118
|
+
summary: Ruby profiler for rest of us
|
119
|
+
test_files:
|
120
|
+
- spec/spec_helper.rb
|