rbkit 0.0.1 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +5 -0
- data/.rspec +2 -0
- data/.travis.yml +17 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +6 -2
- data/LICENSE.txt +22 -0
- data/README.md +74 -11
- data/Rakefile +27 -3
- data/docs/EVENT_FORMAT.md +195 -0
- data/experiments/object_dump.rb +1 -1
- data/experiments/rbkit_command_test.rb +3 -1
- data/experiments/using_rbkit.rb +1 -1
- data/ext/extconf.rb +95 -12
- data/ext/rbkit_allocation_info.c +91 -0
- data/ext/rbkit_allocation_info.h +17 -0
- data/ext/rbkit_event.c +71 -0
- data/ext/rbkit_event.h +63 -0
- data/ext/rbkit_event_packer.c +251 -0
- data/ext/rbkit_event_packer.h +23 -0
- data/ext/rbkit_message_aggregator.c +9 -16
- data/ext/rbkit_message_aggregator.h +0 -1
- data/ext/rbkit_object_graph.c +6 -49
- data/ext/rbkit_object_graph.h +12 -3
- data/ext/rbkit_test_helper.c +25 -0
- data/ext/rbkit_test_helper.h +1 -0
- data/ext/rbkit_tracer.c +106 -323
- data/ext/rbkit_tracer.h +2 -10
- data/lib/rbkit.rb +57 -35
- data/lib/rbkit/rbkit_gc.rb +79 -0
- data/lib/rbkit/version.rb +1 -1
- data/logo.png +0 -0
- data/rbkit.gemspec +1 -0
- data/setup.rb +37 -0
- data/spec/gc_stat_spec.rb +31 -0
- data/spec/hash_event_spec.rb +29 -0
- data/spec/obj_created_spec.rb +52 -0
- data/spec/obj_destroyed_spec.rb +44 -0
- data/spec/object_space_dump_spec.rb +77 -0
- data/spec/rbkit_helpful_messages_spec.rb +61 -0
- data/spec/spec_helper.rb +11 -6
- data/spec/start_server_spec.rb +29 -0
- data/spec/status_spec.rb +48 -0
- data/spec/support/foo_bar_sample_class.rb +24 -0
- data/spec/support/have_message_matcher.rb +26 -0
- metadata +40 -4
- data/schema/tracing_info.md +0 -8
data/ext/rbkit_tracer.h
CHANGED
@@ -9,27 +9,19 @@
|
|
9
9
|
#include "msgpack.h"
|
10
10
|
|
11
11
|
// Structure is used to store profiling data
|
12
|
-
struct
|
12
|
+
typedef struct _rbkit_logger {
|
13
13
|
VALUE hooks[3];
|
14
14
|
VALUE enabled;
|
15
|
-
void (*funcs[3])(void *data, int event_index);
|
16
|
-
void *args[3];
|
17
15
|
void *data;
|
18
16
|
st_table *object_table;
|
19
17
|
st_table *str_table;
|
20
18
|
VALUE newobj_trace;
|
21
19
|
VALUE freeobj_trace;
|
22
|
-
int keep_remains;
|
23
20
|
msgpack_sbuffer *sbuf;
|
24
21
|
msgpack_packer *msgpacker;
|
25
|
-
};
|
22
|
+
} rbkit_logger;
|
26
23
|
|
27
24
|
char * tracer_string_recv(void *socket);
|
28
25
|
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
26
|
|
35
27
|
#endif
|
data/lib/rbkit.rb
CHANGED
@@ -1,57 +1,64 @@
|
|
1
1
|
require "rbkit_tracer"
|
2
2
|
require "rbkit/timer"
|
3
|
+
require "rbkit/rbkit_gc"
|
3
4
|
require "objspace"
|
4
5
|
|
5
6
|
# Class implements user friendly interface in pure Ruby for profiler.
|
6
7
|
module Rbkit
|
8
|
+
DEFAULT_PUB_PORT = 5555
|
9
|
+
DEFAULT_REQ_PORT = 5556
|
10
|
+
|
7
11
|
class Profiler
|
8
12
|
attr_accessor :pub_port, :request_port
|
9
13
|
|
10
14
|
def initialize(pub_port, request_port)
|
15
|
+
[pub_port, request_port].each{|port| validate_port_range(port) }
|
11
16
|
@pub_port = pub_port
|
12
17
|
@request_port = request_port
|
13
18
|
@profiler_thread = nil
|
14
19
|
@stop_thread = false
|
15
20
|
@server_running = false
|
16
21
|
@gc_stats_timer = Rbkit::Timer.new(5) do
|
17
|
-
data =
|
18
|
-
|
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")
|
22
|
+
data = RbkitGC.stat
|
23
|
+
Rbkit.send_hash_as_event(data, Rbkit::EVENT_TYPES[:gc_stats])
|
25
24
|
end
|
26
25
|
@message_dispatch_timer = Rbkit::Timer.new(1) do
|
27
26
|
Rbkit.send_messages
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
31
|
-
def start_server(
|
32
|
-
|
30
|
+
def start_server(enable_object_trace: false, enable_gc_stats: false)
|
31
|
+
if @server_running || !Rbkit.start_stat_server(pub_port, request_port)
|
32
|
+
$stderr.puts "Rbkit server couldn't bind to socket, check if it is already" \
|
33
|
+
" running. Profiling data will not be available."
|
34
|
+
return false
|
35
|
+
end
|
36
|
+
Rbkit.start_stat_tracing if enable_object_trace
|
37
|
+
@enable_gc_stats = enable_gc_stats
|
38
|
+
@server_running = true
|
33
39
|
@profiler_thread = Thread.new do
|
34
|
-
Rbkit.start_stat_server(pub_port, request_port)
|
35
|
-
Rbkit.start_stat_tracing if enable_profiling
|
36
40
|
loop do
|
37
41
|
break if @stop_thread
|
38
42
|
incoming_request = Rbkit.poll_for_request
|
39
43
|
process_incoming_request(incoming_request)
|
40
|
-
@gc_stats_timer.run
|
44
|
+
@gc_stats_timer.run if @enable_gc_stats
|
41
45
|
@message_dispatch_timer.run
|
42
46
|
# Let us sleep this thread for a bit, so as other things can run.
|
43
47
|
sleep(0.05)
|
44
48
|
end
|
45
49
|
end
|
46
|
-
|
50
|
+
at_exit { make_clean_exit(exiting: true) }
|
51
|
+
true
|
47
52
|
end
|
48
53
|
|
49
54
|
def process_incoming_request(incoming_request)
|
50
55
|
case incoming_request
|
51
56
|
when "start_memory_profile"
|
52
57
|
Rbkit.start_stat_tracing
|
58
|
+
@enable_gc_stats = true
|
53
59
|
when "stop_memory_profile"
|
54
60
|
Rbkit.stop_stat_tracing
|
61
|
+
@enable_gc_stats = false
|
55
62
|
when "trigger_gc"
|
56
63
|
GC.start
|
57
64
|
when "objectspace_snapshot"
|
@@ -60,42 +67,57 @@ module Rbkit
|
|
60
67
|
end
|
61
68
|
|
62
69
|
def stop_server
|
63
|
-
return if !@server_running
|
64
70
|
Rbkit.stop_stat_server
|
65
|
-
@server_running = false
|
66
71
|
end
|
67
72
|
|
68
|
-
def make_clean_exit
|
73
|
+
def make_clean_exit(exiting: false)
|
74
|
+
return false if !@server_running
|
69
75
|
@stop_thread = true
|
70
76
|
stop_server
|
77
|
+
@server_running = false
|
78
|
+
true
|
71
79
|
end
|
72
|
-
end
|
73
80
|
|
74
|
-
|
81
|
+
private
|
75
82
|
|
76
|
-
|
77
|
-
|
78
|
-
@profiler = Rbkit::Profiler.new(pub_port, request_port)
|
79
|
-
@profiler.start_server(enable_profiling: true)
|
80
|
-
at_exit do
|
81
|
-
self.stop_server
|
83
|
+
def validate_port_range(port)
|
84
|
+
raise ArgumentError, 'Invalid port value' unless (1024..65000).include?(port)
|
82
85
|
end
|
83
86
|
end
|
84
87
|
|
85
|
-
|
86
|
-
|
87
|
-
#
|
88
|
-
# to the
|
89
|
-
|
90
|
-
|
88
|
+
########### Rbkit API ###########
|
89
|
+
|
90
|
+
# Starts the Rbkit server and waits for a client to connect and issue
|
91
|
+
# commands to the request_port, until then there's zero performance overhead.
|
92
|
+
# Profiling data is sent asynchronously over pub_port.
|
93
|
+
# This method can be called early in a ruby application so that
|
94
|
+
# whenever profiling needs to be done, the client can attach itself to the
|
95
|
+
# inactive server, do the profiling and leave.
|
96
|
+
def self.start_server(pub_port: DEFAULT_PUB_PORT, request_port: DEFAULT_REQ_PORT)
|
97
|
+
@profiler ||= Rbkit::Profiler.new(pub_port, request_port)
|
91
98
|
@profiler.start_server
|
92
|
-
|
93
|
-
|
94
|
-
|
99
|
+
end
|
100
|
+
|
101
|
+
# Starts the server with all tracepoints enabled by default. User can
|
102
|
+
# optionally disable tracepoints using the optional arguments.
|
103
|
+
# This method can be used to profile the startup process of a ruby
|
104
|
+
# application where sending commands from the client to enable
|
105
|
+
# profiling is not feasible.
|
106
|
+
def self.start_profiling(pub_port: DEFAULT_PUB_PORT, request_port: DEFAULT_REQ_PORT,
|
107
|
+
enable_object_trace: true, enable_gc_stats: true)
|
108
|
+
@profiler ||= Rbkit::Profiler.new(pub_port, request_port)
|
109
|
+
@profiler.start_server(enable_object_trace: enable_object_trace,
|
110
|
+
enable_gc_stats: enable_gc_stats)
|
95
111
|
end
|
96
112
|
|
97
113
|
# Stops profiling and brings down the rbkit server if it's running
|
98
114
|
def self.stop_server
|
99
|
-
@profiler.make_clean_exit
|
115
|
+
if !@profiler.nil? && @profiler.make_clean_exit
|
116
|
+
@profiler = nil
|
117
|
+
true
|
118
|
+
else
|
119
|
+
$stderr.puts "Cannot stop Rbkit server. Is it running?"
|
120
|
+
false
|
121
|
+
end
|
100
122
|
end
|
101
123
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require "objspace"
|
2
|
+
|
3
|
+
module Rbkit
|
4
|
+
class RbkitGC
|
5
|
+
# Returns a standardized hash containing the data
|
6
|
+
# returned by GC.stat
|
7
|
+
# @return [Hash] Keys :
|
8
|
+
# [count] Count of major and minor GCs so far
|
9
|
+
# [minor_gc_count] Count of minor GCs
|
10
|
+
# [major_gc_count] Count of major GCs
|
11
|
+
# [heap_allocated_pages] Count of allocated pages (heap_eden_pages + heap_tomb_pages)
|
12
|
+
# [heap_eden_pages] Count of pages which has atleast one live object
|
13
|
+
# [heap_tomb_pages] Count of pages which don't have any object yet
|
14
|
+
# [heap_allocatable_pages] Count of pages that will be allocated if Ruby runs out of heap
|
15
|
+
# [heap_sorted_length] Count of total number of sorted pages (>= heap_allocated_pages + heap_allocatable_pages)
|
16
|
+
# [heap_live_slots] Count of slots in all pages having live objects
|
17
|
+
# [heap_free_slots] Count of free slots in all pages
|
18
|
+
# [heap_final_slots] Count of zombie objects
|
19
|
+
# [heap_swept_slots] Count of slots swept after last GC
|
20
|
+
# [old_objects] Count of old generation objects
|
21
|
+
# [old_objects_limit] Old generation object count after which GC is triggered
|
22
|
+
# [total_allocated_objects] Number of created objects in the lifetime of the process
|
23
|
+
# [total_freed_objects] Number of freed objects in the lifetime of the process
|
24
|
+
# [malloc_increase_bytes] Malloc'ed bytes since last GC
|
25
|
+
# [malloc_increase_bytes_limit] Minor GC is triggered when malloc_increase_bytes exceeds this value
|
26
|
+
# [oldmalloc_increase_bytes] Malloc'ed bytes for old objects since last major GC
|
27
|
+
# [oldmalloc_increase_bytes_limit] Major GC is triggered with oldmalloc_increase_bytes exceeds this value
|
28
|
+
# [total_heap_size] heap_allocated_pages * max slots per page * size of one slot
|
29
|
+
# [total_memsize] ObjectSpace.memsize_of_all
|
30
|
+
def self.stat
|
31
|
+
stats = {}
|
32
|
+
data = GC.stat
|
33
|
+
|
34
|
+
stats[:count] = data[:count]
|
35
|
+
stats[:minor_gc_count] = data[:minor_gc_count]
|
36
|
+
stats[:major_gc_count] = data[:major_gc_count]
|
37
|
+
|
38
|
+
if RUBY_VERSION >= "2.2.0"
|
39
|
+
[
|
40
|
+
:heap_allocated_pages, :heap_eden_pages, :heap_tomb_pages,
|
41
|
+
:heap_allocatable_pages, :heap_sorted_length, :heap_live_slots,
|
42
|
+
:heap_free_slots, :heap_final_slots, :heap_swept_slots,
|
43
|
+
:old_objects, :old_objects_limit, :total_allocated_objects,
|
44
|
+
:total_freed_objects, :malloc_increase_bytes,
|
45
|
+
:malloc_increase_bytes_limit, :oldmalloc_increase_bytes,
|
46
|
+
:oldmalloc_increase_bytes_limit
|
47
|
+
].each do |key|
|
48
|
+
stats[key] = data[key]
|
49
|
+
end
|
50
|
+
elsif RUBY_VERSION >= "2.1.0"
|
51
|
+
stats[:heap_allocated_pages] = data[:heap_used]
|
52
|
+
stats[:heap_eden_pages] = data[:heap_eden_page_length]
|
53
|
+
stats[:heap_tomb_pages] = data[:heap_tomb_page_length]
|
54
|
+
stats[:heap_allocatable_pages] = data[:heap_increment]
|
55
|
+
stats[:heap_sorted_length] = data[:heap_length]
|
56
|
+
stats[:heap_live_slots] = data[:heap_live_slot]
|
57
|
+
stats[:heap_free_slots] = data[:heap_free_slot]
|
58
|
+
stats[:heap_final_slots] = data[:heap_final_slot]
|
59
|
+
stats[:heap_swept_slots] = data[:heap_swept_slot]
|
60
|
+
stats[:old_objects] = data[:old_object]
|
61
|
+
stats[:old_objects_limit] = data[:old_object_limit]
|
62
|
+
stats[:total_allocated_objects] = data[:total_allocated_object]
|
63
|
+
stats[:total_freed_objects] = data[:total_freed_object]
|
64
|
+
stats[:malloc_increase_bytes] = data[:malloc_increase]
|
65
|
+
stats[:malloc_increase_bytes_limit] = data[:malloc_limit]
|
66
|
+
stats[:oldmalloc_increase_bytes] = data[:oldmalloc_increase]
|
67
|
+
stats[:oldmalloc_increase_bytes_limit] = data[:oldmalloc_limit]
|
68
|
+
end
|
69
|
+
|
70
|
+
no_of_allocated_pages = stats[:heap_allocated_pages] rescue 0
|
71
|
+
max_objects_per_page = GC::INTERNAL_CONSTANTS[:HEAP_OBJ_LIMIT]
|
72
|
+
size_of_one_obj = GC::INTERNAL_CONSTANTS[:RVALUE_SIZE]
|
73
|
+
stats[:total_heap_size] = no_of_allocated_pages * max_objects_per_page *
|
74
|
+
size_of_one_obj
|
75
|
+
stats[:total_memsize] = ObjectSpace.memsize_of_all
|
76
|
+
stats
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/rbkit/version.rb
CHANGED
data/logo.png
ADDED
Binary file
|
data/rbkit.gemspec
CHANGED
@@ -14,6 +14,7 @@ Gem::Specification.new do |s|
|
|
14
14
|
if s.respond_to? :required_rubygems_version=
|
15
15
|
s.required_rubygems_version = Gem::Requirement.new(">= 0")
|
16
16
|
end
|
17
|
+
s.required_ruby_version = '>= 2.1.0'
|
17
18
|
s.authors = ["Hemant Kumar", "Emil Soman", "Kashyap"]
|
18
19
|
s.description = %q{Something small for process management}
|
19
20
|
s.email = %q{hemant@codemancers.com emil@codemancers.com kashyap@codemancers.com}
|
data/setup.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
class Setup
|
5
|
+
attr_accessor :site_dir, :site_lib_dir, :site_arch_dir
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@site_dir = RbConfig::CONFIG["sitedir"]
|
9
|
+
@site_lib_dir = RbConfig::CONFIG["sitelibdir"]
|
10
|
+
@site_arch_dir = RbConfig::CONFIG["sitearchdir"]
|
11
|
+
end
|
12
|
+
|
13
|
+
def compile
|
14
|
+
Dir.chdir 'ext' do
|
15
|
+
if File.exist?("Makefile")
|
16
|
+
system("make clean")
|
17
|
+
end
|
18
|
+
|
19
|
+
system("#{Gem.ruby} extconf.rb")
|
20
|
+
system("make")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def copy_files
|
25
|
+
FileUtils.cp_r "lib/.", site_lib_dir, verbose: true
|
26
|
+
ext_path =
|
27
|
+
File.absolute_path "ext/rbkit_tracer.#{RbConfig::MAKEFILE_CONFIG['DLEXT']}"
|
28
|
+
FileUtils.cp_r ext_path, site_arch_dir, verbose: true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
if __FILE__ == $0
|
33
|
+
Setup.new.tap do |setup|
|
34
|
+
setup.compile
|
35
|
+
setup.copy_files
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'gc_stat' do
|
4
|
+
let(:stat) { Rbkit::RbkitGC.stat }
|
5
|
+
it 'should have the correct gc stat keys' do
|
6
|
+
expect(stat.keys).to eql [
|
7
|
+
:count,
|
8
|
+
:minor_gc_count,
|
9
|
+
:major_gc_count,
|
10
|
+
:heap_allocated_pages,
|
11
|
+
:heap_eden_pages,
|
12
|
+
:heap_tomb_pages,
|
13
|
+
:heap_allocatable_pages,
|
14
|
+
:heap_sorted_length,
|
15
|
+
:heap_live_slots,
|
16
|
+
:heap_free_slots,
|
17
|
+
:heap_final_slots,
|
18
|
+
:heap_swept_slots,
|
19
|
+
:old_objects,
|
20
|
+
:old_objects_limit,
|
21
|
+
:total_allocated_objects,
|
22
|
+
:total_freed_objects,
|
23
|
+
:malloc_increase_bytes,
|
24
|
+
:malloc_increase_bytes_limit,
|
25
|
+
:oldmalloc_increase_bytes,
|
26
|
+
:oldmalloc_increase_bytes_limit,
|
27
|
+
:total_heap_size,
|
28
|
+
:total_memsize ]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'msgpack'
|
3
|
+
|
4
|
+
describe 'send_hash_as_event' do
|
5
|
+
let(:hash) { {'foo' => 'bar', 123 => "hello world"} }
|
6
|
+
let(:payload) { Rbkit::MESSAGE_FIELDS[:payload] }
|
7
|
+
let(:event_type) { Rbkit::MESSAGE_FIELDS[:event_type] }
|
8
|
+
describe 'when event_type is known' do
|
9
|
+
before do
|
10
|
+
Rbkit.start_profiling(enable_gc_stats: false, enable_object_trace: false)
|
11
|
+
Rbkit.send_hash_as_event(hash, Rbkit::EVENT_TYPES[:gc_stats])
|
12
|
+
packed_message = Rbkit.get_queued_messages
|
13
|
+
@message = MessagePack.unpack packed_message
|
14
|
+
Rbkit.stop_server
|
15
|
+
end
|
16
|
+
it 'should create a custom event with the serialized hash' do
|
17
|
+
expect(@message[payload].first[event_type]).to eql Rbkit::EVENT_TYPES[:gc_stats]
|
18
|
+
expect(@message[payload].first[payload]).to eql hash
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'when event_type is not known' do
|
23
|
+
it 'should raise NotImplementedError with a meaningful message' do
|
24
|
+
expect { Rbkit.send_hash_as_event(hash, 100) }
|
25
|
+
.to raise_error(NotImplementedError,
|
26
|
+
"Rbkit : Unpacking of event type '100' not implemented")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/have_message_matcher'
|
3
|
+
require 'msgpack'
|
4
|
+
|
5
|
+
describe "obj_created event" do
|
6
|
+
let(:payload) { Rbkit::MESSAGE_FIELDS[:payload] }
|
7
|
+
let(:class_name) { Rbkit::MESSAGE_FIELDS[:class_name] }
|
8
|
+
let(:event_type) { Rbkit::MESSAGE_FIELDS[:event_type] }
|
9
|
+
let(:object_id) { Rbkit::MESSAGE_FIELDS[:object_id] }
|
10
|
+
let(:foo_info) do
|
11
|
+
@message_list[payload]
|
12
|
+
.select{|x| x[event_type] == Rbkit::EVENT_TYPES[:obj_created] &&
|
13
|
+
x[payload][class_name] =='Foo' }
|
14
|
+
end
|
15
|
+
let(:bar_info) do
|
16
|
+
@message_list[payload]
|
17
|
+
.select{|x| x[event_type] == Rbkit::EVENT_TYPES[:obj_created] &&
|
18
|
+
x[payload][class_name] =='Bar'}
|
19
|
+
end
|
20
|
+
let(:short_lived_bar_info) do
|
21
|
+
@message_list[payload]
|
22
|
+
.select{|x| x[event_type] == Rbkit::EVENT_TYPES[:obj_created] &&
|
23
|
+
x[payload][class_name] =='ShortLivedBar' }
|
24
|
+
end
|
25
|
+
before(:all) do
|
26
|
+
Rbkit.start_profiling(enable_gc_stats: false, enable_object_trace: true)
|
27
|
+
@foo_obj = Foo.new
|
28
|
+
packed_message = Rbkit.get_queued_messages
|
29
|
+
Rbkit.stop_server
|
30
|
+
@message_list = MessagePack.unpack packed_message
|
31
|
+
end
|
32
|
+
it "should be part of message list" do
|
33
|
+
expect(@message_list).to have_message(Rbkit::EVENT_TYPES[:obj_created])
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should record objects only once' do
|
37
|
+
expect(foo_info.size).to eql 1
|
38
|
+
expect(bar_info.size).to eql 1
|
39
|
+
expect(short_lived_bar_info.size).to eql 1
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should record correct object_id' do
|
43
|
+
expect(foo_info.first[payload][object_id]).to eql @foo_obj.object_id
|
44
|
+
expect(bar_info.first[payload][object_id]).to eql @foo_obj.bar.object_id
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should record correct class_name' do
|
48
|
+
expect(foo_info.first[payload][class_name]).to eql @foo_obj.class.to_s
|
49
|
+
expect(bar_info.first[payload][class_name]).to eql @foo_obj.bar.class.to_s
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/have_message_matcher'
|
3
|
+
require 'msgpack'
|
4
|
+
|
5
|
+
describe "obj_destroyed event" do
|
6
|
+
let(:payload) { Rbkit::MESSAGE_FIELDS[:payload] }
|
7
|
+
let(:event_type) { Rbkit::MESSAGE_FIELDS[:event_type] }
|
8
|
+
let(:object_id) { Rbkit::MESSAGE_FIELDS[:object_id] }
|
9
|
+
let(:class_name) { Rbkit::MESSAGE_FIELDS[:class_name] }
|
10
|
+
let(:foo_info) do
|
11
|
+
@message_list[payload]
|
12
|
+
.select{|x| x[event_type] == Rbkit::EVENT_TYPES[:obj_destroyed] &&
|
13
|
+
x[payload][object_id] == @foo_obj.object_id }
|
14
|
+
end
|
15
|
+
let(:short_lived_bar_info) do
|
16
|
+
short_lived_bar_object_id = @message_list[payload]
|
17
|
+
.find{|x| x[event_type] == Rbkit::EVENT_TYPES[:obj_created] &&
|
18
|
+
x[payload][class_name] == 'ShortLivedBar'}[payload][object_id]
|
19
|
+
@message_list[payload]
|
20
|
+
.select{|x| x[event_type] == Rbkit::EVENT_TYPES[:obj_destroyed] &&
|
21
|
+
x[payload][object_id] == short_lived_bar_object_id}
|
22
|
+
end
|
23
|
+
before(:all) do
|
24
|
+
Rbkit.start_profiling(enable_gc_stats: false, enable_object_trace: true)
|
25
|
+
@foo_obj = Foo.new
|
26
|
+
GC.start
|
27
|
+
packed_message = Rbkit.get_queued_messages
|
28
|
+
Rbkit.stop_server
|
29
|
+
@message_list = MessagePack.unpack packed_message
|
30
|
+
end
|
31
|
+
it "should be part of message list" do
|
32
|
+
expect(@message_list).to have_message(Rbkit::EVENT_TYPES[:obj_destroyed])
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should record the deleted object' do
|
36
|
+
expect(short_lived_bar_info.size).to eql 1
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should not record the live object' do
|
40
|
+
expect(foo_info.size).to eql 0
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|