Class: Datadog::Profiling::Collectors::CpuAndWallTimeWorker
- Inherits:
-
Object
- Object
- Datadog::Profiling::Collectors::CpuAndWallTimeWorker
- Defined in:
- lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb,
ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c
Overview
Used to trigger the periodic execution of Collectors::ThreadState, which implements all of the sampling logic itself; this class only implements the "when to do it" part. Almost all of this class is implemented as native code.
Methods prefixed with native are implemented in collectors_cpu_and_wall_time_worker.c
Defined Under Namespace
Modules: Testing Classes: ClockFailure
Class Method Summary collapse
- ._native_allocation_count ⇒ Object
- ._native_failure_exception_during_operation ⇒ Object
- ._native_hold_signals ⇒ Object
- ._native_initialize ⇒ Object
- ._native_is_running? ⇒ Boolean
- ._native_reset_after_fork ⇒ Object
- ._native_resume_signals ⇒ Object
- ._native_sampling_loop ⇒ Object
- ._native_stats ⇒ Object
- ._native_stats_reset_not_thread_safe ⇒ Object
- ._native_stop ⇒ Object
Instance Method Summary collapse
-
#initialize(gc_profiling_enabled:, no_signals_workaround_enabled:, thread_context_collector:, dynamic_sampling_rate_overhead_target_percentage:, allocation_profiling_enabled:, allocation_counting_enabled:, gvl_profiling_enabled:, sighandler_sampling_enabled:, cpu_sampling_interval_ms:, waiting_for_gvl_threshold_ns:, dynamic_sampling_rate_enabled: true, skip_idle_samples_for_testing: false, idle_sampling_helper: IdleSamplingHelper.new(thread_context_collector: thread_context_collector)) ⇒ CpuAndWallTimeWorker
constructor
A new instance of CpuAndWallTimeWorker.
-
#reset_after_fork ⇒ Object
: () -> true.
- #start(on_failure_proc: nil) ⇒ Object
-
#stats ⇒ Object
: () -> ::Hash[::Symbol, untyped].
-
#stats_and_reset_not_thread_safe ⇒ Object
: () -> ::Hash[::Symbol, untyped].
-
#stop ⇒ Object
: () -> void.
-
#wait_until_running(timeout_seconds: 5) ⇒ Object
Useful for testing, to e.g.
Constructor Details
#initialize(gc_profiling_enabled:, no_signals_workaround_enabled:, thread_context_collector:, dynamic_sampling_rate_overhead_target_percentage:, allocation_profiling_enabled:, allocation_counting_enabled:, gvl_profiling_enabled:, sighandler_sampling_enabled:, cpu_sampling_interval_ms:, waiting_for_gvl_threshold_ns:, dynamic_sampling_rate_enabled: true, skip_idle_samples_for_testing: false, idle_sampling_helper: IdleSamplingHelper.new(thread_context_collector: thread_context_collector)) ⇒ CpuAndWallTimeWorker
Returns a new instance of CpuAndWallTimeWorker.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb', line 39 def initialize( gc_profiling_enabled:, no_signals_workaround_enabled:, thread_context_collector:, dynamic_sampling_rate_overhead_target_percentage:, allocation_profiling_enabled:, allocation_counting_enabled:, gvl_profiling_enabled:, sighandler_sampling_enabled:, cpu_sampling_interval_ms:, waiting_for_gvl_threshold_ns:, # **NOTE**: This should only be used for testing; disabling the dynamic sampling rate will increase the # profiler overhead! dynamic_sampling_rate_enabled: true, skip_idle_samples_for_testing: false, idle_sampling_helper: IdleSamplingHelper.new(thread_context_collector: thread_context_collector) ) unless dynamic_sampling_rate_enabled Datadog.logger.warn( "Profiling dynamic sampling rate disabled. This should only be used for testing, and will increase overhead!" ) Datadog::Core::Telemetry::Logger.error( "Profiling dynamic sampling rate disabled. This should only be used for testing, and will increase overhead!" ) end if cpu_sampling_interval_ms < 1 raise ArgumentError, "cpu_sampling_interval_ms must be a positive integer, got #{cpu_sampling_interval_ms}" end self.class._native_initialize( self_instance: self, thread_context_collector: thread_context_collector, gc_profiling_enabled: gc_profiling_enabled, idle_sampling_helper: idle_sampling_helper, no_signals_workaround_enabled: no_signals_workaround_enabled, dynamic_sampling_rate_enabled: dynamic_sampling_rate_enabled, dynamic_sampling_rate_overhead_target_percentage: dynamic_sampling_rate_overhead_target_percentage, allocation_profiling_enabled: allocation_profiling_enabled, allocation_counting_enabled: allocation_counting_enabled, gvl_profiling_enabled: gvl_profiling_enabled, sighandler_sampling_enabled: sighandler_sampling_enabled, skip_idle_samples_for_testing: skip_idle_samples_for_testing, cpu_sampling_interval_ms: cpu_sampling_interval_ms, waiting_for_gvl_threshold_ns: waiting_for_gvl_threshold_ns, ) @worker_thread = nil @failure_exception = nil @start_stop_mutex = Mutex.new @idle_sampling_helper = idle_sampling_helper @wait_until_running_mutex = Mutex.new @wait_until_running_condition = ConditionVariable.new end |
Class Method Details
._native_allocation_count ⇒ Object
267 |
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 267 static VALUE _native_allocation_count(DDTRACE_UNUSED VALUE self); |
._native_failure_exception_during_operation ⇒ Object
242 |
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 242 static VALUE _native_failure_exception_during_operation(DDTRACE_UNUSED VALUE self, VALUE instance); |
._native_hold_signals ⇒ Object
276 |
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 276 static VALUE _native_hold_signals(DDTRACE_UNUSED VALUE self); |
._native_initialize ⇒ Object
228 |
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 228 static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self); |
._native_is_running? ⇒ Boolean
241 |
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 241 static VALUE _native_is_running(DDTRACE_UNUSED VALUE self, VALUE instance); |
._native_reset_after_fork ⇒ Object
259 |
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 259 static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE instance); |
._native_resume_signals ⇒ Object
277 |
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 277 static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self); |
._native_sampling_loop ⇒ Object
230 |
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 230 static VALUE _native_sampling_loop(VALUE self, VALUE instance); |
._native_stats ⇒ Object
261 |
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 261 static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance); |
._native_stats_reset_not_thread_safe ⇒ Object
262 |
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 262 static VALUE _native_stats_reset_not_thread_safe(DDTRACE_UNUSED VALUE self, VALUE instance); |
._native_stop ⇒ Object
231 |
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 231 static VALUE _native_stop(DDTRACE_UNUSED VALUE _self, VALUE self_instance, VALUE worker_thread); |
Instance Method Details
#reset_after_fork ⇒ Object
: () -> true
151 152 153 |
# File 'lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb', line 151 def reset_after_fork self.class._native_reset_after_fork(self) end |
#start(on_failure_proc: nil) ⇒ Object
95 96 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 128 129 130 131 |
# File 'lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb', line 95 def start(on_failure_proc: nil) @start_stop_mutex.synchronize do return if @worker_thread&.alive? Datadog.logger.debug { "Starting thread for: #{self}" } @idle_sampling_helper.start @worker_thread = Thread.new do Thread.current.name = self.class.name self.class._native_sampling_loop(self) Datadog.logger.debug("CpuAndWallTimeWorker thread stopping cleanly") rescue Profiling::ExistingSignalHandler => e @failure_exception = e Datadog.logger.warn( "Profiling was not started as another profiler or gem is already using the SIGPROF signal. " \ "Please disable the other profiler to use Datadog profiling." ) on_failure_proc&.call(log_failure: false) rescue Exception => e # rubocop:disable Lint/RescueException @failure_exception = e operation_name = self.class._native_failure_exception_during_operation(self).inspect Datadog.logger.warn( "CpuAndWallTimeWorker thread error. " \ "Operation: #{operation_name} Cause: #{e.class}: #{e.message} Location: #{Array(e.backtrace).first}" ) on_failure_proc&.call Datadog::Core::Telemetry::Logger.report(e, description: "CpuAndWallTimeWorker thread error: #{operation_name}") end @worker_thread.name = self.class.name # Repeated from above to make sure thread gets named asap @worker_thread.thread_variable_set(:fork_safe, true) end true end |
#stats ⇒ Object
: () -> ::Hash[::Symbol, untyped]
156 157 158 |
# File 'lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb', line 156 def stats self.class._native_stats(self) end |
#stats_and_reset_not_thread_safe ⇒ Object
: () -> ::Hash[::Symbol, untyped]
161 162 163 164 165 |
# File 'lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb', line 161 def stats_and_reset_not_thread_safe stats = self.stats self.class._native_stats_reset_not_thread_safe(self) stats end |
#stop ⇒ Object
: () -> void
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb', line 134 def stop @start_stop_mutex.synchronize do Datadog.logger.debug("Requesting CpuAndWallTimeWorker thread shut down") @idle_sampling_helper.stop return unless @worker_thread self.class._native_stop(self, @worker_thread) @worker_thread.join @worker_thread = nil @failure_exception = nil end end |
#wait_until_running(timeout_seconds: 5) ⇒ Object
Useful for testing, to e.g. make sure the profiler is running before we start running some code we want to observe
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb', line 170 def wait_until_running(timeout_seconds: 5) @wait_until_running_mutex.synchronize do return true if self.class._native_is_running?(self) @wait_until_running_condition.wait(@wait_until_running_mutex, timeout_seconds) # Not using `_native_is_running?(self) || raise(...)` here: `_native_is_running?` is declared # to return `bool`, so steep infers the `||` expression as `bool` too and rejects it against # this method's declared `true` return type. The explicit `if`/`else` type-checks correctly. # rubocop:disable Style/RedundantCondition if self.class._native_is_running?(self) true else raise "Timeout waiting for #{self.class.name} to start (waited for #{timeout_seconds} seconds)" end # rubocop:enable Style/RedundantCondition end end |