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
@@ -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
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
}
|
data/ext/rbkit_object_graph.c
CHANGED
@@ -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
|
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(
|
48
|
+
data->references = malloc(sizeof(unsigned long long));
|
78
49
|
} else {
|
79
|
-
data->references = realloc(data->references, data->reference_count * sizeof(
|
50
|
+
data->references = realloc(data->references, data->reference_count * sizeof(unsigned long long) );
|
80
51
|
}
|
81
|
-
data->references[data->reference_count - 1] = (
|
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 = (
|
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
|
}
|
data/ext/rbkit_object_graph.h
CHANGED
@@ -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
|
-
|
8
|
+
unsigned long long object_id;
|
8
9
|
const char * class_name;
|
9
|
-
|
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();
|
data/ext/rbkit_tracer.c
CHANGED
@@ -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
|
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
|
-
|
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(
|
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
|
-
|
79
|
-
|
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
|
-
|
86
|
-
|
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
|
-
|
93
|
-
|
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
|
-
|
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
|
-
|
172
|
-
|
173
|
-
|
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
|
-
|
191
|
-
|
192
|
-
|
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
|
-
|
219
|
-
|
120
|
+
// Delete allocation info of freed object
|
121
|
+
delete_rbkit_allocation_info(tparg, obj, arg->str_table, arg->object_table);
|
220
122
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
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
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
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
|
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
|
-
|
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
|
284
|
+
VALUE event_type;
|
420
285
|
|
421
|
-
rb_scan_args(argc, argv, "20", &hash_object, &
|
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
|
-
|
429
|
-
|
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
|
-
|
457
|
-
|
458
|
-
|
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
|
}
|