rbkit 0.0.1 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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
+ }