ext/stackprof/stackprof.c in stackprof-0.2.12 vs ext/stackprof/stackprof.c in stackprof-0.2.13
- old
+ new
@@ -307,15 +307,16 @@
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 {
+ if (rb_respond_to(_stackprof.out, rb_intern("to_io"))) {
file = rb_io_check_io(_stackprof.out);
+ } else {
+ file = rb_file_open_str(_stackprof.out, "w");
}
+
rb_marshal_dump(results, file);
rb_io_flush(file);
_stackprof.out = Qnil;
return file;
} else {
@@ -385,21 +386,33 @@
_stackprof.overall_samples++;
if (_stackprof.raw) {
int found = 0;
+ /* If there's no sample buffer allocated, then allocate one. The buffer
+ * format is the number of frames (num), then the list of frames (from
+ * `_stackprof.raw_samples`), followed by the number of times this
+ * particular stack has been seen in a row. Each "new" stack is added
+ * to the end of the buffer, but if the previous stack is the same as
+ * the current stack, the counter will be incremented. */
if (!_stackprof.raw_samples) {
_stackprof.raw_samples_capa = num * 100;
_stackprof.raw_samples = malloc(sizeof(VALUE) * _stackprof.raw_samples_capa);
}
+ /* If we can't fit all the samples in the buffer, double the buffer size. */
while (_stackprof.raw_samples_capa <= _stackprof.raw_samples_len + (num + 2)) {
_stackprof.raw_samples_capa *= 2;
_stackprof.raw_samples = realloc(_stackprof.raw_samples, sizeof(VALUE) * _stackprof.raw_samples_capa);
}
+ /* If we've seen this stack before in the last sample, then increment the "seen" count. */
if (_stackprof.raw_samples_len > 0 && _stackprof.raw_samples[_stackprof.raw_sample_index] == (VALUE)num) {
+ /* The number of samples could have been the same, but the stack
+ * might be different, so we need to check the stack here. Stacks
+ * in the raw buffer are stored in the opposite direction of stacks
+ * 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)
break;
}
@@ -407,31 +420,38 @@
_stackprof.raw_samples[_stackprof.raw_samples_len-1] += 1;
found = 1;
}
}
+ /* If we haven't seen the stack, then add it to the buffer along with
+ * the length of the stack and a 1 for the "seen" count */
if (!found) {
+ /* Bump the `raw_sample_index` up so that the next iteration can
+ * find the previously recorded stack size. */
_stackprof.raw_sample_index = _stackprof.raw_samples_len;
_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;
}
_stackprof.raw_samples[_stackprof.raw_samples_len++] = (VALUE)1;
}
+ /* If there's no timestamp delta buffer, allocate one */
if (!_stackprof.raw_timestamp_deltas) {
_stackprof.raw_timestamp_deltas_capa = 100;
_stackprof.raw_timestamp_deltas = malloc(sizeof(int) * _stackprof.raw_timestamp_deltas_capa);
_stackprof.raw_timestamp_deltas_len = 0;
}
+ /* Double the buffer size if it's too small */
while (_stackprof.raw_timestamp_deltas_capa <= _stackprof.raw_timestamp_deltas_len + 1) {
_stackprof.raw_timestamp_deltas_capa *= 2;
_stackprof.raw_timestamp_deltas = realloc(_stackprof.raw_timestamp_deltas, sizeof(int) * _stackprof.raw_timestamp_deltas_capa);
}
+ /* Store the time delta (which is the amount of time between samples) */
_stackprof.raw_timestamp_deltas[_stackprof.raw_timestamp_deltas_len++] = timestamp_delta;
}
for (i = 0; i < num; i++) {
int line = _stackprof.lines_buffer[i];
@@ -494,20 +514,20 @@
gettimeofday(&t, NULL);
timersub(&t, &_stackprof.last_sample_at, &diff);
// We don't know when the GC samples were actually marked, so let's
// assume that they were marked at a perfectly regular interval.
- delta_to_first_unrecorded_gc_sample = (1000 * diff.tv_sec + diff.tv_usec) - (_stackprof.unrecorded_gc_samples - 1) * _stackprof.interval;
+ delta_to_first_unrecorded_gc_sample = (1000 * diff.tv_sec + diff.tv_usec) - (_stackprof.unrecorded_gc_samples - 1) * NUM2LONG(_stackprof.interval);
if (delta_to_first_unrecorded_gc_sample < 0) {
delta_to_first_unrecorded_gc_sample = 0;
}
}
_stackprof.frames_buffer[0] = _stackprof.fake_gc_frame;
_stackprof.lines_buffer[0] = 0;
for (i = 0; i < _stackprof.unrecorded_gc_samples; i++) {
- int timestamp_delta = i == 0 ? delta_to_first_unrecorded_gc_sample : _stackprof.interval;
+ int timestamp_delta = i == 0 ? delta_to_first_unrecorded_gc_sample : NUM2LONG(_stackprof.interval);
stackprof_record_sample_for_stack(1, timestamp_delta);
}
_stackprof.during_gc += _stackprof.unrecorded_gc_samples;
_stackprof.unrecorded_gc_samples = 0;
}