Module: EventMachine

Defined in:
lib/em-monitor.rb

Overview

EM::Monitor adds a few methods to eventmachine that can help you keep track of ‘lag’ caused by long-running CPU spans on the reactor thread.

Defined Under Namespace

Classes: Monitor

Class Method Summary collapse

Class Method Details

.monitor_histogram(opts = {}, &block) {|histogram, from, to| ... } ⇒ Object

Set the block to be called periodically with histogram data.

This is a convenience wrapper around monitor_spans for the common use-case of wanting to plot a histogram of loop utilisation split into time-chunks.

In the normal case you can plot these values directly and it will tell you how much CPU-time was used by spans shorter than a given length. However, care should be taken if CPU-spans are often of similar length to :interval. This can cause the actual delay between calls to the block to vary significantly and so if you’re trying to plot a line of CPU-utilization then it can give you misleading answers. If this is a concern to you then you might want to use the :cumulative mode and ask your graphing library to plot the derivative of the values over time.

Examples:

# Create an input file suitable for feeding to gnuplot.
#
EM::monitor_histogram(stacked: true) do |hist, from, to|
  gnuplot_input.puts #{to.iso8601} #{hist.values.join(" ")}"
end

Parameters:

  • opts (Hash) (defaults to: {})

    Configuration for the histogram

  • block (Proc)

    the block to call.

Options Hash (opts):

  • :interval (Number) — default: 60

    The approximate number of seconds between calls to your block. If your event loop regularly runs long CPU-spans then the actual time between calls can vary significantly.

  • :buckets (Array<Number>) — default: [0.001, 0.01, 0.1, 1, 10, Infinity]

    The boundaries of the histogram buckets, Infinity will be added even if it’s not specified by you to ensure that all spans are included. CPU-spans are put into the smallest bucket with a limit longer than the span.

  • :stacked (Boolean) — default: false

    When true larger buckets include the sum of all smaller buckets in addition to the number of seconds spent in CPU-spans that fell into that bucket directly. When false each CPU-span will be put into exactly one bucket

  • :cumulative (Boolean) — default: false

    When true the values of each bucket will increase monotonically and the derivative over time can be used to tell how much CPU was used by spans in each bucket in the current monitoring interval. When false the values of each bucket are only the amount of time spent by CPU-spans in that bucket in the current monitoring interval.

Yield Parameters:

  • histogram (Hash<Float,Float>)

    A histogram from bucket-size to amount of CPU-time spent in that bucket.

  • from (Time)

    The start of the monitoring interval

  • to (Time)

    The end of the monitoring interval



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/em-monitor.rb', line 97

def self.monitor_histogram(opts = {}, &block)
  stacked    = !!opts[:stacked]
  cumulative = !!opts[:cumulative]
  interval   =   opts[:interval] || Monitor::DEFAULT_INTERVAL
  buckets    =  (opts[:buckets]  || Monitor::DEFAULT_BUCKETS).sort
  buckets << (1/0.0)

  # ensure the histogram keys are in the right order
  hist = buckets.each_with_object({}){ |bucket, h| h[bucket] = 0 }

  monitor_spans(opts) do |spans, from, to|

    unless cumulative
      hist = buckets.each_with_object({}){ |bucket, h| h[bucket] = 0 }
    end

    if stacked
      spans.each do |span|
        buckets.each do |bucket|
          hist[bucket] += span if bucket > span
        end
      end
    else
      spans.each do |span|
        hist[buckets.detect{ |bucket| bucket > span }] += span
      end
    end

    block.call hist, from, to
  end
end

.monitor_spans(opts = {}, &block) {|spans, from, to| ... } ⇒ Object

Set the block to be called periodically with timing data.

Examples:

EM::monitor_spans do |spans, from, to|
  puts "Used %.2f seconds of CPU in the last %.2f seconds." % (spans.inject(&:+), to - from)
end

Parameters:

  • opts (Hash) (defaults to: {})

    Configuration

  • block (Proc)

    the block to call.

Options Hash (opts):

  • :interval (Number) — default: 60

    The approximate number of seconds between calls to your block. If your event loop regularly runs long CPU-spans then the actual time between calls can vary significantly.

Yield Parameters:

  • spans (Array<Float>)

    The number of seconds spent by each CPU-span in the monitoring interval

  • from (Time)

    The start of the monitoring interval

  • to (Time)

    The end of the monitoring interval



43
44
45
46
# File 'lib/em-monitor.rb', line 43

def self.monitor_spans(opts = {}, &block)
  raise "EventMachine not initialized" unless @monitor
  @monitor.monitor_spans(opts[:interval] || Monitor::DEFAULT_INTERVAL, &block)
end

.run(*args, &block) ⇒ Object

Run the eventmachine reactor with monitoring.



13
14
15
16
17
18
19
20
21
22
# File 'lib/em-monitor.rb', line 13

def self.run(*args, &block)
  run_without_monitor(*args) do |*a, &b|
    EM::Monitor.new do |monitor|
      @monitor = monitor
      block.call(*a, &b) if block_given?
    end
  end
ensure
  @monitor = nil
end

.run_without_monitorObject



8
# File 'lib/em-monitor.rb', line 8

alias_method :run_without_monitor, :run