Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add raw line numbers for raw mode #213

Merged
merged 1 commit into from
Jul 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions ext/stackprof/stackprof.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ static struct {
VALUE metadata;
int ignore_gc;

VALUE *raw_samples;
uint64_t *raw_samples;
size_t raw_samples_len;
size_t raw_samples_capa;
size_t raw_sample_index;
Expand Down Expand Up @@ -133,7 +133,7 @@ static struct {

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_raw, sym_metadata, sym_frames, sym_ignore_gc, sym_out;
static VALUE sym_version, sym_mode, sym_interval, sym_raw, sym_raw_lines, sym_metadata, sym_frames, sym_ignore_gc, sym_out;
static VALUE sym_aggregate, sym_raw_sample_timestamps, sym_raw_timestamp_deltas, sym_state, sym_marking, sym_sweeping;
static VALUE sym_gc_samples, objtracer;
static VALUE gc_hook;
Expand Down Expand Up @@ -374,14 +374,23 @@ stackprof_results(int argc, VALUE *argv, VALUE self)
size_t len, n, o;
VALUE raw_sample_timestamps, raw_timestamp_deltas;
VALUE raw_samples = rb_ary_new_capa(_stackprof.raw_samples_len);
VALUE raw_lines = rb_ary_new_capa(_stackprof.raw_samples_len);

for (n = 0; n < _stackprof.raw_samples_len; n++) {
len = (size_t)_stackprof.raw_samples[n];
rb_ary_push(raw_samples, SIZET2NUM(len));
rb_ary_push(raw_lines, SIZET2NUM(len));

for (o = 0, n++; o < len; n++, o++) {
// Line is in the upper 16 bits
rb_ary_push(raw_lines, INT2NUM(_stackprof.raw_samples[n] >> 48));

VALUE frame = _stackprof.raw_samples[n] & ~((uint64_t)0xFFFF << 48);
rb_ary_push(raw_samples, PTR2NUM(frame));
}

for (o = 0, n++; o < len; n++, o++)
rb_ary_push(raw_samples, PTR2NUM(_stackprof.raw_samples[n]));
rb_ary_push(raw_samples, SIZET2NUM((size_t)_stackprof.raw_samples[n]));
rb_ary_push(raw_lines, SIZET2NUM((size_t)_stackprof.raw_samples[n]));
}

free(_stackprof.raw_samples);
Expand All @@ -391,6 +400,7 @@ stackprof_results(int argc, VALUE *argv, VALUE self)
_stackprof.raw_sample_index = 0;

rb_hash_aset(results, sym_raw, raw_samples);
rb_hash_aset(results, sym_raw_lines, raw_lines);

raw_sample_timestamps = rb_ary_new_capa(_stackprof.raw_sample_times_len);
raw_timestamp_deltas = rb_ary_new_capa(_stackprof.raw_sample_times_len);
Expand Down Expand Up @@ -520,7 +530,12 @@ stackprof_record_sample_for_stack(int num, uint64_t sample_timestamp, int64_t ti
* in the frames buffer that came from Ruby. */
for (i = num-1, n = 0; i >= 0; i--, n++) {
VALUE frame = _stackprof.frames_buffer[i];
if (_stackprof.raw_samples[_stackprof.raw_sample_index + 1 + n] != frame)
int line = _stackprof.lines_buffer[i];

// Encode the line in to the upper 16 bits.
uint64_t key = ((uint64_t)line << 48) | (uint64_t)frame;

if (_stackprof.raw_samples[_stackprof.raw_sample_index + 1 + n] != key)
break;
}
if (i == -1) {
Expand All @@ -538,7 +553,12 @@ stackprof_record_sample_for_stack(int num, uint64_t sample_timestamp, int64_t ti
_stackprof.raw_samples[_stackprof.raw_samples_len++] = (VALUE)num;
for (i = num-1; i >= 0; i--) {
VALUE frame = _stackprof.frames_buffer[i];
_stackprof.raw_samples[_stackprof.raw_samples_len++] = frame;
int line = _stackprof.lines_buffer[i];

// Encode the line in to the upper 16 bits.
uint64_t key = ((uint64_t)line << 48) | (uint64_t)frame;

_stackprof.raw_samples[_stackprof.raw_samples_len++] = key;
}
_stackprof.raw_samples[_stackprof.raw_samples_len++] = (VALUE)1;
}
Expand Down Expand Up @@ -894,6 +914,7 @@ Init_stackprof(void)
S(mode);
S(interval);
S(raw);
S(raw_lines);
S(raw_sample_timestamps);
S(raw_timestamp_deltas);
S(out);
Expand Down
3 changes: 3 additions & 0 deletions test/test_stackprof.rb
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,13 @@ def test_raw
after_monotonic = Process.clock_gettime(Process::CLOCK_MONOTONIC, :microsecond)

raw = profile[:raw]
raw_lines = profile[:raw_lines]
assert_equal 10, raw[-1]
assert_equal raw[0] + 2, raw.size
assert_equal 10, raw_lines[-1] # seen 10 times

offset = RUBY_VERSION >= '3' ? -3 : -2
assert_equal 140, raw_lines[offset] # sample caller is on 140
assert_includes profile[:frames][raw[offset]][:name], 'StackProfTest#test_raw'

assert_equal 10, profile[:raw_sample_timestamps].size
Expand Down