benelux 0.3.2 → 0.4.1

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.
@@ -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