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; }