fiber-profiler 0.1.5 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7eff364d5f9fc0850ed71072242195873f790518f3f10b784329fe31dafcbf6f
4
- data.tar.gz: ad7c9544f0d14fa2b2085d91d9211c7bcb42dc26e0840ca19bf7c064c5067cba
3
+ metadata.gz: 763fd680dafd595bcfdb69ffcac3161ab2c21ffe4ddeb54110d30b26af78c645
4
+ data.tar.gz: 7619a44d197a88b4ecb2f24e3e48a4d4e8a660f7fc9bd1d6cc0482bad45df92f
5
5
  SHA512:
6
- metadata.gz: '069d76a3551bd65c3cf877e371f00c5dd57c3b0bb8c1d937f7187a291adca561b85628ed46b28b3ad2325e6e37e1da1ec4480cb7f4ef4e180b91c55ffd6fcea6'
7
- data.tar.gz: d44f0981b66d6fc382005e13e2900b1c56cc879993d6dd0c141293b1b5ed6223e81e3201ce2e345cfa4e663b8e1b42ce3bacea53b7abff9db901470fc897d0df
6
+ metadata.gz: 968cc396e79c7030a7fa2d384b21dd0491f4d4ea03c2173cfe1c1081d982cc6976ba32c023a676deab5dfc748b1dbc320d9f1087f41532249484f647a62b1f94
7
+ data.tar.gz: 1b68a1bfccf03defd375fe90da755b33fd9da19155bfac3b7b03208a664075c3469518077c0270102f36f07b44b4016ce8fd96dd1969701370f14ccd526816b3
checksums.yaml.gz.sig CHANGED
Binary file
@@ -19,6 +19,7 @@ enum {
19
19
 
20
20
  int Fiber_Profiler_capture_p = 0;
21
21
  double Fiber_Profiler_Capture_stall_threshold = 0.01;
22
+ double Fiber_Profiler_Capture_filter_threshold = 0.001;
22
23
  int Fiber_Profiler_Capture_track_calls = 1;
23
24
  double Fiber_Profiler_Capture_sample_rate = 1;
24
25
 
@@ -65,7 +66,7 @@ void Fiber_Profiler_Stream_free(struct Fiber_Profiler_Stream *stream) {
65
66
  }
66
67
 
67
68
  struct Fiber_Profiler_Capture;
68
- typedef void(*Fiber_Profiler_Stream_Print)(struct Fiber_Profiler_Capture*, FILE* restrict);
69
+ typedef void(*Fiber_Profiler_Stream_Print)(struct Fiber_Profiler_Capture*, FILE* restrict, double duration);
69
70
 
70
71
  struct Fiber_Profiler_Capture {
71
72
  // The threshold in seconds, which determines when a fiber is considered to have stalled the event loop.
@@ -74,7 +75,7 @@ struct Fiber_Profiler_Capture {
74
75
  // Whether or not to track calls.
75
76
  int track_calls;
76
77
 
77
- // The sample rate of the profiler, as a fraction of 1.0, which controls how often the profiler will sample between fiber context switches.
78
+ // The sample rate of the capture, as a fraction of 1.0, which controls how often the profiler will sample between fiber context switches.
78
79
  double sample_rate;
79
80
 
80
81
  // Calls that are shorter than this filter threshold will be ignored.
@@ -89,6 +90,15 @@ struct Fiber_Profiler_Capture {
89
90
  // The stream buffer used for printing.
90
91
  struct Fiber_Profiler_Stream stream;
91
92
 
93
+ // How many fiber context switches have been encountered. Not all of them will be sampled, based on the sample rate.
94
+ size_t switches;
95
+
96
+ // How many samples have been taken, not all of them will be stalls, based on the stall threshold.
97
+ size_t samples;
98
+
99
+ // The number of stalls encountered and printed.
100
+ size_t stalls;
101
+
92
102
  // Whether or not the profiler is currently running.
93
103
  int running;
94
104
 
@@ -98,14 +108,11 @@ struct Fiber_Profiler_Capture {
98
108
  // Whether or not to capture call data.
99
109
  int capture;
100
110
 
101
- // The number of stalls encountered.
102
- size_t stalls;
103
-
104
111
  // The start time of the profile.
105
112
  struct timespec start_time;
106
113
 
107
- // The stop time of the profile.
108
- struct timespec stop_time;
114
+ // The time of the last fiber switch that was sampled.
115
+ struct timespec switch_time;
109
116
 
110
117
  // The depth of the call stack (can be negative).
111
118
  int nesting;
@@ -120,13 +127,6 @@ struct Fiber_Profiler_Capture {
120
127
  struct Fiber_Profiler_Deque calls;
121
128
  };
122
129
 
123
- void Fiber_Profiler_Capture_reset(struct Fiber_Profiler_Capture *profiler) {
124
- profiler->nesting = 0;
125
- profiler->nesting_minimum = 0;
126
- profiler->current = NULL;
127
- Fiber_Profiler_Deque_truncate(&profiler->calls);
128
- }
129
-
130
130
  void Fiber_Profiler_Capture_Call_initialize(void *element) {
131
131
  struct Fiber_Profiler_Capture_Call *call = element;
132
132
 
@@ -155,43 +155,43 @@ void Fiber_Profiler_Capture_Call_free(void *element) {
155
155
  }
156
156
 
157
157
  static void Fiber_Profiler_Capture_mark(void *ptr) {
158
- struct Fiber_Profiler_Capture *profiler = (struct Fiber_Profiler_Capture*)ptr;
158
+ struct Fiber_Profiler_Capture *capture = (struct Fiber_Profiler_Capture*)ptr;
159
159
 
160
- rb_gc_mark_movable(profiler->thread);
161
- rb_gc_mark_movable(profiler->output);
160
+ rb_gc_mark_movable(capture->thread);
161
+ rb_gc_mark_movable(capture->output);
162
162
 
163
163
  // If `klass` is stored as a VALUE in calls, we need to mark them here:
164
- Fiber_Profiler_Deque_each(&profiler->calls, struct Fiber_Profiler_Capture_Call, call) {
164
+ Fiber_Profiler_Deque_each(&capture->calls, struct Fiber_Profiler_Capture_Call, call) {
165
165
  rb_gc_mark_movable(call->klass);
166
166
  }
167
167
  }
168
168
 
169
169
  static void Fiber_Profiler_Capture_compact(void *ptr) {
170
- struct Fiber_Profiler_Capture *profiler = (struct Fiber_Profiler_Capture*)ptr;
170
+ struct Fiber_Profiler_Capture *capture = (struct Fiber_Profiler_Capture*)ptr;
171
171
 
172
- profiler->thread = rb_gc_location(profiler->thread);
173
- profiler->output = rb_gc_location(profiler->output);
172
+ capture->thread = rb_gc_location(capture->thread);
173
+ capture->output = rb_gc_location(capture->output);
174
174
 
175
175
  // If `klass` is stored as a VALUE in calls, we need to update their locations here:
176
- Fiber_Profiler_Deque_each(&profiler->calls, struct Fiber_Profiler_Capture_Call, call) {
176
+ Fiber_Profiler_Deque_each(&capture->calls, struct Fiber_Profiler_Capture_Call, call) {
177
177
  call->klass = rb_gc_location(call->klass);
178
178
  }
179
179
  }
180
180
 
181
181
  static void Fiber_Profiler_Capture_free(void *ptr) {
182
- struct Fiber_Profiler_Capture *profiler = (struct Fiber_Profiler_Capture*)ptr;
182
+ struct Fiber_Profiler_Capture *capture = (struct Fiber_Profiler_Capture*)ptr;
183
183
 
184
- RUBY_ASSERT(profiler->running == 0);
184
+ RUBY_ASSERT(capture->running == 0);
185
185
 
186
- Fiber_Profiler_Stream_free(&profiler->stream);
187
- Fiber_Profiler_Deque_free(&profiler->calls);
186
+ Fiber_Profiler_Stream_free(&capture->stream);
187
+ Fiber_Profiler_Deque_free(&capture->calls);
188
188
 
189
- free(profiler);
189
+ free(capture);
190
190
  }
191
191
 
192
192
  static size_t Fiber_Profiler_Capture_memsize(const void *ptr) {
193
- const struct Fiber_Profiler_Capture *profiler = (const struct Fiber_Profiler_Capture*)ptr;
194
- return sizeof(*profiler) + Fiber_Profiler_Deque_memory_size(&profiler->calls);
193
+ const struct Fiber_Profiler_Capture *capture = (const struct Fiber_Profiler_Capture*)ptr;
194
+ return sizeof(*capture) + Fiber_Profiler_Deque_memory_size(&capture->calls);
195
195
  }
196
196
 
197
197
  const rb_data_type_t Fiber_Profiler_Capture_Type = {
@@ -206,9 +206,9 @@ const rb_data_type_t Fiber_Profiler_Capture_Type = {
206
206
  };
207
207
 
208
208
  struct Fiber_Profiler_Capture *Fiber_Profiler_Capture_get(VALUE self) {
209
- struct Fiber_Profiler_Capture *profiler;
210
- TypedData_Get_Struct(self, struct Fiber_Profiler_Capture, &Fiber_Profiler_Capture_Type, profiler);
211
- return profiler;
209
+ struct Fiber_Profiler_Capture *capture;
210
+ TypedData_Get_Struct(self, struct Fiber_Profiler_Capture, &Fiber_Profiler_Capture_Type, capture);
211
+ return capture;
212
212
  }
213
213
 
214
214
  int IO_istty(VALUE io) {
@@ -220,78 +220,83 @@ int IO_istty(VALUE io) {
220
220
  return 0;
221
221
  }
222
222
 
223
- void Fiber_Profiler_Capture_print_tty(struct Fiber_Profiler_Capture *profiler, FILE *restrict stream);
224
- void Fiber_Profiler_Capture_print_json(struct Fiber_Profiler_Capture *profiler, FILE *restrict stream);
223
+ void Fiber_Profiler_Capture_print_tty(struct Fiber_Profiler_Capture *capture, FILE *restrict stream, double duration);
224
+ void Fiber_Profiler_Capture_print_json(struct Fiber_Profiler_Capture *capture, FILE *restrict stream, double duration);
225
225
 
226
- static void Fiber_Profiler_Capture_output_set(struct Fiber_Profiler_Capture *profiler, VALUE output) {
227
- profiler->output = output;
226
+ static void Fiber_Profiler_Capture_output_set(struct Fiber_Profiler_Capture *capture, VALUE output) {
227
+ capture->output = output;
228
228
 
229
- if (IO_istty(profiler->output)) {
230
- profiler->print = &Fiber_Profiler_Capture_print_tty;
229
+ if (IO_istty(capture->output)) {
230
+ capture->print = &Fiber_Profiler_Capture_print_tty;
231
231
  } else {
232
- profiler->print = &Fiber_Profiler_Capture_print_json;
232
+ capture->print = &Fiber_Profiler_Capture_print_json;
233
233
  }
234
234
  }
235
235
 
236
236
  VALUE Fiber_Profiler_Capture_allocate(VALUE klass) {
237
- struct Fiber_Profiler_Capture *profiler = ALLOC(struct Fiber_Profiler_Capture);
237
+ struct Fiber_Profiler_Capture *capture = ALLOC(struct Fiber_Profiler_Capture);
238
238
 
239
239
  // Initialize the profiler state:
240
- Fiber_Profiler_Stream_initialize(&profiler->stream);
241
- profiler->output = Qnil;
240
+ Fiber_Profiler_Stream_initialize(&capture->stream);
241
+ capture->output = Qnil;
242
242
 
243
- profiler->running = 0;
244
- profiler->thread = Qnil;
243
+ capture->switches = 0;
244
+ capture->samples = 0;
245
+ capture->stalls = 0;
245
246
 
246
- profiler->capture = 0;
247
- profiler->stalls = 0;
248
- profiler->nesting = 0;
249
- profiler->nesting_minimum = 0;
250
- profiler->current = NULL;
247
+ capture->running = 0;
248
+ capture->thread = Qnil;
251
249
 
252
- profiler->stall_threshold = Fiber_Profiler_Capture_stall_threshold;
253
- profiler->track_calls = Fiber_Profiler_Capture_track_calls;
254
- profiler->sample_rate = Fiber_Profiler_Capture_sample_rate;
250
+ capture->capture = 0;
251
+ capture->nesting = 0;
252
+ capture->nesting_minimum = 0;
253
+ capture->current = NULL;
255
254
 
256
- // Filter calls that are less than 10% of the stall threshold:
257
- profiler->filter_threshold = profiler->stall_threshold * 0.1;
255
+ capture->stall_threshold = Fiber_Profiler_Capture_stall_threshold;
256
+ capture->filter_threshold = Fiber_Profiler_Capture_filter_threshold;
257
+ capture->track_calls = Fiber_Profiler_Capture_track_calls;
258
+ capture->sample_rate = Fiber_Profiler_Capture_sample_rate;
258
259
 
259
- profiler->calls.element_initialize = (void (*)(void*))Fiber_Profiler_Capture_Call_initialize;
260
- profiler->calls.element_free = (void (*)(void*))Fiber_Profiler_Capture_Call_free;
260
+ capture->calls.element_initialize = (void (*)(void*))Fiber_Profiler_Capture_Call_initialize;
261
+ capture->calls.element_free = (void (*)(void*))Fiber_Profiler_Capture_Call_free;
261
262
 
262
- Fiber_Profiler_Deque_initialize(&profiler->calls, sizeof(struct Fiber_Profiler_Capture_Call));
263
- Fiber_Profiler_Deque_reserve_default(&profiler->calls);
263
+ Fiber_Profiler_Deque_initialize(&capture->calls, sizeof(struct Fiber_Profiler_Capture_Call));
264
+ Fiber_Profiler_Deque_reserve_default(&capture->calls);
264
265
 
265
- return TypedData_Wrap_Struct(klass, &Fiber_Profiler_Capture_Type, profiler);
266
+ return TypedData_Wrap_Struct(klass, &Fiber_Profiler_Capture_Type, capture);
266
267
  }
267
268
 
268
- ID Fiber_Profiler_Capture_initialize_options[4];
269
+ ID Fiber_Profiler_Capture_initialize_options[5];
269
270
 
270
271
  VALUE Fiber_Profiler_Capture_initialize(int argc, VALUE *argv, VALUE self) {
271
- struct Fiber_Profiler_Capture *profiler = Fiber_Profiler_Capture_get(self);
272
+ struct Fiber_Profiler_Capture *capture = Fiber_Profiler_Capture_get(self);
272
273
 
273
- VALUE arguments[4] = {0};
274
+ VALUE arguments[5] = {0};
274
275
  VALUE options = Qnil;
275
276
  rb_scan_args(argc, argv, ":", &options);
276
- rb_get_kwargs(options, Fiber_Profiler_Capture_initialize_options, 0, 4, arguments);
277
+ rb_get_kwargs(options, Fiber_Profiler_Capture_initialize_options, 0, 5, arguments);
277
278
 
278
279
  if (arguments[0] != Qundef) {
279
- profiler->stall_threshold = NUM2DBL(arguments[0]);
280
+ capture->stall_threshold = NUM2DBL(arguments[0]);
280
281
  }
281
282
 
282
283
  if (arguments[1] != Qundef) {
283
- profiler->track_calls = RB_TEST(arguments[1]);
284
+ capture->filter_threshold = NUM2DBL(arguments[1]);
284
285
  }
285
286
 
286
287
  if (arguments[2] != Qundef) {
287
- profiler->sample_rate = NUM2DBL(arguments[2]);
288
+ capture->track_calls = RB_TEST(arguments[2]);
288
289
  }
289
290
 
290
291
  if (arguments[3] != Qundef) {
291
- Fiber_Profiler_Capture_output_set(profiler, arguments[3]);
292
+ capture->sample_rate = NUM2DBL(arguments[3]);
293
+ }
294
+
295
+ if (arguments[4] != Qundef) {
296
+ Fiber_Profiler_Capture_output_set(capture, arguments[4]);
292
297
  } else {
293
298
  // Initialize the profiler output - we dup `rb_stderr` because the profiler may otherwise run into synchronization issues with other uses of `rb_stderr`:
294
- Fiber_Profiler_Capture_output_set(profiler, rb_obj_dup(rb_stderr));
299
+ Fiber_Profiler_Capture_output_set(capture, rb_obj_dup(rb_stderr));
295
300
  }
296
301
 
297
302
  return self;
@@ -302,10 +307,10 @@ VALUE Fiber_Profiler_Capture_default(VALUE klass) {
302
307
  return Qnil;
303
308
  }
304
309
 
305
- VALUE profiler = Fiber_Profiler_Capture_allocate(klass);
306
- Fiber_Profiler_Capture_initialize(0, NULL, profiler);
310
+ VALUE capture = Fiber_Profiler_Capture_allocate(klass);
311
+ Fiber_Profiler_Capture_initialize(0, NULL, capture);
307
312
 
308
- return profiler;
313
+ return capture;
309
314
  }
310
315
 
311
316
  int event_flag_call_p(rb_event_flag_t event_flags) {
@@ -332,19 +337,19 @@ const char *event_flag_name(rb_event_flag_t event_flag) {
332
337
  }
333
338
  }
334
339
 
335
- static struct Fiber_Profiler_Capture_Call* Fiber_Profiler_Capture_Call_new(struct Fiber_Profiler_Capture *profiler, rb_event_flag_t event_flag, ID id, VALUE klass) {
336
- struct Fiber_Profiler_Capture_Call *call = Fiber_Profiler_Deque_push(&profiler->calls);
340
+ static struct Fiber_Profiler_Capture_Call* Fiber_Profiler_Capture_Call_new(struct Fiber_Profiler_Capture *capture, rb_event_flag_t event_flag, ID id, VALUE klass) {
341
+ struct Fiber_Profiler_Capture_Call *call = Fiber_Profiler_Deque_push(&capture->calls);
337
342
 
338
343
  call->event_flag = event_flag;
339
344
 
340
- call->parent = profiler->current;
345
+ call->parent = capture->current;
341
346
  if (call->parent) {
342
347
  call->parent->children += 1;
343
348
  }
344
349
 
345
- profiler->current = call;
350
+ capture->current = call;
346
351
 
347
- call->nesting = profiler->nesting;
352
+ call->nesting = capture->nesting;
348
353
 
349
354
  if (id) {
350
355
  call->id = id;
@@ -363,15 +368,20 @@ static struct Fiber_Profiler_Capture_Call* Fiber_Profiler_Capture_Call_new(struc
363
368
  }
364
369
 
365
370
  // Finish the call by calculating the duration and filtering it if necessary.
366
- int Fiber_Profiler_Capture_Call_finish(struct Fiber_Profiler_Capture *profiler, struct Fiber_Profiler_Capture_Call *call) {
371
+ int Fiber_Profiler_Capture_Call_finish(struct Fiber_Profiler_Capture *capture, struct Fiber_Profiler_Capture_Call *call) {
367
372
  // Don't filter calls if we're not running:
368
373
  if (DEBUG_FILTERED) return 0;
369
374
 
370
- if (call->duration < profiler->filter_threshold) {
375
+ if (event_flag_return_p(call->event_flag)) {
376
+ // We don't filter return statements, as they are always part of the call stack:
377
+ return 0;
378
+ }
379
+
380
+ if (call->duration < capture->filter_threshold) {
371
381
  // We can only remove calls from the end of the deque, otherwise they might be referenced by other calls:
372
- if (call == Fiber_Profiler_Deque_last(&profiler->calls)) {
373
- if (profiler->current == call) {
374
- profiler->current = call->parent;
382
+ if (call == Fiber_Profiler_Deque_last(&capture->calls)) {
383
+ if (capture->current == call) {
384
+ capture->current = call->parent;
375
385
  }
376
386
 
377
387
  if (call->parent) {
@@ -380,7 +390,7 @@ int Fiber_Profiler_Capture_Call_finish(struct Fiber_Profiler_Capture *profiler,
380
390
  call->parent = NULL;
381
391
  }
382
392
 
383
- Fiber_Profiler_Deque_pop(&profiler->calls);
393
+ Fiber_Profiler_Deque_pop(&capture->calls);
384
394
 
385
395
  return 1;
386
396
  }
@@ -389,10 +399,11 @@ int Fiber_Profiler_Capture_Call_finish(struct Fiber_Profiler_Capture *profiler,
389
399
  return 0;
390
400
  }
391
401
 
402
+ // Whether to highlight a call as expensive. This is purely cosmetic.
392
403
  static const double Fiber_Profiler_Capture_Call_EXPENSIVE_THRESHOLD = 0.2;
393
404
 
394
- int Fiber_Profiler_Capture_Call_expensive_p(struct Fiber_Profiler_Capture_Call *call, double total_duration) {
395
- if (call->duration > total_duration * Fiber_Profiler_Capture_Call_EXPENSIVE_THRESHOLD) {
405
+ int Fiber_Profiler_Capture_Call_expensive_p(struct Fiber_Profiler_Capture *capture, struct Fiber_Profiler_Capture_Call *call, double duration) {
406
+ if (call->duration > duration * Fiber_Profiler_Capture_Call_EXPENSIVE_THRESHOLD) {
396
407
  return 1;
397
408
  }
398
409
 
@@ -400,57 +411,63 @@ int Fiber_Profiler_Capture_Call_expensive_p(struct Fiber_Profiler_Capture_Call *
400
411
  }
401
412
 
402
413
  static void Fiber_Profiler_Capture_callback(rb_event_flag_t event_flag, VALUE data, VALUE self, ID id, VALUE klass) {
403
- struct Fiber_Profiler_Capture *profiler = Fiber_Profiler_Capture_get(data);
414
+ struct Fiber_Profiler_Capture *capture = Fiber_Profiler_Capture_get(data);
404
415
 
405
416
  // We don't want to capture data if we're not running:
406
- if (!profiler->capture) return;
417
+ if (!capture->capture) return;
407
418
 
408
419
  if (event_flag_call_p(event_flag)) {
409
- struct Fiber_Profiler_Capture_Call *call = Fiber_Profiler_Capture_Call_new(profiler, event_flag, id, klass);
420
+ struct Fiber_Profiler_Capture_Call *call = Fiber_Profiler_Capture_Call_new(capture, event_flag, id, klass);
410
421
 
411
- profiler->nesting += 1;
422
+ capture->nesting += 1;
412
423
 
413
424
  Fiber_Profiler_Time_current(&call->enter_time);
414
425
  }
415
426
 
416
427
  else if (event_flag_return_p(event_flag)) {
417
- struct Fiber_Profiler_Capture_Call *call = profiler->current;
428
+ struct Fiber_Profiler_Capture_Call *call = capture->current;
418
429
 
419
430
  // We may encounter returns without a preceeding call. This isn't an error, but we should pretend like the call started at the beginning of the profiling session:
420
431
  if (call == NULL) {
421
- struct Fiber_Profiler_Capture_Call *last_call = Fiber_Profiler_Deque_last(&profiler->calls);
422
- call = Fiber_Profiler_Capture_Call_new(profiler, event_flag, id, klass);
432
+ struct Fiber_Profiler_Capture_Call *last_call = Fiber_Profiler_Deque_last(&capture->calls);
433
+ call = Fiber_Profiler_Capture_Call_new(capture, event_flag, id, klass);
434
+
435
+ struct timespec call_time;
423
436
 
424
437
  if (last_call) {
425
- call->enter_time = last_call->enter_time;
438
+ call_time = last_call->enter_time;
426
439
  } else {
427
- call->enter_time = profiler->start_time;
440
+ call_time = capture->switch_time;
428
441
  }
442
+
443
+ // For return statements, we record the current time as the enter time:
444
+ Fiber_Profiler_Time_current(&call->enter_time);
445
+ call->duration = Fiber_Profiler_Time_delta(&call_time, &call->enter_time);
446
+ } else {
447
+ call->duration = Fiber_Profiler_Time_delta_current(&call->enter_time);
429
448
  }
430
449
 
431
- call->duration = Fiber_Profiler_Time_delta_current(&call->enter_time);
432
-
433
- profiler->current = call->parent;
450
+ capture->current = call->parent;
434
451
 
435
452
  // We may encounter returns without a preceeding call.
436
- profiler->nesting -= 1;
453
+ capture->nesting -= 1;
437
454
 
438
455
  // We need to keep track of how deep the call stack goes:
439
- if (profiler->nesting < profiler->nesting_minimum) {
440
- profiler->nesting_minimum = profiler->nesting;
456
+ if (capture->nesting < capture->nesting_minimum) {
457
+ capture->nesting_minimum = capture->nesting;
441
458
  }
442
459
 
443
- Fiber_Profiler_Capture_Call_finish(profiler, call);
460
+ Fiber_Profiler_Capture_Call_finish(capture, call);
444
461
  }
445
462
 
446
463
  else {
447
- struct Fiber_Profiler_Capture_Call *last_call = Fiber_Profiler_Deque_last(&profiler->calls);
448
- struct Fiber_Profiler_Capture_Call *call = Fiber_Profiler_Capture_Call_new(profiler, event_flag, id, klass);
464
+ struct Fiber_Profiler_Capture_Call *last_call = Fiber_Profiler_Deque_last(&capture->calls);
465
+ struct Fiber_Profiler_Capture_Call *call = Fiber_Profiler_Capture_Call_new(capture, event_flag, id, klass);
449
466
 
450
467
  if (last_call) {
451
468
  call->enter_time = last_call->enter_time;
452
469
  } else {
453
- call->enter_time = profiler->start_time;
470
+ call->enter_time = capture->switch_time;
454
471
  }
455
472
 
456
473
  call->duration = Fiber_Profiler_Time_delta_current(&call->enter_time);
@@ -458,35 +475,35 @@ static void Fiber_Profiler_Capture_callback(rb_event_flag_t event_flag, VALUE da
458
475
  }
459
476
 
460
477
  void Fiber_Profiler_Capture_pause(VALUE self) {
461
- struct Fiber_Profiler_Capture *profiler = Fiber_Profiler_Capture_get(self);
478
+ struct Fiber_Profiler_Capture *capture = Fiber_Profiler_Capture_get(self);
462
479
 
463
- if (!profiler->capture) return;
480
+ if (!capture->capture) return;
481
+ capture->capture = 0;
464
482
 
465
- profiler->capture = 0;
466
-
467
- rb_thread_remove_event_hook_with_data(profiler->thread, Fiber_Profiler_Capture_callback, self);
483
+ if (capture->track_calls) {
484
+ rb_thread_remove_event_hook_with_data(capture->thread, Fiber_Profiler_Capture_callback, self);
485
+ }
468
486
  }
469
487
 
470
488
  void Fiber_Profiler_Capture_resume(VALUE self) {
471
- struct Fiber_Profiler_Capture *profiler = Fiber_Profiler_Capture_get(self);
472
-
473
- if (profiler->capture) return;
489
+ struct Fiber_Profiler_Capture *capture = Fiber_Profiler_Capture_get(self);
474
490
 
475
- profiler->capture = 1;
491
+ if (capture->capture) return;
492
+ capture->capture = 1;
493
+ capture->samples += 1;
476
494
 
477
- rb_event_flag_t event_flags = 0;
478
-
479
- if (profiler->track_calls) {
480
- // event_flags |= RUBY_EVENT_LINE;
495
+ if (capture->track_calls) {
496
+ rb_event_flag_t event_flags = 0;
481
497
 
498
+ // event_flags |= RUBY_EVENT_LINE;
482
499
  event_flags |= RUBY_EVENT_CALL | RUBY_EVENT_RETURN;
483
500
  event_flags |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
484
501
  event_flags |= RUBY_EVENT_B_CALL | RUBY_EVENT_B_RETURN;
502
+
503
+ // CRuby will raise an exception if you try to add "INTERNAL_EVENT" hooks at the same time as other hooks, so we do it in two calls:
504
+ rb_thread_add_event_hook(capture->thread, Fiber_Profiler_Capture_callback, event_flags, self);
505
+ rb_thread_add_event_hook(capture->thread, Fiber_Profiler_Capture_callback, RUBY_INTERNAL_EVENT_GC_START | RUBY_INTERNAL_EVENT_GC_END_SWEEP, self);
485
506
  }
486
-
487
- // CRuby will raise an exception if you try to add "INTERNAL_EVENT" hooks at the same time as other hooks, so we do it in two calls:
488
- rb_thread_add_event_hook(profiler->thread, Fiber_Profiler_Capture_callback, event_flags, self);
489
- rb_thread_add_event_hook(profiler->thread, Fiber_Profiler_Capture_callback, RUBY_INTERNAL_EVENT_GC_START | RUBY_INTERNAL_EVENT_GC_END_SWEEP, self);
490
507
  }
491
508
 
492
509
  void Fiber_Profiler_Capture_fiber_switch(VALUE self);
@@ -495,68 +512,70 @@ void Fiber_Profiler_Capture_fiber_switch_callback(rb_event_flag_t event_flag, VA
495
512
  Fiber_Profiler_Capture_fiber_switch(data);
496
513
  }
497
514
 
515
+ // Reset the sample state, and truncate the call log.
516
+ void Fiber_Profiler_Capture_reset(struct Fiber_Profiler_Capture *capture) {
517
+ capture->nesting = 0;
518
+ capture->nesting_minimum = 0;
519
+ capture->current = NULL;
520
+ Fiber_Profiler_Deque_truncate(&capture->calls);
521
+ }
522
+
498
523
  VALUE Fiber_Profiler_Capture_start(VALUE self) {
499
- struct Fiber_Profiler_Capture *profiler = Fiber_Profiler_Capture_get(self);
524
+ struct Fiber_Profiler_Capture *capture = Fiber_Profiler_Capture_get(self);
500
525
 
501
- if (profiler->running) return Qfalse;
526
+ if (capture->running) return Qfalse;
502
527
 
503
- profiler->running = 1;
504
- profiler->thread = rb_thread_current();
528
+ capture->running = 1;
529
+ capture->thread = rb_thread_current();
505
530
 
506
- Fiber_Profiler_Capture_reset(profiler);
507
- Fiber_Profiler_Time_current(&profiler->start_time);
531
+ Fiber_Profiler_Capture_reset(capture);
532
+ Fiber_Profiler_Time_current(&capture->start_time);
508
533
 
509
- rb_thread_add_event_hook(profiler->thread, Fiber_Profiler_Capture_fiber_switch_callback, RUBY_EVENT_FIBER_SWITCH, self);
534
+ rb_thread_add_event_hook(capture->thread, Fiber_Profiler_Capture_fiber_switch_callback, RUBY_EVENT_FIBER_SWITCH, self);
510
535
 
511
536
  return self;
512
537
  }
513
538
 
514
539
  VALUE Fiber_Profiler_Capture_stop(VALUE self) {
515
- struct Fiber_Profiler_Capture *profiler = Fiber_Profiler_Capture_get(self);
540
+ struct Fiber_Profiler_Capture *capture = Fiber_Profiler_Capture_get(self);
516
541
 
517
- if (!profiler->running) return Qfalse;
542
+ if (!capture->running) return Qfalse;
518
543
 
519
544
  Fiber_Profiler_Capture_pause(self);
520
545
 
521
- rb_thread_remove_event_hook_with_data(profiler->thread, Fiber_Profiler_Capture_fiber_switch_callback, self);
546
+ rb_thread_remove_event_hook_with_data(capture->thread, Fiber_Profiler_Capture_fiber_switch_callback, self);
522
547
 
523
- profiler->running = 0;
524
- profiler->thread = Qnil;
525
-
526
- Fiber_Profiler_Time_current(&profiler->stop_time);
527
- Fiber_Profiler_Capture_reset(profiler);
548
+ capture->running = 0;
549
+ capture->thread = Qnil;
550
+
551
+ Fiber_Profiler_Capture_reset(capture);
528
552
 
529
553
  return self;
530
554
  }
531
555
 
532
- void Fiber_Profiler_Capture_finish(struct Fiber_Profiler_Capture *profiler) {
533
- profiler->capture = 0;
534
-
535
- struct timespec stop_time;
536
- Fiber_Profiler_Time_current(&stop_time);
537
-
538
- struct Fiber_Profiler_Capture_Call *current = profiler->current;
556
+ void Fiber_Profiler_Capture_finish(struct Fiber_Profiler_Capture *capture, struct timespec switch_time) {
557
+ struct Fiber_Profiler_Capture_Call *current = capture->current;
539
558
  while (current) {
540
559
  struct Fiber_Profiler_Capture_Call *parent = current->parent;
541
560
 
542
- current->duration = Fiber_Profiler_Time_delta(&current->enter_time, &stop_time);
561
+ current->duration = Fiber_Profiler_Time_delta(&current->enter_time, &switch_time);
543
562
 
544
- Fiber_Profiler_Capture_Call_finish(profiler, current);
563
+ Fiber_Profiler_Capture_Call_finish(capture, current);
545
564
 
546
565
  current = parent;
547
566
  }
548
567
  }
549
568
 
550
- void Fiber_Profiler_Capture_print(struct Fiber_Profiler_Capture *profiler);
569
+ void Fiber_Profiler_Capture_print(struct Fiber_Profiler_Capture *capture, double duration);
551
570
 
552
- int Fiber_Profiler_Capture_sample(struct Fiber_Profiler_Capture *profiler) {
571
+ int Fiber_Profiler_Capture_sample(struct Fiber_Profiler_Capture *capture) {
553
572
  VALUE fiber = Fiber_Profiler_Fiber_current();
554
573
 
555
574
  // We don't want to capture data from blocking fibers:
556
575
  if (Fiber_Profiler_Fiber_blocking(fiber)) return 0;
557
576
 
558
- if (profiler->sample_rate < 1) {
559
- return rand() < (RAND_MAX * profiler->sample_rate);
577
+ if (capture->sample_rate < 1) {
578
+ return rand() < (RAND_MAX * capture->sample_rate);
560
579
  } else {
561
580
  return 1;
562
581
  }
@@ -564,47 +583,58 @@ int Fiber_Profiler_Capture_sample(struct Fiber_Profiler_Capture *profiler) {
564
583
 
565
584
  void Fiber_Profiler_Capture_fiber_switch(VALUE self)
566
585
  {
567
- struct Fiber_Profiler_Capture *profiler = Fiber_Profiler_Capture_get(self);
568
- Fiber_Profiler_Time_current(&profiler->stop_time);
569
- double duration = Fiber_Profiler_Time_delta(&profiler->start_time, &profiler->stop_time);
586
+ struct Fiber_Profiler_Capture *capture = Fiber_Profiler_Capture_get(self);
587
+ capture->switches += 1;
570
588
 
571
- if (profiler->capture) {
572
- Fiber_Profiler_Capture_pause(self);
589
+ // The time of the switch:
590
+ struct timespec switch_time;
591
+ Fiber_Profiler_Time_current(&switch_time);
592
+
593
+ if (capture->capture) {
594
+ // The duration of the sample:
595
+ double duration = Fiber_Profiler_Time_delta(&capture->switch_time, &switch_time);
573
596
 
574
- Fiber_Profiler_Capture_finish(profiler);
597
+ // Finish the current sample:
598
+ Fiber_Profiler_Capture_pause(self);
599
+ Fiber_Profiler_Capture_finish(capture, switch_time);
575
600
 
576
- if (duration > profiler->stall_threshold) {
577
- profiler->stalls += 1;
578
- Fiber_Profiler_Capture_print(profiler);
601
+ // If the duration of the sample is greater than the stall threshold, we consider it a stall:
602
+ if (duration > capture->stall_threshold) {
603
+ capture->stalls += 1;
604
+
605
+ // Print the sample:
606
+ Fiber_Profiler_Capture_print(capture, duration);
579
607
  }
580
608
 
581
- Fiber_Profiler_Capture_reset(profiler);
609
+ // Reset the capture state:
610
+ Fiber_Profiler_Capture_reset(capture);
582
611
  }
583
612
 
584
- if (Fiber_Profiler_Capture_sample(profiler)) {
585
- // Reset the start time:
586
- Fiber_Profiler_Time_current(&profiler->start_time);
613
+ if (Fiber_Profiler_Capture_sample(capture)) {
614
+ // Save the time of the switch for the next sample:
615
+ capture->switch_time = switch_time;
587
616
 
617
+ // Start capturing data again:
588
618
  Fiber_Profiler_Capture_resume(self);
589
619
  }
590
620
  }
591
621
 
592
622
  // When sampling a fiber, we may encounter returns without a preceeding call. This isn't an error, and we should correctly visualize the call stack. We track both the relative nesting (which can be negative) and the minimum nesting level encountered during the profiling session, and use that to determine the absolute nesting level of each call when printing the call stack.
593
- static size_t Fiber_Profiler_Capture_absolute_nesting(struct Fiber_Profiler_Capture *profiler, struct Fiber_Profiler_Capture_Call *call) {
594
- return call->nesting - profiler->nesting_minimum;
623
+ static size_t Fiber_Profiler_Capture_absolute_nesting(struct Fiber_Profiler_Capture *capture, struct Fiber_Profiler_Capture_Call *call) {
624
+ return call->nesting - capture->nesting_minimum;
595
625
  }
596
626
 
597
627
  // If a call is within this threshold of the parent call, it will be skipped when printing the call stack - it's considered inconsequential to the performance of the parent call.
598
628
  static const double Fiber_Profiler_Capture_SKIP_THRESHOLD = 0.98;
599
629
 
600
- void Fiber_Profiler_Capture_print_tty(struct Fiber_Profiler_Capture *profiler, FILE *restrict stream) {
601
- double total_duration = Fiber_Profiler_Time_delta(&profiler->start_time, &profiler->stop_time);
630
+ void Fiber_Profiler_Capture_print_tty(struct Fiber_Profiler_Capture *capture, FILE *restrict stream, double duration) {
631
+ double start_time = Fiber_Profiler_Time_delta(&capture->start_time, &capture->switch_time);
602
632
 
603
- fprintf(stderr, "## Fiber stalled for %.3f seconds ##\n", total_duration);
633
+ fprintf(stderr, "## Fiber stalled for %.3f seconds (switches=%zu, samples=%zu, stalls=%zu, T+%0.3fs)\n", duration, capture->switches, capture->samples, capture->stalls, start_time);
604
634
 
605
635
  size_t skipped = 0;
606
636
 
607
- Fiber_Profiler_Deque_each(&profiler->calls, struct Fiber_Profiler_Capture_Call, call) {
637
+ Fiber_Profiler_Deque_each(&capture->calls, struct Fiber_Profiler_Capture_Call, call) {
608
638
  if (call->children) {
609
639
  if (call->parent && call->parent->children == 1) {
610
640
  if (call->duration > call->parent->duration * Fiber_Profiler_Capture_SKIP_THRESHOLD) {
@@ -627,7 +657,7 @@ void Fiber_Profiler_Capture_print_tty(struct Fiber_Profiler_Capture *profiler, F
627
657
  if (skipped) {
628
658
  fprintf(stream, "\e[2m");
629
659
 
630
- size_t nesting = Fiber_Profiler_Capture_absolute_nesting(profiler, call);
660
+ size_t nesting = Fiber_Profiler_Capture_absolute_nesting(capture, call);
631
661
  for (size_t i = 0; i < nesting; i += 1) {
632
662
  fputc('\t', stream);
633
663
  }
@@ -638,12 +668,12 @@ void Fiber_Profiler_Capture_print_tty(struct Fiber_Profiler_Capture *profiler, F
638
668
  call->nesting += 1;
639
669
  }
640
670
 
641
- size_t nesting = Fiber_Profiler_Capture_absolute_nesting(profiler, call);
671
+ size_t nesting = Fiber_Profiler_Capture_absolute_nesting(capture, call);
642
672
  for (size_t i = 0; i < nesting; i += 1) {
643
673
  fputc('\t', stream);
644
674
  }
645
675
 
646
- if (Fiber_Profiler_Capture_Call_expensive_p(call, total_duration)) {
676
+ if (Fiber_Profiler_Capture_Call_expensive_p(capture, call, duration)) {
647
677
  fprintf(stream, "\e[31m");
648
678
  }
649
679
 
@@ -651,7 +681,7 @@ void Fiber_Profiler_Capture_print_tty(struct Fiber_Profiler_Capture *profiler, F
651
681
  const char *name = rb_id2name(call->id);
652
682
 
653
683
  struct timespec offset;
654
- Fiber_Profiler_Time_elapsed(&profiler->start_time, &call->enter_time, &offset);
684
+ Fiber_Profiler_Time_elapsed(&capture->switch_time, &call->enter_time, &offset);
655
685
 
656
686
  fprintf(stream, "%s:%d in %s '%s#%s' (%0.4fs, T+" Fiber_Profiler_TIME_PRINTF_TIMESPEC ")\n", call->path, call->line, event_flag_name(call->event_flag), RSTRING_PTR(class_inspect), name, call->duration, Fiber_Profiler_TIME_PRINTF_TIMESPEC_ARGUMENTS(offset));
657
687
 
@@ -667,21 +697,25 @@ void Fiber_Profiler_Capture_print_tty(struct Fiber_Profiler_Capture *profiler, F
667
697
  fprintf(stream, "... filtered %zu direct calls ...\e[0m\n", call->filtered);
668
698
  }
669
699
  }
700
+
701
+ if (skipped) {
702
+ fprintf(stream, "\e[2m... skipped %zu calls ...\e[0m\n", skipped);
703
+ }
670
704
  }
671
705
 
672
- void Fiber_Profiler_Capture_print_json(struct Fiber_Profiler_Capture *profiler, FILE *restrict stream) {
673
- double total_duration = Fiber_Profiler_Time_delta(&profiler->start_time, &profiler->stop_time);
706
+ void Fiber_Profiler_Capture_print_json(struct Fiber_Profiler_Capture *capture, FILE *restrict stream, double duration) {
707
+ double start_time = Fiber_Profiler_Time_delta(&capture->start_time, &capture->switch_time);
674
708
 
675
709
  fputc('{', stream);
676
710
 
677
- fprintf(stream, "\"duration\":%0.6f", total_duration);
711
+ fprintf(stream, "\"start_time\":%0.3f,\"duration\":%0.6f", start_time, duration);
678
712
 
679
713
  size_t skipped = 0;
680
714
 
681
715
  fprintf(stream, ",\"calls\":[");
682
716
  int first = 1;
683
717
 
684
- Fiber_Profiler_Deque_each(&profiler->calls, struct Fiber_Profiler_Capture_Call, call) {
718
+ Fiber_Profiler_Deque_each(&capture->calls, struct Fiber_Profiler_Capture_Call, call) {
685
719
  if (call->children) {
686
720
  if (call->parent && call->parent->children == 1) {
687
721
  if (call->duration > call->parent->duration * Fiber_Profiler_Capture_SKIP_THRESHOLD) {
@@ -700,10 +734,10 @@ void Fiber_Profiler_Capture_print_json(struct Fiber_Profiler_Capture *profiler,
700
734
  VALUE class_inspect = rb_inspect(call->klass);
701
735
  const char *name = rb_id2name(call->id);
702
736
 
703
- size_t nesting = Fiber_Profiler_Capture_absolute_nesting(profiler, call);
737
+ size_t nesting = Fiber_Profiler_Capture_absolute_nesting(capture, call);
704
738
 
705
739
  struct timespec offset;
706
- Fiber_Profiler_Time_elapsed(&profiler->start_time, &call->enter_time, &offset);
740
+ Fiber_Profiler_Time_elapsed(&capture->switch_time, &call->enter_time, &offset);
707
741
 
708
742
  fprintf(stream, "%s{\"path\":\"%s\",\"line\":%d,\"class\":\"%s\",\"method\":\"%s\",\"duration\":%0.6f,\"offset\":" Fiber_Profiler_TIME_PRINTF_TIMESPEC ",\"nesting\":%zu,\"skipped\":%zu,\"filtered\":%zu}", first ? "" : ",", call->path, call->line, RSTRING_PTR(class_inspect), name, call->duration, Fiber_Profiler_TIME_PRINTF_TIMESPEC_ARGUMENTS(offset), nesting, skipped, call->filtered);
709
743
 
@@ -717,17 +751,17 @@ void Fiber_Profiler_Capture_print_json(struct Fiber_Profiler_Capture *profiler,
717
751
  fprintf(stream, ",\"skipped\":%zu", skipped);
718
752
  }
719
753
 
720
- fprintf(stream, "}\n");
754
+ fprintf(stream, ",\"switches\":%zu,\"samples\":%zu,\"stalls\":%zu}\n", capture->switches, capture->samples, capture->stalls);
721
755
  }
722
756
 
723
- void Fiber_Profiler_Capture_print(struct Fiber_Profiler_Capture *profiler) {
724
- if (profiler->output == Qnil) return;
757
+ void Fiber_Profiler_Capture_print(struct Fiber_Profiler_Capture *capture, double duration) {
758
+ if (capture->output == Qnil) return;
725
759
 
726
- FILE *stream = profiler->stream.file;
727
- profiler->print(profiler, stream);
760
+ FILE *stream = capture->stream.file;
761
+ capture->print(capture, stream, duration);
728
762
  fflush(stream);
729
763
 
730
- rb_io_write(profiler->output, rb_str_new_static(profiler->stream.buffer, profiler->stream.size));
764
+ rb_io_write(capture->output, rb_str_new_static(capture->stream.buffer, capture->stream.size));
731
765
 
732
766
  fseek(stream, 0, SEEK_SET);
733
767
  }
@@ -735,27 +769,33 @@ void Fiber_Profiler_Capture_print(struct Fiber_Profiler_Capture *profiler) {
735
769
  #pragma mark - Accessors
736
770
 
737
771
  static VALUE Fiber_Profiler_Capture_stall_threshold_get(VALUE self) {
738
- struct Fiber_Profiler_Capture *profiler = Fiber_Profiler_Capture_get(self);
772
+ struct Fiber_Profiler_Capture *capture = Fiber_Profiler_Capture_get(self);
773
+
774
+ return DBL2NUM(capture->stall_threshold);
775
+ }
776
+
777
+ static VALUE Fiber_Profiler_Capture_filter_threshold_get(VALUE self) {
778
+ struct Fiber_Profiler_Capture *capture = Fiber_Profiler_Capture_get(self);
739
779
 
740
- return DBL2NUM(profiler->stall_threshold);
780
+ return DBL2NUM(capture->filter_threshold);
741
781
  }
742
782
 
743
783
  static VALUE Fiber_Profiler_Capture_track_calls_get(VALUE self) {
744
- struct Fiber_Profiler_Capture *profiler = Fiber_Profiler_Capture_get(self);
784
+ struct Fiber_Profiler_Capture *capture = Fiber_Profiler_Capture_get(self);
745
785
 
746
- return profiler->track_calls ? Qtrue : Qfalse;
786
+ return capture->track_calls ? Qtrue : Qfalse;
747
787
  }
748
788
 
749
789
  static VALUE Fiber_Profiler_Capture_stalls_get(VALUE self) {
750
- struct Fiber_Profiler_Capture *profiler = Fiber_Profiler_Capture_get(self);
790
+ struct Fiber_Profiler_Capture *capture = Fiber_Profiler_Capture_get(self);
751
791
 
752
- return SIZET2NUM(profiler->stalls);
792
+ return SIZET2NUM(capture->stalls);
753
793
  }
754
794
 
755
795
  static VALUE Fiber_Profiler_Capture_sample_rate_get(VALUE self) {
756
- struct Fiber_Profiler_Capture *profiler = Fiber_Profiler_Capture_get(self);
796
+ struct Fiber_Profiler_Capture *capture = Fiber_Profiler_Capture_get(self);
757
797
 
758
- return DBL2NUM(profiler->sample_rate);
798
+ return DBL2NUM(capture->sample_rate);
759
799
  }
760
800
 
761
801
  #pragma mark - Environment Variables
@@ -800,18 +840,31 @@ static double FIBER_PROFILER_CAPTURE_SAMPLE_RATE(void) {
800
840
  }
801
841
  }
802
842
 
843
+ static double FIBER_PROFILER_CAPTURE_FILTER_THRESHOLD(void) {
844
+ const char *value = getenv("FIBER_PROFILER_CAPTURE_FILTER_THRESHOLD");
845
+
846
+ if (value) {
847
+ return atof(value);
848
+ } else {
849
+ // We use 10% of the stall threshold as the default filter threshold:
850
+ return Fiber_Profiler_Capture_stall_threshold * 0.1;
851
+ }
852
+ }
853
+
803
854
  #pragma mark - Initialization
804
855
 
805
856
  void Init_Fiber_Profiler_Capture(VALUE Fiber_Profiler) {
806
857
  Fiber_Profiler_capture_p = FIBER_PROFILER_CAPTURE();
807
858
  Fiber_Profiler_Capture_stall_threshold = FIBER_PROFILER_CAPTURE_STALL_THRESHOLD();
859
+ Fiber_Profiler_Capture_filter_threshold = FIBER_PROFILER_CAPTURE_FILTER_THRESHOLD();
808
860
  Fiber_Profiler_Capture_track_calls = FIBER_PROFILER_CAPTURE_TRACK_CALLS();
809
861
  Fiber_Profiler_Capture_sample_rate = FIBER_PROFILER_CAPTURE_SAMPLE_RATE();
810
862
 
811
863
  Fiber_Profiler_Capture_initialize_options[0] = rb_intern("stall_threshold");
812
- Fiber_Profiler_Capture_initialize_options[1] = rb_intern("track_calls");
813
- Fiber_Profiler_Capture_initialize_options[2] = rb_intern("sample_rate");
814
- Fiber_Profiler_Capture_initialize_options[3] = rb_intern("output");
864
+ Fiber_Profiler_Capture_initialize_options[1] = rb_intern("filter_threshold");
865
+ Fiber_Profiler_Capture_initialize_options[2] = rb_intern("track_calls");
866
+ Fiber_Profiler_Capture_initialize_options[3] = rb_intern("sample_rate");
867
+ Fiber_Profiler_Capture_initialize_options[4] = rb_intern("output");
815
868
 
816
869
  Fiber_Profiler_Capture = rb_define_class_under(Fiber_Profiler, "Capture", rb_cObject);
817
870
  rb_define_alloc_func(Fiber_Profiler_Capture, Fiber_Profiler_Capture_allocate);
@@ -824,6 +877,7 @@ void Init_Fiber_Profiler_Capture(VALUE Fiber_Profiler) {
824
877
  rb_define_method(Fiber_Profiler_Capture, "stop", Fiber_Profiler_Capture_stop, 0);
825
878
 
826
879
  rb_define_method(Fiber_Profiler_Capture, "stall_threshold", Fiber_Profiler_Capture_stall_threshold_get, 0);
880
+ rb_define_method(Fiber_Profiler_Capture, "filter_threshold", Fiber_Profiler_Capture_filter_threshold_get, 0);
827
881
  rb_define_method(Fiber_Profiler_Capture, "track_calls", Fiber_Profiler_Capture_track_calls_get, 0);
828
882
  rb_define_method(Fiber_Profiler_Capture, "sample_rate", Fiber_Profiler_Capture_sample_rate_get, 0);
829
883
 
@@ -5,8 +5,4 @@
5
5
 
6
6
  #include <ruby.h>
7
7
 
8
- extern int Fiber_Profiler_capture;
9
- extern float Fiber_Profiler_Capture_stall_threshold;
10
- extern int Fiber_Profiler_Capture_track_calls;
11
-
12
8
  void Init_Fiber_Profiler_Capture(VALUE Fiber_Profiler);
@@ -7,6 +7,6 @@
7
7
  class Fiber
8
8
  # @namespace
9
9
  module Profiler
10
- VERSION = "0.1.5"
10
+ VERSION = "0.3.0"
11
11
  end
12
12
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,10 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fiber-profiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain:
10
11
  - |
@@ -36,8 +37,10 @@ cert_chain:
36
37
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
37
38
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
38
39
  -----END CERTIFICATE-----
39
- date: 2025-02-14 00:00:00.000000000 Z
40
+ date: 2025-02-15 00:00:00.000000000 Z
40
41
  dependencies: []
42
+ description:
43
+ email:
41
44
  executables: []
42
45
  extensions:
43
46
  - ext/extconf.rb
@@ -66,6 +69,7 @@ licenses:
66
69
  metadata:
67
70
  documentation_uri: https://socketry.github.io/fiber-profiler/
68
71
  source_code_uri: https://github.com/socketry/fiber-profiler.git
72
+ post_install_message:
69
73
  rdoc_options: []
70
74
  require_paths:
71
75
  - lib
@@ -80,7 +84,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
84
  - !ruby/object:Gem::Version
81
85
  version: '0'
82
86
  requirements: []
83
- rubygems_version: 3.6.2
87
+ rubygems_version: 3.5.16
88
+ signing_key:
84
89
  specification_version: 4
85
90
  summary: A fiber stall profiler.
86
91
  test_files: []
metadata.gz.sig CHANGED
Binary file