ext/stackprof.c in stackprof-0.2.2 vs ext/stackprof.c in stackprof-0.2.3
- old
+ new
@@ -1,22 +1,18 @@
/**********************************************************************
stackprof.c - Sampling call-stack frame profiler for MRI.
- $Author$
- created at: Thu May 30 17:55:25 2013
+ vim: setl noexpandtab shiftwidth=4 tabstop=8 softtabstop=4
- NOTE: This extension library is not expected to exist except C Ruby.
-
- All the files in this distribution are covered under the Ruby's
- license (see the file COPYING).
-
**********************************************************************/
#include <ruby/ruby.h>
#include <ruby/debug.h>
#include <ruby/st.h>
+#include <ruby/io.h>
+#include <ruby/intern.h>
#include <signal.h>
#include <sys/time.h>
#include <pthread.h>
#define BUF_SIZE 2048
@@ -30,10 +26,13 @@
static struct {
int running;
VALUE mode;
VALUE interval;
+ VALUE raw;
+ size_t raw_sample_index;
+ VALUE out;
size_t overall_signals;
size_t overall_samples;
size_t during_gc;
st_table *frames;
@@ -42,11 +41,11 @@
int lines_buffer[BUF_SIZE];
} _stackprof;
static VALUE sym_object, sym_wall, sym_cpu, sym_custom, sym_name, sym_file, sym_line;
static VALUE sym_samples, sym_total_samples, sym_missed_samples, sym_edges, sym_lines;
-static VALUE sym_version, sym_mode, sym_interval, sym_frames;
+static VALUE sym_version, sym_mode, sym_interval, sym_raw, sym_frames, sym_out;
static VALUE sym_gc_samples, objtracer;
static VALUE gc_hook;
static VALUE rb_mStackProf;
static void stackprof_newobj_handler(VALUE, void*);
@@ -55,20 +54,24 @@
static VALUE
stackprof_start(int argc, VALUE *argv, VALUE self)
{
struct sigaction sa;
struct itimerval timer;
- VALUE opts = Qnil, mode = Qnil, interval = Qnil;
+ VALUE opts = Qnil, mode = Qnil, interval = Qnil, raw = Qfalse, out = Qfalse;
if (_stackprof.running)
return Qfalse;
rb_scan_args(argc, argv, "0:", &opts);
if (RTEST(opts)) {
mode = rb_hash_aref(opts, sym_mode);
interval = rb_hash_aref(opts, sym_interval);
+ out = rb_hash_aref(opts, sym_out);
+
+ if (RTEST(rb_hash_aref(opts, sym_raw)))
+ raw = rb_ary_new();
}
if (!RTEST(mode)) mode = sym_wall;
if (!_stackprof.frames) {
_stackprof.frames = st_init_numtable();
@@ -100,12 +103,14 @@
} else {
rb_raise(rb_eArgError, "unknown profiler mode");
}
_stackprof.running = 1;
+ _stackprof.raw = raw;
_stackprof.mode = mode;
_stackprof.interval = interval;
+ _stackprof.out = out;
return Qtrue;
}
static VALUE
@@ -205,11 +210,11 @@
xfree(frame_data);
return ST_DELETE;
}
static VALUE
-stackprof_results(VALUE self)
+stackprof_results(int argc, VALUE *argv, VALUE self)
{
VALUE results, frames;
if (!_stackprof.frames || _stackprof.running)
return Qnil;
@@ -227,20 +232,41 @@
st_foreach(_stackprof.frames, frame_i, (st_data_t)frames);
st_free_table(_stackprof.frames);
_stackprof.frames = NULL;
- return results;
+ if (RTEST(_stackprof.raw)) {
+ rb_hash_aset(results, sym_raw, _stackprof.raw);
+ _stackprof.raw = Qfalse;
+ }
+
+ if (argc == 1)
+ _stackprof.out = argv[0];
+
+ if (RTEST(_stackprof.out)) {
+ VALUE file;
+ if (RB_TYPE_P(_stackprof.out, T_STRING)) {
+ file = rb_file_open_str(_stackprof.out, "w");
+ } else {
+ file = rb_io_check_io(_stackprof.out);
+ }
+ rb_marshal_dump(results, file);
+ rb_io_flush(file);
+ _stackprof.out = Qnil;
+ return file;
+ } else {
+ return results;
+ }
}
static VALUE
stackprof_run(int argc, VALUE *argv, VALUE self)
{
rb_need_block();
stackprof_start(argc, argv, self);
rb_ensure(rb_yield, Qundef, stackprof_stop, self);
- return stackprof_results(self);
+ return stackprof_results(0, 0, self);
}
static VALUE
stackprof_running_p(VALUE self)
{
@@ -286,16 +312,45 @@
}
void
stackprof_record_sample()
{
- int num, i;
+ int num, i, n;
+ int raw_mode = RTEST(_stackprof.raw);
VALUE prev_frame = Qnil;
+ size_t raw_len;
_stackprof.overall_samples++;
num = rb_profile_frames(0, sizeof(_stackprof.frames_buffer), _stackprof.frames_buffer, _stackprof.lines_buffer);
+ if (raw_mode) {
+ int found = 0;
+ raw_len = RARRAY_LEN(_stackprof.raw);
+
+ if (RARRAY_LEN(_stackprof.raw) > 0 && RARRAY_AREF(_stackprof.raw, _stackprof.raw_sample_index) == INT2FIX(num)) {
+ for (i = num-1, n = 0; i >= 0; i--, n++) {
+ VALUE frame = _stackprof.frames_buffer[i];
+ if (RARRAY_AREF(_stackprof.raw, _stackprof.raw_sample_index + 1 + n) != rb_obj_id(frame))
+ break;
+ }
+ if (i == -1) {
+ RARRAY_ASET(_stackprof.raw, raw_len-1, LONG2NUM(NUM2LONG(RARRAY_AREF(_stackprof.raw, raw_len-1))+1));
+ found = 1;
+ }
+ }
+
+ if (!found) {
+ _stackprof.raw_sample_index = raw_len;
+ rb_ary_push(_stackprof.raw, INT2FIX(num));
+ for (i = num-1; i >= 0; i--) {
+ VALUE frame = _stackprof.frames_buffer[i];
+ rb_ary_push(_stackprof.raw, rb_obj_id(frame));
+ }
+ rb_ary_push(_stackprof.raw, INT2FIX(1));
+ }
+ }
+
for (i = 0; i < num; i++) {
int line = _stackprof.lines_buffer[i];
VALUE frame = _stackprof.frames_buffer[i];
frame_data_t *frame_data = sample_for(frame);
@@ -344,10 +399,11 @@
}
static void
stackprof_newobj_handler(VALUE tpval, void *data)
{
+ /* TODO: implement interval */
_stackprof.overall_signals++;
stackprof_job_handler(0);
}
static VALUE
@@ -370,10 +426,15 @@
}
static void
stackprof_gc_mark(void *data)
{
+ if (RTEST(_stackprof.raw))
+ rb_gc_mark(_stackprof.raw);
+ if (RTEST(_stackprof.out))
+ rb_gc_mark(_stackprof.out);
+
if (_stackprof.frames)
st_foreach(_stackprof.frames, frame_mark_i, 0);
}
static void
@@ -425,20 +486,22 @@
sym_edges = ID2SYM(rb_intern("edges"));
sym_lines = ID2SYM(rb_intern("lines"));
sym_version = ID2SYM(rb_intern("version"));
sym_mode = ID2SYM(rb_intern("mode"));
sym_interval = ID2SYM(rb_intern("interval"));
+ sym_raw = ID2SYM(rb_intern("raw"));
+ sym_out = ID2SYM(rb_intern("out"));
sym_frames = ID2SYM(rb_intern("frames"));
gc_hook = Data_Wrap_Struct(rb_cObject, stackprof_gc_mark, NULL, NULL);
rb_global_variable(&gc_hook);
rb_mStackProf = rb_define_module("StackProf");
rb_define_singleton_method(rb_mStackProf, "running?", stackprof_running_p, 0);
rb_define_singleton_method(rb_mStackProf, "run", stackprof_run, -1);
rb_define_singleton_method(rb_mStackProf, "start", stackprof_start, -1);
rb_define_singleton_method(rb_mStackProf, "stop", stackprof_stop, 0);
- rb_define_singleton_method(rb_mStackProf, "results", stackprof_results, 0);
+ rb_define_singleton_method(rb_mStackProf, "results", stackprof_results, -1);
rb_define_singleton_method(rb_mStackProf, "sample", stackprof_sample, 0);
rb_autoload(rb_mStackProf, rb_intern_const("Report"), "stackprof/report.rb");
rb_autoload(rb_mStackProf, rb_intern_const("Middleware"), "stackprof/middleware.rb");