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 +4 -4
- data/README.md +1 -1
- data/Rakefile +2 -0
- data/ext/rotoscope/rotoscope.c +74 -42
- data/ext/rotoscope/rotoscope.h +15 -11
- data/ext/rotoscope/stack.c +4 -5
- data/ext/rotoscope/stack.h +2 -2
- data/ext/rotoscope/tracepoint.c +18 -0
- data/ext/rotoscope/tracepoint.h +13 -1
- data/lib/rotoscope/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 214bc0f95d10e738330ccf96ad98195588ce2fed
|
4
|
+
data.tar.gz: c8be5f0941288a7a5242e830b17c98de16935022
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
[![
|
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
data/ext/rotoscope/rotoscope.c
CHANGED
@@ -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
|
123
|
-
|
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
|
-
|
127
|
-
|
128
|
-
|
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
|
-
|
136
|
-
|
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
|
-
|
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
|
-
|
157
|
-
|
158
|
-
if (
|
159
|
-
|
160
|
-
blacklisted
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
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
|
-
|
174
|
-
|
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 (
|
180
|
-
|
181
|
-
if (
|
182
|
-
|
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);
|
data/ext/rotoscope/rotoscope.h
CHANGED
@@ -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(
|
22
|
-
StringValueCStr(
|
23
|
-
|
24
|
-
StringValueCStr(
|
25
|
-
|
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
|
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(
|
35
|
-
_RS_COMMON_CSV_VALUES(
|
36
|
-
StringValueCStr(
|
37
|
-
StringValueCStr(
|
38
|
-
|
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 {
|
data/ext/rotoscope/stack.c
CHANGED
@@ -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);
|
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 =
|
43
|
-
.tp = trace, .caller = caller
|
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;
|
data/ext/rotoscope/stack.h
CHANGED
@@ -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
|
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);
|
data/ext/rotoscope/tracepoint.c
CHANGED
@@ -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
|
}
|
data/ext/rotoscope/tracepoint.h
CHANGED
@@ -1,7 +1,18 @@
|
|
1
1
|
#ifndef _INC_ROTOSCOPE_TRACEPOINT_H_
|
2
2
|
#define _INC_ROTOSCOPE_TRACEPOINT_H_
|
3
3
|
|
4
|
-
#include
|
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);
|
data/lib/rotoscope/version.rb
CHANGED
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.
|
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.
|
123
|
+
rubygems_version: 2.6.14
|
124
124
|
signing_key:
|
125
125
|
specification_version: 4
|
126
126
|
summary: Tracing Ruby
|