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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +17 -0
  5. data/CHANGELOG.md +5 -0
  6. data/Gemfile +6 -2
  7. data/LICENSE.txt +22 -0
  8. data/README.md +74 -11
  9. data/Rakefile +27 -3
  10. data/docs/EVENT_FORMAT.md +195 -0
  11. data/experiments/object_dump.rb +1 -1
  12. data/experiments/rbkit_command_test.rb +3 -1
  13. data/experiments/using_rbkit.rb +1 -1
  14. data/ext/extconf.rb +95 -12
  15. data/ext/rbkit_allocation_info.c +91 -0
  16. data/ext/rbkit_allocation_info.h +17 -0
  17. data/ext/rbkit_event.c +71 -0
  18. data/ext/rbkit_event.h +63 -0
  19. data/ext/rbkit_event_packer.c +251 -0
  20. data/ext/rbkit_event_packer.h +23 -0
  21. data/ext/rbkit_message_aggregator.c +9 -16
  22. data/ext/rbkit_message_aggregator.h +0 -1
  23. data/ext/rbkit_object_graph.c +6 -49
  24. data/ext/rbkit_object_graph.h +12 -3
  25. data/ext/rbkit_test_helper.c +25 -0
  26. data/ext/rbkit_test_helper.h +1 -0
  27. data/ext/rbkit_tracer.c +106 -323
  28. data/ext/rbkit_tracer.h +2 -10
  29. data/lib/rbkit.rb +57 -35
  30. data/lib/rbkit/rbkit_gc.rb +79 -0
  31. data/lib/rbkit/version.rb +1 -1
  32. data/logo.png +0 -0
  33. data/rbkit.gemspec +1 -0
  34. data/setup.rb +37 -0
  35. data/spec/gc_stat_spec.rb +31 -0
  36. data/spec/hash_event_spec.rb +29 -0
  37. data/spec/obj_created_spec.rb +52 -0
  38. data/spec/obj_destroyed_spec.rb +44 -0
  39. data/spec/object_space_dump_spec.rb +77 -0
  40. data/spec/rbkit_helpful_messages_spec.rb +61 -0
  41. data/spec/spec_helper.rb +11 -6
  42. data/spec/start_server_spec.rb +29 -0
  43. data/spec/status_spec.rb +48 -0
  44. data/spec/support/foo_bar_sample_class.rb +24 -0
  45. data/spec/support/have_message_matcher.rb +26 -0
  46. metadata +40 -4
  47. data/schema/tracing_info.md +0 -8
@@ -3,7 +3,7 @@ $:<< File.join(File.dirname(__FILE__), "../ext")
3
3
 
4
4
  require 'rbkit'
5
5
 
6
- Rbkit.start_profiling(5555)
6
+ Rbkit.start_profiling
7
7
 
8
8
  class Foo
9
9
  def initialize(name)
@@ -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
@@ -3,7 +3,7 @@ $:<< File.join(File.dirname(__FILE__), "../ext")
3
3
 
4
4
  require 'rbkit'
5
5
 
6
- Rbkit.start_profiling(5555)
6
+ Rbkit.start_profiling
7
7
 
8
8
  class Foo
9
9
  def initialize(name)
@@ -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
- $stderr.puts "Dev environment enabled."
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
- if(have_func('rb_postponed_job_register_one') &&
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
- have_library("zmq") &&
12
- have_header("zmq.h") &&
13
- have_library("msgpack") &&
14
- have_header("msgpack.h"))
15
- create_makefile('rbkit_tracer')
16
- else
17
- fail 'missing API: are you using ruby 2.1+?'
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
@@ -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
+ }
@@ -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
+ }