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
@@ -0,0 +1,23 @@
1
+ #ifndef RBKIT_MESSAGE_PACKER
2
+ #define RBKIT_MESSAGE_PACKER
3
+ #include "msgpack.h"
4
+ #include "rbkit_event.h"
5
+
6
+ typedef enum _rbkit_message_fields {
7
+ rbkit_message_field_event_type,
8
+ rbkit_message_field_timestamp,
9
+ rbkit_message_field_payload,
10
+ rbkit_message_field_object_id,
11
+ rbkit_message_field_class_name,
12
+ rbkit_message_field_references,
13
+ rbkit_message_field_file,
14
+ rbkit_message_field_line,
15
+ rbkit_message_field_size,
16
+ rbkit_message_field_message_counter
17
+ } rbkit_message_fields;
18
+
19
+ VALUE rbkit_message_fields_as_hash();
20
+
21
+ void pack_event(rbkit_event_header *event_header, msgpack_packer *packer);
22
+
23
+ #endif
@@ -1,8 +1,6 @@
1
- #include <assert.h>
2
- #include "zmq.h"
3
1
  #include "rbkit_message_aggregator.h"
2
+ #include "rbkit_event_packer.h"
4
3
 
5
- static msgpack_sbuffer * sbuf;
6
4
  static void* message_array;
7
5
  static size_t used_memsize;
8
6
  static size_t total_capacity;
@@ -15,7 +13,6 @@ static int has_enough_space_for(size_t size) {
15
13
  static void double_the_capacity() {
16
14
  total_capacity *= 2;
17
15
  message_array = realloc(message_array, total_capacity);
18
- assert(message_array);
19
16
  }
20
17
 
21
18
  void message_list_new() {
@@ -51,16 +48,12 @@ void add_message(msgpack_sbuffer *buffer) {
51
48
  // Creates a message containing all the available
52
49
  // msgpack sbuffers in the array
53
50
  void get_event_collection_message(msgpack_sbuffer *sbuf) {
54
- if(no_of_messages > 0) {
55
- msgpack_packer *pk = msgpack_packer_new(sbuf, msgpack_sbuffer_write);
56
- pack_event_header(pk, "event_collection", 3);
57
- pack_string(pk, "payload");
58
- msgpack_pack_array(pk, no_of_messages);
59
- sbuf->data = realloc(sbuf->data, used_memsize + sbuf->size);
60
- assert(sbuf->data);
61
- memcpy(sbuf->data + sbuf->size, message_array, used_memsize);
62
- sbuf->size += used_memsize;
63
-
64
- msgpack_packer_free(pk);
65
- }
51
+ if(no_of_messages == 0)
52
+ return;
53
+
54
+ rbkit_event_collection_event *event = new_rbkit_event_collection_event(message_array, used_memsize, no_of_messages);
55
+ msgpack_packer* pk = msgpack_packer_new(sbuf, msgpack_sbuffer_write);
56
+ pack_event((rbkit_event_header *)event, pk);
57
+ free(event);
58
+ msgpack_packer_free(pk);
66
59
  }
@@ -2,7 +2,6 @@
2
2
  #define RBKIT_MESSAGE_AGGREGATOR_H
3
3
 
4
4
  #include "msgpack.h"
5
- #include "zmq.h"
6
5
 
7
6
  void message_list_new();
8
7
  void add_message(msgpack_sbuffer *);
@@ -37,48 +37,19 @@ static void set_size(VALUE obj, rbkit_object_data * data) {
37
37
  data->size = size;
38
38
  }
39
39
 
40
- static void dump_root_object(VALUE obj, const char* category, rbkit_object_dump *dump) {
41
- rbkit_object_data *data = initialize_object_data(dump);
42
-
43
- //Set object id
44
- data->object_id = (void *)obj;
45
- //Set classname
46
- data->class_name = NULL;
47
- //Set classname of "symbols" category as "Symbol" to match <symbol>.class output
48
- if(strcmp(category, "symbols") == 0){
49
- data->class_name = "Symbol" ;
50
- } else {
51
- data->class_name = category ;
52
- }
53
-
54
- //Set file path and line no where object is defined
55
- struct allocation_info *info;
56
- if (st_lookup(dump->object_table, obj, (st_data_t *)&info)) {
57
- if(info) {
58
- data->file = info->path;
59
- data->line = info->line;
60
- }
61
- }
62
-
63
- set_size(obj, data);
64
- // Update total number of objects
65
- dump->object_count++;
66
- // Update number of objects on last page
67
- dump->last->count++;
68
- }
69
-
70
- static void reachable_object_i(VALUE ref, rbkit_object_data *data)
40
+ static void reachable_object_i(VALUE ref, void *arg)
71
41
  {
42
+ rbkit_object_data *data = (rbkit_object_data *)arg;
72
43
  if(RBASIC_CLASS(ref) == ref)
73
44
  return;
74
45
 
75
46
  data->reference_count ++;
76
47
  if (data->reference_count == 1) {
77
- data->references = malloc(sizeof(void *));
48
+ data->references = malloc(sizeof(unsigned long long));
78
49
  } else {
79
- data->references = realloc(data->references, data->reference_count * sizeof(void *) );
50
+ data->references = realloc(data->references, data->reference_count * sizeof(unsigned long long) );
80
51
  }
81
- data->references[data->reference_count - 1] = (void *)ref;
52
+ data->references[data->reference_count - 1] = FIX2ULONG(rb_obj_id(ref));
82
53
  }
83
54
 
84
55
  static void dump_heap_object(VALUE obj, rbkit_object_dump *dump) {
@@ -86,7 +57,7 @@ static void dump_heap_object(VALUE obj, rbkit_object_dump *dump) {
86
57
  // Get next available slot from page
87
58
  rbkit_object_data *data = initialize_object_data(dump);
88
59
  //Set object id
89
- data->object_id = (void *)obj;
60
+ data->object_id = FIX2ULONG(rb_obj_id(obj));
90
61
 
91
62
  //Set classname
92
63
  VALUE klass = RBASIC_CLASS(obj);
@@ -109,15 +80,6 @@ static void dump_heap_object(VALUE obj, rbkit_object_dump *dump) {
109
80
  dump->last->count++;
110
81
  }
111
82
 
112
- /*
113
- * The following categories of objects are directly accessible from the root:
114
- * ["vm", "machine_context", "symbols", "global_list", "end_proc", "global_tbl"]
115
- */
116
- static void root_object_i(const char *category, VALUE obj, void *dump_data)
117
- {
118
- dump_root_object(obj, category, (rbkit_object_dump *)dump_data);
119
- }
120
-
121
83
  /*
122
84
  * Iterator that walks over heap pages
123
85
  */
@@ -135,10 +97,6 @@ static int heap_obj_i(void *vstart, void *vend, size_t stride, void *dump_data)
135
97
  return 0;
136
98
  }
137
99
 
138
- static void collect_root_objects(rbkit_object_dump * dump) {
139
- rb_objspace_reachable_objects_from_root(root_object_i, (void *)dump);
140
- }
141
-
142
100
  static void collect_heap_objects(rbkit_object_dump * dump) {
143
101
  rb_objspace_each_objects(heap_obj_i, (void *)dump);
144
102
  }
@@ -148,7 +106,6 @@ rbkit_object_dump * get_object_dump(st_table * object_table) {
148
106
  dump->object_table = object_table;
149
107
  dump->first = NULL;
150
108
  dump->last = NULL;
151
- collect_root_objects(dump);
152
109
  collect_heap_objects(dump);
153
110
  return dump;
154
111
  }
@@ -1,14 +1,15 @@
1
1
  #ifndef RBKIT_OBJECT_GRAPH
2
2
  #define RBKIT_OBJECT_GRAPH
3
+ #include <ruby.h>
3
4
 
4
5
  #define RBKIT_OBJECT_DUMP_PAGE_SIZE 1000
5
6
 
6
7
  typedef struct _rbkit_object_data {
7
- const void * object_id;
8
+ unsigned long long object_id;
8
9
  const char * class_name;
9
- void ** references;
10
+ unsigned long long * references;
10
11
  size_t reference_count;
11
- char * file;
12
+ const char * file;
12
13
  unsigned long line;
13
14
  size_t size;
14
15
  } rbkit_object_data;
@@ -36,4 +37,12 @@ struct allocation_info {
36
37
  VALUE method_id;
37
38
  size_t generation;
38
39
  };
40
+
41
+ // Declarations of ruby internals to silence warnings
42
+ void rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *data);
43
+ void rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE, void *), void *data);
44
+ size_t rb_obj_memsize_of(VALUE);
45
+ void rb_objspace_each_objects(
46
+ int (*callback)(void *start, void *end, size_t stride, void *data),
47
+ void *data);
39
48
  #endif
@@ -0,0 +1,25 @@
1
+ #include <ruby.h>
2
+ #include "rbkit_message_aggregator.h"
3
+
4
+ static VALUE noop_send_messages() {
5
+ //NOOP
6
+ return Qnil;
7
+ }
8
+
9
+ static VALUE get_queued_messages() {
10
+ msgpack_sbuffer * sbuf = msgpack_sbuffer_new();
11
+ get_event_collection_message(sbuf);
12
+ if(sbuf && sbuf->size > 0) {
13
+ VALUE str = rb_str_new(sbuf->data, sbuf->size);
14
+ message_list_clear();
15
+ msgpack_sbuffer_destroy(sbuf);
16
+ return str;
17
+ }
18
+ return Qnil;
19
+ }
20
+
21
+ void Init_rbkit_test_helper(void) {
22
+ VALUE rbkit_module = rb_define_module("Rbkit");
23
+ rb_define_module_function(rbkit_module, "send_messages", noop_send_messages, 0);
24
+ rb_define_module_function(rbkit_module, "get_queued_messages", get_queued_messages, 0);
25
+ }
@@ -0,0 +1 @@
1
+ void Init_rbkit_test_helper();
@@ -7,8 +7,12 @@
7
7
  //
8
8
 
9
9
  #include "rbkit_tracer.h"
10
+ #include "rbkit_allocation_info.h"
11
+ #include "rbkit_event.h"
12
+ #include "rbkit_event_packer.h"
10
13
  #include "rbkit_object_graph.h"
11
14
  #include "rbkit_message_aggregator.h"
15
+ #include "rbkit_test_helper.h"
12
16
  #include <sys/time.h>
13
17
 
14
18
  static const char *event_names[] = {
@@ -19,51 +23,22 @@ static const char *event_names[] = {
19
23
  "obj_destroyed"
20
24
  };
21
25
 
22
- static struct gc_hooks *logger;
23
- static int tmp_keep_remains;
26
+ static rbkit_logger *logger;
24
27
  static void *zmq_publisher;
25
28
  static void *zmq_context;
26
29
  static void *zmq_response_socket;
27
30
  static zmq_pollitem_t items[1];
28
31
 
29
- void pack_event_header(msgpack_packer* packer, const char *event_type, int map_size)
30
- {
31
- msgpack_pack_map(packer, map_size);
32
- pack_string(packer, "event_type");
33
- pack_string(packer, event_type);
34
-
35
- pack_string(packer, "timestamp");
36
- pack_timestamp(packer);
37
- }
38
-
39
-
40
- static void trace_gc_invocation(void *data, int event_index) {
41
- if (event_index == 0) {
42
- msgpack_sbuffer_clear(logger->sbuf);
43
- pack_event_header(logger->msgpacker, event_names[event_index], 2);
44
- add_message(logger->sbuf);
45
- } else if (event_index == 2) {
46
- msgpack_sbuffer_clear(logger->sbuf);
47
- pack_event_header(logger->msgpacker, event_names[event_index], 2);
48
- add_message(logger->sbuf);
49
- }
50
- }
51
-
52
- static struct gc_hooks * get_trace_logger() {
32
+ static rbkit_logger * get_trace_logger() {
53
33
  int i = 0;
54
34
  if (logger == 0) {
55
- logger = ALLOC_N(struct gc_hooks, 1);
35
+ logger = ALLOC_N(rbkit_logger, 1);
56
36
  logger->enabled = Qfalse;
57
37
  logger->newobj_trace = 0;
58
38
  logger->freeobj_trace = 0;
59
- logger->keep_remains = tmp_keep_remains;
60
39
  logger->object_table = st_init_numtable();
61
40
  logger->str_table = st_init_strtable();
62
41
 
63
- for (i = 0; i < 3; i++) {
64
- logger->funcs[i] = trace_gc_invocation;
65
- logger->args[i] = (void *)event_names[i];
66
- }
67
42
  logger->sbuf = msgpack_sbuffer_new();
68
43
  logger->msgpacker = msgpack_packer_new(logger->sbuf, msgpack_sbuffer_write);
69
44
  logger->data = 0;
@@ -71,26 +46,37 @@ static struct gc_hooks * get_trace_logger() {
71
46
  return logger;
72
47
  }
73
48
 
74
-
75
49
  static void
76
50
  gc_start_i(VALUE tpval, void *data)
77
51
  {
78
- struct gc_hooks *hooks = (struct gc_hooks *)data;
79
- (*hooks->funcs[0])(hooks->args[0], 0);
52
+ rbkit_logger * arg = (rbkit_logger *)data;
53
+ rbkit_event_header *event = malloc(sizeof(rbkit_event_header));
54
+ event->event_type = gc_start;
55
+ pack_event(event, arg->msgpacker);
56
+ free(event);
57
+ add_message(arg->sbuf);
80
58
  }
81
59
 
82
60
  static void
83
61
  gc_end_mark_i(VALUE tpval, void *data)
84
62
  {
85
- struct gc_hooks *hooks = (struct gc_hooks *)data;
86
- (*hooks->funcs[1])(hooks->args[1], 1);
63
+ rbkit_logger * arg = (rbkit_logger *)data;
64
+ rbkit_event_header *event = malloc(sizeof(rbkit_event_header));
65
+ event->event_type = gc_end_m;
66
+ pack_event(event, arg->msgpacker);
67
+ free(event);
68
+ add_message(arg->sbuf);
87
69
  }
88
70
 
89
71
  static void
90
72
  gc_end_sweep_i(VALUE tpval, void *data)
91
73
  {
92
- struct gc_hooks *hooks = (struct gc_hooks *)data;
93
- (*hooks->funcs[2])(hooks->args[2], 2);
74
+ rbkit_logger * arg = (rbkit_logger *)data;
75
+ rbkit_event_header *event = malloc(sizeof(rbkit_event_header));
76
+ event->event_type = gc_end_s;
77
+ pack_event(event, arg->msgpacker);
78
+ free(event);
79
+ add_message(arg->sbuf);
94
80
  }
95
81
 
96
82
  static void
@@ -107,106 +93,21 @@ create_gc_hooks(void)
107
93
  for (i=0; i<3; i++) rb_gc_register_mark_object(logger->hooks[i]);
108
94
  }
109
95
 
110
- void pack_pointer(msgpack_packer *packer, VALUE object_id) {
111
- char *object_string;
112
- asprintf(&object_string, "%p", object_id);
113
- pack_string(packer, object_string);
114
- free(object_string);
115
- }
116
- /*
117
- * make_unique_str helps to reuse memory by allocating memory for a string
118
- * only once and keeping track of how many times that string is referenced.
119
- * It does so by creating a map of strings to their no of references.
120
- * A new map is created for a string on its first use, and for further usages
121
- * the reference count is incremented.
122
- */
123
- static const char * make_unique_str(st_table *tbl, const char *str, long len) {
124
- if (!str) {
125
- return NULL;
126
- }
127
- else {
128
- st_data_t n;
129
- char *result;
130
-
131
- if (st_lookup(tbl, (st_data_t)str, &n)) {
132
- st_insert(tbl, (st_data_t)str, n+1);
133
- st_get_key(tbl, (st_data_t)str, (st_data_t *)&result);
134
- }
135
- else {
136
- result = (char *)ruby_xmalloc(len+1);
137
- strncpy(result, str, len);
138
- result[len] = 0;
139
- st_add_direct(tbl, (st_data_t)result, 1);
140
- }
141
- return result;
142
- }
143
- }
144
-
145
- /*
146
- * Used to free allocation of string when it's not referenced anymore.
147
- * Decrements the reference count of a string if it's still used, else
148
- * the map is removed completely.
149
- */
150
- static void delete_unique_str(st_table *tbl, const char *str) {
151
- if (str) {
152
- st_data_t n;
153
-
154
- st_lookup(tbl, (st_data_t)str, &n);
155
- if (n == 1) {
156
- st_delete(tbl, (st_data_t *)&str, 0);
157
- ruby_xfree((char *)str);
158
- }
159
- else {
160
- st_insert(tbl, (st_data_t)str, n-1);
161
- }
162
- }
163
- }
164
-
165
96
  // Refer Ruby source ext/objspace/object_tracing.c::newobj_i
166
97
  static void newobj_i(VALUE tpval, void *data) {
167
- struct gc_hooks * arg = (struct gc_hooks *)data;
98
+ rbkit_logger * arg = (rbkit_logger *)data;
168
99
  rb_trace_arg_t *tparg = rb_tracearg_from_tracepoint(tpval);
100
+ rbkit_allocation_info *info = new_rbkit_allocation_info(tparg, arg->str_table, arg->object_table);
101
+
169
102
  VALUE obj = rb_tracearg_object(tparg);
170
103
  VALUE klass = RBASIC_CLASS(obj);
171
- VALUE path = rb_tracearg_path(tparg);
172
- VALUE line = rb_tracearg_lineno(tparg);
173
- VALUE method_id = rb_tracearg_method_id(tparg);
174
- VALUE defined_klass = rb_tracearg_defined_class(tparg);
175
-
176
- struct allocation_info *info;
177
- const char *path_cstr = RTEST(path) ? make_unique_str(arg->str_table, RSTRING_PTR(path), RSTRING_LEN(path)) : 0;
178
- VALUE class_path = (RTEST(defined_klass) && !OBJ_FROZEN(defined_klass)) ? rb_class_path_cached(defined_klass) : Qnil;
179
- const char *class_path_cstr = RTEST(class_path) ? make_unique_str(arg->str_table, RSTRING_PTR(class_path), RSTRING_LEN(class_path)) : 0;
180
-
181
- if (st_lookup(arg->object_table, (st_data_t)obj, (st_data_t *)&info)) {
182
- /* reuse info */
183
- delete_unique_str(arg->str_table, info->path);
184
- delete_unique_str(arg->str_table, info->class_path);
185
- }
186
- else {
187
- info = (struct allocation_info *)ruby_xmalloc(sizeof(struct allocation_info));
188
- }
104
+ const char *class_name = NULL;
105
+ if (!NIL_P(klass) && BUILTIN_TYPE(obj) != T_NONE && BUILTIN_TYPE(obj) != T_ZOMBIE && BUILTIN_TYPE(obj) != T_ICLASS)
106
+ class_name = rb_class2name(klass);
189
107
 
190
- info->path = path_cstr;
191
- info->line = NUM2INT(line);
192
- info->method_id = method_id;
193
- info->class_path = class_path_cstr;
194
- info->generation = rb_gc_count();
195
- st_insert(arg->object_table, (st_data_t)obj, (st_data_t)info);
196
-
197
- msgpack_sbuffer_clear(arg->sbuf);
198
- pack_event_header(arg->msgpacker, event_names[3], 3);
199
- pack_string(arg->msgpacker, "payload");
200
- msgpack_pack_map(arg->msgpacker, 2);
201
- pack_string(arg->msgpacker, "object_id");
202
- pack_pointer(arg->msgpacker, obj);
203
- pack_string(arg->msgpacker, "class");
204
- if (!NIL_P(klass) && BUILTIN_TYPE(obj) != T_NONE && BUILTIN_TYPE(obj) != T_ZOMBIE && BUILTIN_TYPE(obj) != T_ICLASS) {
205
- pack_string(arg->msgpacker, rb_class2name(klass));
206
-
207
- } else {
208
- msgpack_pack_nil(arg->msgpacker);
209
- }
108
+ rbkit_obj_created_event *event = new_rbkit_obj_created_event(FIX2ULONG(rb_obj_id(obj)), class_name, info);
109
+ pack_event((rbkit_event_header *)event, arg->msgpacker);
110
+ free(event);
210
111
  add_message(arg->sbuf);
211
112
  }
212
113
 
@@ -214,45 +115,38 @@ static void newobj_i(VALUE tpval, void *data) {
214
115
  static void freeobj_i(VALUE tpval, void *data) {
215
116
  rb_trace_arg_t *tparg = rb_tracearg_from_tracepoint(tpval);
216
117
  VALUE obj = rb_tracearg_object(tparg);
118
+ rbkit_logger *arg = (rbkit_logger *)data;
217
119
 
218
- struct gc_hooks *arg = (struct gc_hooks *)data;
219
- struct allocation_info *info;
120
+ // Delete allocation info of freed object
121
+ delete_rbkit_allocation_info(tparg, obj, arg->str_table, arg->object_table);
220
122
 
221
- if (st_lookup(arg->object_table, (st_data_t)obj, (st_data_t *)&info)) {
222
- st_delete(arg->object_table, (st_data_t *)&obj, (st_data_t *)&info);
223
- delete_unique_str(arg->str_table, info->path);
224
- delete_unique_str(arg->str_table, info->class_path);
225
- ruby_xfree(info);
226
- }
227
-
228
- msgpack_sbuffer_clear(logger->sbuf);
229
- pack_event_header(logger->msgpacker, event_names[4], 3);
230
- pack_string(logger->msgpacker, "payload");
231
- msgpack_pack_map(logger->msgpacker, 1);
232
- pack_string(logger->msgpacker, "object_id");
233
- pack_pointer(logger->msgpacker, obj);
234
- add_message(logger->sbuf);
123
+ rbkit_obj_destroyed_event *event = new_rbkit_obj_destroyed_event(FIX2ULONG(rb_obj_id(obj)));
124
+ pack_event((rbkit_event_header *)event, arg->msgpacker);
125
+ free(event);
126
+ add_message(arg->sbuf);
235
127
  }
236
128
 
237
129
  static VALUE start_stat_server(int argc, VALUE *argv, VALUE self) {
238
- int default_pub_port = 5555;
239
- int default_request_port = 5556;
240
130
  VALUE pub_port;
241
131
  VALUE request_port;
242
132
  int bind_result;
243
133
 
244
134
  rb_scan_args(argc, argv, "02", &pub_port, &request_port);
245
- if (!NIL_P(pub_port)) {
246
- default_pub_port = FIX2INT(pub_port);
247
- if (default_pub_port < 1024 || default_pub_port > 65000)
248
- rb_raise(rb_eArgError, "invalid port value");
249
- }
250
135
 
251
- if (!NIL_P(request_port)) {
252
- default_request_port = FIX2INT(request_port);
253
- if(default_request_port < 1024 || default_request_port > 65000)
254
- rb_raise(rb_eArgError, "invalid port value");
255
- }
136
+ char zmq_endpoint[14];
137
+ sprintf(zmq_endpoint, "tcp://*:%d", FIX2INT(pub_port));
138
+ zmq_context = zmq_ctx_new();
139
+ zmq_publisher = zmq_socket(zmq_context, ZMQ_PUB);
140
+ bind_result = zmq_bind(zmq_publisher, zmq_endpoint);
141
+ if(bind_result != 0)
142
+ return Qfalse;
143
+
144
+ char zmq_request_endpoint[14];
145
+ sprintf(zmq_request_endpoint, "tcp://*:%d", FIX2INT(request_port));
146
+ zmq_response_socket = zmq_socket(zmq_context, ZMQ_REP);
147
+ bind_result = zmq_bind(zmq_response_socket, zmq_request_endpoint);
148
+ if(bind_result != 0)
149
+ return Qfalse;
256
150
 
257
151
  // Creates a list which aggregates messages
258
152
  message_list_new();
@@ -263,24 +157,9 @@ static VALUE start_stat_server(int argc, VALUE *argv, VALUE self) {
263
157
  rb_gc_register_mark_object(logger->freeobj_trace);
264
158
  create_gc_hooks();
265
159
 
266
- char zmq_endpoint[14];
267
- sprintf(zmq_endpoint, "tcp://*:%d", default_pub_port);
268
-
269
- zmq_context = zmq_ctx_new();
270
- zmq_publisher = zmq_socket(zmq_context, ZMQ_PUB);
271
- bind_result = zmq_bind(zmq_publisher, zmq_endpoint);
272
- assert(bind_result == 0);
273
-
274
- char zmq_request_endpoint[14];
275
- sprintf(zmq_request_endpoint, "tcp://*:%d", default_request_port);
276
-
277
- zmq_response_socket = zmq_socket(zmq_context, ZMQ_REP);
278
- bind_result = zmq_bind(zmq_response_socket, zmq_request_endpoint);
279
- assert(bind_result == 0);
280
-
281
160
  items[0].socket = zmq_response_socket;
282
161
  items[0].events = ZMQ_POLLIN;
283
- return Qnil;
162
+ return Qtrue;
284
163
  }
285
164
 
286
165
  char * tracer_string_recv(void *socket) {
@@ -304,6 +183,33 @@ int tracer_string_send(void *socket, const char *message) {
304
183
  return size;
305
184
  }
306
185
 
186
+ static VALUE rbkit_status_as_hash() {
187
+ VALUE status = rb_hash_new();
188
+ VALUE pid = rb_funcall(rb_path2class("Process"), rb_intern("pid"), 0, 0);
189
+ VALUE processName = rb_funcall(rb_path2class("Process"), rb_intern("argv0"), 0, 0);
190
+ int object_trace_enabled = (logger && logger->enabled) ? 1 : 0;
191
+ rb_hash_aset(status, ID2SYM(rb_intern("process_name")), processName);
192
+ rb_hash_aset(status, ID2SYM(rb_intern("pwd")), rb_dir_getwd());
193
+ rb_hash_aset(status, ID2SYM(rb_intern("pid")), pid);
194
+ rb_hash_aset(status, ID2SYM(rb_intern("object_trace_enabled")), INT2FIX(object_trace_enabled));
195
+ return status;
196
+ }
197
+
198
+ static void send_handshake_response() {
199
+ msgpack_sbuffer *buffer = msgpack_sbuffer_new();
200
+ msgpack_packer *packer = msgpack_packer_new(buffer, msgpack_sbuffer_write);
201
+
202
+ rbkit_hash_event *event = new_rbkit_hash_event(handshake, rbkit_status_as_hash());
203
+ pack_event((rbkit_event_header *)event, packer);
204
+ free(event);
205
+
206
+ if(buffer && buffer->size > 0)
207
+ zmq_send(zmq_response_socket, buffer->data, buffer->size, 0);
208
+
209
+ msgpack_sbuffer_free(buffer);
210
+ msgpack_packer_free(packer);
211
+ }
212
+
307
213
  static VALUE poll_for_request() {
308
214
  // Wait for 100 millisecond and check if there is a message
309
215
  // we can't wait here indefenitely because ruby is not aware this is a
@@ -312,7 +218,11 @@ static VALUE poll_for_request() {
312
218
  zmq_poll(items, 1, 100);
313
219
  if (items[0].revents && ZMQ_POLLIN) {
314
220
  char *message = tracer_string_recv(zmq_response_socket);
315
- tracer_string_send(zmq_response_socket, "ok");
221
+ if(strcmp(message, "handshake") == 0) {
222
+ send_handshake_response();
223
+ } else {
224
+ tracer_string_send(zmq_response_socket, "ok");
225
+ }
316
226
  VALUE command_ruby_string = rb_str_new_cstr(message);
317
227
  free(message);
318
228
  return command_ruby_string;
@@ -365,70 +275,23 @@ static VALUE stop_stat_server() {
365
275
  zmq_close(zmq_response_socket);
366
276
  zmq_ctx_destroy(zmq_context);
367
277
  free(logger);
278
+ logger = 0;
368
279
  return Qnil;
369
280
  }
370
281
 
371
- void pack_value_object(msgpack_packer *packer, VALUE value) {
372
- switch (TYPE(value)) {
373
- case T_FIXNUM:
374
- msgpack_pack_long(packer, FIX2LONG(value));
375
- break;
376
- case T_FLOAT:
377
- msgpack_pack_double(packer, rb_num2dbl(value));
378
- break;
379
- default:
380
- ;
381
- VALUE rubyString = rb_funcall(value, rb_intern("to_s"), 0, 0);
382
- char *keyString = StringValueCStr(rubyString);
383
- pack_string(packer, keyString);
384
- break;
385
- }
386
- }
387
-
388
- static int hash_iterator(VALUE key, VALUE value, VALUE hash_arg) {
389
- msgpack_packer *packer = (msgpack_packer *)hash_arg;
390
-
391
- // pack the key
392
- pack_value_object(packer,key);
393
- // pack the value
394
- pack_value_object(packer, value);
395
- return ST_CONTINUE;
396
- }
397
-
398
-
399
- void pack_string(msgpack_packer *packer, char *string) {
400
- if(string == NULL) {
401
- msgpack_pack_nil(packer);
402
- } else {
403
- int length = strlen(string);
404
- msgpack_pack_raw(packer, length);
405
- msgpack_pack_raw_body(packer, string, length);
406
- }
407
- }
408
-
409
- void pack_timestamp(msgpack_packer *packer) {
410
- struct timeval tv;
411
- gettimeofday(&tv, NULL);
412
-
413
- double time_in_milliseconds = (tv.tv_sec)*1000 + (tv.tv_usec)/1000;
414
- msgpack_pack_double(packer, time_in_milliseconds);
415
- }
416
-
417
282
  static VALUE send_hash_as_event(int argc, VALUE *argv, VALUE self) {
418
283
  VALUE hash_object;
419
- VALUE event_name;
284
+ VALUE event_type;
420
285
 
421
- rb_scan_args(argc, argv, "20", &hash_object, &event_name);
286
+ rb_scan_args(argc, argv, "20", &hash_object, &event_type);
422
287
 
423
- int size = RHASH_SIZE(hash_object);
424
288
  msgpack_sbuffer *buffer = msgpack_sbuffer_new();
425
289
  msgpack_packer *packer = msgpack_packer_new(buffer, msgpack_sbuffer_write);
426
- pack_event_header(packer, StringValueCStr(event_name), 3);
427
290
 
428
- pack_string(packer, "payload");
429
- msgpack_pack_map(packer, size);
291
+ rbkit_hash_event *event = new_rbkit_hash_event(FIX2INT(event_type), hash_object);
292
+ pack_event((rbkit_event_header *)event, packer);
293
+ free(event);
430
294
 
431
- rb_hash_foreach(hash_object, hash_iterator, (VALUE)packer);
432
295
  add_message(buffer);
433
296
  msgpack_sbuffer_free(buffer);
434
297
  msgpack_packer_free(packer);
@@ -453,103 +316,14 @@ static VALUE send_objectspace_dump() {
453
316
  msgpack_packer* pk = msgpack_packer_new(buffer, msgpack_sbuffer_write);
454
317
 
455
318
  rbkit_object_dump * dump = get_object_dump(logger->object_table);
456
- pack_event_header(pk, "object_space_dump", 3);
457
- pack_string(pk, "payload");
458
- // Set size of array to hold all objects
459
- msgpack_pack_array(pk, dump->object_count);
460
-
461
- // Iterate through all object data
462
- rbkit_object_dump_page * page = dump->first ;
463
- while(page != NULL) {
464
- rbkit_object_data *data;
465
- size_t i = 0;
466
- for(;i < page->count; i++) {
467
- data = &(page->data[i]);
468
- /* Object dump is a map that looks like this :
469
- * {
470
- * object_id: <OBJECT_ID_IN_HEX>,
471
- * class: <CLASS_NAME>,
472
- * references: [<OBJECT_ID_IN_HEX>, <OBJECT_ID_IN_HEX>, ...],
473
- * file: <FILE_PATH>,
474
- * line: <LINE_NO>,
475
- * size: <SIZE>
476
- * }
477
- */
478
-
479
- msgpack_pack_map(pk, 6);
480
-
481
- // Key1 : "object_id"
482
- pack_string(pk, "object_id");
483
-
484
- // Value1 : pointer address of object
485
- char * object_id;
486
- asprintf(&object_id, "%p", data->object_id);
487
- pack_string(pk, object_id);
488
- free(object_id);
489
-
490
- // Key2 : "class_name"
491
- pack_string(pk, "class_name");
492
-
493
- // Value2 : Class name of object
494
- if(data->class_name == NULL) {
495
- msgpack_pack_nil(pk);
496
- } else {
497
- pack_string(pk, data->class_name);
498
- }
499
-
500
- // Key3 : "references"
501
- pack_string(pk, "references");
502
-
503
- // Value3 : References held by the object
504
- msgpack_pack_array(pk, data->reference_count);
505
- if(data->reference_count != 0) {
506
- size_t count = 0;
507
- for(; count < data->reference_count; count++ ) {
508
- char * object_id;
509
- asprintf(&object_id, "%p", data->references[count]);
510
- pack_string(pk, object_id);
511
- free(object_id);
512
- }
513
- free(data->references);
514
- }
515
-
516
- // Key4 : "file"
517
- pack_string(pk, "file");
518
-
519
- // Value4 : File path where object is defined
520
- pack_string(pk, data->file);
521
-
522
- // Key5 : "line"
523
- pack_string(pk, "line");
524
-
525
- // Value5 : Line no where object is defined
526
- if(data->line == 0)
527
- msgpack_pack_nil(pk);
528
- else
529
- msgpack_pack_unsigned_long(pk, data->line);
530
-
531
- // Key6 : "size"
532
- pack_string(pk, "size");
533
-
534
- // Value6 : Size of the object in memory
535
- if(data->size == 0)
536
- msgpack_pack_nil(pk);
537
- else
538
- msgpack_pack_uint32(pk, data->size);
539
- }
540
- rbkit_object_dump_page * prev = page;
541
- page = page->next;
542
- free(prev);
543
- }
544
-
545
- // Send packed message over zmq
319
+ rbkit_object_space_dump_event *event = new_rbkit_object_space_dump_event(dump);
320
+ pack_event((rbkit_event_header *)event, pk);
321
+ free(event);
546
322
  add_message(buffer);
547
323
 
548
- //Cleanup
549
324
  free(dump);
550
325
  msgpack_sbuffer_free(buffer);
551
326
  msgpack_packer_free(pk);
552
-
553
327
  return Qnil;
554
328
  }
555
329
 
@@ -570,6 +344,11 @@ static VALUE send_messages() {
570
344
  return Qnil;
571
345
  }
572
346
 
347
+ static VALUE enable_test_mode() {
348
+ Init_rbkit_test_helper();
349
+ return Qnil;
350
+ }
351
+
573
352
  void Init_rbkit_tracer(void) {
574
353
  VALUE objectStatsModule = rb_define_module("Rbkit");
575
354
  rb_define_module_function(objectStatsModule, "start_stat_server", start_stat_server, -1);
@@ -580,4 +359,8 @@ void Init_rbkit_tracer(void) {
580
359
  rb_define_module_function(objectStatsModule, "send_objectspace_dump", send_objectspace_dump, 0);
581
360
  rb_define_module_function(objectStatsModule, "send_hash_as_event", send_hash_as_event, -1);
582
361
  rb_define_module_function(objectStatsModule, "send_messages", send_messages, 0);
362
+ rb_define_module_function(objectStatsModule, "enable_test_mode", enable_test_mode, 0);
363
+ rb_define_module_function(objectStatsModule, "status", rbkit_status_as_hash, 0);
364
+ rb_define_const(objectStatsModule, "EVENT_TYPES", rbkit_event_types_as_hash());
365
+ rb_define_const(objectStatsModule, "MESSAGE_FIELDS", rbkit_message_fields_as_hash());
583
366
  }