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