benelux 0.3.2 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,21 @@
1
1
  BENELUX, CHANGES
2
2
 
3
3
 
4
+ #### 0.4.1 (2009-10-06) ###############################
5
+
6
+ * FIXED: Nil @thread error in reporter
7
+ * CHANGE: Reporter starts only one thread.
8
+
9
+
10
+ #### 0.4.0 (2009-10-05) ###############################
11
+
12
+ * CHANGE: All tag values are stored as strings. Keys can be anything.
13
+ * CHANGE: Removed object-specific timelines
14
+ * CHANGED: Stats calculators no longer keep all values
15
+ * ADDED: Counts
16
+ * ADDED: Reporter thread
17
+
18
+
4
19
  #### 0.3.2 (2009-10-02) ###############################
5
20
 
6
21
  * CHANGE: Major performance improvement.
@@ -1,4 +1,4 @@
1
- = Benelux v0.3 (IN PROGRESS)
1
+ = Benelux v0.4 (IN PROGRESS)
2
2
 
3
3
  <b>A madhouse of timers for your Ruby codes</b>
4
4
 
@@ -1,7 +1,7 @@
1
1
  @spec = Gem::Specification.new do |s|
2
2
  s.name = "benelux"
3
3
  s.rubyforge_project = 'benelux'
4
- s.version = "0.3.2"
4
+ s.version = "0.4.1"
5
5
  s.summary = "Benelux: Little freakin' timers for your Ruby codes"
6
6
  s.description = s.summary
7
7
  s.author = "Delano Mandelbaum"
@@ -24,17 +24,28 @@
24
24
  Rakefile
25
25
  benelux.gemspec
26
26
  lib/benelux.rb
27
+ lib/benelux/count.rb
27
28
  lib/benelux/mark.rb
29
+ lib/benelux/mixins/symbol.rb
28
30
  lib/benelux/mixins/thread.rb
31
+ lib/benelux/packer.rb
29
32
  lib/benelux/range.rb
33
+ lib/benelux/reporter.rb
30
34
  lib/benelux/stats.rb
31
- lib/benelux/tags.rb
32
35
  lib/benelux/timeline.rb
36
+ lib/benelux/track.rb
37
+ lib/selectable.rb
38
+ lib/selectable/global.rb
39
+ lib/selectable/object.rb
40
+ lib/selectable/tags.rb
33
41
  tryouts/10_stats_tryouts.rb
34
- tryouts/11_tags_tryouts.rb
35
- tryouts/20_class_methods_tryouts.rb
42
+ tryouts/11_selectable_tryouts.rb
43
+ tryouts/12_selectable_global_tryouts.rb
44
+ tryouts/20_tracks_tryouts.rb
45
+ tryouts/30_reporter_tryouts.rb
36
46
  tryouts/30_timeline_tryouts.rb
37
47
  tryouts/proofs/alias_performance.rb
48
+ tryouts/proofs/array_performance.rb
38
49
  tryouts/proofs/timer_threading.rb
39
50
  )
40
51
 
@@ -1,246 +1,215 @@
1
1
  require 'attic'
2
2
  require 'hexoid'
3
3
  require 'thread'
4
+ require 'thwait'
5
+ require 'selectable'
4
6
 
5
7
  module Benelux
6
- VERSION = "0.3.2"
8
+ VERSION = "0.4.1"
7
9
  NOTSUPPORTED = [Class, Object, Kernel]
8
10
 
9
11
  class BeneluxError < RuntimeError; end
10
12
  class NotSupported < BeneluxError; end
11
- class NoTrack < BeneluxError; end
13
+ class AlreadyTimed < BeneluxError; end
14
+ class UnknownTrack < BeneluxError; end
15
+ class BadRecursion < BeneluxError; end
12
16
 
13
- require 'benelux/tags'
14
17
  require 'benelux/mark'
18
+ require 'benelux/count'
19
+ require 'benelux/track'
15
20
  require 'benelux/range'
16
21
  require 'benelux/stats'
22
+ require 'benelux/packer'
23
+ require 'benelux/reporter'
17
24
  require 'benelux/timeline'
18
25
  require 'benelux/mixins/thread'
26
+ require 'benelux/mixins/symbol'
19
27
 
20
- @@timed_methods = {}
21
- @@known_threads = []
22
- @@timelines = {}
23
- @@mutex = Mutex.new
24
- @@debug = true
28
+ class << self
29
+ attr_reader :packed_methods
30
+ attr_reader :tracks
31
+ attr_reader :timeline
32
+ attr_reader :reporter
33
+ end
25
34
 
26
- def Benelux.enable_debug; @@debug = true; end
27
- def Benelux.disable_debug; @@debug = false; end
28
- def Benelux.debug?; @@debug; end
35
+ @packed_methods = SelectableArray.new
36
+ @tracks = SelectableHash.new
37
+ @timeline = Timeline.new
38
+ @reporter = Reporter.new
29
39
 
30
- # Returns an Array of method names for the current class that
31
- # are timed by Benelux.
32
- #
33
- # This is an instance method for objects which have Benelux
34
- # modified methods.
35
- def benelux_timers
36
- Benelux.timed_methods[self.class]
37
- end
40
+ @@mutex = Mutex.new
41
+ @@debug = false
42
+ @@logger = STDERR
38
43
 
39
- def Benelux.timeline(track=nil)
40
- if track.nil?
41
- if Benelux.timelines.empty?
42
- tl = known_threads.collect { |t| t.timeline}
43
- else
44
- tl = Benelux.timelines.values
45
- end
46
- Benelux.merge_timelines *tl
47
- else
48
- Benelux.timelines[track]
49
- end
44
+ def Benelux.thread_timeline
45
+ Thread.current.timeline
50
46
  end
51
47
 
52
- # Must be run in single-threaded mode (after all track threads
53
- # have finished).
54
- #
55
- def Benelux.update_all_track_timelines
56
- Benelux.timelines.keys.each { |track| Benelux.update_track_timeline(track) }
48
+ def Benelux.track(name)
49
+ raise UnknownTrack unless track? name
50
+ @tracks[name]
57
51
  end
58
52
 
59
- # Must be run from the master thread in the current track. The master
60
- # thread is either the first thread in a track or the one which creates
61
- # additional threads for the track.
62
- #
63
- def Benelux.update_track_timeline(track=nil)
64
- track = Thread.current.track if track.nil?
65
- threads = Benelux.known_threads.select { |t| t.track == track }
66
- Benelux.timelines[track] = Benelux.merge_timelines(*threads.collect { |t| t.timeline })
67
- threads.each { |t| t.timeline.clear }
68
- Benelux.timelines[track]
53
+ def Benelux.track?(name)
54
+ @tracks.has_key? name
69
55
  end
70
56
 
71
- # If +track+ is specified, this will associate the current
72
- # thread with that +track+.
57
+ # If +name+ is specified, this will associate the current
58
+ # thread with that Track +name+ (the Track will be created
59
+ # if necessary).
73
60
  #
74
- # If +track+ is nil, it returns the timeline for the
75
- # track associated to the current thread.
61
+ # If +track+ is nil, it returns the Track object for the
62
+ # Track associated to the current thread.
76
63
  #
77
- def Benelux.current_track(track=nil)
78
- if track.nil?
79
- raise NoTrack if Benelux.timelines[Thread.current.track].nil?
80
- return Benelux.timelines[Thread.current.track]
81
- end
82
- Benelux.store_thread_reference
83
- @@mutex.synchronize do
84
- # QUESTION: Is it okay for multiple threads to write to
85
- # different elements in the same hash?
86
- Benelux.timelines[track] ||= Benelux::Timeline.new
87
- Benelux.add_thread_tags :track => track
88
- Thread.current.track = track
64
+ def Benelux.current_track(name=nil,group=nil)
65
+ if name.nil?
66
+ name = Thread.current.track_name
67
+ else
68
+ Thread.current.track_name = name
69
+ Thread.current.timeline ||= Benelux::Timeline.new
70
+ @@mutex.synchronize do
71
+ @tracks[name] ||= Track.new(name, group)
72
+ @tracks[name].add_thread Thread.current
73
+ @reporter.add_thread Thread.current
74
+ end
89
75
  end
76
+ Benelux.track(name)
90
77
  end
78
+ Benelux.current_track :main
91
79
 
92
- # Combine two or more timelines into a new, single Benelux::Timeline.
93
- #
94
- def Benelux.merge_timelines(*timelines)
95
- tl, stats, ranges = Benelux::Timeline.new, Benelux::Stats.new, []
96
- timelines.each do |t|
97
- tl += t
98
- end
99
- tl
80
+ # Thread tags become the default for any new Mark or Range.
81
+ def Benelux.add_thread_tags(args=Selectable::Tags.new)
82
+
83
+ Benelux.thread_timeline.add_default_tags args
100
84
  end
85
+ def Benelux.add_thread_tag(*args) add_thread_tags *args end
101
86
 
102
- def Benelux.thread_timeline
103
- Thread.current.timeline ||= Benelux::Timeline.new
104
- Thread.current.timeline
87
+ def Benelux.remove_thread_tags(*args)
88
+ Benelux.thread_timeline.remove_default_tags *args
105
89
  end
90
+ def Benelux.remove_thread_tag(*args) remove_thread_tags *args end
106
91
 
107
- # Make note of the class which included Benelux.
108
- def Benelux.included(klass)
109
- timed_methods[klass] = [] unless timed_methods.has_key? klass
92
+
93
+ def Benelux.inspect
94
+ str = ["Benelux"]
95
+ str << "tracks:" << Benelux.tracks.inspect
96
+ str << "timers:" << Benelux.timed_methods.inspect
97
+ #str << "timeline:" << Benelux.timeline.inspect
98
+ str.join $/
110
99
  end
111
100
 
112
- def Benelux.timed_method? klass, meth
113
- !timed_methods[klass].nil? && timed_methods[klass].member?(meth)
101
+ def Benelux.supported?(klass)
102
+ !NOTSUPPORTED.member?(klass)
114
103
  end
115
104
 
116
- def Benelux.add_timer klass, meth
117
- raise NotSupported, klass unless Benelux.supported? klass
118
- raise AlreadyTimed, klass if Benelux.timed_method? klass, meth
119
- prepare_object klass
120
- meth_alias = rename_method klass, meth
121
- timed_methods[klass] << meth
122
- klass.module_eval generate_timer_str(meth_alias, meth), __FILE__, 215
105
+ def Benelux.timed_methods
106
+ Benelux.packed_methods.filter :kind => :'Benelux::MethodTimer'
107
+ end
108
+
109
+ def Benelux.counted_methods
110
+ Benelux.packed_methods.filter :kind => :'Benelux::MethodCounter'
123
111
  end
124
112
 
125
- def Benelux.add_tally obj, meth
113
+ def Benelux.known_thread?(t=Thread.current)
114
+ @reporter.thwait.threads.member? t
126
115
  end
127
116
 
128
- def Benelux.name(*names)
129
- names.flatten.collect { |n| n.to_s }.join('_')
117
+ def Benelux.known_threads
118
+ @reporter.thwait.threads
130
119
  end
131
120
 
121
+ def Benelux.reporting_wait
122
+ @reporter.wait
123
+ end
132
124
 
133
- def Benelux.prepare_object obj
134
- obj.extend Attic unless obj.kind_of?(Attic)
135
- unless obj.kind_of?(Benelux)
136
- obj.attic :timeline
137
- obj.send :include, Benelux
138
- end
125
+ def Benelux.packed_method(klass, meth)
126
+ Benelux.packed_methods.filter(klass.to_s.to_sym, meth).first
139
127
  end
140
-
141
- # Benelux keeps track of the threads which have timed
142
- # objects so it can process the timelines after all is
143
- # said and done.
144
- def Benelux.store_thread_reference
145
- return if Benelux.known_threads.member? Thread.current
146
- @@mutex.synchronize do
147
- Thread.current.timeline ||= Benelux::Timeline.new
148
- Benelux.known_threads << Thread.current
149
- Benelux.known_threads.uniq!
150
- end
128
+
129
+ def Benelux.counted_method(klass, meth)
130
+ Benelux.counted_methods.filter(klass.to_s.to_sym, meth).first
151
131
  end
152
132
 
153
- # Thread tags become the default for any new Mark or Range.
154
- def Benelux.add_thread_tags(args=Benelux::Tags.new)
155
- Benelux.thread_timeline.add_default_tags args
133
+ def Benelux.timed_method(klass, meth)
134
+ Benelux.timed_methods.filter(klass.to_s.to_sym, meth).first
156
135
  end
157
- def Benelux.add_thread_tag(*args) add_thread_tags *args end
158
136
 
159
- def Benelux.remove_thread_tags(*args)
160
- Benelux.thread_timeline.remove_default_tags *args
137
+ def Benelux.timed_method? klass, meth
138
+ Benelux.packed_method? klass, meth, :'Benelux::MethodTimer'
161
139
  end
162
- def Benelux.remove_thread_tag(*args) remove_thread_tags *args end
163
140
 
164
- def Benelux.tracks
165
- Benelux.timelines.keys
141
+ def Benelux.counted_method? klass, meth
142
+ Benelux.packed_method? klass, meth, :'Benelux::MethodCounter'
166
143
  end
167
144
 
168
- def Benelux.inspect
169
- str = ["Benelux"]
170
- str << "threads:" << Benelux.known_threads.inspect
171
- str << "tracks:" << Benelux.tracks.inspect
172
- str << "timers:" << Benelux.timed_methods.inspect
173
- str << "timeline:" << Benelux.timeline.inspect
174
- str.join $/
145
+ def Benelux.packed_method? klass, meth, kind=nil
146
+ list = Benelux.packed_methods.filter(klass.to_s.to_sym, meth)
147
+ list.filter! :kind => kind unless kind.nil?
148
+ !list.empty?
175
149
  end
176
150
 
177
- def Benelux.supported?(klass)
178
- !NOTSUPPORTED.member?(klass)
151
+
152
+ def Benelux.add_timer klass, meth, &blk
153
+ raise NotSupported, klass unless Benelux.supported? klass
154
+ raise AlreadyTimed, klass if Benelux.timed_method? klass, meth
155
+ Benelux::MethodTimer.new klass, meth, &blk
179
156
  end
180
157
 
181
- def Benelux.timed_methods
182
- @@timed_methods
158
+ def Benelux.add_counter klass, meth, &blk
159
+ raise NotSupported, klass unless Benelux.supported? klass
160
+ Benelux::MethodCounter.new klass, meth, &blk
183
161
  end
184
162
 
185
- def Benelux.known_threads
186
- @@known_threads
163
+ def Benelux.ld(*msg)
164
+ @@logger.puts "D: " << msg.join("#{$/}D: ") if debug?
187
165
  end
188
166
 
189
- def Benelux.timelines
190
- @@timelines
167
+
168
+ # Returns an Array of method names for the current class that
169
+ # are timed by Benelux.
170
+ #
171
+ # This is an instance method for objects which have Benelux
172
+ # modified methods.
173
+ def timed_methods
174
+ Benelux.timed_methods.filter(:class => self.class.to_s.to_sym)
191
175
  end
192
176
 
193
- # Rename the method +meth+ in the object +obj+ and return
194
- # the new alias.
195
- #
196
- # e.g.
177
+ # Returns an Array of method names for the current class that
178
+ # are counted by Benelux.
197
179
  #
198
- # Benelux.renamed(SomeClass, :execute)
199
- # # => __benelux_execute_2151884308_2165479316
200
- #
201
- def Benelux.rename_method(obj, meth)
202
- ## NOTE: This is commented out so we can include
203
- ## Benelux definitions before all classes are loaded.
204
- ##unless obj.respond_to? meth
205
- ## raise NoMethodError, "undefined method `#{meth}' for #{obj}:Class"
206
- ##end
207
- thread_id, call_id = Thread.current.object_id.abs, obj.object_id.abs
208
- meth_alias = "__benelux_#{meth}_#{thread_id}_#{call_id}"
209
- obj.module_eval do
210
- alias_method meth_alias, meth
211
- end
212
- meth_alias
180
+ # This is an instance method for objects which have Benelux
181
+ # modified methods.
182
+ def counted_methods
183
+ Benelux.counted_methods.filter(:class => self.class.to_s.to_sym)
213
184
  end
214
185
 
215
- # Creates a method definition (for an `eval` that) for a method
216
- # named +meth+ which times a call to +meth_alias+.
217
- def Benelux.generate_timer_str(meth_alias, meth)
218
- %Q{
219
- def #{meth}(*args, &block)
220
- call_id = "" << self.object_id.abs.to_s << args.object_id.abs.to_s
221
- # We only need to do these things once.
222
- if self.timeline.nil?
223
- self.timeline = Benelux::Timeline.new
224
- Benelux.store_thread_reference
225
- end
226
- mark_a = self.timeline.add_mark :'#{meth}_a'
227
- mark_a.add_tag :call_id => call_id
228
- tags = mark_a.tags
229
- ret = #{meth_alias}(*args, &block)
230
- rescue => ex
231
- raise ex
232
- ensure
233
- mark_z = self.timeline.add_mark :'#{meth}_z'
234
- mark_z.tags = tags # In case tags were added between these marks
235
- range = self.timeline.add_range :'#{meth}', mark_a, mark_z
236
- range.exception = ex if defined?(ex) && !ex.nil?
237
- end
238
- }
239
- end
186
+
187
+ def Benelux.enable_debug; @@debug = true; end
188
+ def Benelux.disable_debug; @@debug = false; end
189
+ def Benelux.debug?; @@debug; end
190
+
240
191
 
241
192
  end
242
193
 
243
194
 
244
195
 
245
196
 
197
+ __END__
198
+ % cumulative self self total
199
+ time seconds seconds calls ms/call ms/call name
200
+ 33.04 40.39 40.39 832483 0.05 0.10 Selectable::Tags#==
201
+ 20.65 65.64 25.25 824759 0.03 0.04 Hash#==
202
+ 15.38 84.44 18.80 8173 2.30 12.16 Array#select
203
+ 6.94 92.93 8.49 101 84.06 84.06 Thread#join
204
+ 6.42 100.78 7.85 927328 0.01 0.01 String#==
205
+ 5.42 107.40 6.62 832912 0.01 0.01 Kernel.is_a?
206
+ 2.01 109.86 2.46 23840 0.10 5.13 Array#each
207
+ 0.85 110.90 1.04 9577 0.11 0.46 Selectable::Tags#>=
208
+ 0.83 111.92 1.02 13295 0.08 0.87 Kernel.send
209
+ 0.67 112.74 0.82 6348 0.13 0.18 Benelux::Stats::Calculator#update
210
+ 0.46 113.30 0.56 238 2.35 10.50 Kernel.require
211
+ 0.41 113.80 0.50 10620 0.05 0.22 Object#metaclass
212
+ 0.36 114.24 0.44 10776 0.04 0.15 Object#metaclass?
213
+ 0.35 114.67 0.43 9900 0.04 0.08 Gibbler::Digest#==
214
+ 0.35 115.10 0.43 6348 0.07 0.26 Benelux::Stats::Calculator#sample
246
215