rotoscope 0.3.0.pre.3 → 0.3.0.pre.4

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: f45130c1218060c685c57b16ad4adadcccd40ee2
4
- data.tar.gz: aeb4fd036a4a795396a4a8746eb3ab1033040c6f
3
+ metadata.gz: f4fd8393cc33b1bc131fd9f8b59f5445df3ba615
4
+ data.tar.gz: e4dbe71f46625cc11039cf3fc2a97eae80226f35
5
5
  SHA512:
6
- metadata.gz: c58c3b03672d6f2c84906f4eb4e6598bbd0e0c6844e6e13df35d18025567b7f60ed367d8ca630a3738011ecee6b7c5e359009b4034810004a2f2b0f29a4c4d03
7
- data.tar.gz: a0b993814e3ce2f1621c71433f9171cf51e595ce8c81e2f7f11ccc951e41ee15e7e96bc0391f7a11f051eb0ab7afa4bebf4ee9bc99dd3568d64c4ccee31aaada
6
+ metadata.gz: 2516f3ec80a5de3fca9cfdb241e085fbb93cd8a29ad75dc050a210971547b59b530866aab8120bd8c142f219ce12137a8a569ea40cb6a4a76775b385ecb5c670
7
+ data.tar.gz: 0ed7735ef3e1a6bb3126ad2e79d72d7d3fc0c51b313a9b0d211e14755a51e7997df7e1aa5170c84f6b966329bf2f5d56bb7b39de6f127e240bcffef65926c292
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-entity_whitelist-nil-flatten-false)
89
- - [`new`](#rotoscopenewdest-entity_whitelist-nil-flatten-false)
88
+ - [`trace`](#rotoscopetracedest-blacklist--flatten-false)
89
+ - [`new`](#rotoscopenewdest-blacklist--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, entity_whitelist: nil, flatten: false)`
104
+ #### `Rotoscope::trace(dest, blacklist: [], flatten: false)`
105
105
 
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>`.
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>`.
107
107
 
108
108
  ```ruby
109
109
  Rotoscope.trace(dest) { |rs| ... }
110
110
  # or...
111
- Rotoscope.trace(dest, entity_whitelist: ["Foo", "Bar"], flatten: true) { |rs| ... }
111
+ Rotoscope.trace(dest, blacklist: ["/.gem/"], flatten: true) { |rs| ... }
112
112
  ```
113
113
 
114
- #### `Rotoscope::new(dest, entity_whitelist: nil, flatten: false)`
114
+ #### `Rotoscope::new(dest, blacklist: [], 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, entity_whitelist: ["Foo", "Bar"], flatten: true)
120
+ rs = Rotoscope.new(dest, blacklist: ["/.gem/"], flatten: true)
121
121
  ```
122
122
 
123
123
  ---
@@ -37,9 +37,12 @@ static const char *evflag2name(rb_event_flag_t evflag) {
37
37
  }
38
38
  }
39
39
 
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;
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;
43
46
  }
44
47
 
45
48
  static VALUE class_path(VALUE klass) {
@@ -123,14 +126,10 @@ static void log_trace_event(FILE *stream, rs_tracepoint_t *trace) {
123
126
  unsigned char output_buffer[LOG_BUFFER_SIZE];
124
127
  static void log_trace_event_with_caller(FILE *stream,
125
128
  rs_stack_frame_t *stack_frame,
129
+ rs_stack_frame_t *caller_frame,
126
130
  rs_strmemo_t **call_memo) {
127
- rs_stack_frame_t *caller = stack_frame->caller;
128
- while (caller->blacklisted) {
129
- caller = caller->caller;
130
- }
131
-
132
131
  snprintf((char *)output_buffer, LOG_BUFFER_SIZE, RS_FLATTENED_CSV_FORMAT "\n",
133
- RS_FLATTENED_CSV_VALUES(&stack_frame->tp, &caller->tp));
132
+ RS_FLATTENED_CSV_VALUES(&stack_frame->tp, &caller_frame->tp));
134
133
 
135
134
  if (rs_strmemo_uniq(call_memo, output_buffer)) {
136
135
  fputs((char *)output_buffer, stream);
@@ -151,38 +150,38 @@ static void event_hook(VALUE tpval, void *data) {
151
150
  rb_event_flag_t event_flag = rb_tracearg_event_flag(trace_arg);
152
151
 
153
152
  rs_callsite_t trace_path;
153
+ bool blacklisted;
154
154
  if (event_flag & EVENT_CALL) {
155
155
  trace_path = tracearg_path(trace_arg);
156
+ blacklisted = rejected_path(trace_path.filepath, config);
156
157
  } else {
157
158
  if (rs_stack_empty(&config->stack)) return;
158
159
  rs_stack_frame_t *call_frame = rs_stack_peek(&config->stack);
159
160
  trace_path = (rs_callsite_t){
160
161
  .filepath = call_frame->tp.filepath, .lineno = call_frame->tp.lineno,
161
162
  };
163
+ blacklisted = call_frame->blacklisted;
162
164
  }
163
165
 
164
166
  rs_tracepoint_t trace = extract_full_tracevals(trace_arg, &trace_path);
165
167
  if (!strcmp("Rotoscope", StringValueCStr(trace.entity))) return;
166
168
 
167
- bool blacklisted;
168
169
  if (event_flag & EVENT_CALL) {
169
- blacklisted = rejected_entity(trace.entity, config);
170
170
  rs_stack_push(&config->stack, trace, blacklisted);
171
171
  } else {
172
- blacklisted = rs_stack_peek(&config->stack)->blacklisted;
173
172
  rs_stack_pop(&config->stack);
174
173
  }
175
174
  if (blacklisted) return;
176
175
 
177
176
  if (config->flatten_output) {
178
177
  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
- }
178
+ rs_stack_frame_t *caller = rs_stack_peek(&config->stack);
179
+ do {
180
+ caller = rs_stack_below(&config->stack, caller);
181
+ } while (caller && caller->blacklisted);
183
182
  if (caller) {
184
183
  log_trace_event_with_caller(config->log, rs_stack_peek(&config->stack),
185
- &config->call_memo);
184
+ caller, &config->call_memo);
186
185
  }
187
186
  }
188
187
  } else {
@@ -215,7 +214,6 @@ static void close_log_handle(Rotoscope *config) {
215
214
  static void rs_gc_mark(Rotoscope *config) {
216
215
  rb_gc_mark(config->log_path);
217
216
  rb_gc_mark(config->tracepoint);
218
- rb_gc_mark(config->entity_whitelist);
219
217
  rs_stack_mark(&config->stack);
220
218
  }
221
219
 
@@ -223,6 +221,7 @@ void rs_dealloc(Rotoscope *config) {
223
221
  close_log_handle(config);
224
222
  rs_stack_free(&config->stack);
225
223
  rs_strmemo_free(config->call_memo);
224
+ xfree(config->blacklist);
226
225
  xfree(config);
227
226
  }
228
227
 
@@ -231,7 +230,6 @@ static VALUE rs_alloc(VALUE klass) {
231
230
  VALUE self =
232
231
  Data_Make_Struct(klass, Rotoscope, rs_gc_mark, rs_dealloc, config);
233
232
  config->log_path = Qnil;
234
- config->entity_whitelist = Qnil;
235
233
  config->tracepoint = rb_tracepoint_new(Qnil, EVENT_CALL | EVENT_RETURN,
236
234
  event_hook, (void *)config);
237
235
  config->pid = getpid();
@@ -245,25 +243,42 @@ static Rotoscope *get_config(VALUE self) {
245
243
  return config;
246
244
  }
247
245
 
248
- bool blacklisted_root(Rotoscope *config) {
249
- return !NIL_P(config->entity_whitelist);
246
+ void copy_blacklist(Rotoscope *config, VALUE blacklist) {
247
+ Check_Type(blacklist, T_ARRAY);
248
+
249
+ size_t blacklist_malloc_size =
250
+ RARRAY_LEN(blacklist) * sizeof(*config->blacklist);
251
+
252
+ for (long i = 0; i < RARRAY_LEN(blacklist); i++) {
253
+ VALUE ruby_string = RARRAY_AREF(blacklist, i);
254
+ Check_Type(ruby_string, T_STRING);
255
+ blacklist_malloc_size += RSTRING_LEN(ruby_string) + 1;
256
+ }
257
+
258
+ config->blacklist = ruby_xmalloc(blacklist_malloc_size);
259
+ config->blacklist_size = RARRAY_LEN(blacklist);
260
+ char *str = (char *)(config->blacklist + config->blacklist_size);
261
+
262
+ for (unsigned long i = 0; i < config->blacklist_size; i++) {
263
+ VALUE ruby_string = RARRAY_AREF(blacklist, i);
264
+
265
+ config->blacklist[i] = str;
266
+ memcpy(str, RSTRING_PTR(ruby_string), RSTRING_LEN(ruby_string));
267
+ str += RSTRING_LEN(ruby_string);
268
+ *str = '\0';
269
+ str++;
270
+ }
250
271
  }
251
272
 
252
273
  VALUE initialize(int argc, VALUE *argv, VALUE self) {
253
274
  Rotoscope *config = get_config(self);
254
- VALUE output_path, entity_whitelist, flatten;
275
+ VALUE output_path, blacklist, flatten;
255
276
 
256
- rb_scan_args(argc, argv, "12", &output_path, &entity_whitelist, &flatten);
277
+ rb_scan_args(argc, argv, "12", &output_path, &blacklist, &flatten);
257
278
  Check_Type(output_path, T_STRING);
258
279
 
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
- }
280
+ if (!NIL_P(blacklist)) {
281
+ copy_blacklist(config, blacklist);
267
282
  }
268
283
 
269
284
  config->flatten_output = RTEST(flatten);
@@ -281,7 +296,7 @@ VALUE initialize(int argc, VALUE *argv, VALUE self) {
281
296
  else
282
297
  write_csv_header(config->log, RS_CSV_HEADER);
283
298
 
284
- rs_stack_init(&config->stack, STACK_CAPACITY, blacklisted_root(config));
299
+ rs_stack_init(&config->stack, STACK_CAPACITY);
285
300
  config->call_memo = NULL;
286
301
  config->state = RS_OPEN;
287
302
  return self;
@@ -299,7 +314,7 @@ VALUE rotoscope_stop_trace(VALUE self) {
299
314
  if (rb_tracepoint_enabled_p(config->tracepoint)) {
300
315
  rb_tracepoint_disable(config->tracepoint);
301
316
  config->state = RS_OPEN;
302
- rs_stack_reset(&config->stack, blacklisted_root(config));
317
+ rs_stack_reset(&config->stack);
303
318
  }
304
319
 
305
320
  return Qnil;
@@ -48,7 +48,8 @@ typedef struct {
48
48
  FILE *log;
49
49
  VALUE log_path;
50
50
  VALUE tracepoint;
51
- VALUE entity_whitelist;
51
+ const char **blacklist;
52
+ unsigned long blacklist_size;
52
53
  bool flatten_output;
53
54
  pid_t pid;
54
55
  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, bool blacklisted) {
8
+ static void insert_root_node(rs_stack_t *stack) {
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, bool blacklisted) {
14
14
  .method_name = rb_unknown_str,
15
15
  .method_level = UNKNOWN_STR,
16
16
  .lineno = 0};
17
- rs_stack_push(stack, root_trace, blacklisted);
17
+ rs_stack_push(stack, root_trace, false);
18
18
  }
19
19
 
20
20
  static void resize_buffer(rs_stack_t *stack) {
@@ -37,10 +37,8 @@ rs_stack_frame_t rs_stack_push(rs_stack_t *stack, rs_tracepoint_t trace,
37
37
  resize_buffer(stack);
38
38
  }
39
39
 
40
- rs_stack_frame_t *caller =
41
- rs_stack_empty(stack) ? NULL : rs_stack_peek(stack);
42
- rs_stack_frame_t new_frame = (rs_stack_frame_t){
43
- .tp = trace, .caller = caller, .blacklisted = blacklisted};
40
+ rs_stack_frame_t new_frame =
41
+ (rs_stack_frame_t){.tp = trace, .blacklisted = blacklisted};
44
42
 
45
43
  stack->contents[++stack->top] = new_frame;
46
44
  return new_frame;
@@ -64,9 +62,21 @@ rs_stack_frame_t *rs_stack_peek(rs_stack_t *stack) {
64
62
  return &stack->contents[stack->top];
65
63
  }
66
64
 
67
- void rs_stack_reset(rs_stack_t *stack, bool blacklisted_root) {
65
+ rs_stack_frame_t *rs_stack_below(rs_stack_t *stack, rs_stack_frame_t *frame) {
66
+ if (frame < stack->contents || frame > stack->contents + stack->top) {
67
+ fprintf(stderr, "Invalid stack frame (bottom: %p, frame: %p, top: %p)\n",
68
+ stack->contents, frame, &stack->contents[stack->top]);
69
+ exit(1);
70
+ } else if (stack->contents == frame) {
71
+ return NULL;
72
+ } else {
73
+ return frame - 1;
74
+ }
75
+ }
76
+
77
+ void rs_stack_reset(rs_stack_t *stack) {
68
78
  stack->top = -1;
69
- insert_root_node(stack, blacklisted_root);
79
+ insert_root_node(stack);
70
80
  }
71
81
 
72
82
  void rs_stack_free(rs_stack_t *stack) {
@@ -76,14 +86,13 @@ void rs_stack_free(rs_stack_t *stack) {
76
86
  stack->capacity = 0;
77
87
  }
78
88
 
79
- void rs_stack_init(rs_stack_t *stack, unsigned int capacity,
80
- bool blacklisted_root) {
89
+ void rs_stack_init(rs_stack_t *stack, unsigned int capacity) {
81
90
  rs_stack_frame_t *contents = ALLOC_N(rs_stack_frame_t, capacity);
82
91
  stack->contents = contents;
83
92
  stack->capacity = capacity;
84
93
  stack->top = -1;
85
94
 
86
- insert_root_node(stack, blacklisted_root);
95
+ insert_root_node(stack);
87
96
  }
88
97
 
89
98
  void rs_stack_mark(rs_stack_t *stack) {
@@ -8,7 +8,6 @@
8
8
  typedef struct rs_stack_frame_t {
9
9
  struct rs_tracepoint_t tp;
10
10
  bool blacklisted;
11
- struct rs_stack_frame_t *caller;
12
11
  } rs_stack_frame_t;
13
12
 
14
13
  typedef struct {
@@ -17,14 +16,15 @@ typedef struct {
17
16
  rs_stack_frame_t *contents;
18
17
  } rs_stack_t;
19
18
 
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);
19
+ void rs_stack_init(rs_stack_t *stack, unsigned int capacity);
20
+ void rs_stack_reset(rs_stack_t *stack);
22
21
  void rs_stack_free(rs_stack_t *stack);
23
22
  rs_stack_frame_t rs_stack_push(rs_stack_t *stack, rs_tracepoint_t trace, bool backlisted);
24
23
  bool rs_stack_empty(rs_stack_t *stack);
25
24
  bool rs_stack_full(rs_stack_t *stack);
26
25
  rs_stack_frame_t rs_stack_pop(rs_stack_t *stack);
27
26
  rs_stack_frame_t *rs_stack_peek(rs_stack_t *stack);
27
+ rs_stack_frame_t *rs_stack_below(rs_stack_t *stack, rs_stack_frame_t *frame);
28
28
  void rs_stack_mark(rs_stack_t *stack);
29
29
 
30
30
  #endif
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, entity_whitelist: nil, flatten: false)
10
- super(output_path, entity_whitelist, flatten)
9
+ def new(output_path, blacklist: [], flatten: false)
10
+ super(output_path, blacklist, flatten)
11
11
  end
12
12
 
13
- def trace(dest, entity_whitelist: nil, flatten: false, &block)
14
- config = { entity_whitelist: entity_whitelist, flatten: flatten }
13
+ def trace(dest, blacklist: [], flatten: false, &block)
14
+ config = { blacklist: blacklist, 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, entity_whitelist: config[:entity_whitelist], flatten: config[:flatten])
48
+ rs = Rotoscope.new(dest_path, blacklist: config[:blacklist], 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.3"
3
+ VERSION = "0.3.0.pre.4"
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.3
4
+ version: 0.3.0.pre.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jahfer Husain