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

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