rotoscope 0.3.0.pre.1 → 0.3.0.pre.2

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: 8a94009a6d6ee2a34d124e8b922feb3ff3eda7f2
4
- data.tar.gz: eab31fe889c50ea034197aa1a435ccb22c832630
3
+ metadata.gz: 214bc0f95d10e738330ccf96ad98195588ce2fed
4
+ data.tar.gz: c8be5f0941288a7a5242e830b17c98de16935022
5
5
  SHA512:
6
- metadata.gz: 8ab381c724461c0b5dbab3a8dbbbf3e451c5aae060b8aecbaa9f28abc4d7aa636ecf7cd451b68537e104e13fc53c45243c47e4b44b48875f58bf1e32902a3f58
7
- data.tar.gz: 5a598811ac79f0524d0e2d93d28a727a51e296cb575ed1de9b98e0f1b3921927b8557873e0bdcc682b8f7d09136f6d347c5d6eb2f8a7192bf39355a01e26f228
6
+ metadata.gz: 0af5d811380da0de299478d7176a09308c1c2ff3a54ea77be54df01e4c34213d8208407b30a90ef34b19d07395c34e2b08395db7a2ba0b0eb783dff8c039b5a8
7
+ data.tar.gz: 577ec0a7a6bfc747bc3cde9d80b854aab30cd4804f60ad844273b917741c78f8900d043e87b4eb9a0905884c421e282e0cfe991a62d37ebfef6b7906114bb10d
data/README.md CHANGED
@@ -4,7 +4,7 @@ Rotoscope is a high-performance logger of Ruby method invocations.
4
4
 
5
5
  ## Status
6
6
 
7
- [![status](https://circleci.com/gh/Shopify/rotoscope/tree/master.svg?style=shield&circle-token=cddbd315df7a81ab944adf4dfc14a5800cd589fc)](https://circleci.com/gh/Shopify/rotoscope/tree/master) [![Gem Version](https://badge.fury.io/rb/rotoscope.svg)](https://badge.fury.io/rb/rotoscope)
7
+ [![Build Status](https://travis-ci.org/Shopify/rotoscope.svg?branch=master)](https://travis-ci.org/Shopify/rotoscope) [![Gem Version](https://badge.fury.io/rb/rotoscope.svg)](https://badge.fury.io/rb/rotoscope)
8
8
 
9
9
  Rotoscope is subject to breaking changes in minor versions until `1.0` is available.
10
10
 
data/Rakefile CHANGED
@@ -4,7 +4,9 @@
4
4
  # ==========================================================
5
5
  GEMSPEC = Gem::Specification.load('rotoscope.gemspec')
6
6
 
7
+ require 'bundler/gem_tasks'
7
8
  require 'rubygems/package_task'
9
+
8
10
  Gem::PackageTask.new(GEMSPEC) do |pkg|
9
11
  end
10
12
 
@@ -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, cInstructionSeq;
17
+ ID id_initialize, id_of, id_label;
18
18
 
19
19
  static unsigned long gettid() {
20
20
  return NUM2ULONG(rb_obj_id(rb_thread_current()));
@@ -108,7 +108,6 @@ static rs_tracepoint_t extract_full_tracevals(rb_trace_arg_t *trace_arg,
108
108
 
109
109
  VALUE method_name = tracearg_method_name(trace_arg);
110
110
  VALUE filepath = callsite->filepath;
111
-
112
111
  return (rs_tracepoint_t){.event = evflag2name(event_flag),
113
112
  .entity = method_owner.name,
114
113
  .filepath = filepath,
@@ -119,30 +118,58 @@ static rs_tracepoint_t extract_full_tracevals(rb_trace_arg_t *trace_arg,
119
118
 
120
119
  static bool in_fork(Rotoscope *config) { return config->pid != getpid(); }
121
120
 
122
- static void log_trace_event(FILE *stream, rs_tracepoint_t *trace) {
123
- fprintf(stream, RS_CSV_FORMAT "\n", RS_CSV_VALUES(trace));
121
+ static VALUE unsafe_obj_method(VALUE argv) {
122
+ VALUE *args = (VALUE *)argv;
123
+ return rb_obj_method(args[0], args[1]);
124
124
  }
125
+ static VALUE nil_method(VALUE *args) { return Qnil; }
125
126
 
126
- unsigned char output_buffer[LOG_BUFFER_SIZE];
127
- static void log_trace_event_with_caller(FILE *stream,
128
- rs_stack_frame_t *stack_frame,
129
- rs_strmemo_t **call_memo) {
130
- rs_stack_frame_t *caller = stack_frame->caller;
131
- while (caller->blacklisted) {
132
- caller = caller->caller;
133
- }
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;
134
130
 
135
- snprintf((char *)output_buffer, LOG_BUFFER_SIZE, RS_FLATTENED_CSV_FORMAT "\n",
136
- RS_FLATTENED_CSV_VALUES(&stack_frame->tp, &caller->tp));
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;
137
139
 
138
- if (rs_strmemo_uniq(call_memo, output_buffer)) {
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;
143
+ }
144
+
145
+ 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)) {
139
151
  fputs((char *)output_buffer, stream);
140
152
  }
141
153
  }
142
154
 
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
+ }
163
+
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;
169
+ }
170
+
143
171
  static void event_hook(VALUE tpval, void *data) {
144
172
  Rotoscope *config = (Rotoscope *)data;
145
-
146
173
  if (config->tid != gettid()) return;
147
174
  if (in_fork(config)) {
148
175
  rb_tracepoint_disable(config->tracepoint);
@@ -152,39 +179,41 @@ static void event_hook(VALUE tpval, void *data) {
152
179
 
153
180
  rb_trace_arg_t *trace_arg = rb_tracearg_from_tracepoint(tpval);
154
181
  rb_event_flag_t event_flag = rb_tracearg_event_flag(trace_arg);
155
-
156
- rs_callsite_t trace_path;
157
- bool blacklisted;
158
- if (event_flag & EVENT_CALL) {
159
- trace_path = tracearg_path(trace_arg);
160
- blacklisted = rejected_path(trace_path.filepath, config);
161
- } else {
162
- if (rs_stack_empty(&config->stack)) return;
163
- rs_stack_frame_t *call_frame = rs_stack_peek(&config->stack);
164
- trace_path = (rs_callsite_t){
165
- .filepath = call_frame->tp.filepath, .lineno = call_frame->tp.lineno,
166
- };
167
- blacklisted = call_frame->blacklisted;
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;
168
195
  }
169
196
 
170
197
  rs_tracepoint_t trace = extract_full_tracevals(trace_arg, &trace_path);
198
+ trace.raw = raw_trace;
199
+
171
200
  if (!strcmp("Rotoscope", StringValueCStr(trace.entity))) return;
172
201
 
173
- if (event_flag & EVENT_CALL) {
174
- rs_stack_push(&config->stack, trace, blacklisted);
202
+ rs_stack_frame_t frame;
203
+ if (METHOD_CALL_P(event_flag)) {
204
+ frame = rs_stack_push(&config->stack, trace);
175
205
  } 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
+ }
176
210
  rs_stack_pop(&config->stack);
177
211
  }
178
212
 
179
- if (blacklisted) return;
180
-
181
- if (config->flatten_output) {
182
- if (event_flag & EVENT_CALL) {
183
- log_trace_event_with_caller(config->log, rs_stack_peek(&config->stack),
184
- &config->call_memo);
185
- }
186
- } else {
187
- log_trace_event(config->log, &trace);
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);
188
217
  }
189
218
  }
190
219
 
@@ -313,7 +342,6 @@ VALUE rotoscope_stop_trace(VALUE self) {
313
342
  if (rb_tracepoint_enabled_p(config->tracepoint)) {
314
343
  rb_tracepoint_disable(config->tracepoint);
315
344
  config->state = RS_OPEN;
316
- rs_stack_reset(&config->stack, STACK_CAPACITY);
317
345
  }
318
346
 
319
347
  return Qnil;
@@ -368,9 +396,13 @@ VALUE rotoscope_state(VALUE self) {
368
396
  }
369
397
 
370
398
  void Init_rotoscope(void) {
399
+ VALUE cRubyVm = rb_const_get(rb_cObject, rb_intern("RubyVM"));
400
+ cInstructionSeq = rb_const_get(cRubyVm, rb_intern("InstructionSequence"));
371
401
  cTracePoint = rb_const_get(rb_cObject, rb_intern("TracePoint"));
372
402
 
373
403
  id_initialize = rb_intern("initialize");
404
+ id_of = rb_intern("of");
405
+ id_label = rb_intern("label");
374
406
 
375
407
  cRotoscope = rb_define_class("Rotoscope", rb_cObject);
376
408
  rb_define_alloc_func(cRotoscope, rs_alloc);
@@ -7,10 +7,14 @@
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
10
12
 
11
13
  #define CLASS_METHOD "class"
12
14
  #define INSTANCE_METHOD "instance"
13
15
 
16
+ #define VM_BLOCK_PREFIX "block "
17
+
14
18
  #define STACK_CAPACITY 500
15
19
  #define LOG_BUFFER_SIZE 1000
16
20
 
@@ -18,24 +22,24 @@
18
22
  #define _RS_COMMON_CSV_HEADER "entity,method_name,method_level,filepath,lineno"
19
23
  #define _RS_COMMON_CSV_FORMAT "\"%s\",\"%s\",%s,\"%s\",%d"
20
24
  #define _RS_COMMON_CSV_VALUES(trace) \
21
- StringValueCStr((trace)->entity), \
22
- StringValueCStr((trace)->method_name), \
23
- (trace)->method_level, \
24
- StringValueCStr((trace)->filepath), \
25
- (trace)->lineno
25
+ StringValueCStr(trace.entity), \
26
+ StringValueCStr(trace.method_name), \
27
+ trace.method_level, \
28
+ StringValueCStr(trace.filepath), \
29
+ trace.lineno
26
30
 
27
31
  #define RS_CSV_HEADER "event," _RS_COMMON_CSV_HEADER
28
32
  #define RS_CSV_FORMAT "%s," _RS_COMMON_CSV_FORMAT
29
- #define RS_CSV_VALUES(trace) trace->event, _RS_COMMON_CSV_VALUES(trace)
33
+ #define RS_CSV_VALUES(trace) trace.event, _RS_COMMON_CSV_VALUES(trace)
30
34
 
31
35
  #define RS_FLATTENED_CSV_HEADER \
32
36
  _RS_COMMON_CSV_HEADER ",caller_entity,caller_method_name,caller_method_level"
33
37
  #define RS_FLATTENED_CSV_FORMAT _RS_COMMON_CSV_FORMAT ",\"%s\",\"%s\",%s"
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
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
39
43
  // clang-format on
40
44
 
41
45
  typedef enum {
@@ -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, false);
17
+ rs_stack_push(stack, root_trace);
18
18
  }
19
19
 
20
20
  static void resize_buffer(rs_stack_t *stack) {
@@ -31,16 +31,15 @@ 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,
35
- bool blacklisted) {
34
+ rs_stack_frame_t rs_stack_push(rs_stack_t *stack, rs_tracepoint_t trace) {
36
35
  if (rs_stack_full(stack)) {
37
36
  resize_buffer(stack);
38
37
  }
39
38
 
40
39
  rs_stack_frame_t *caller =
41
40
  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};
41
+ rs_stack_frame_t new_frame =
42
+ (rs_stack_frame_t){.tp = trace, .caller = caller};
44
43
 
45
44
  stack->contents[++stack->top] = new_frame;
46
45
  return new_frame;
@@ -1,5 +1,6 @@
1
1
  #ifndef _INC_ROTOSCOPE_STACK_H_
2
2
  #define _INC_ROTOSCOPE_STACK_H_
3
+
3
4
  #include <stdbool.h>
4
5
  #include "tracepoint.h"
5
6
 
@@ -7,7 +8,6 @@
7
8
 
8
9
  typedef struct rs_stack_frame_t {
9
10
  struct rs_tracepoint_t tp;
10
- bool blacklisted;
11
11
  struct rs_stack_frame_t *caller;
12
12
  } rs_stack_frame_t;
13
13
 
@@ -20,7 +20,7 @@ typedef struct {
20
20
  void rs_stack_init(rs_stack_t *stack, unsigned int capacity);
21
21
  void rs_stack_reset(rs_stack_t *stack, unsigned int capacity);
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, bool backlisted);
23
+ rs_stack_frame_t rs_stack_push(rs_stack_t *stack, rs_tracepoint_t trace);
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,8 +1,26 @@
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
+
4
17
  void rs_tracepoint_mark(rs_tracepoint_t *tracepoint) {
5
18
  rb_gc_mark(tracepoint->entity);
6
19
  rb_gc_mark(tracepoint->filepath);
7
20
  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);
8
26
  }
@@ -1,7 +1,18 @@
1
1
  #ifndef _INC_ROTOSCOPE_TRACEPOINT_H_
2
2
  #define _INC_ROTOSCOPE_TRACEPOINT_H_
3
3
 
4
- #include "ruby.h"
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);
5
16
 
6
17
  typedef struct rs_tracepoint_t {
7
18
  const char *event;
@@ -10,6 +21,7 @@ typedef struct rs_tracepoint_t {
10
21
  VALUE method_name;
11
22
  const char *method_level;
12
23
  unsigned int lineno;
24
+ rs_raw_tracepoint_t raw;
13
25
  } rs_tracepoint_t;
14
26
 
15
27
  void rs_tracepoint_mark(rs_tracepoint_t *tracepoint);
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  class Rotoscope
3
- VERSION = "0.3.0.pre.1"
3
+ VERSION = "0.3.0.pre.2"
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.1
4
+ version: 0.3.0.pre.2
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.13
123
+ rubygems_version: 2.6.14
124
124
  signing_key:
125
125
  specification_version: 4
126
126
  summary: Tracing Ruby