rbkit 0.0.1 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- 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/experiments/object_dump.rb
CHANGED
@@ -9,7 +9,8 @@ commands = [
|
|
9
9
|
'start_memory_profile',
|
10
10
|
'stop_memory_profile',
|
11
11
|
'objectspace_snapshot',
|
12
|
-
'trigger_gc'
|
12
|
+
'trigger_gc',
|
13
|
+
'handshake'
|
13
14
|
]
|
14
15
|
|
15
16
|
output_file = File.open("/tmp/rbkit.log", "w")
|
@@ -33,6 +34,7 @@ Thread.new do
|
|
33
34
|
request_socket.send(command)
|
34
35
|
puts "sent #{command}"
|
35
36
|
response = request_socket.recv()
|
37
|
+
response = MessagePack.unpack(response) unless response == "ok"
|
36
38
|
puts "received #{response}"
|
37
39
|
end
|
38
40
|
end
|
data/experiments/using_rbkit.rb
CHANGED
data/ext/extconf.rb
CHANGED
@@ -1,18 +1,101 @@
|
|
1
1
|
require 'mkmf'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
CWD = File.expand_path('../', __FILE__)
|
5
|
+
|
6
|
+
def red(str); "\033[31m#{str}\033[0m" end
|
7
|
+
def green(str); "\033[32m#{str}\033[0m" end
|
8
|
+
|
2
9
|
if ENV['RBKIT_DEV']
|
3
|
-
|
4
|
-
$CFLAGS << ' -g'
|
5
|
-
$defs << '-DRBKIT_DEV'
|
10
|
+
puts green("Dev environment enabled.")
|
11
|
+
$CFLAGS << ' -g' # Enable debug flag
|
12
|
+
$defs << '-DRBKIT_DEV' # Set macro named RBKIT_DEV
|
6
13
|
end
|
7
|
-
|
14
|
+
|
15
|
+
def download_file(url)
|
16
|
+
if find_executable('curl')
|
17
|
+
system("curl -L -O #{url}")
|
18
|
+
elsif find_executable('wget')
|
19
|
+
system("wget #{url}")
|
20
|
+
else
|
21
|
+
fail "Cannot download #{url}. You need either curl or wget to continue"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def download_and_install_zeromq_from_source
|
26
|
+
url = "http://download.zeromq.org/zeromq-4.0.4.tar.gz"
|
27
|
+
filename = "zeromq-4.0.4.tar.gz"
|
28
|
+
basename = File.basename(filename, '.tar.gz')
|
29
|
+
dist_path = "#{CWD}/#{basename}/dist"
|
30
|
+
|
31
|
+
unless File.exists? "#{dist_path}/lib/libzmq.a"
|
32
|
+
['libtool', 'autoconf', 'automake'].each do |executable|
|
33
|
+
fail "#{executable} needed by zeromq not found." unless find_executable(executable)
|
34
|
+
end
|
35
|
+
puts green("Downloading and installing zeromq from source")
|
36
|
+
download_file(url)
|
37
|
+
system("tar zxvf #{filename}")
|
38
|
+
Dir.chdir(basename) do
|
39
|
+
system("./configure CPPFLAGS='-fPIC' --prefix='#{dist_path}'")
|
40
|
+
system("make && make install")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
FileUtils.cp "#{dist_path}/lib/libzmq.a", "#{CWD}/libzmq.a"
|
44
|
+
$INCFLAGS[0,0] = "-I#{dist_path}/include "
|
45
|
+
end
|
46
|
+
|
47
|
+
def download_and_install_msgpack_from_source
|
48
|
+
url = "https://github.com/msgpack/msgpack-c/releases/download/cpp-0.5.9/msgpack-0.5.9.tar.gz"
|
49
|
+
filename = "msgpack-0.5.9.tar.gz"
|
50
|
+
basename = File.basename(filename, '.tar.gz')
|
51
|
+
dist_path = "#{CWD}/#{basename}/dist"
|
52
|
+
|
53
|
+
unless File.exists? "#{dist_path}/lib/libmsgpack.a"
|
54
|
+
puts green("Downloading and installing msgpack from source")
|
55
|
+
download_file(url)
|
56
|
+
system("tar zxvf #{filename}")
|
57
|
+
Dir.chdir(basename) do
|
58
|
+
system("./configure CFLAGS='-fPIC' --prefix='#{dist_path}'")
|
59
|
+
system("make && make install")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
FileUtils.cp "#{dist_path}/lib/libmsgpack.a", "#{CWD}/libmsgpack.a"
|
64
|
+
$INCFLAGS[0,0] = "-I#{dist_path}/include "
|
65
|
+
end
|
66
|
+
|
67
|
+
# Ensure Ruby 2.1.x API exists before proceeding
|
68
|
+
unless(have_func('rb_postponed_job_register_one') &&
|
8
69
|
have_func('rb_profile_frames') &&
|
9
70
|
have_func('rb_tracepoint_new') &&
|
10
|
-
have_const('RUBY_INTERNAL_EVENT_NEWOBJ')
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
71
|
+
have_const('RUBY_INTERNAL_EVENT_NEWOBJ'))
|
72
|
+
fail 'Missing Ruby 2.1.x API. Rbkit only works with Ruby 2.1+'
|
73
|
+
end
|
74
|
+
|
75
|
+
# Install zmq if not available
|
76
|
+
unless(have_library("zmq") && have_header("zmq.h"))
|
77
|
+
if Gem.win_platform?
|
78
|
+
puts red("On Windows? You'll have to install zeromq by yourself.")
|
79
|
+
else
|
80
|
+
download_and_install_zeromq_from_source
|
81
|
+
end
|
82
|
+
|
83
|
+
unless have_library('stdc++') and have_library('zmq') and have_header('zmq.h')
|
84
|
+
fail 'zeromq build failed.'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Install msgpack if not available
|
89
|
+
unless(have_library("msgpack") && have_header("msgpack.h"))
|
90
|
+
if Gem.win_platform?
|
91
|
+
puts red("On Windows? You'll have to install msgpack by yourself.")
|
92
|
+
else
|
93
|
+
download_and_install_msgpack_from_source
|
94
|
+
end
|
95
|
+
|
96
|
+
unless have_library('msgpack') and have_header('msgpack.h')
|
97
|
+
fail 'msgpack build failed.'
|
98
|
+
end
|
18
99
|
end
|
100
|
+
|
101
|
+
create_makefile('rbkit_tracer')
|
@@ -0,0 +1,91 @@
|
|
1
|
+
#include "rbkit_allocation_info.h"
|
2
|
+
|
3
|
+
/*
|
4
|
+
* make_unique_str helps to reuse memory by allocating memory for a string
|
5
|
+
* only once and keeping track of how many times that string is referenced.
|
6
|
+
* It does so by creating a map of strings to their no of references.
|
7
|
+
* A new map is created for a string on its first use, and for further usages
|
8
|
+
* the reference count is incremented.
|
9
|
+
*/
|
10
|
+
static const char * make_unique_str(st_table *tbl, const char *str, long len) {
|
11
|
+
if (!str) {
|
12
|
+
return NULL;
|
13
|
+
}
|
14
|
+
else {
|
15
|
+
st_data_t n;
|
16
|
+
char *result;
|
17
|
+
|
18
|
+
if (st_lookup(tbl, (st_data_t)str, &n)) {
|
19
|
+
st_insert(tbl, (st_data_t)str, n+1);
|
20
|
+
st_get_key(tbl, (st_data_t)str, (st_data_t *)&result);
|
21
|
+
}
|
22
|
+
else {
|
23
|
+
result = (char *)ruby_xmalloc(len+1);
|
24
|
+
strncpy(result, str, len);
|
25
|
+
result[len] = 0;
|
26
|
+
st_add_direct(tbl, (st_data_t)result, 1);
|
27
|
+
}
|
28
|
+
return result;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
/*
|
33
|
+
* Used to free allocation of string when it's not referenced anymore.
|
34
|
+
* Decrements the reference count of a string if it's still used, else
|
35
|
+
* the map is removed completely.
|
36
|
+
*/
|
37
|
+
static void delete_unique_str(st_table *tbl, const char *str) {
|
38
|
+
if (str) {
|
39
|
+
st_data_t n;
|
40
|
+
|
41
|
+
st_lookup(tbl, (st_data_t)str, &n);
|
42
|
+
if (n == 1) {
|
43
|
+
st_delete(tbl, (st_data_t *)&str, 0);
|
44
|
+
ruby_xfree((char *)str);
|
45
|
+
}
|
46
|
+
else {
|
47
|
+
st_insert(tbl, (st_data_t)str, n-1);
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
rbkit_allocation_info * new_rbkit_allocation_info(rb_trace_arg_t *tparg, st_table *str_table, st_table *object_table) {
|
53
|
+
VALUE obj = rb_tracearg_object(tparg);
|
54
|
+
VALUE klass = RBASIC_CLASS(obj);
|
55
|
+
VALUE path = rb_tracearg_path(tparg);
|
56
|
+
VALUE line = rb_tracearg_lineno(tparg);
|
57
|
+
VALUE method_id = rb_tracearg_method_id(tparg);
|
58
|
+
VALUE defined_klass = rb_tracearg_defined_class(tparg);
|
59
|
+
|
60
|
+
rbkit_allocation_info *info;
|
61
|
+
const char *path_cstr = RTEST(path) ? make_unique_str(str_table, RSTRING_PTR(path), RSTRING_LEN(path)) : 0;
|
62
|
+
VALUE class_path = (RTEST(defined_klass) && !OBJ_FROZEN(defined_klass)) ? rb_class_path_cached(defined_klass) : Qnil;
|
63
|
+
const char *class_path_cstr = RTEST(class_path) ? make_unique_str(str_table, RSTRING_PTR(class_path), RSTRING_LEN(class_path)) : 0;
|
64
|
+
|
65
|
+
if (st_lookup(object_table, (st_data_t)obj, (st_data_t *)&info)) {
|
66
|
+
/* reuse info */
|
67
|
+
delete_unique_str(str_table, info->path);
|
68
|
+
delete_unique_str(str_table, info->class_path);
|
69
|
+
}
|
70
|
+
else {
|
71
|
+
info = (rbkit_allocation_info *)ruby_xmalloc(sizeof(rbkit_allocation_info));
|
72
|
+
}
|
73
|
+
|
74
|
+
info->path = path_cstr;
|
75
|
+
info->line = NUM2INT(line);
|
76
|
+
info->method_id = method_id;
|
77
|
+
info->class_path = class_path_cstr;
|
78
|
+
info->generation = rb_gc_count();
|
79
|
+
st_insert(object_table, (st_data_t)obj, (st_data_t)info);
|
80
|
+
return info;
|
81
|
+
}
|
82
|
+
|
83
|
+
void delete_rbkit_allocation_info(rb_trace_arg_t *tparg, VALUE obj, st_table *str_table, st_table *object_table) {
|
84
|
+
rbkit_allocation_info *info;
|
85
|
+
if (st_lookup(object_table, (st_data_t)obj, (st_data_t *)&info)) {
|
86
|
+
st_delete(object_table, (st_data_t *)&obj, (st_data_t *)&info);
|
87
|
+
delete_unique_str(str_table, info->path);
|
88
|
+
delete_unique_str(str_table, info->class_path);
|
89
|
+
ruby_xfree(info);
|
90
|
+
}
|
91
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#ifndef RBKIT_ALLOCATION_INFO
|
2
|
+
#define RBKIT_ALLOCATION_INFO
|
3
|
+
#include <ruby.h>
|
4
|
+
#include "ruby/debug.h"
|
5
|
+
|
6
|
+
typedef struct _rbkit_allocation_info {
|
7
|
+
const char *path;
|
8
|
+
unsigned long line;
|
9
|
+
const char *class_path;
|
10
|
+
VALUE method_id;
|
11
|
+
size_t generation;
|
12
|
+
} rbkit_allocation_info;
|
13
|
+
|
14
|
+
rbkit_allocation_info * new_rbkit_allocation_info(rb_trace_arg_t *tparg, st_table *str_table, st_table *object_table);
|
15
|
+
void delete_rbkit_allocation_info(rb_trace_arg_t *tparg, VALUE obj, st_table *str_table, st_table *object_table);
|
16
|
+
|
17
|
+
#endif
|
data/ext/rbkit_event.c
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
#include "rbkit_event.h"
|
2
|
+
|
3
|
+
VALUE rbkit_event_types_as_hash() {
|
4
|
+
VALUE events = rb_hash_new();
|
5
|
+
rb_hash_aset(events, ID2SYM(rb_intern("obj_created")), INT2FIX(obj_created));
|
6
|
+
rb_hash_aset(events, ID2SYM(rb_intern("obj_destroyed")), INT2FIX(obj_destroyed));
|
7
|
+
rb_hash_aset(events, ID2SYM(rb_intern("gc_start")), INT2FIX(gc_start));
|
8
|
+
rb_hash_aset(events, ID2SYM(rb_intern("gc_end_m")), INT2FIX(gc_end_m));
|
9
|
+
rb_hash_aset(events, ID2SYM(rb_intern("gc_end_s")), INT2FIX(gc_end_s));
|
10
|
+
rb_hash_aset(events, ID2SYM(rb_intern("object_space_dump")), INT2FIX(object_space_dump));
|
11
|
+
rb_hash_aset(events, ID2SYM(rb_intern("gc_stats")), INT2FIX(gc_stats));
|
12
|
+
rb_hash_aset(events, ID2SYM(rb_intern("event_collection")), INT2FIX(event_collection));
|
13
|
+
rb_hash_aset(events, ID2SYM(rb_intern("handshake")), INT2FIX(handshake));
|
14
|
+
OBJ_FREEZE(events);
|
15
|
+
return events;
|
16
|
+
}
|
17
|
+
|
18
|
+
rbkit_obj_created_event *new_rbkit_obj_created_event(unsigned long long object_id,
|
19
|
+
const char *klass, rbkit_allocation_info *info) {
|
20
|
+
rbkit_obj_created_event *event = malloc(sizeof(rbkit_obj_created_event));
|
21
|
+
|
22
|
+
rbkit_event_header *header = (rbkit_event_header *)event;
|
23
|
+
header->event_type = obj_created;
|
24
|
+
|
25
|
+
event->object_id = object_id;
|
26
|
+
event->klass = klass;
|
27
|
+
event->allocation_info = info;
|
28
|
+
return event;
|
29
|
+
}
|
30
|
+
|
31
|
+
rbkit_obj_destroyed_event *new_rbkit_obj_destroyed_event(unsigned long long object_id) {
|
32
|
+
rbkit_obj_destroyed_event *event = malloc(sizeof(rbkit_obj_destroyed_event));
|
33
|
+
|
34
|
+
rbkit_event_header *header = (rbkit_event_header *)event;
|
35
|
+
header->event_type = obj_destroyed;
|
36
|
+
|
37
|
+
event->object_id = object_id;
|
38
|
+
return event;
|
39
|
+
}
|
40
|
+
|
41
|
+
rbkit_hash_event *new_rbkit_hash_event(rbkit_event_type event_type, VALUE hash) {
|
42
|
+
rbkit_hash_event *event = malloc(sizeof(rbkit_hash_event));
|
43
|
+
|
44
|
+
rbkit_event_header *header = (rbkit_event_header *)event;
|
45
|
+
header->event_type = event_type;
|
46
|
+
|
47
|
+
event->hash = hash;
|
48
|
+
return event;
|
49
|
+
}
|
50
|
+
|
51
|
+
rbkit_object_space_dump_event *new_rbkit_object_space_dump_event(rbkit_object_dump *dump) {
|
52
|
+
rbkit_object_space_dump_event *event = malloc(sizeof(rbkit_object_space_dump_event));
|
53
|
+
|
54
|
+
rbkit_event_header *header = (rbkit_event_header *)event;
|
55
|
+
header->event_type = object_space_dump;
|
56
|
+
|
57
|
+
event->dump = dump;
|
58
|
+
return event;
|
59
|
+
}
|
60
|
+
|
61
|
+
rbkit_event_collection_event *new_rbkit_event_collection_event(void *buffer, size_t buffer_size, size_t message_count) {
|
62
|
+
rbkit_event_collection_event *event = malloc(sizeof(rbkit_event_collection_event));
|
63
|
+
|
64
|
+
rbkit_event_header *header = (rbkit_event_header *)event;
|
65
|
+
header->event_type = event_collection;
|
66
|
+
|
67
|
+
event->buffer = buffer;
|
68
|
+
event->buffer_size = buffer_size;
|
69
|
+
event->message_count = message_count;
|
70
|
+
return event;
|
71
|
+
}
|
data/ext/rbkit_event.h
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#ifndef RBKIT_EVENT
|
2
|
+
#define RBKIT_EVENT
|
3
|
+
#include "rbkit_allocation_info.h"
|
4
|
+
#include "rbkit_object_graph.h"
|
5
|
+
|
6
|
+
typedef enum _event_type {
|
7
|
+
obj_created,
|
8
|
+
obj_destroyed,
|
9
|
+
gc_start,
|
10
|
+
gc_end_m,
|
11
|
+
gc_end_s,
|
12
|
+
object_space_dump,
|
13
|
+
gc_stats,
|
14
|
+
event_collection,
|
15
|
+
handshake
|
16
|
+
} rbkit_event_type;
|
17
|
+
|
18
|
+
VALUE rbkit_event_types_as_hash();
|
19
|
+
|
20
|
+
typedef struct _rbkit_event_header {
|
21
|
+
rbkit_event_type event_type;
|
22
|
+
} rbkit_event_header;
|
23
|
+
|
24
|
+
typedef struct _rbkit_obj_created_event {
|
25
|
+
rbkit_event_header event_header;
|
26
|
+
unsigned long long object_id;
|
27
|
+
const char *klass;
|
28
|
+
rbkit_allocation_info *allocation_info;
|
29
|
+
} rbkit_obj_created_event;
|
30
|
+
|
31
|
+
rbkit_obj_created_event *new_rbkit_obj_created_event(unsigned long long object_id, const char *klass, rbkit_allocation_info *info);
|
32
|
+
|
33
|
+
typedef struct _rbkit_obj_destroyed_event {
|
34
|
+
rbkit_event_header event_header;
|
35
|
+
unsigned long long object_id;
|
36
|
+
} rbkit_obj_destroyed_event;
|
37
|
+
|
38
|
+
rbkit_obj_destroyed_event *new_rbkit_obj_destroyed_event(unsigned long long object_id);
|
39
|
+
|
40
|
+
typedef struct _rbkit_hash_event {
|
41
|
+
rbkit_event_header event_header;
|
42
|
+
VALUE hash;
|
43
|
+
} rbkit_hash_event;
|
44
|
+
|
45
|
+
rbkit_hash_event *new_rbkit_hash_event(rbkit_event_type event_type, VALUE hash);
|
46
|
+
|
47
|
+
typedef struct _rbkit_object_space_dump_event {
|
48
|
+
rbkit_event_header event_header;
|
49
|
+
rbkit_object_dump *dump;
|
50
|
+
} rbkit_object_space_dump_event;
|
51
|
+
|
52
|
+
rbkit_object_space_dump_event *new_rbkit_object_space_dump_event(rbkit_object_dump *dump);
|
53
|
+
|
54
|
+
typedef struct _rbkit_event_collection_event {
|
55
|
+
rbkit_event_header event_header;
|
56
|
+
void *buffer;
|
57
|
+
size_t buffer_size;
|
58
|
+
size_t message_count;
|
59
|
+
} rbkit_event_collection_event;
|
60
|
+
|
61
|
+
rbkit_event_collection_event *new_rbkit_event_collection_event(void * buffer, size_t buffer_size, size_t message_count);
|
62
|
+
|
63
|
+
#endif
|
@@ -0,0 +1,251 @@
|
|
1
|
+
#include "rbkit_event_packer.h"
|
2
|
+
#include "rbkit_object_graph.h"
|
3
|
+
#include <sys/time.h>
|
4
|
+
|
5
|
+
static void pack_string(msgpack_packer *packer, const char *string) {
|
6
|
+
if(string == NULL) {
|
7
|
+
msgpack_pack_nil(packer);
|
8
|
+
} else {
|
9
|
+
int length = strlen(string);
|
10
|
+
msgpack_pack_raw(packer, length);
|
11
|
+
msgpack_pack_raw_body(packer, string, length);
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
static void pack_timestamp(msgpack_packer *packer) {
|
16
|
+
struct timeval tv;
|
17
|
+
gettimeofday(&tv, NULL);
|
18
|
+
|
19
|
+
double time_in_milliseconds = (tv.tv_sec)*1000 + (tv.tv_usec)/1000;
|
20
|
+
msgpack_pack_double(packer, time_in_milliseconds);
|
21
|
+
}
|
22
|
+
|
23
|
+
static void pack_event_header(msgpack_packer* packer, rbkit_event_type event_type)
|
24
|
+
{
|
25
|
+
msgpack_pack_int(packer, rbkit_message_field_event_type);
|
26
|
+
msgpack_pack_int(packer, event_type);
|
27
|
+
|
28
|
+
msgpack_pack_int(packer, rbkit_message_field_timestamp);
|
29
|
+
pack_timestamp(packer);
|
30
|
+
}
|
31
|
+
|
32
|
+
static unsigned long message_counter = 0;
|
33
|
+
|
34
|
+
static unsigned long get_message_counter() {
|
35
|
+
return message_counter++;
|
36
|
+
}
|
37
|
+
|
38
|
+
static void pack_obj_created_event(rbkit_obj_created_event *event, msgpack_packer *packer) {
|
39
|
+
msgpack_pack_map(packer, 3);
|
40
|
+
pack_event_header(packer, event->event_header.event_type);
|
41
|
+
|
42
|
+
msgpack_pack_int(packer, rbkit_message_field_payload);
|
43
|
+
msgpack_pack_map(packer, 2);
|
44
|
+
msgpack_pack_int(packer, rbkit_message_field_object_id);
|
45
|
+
msgpack_pack_unsigned_long_long(packer, event->object_id);
|
46
|
+
msgpack_pack_int(packer, rbkit_message_field_class_name);
|
47
|
+
pack_string(packer, event->klass);
|
48
|
+
//TODO: pack allocation info as well
|
49
|
+
}
|
50
|
+
|
51
|
+
static void pack_obj_destroyed_event(rbkit_obj_destroyed_event *event, msgpack_packer *packer) {
|
52
|
+
msgpack_pack_map(packer, 3);
|
53
|
+
pack_event_header(packer, event->event_header.event_type);
|
54
|
+
|
55
|
+
msgpack_pack_int(packer, rbkit_message_field_payload);
|
56
|
+
msgpack_pack_map(packer, 1);
|
57
|
+
msgpack_pack_int(packer, rbkit_message_field_object_id);
|
58
|
+
msgpack_pack_unsigned_long_long(packer, event->object_id);
|
59
|
+
}
|
60
|
+
|
61
|
+
static void pack_event_header_only(rbkit_event_header *event_header, msgpack_packer *packer) {
|
62
|
+
msgpack_pack_map(packer, 2);
|
63
|
+
pack_event_header(packer, event_header->event_type);
|
64
|
+
}
|
65
|
+
|
66
|
+
static void pack_value_object(msgpack_packer *packer, VALUE value) {
|
67
|
+
switch (TYPE(value)) {
|
68
|
+
case T_FIXNUM:
|
69
|
+
msgpack_pack_long(packer, FIX2LONG(value));
|
70
|
+
break;
|
71
|
+
case T_FLOAT:
|
72
|
+
msgpack_pack_double(packer, rb_num2dbl(value));
|
73
|
+
break;
|
74
|
+
default:
|
75
|
+
;
|
76
|
+
VALUE rubyString = rb_funcall(value, rb_intern("to_s"), 0, 0);
|
77
|
+
char *keyString = StringValueCStr(rubyString);
|
78
|
+
pack_string(packer, keyString);
|
79
|
+
break;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
static int hash_pack_iterator(VALUE key, VALUE value, VALUE hash_arg) {
|
84
|
+
msgpack_packer *packer = (msgpack_packer *)hash_arg;
|
85
|
+
|
86
|
+
// pack the key
|
87
|
+
pack_value_object(packer,key);
|
88
|
+
// pack the value
|
89
|
+
pack_value_object(packer, value);
|
90
|
+
return ST_CONTINUE;
|
91
|
+
}
|
92
|
+
|
93
|
+
static void pack_hash_event(rbkit_hash_event *event, msgpack_packer *packer) {
|
94
|
+
msgpack_pack_map(packer, 3);
|
95
|
+
pack_event_header(packer, event->event_header.event_type);
|
96
|
+
VALUE hash = event->hash;
|
97
|
+
int size = RHASH_SIZE(hash);
|
98
|
+
msgpack_pack_int(packer, rbkit_message_field_payload);
|
99
|
+
msgpack_pack_map(packer, size);
|
100
|
+
rb_hash_foreach(hash, hash_pack_iterator, (VALUE)packer);
|
101
|
+
}
|
102
|
+
|
103
|
+
static void pack_object_space_dump_event(rbkit_object_space_dump_event *event, msgpack_packer *packer) {
|
104
|
+
rbkit_object_dump *dump = event->dump;
|
105
|
+
msgpack_pack_map(packer, 3);
|
106
|
+
pack_event_header(packer, event->event_header.event_type);
|
107
|
+
msgpack_pack_int(packer, rbkit_message_field_payload);
|
108
|
+
// Set size of array to hold all objects
|
109
|
+
msgpack_pack_array(packer, dump->object_count);
|
110
|
+
|
111
|
+
// Iterate through all object data
|
112
|
+
rbkit_object_dump_page * page = dump->first ;
|
113
|
+
while(page != NULL) {
|
114
|
+
rbkit_object_data *data;
|
115
|
+
size_t i = 0;
|
116
|
+
for(;i < page->count; i++) {
|
117
|
+
data = &(page->data[i]);
|
118
|
+
/* Object dump is a map that looks like this :
|
119
|
+
* {
|
120
|
+
* object_id: <OBJECT_ID_IN_HEX>,
|
121
|
+
* class: <CLASS_NAME>,
|
122
|
+
* references: [<OBJECT_ID_IN_HEX>, <OBJECT_ID_IN_HEX>, ...],
|
123
|
+
* file: <FILE_PATH>,
|
124
|
+
* line: <LINE_NO>,
|
125
|
+
* size: <SIZE>
|
126
|
+
* }
|
127
|
+
*/
|
128
|
+
|
129
|
+
msgpack_pack_map(packer, 6);
|
130
|
+
|
131
|
+
// Key1 : rbkit_message_field_object_id
|
132
|
+
msgpack_pack_int(packer, rbkit_message_field_object_id);
|
133
|
+
|
134
|
+
// Value1 : pointer address of object
|
135
|
+
msgpack_pack_unsigned_long_long(packer, data->object_id);
|
136
|
+
|
137
|
+
// Key2 : rbkit_message_field_class_name
|
138
|
+
msgpack_pack_int(packer, rbkit_message_field_class_name);
|
139
|
+
|
140
|
+
// Value2 : Class name of object
|
141
|
+
pack_string(packer, data->class_name);
|
142
|
+
|
143
|
+
// Key3 : rbkit_message_field_references
|
144
|
+
msgpack_pack_int(packer, rbkit_message_field_references);
|
145
|
+
|
146
|
+
// Value3 : References held by the object
|
147
|
+
msgpack_pack_array(packer, data->reference_count);
|
148
|
+
if(data->reference_count != 0) {
|
149
|
+
size_t count = 0;
|
150
|
+
for(; count < data->reference_count; count++ )
|
151
|
+
msgpack_pack_unsigned_long_long(packer, data->references[count]);
|
152
|
+
free(data->references);
|
153
|
+
}
|
154
|
+
|
155
|
+
// Key4 : rbkit_message_field_file
|
156
|
+
msgpack_pack_int(packer, rbkit_message_field_file);
|
157
|
+
|
158
|
+
// Value4 : File path where object is defined
|
159
|
+
pack_string(packer, data->file);
|
160
|
+
|
161
|
+
// Key5 : rbkit_message_field_line
|
162
|
+
msgpack_pack_int(packer, rbkit_message_field_line);
|
163
|
+
|
164
|
+
// Value5 : Line no where object is defined
|
165
|
+
if(data->line == 0)
|
166
|
+
msgpack_pack_nil(packer);
|
167
|
+
else
|
168
|
+
msgpack_pack_unsigned_long(packer, data->line);
|
169
|
+
|
170
|
+
// Key6 : rbkit_message_field_size
|
171
|
+
msgpack_pack_int(packer, rbkit_message_field_size);
|
172
|
+
|
173
|
+
// Value6 : Size of the object in memory
|
174
|
+
if(data->size == 0)
|
175
|
+
msgpack_pack_nil(packer);
|
176
|
+
else
|
177
|
+
msgpack_pack_uint32(packer, data->size);
|
178
|
+
}
|
179
|
+
rbkit_object_dump_page * prev = page;
|
180
|
+
page = page->next;
|
181
|
+
free(prev);
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
185
|
+
static void pack_event_collection_event(rbkit_event_collection_event *event, msgpack_packer *packer) {
|
186
|
+
msgpack_sbuffer *sbuf = packer->data;
|
187
|
+
msgpack_pack_map(packer, 4);
|
188
|
+
pack_event_header(packer, event->event_header.event_type);
|
189
|
+
msgpack_pack_int(packer, rbkit_message_field_message_counter);
|
190
|
+
msgpack_pack_unsigned_long(packer, get_message_counter());
|
191
|
+
msgpack_pack_int(packer, rbkit_message_field_payload);
|
192
|
+
msgpack_pack_array(packer, event->message_count);
|
193
|
+
sbuf->data = realloc(sbuf->data, event->buffer_size + sbuf->size);
|
194
|
+
memcpy(sbuf->data + sbuf->size, event->buffer, event->buffer_size);
|
195
|
+
sbuf->size += event->buffer_size;
|
196
|
+
}
|
197
|
+
|
198
|
+
void pack_event(rbkit_event_header *event_header, msgpack_packer *packer) {
|
199
|
+
msgpack_sbuffer *sbuf = packer->data;
|
200
|
+
msgpack_sbuffer_clear(sbuf);
|
201
|
+
|
202
|
+
switch (event_header->event_type) {
|
203
|
+
case obj_created:
|
204
|
+
pack_obj_created_event((rbkit_obj_created_event *)event_header, packer);
|
205
|
+
break;
|
206
|
+
case obj_destroyed:
|
207
|
+
pack_obj_destroyed_event((rbkit_obj_destroyed_event *)event_header, packer);
|
208
|
+
break;
|
209
|
+
case gc_start:
|
210
|
+
pack_event_header_only(event_header, packer);
|
211
|
+
break;
|
212
|
+
case gc_end_m:
|
213
|
+
pack_event_header_only(event_header, packer);
|
214
|
+
break;
|
215
|
+
case gc_end_s:
|
216
|
+
pack_event_header_only(event_header, packer);
|
217
|
+
break;
|
218
|
+
case object_space_dump:
|
219
|
+
pack_object_space_dump_event((rbkit_object_space_dump_event *)event_header, packer);
|
220
|
+
break;
|
221
|
+
case gc_stats:
|
222
|
+
pack_hash_event((rbkit_hash_event *)event_header, packer);
|
223
|
+
break;
|
224
|
+
case handshake:
|
225
|
+
pack_hash_event((rbkit_hash_event *)event_header, packer);
|
226
|
+
break;
|
227
|
+
case event_collection:
|
228
|
+
pack_event_collection_event((rbkit_event_collection_event *)event_header, packer);
|
229
|
+
break;
|
230
|
+
default:
|
231
|
+
rb_raise(rb_eNotImpError,
|
232
|
+
"Rbkit : Unpacking of event type '%u' not implemented",
|
233
|
+
event_header->event_type);
|
234
|
+
}
|
235
|
+
}
|
236
|
+
|
237
|
+
VALUE rbkit_message_fields_as_hash() {
|
238
|
+
VALUE events = rb_hash_new();
|
239
|
+
rb_hash_aset(events, ID2SYM(rb_intern("event_type")), INT2FIX(rbkit_message_field_event_type));
|
240
|
+
rb_hash_aset(events, ID2SYM(rb_intern("timestamp")), INT2FIX(rbkit_message_field_timestamp));
|
241
|
+
rb_hash_aset(events, ID2SYM(rb_intern("payload")), INT2FIX(rbkit_message_field_payload));
|
242
|
+
rb_hash_aset(events, ID2SYM(rb_intern("object_id")), INT2FIX(rbkit_message_field_object_id));
|
243
|
+
rb_hash_aset(events, ID2SYM(rb_intern("class_name")), INT2FIX(rbkit_message_field_class_name));
|
244
|
+
rb_hash_aset(events, ID2SYM(rb_intern("references")), INT2FIX(rbkit_message_field_references));
|
245
|
+
rb_hash_aset(events, ID2SYM(rb_intern("file")), INT2FIX(rbkit_message_field_file));
|
246
|
+
rb_hash_aset(events, ID2SYM(rb_intern("line")), INT2FIX(rbkit_message_field_line));
|
247
|
+
rb_hash_aset(events, ID2SYM(rb_intern("size")), INT2FIX(rbkit_message_field_size));
|
248
|
+
rb_hash_aset(events, ID2SYM(rb_intern("message_counter")), INT2FIX(rbkit_message_field_message_counter));
|
249
|
+
OBJ_FREEZE(events);
|
250
|
+
return events;
|
251
|
+
}
|