rotoscope 0.3.0.pre.2 → 0.3.0.pre.3
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/README.md +7 -7
- data/ext/rotoscope/callsite.c +14 -55
- data/ext/rotoscope/rotoscope.c +65 -112
- data/ext/rotoscope/rotoscope.h +12 -17
- data/ext/rotoscope/stack.c +11 -9
- data/ext/rotoscope/stack.h +4 -4
- data/ext/rotoscope/tracepoint.c +0 -18
- data/ext/rotoscope/tracepoint.h +1 -13
- data/lib/rotoscope.rb +5 -5
- data/lib/rotoscope/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f45130c1218060c685c57b16ad4adadcccd40ee2
|
4
|
+
data.tar.gz: aeb4fd036a4a795396a4a8746eb3ab1033040c6f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c58c3b03672d6f2c84906f4eb4e6598bbd0e0c6844e6e13df35d18025567b7f60ed367d8ca630a3738011ecee6b7c5e359009b4034810004a2f2b0f29a4c4d03
|
7
|
+
data.tar.gz: a0b993814e3ce2f1621c71433f9171cf51e595ce8c81e2f7f11ccc951e41ee15e7e96bc0391f7a11f051eb0ab7afa4bebf4ee9bc99dd3568d64c4ccee31aaada
|
data/README.md
CHANGED
@@ -85,8 +85,8 @@ IO,write,instance,example/flattened_dog.rb,11,IO,puts,instance
|
|
85
85
|
## API
|
86
86
|
|
87
87
|
- [Public Class Methods](#public-class-methods)
|
88
|
-
- [`trace`](#rotoscopetracedest-
|
89
|
-
- [`new`](#rotoscopenewdest-
|
88
|
+
- [`trace`](#rotoscopetracedest-entity_whitelist-nil-flatten-false)
|
89
|
+
- [`new`](#rotoscopenewdest-entity_whitelist-nil-flatten-false)
|
90
90
|
- [Public Instance Methods](#public-instance-methods)
|
91
91
|
- [`trace`](#rotoscopetraceblock)
|
92
92
|
- [`start_trace`](#rotoscopestart_trace)
|
@@ -101,23 +101,23 @@ IO,write,instance,example/flattened_dog.rb,11,IO,puts,instance
|
|
101
101
|
|
102
102
|
### Public Class Methods
|
103
103
|
|
104
|
-
#### `Rotoscope::trace(dest,
|
104
|
+
#### `Rotoscope::trace(dest, entity_whitelist: nil, flatten: false)`
|
105
105
|
|
106
|
-
Writes all calls and returns of methods to `dest`, except for those whose
|
106
|
+
Writes all calls and returns of methods to `dest`, except for those whose entity doesn't contain any entry in a provided `entity_whitelist`. `dest` is either a filename or an `IO`. The `flatten` option reduces the output data to a deduplicated list of method invocations and their caller, instead of all `call` and `return` events. Methods invoked at the top of the trace will have a caller entity of `<ROOT>` and a caller method name of `<UNKNOWN>`.
|
107
107
|
|
108
108
|
```ruby
|
109
109
|
Rotoscope.trace(dest) { |rs| ... }
|
110
110
|
# or...
|
111
|
-
Rotoscope.trace(dest,
|
111
|
+
Rotoscope.trace(dest, entity_whitelist: ["Foo", "Bar"], flatten: true) { |rs| ... }
|
112
112
|
```
|
113
113
|
|
114
|
-
#### `Rotoscope::new(dest,
|
114
|
+
#### `Rotoscope::new(dest, entity_whitelist: nil, flatten: false)`
|
115
115
|
|
116
116
|
Same interface as `Rotoscope::trace`, but returns a `Rotoscope` instance, allowing fine-grain control via `Rotoscope#start_trace` and `Rotoscope#stop_trace`.
|
117
117
|
```ruby
|
118
118
|
rs = Rotoscope.new(dest)
|
119
119
|
# or...
|
120
|
-
rs = Rotoscope.new(dest,
|
120
|
+
rs = Rotoscope.new(dest, entity_whitelist: ["Foo", "Bar"], flatten: true)
|
121
121
|
```
|
122
122
|
|
123
123
|
---
|
data/ext/rotoscope/callsite.c
CHANGED
@@ -4,43 +4,6 @@
|
|
4
4
|
|
5
5
|
VALUE empty_ruby_string;
|
6
6
|
|
7
|
-
// Need the cfp field from this internal ruby structure.
|
8
|
-
struct rb_trace_arg_struct {
|
9
|
-
// unused fields needed to make sure the cfp is at the
|
10
|
-
// correct offset
|
11
|
-
rb_event_flag_t unused1;
|
12
|
-
void *unused2;
|
13
|
-
void *cfp;
|
14
|
-
// rest of fields are unused
|
15
|
-
};
|
16
|
-
|
17
|
-
size_t ruby_control_frame_size;
|
18
|
-
|
19
|
-
// We depend on MRI to store ruby control frames as an array
|
20
|
-
// to determine the control frame size, which is used here to
|
21
|
-
// get the caller's control frame
|
22
|
-
static void *caller_cfp(void *cfp) {
|
23
|
-
return ((char *)cfp) + ruby_control_frame_size;
|
24
|
-
}
|
25
|
-
|
26
|
-
static VALUE dummy(VALUE self, VALUE first) {
|
27
|
-
if (first == Qtrue) {
|
28
|
-
rb_funcall(self, rb_intern("dummy"), 1, Qfalse);
|
29
|
-
}
|
30
|
-
return Qnil;
|
31
|
-
}
|
32
|
-
|
33
|
-
static void trace_control_frame_size(VALUE tpval, void *data) {
|
34
|
-
void **cfps = data;
|
35
|
-
rb_trace_arg_t *trace_arg = rb_tracearg_from_tracepoint(tpval);
|
36
|
-
|
37
|
-
if (cfps[0] == NULL) {
|
38
|
-
cfps[0] = trace_arg->cfp;
|
39
|
-
} else if (cfps[1] == NULL) {
|
40
|
-
cfps[1] = trace_arg->cfp;
|
41
|
-
}
|
42
|
-
}
|
43
|
-
|
44
7
|
rs_callsite_t c_callsite(rb_trace_arg_t *trace_arg) {
|
45
8
|
VALUE path = rb_tracearg_path(trace_arg);
|
46
9
|
return (rs_callsite_t){
|
@@ -50,29 +13,25 @@ rs_callsite_t c_callsite(rb_trace_arg_t *trace_arg) {
|
|
50
13
|
}
|
51
14
|
|
52
15
|
rs_callsite_t ruby_callsite(rb_trace_arg_t *trace_arg) {
|
53
|
-
|
54
|
-
|
55
|
-
//
|
56
|
-
|
57
|
-
|
58
|
-
|
16
|
+
VALUE frames[2];
|
17
|
+
int lines[2];
|
18
|
+
// There is currently a bug in rb_profile_frames that
|
19
|
+
// causes the start argument to effectively always
|
20
|
+
// act as if it were 0, so we need to also get the top
|
21
|
+
// frame.
|
22
|
+
if (rb_profile_frames(0, 2, frames, lines) < 2) {
|
23
|
+
return (rs_callsite_t){
|
24
|
+
.filepath = empty_ruby_string, .lineno = 0,
|
25
|
+
};
|
26
|
+
}
|
59
27
|
|
60
|
-
return
|
28
|
+
return (rs_callsite_t){
|
29
|
+
.filepath = rb_profile_frame_path(frames[1]), .lineno = lines[1],
|
30
|
+
};
|
61
31
|
}
|
62
32
|
|
63
33
|
void init_callsite() {
|
64
34
|
empty_ruby_string = rb_str_new_literal("");
|
65
35
|
RB_OBJ_FREEZE(empty_ruby_string);
|
66
36
|
rb_global_variable(&empty_ruby_string);
|
67
|
-
|
68
|
-
VALUE tmp_obj = rb_funcall(rb_cObject, rb_intern("new"), 0);
|
69
|
-
rb_define_singleton_method(tmp_obj, "dummy", dummy, 1);
|
70
|
-
|
71
|
-
char *cfps[2] = {NULL, NULL};
|
72
|
-
VALUE tracepoint = rb_tracepoint_new(Qnil, RUBY_EVENT_C_CALL,
|
73
|
-
trace_control_frame_size, &cfps);
|
74
|
-
rb_tracepoint_enable(tracepoint);
|
75
|
-
rb_funcall(tmp_obj, rb_intern("dummy"), 1, Qtrue);
|
76
|
-
rb_tracepoint_disable(tracepoint);
|
77
|
-
ruby_control_frame_size = (size_t)cfps[0] - (size_t)cfps[1];
|
78
37
|
}
|
data/ext/rotoscope/rotoscope.c
CHANGED
@@ -13,8 +13,8 @@
|
|
13
13
|
#include "strmemo.h"
|
14
14
|
#include "tracepoint.h"
|
15
15
|
|
16
|
-
VALUE cRotoscope, cTracePoint
|
17
|
-
ID id_initialize
|
16
|
+
VALUE cRotoscope, cTracePoint;
|
17
|
+
ID id_initialize;
|
18
18
|
|
19
19
|
static unsigned long gettid() {
|
20
20
|
return NUM2ULONG(rb_obj_id(rb_thread_current()));
|
@@ -37,12 +37,9 @@ static const char *evflag2name(rb_event_flag_t evflag) {
|
|
37
37
|
}
|
38
38
|
}
|
39
39
|
|
40
|
-
static bool
|
41
|
-
|
42
|
-
|
43
|
-
}
|
44
|
-
|
45
|
-
return false;
|
40
|
+
static bool rejected_entity(VALUE entity, Rotoscope *config) {
|
41
|
+
if (NIL_P(config->entity_whitelist)) return false;
|
42
|
+
return rb_hash_lookup(config->entity_whitelist, entity) != Qtrue;
|
46
43
|
}
|
47
44
|
|
48
45
|
static VALUE class_path(VALUE klass) {
|
@@ -108,6 +105,7 @@ static rs_tracepoint_t extract_full_tracevals(rb_trace_arg_t *trace_arg,
|
|
108
105
|
|
109
106
|
VALUE method_name = tracearg_method_name(trace_arg);
|
110
107
|
VALUE filepath = callsite->filepath;
|
108
|
+
|
111
109
|
return (rs_tracepoint_t){.event = evflag2name(event_flag),
|
112
110
|
.entity = method_owner.name,
|
113
111
|
.filepath = filepath,
|
@@ -118,58 +116,30 @@ static rs_tracepoint_t extract_full_tracevals(rb_trace_arg_t *trace_arg,
|
|
118
116
|
|
119
117
|
static bool in_fork(Rotoscope *config) { return config->pid != getpid(); }
|
120
118
|
|
121
|
-
static
|
122
|
-
|
123
|
-
return rb_obj_method(args[0], args[1]);
|
124
|
-
}
|
125
|
-
static VALUE nil_method(VALUE *args) { return Qnil; }
|
126
|
-
|
127
|
-
static bool endof_block_method(rb_trace_arg_t *trace_arg) {
|
128
|
-
VALUE method_id = rb_tracearg_method_id(trace_arg);
|
129
|
-
if (NIL_P(method_id)) return false;
|
130
|
-
|
131
|
-
VALUE self = rb_tracearg_self(trace_arg);
|
132
|
-
VALUE argv[2] = {self, method_id};
|
133
|
-
VALUE method = rb_rescue2(unsafe_obj_method, (VALUE)&argv, nil_method,
|
134
|
-
(VALUE)&argv, rb_eNameError, (VALUE)0);
|
135
|
-
if (NIL_P(method)) return false;
|
136
|
-
|
137
|
-
VALUE iseq = rb_funcall(cInstructionSeq, id_of, 1, method);
|
138
|
-
if (!RTEST(iseq)) return false;
|
139
|
-
|
140
|
-
VALUE label = rb_funcall(iseq, id_label, 0);
|
141
|
-
char *label_str = StringValueCStr(label);
|
142
|
-
return strncmp(VM_BLOCK_PREFIX, label_str, strlen(VM_BLOCK_PREFIX)) == 0;
|
119
|
+
static void log_trace_event(FILE *stream, rs_tracepoint_t *trace) {
|
120
|
+
fprintf(stream, RS_CSV_FORMAT "\n", RS_CSV_VALUES(trace));
|
143
121
|
}
|
144
122
|
|
145
123
|
unsigned char output_buffer[LOG_BUFFER_SIZE];
|
146
|
-
static void log_trace_event_with_caller(FILE *stream,
|
147
|
-
rs_stack_frame_t
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
124
|
+
static void log_trace_event_with_caller(FILE *stream,
|
125
|
+
rs_stack_frame_t *stack_frame,
|
126
|
+
rs_strmemo_t **call_memo) {
|
127
|
+
rs_stack_frame_t *caller = stack_frame->caller;
|
128
|
+
while (caller->blacklisted) {
|
129
|
+
caller = caller->caller;
|
152
130
|
}
|
153
|
-
}
|
154
131
|
|
155
|
-
|
156
|
-
|
157
|
-
}
|
158
|
-
|
159
|
-
static bool invalid_stack_return(rs_stack_t *stack, rs_tracepoint_t *trace) {
|
160
|
-
rs_stack_frame_t *last_frame = rs_stack_peek(stack);
|
161
|
-
return !rs_raw_tracepoint_cmp(&trace->raw, &last_frame->tp.raw);
|
162
|
-
}
|
132
|
+
snprintf((char *)output_buffer, LOG_BUFFER_SIZE, RS_FLATTENED_CSV_FORMAT "\n",
|
133
|
+
RS_FLATTENED_CSV_VALUES(&stack_frame->tp, &caller->tp));
|
163
134
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
trace->filepath = last_frame->tp.filepath;
|
168
|
-
trace->lineno = last_frame->tp.lineno;
|
135
|
+
if (rs_strmemo_uniq(call_memo, output_buffer)) {
|
136
|
+
fputs((char *)output_buffer, stream);
|
137
|
+
}
|
169
138
|
}
|
170
139
|
|
171
140
|
static void event_hook(VALUE tpval, void *data) {
|
172
141
|
Rotoscope *config = (Rotoscope *)data;
|
142
|
+
|
173
143
|
if (config->tid != gettid()) return;
|
174
144
|
if (in_fork(config)) {
|
175
145
|
rb_tracepoint_disable(config->tracepoint);
|
@@ -179,41 +149,44 @@ static void event_hook(VALUE tpval, void *data) {
|
|
179
149
|
|
180
150
|
rb_trace_arg_t *trace_arg = rb_tracearg_from_tracepoint(tpval);
|
181
151
|
rb_event_flag_t event_flag = rb_tracearg_event_flag(trace_arg);
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
if (!rs_raw_tracepoint_cmp(&raw_trace, &last_frame->tp.raw)) return;
|
193
|
-
// Are we dealing with a block return in wrong context?
|
194
|
-
if (!endof_block_method(trace_arg)) return;
|
152
|
+
|
153
|
+
rs_callsite_t trace_path;
|
154
|
+
if (event_flag & EVENT_CALL) {
|
155
|
+
trace_path = tracearg_path(trace_arg);
|
156
|
+
} else {
|
157
|
+
if (rs_stack_empty(&config->stack)) return;
|
158
|
+
rs_stack_frame_t *call_frame = rs_stack_peek(&config->stack);
|
159
|
+
trace_path = (rs_callsite_t){
|
160
|
+
.filepath = call_frame->tp.filepath, .lineno = call_frame->tp.lineno,
|
161
|
+
};
|
195
162
|
}
|
196
163
|
|
197
164
|
rs_tracepoint_t trace = extract_full_tracevals(trace_arg, &trace_path);
|
198
|
-
trace.raw = raw_trace;
|
199
|
-
|
200
165
|
if (!strcmp("Rotoscope", StringValueCStr(trace.entity))) return;
|
201
166
|
|
202
|
-
|
203
|
-
if (
|
204
|
-
|
167
|
+
bool blacklisted;
|
168
|
+
if (event_flag & EVENT_CALL) {
|
169
|
+
blacklisted = rejected_entity(trace.entity, config);
|
170
|
+
rs_stack_push(&config->stack, trace, blacklisted);
|
205
171
|
} else {
|
206
|
-
|
207
|
-
if (endof_block_method(trace_arg)) {
|
208
|
-
copy_filepath_from_caller(&config->stack, &trace);
|
209
|
-
}
|
172
|
+
blacklisted = rs_stack_peek(&config->stack)->blacklisted;
|
210
173
|
rs_stack_pop(&config->stack);
|
211
174
|
}
|
175
|
+
if (blacklisted) return;
|
212
176
|
|
213
|
-
if (
|
214
|
-
|
215
|
-
|
216
|
-
|
177
|
+
if (config->flatten_output) {
|
178
|
+
if (event_flag & EVENT_CALL) {
|
179
|
+
rs_stack_frame_t *caller = rs_stack_peek(&config->stack)->caller;
|
180
|
+
while (caller && caller->blacklisted) {
|
181
|
+
caller = caller->caller;
|
182
|
+
}
|
183
|
+
if (caller) {
|
184
|
+
log_trace_event_with_caller(config->log, rs_stack_peek(&config->stack),
|
185
|
+
&config->call_memo);
|
186
|
+
}
|
187
|
+
}
|
188
|
+
} else {
|
189
|
+
log_trace_event(config->log, &trace);
|
217
190
|
}
|
218
191
|
}
|
219
192
|
|
@@ -242,6 +215,7 @@ static void close_log_handle(Rotoscope *config) {
|
|
242
215
|
static void rs_gc_mark(Rotoscope *config) {
|
243
216
|
rb_gc_mark(config->log_path);
|
244
217
|
rb_gc_mark(config->tracepoint);
|
218
|
+
rb_gc_mark(config->entity_whitelist);
|
245
219
|
rs_stack_mark(&config->stack);
|
246
220
|
}
|
247
221
|
|
@@ -249,7 +223,6 @@ void rs_dealloc(Rotoscope *config) {
|
|
249
223
|
close_log_handle(config);
|
250
224
|
rs_stack_free(&config->stack);
|
251
225
|
rs_strmemo_free(config->call_memo);
|
252
|
-
xfree(config->blacklist);
|
253
226
|
xfree(config);
|
254
227
|
}
|
255
228
|
|
@@ -258,6 +231,7 @@ static VALUE rs_alloc(VALUE klass) {
|
|
258
231
|
VALUE self =
|
259
232
|
Data_Make_Struct(klass, Rotoscope, rs_gc_mark, rs_dealloc, config);
|
260
233
|
config->log_path = Qnil;
|
234
|
+
config->entity_whitelist = Qnil;
|
261
235
|
config->tracepoint = rb_tracepoint_new(Qnil, EVENT_CALL | EVENT_RETURN,
|
262
236
|
event_hook, (void *)config);
|
263
237
|
config->pid = getpid();
|
@@ -271,42 +245,25 @@ static Rotoscope *get_config(VALUE self) {
|
|
271
245
|
return config;
|
272
246
|
}
|
273
247
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
size_t blacklist_malloc_size =
|
278
|
-
RARRAY_LEN(blacklist) * sizeof(*config->blacklist);
|
279
|
-
|
280
|
-
for (long i = 0; i < RARRAY_LEN(blacklist); i++) {
|
281
|
-
VALUE ruby_string = RARRAY_AREF(blacklist, i);
|
282
|
-
Check_Type(ruby_string, T_STRING);
|
283
|
-
blacklist_malloc_size += RSTRING_LEN(ruby_string) + 1;
|
284
|
-
}
|
285
|
-
|
286
|
-
config->blacklist = ruby_xmalloc(blacklist_malloc_size);
|
287
|
-
config->blacklist_size = RARRAY_LEN(blacklist);
|
288
|
-
char *str = (char *)(config->blacklist + config->blacklist_size);
|
289
|
-
|
290
|
-
for (unsigned long i = 0; i < config->blacklist_size; i++) {
|
291
|
-
VALUE ruby_string = RARRAY_AREF(blacklist, i);
|
292
|
-
|
293
|
-
config->blacklist[i] = str;
|
294
|
-
memcpy(str, RSTRING_PTR(ruby_string), RSTRING_LEN(ruby_string));
|
295
|
-
str += RSTRING_LEN(ruby_string);
|
296
|
-
*str = '\0';
|
297
|
-
str++;
|
298
|
-
}
|
248
|
+
bool blacklisted_root(Rotoscope *config) {
|
249
|
+
return !NIL_P(config->entity_whitelist);
|
299
250
|
}
|
300
251
|
|
301
252
|
VALUE initialize(int argc, VALUE *argv, VALUE self) {
|
302
253
|
Rotoscope *config = get_config(self);
|
303
|
-
VALUE output_path,
|
254
|
+
VALUE output_path, entity_whitelist, flatten;
|
304
255
|
|
305
|
-
rb_scan_args(argc, argv, "12", &output_path, &
|
256
|
+
rb_scan_args(argc, argv, "12", &output_path, &entity_whitelist, &flatten);
|
306
257
|
Check_Type(output_path, T_STRING);
|
307
258
|
|
308
|
-
if (!NIL_P(
|
309
|
-
|
259
|
+
if (!NIL_P(entity_whitelist)) {
|
260
|
+
Check_Type(entity_whitelist, T_ARRAY);
|
261
|
+
config->entity_whitelist = rb_hash_new();
|
262
|
+
for (long i = 0; i < RARRAY_LEN(entity_whitelist); i++) {
|
263
|
+
VALUE item = RARRAY_AREF(entity_whitelist, i);
|
264
|
+
Check_Type(item, T_STRING);
|
265
|
+
rb_hash_aset(config->entity_whitelist, item, Qtrue);
|
266
|
+
}
|
310
267
|
}
|
311
268
|
|
312
269
|
config->flatten_output = RTEST(flatten);
|
@@ -324,7 +281,7 @@ VALUE initialize(int argc, VALUE *argv, VALUE self) {
|
|
324
281
|
else
|
325
282
|
write_csv_header(config->log, RS_CSV_HEADER);
|
326
283
|
|
327
|
-
rs_stack_init(&config->stack, STACK_CAPACITY);
|
284
|
+
rs_stack_init(&config->stack, STACK_CAPACITY, blacklisted_root(config));
|
328
285
|
config->call_memo = NULL;
|
329
286
|
config->state = RS_OPEN;
|
330
287
|
return self;
|
@@ -342,6 +299,7 @@ VALUE rotoscope_stop_trace(VALUE self) {
|
|
342
299
|
if (rb_tracepoint_enabled_p(config->tracepoint)) {
|
343
300
|
rb_tracepoint_disable(config->tracepoint);
|
344
301
|
config->state = RS_OPEN;
|
302
|
+
rs_stack_reset(&config->stack, blacklisted_root(config));
|
345
303
|
}
|
346
304
|
|
347
305
|
return Qnil;
|
@@ -361,7 +319,6 @@ VALUE rotoscope_mark(int argc, VALUE *argv, VALUE self) {
|
|
361
319
|
|
362
320
|
Rotoscope *config = get_config(self);
|
363
321
|
if (config->log != NULL && !in_fork(config)) {
|
364
|
-
rs_stack_reset(&config->stack, STACK_CAPACITY);
|
365
322
|
rs_strmemo_free(config->call_memo);
|
366
323
|
fprintf(config->log, "--- %s\n", StringValueCStr(str));
|
367
324
|
}
|
@@ -396,13 +353,9 @@ VALUE rotoscope_state(VALUE self) {
|
|
396
353
|
}
|
397
354
|
|
398
355
|
void Init_rotoscope(void) {
|
399
|
-
VALUE cRubyVm = rb_const_get(rb_cObject, rb_intern("RubyVM"));
|
400
|
-
cInstructionSeq = rb_const_get(cRubyVm, rb_intern("InstructionSequence"));
|
401
356
|
cTracePoint = rb_const_get(rb_cObject, rb_intern("TracePoint"));
|
402
357
|
|
403
358
|
id_initialize = rb_intern("initialize");
|
404
|
-
id_of = rb_intern("of");
|
405
|
-
id_label = rb_intern("label");
|
406
359
|
|
407
360
|
cRotoscope = rb_define_class("Rotoscope", rb_cObject);
|
408
361
|
rb_define_alloc_func(cRotoscope, rs_alloc);
|
data/ext/rotoscope/rotoscope.h
CHANGED
@@ -7,14 +7,10 @@
|
|
7
7
|
|
8
8
|
#define EVENT_CALL (RUBY_EVENT_CALL | RUBY_EVENT_C_CALL)
|
9
9
|
#define EVENT_RETURN (RUBY_EVENT_RETURN | RUBY_EVENT_C_RETURN)
|
10
|
-
#define METHOD_CALL_P(event) event &EVENT_CALL
|
11
|
-
#define METHOD_RETURN_P(event) event &EVENT_RETURN
|
12
10
|
|
13
11
|
#define CLASS_METHOD "class"
|
14
12
|
#define INSTANCE_METHOD "instance"
|
15
13
|
|
16
|
-
#define VM_BLOCK_PREFIX "block "
|
17
|
-
|
18
14
|
#define STACK_CAPACITY 500
|
19
15
|
#define LOG_BUFFER_SIZE 1000
|
20
16
|
|
@@ -22,24 +18,24 @@
|
|
22
18
|
#define _RS_COMMON_CSV_HEADER "entity,method_name,method_level,filepath,lineno"
|
23
19
|
#define _RS_COMMON_CSV_FORMAT "\"%s\",\"%s\",%s,\"%s\",%d"
|
24
20
|
#define _RS_COMMON_CSV_VALUES(trace) \
|
25
|
-
StringValueCStr(trace
|
26
|
-
StringValueCStr(trace
|
27
|
-
trace
|
28
|
-
StringValueCStr(trace
|
29
|
-
trace
|
21
|
+
StringValueCStr((trace)->entity), \
|
22
|
+
StringValueCStr((trace)->method_name), \
|
23
|
+
(trace)->method_level, \
|
24
|
+
StringValueCStr((trace)->filepath), \
|
25
|
+
(trace)->lineno
|
30
26
|
|
31
27
|
#define RS_CSV_HEADER "event," _RS_COMMON_CSV_HEADER
|
32
28
|
#define RS_CSV_FORMAT "%s," _RS_COMMON_CSV_FORMAT
|
33
|
-
#define RS_CSV_VALUES(trace) trace
|
29
|
+
#define RS_CSV_VALUES(trace) trace->event, _RS_COMMON_CSV_VALUES(trace)
|
34
30
|
|
35
31
|
#define RS_FLATTENED_CSV_HEADER \
|
36
32
|
_RS_COMMON_CSV_HEADER ",caller_entity,caller_method_name,caller_method_level"
|
37
33
|
#define RS_FLATTENED_CSV_FORMAT _RS_COMMON_CSV_FORMAT ",\"%s\",\"%s\",%s"
|
38
|
-
#define RS_FLATTENED_CSV_VALUES(
|
39
|
-
_RS_COMMON_CSV_VALUES(
|
40
|
-
StringValueCStr(
|
41
|
-
StringValueCStr(
|
42
|
-
|
34
|
+
#define RS_FLATTENED_CSV_VALUES(trace, caller_trace) \
|
35
|
+
_RS_COMMON_CSV_VALUES(trace), \
|
36
|
+
StringValueCStr((caller_trace)->entity), \
|
37
|
+
StringValueCStr((caller_trace)->method_name), \
|
38
|
+
(caller_trace)->method_level
|
43
39
|
// clang-format on
|
44
40
|
|
45
41
|
typedef enum {
|
@@ -52,8 +48,7 @@ typedef struct {
|
|
52
48
|
FILE *log;
|
53
49
|
VALUE log_path;
|
54
50
|
VALUE tracepoint;
|
55
|
-
|
56
|
-
unsigned long blacklist_size;
|
51
|
+
VALUE entity_whitelist;
|
57
52
|
bool flatten_output;
|
58
53
|
pid_t pid;
|
59
54
|
unsigned long tid;
|
data/ext/rotoscope/stack.c
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
#include "ruby.h"
|
6
6
|
#include "tracepoint.h"
|
7
7
|
|
8
|
-
static void insert_root_node(rs_stack_t *stack) {
|
8
|
+
static void insert_root_node(rs_stack_t *stack, bool blacklisted) {
|
9
9
|
VALUE rb_unknown_str = rb_str_new_cstr(UNKNOWN_STR);
|
10
10
|
rs_tracepoint_t root_trace =
|
11
11
|
(rs_tracepoint_t){.event = UNKNOWN_STR,
|
@@ -14,7 +14,7 @@ static void insert_root_node(rs_stack_t *stack) {
|
|
14
14
|
.method_name = rb_unknown_str,
|
15
15
|
.method_level = UNKNOWN_STR,
|
16
16
|
.lineno = 0};
|
17
|
-
rs_stack_push(stack, root_trace);
|
17
|
+
rs_stack_push(stack, root_trace, blacklisted);
|
18
18
|
}
|
19
19
|
|
20
20
|
static void resize_buffer(rs_stack_t *stack) {
|
@@ -31,15 +31,16 @@ bool rs_stack_full(rs_stack_t *stack) {
|
|
31
31
|
|
32
32
|
bool rs_stack_empty(rs_stack_t *stack) { return stack->top < 0; }
|
33
33
|
|
34
|
-
rs_stack_frame_t rs_stack_push(rs_stack_t *stack, rs_tracepoint_t trace
|
34
|
+
rs_stack_frame_t rs_stack_push(rs_stack_t *stack, rs_tracepoint_t trace,
|
35
|
+
bool blacklisted) {
|
35
36
|
if (rs_stack_full(stack)) {
|
36
37
|
resize_buffer(stack);
|
37
38
|
}
|
38
39
|
|
39
40
|
rs_stack_frame_t *caller =
|
40
41
|
rs_stack_empty(stack) ? NULL : rs_stack_peek(stack);
|
41
|
-
rs_stack_frame_t new_frame =
|
42
|
-
|
42
|
+
rs_stack_frame_t new_frame = (rs_stack_frame_t){
|
43
|
+
.tp = trace, .caller = caller, .blacklisted = blacklisted};
|
43
44
|
|
44
45
|
stack->contents[++stack->top] = new_frame;
|
45
46
|
return new_frame;
|
@@ -63,9 +64,9 @@ rs_stack_frame_t *rs_stack_peek(rs_stack_t *stack) {
|
|
63
64
|
return &stack->contents[stack->top];
|
64
65
|
}
|
65
66
|
|
66
|
-
void rs_stack_reset(rs_stack_t *stack,
|
67
|
+
void rs_stack_reset(rs_stack_t *stack, bool blacklisted_root) {
|
67
68
|
stack->top = -1;
|
68
|
-
insert_root_node(stack);
|
69
|
+
insert_root_node(stack, blacklisted_root);
|
69
70
|
}
|
70
71
|
|
71
72
|
void rs_stack_free(rs_stack_t *stack) {
|
@@ -75,13 +76,14 @@ void rs_stack_free(rs_stack_t *stack) {
|
|
75
76
|
stack->capacity = 0;
|
76
77
|
}
|
77
78
|
|
78
|
-
void rs_stack_init(rs_stack_t *stack, unsigned int capacity
|
79
|
+
void rs_stack_init(rs_stack_t *stack, unsigned int capacity,
|
80
|
+
bool blacklisted_root) {
|
79
81
|
rs_stack_frame_t *contents = ALLOC_N(rs_stack_frame_t, capacity);
|
80
82
|
stack->contents = contents;
|
81
83
|
stack->capacity = capacity;
|
82
84
|
stack->top = -1;
|
83
85
|
|
84
|
-
insert_root_node(stack);
|
86
|
+
insert_root_node(stack, blacklisted_root);
|
85
87
|
}
|
86
88
|
|
87
89
|
void rs_stack_mark(rs_stack_t *stack) {
|
data/ext/rotoscope/stack.h
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
#ifndef _INC_ROTOSCOPE_STACK_H_
|
2
2
|
#define _INC_ROTOSCOPE_STACK_H_
|
3
|
-
|
4
3
|
#include <stdbool.h>
|
5
4
|
#include "tracepoint.h"
|
6
5
|
|
@@ -8,6 +7,7 @@
|
|
8
7
|
|
9
8
|
typedef struct rs_stack_frame_t {
|
10
9
|
struct rs_tracepoint_t tp;
|
10
|
+
bool blacklisted;
|
11
11
|
struct rs_stack_frame_t *caller;
|
12
12
|
} rs_stack_frame_t;
|
13
13
|
|
@@ -17,10 +17,10 @@ typedef struct {
|
|
17
17
|
rs_stack_frame_t *contents;
|
18
18
|
} rs_stack_t;
|
19
19
|
|
20
|
-
void rs_stack_init(rs_stack_t *stack, unsigned int capacity);
|
21
|
-
void rs_stack_reset(rs_stack_t *stack,
|
20
|
+
void rs_stack_init(rs_stack_t *stack, unsigned int capacity, bool blacklisted_root);
|
21
|
+
void rs_stack_reset(rs_stack_t *stack, bool blacklisted_root);
|
22
22
|
void rs_stack_free(rs_stack_t *stack);
|
23
|
-
rs_stack_frame_t rs_stack_push(rs_stack_t *stack, rs_tracepoint_t trace);
|
23
|
+
rs_stack_frame_t rs_stack_push(rs_stack_t *stack, rs_tracepoint_t trace, bool backlisted);
|
24
24
|
bool rs_stack_empty(rs_stack_t *stack);
|
25
25
|
bool rs_stack_full(rs_stack_t *stack);
|
26
26
|
rs_stack_frame_t rs_stack_pop(rs_stack_t *stack);
|
data/ext/rotoscope/tracepoint.c
CHANGED
@@ -1,26 +1,8 @@
|
|
1
1
|
#include "tracepoint.h"
|
2
2
|
#include "ruby.h"
|
3
3
|
|
4
|
-
rs_raw_tracepoint_t rs_raw_from_tracepoint(VALUE tracepoint) {
|
5
|
-
rb_trace_arg_t *trace_arg = rb_tracearg_from_tracepoint(tracepoint);
|
6
|
-
return (rs_raw_tracepoint_t){
|
7
|
-
.self = rb_tracearg_self(trace_arg),
|
8
|
-
.method_id = rb_tracearg_method_id(trace_arg),
|
9
|
-
};
|
10
|
-
}
|
11
|
-
|
12
|
-
void rs_raw_tracepoint_mark(rs_raw_tracepoint_t *tracepoint) {
|
13
|
-
rb_gc_mark(tracepoint->method_id);
|
14
|
-
rb_gc_mark(tracepoint->self);
|
15
|
-
}
|
16
|
-
|
17
4
|
void rs_tracepoint_mark(rs_tracepoint_t *tracepoint) {
|
18
5
|
rb_gc_mark(tracepoint->entity);
|
19
6
|
rb_gc_mark(tracepoint->filepath);
|
20
7
|
rb_gc_mark(tracepoint->method_name);
|
21
|
-
rs_raw_tracepoint_mark(&tracepoint->raw);
|
22
|
-
}
|
23
|
-
|
24
|
-
bool rs_raw_tracepoint_cmp(rs_raw_tracepoint_t *tp1, rs_raw_tracepoint_t *tp2) {
|
25
|
-
return (tp1->method_id == tp2->method_id) && (tp1->self == tp2->self);
|
26
8
|
}
|
data/ext/rotoscope/tracepoint.h
CHANGED
@@ -1,18 +1,7 @@
|
|
1
1
|
#ifndef _INC_ROTOSCOPE_TRACEPOINT_H_
|
2
2
|
#define _INC_ROTOSCOPE_TRACEPOINT_H_
|
3
3
|
|
4
|
-
#include
|
5
|
-
#include <ruby/debug.h>
|
6
|
-
#include <stdbool.h>
|
7
|
-
|
8
|
-
typedef struct rs_raw_tracepoint_t {
|
9
|
-
VALUE method_id;
|
10
|
-
VALUE self;
|
11
|
-
} rs_raw_tracepoint_t;
|
12
|
-
|
13
|
-
rs_raw_tracepoint_t rs_raw_from_tracepoint(VALUE tracepoint);
|
14
|
-
void rs_raw_tracepoint_mark(rs_raw_tracepoint_t *tracepoint);
|
15
|
-
bool rs_raw_tracepoint_cmp(rs_raw_tracepoint_t *tp1, rs_raw_tracepoint_t *tp2);
|
4
|
+
#include "ruby.h"
|
16
5
|
|
17
6
|
typedef struct rs_tracepoint_t {
|
18
7
|
const char *event;
|
@@ -21,7 +10,6 @@ typedef struct rs_tracepoint_t {
|
|
21
10
|
VALUE method_name;
|
22
11
|
const char *method_level;
|
23
12
|
unsigned int lineno;
|
24
|
-
rs_raw_tracepoint_t raw;
|
25
13
|
} rs_tracepoint_t;
|
26
14
|
|
27
15
|
void rs_tracepoint_mark(rs_tracepoint_t *tracepoint);
|
data/lib/rotoscope.rb
CHANGED
@@ -6,12 +6,12 @@ require 'csv'
|
|
6
6
|
|
7
7
|
class Rotoscope
|
8
8
|
class << self
|
9
|
-
def new(output_path,
|
10
|
-
super(output_path,
|
9
|
+
def new(output_path, entity_whitelist: nil, flatten: false)
|
10
|
+
super(output_path, entity_whitelist, flatten)
|
11
11
|
end
|
12
12
|
|
13
|
-
def trace(dest,
|
14
|
-
config = {
|
13
|
+
def trace(dest, entity_whitelist: nil, flatten: false, &block)
|
14
|
+
config = { entity_whitelist: entity_whitelist, flatten: flatten }
|
15
15
|
if dest.is_a?(String)
|
16
16
|
event_trace(dest, config, &block)
|
17
17
|
else
|
@@ -45,7 +45,7 @@ class Rotoscope
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def event_trace(dest_path, config)
|
48
|
-
rs = Rotoscope.new(dest_path,
|
48
|
+
rs = Rotoscope.new(dest_path, entity_whitelist: config[:entity_whitelist], flatten: config[:flatten])
|
49
49
|
rs.trace { yield rs }
|
50
50
|
rs
|
51
51
|
ensure
|
data/lib/rotoscope/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rotoscope
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.0.pre.
|
4
|
+
version: 0.3.0.pre.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jahfer Husain
|
@@ -120,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
120
|
version: 1.3.1
|
121
121
|
requirements: []
|
122
122
|
rubyforge_project:
|
123
|
-
rubygems_version: 2.
|
123
|
+
rubygems_version: 2.5.2.1
|
124
124
|
signing_key:
|
125
125
|
specification_version: 4
|
126
126
|
summary: Tracing Ruby
|