rblineprof 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README.md +25 -22
  2. data/ext/rblineprof.c +56 -28
  3. data/rblineprof.gemspec +1 -1
  4. data/test.rb +8 -3
  5. metadata +4 -4
data/README.md CHANGED
@@ -4,28 +4,31 @@
4
4
  % ruby -C ext extconf.rb
5
5
  % make -C ext
6
6
  % ruby test.rb
7
- | $:.unshift 'ext'
8
- | require 'rblineprof'
9
- |
10
- | profile = lineprof(/./) do
11
- 1 | 1000.times do
12
- |
13
- 410 | 1*2*3
14
- 441 | 4*5*6
15
- 1243 | 7*8*9*10*11*12*13*14*15
16
- 380 | 2**32
17
- 1115 | 2**128
18
- |
19
- | end
20
- | end
21
- |
22
- | File.readlines(__FILE__).each_with_index do |line, num|
23
- | if (sample = profile[__FILE__][num+1]) > 0
24
- | printf "% 6d | %s", sample, line
25
- | else
26
- | printf " | %s", line
27
- | end
28
- | end
7
+ | $:.unshift 'ext'
8
+ | require 'rblineprof'
9
+ |
10
+ | profile = lineprof(/./) do
11
+ 1.2ms | sleep 0.001
12
+ |
13
+ 0.1ms | 100.times do
14
+ |
15
+ 119.6ms | sleep 0.001
16
+ 0.7ms | 1*2*3
17
+ 0.2ms | 4*5*6
18
+ 0.4ms | 7*8*9*10*11*12*13*14*15
19
+ 0.2ms | 2**32
20
+ 1.4ms | 2**128
21
+ |
22
+ | end
23
+ | end
24
+ |
25
+ | File.readlines(__FILE__).each_with_index do |line, num|
26
+ | if (sample = profile[__FILE__][num+1]) > 0
27
+ | printf "% 8.1fms | %s", sample/1000.0, line
28
+ | else
29
+ | printf " | %s", line
30
+ | end
31
+ | end
29
32
  ```
30
33
 
31
34
  ## Other profilers
data/ext/rblineprof.c CHANGED
@@ -22,6 +22,8 @@ typedef struct {
22
22
 
23
23
  static struct {
24
24
  bool enabled;
25
+ char *last_file;
26
+ long last_line;
25
27
 
26
28
  // single file mode, store filename and line data directly
27
29
  char *source_filename;
@@ -30,14 +32,16 @@ static struct {
30
32
  // regex mode, store file data in hash table
31
33
  VALUE source_regex;
32
34
  st_table *files;
33
- sourcefile_t *last_file;
35
+ sourcefile_t *last_sourcefile;
34
36
  }
35
37
  rblineprof = {
36
38
  .enabled = false,
39
+ .last_file = NULL,
40
+ .last_line = 0,
37
41
  .source_filename = NULL,
38
42
  .source_regex = Qfalse,
39
43
  .files = NULL,
40
- .last_file = NULL
44
+ .last_sourcefile = NULL
41
45
  };
42
46
 
43
47
  static uint64_t
@@ -49,17 +53,51 @@ timeofday_usec()
49
53
  (uint64_t)tv.tv_usec;
50
54
  }
51
55
 
56
+ static inline void
57
+ sourcefile_record(sourcefile_t *sourcefile, uint64_t now)
58
+ {
59
+ if (sourcefile->last_time && sourcefile->last_line) {
60
+ /* allocate space for per-line data the first time */
61
+ if (sourcefile->lines == NULL) {
62
+ sourcefile->nlines = sourcefile->last_line + 100;
63
+ sourcefile->lines = ALLOC_N(uint64_t, sourcefile->nlines);
64
+ MEMZERO(sourcefile->lines, uint64_t, sourcefile->nlines);
65
+ }
66
+
67
+ /* grow the per-line array if necessary */
68
+ if (sourcefile->last_line >= sourcefile->nlines) {
69
+ long prev_nlines = sourcefile->nlines;
70
+ sourcefile->nlines = sourcefile->last_line + 100;
71
+
72
+ REALLOC_N(sourcefile->lines, uint64_t, sourcefile->nlines);
73
+ MEMZERO(sourcefile->lines + prev_nlines, uint64_t, sourcefile->nlines - prev_nlines);
74
+ }
75
+
76
+ /* record the sample */
77
+ sourcefile->lines[sourcefile->last_line] += (now - sourcefile->last_time);
78
+ sourcefile->last_time = now;
79
+ }
80
+ }
81
+
52
82
  static void
53
83
  profiler_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
54
84
  {
55
85
  sourcefile_t *sourcefile = NULL;
56
86
 
87
+ if (!node) return;
88
+
57
89
  char *file = node->nd_file;
58
90
  long line = nd_line(node);
59
91
 
60
92
  if (!file) return;
61
93
  if (line <= 0) return;
62
94
 
95
+ // skip duplicate events fast
96
+ if (file == rblineprof.last_file && line == rblineprof.last_line)
97
+ return;
98
+ rblineprof.last_file = file;
99
+ rblineprof.last_line = line;
100
+
63
101
  if (rblineprof.source_filename) { // single file mode
64
102
  if (rblineprof.source_filename == file) {
65
103
  sourcefile = &rblineprof.file;
@@ -90,34 +128,22 @@ profiler_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
90
128
  if (sourcefile) {
91
129
  uint64_t now = timeofday_usec();
92
130
 
93
- if (sourcefile->last_time) {
94
- /* allocate space for per-line data the first time */
95
- if (sourcefile->lines == NULL) {
96
- sourcefile->nlines = sourcefile->last_line + 100;
97
- sourcefile->lines = ALLOC_N(uint64_t, sourcefile->nlines);
98
- MEMZERO(sourcefile->lines, uint64_t, sourcefile->nlines);
99
- }
100
-
101
- /* grow the per-line array if necessary */
102
- if (sourcefile->last_line >= sourcefile->nlines) {
103
- long prev_nlines = sourcefile->nlines;
104
- sourcefile->nlines = sourcefile->last_line + 100;
105
-
106
- REALLOC_N(sourcefile->lines, uint64_t, sourcefile->nlines);
107
- MEMZERO(sourcefile->lines + prev_nlines, uint64_t, sourcefile->nlines - prev_nlines);
108
- }
109
-
110
- /* record the sample */
111
- sourcefile->lines[sourcefile->last_line] += (now - sourcefile->last_time);
131
+ /* increment if the line in the current file changed */
132
+ if (sourcefile->last_line != line) {
133
+ sourcefile_record(sourcefile, now);
112
134
  }
113
-
114
- sourcefile->last_time = now;
115
135
  sourcefile->last_line = line;
116
136
 
117
- if (rblineprof.last_file && rblineprof.last_file != sourcefile)
118
- rblineprof.last_file->last_time = 0;
137
+ if (!sourcefile->last_time)
138
+ sourcefile->last_time = now;
139
+
140
+ /* if we came from another file, increment there and reset */
141
+ if (rblineprof.last_sourcefile && rblineprof.last_sourcefile != sourcefile) {
142
+ sourcefile_record(rblineprof.last_sourcefile, now);
143
+ rblineprof.last_sourcefile->last_line = 0;
144
+ }
119
145
 
120
- rblineprof.last_file = sourcefile;
146
+ rblineprof.last_sourcefile = sourcefile;
121
147
  }
122
148
  }
123
149
 
@@ -181,8 +207,10 @@ lineprof(VALUE self, VALUE filename)
181
207
  rb_raise(rb_eArgError, "argument must be String or Regexp");
182
208
  }
183
209
 
184
- // cleanup
210
+ // reset state
185
211
  rblineprof.last_file = NULL;
212
+ rblineprof.last_line = 0;
213
+ rblineprof.last_sourcefile = NULL;
186
214
  st_foreach(rblineprof.files, cleanup_files, 0);
187
215
  if (rblineprof.file.lines) {
188
216
  xfree(rblineprof.file.lines);
@@ -191,7 +219,7 @@ lineprof(VALUE self, VALUE filename)
191
219
  }
192
220
 
193
221
  rblineprof.enabled = true;
194
- rb_add_event_hook(profiler_hook, RUBY_EVENT_LINE);
222
+ rb_add_event_hook(profiler_hook, RUBY_EVENT_ALL);
195
223
  rb_ensure(rb_yield, Qnil, lineprof_ensure, self);
196
224
 
197
225
  VALUE ret = rb_hash_new();
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.0'
3
+ s.version = '0.2.1'
4
4
  s.homepage = 'http://github.com/tmm1/rblineprof'
5
5
 
6
6
  s.authors = 'Aman Gupta'
data/test.rb CHANGED
@@ -2,8 +2,11 @@ $:.unshift 'ext'
2
2
  require 'rblineprof'
3
3
 
4
4
  profile = lineprof(/./) do
5
- 1000.times do
5
+ sleep 0.001
6
6
 
7
+ 100.times do
8
+
9
+ sleep 0.001
7
10
  1*2*3
8
11
  4*5*6
9
12
  7*8*9*10*11*12*13*14*15
@@ -15,8 +18,10 @@ end
15
18
 
16
19
  File.readlines(__FILE__).each_with_index do |line, num|
17
20
  if (sample = profile[__FILE__][num+1]) > 0
18
- printf "% 6d | %s", sample, line
21
+ # printf "% 7d | %s", sample, line
22
+ printf "% 8.1fms | %s", sample/1000.0, line
19
23
  else
20
- printf " | %s", line
24
+ # printf " | %s", line
25
+ printf " | %s", line
21
26
  end
22
27
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rblineprof
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 0
10
- version: 0.2.0
9
+ - 1
10
+ version: 0.2.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Aman Gupta
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-09-18 00:00:00 Z
18
+ date: 2012-09-24 00:00:00 Z
19
19
  dependencies: []
20
20
 
21
21
  description: rblineprof shows you lines of code that are slow.