rblineprof 0.2.7 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
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: