Class: Datadog::Profiling::Collectors::CpuAndWallTimeWorker

Inherits:
Object
  • Object
show all
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

Instance Method Summary collapse

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:, dynamic_sampling_rate_enabled: true, skip_idle_samples_for_testing: false, idle_sampling_helper: IdleSamplingHelper.new) ⇒ CpuAndWallTimeWorker

Returns a new instance of CpuAndWallTimeWorker.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb', line 18

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:,
  # **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
)
  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

  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,
  )
  @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_countObject



227
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 227

static VALUE _native_allocation_count(DDTRACE_UNUSED VALUE self);

._native_failure_exception_during_operationObject



203
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 203

static VALUE _native_failure_exception_during_operation(DDTRACE_UNUSED VALUE self, VALUE instance);

._native_hold_signalsObject



235
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 235

static VALUE _native_hold_signals(DDTRACE_UNUSED VALUE self);

._native_initializeObject



189
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 189

static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);

._native_is_running?Boolean

Returns:

  • (Boolean)


202
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 202

static VALUE _native_is_running(DDTRACE_UNUSED VALUE self, VALUE instance);

._native_reset_after_forkObject



219
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 219

static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE instance);

._native_resume_signalsObject



236
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 236

static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self);

._native_sampling_loopObject



191
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 191

static VALUE _native_sampling_loop(VALUE self, VALUE instance);

._native_statsObject



221
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 221

static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance);

._native_stats_reset_not_thread_safeObject



222
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 222

static VALUE _native_stats_reset_not_thread_safe(DDTRACE_UNUSED VALUE self, VALUE instance);

._native_stopObject



192
# File 'ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c', line 192

static VALUE _native_stop(DDTRACE_UNUSED VALUE _self, VALUE self_instance, VALUE worker_thread);

Instance Method Details

#reset_after_forkObject



111
112
113
# File 'lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb', line 111

def reset_after_fork
  self.class._native_reset_after_fork(self)
end

#start(on_failure_proc: nil) ⇒ Object



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
92
93
# File 'lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb', line 64

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 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.name} #{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

#statsObject



115
116
117
# File 'lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb', line 115

def stats
  self.class._native_stats(self)
end

#stats_and_reset_not_thread_safeObject



119
120
121
122
123
# File 'lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb', line 119

def stats_and_reset_not_thread_safe
  stats = self.stats
  self.class._native_stats_reset_not_thread_safe(self)
  stats
end

#stopObject



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb', line 95

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



126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb', line 126

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)

    if self.class._native_is_running?(self)
      true
    else
      raise "Timeout waiting for #{self.class.name} to start (waited for #{timeout_seconds} seconds)"
    end
  end
end