class Watchdog
- Prepends
ThreadLocalProfiler: #start, #stop
Samples stacks while a fiber runs without switching back to the event loop.
Definitions
def self.default(env = ENV)
Build a watchdog using environment configuration.
Signature
-
parameter
envHash The environment to read configuration from.
-
returns
Watchdog The configured watchdog.
Implementation
def self.default(env = ENV)
new(
stall_threshold: Float(env.fetch("FIBER_PROFILER_WATCHDOG_STALL_THRESHOLD", "0.5")),
sample_interval: Float(env.fetch("FIBER_PROFILER_WATCHDOG_SAMPLE_INTERVAL", "0.1"))
)
end
def initialize(stall_threshold: 0.5, sample_interval: 0.1, max_samples: 5, output: $stderr)
Initialize a watchdog. Monitoring begins when Fiber::Profiler::Watchdog#start is called.
Signature
-
parameter
stall_thresholdFloat Seconds without a fiber switch before reporting, and the minimum interval between reports for the same execution.
-
parameter
sample_intervalFloat Seconds between stack samples.
-
parameter
max_samplesInteger Maximum number of recent stacks retained per execution.
-
parameter
outputIO The destination for stall reports.
Implementation
def initialize(stall_threshold: 0.5, sample_interval: 0.1, max_samples: 5, output: $stderr)
@stall_threshold = Float(stall_threshold)
@sample_interval = Float(sample_interval)
unless @stall_threshold.finite? && @stall_threshold.positive? && @sample_interval.finite? && @sample_interval.positive?
raise ArgumentError, "Watchdog intervals must be finite and positive"
end
unless max_samples.is_a?(Integer) && max_samples.positive?
raise ArgumentError, "max_samples must be a positive integer"
end
@max_samples = max_samples
@output = output
@running = false
@stalls = 0
@error = nil
end
attr_reader :stall_threshold
Signature
-
attribute
Float The minimum execution duration before reporting a stall.
attr_reader :sample_interval
Signature
-
attribute
Float The delay between samples.
attr_reader :stalls
Signature
-
attribute
Integer The number of reports written.
attr_reader :error
Signature
-
attribute
StandardError | Nil The sampling or reporting failure, retained until monitoring starts again.
def start
Start monitoring application fibers on the calling thread.
Signature
-
returns
Watchdog | false Self, or false if already running.
Implementation
def start
return false if @running
@thread = Thread.current
@pid = Process.pid
@mutex = Mutex.new
@condition = ConditionVariable.new
@running = true
@execution = nil
@error = nil
# When started on the event loop, distinguish it from blocking application fibers:
@loop = Fiber.current if Fiber.current.blocking?
@tracepoint = TracePoint.new(:fiber_switch){record_execution}
@tracepoint.enable(target_thread: @thread)
record_execution
@watchdog = Thread.new{watch}
self
rescue Exception
stop
raise
end
def stop
Stop monitoring and wait for the sampling thread to finish.
Signature
-
returns
Watchdog | false Self, or false if already stopped.
Implementation
def stop
return false unless @running
@tracepoint&.disable
if @pid == Process.pid
@mutex.synchronize do
@running = false
@condition.broadcast
end
@watchdog&.join
else
# The sampling thread does not survive fork; avoid inherited synchronization:
@running = false
end
self
ensure
@watchdog = @thread = @execution = @loop = @tracepoint = nil
end