rotoscope 0.3.0.pre.1 → 0.3.0.pre.2
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 +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
|
-
[](https://travis-ci.org/Shopify/rotoscope) [](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
|