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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 214bc0f95d10e738330ccf96ad98195588ce2fed
4
- data.tar.gz: c8be5f0941288a7a5242e830b17c98de16935022
3
+ metadata.gz: f45130c1218060c685c57b16ad4adadcccd40ee2
4
+ data.tar.gz: aeb4fd036a4a795396a4a8746eb3ab1033040c6f
5
5
  SHA512:
6
- metadata.gz: 0af5d811380da0de299478d7176a09308c1c2ff3a54ea77be54df01e4c34213d8208407b30a90ef34b19d07395c34e2b08395db7a2ba0b0eb783dff8c039b5a8
7
- data.tar.gz: 577ec0a7a6bfc747bc3cde9d80b854aab30cd4804f60ad844273b917741c78f8900d043e87b4eb9a0905884c421e282e0cfe991a62d37ebfef6b7906114bb10d
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-blacklist--flatten-false)
89
- - [`new`](#rotoscopenewdest-blacklist)
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, blacklist: [], flatten: false)`
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 filepath contains any entry in `blacklist`. `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>`.
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, blacklist: ["/.gem/"], flatten: true) { |rs| ... }
111
+ Rotoscope.trace(dest, entity_whitelist: ["Foo", "Bar"], flatten: true) { |rs| ... }
112
112
  ```
113
113
 
114
- #### `Rotoscope::new(dest, blacklist: [], flatten: false)`
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, blacklist: ["/.gem/"], flatten: true)
120
+ rs = Rotoscope.new(dest, entity_whitelist: ["Foo", "Bar"], flatten: true)
121
121
  ```
122
122
 
123
123
  ---
@@ -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
- void *old_cfp = trace_arg->cfp;
54
-
55
- // Ruby uses trace_arg->cfp to get the path and line number
56
- trace_arg->cfp = caller_cfp(trace_arg->cfp);
57
- rs_callsite_t callsite = c_callsite(trace_arg);
58
- trace_arg->cfp = old_cfp;
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 callsite;
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
  }
@@ -13,8 +13,8 @@
13
13
  #include "strmemo.h"
14
14
  #include "tracepoint.h"
15
15
 
16
- VALUE cRotoscope, cTracePoint, cInstructionSeq;
17
- ID id_initialize, id_of, id_label;
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 rejected_path(VALUE path, Rotoscope *config) {
41
- for (unsigned long i = 0; i < config->blacklist_size; i++) {
42
- if (strstr(StringValueCStr(path), config->blacklist[i])) return true;
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 VALUE unsafe_obj_method(VALUE argv) {
122
- VALUE *args = (VALUE *)argv;
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, rs_strmemo_t **call_memo,
147
- rs_stack_frame_t frame) {
148
- snprintf((char *)output_buffer, LOG_BUFFER_SIZE, RS_FLATTENED_CSV_FORMAT "\n",
149
- RS_FLATTENED_CSV_VALUES(frame));
150
- if (rs_strmemo_uniq(call_memo, (unsigned char *)output_buffer)) {
151
- fputs((char *)output_buffer, stream);
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
- static void log_trace_event(FILE *stream, rs_tracepoint_t trace) {
156
- fprintf(stream, RS_CSV_FORMAT "\n", RS_CSV_VALUES(trace));
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
- static void copy_filepath_from_caller(rs_stack_t *stack,
165
- rs_tracepoint_t *trace) {
166
- rs_stack_frame_t *last_frame = rs_stack_peek(stack);
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
- rs_callsite_t trace_path = tracearg_path(trace_arg);
183
- rs_raw_tracepoint_t raw_trace = rs_raw_from_tracepoint(tpval);
184
-
185
- if (rejected_path(trace_path.filepath, config)) {
186
- if (METHOD_CALL_P(event_flag)) return;
187
- // We must ensure the event being blacklisted has correct filepath set,
188
- // since block-method returns always point one level too high in the stack.
189
-
190
- // Does this match the last caller?
191
- rs_stack_frame_t *last_frame = rs_stack_peek(&config->stack);
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
- rs_stack_frame_t frame;
203
- if (METHOD_CALL_P(event_flag)) {
204
- frame = rs_stack_push(&config->stack, trace);
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
- if (invalid_stack_return(&config->stack, &trace)) return;
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 (!config->flatten_output) {
214
- return log_trace_event(config->log, trace);
215
- } else if (METHOD_CALL_P(event_flag)) {
216
- log_trace_event_with_caller(config->log, &config->call_memo, frame);
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
- void copy_blacklist(Rotoscope *config, VALUE blacklist) {
275
- Check_Type(blacklist, T_ARRAY);
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, blacklist, flatten;
254
+ VALUE output_path, entity_whitelist, flatten;
304
255
 
305
- rb_scan_args(argc, argv, "12", &output_path, &blacklist, &flatten);
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(blacklist)) {
309
- copy_blacklist(config, blacklist);
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);
@@ -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.entity), \
26
- StringValueCStr(trace.method_name), \
27
- trace.method_level, \
28
- StringValueCStr(trace.filepath), \
29
- trace.lineno
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.event, _RS_COMMON_CSV_VALUES(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(frame) \
39
- _RS_COMMON_CSV_VALUES(frame.tp), \
40
- StringValueCStr(frame.caller->tp.entity), \
41
- StringValueCStr(frame.caller->tp.method_name), \
42
- frame.caller->tp.method_level
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
- const char **blacklist;
56
- unsigned long blacklist_size;
51
+ VALUE entity_whitelist;
57
52
  bool flatten_output;
58
53
  pid_t pid;
59
54
  unsigned long tid;
@@ -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
- (rs_stack_frame_t){.tp = trace, .caller = caller};
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, unsigned int capacity) {
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) {
@@ -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, unsigned int capacity);
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);
@@ -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
  }
@@ -1,18 +1,7 @@
1
1
  #ifndef _INC_ROTOSCOPE_TRACEPOINT_H_
2
2
  #define _INC_ROTOSCOPE_TRACEPOINT_H_
3
3
 
4
- #include <ruby.h>
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, blacklist: [], flatten: false)
10
- super(output_path, blacklist, flatten)
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, blacklist: [], flatten: false, &block)
14
- config = { blacklist: blacklist, flatten: flatten }
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, blacklist: config[:blacklist], flatten: config[:flatten])
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
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  class Rotoscope
3
- VERSION = "0.3.0.pre.2"
3
+ VERSION = "0.3.0.pre.3"
4
4
  end
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.2
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.6.14
123
+ rubygems_version: 2.5.2.1
124
124
  signing_key:
125
125
  specification_version: 4
126
126
  summary: Tracing Ruby