Module: NewRelic::Agent::BusyCalculator

Extended by:
BusyCalculator
Included in:
BusyCalculator
Defined in:
lib/new_relic/agent/busy_calculator.rb

Overview

This module supports calculation of actual time spent processing requests over the course of one harvest period. It’s similar to what you would get if you just added up all the execution times of controller calls, however that will be inaccurate when requests span the minute boundaries. This module manages accounting of requests not yet completed.

Calls are re-entrant. All start calls must be paired with finish calls, or a reset call.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#accumulatorObject (readonly)

For testability, add accessors:



20
21
22
# File 'lib/new_relic/agent/busy_calculator.rb', line 20

def accumulator
  @accumulator
end

#harvest_startObject (readonly)

For testability, add accessors:



20
21
22
# File 'lib/new_relic/agent/busy_calculator.rb', line 20

def harvest_start
  @harvest_start
end

Instance Method Details

#busy_countObject

this returns the size of the entry point stack, which determines how many transactions are running



58
59
60
# File 'lib/new_relic/agent/busy_calculator.rb', line 58

def busy_count
  @entrypoint_stack.size
end

#dispatcher_finish(end_time = nil) ⇒ Object

called when a transaction finishes, to add time to the instance variable accumulator. this is harvested when we send data to the server



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/new_relic/agent/busy_calculator.rb', line 37

def dispatcher_finish(end_time = nil)
  # If #dispatcher_start hasn't been called at least once, abort early
  return unless Thread.current[:busy_entries]

  end_time ||= time_now
  callers = Thread.current[:busy_entries] -= 1

  # Ignore nested calls
  return if callers > 0

  @lock.synchronize do
    if @entrypoint_stack.empty?
      ::NewRelic::Agent.logger.warn("Stack underflow tracking dispatcher entry and exit!\n  #{caller.join("  \n")}")
    else
      @accumulator += (end_time - @entrypoint_stack.pop).to_f
    end
  end
end

#dispatcher_start(time) ⇒ Object

sets up busy calculations based on the start and end of transactions - used for a rough estimate of what percentage of wall clock time is spent processing requests



25
26
27
28
29
30
31
32
# File 'lib/new_relic/agent/busy_calculator.rb', line 25

def dispatcher_start(time)
  Thread.current[:busy_entries] ||= 0
  callers = Thread.current[:busy_entries] += 1
  return if callers > 1
  @lock.synchronize do
    @entrypoint_stack.push time
  end
end

#harvest_busyObject

Called before uploading to to the server to collect current busy stats.



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/new_relic/agent/busy_calculator.rb', line 74

def harvest_busy
  busy = 0
  t0 = time_now
  @lock.synchronize do
    busy = accumulator
    @accumulator = 0

    # Walk through the stack and capture all times up to
    # now for entrypoints
    @entrypoint_stack.size.times do |frame|
      busy += (t0 - @entrypoint_stack[frame]).to_f
      @entrypoint_stack[frame] = t0
    end

  end

  busy = 0.0 if busy < 0.0 # don't go below 0%

  time_window = (t0 - harvest_start).to_f
  time_window = 1.0 if time_window == 0.0  # protect against divide by zero

  busy = busy / time_window

  if Agent.config[:report_instance_busy]
    NewRelic::Agent.record_metric('Instance/Busy', busy)
  end
  @harvest_start = t0
end

#resetObject

Reset the state of the information accumulated by all threads, but only reset the recursion counter for this thread.



64
65
66
67
68
69
70
# File 'lib/new_relic/agent/busy_calculator.rb', line 64

def reset
  @entrypoint_stack = []
  Thread.current[:busy_entries] = 0
  @lock ||= Mutex.new
  @accumulator = 0
  @harvest_start = time_now
end