module Datadog::Profiling::Ext::CThread

Extension used to enable CPU-time profiling via use of pthread's `getcpuclockid`.

Public Class Methods

new(*args) { |*t_args| ... } click to toggle source
Calls superclass method
# File lib/ddtrace/profiling/ext/cthread.rb, line 76
def initialize(*args)
  @pid = ::Process.pid
  @pthread_thread_id = nil
  @clock_id = nil

  # Wrap the work block with our own
  # so we can retrieve the native thread ID within the thread's context.
  wrapped_block = proc do |*t_args|
    # Set native thread ID & clock ID
    update_native_ids
    yield(*t_args)
  end
  wrapped_block.ruby2_keywords if wrapped_block.respond_to?(:ruby2_keywords, true)

  super(*args, &wrapped_block)
end
prepended(base) click to toggle source
# File lib/ddtrace/profiling/ext/cthread.rb, line 39
def self.prepended(base)
  # Threads that have already been created, will not have resolved
  # a thread/clock ID. This is because these IDs can only be resolved
  # from within the thread's execution context, which we do not control.
  #
  # We can mitigate this for the current thread via #update_native_ids,
  # since we are currently running within its execution context. We cannot
  # do this for any other threads that may have been created already.
  # (This is why it's important that CThread is applied before anything else runs.)
  base.current.send(:update_native_ids) if base.current.is_a?(CThread)
end

Public Instance Methods

cpu_time(unit = :float_second) click to toggle source
# File lib/ddtrace/profiling/ext/cthread.rb, line 94
def cpu_time(unit = :float_second)
  ::Process.clock_gettime(clock_id, unit) if clock_id
end
cpu_time_instrumentation_installed?() click to toggle source
# File lib/ddtrace/profiling/ext/cthread.rb, line 98
def cpu_time_instrumentation_installed?
  # If this thread was started before this module was added to Thread OR if something caused the initialize
  # method above not to be properly called on new threads, this instance variable is never defined (never set to
  # any value at all, including nil).
  #
  # Thus, we can use @clock_id as a canary to detect a thread that has missing instrumentation, because we
  # know that in initialize above we always set this variable to nil.
  defined?(@clock_id) != nil
end
pthread_thread_id() click to toggle source
# File lib/ddtrace/profiling/ext/cthread.rb, line 71
def pthread_thread_id
  defined?(@pthread_thread_id) && @pthread_thread_id
end

Private Instance Methods

clock_id() click to toggle source
# File lib/ddtrace/profiling/ext/cthread.rb, line 110
def clock_id
  update_native_ids if forked?
  defined?(@clock_id) && @clock_id
end
forked?() click to toggle source
# File lib/ddtrace/profiling/ext/cthread.rb, line 115
def forked?
  ::Process.pid != (@pid ||= nil)
end
update_native_ids() click to toggle source
# File lib/ddtrace/profiling/ext/cthread.rb, line 119
def update_native_ids
  # Can only resolve if invoked from same thread
  return unless ::Thread.current == self

  @pid = ::Process.pid
  @pthread_thread_id = NativePthread.get_pthread_thread_id(self)
  @clock_id = NativePthread.get_clock_id(self, @pthread_thread_id)
end