rblineprof 0.2.7 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. data/ext/extconf.rb +3 -8
  2. data/ext/rblineprof.c +231 -75
  3. data/rblineprof.gemspec +3 -1
  4. data/test.rb +72 -5
  5. metadata +54 -20
data/ext/extconf.rb CHANGED
@@ -1,16 +1,11 @@
1
1
  require 'mkmf'
2
2
 
3
3
  if RUBY_VERSION >= "1.9"
4
- begin
5
- require "debugger/ruby_core_source"
6
- rescue LoadError
7
- require 'rubygems/dependency_installer'
8
- installer = Gem::DependencyInstaller.new
9
- installer.install 'debugger-ruby_core_source'
10
- require "debugger/ruby_core_source"
11
- end
4
+ require "debugger/ruby_core_source"
12
5
 
13
6
  hdrs = proc {
7
+ have_type("rb_iseq_location_t", "vm_core.h")
8
+
14
9
  have_header("vm_core.h") and
15
10
  have_header("iseq.h")
16
11
  }
data/ext/rblineprof.c CHANGED
@@ -1,5 +1,8 @@
1
1
  #include <ruby.h>
2
2
  #include <stdbool.h>
3
+ #include <time.h>
4
+ #include <sys/time.h>
5
+ #include <sys/resource.h>
3
6
 
4
7
  #ifdef RUBY_VM
5
8
  #include <ruby/re.h>
@@ -20,17 +23,27 @@
20
23
  typedef rb_event_t rb_event_flag_t;
21
24
  #endif
22
25
 
23
- typedef uint64_t prof_time_t;
24
26
  static VALUE gc_hook;
25
27
 
26
28
  /*
27
- * Struct representing an individual line of
28
- * Ruby source code
29
+ * Time in microseconds
30
+ */
31
+ typedef uint64_t prof_time_t;
32
+
33
+ /*
34
+ * Profiling snapshot
35
+ */
36
+ typedef struct snapshot {
37
+ prof_time_t wall_time;
38
+ prof_time_t cpu_time;
39
+ } snapshot_t;
40
+
41
+ /*
42
+ * A line of Ruby source code
29
43
  */
30
44
  typedef struct sourceline {
31
- uint64_t calls; // total number of calls
32
- prof_time_t total_time;
33
- prof_time_t max_time;
45
+ uint64_t calls; // total number of call/c_call events
46
+ snapshot_t total;
34
47
  } sourceline_t;
35
48
 
36
49
  /*
@@ -38,11 +51,17 @@ typedef struct sourceline {
38
51
  */
39
52
  typedef struct sourcefile {
40
53
  char *filename;
54
+
55
+ /* per line timing */
41
56
  long nlines;
42
57
  sourceline_t *lines;
43
58
 
44
- prof_time_t exclusive_start;
45
- prof_time_t exclusive_time;
59
+ /* overall file timing */
60
+ snapshot_t total;
61
+ snapshot_t child;
62
+ uint64_t depth;
63
+ snapshot_t exclusive_start;
64
+ snapshot_t exclusive;
46
65
  } sourcefile_t;
47
66
 
48
67
  /*
@@ -64,7 +83,7 @@ typedef struct stackframe {
64
83
  char *filename;
65
84
  long line;
66
85
 
67
- prof_time_t start;
86
+ snapshot_t start;
68
87
  sourcefile_t *srcfile;
69
88
  } stackframe_t;
70
89
 
@@ -79,9 +98,6 @@ static struct {
79
98
  stackframe_t stack[MAX_STACK_DEPTH];
80
99
  uint64_t stack_depth;
81
100
 
82
- // current file
83
- sourcefile_t *curr_srcfile;
84
-
85
101
  // single file mode, store filename and line data directly
86
102
  char *source_filename;
87
103
  sourcefile_t file;
@@ -102,7 +118,30 @@ rblineprof = {
102
118
  };
103
119
 
104
120
  static prof_time_t
105
- timeofday_usec()
121
+ cputime_usec()
122
+ {
123
+ #if defined(__linux__)
124
+ struct timespec ts;
125
+
126
+ if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == 0) {
127
+ return (prof_time_t)ts.tv_sec*1e6 +
128
+ (prof_time_t)ts.tv_nsec*1e-3;
129
+ }
130
+ #endif
131
+
132
+ #if defined(RUSAGE_SELF)
133
+ struct rusage usage;
134
+
135
+ getrusage(RUSAGE_SELF, &usage);
136
+ return (prof_time_t)usage.ru_utime.tv_sec*1e6 +
137
+ (prof_time_t)usage.ru_utime.tv_usec;
138
+ #endif
139
+
140
+ return 0;
141
+ }
142
+
143
+ static prof_time_t
144
+ walltime_usec()
106
145
  {
107
146
  struct timeval tv;
108
147
  gettimeofday(&tv, NULL);
@@ -110,8 +149,26 @@ timeofday_usec()
110
149
  (prof_time_t)tv.tv_usec;
111
150
  }
112
151
 
152
+ static inline snapshot_t
153
+ snapshot_diff(snapshot_t *t1, snapshot_t *t2)
154
+ {
155
+ snapshot_t diff = {
156
+ .wall_time = t1->wall_time - t2->wall_time,
157
+ .cpu_time = t1->cpu_time - t2->cpu_time,
158
+ };
159
+
160
+ return diff;
161
+ }
162
+
113
163
  static inline void
114
- stackframe_record(stackframe_t *frame, prof_time_t now)
164
+ snapshot_increment(snapshot_t *s, snapshot_t *inc)
165
+ {
166
+ s->wall_time += inc->wall_time;
167
+ s->cpu_time += inc->cpu_time;
168
+ }
169
+
170
+ static inline void
171
+ stackframe_record(stackframe_t *frame, snapshot_t now, stackframe_t *caller_frame)
115
172
  {
116
173
  sourcefile_t *srcfile = frame->srcfile;
117
174
  long line = frame->line;
@@ -132,13 +189,35 @@ stackframe_record(stackframe_t *frame, prof_time_t now)
132
189
  MEMZERO(srcfile->lines + prev_nlines, sourceline_t, srcfile->nlines - prev_nlines);
133
190
  }
134
191
 
135
- /* record the sample */
136
- prof_time_t diff = now - frame->start;
192
+ snapshot_t diff = snapshot_diff(&now, &frame->start);
137
193
  sourceline_t *srcline = &(srcfile->lines[line]);
194
+
195
+ /* Line profiler metrics.
196
+ */
197
+
138
198
  srcline->calls++;
139
- srcline->total_time += diff;
140
- if (diff > srcline->max_time)
141
- srcline->max_time = diff;
199
+
200
+ /* Increment current line's total_time.
201
+ *
202
+ * Skip the special case where the stack frame we're returning to
203
+ * had the same file/line. This fixes double counting on crazy one-liners.
204
+ */
205
+ if (!(caller_frame && caller_frame->srcfile == frame->srcfile && caller_frame->line == frame->line))
206
+ snapshot_increment(&srcline->total, &diff);
207
+
208
+ /* File profiler metrics.
209
+ */
210
+
211
+ /* Increment the caller file's child_time.
212
+ */
213
+ if (caller_frame && caller_frame->srcfile != srcfile)
214
+ snapshot_increment(&caller_frame->srcfile->child, &diff);
215
+
216
+ /* Increment current file's total_time, but only when we return
217
+ * to the outermost stack frame when we first entered the file.
218
+ */
219
+ if (srcfile->depth == 0)
220
+ snapshot_increment(&srcfile->total, &diff);
142
221
  }
143
222
 
144
223
  static inline sourcefile_t*
@@ -165,7 +244,12 @@ sourcefile_lookup(char *filename)
165
244
  return NULL;
166
245
 
167
246
  if (!srcfile) { // unknown file, check against regex
168
- if (rb_reg_search(rblineprof.source_regex, rb_str_new2(filename), 0, 0) >= 0) {
247
+ VALUE backref = rb_backref_get();
248
+ rb_match_busy(backref);
249
+ long rc = rb_reg_search(rblineprof.source_regex, rb_str_new2(filename), 0, 0);
250
+ rb_backref_set(backref);
251
+
252
+ if (rc >= 0) {
169
253
  srcfile = ALLOC_N(sourcefile_t, 1);
170
254
  MEMZERO(srcfile, sourcefile_t, 1);
171
255
  srcfile->filename = strdup(filename);
@@ -188,6 +272,7 @@ sourcefile_lookup(char *filename)
188
272
  * top-most cfp on the stack in these cases points to the 'def method' line, so we skip
189
273
  * these and grab the second caller instead.
190
274
  */
275
+ static inline
191
276
  rb_control_frame_t *
192
277
  rb_vm_get_caller(rb_thread_t *th, rb_control_frame_t *cfp, ID mid)
193
278
  {
@@ -205,6 +290,26 @@ rb_vm_get_caller(rb_thread_t *th, rb_control_frame_t *cfp, ID mid)
205
290
 
206
291
  return 0;
207
292
  }
293
+
294
+ #ifdef HAVE_TYPE_RB_ISEQ_LOCATION_T
295
+ inline static int
296
+ calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
297
+ {
298
+ return rb_iseq_line_no(iseq, pc - iseq->iseq_encoded);
299
+ }
300
+
301
+ int
302
+ rb_vm_get_sourceline(const rb_control_frame_t *cfp)
303
+ {
304
+ int lineno = 0;
305
+ const rb_iseq_t *iseq = cfp->iseq;
306
+
307
+ if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
308
+ lineno = calc_lineno(cfp->iseq, cfp->pc);
309
+ }
310
+ return lineno;
311
+ }
312
+ #endif
208
313
  #endif
209
314
 
210
315
  static void
@@ -216,40 +321,8 @@ profiler_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE klass
216
321
  {
217
322
  char *file;
218
323
  long line;
219
- stackframe_t *frame = NULL;
220
- sourcefile_t *srcfile, *curr_srcfile;
221
- prof_time_t now = timeofday_usec();
222
-
223
- #if 0
224
- /* file profiler: when invoking a method in a new file, account elapsed
225
- * time to the current file and start a new timer.
226
- */
227
- #ifndef RUBY_VM
228
- if (!node) return;
229
- file = node->nd_file;
230
- line = nd_line(node);
231
- #else
232
- // this returns filename (instead of filepath) on 1.9
233
- file = (char *) rb_sourcefile();
234
- line = rb_sourceline();
235
- #endif
236
-
237
- if (!file) return;
238
- if (line <= 0) return;
239
-
240
- srcfile = sourcefile_lookup(file);
241
- curr_srcfile = rblineprof.curr_srcfile;
242
-
243
- if (curr_srcfile != srcfile) {
244
- if (curr_srcfile)
245
- curr_srcfile->exclusive_time += now - curr_srcfile->exclusive_start;
246
-
247
- if (srcfile)
248
- srcfile->exclusive_start = now;
249
-
250
- rblineprof.curr_srcfile = srcfile;
251
- }
252
- #endif
324
+ stackframe_t *frame = NULL, *prev = NULL;
325
+ sourcefile_t *srcfile;
253
326
 
254
327
  /* line profiler: maintain a stack of CALL events with timestamps. for
255
328
  * each corresponding RETURN, account elapsed time to the calling line.
@@ -264,14 +337,21 @@ profiler_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE klass
264
337
  file = caller_node->nd_file;
265
338
  line = nd_line(caller_node);
266
339
  #else
267
- rb_thread_t *th = GET_THREAD();
340
+ rb_thread_t *th = ruby_current_thread;
268
341
  rb_control_frame_t *cfp = rb_vm_get_caller(th, th->cfp, mid);
269
342
  if (!cfp) return;
270
343
 
271
- if (RTEST(cfp->iseq->filepath))
272
- file = StringValueCStr(cfp->iseq->filepath);
273
- else
274
- file = StringValueCStr(cfp->iseq->filename);
344
+ #ifdef HAVE_TYPE_RB_ISEQ_LOCATION_T
345
+ if (RTEST(cfp->iseq->location.absolute_path))
346
+ file = StringValueCStr(cfp->iseq->location.absolute_path);
347
+ else
348
+ file = StringValueCStr(cfp->iseq->location.path);
349
+ #else
350
+ if (RTEST(cfp->iseq->filepath))
351
+ file = StringValueCStr(cfp->iseq->filepath);
352
+ else
353
+ file = StringValueCStr(cfp->iseq->filename);
354
+ #endif
275
355
  line = rb_vm_get_sourceline(cfp);
276
356
  #endif
277
357
 
@@ -294,46 +374,115 @@ profiler_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE klass
294
374
  rblineprof.cache.srcfile = srcfile;
295
375
  if (!srcfile) return; /* skip line profiling for this file */
296
376
 
377
+ snapshot_t now = {
378
+ .wall_time = walltime_usec(),
379
+ .cpu_time = cputime_usec(),
380
+ };
381
+
297
382
  switch (event) {
298
383
  case RUBY_EVENT_CALL:
299
384
  case RUBY_EVENT_C_CALL:
385
+ /* Create a stack frame entry with this event,
386
+ * the current file, and a snapshot of metrics.
387
+ *
388
+ * On a corresponding RETURN event later, we can
389
+ * pop this stack frame and accumulate metrics to the
390
+ * associated file and line.
391
+ */
300
392
  rblineprof.stack_depth++;
301
393
  if (rblineprof.stack_depth > 0 && rblineprof.stack_depth < MAX_STACK_DEPTH) {
302
394
  frame = &rblineprof.stack[rblineprof.stack_depth-1];
303
395
  frame->event = event;
304
-
305
- #ifdef RUBY_VM
306
- frame->thread = th;
307
- #else
308
- frame->node = node;
309
- #endif
310
396
  frame->self = self;
311
397
  frame->mid = mid;
312
398
  frame->klass = klass;
313
399
  frame->line = line;
314
400
  frame->start = now;
315
401
  frame->srcfile = srcfile;
402
+ #ifdef RUBY_VM
403
+ frame->thread = th;
404
+ #else
405
+ frame->node = node;
406
+ #endif
407
+ }
408
+
409
+ /* Record when we entered this file for the first time.
410
+ * The difference is later accumulated into exclusive_time,
411
+ * e.g. on the next event if the file changes.
412
+ */
413
+ if (srcfile->depth == 0)
414
+ srcfile->exclusive_start = now;
415
+ srcfile->depth++;
416
+
417
+ if (rblineprof.stack_depth > 1) { // skip if outermost frame
418
+ prev = &rblineprof.stack[rblineprof.stack_depth-2];
419
+
420
+ /* If we just switched files, record time that was spent in
421
+ * the previous file.
422
+ */
423
+ if (prev->srcfile != frame->srcfile) {
424
+ snapshot_t diff = snapshot_diff(&now, &prev->srcfile->exclusive_start);
425
+ snapshot_increment(&prev->srcfile->exclusive, &diff);
426
+ prev->srcfile->exclusive_start = now;
427
+ }
316
428
  }
317
429
  break;
318
430
 
319
431
  case RUBY_EVENT_RETURN:
320
432
  case RUBY_EVENT_C_RETURN:
433
+ /* Find the corresponding CALL for this event.
434
+ *
435
+ * We loop here instead of a simple pop, because in the event of a
436
+ * raise/rescue several stack frames could have disappeared.
437
+ */
321
438
  do {
322
- if (rblineprof.stack_depth > 0 && rblineprof.stack_depth < MAX_STACK_DEPTH)
439
+ if (rblineprof.stack_depth > 0 && rblineprof.stack_depth < MAX_STACK_DEPTH) {
323
440
  frame = &rblineprof.stack[rblineprof.stack_depth-1];
324
- else
441
+ if (frame->srcfile->depth > 0)
442
+ frame->srcfile->depth--;
443
+ } else
325
444
  frame = NULL;
445
+
326
446
  rblineprof.stack_depth--;
327
447
  } while (frame &&
328
448
  #ifdef RUBY_VM
329
449
  frame->thread != th &&
330
450
  #endif
451
+ /* Break when we find a matching CALL/C_CALL.
452
+ */
453
+ frame->event != (event == RUBY_EVENT_CALL ? RUBY_EVENT_RETURN : RUBY_EVENT_C_RETURN) &&
331
454
  frame->self != self &&
332
455
  frame->mid != mid &&
333
456
  frame->klass != klass);
334
457
 
458
+ if (rblineprof.stack_depth > 0) {
459
+ // The new top of the stack (that we're returning to)
460
+ prev = &rblineprof.stack[rblineprof.stack_depth-1];
461
+
462
+ /* If we're leaving this frame to go back to a different file,
463
+ * accumulate time we spent in this file.
464
+ *
465
+ * Note that we do this both when entering a new file and leaving to
466
+ * a new file to ensure we only count time spent exclusively in that file.
467
+ * Consider the following scenario:
468
+ *
469
+ * call (a.rb:1)
470
+ * call (b.rb:1) <-- leaving a.rb, increment into exclusive_time
471
+ * call (a.rb:5)
472
+ * return <-- leaving a.rb, increment into exclusive_time
473
+ * return
474
+ * return
475
+ */
476
+ if (frame->srcfile != prev->srcfile) {
477
+ snapshot_t diff = snapshot_diff(&now, &frame->srcfile->exclusive_start);
478
+ snapshot_increment(&frame->srcfile->exclusive, &diff);
479
+ frame->srcfile->exclusive_start = now;
480
+ prev->srcfile->exclusive_start = now;
481
+ }
482
+ }
483
+
335
484
  if (frame)
336
- stackframe_record(frame, now);
485
+ stackframe_record(frame, now, prev);
337
486
 
338
487
  break;
339
488
  }
@@ -364,9 +513,21 @@ summarize_files(st_data_t key, st_data_t record, st_data_t arg)
364
513
  VALUE ary = rb_ary_new();
365
514
  long i;
366
515
 
367
- rb_ary_store(ary, 0, ULL2NUM(srcfile->exclusive_time));
516
+ rb_ary_store(ary, 0, rb_ary_new3(6,
517
+ ULL2NUM(srcfile->total.wall_time),
518
+ ULL2NUM(srcfile->child.wall_time),
519
+ ULL2NUM(srcfile->exclusive.wall_time),
520
+ ULL2NUM(srcfile->total.cpu_time),
521
+ ULL2NUM(srcfile->child.cpu_time),
522
+ ULL2NUM(srcfile->exclusive.cpu_time)
523
+ ));
524
+
368
525
  for (i=1; i<srcfile->nlines; i++)
369
- rb_ary_store(ary, i, rb_ary_new3(2, ULL2NUM(srcfile->lines[i].total_time), ULL2NUM(srcfile->lines[i].calls)));
526
+ rb_ary_store(ary, i, rb_ary_new3(3,
527
+ ULL2NUM(srcfile->lines[i].total.wall_time),
528
+ ULL2NUM(srcfile->lines[i].total.cpu_time),
529
+ ULL2NUM(srcfile->lines[i].calls)
530
+ ));
370
531
  rb_hash_aset(ret, rb_str_new2(srcfile->filename), ary);
371
532
 
372
533
  return ST_CONTINUE;
@@ -408,7 +569,6 @@ lineprof(VALUE self, VALUE filename)
408
569
  }
409
570
 
410
571
  // reset state
411
- rblineprof.curr_srcfile = NULL;
412
572
  st_foreach(rblineprof.files, cleanup_files, 0);
413
573
  if (rblineprof.file.lines) {
414
574
  xfree(rblineprof.file.lines);
@@ -427,10 +587,6 @@ lineprof(VALUE self, VALUE filename)
427
587
 
428
588
  rb_ensure(rb_yield, Qnil, lineprof_ensure, self);
429
589
 
430
- sourcefile_t *curr_srcfile = rblineprof.curr_srcfile;
431
- if (curr_srcfile)
432
- curr_srcfile->exclusive_time += timeofday_usec() - curr_srcfile->exclusive_start;
433
-
434
590
  VALUE ret = rb_hash_new();
435
591
  VALUE ary = Qnil;
436
592
 
data/rblineprof.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'rblineprof'
3
- s.version = '0.2.7'
3
+ s.version = '0.3.2'
4
4
  s.homepage = 'http://github.com/tmm1/rblineprof'
5
5
 
6
6
  s.authors = 'Aman Gupta'
@@ -11,4 +11,6 @@ Gem::Specification.new do |s|
11
11
 
12
12
  s.summary = 'line-profiler for ruby'
13
13
  s.description = 'rblineprof shows you lines of code that are slow.'
14
+
15
+ s.add_dependency 'debugger-ruby_core_source', '~> 1.2'
14
16
  end
data/test.rb CHANGED
@@ -9,6 +9,40 @@ class Obj
9
9
  def another(options={})
10
10
  sleep 0.001
11
11
  end
12
+
13
+ def out=(*)
14
+ end
15
+
16
+ def with_defaults(arg=self.object_id.to_s)
17
+ another
18
+ list = [1,2,3]
19
+ # for cookie in list
20
+ # self.out=(
21
+ dummy(
22
+ 1, "str
23
+ ing")
24
+ dummy <<-EOS
25
+ hi
26
+ EOS
27
+ dummy \
28
+ 1234
29
+ dummy :a => 'b',
30
+ :c => 'd',
31
+ :e => 1024**1024,
32
+ 'something' => dummy(:ok)
33
+ # )
34
+ # end
35
+ end
36
+
37
+ def dummy(*args)
38
+ args.inspect
39
+ end
40
+
41
+ class_eval <<-RUBY, 'otherfile.rb', 1
42
+ def other_file
43
+ another
44
+ end
45
+ RUBY
12
46
  end
13
47
 
14
48
  def inner
@@ -22,10 +56,29 @@ def inner
22
56
  o = Obj.new
23
57
  o.inner_block
24
58
  o.another
59
+ o.other_file
60
+ o.with_defaults
25
61
  end
26
62
 
27
63
  def outer
28
- sleep 0.001
64
+ sleep 0.01
65
+
66
+ 3000.times{ 2**1024 }
67
+ for i in 1..3000 do 2**1024 end
68
+
69
+ for i in 1..3000
70
+ 2**1024
71
+ end
72
+
73
+ (fibonacci = Hash.new{ |h,k| h[k] = k < 2 ? k : h[k-1] + h[k-2] })[500]
74
+
75
+ (fibonacci = Hash.new{ |h,k|
76
+ h[k] = k < 2 ?
77
+ k :
78
+ h[k-1] +
79
+ h[k-2]
80
+ })
81
+ fibonacci[500]
29
82
 
30
83
  100.times do
31
84
  inner
@@ -34,16 +87,30 @@ def outer
34
87
  inner
35
88
  end
36
89
 
90
+ file = RUBY_VERSION > '1.9' ? File.expand_path(__FILE__) : __FILE__
91
+
92
+ # profile = lineprof(file) do
37
93
  profile = lineprof(/./) do
38
94
  outer
39
95
  end
40
96
 
41
- file = File.expand_path(__FILE__)
42
97
  File.readlines(file).each_with_index do |line, num|
43
- time, calls = profile[file][num+1]
98
+ wall, cpu, calls = profile[file][num+1]
44
99
  if calls && calls > 0
45
- printf "% 8.1fms (% 5d) | %s", time/1000.0, calls, line
100
+ printf "% 8.1fms + % 8.1fms (% 5d) | %s", cpu/1000.0, (wall-cpu)/1000.0, calls, line
101
+ # printf "% 8.1fms (% 5d) | %s", wall/1000.0, calls, line
46
102
  else
47
- printf " | %s", line
103
+ printf " | %s", line
104
+ # printf " | %s", line
48
105
  end
49
106
  end
107
+
108
+ puts
109
+ profile.each do |file, data|
110
+ total, child, exclusive = data[0]
111
+ puts file
112
+ printf " % 10.1fms in this file\n", exclusive/1000.0
113
+ printf " % 10.1fms in this file + children\n", total/1000.0
114
+ printf " % 10.1fms in children\n", child/1000.0
115
+ puts
116
+ end
metadata CHANGED
@@ -1,23 +1,46 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: rblineprof
3
- version: !ruby/object:Gem::Version
4
- version: 0.2.7
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 3
9
+ - 2
10
+ version: 0.3.2
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Aman Gupta
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2013-02-13 00:00:00.000000000 Z
13
- dependencies: []
17
+
18
+ date: 2013-04-19 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: debugger-ruby_core_source
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ hash: 11
29
+ segments:
30
+ - 1
31
+ - 2
32
+ version: "1.2"
33
+ type: :runtime
34
+ version_requirements: *id001
14
35
  description: rblineprof shows you lines of code that are slow.
15
36
  email: aman@tmm1.net
16
37
  executables: []
17
- extensions:
38
+
39
+ extensions:
18
40
  - ext/extconf.rb
19
41
  extra_rdoc_files: []
20
- files:
42
+
43
+ files:
21
44
  - README.md
22
45
  - ext/.gitignore
23
46
  - ext/extconf.rb
@@ -26,26 +49,37 @@ files:
26
49
  - test.rb
27
50
  homepage: http://github.com/tmm1/rblineprof
28
51
  licenses: []
52
+
29
53
  post_install_message:
30
54
  rdoc_options: []
31
- require_paths:
55
+
56
+ require_paths:
32
57
  - lib
33
- required_ruby_version: !ruby/object:Gem::Requirement
58
+ required_ruby_version: !ruby/object:Gem::Requirement
34
59
  none: false
35
- requirements:
36
- - - ! '>='
37
- - !ruby/object:Gem::Version
38
- version: '0'
39
- required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ hash: 3
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
68
  none: false
41
- requirements:
42
- - - ! '>='
43
- - !ruby/object:Gem::Version
44
- version: '0'
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
45
76
  requirements: []
77
+
46
78
  rubyforge_project:
47
- rubygems_version: 1.8.23
79
+ rubygems_version: 1.8.24
48
80
  signing_key:
49
81
  specification_version: 3
50
82
  summary: line-profiler for ruby
51
83
  test_files: []
84
+
85
+ has_rdoc: