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.
- 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
|
}
|