rotoscope 0.3.0.pre.2 → 0.3.0.pre.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|