Module: Benelux

Defined in:
lib/benelux.rb,
lib/benelux/mark.rb,
lib/benelux/tags.rb,
lib/benelux/range.rb,
lib/benelux/stats.rb,
lib/benelux/timeline.rb

Defined Under Namespace

Modules: TagHelpers Classes: BeneluxError, Mark, NoTrack, NotSupported, Range, Stats, Tags, Timeline

Constant Summary collapse

VERSION =
"0.3.0"
NOTSUPPORTED =
[Class, Object, Kernel]
@@timed_methods =
{}
@@known_threads =
[]
@@timelines =
{}
@@mutex =
Mutex.new
@@debug =
true

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.add_tally(obj, meth) ⇒ Object



125
126
# File 'lib/benelux.rb', line 125

def Benelux.add_tally obj, meth
end

.add_thread_tag(*args) ⇒ Object



157
# File 'lib/benelux.rb', line 157

def Benelux.add_thread_tag(*args) add_thread_tags *args end

.add_thread_tags(args = Benelux::Tags.new) ⇒ Object

Thread tags become the default for any new Mark or Range.



154
155
156
# File 'lib/benelux.rb', line 154

def Benelux.add_thread_tags(args=Benelux::Tags.new)
  Benelux.thread_timeline.add_default_tags args
end

.add_timer(klass, meth) ⇒ Object

Raises:



116
117
118
119
120
121
122
123
# File 'lib/benelux.rb', line 116

def Benelux.add_timer klass, meth
  raise NotSupported, klass unless Benelux.supported? klass
  raise AlreadyTimed, klass if Benelux.timed_method? klass, meth
  prepare_object klass
  meth_alias = rename_method klass, meth
  timed_methods[klass] << meth
  klass.module_eval generate_timer_str(meth_alias, meth), __FILE__, 215
end

.current_track(track = nil) ⇒ Object

If track is specified, this will associate the current thread with that track.

If track is nil, it returns the timeline for the track associated to the current thread.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/benelux.rb', line 77

def Benelux.current_track(track=nil)
  if track.nil? 
    raise NoTrack if Benelux.timelines[Thread.current.track].nil?
    return Benelux.timelines[Thread.current.track] 
  end
  Benelux.store_thread_reference
  @@mutex.synchronize do
    # QUESTION: Is it okay for multiple threads to write to
    # different elements in the same hash?
    Benelux.timelines[track] ||= Benelux::Timeline.new
    Benelux.add_thread_tags :track => track
    Thread.current.track = track
  end
end

.debug?Boolean

Returns:

  • (Boolean)


28
# File 'lib/benelux.rb', line 28

def Benelux.debug?; @@debug; end

.disable_debugObject



27
# File 'lib/benelux.rb', line 27

def Benelux.disable_debug; @@debug = false; end

.enable_debugObject



26
# File 'lib/benelux.rb', line 26

def Benelux.enable_debug; @@debug = true; end

.generate_timer_str(meth_alias, meth) ⇒ Object

Creates a method definition (for an ‘eval` that) for a method named meth which times a call to meth_alias.



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/benelux.rb', line 217

def Benelux.generate_timer_str(meth_alias, meth)
  %Q{
  def #{meth}(*args, &block)
    call_id = "" << self.object_id.abs.to_s << args.object_id.abs.to_s
    # We only need to do these things once.
    if self.timeline.nil?
      self.timeline = Benelux::Timeline.new
      Benelux.store_thread_reference
    end
    mark_a = self.timeline.add_mark :'#{meth}_a'
    mark_a.add_tag :call_id => call_id
    tags = mark_a.tags
    ret = #{meth_alias}(*args, &block)
  rescue => ex
    raise ex
  ensure
    mark_z = self.timeline.add_mark :'#{meth}_z'
    mark_z.tags = tags # In case tags were added between these marks
    range = self.timeline.add_range :'#{meth}', mark_a, mark_z
    range.exception = ex if defined?(ex) && !ex.nil?
  end
  }
end

.included(klass) ⇒ Object

Make note of the class which included Benelux.



108
109
110
# File 'lib/benelux.rb', line 108

def Benelux.included(klass)
  timed_methods[klass] = [] unless timed_methods.has_key? klass
end

.inspectObject



168
169
170
171
172
173
174
175
# File 'lib/benelux.rb', line 168

def Benelux.inspect
  str = ["Benelux"]
  str << "threads:" << Benelux.known_threads.inspect
  str << "tracks:" << Benelux.tracks.inspect
  str << "timers:" << Benelux.timed_methods.inspect
  str << "timeline:" << Benelux.timeline.inspect
  str.join $/
end

.known_threadsObject



185
186
187
# File 'lib/benelux.rb', line 185

def Benelux.known_threads
  @@known_threads
end

.merge_timelines(*timelines) ⇒ Object

Combine two or more timelines into a new, single Benelux::Timeline.



94
95
96
97
98
99
100
# File 'lib/benelux.rb', line 94

def Benelux.merge_timelines(*timelines)
  tl, stats, ranges = Benelux::Timeline.new, Benelux::Stats.new, []
  timelines.each do |t|
    tl += t
  end
  tl
end

.name(*names) ⇒ Object



128
129
130
# File 'lib/benelux.rb', line 128

def Benelux.name(*names)
  names.flatten.collect { |n| n.to_s }.join('_')
end

.prepare_object(obj) ⇒ Object



133
134
135
136
137
138
139
# File 'lib/benelux.rb', line 133

def Benelux.prepare_object obj
  obj.extend Attic  unless obj.kind_of?(Attic)
  unless obj.kind_of?(Benelux)
    obj.attic :timeline
    obj.send :include, Benelux
  end
end

.remove_thread_tag(*args) ⇒ Object



162
# File 'lib/benelux.rb', line 162

def Benelux.remove_thread_tag(*args) remove_thread_tags *args end

.remove_thread_tags(*args) ⇒ Object



159
160
161
# File 'lib/benelux.rb', line 159

def Benelux.remove_thread_tags(*args)
  Benelux.thread_timeline.remove_default_tags *args
end

.rename_method(obj, meth) ⇒ Object

Rename the method meth in the object obj and return the new alias.

e.g.

Benelux.renamed(SomeClass, :execute) 
  # => __benelux_execute_2151884308_2165479316


201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/benelux.rb', line 201

def Benelux.rename_method(obj, meth)
  ## NOTE: This is commented out so we can include  
  ## Benelux definitions before all classes are loaded. 
  ##unless obj.respond_to? meth
  ##  raise NoMethodError, "undefined method `#{meth}' for #{obj}:Class"
  ##end
  thread_id, call_id = Thread.current.object_id.abs, obj.object_id.abs
  meth_alias = "__benelux_#{meth}_#{thread_id}_#{call_id}"
  obj.module_eval do
    alias_method meth_alias, meth
  end
  meth_alias
end

.store_thread_referenceObject

Benelux keeps track of the threads which have timed objects so it can process the timelines after all is said and done.



144
145
146
147
148
149
150
151
# File 'lib/benelux.rb', line 144

def Benelux.store_thread_reference
  return if Benelux.known_threads.member? Thread.current
  @@mutex.synchronize do
    Thread.current.timeline ||= Benelux::Timeline.new
    Benelux.known_threads << Thread.current
    Benelux.known_threads.uniq!
  end
end

.supported?(klass) ⇒ Boolean

Returns:

  • (Boolean)


177
178
179
# File 'lib/benelux.rb', line 177

def Benelux.supported?(klass)
  !NOTSUPPORTED.member?(klass)
end

.thread_timelineObject



102
103
104
105
# File 'lib/benelux.rb', line 102

def Benelux.thread_timeline
  Thread.current.timeline ||= Benelux::Timeline.new
  Thread.current.timeline
end

.timed_method?(klass, meth) ⇒ Boolean

Returns:

  • (Boolean)


112
113
114
# File 'lib/benelux.rb', line 112

def Benelux.timed_method? klass, meth
  !timed_methods[klass].nil? && timed_methods[klass].member?(meth)
end

.timed_methodsObject



181
182
183
# File 'lib/benelux.rb', line 181

def Benelux.timed_methods
  @@timed_methods
end

.timeline(track = nil) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/benelux.rb', line 39

def Benelux.timeline(track=nil)
  if track.nil?
    if Benelux.timelines.empty?
      tl = known_threads.collect { |t| t.timeline}
    else
      tl = Benelux.timelines.values
    end
    Benelux.merge_timelines *tl
  else
    Benelux.timelines[track]
  end
end

.timelinesObject



189
190
191
# File 'lib/benelux.rb', line 189

def Benelux.timelines
  @@timelines
end

.tracksObject



164
165
166
# File 'lib/benelux.rb', line 164

def Benelux.tracks
  Benelux.timelines.keys
end

.update_all_track_timelinesObject

Must be run in single-threaded mode (after all track threads have finished).



55
56
57
# File 'lib/benelux.rb', line 55

def Benelux.update_all_track_timelines
  Benelux.timelines.keys.each { |track| Benelux.update_track(track) }
end

.update_track_timeline(track = nil) ⇒ Object

Must be run from the master thread in the current track. The master thread is either the first thread in a track or the one which creates additional threads for the track.



63
64
65
66
67
68
69
# File 'lib/benelux.rb', line 63

def Benelux.update_track_timeline(track=nil)
  track = Thread.current.track if track.nil?
  threads = Benelux.known_threads.select { |t| t.track == track }
  Benelux.timelines[track] = Benelux.merge_timelines(*threads.collect { |t| t.timeline })
  threads.each { |t| t.timeline.clear }
  Benelux.timelines[track]
end

Instance Method Details

#benelux_timersObject

Returns an Array of method names for the current class that are timed by Benelux.

This is an instance method for objects which have Benelux modified methods.



35
36
37
# File 'lib/benelux.rb', line 35

def benelux_timers
  Benelux.timed_methods[self.class]
end