Class: Datadog::Profiling::StackRecorder

Inherits:
Object
  • Object
show all
Defined in:
lib/datadog/profiling/stack_recorder.rb,
ext/ddtrace_profiling_native_extension/stack_recorder.c

Overview

Stores stack samples in a native libdatadog data structure and expose Ruby-level serialization APIs Note that ‘record_sample` is only accessible from native code. Methods prefixed with native are implemented in `stack_recorder.c`

Defined Under Namespace

Modules: Testing

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(cpu_time_enabled:, alloc_samples_enabled:) ⇒ StackRecorder

Returns a new instance of StackRecorder.



7
8
9
10
11
12
13
14
15
16
17
# File 'lib/datadog/profiling/stack_recorder.rb', line 7

def initialize(cpu_time_enabled:, alloc_samples_enabled:)
  # This mutex works in addition to the fancy C-level mutexes we have in the native side (see the docs there).
  # It prevents multiple Ruby threads calling serialize at the same time -- something like
  # `10.times { Thread.new { stack_recorder.serialize } }`.
  # This isn't something we expect to happen normally, but because it would break the assumptions of the
  # C-level mutexes (that there is a single serializer thread), we add it here as an extra safeguard against it
  # accidentally happening.
  @no_concurrent_synchronize_mutex = Mutex.new

  self.class._native_initialize(self, cpu_time_enabled, alloc_samples_enabled)
end

Class Method Details

._native_initializeObject



200
# File 'ext/ddtrace_profiling_native_extension/stack_recorder.c', line 200

static VALUE _native_initialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE cpu_time_enabled, VALUE alloc_samples_enabled);

._native_reset_after_forkObject



212
# File 'ext/ddtrace_profiling_native_extension/stack_recorder.c', line 212

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

._native_serializeObject



201
# File 'ext/ddtrace_profiling_native_extension/stack_recorder.c', line 201

static VALUE _native_serialize(VALUE self, VALUE recorder_instance);

Instance Method Details

#clearObject



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/datadog/profiling/stack_recorder.rb', line 51

def clear
  status, result = @no_concurrent_synchronize_mutex.synchronize { self.class._native_clear(self) }

  if status == :ok
    finish_timestamp = result

    Datadog.logger.debug { "Cleared profile at #{finish_timestamp}" }

    finish_timestamp
  else
    error_message = result

    Datadog.logger.error("Failed to clear profiling data: #{error_message}")

    nil
  end
end

#reset_after_forkObject



69
70
71
# File 'lib/datadog/profiling/stack_recorder.rb', line 69

def reset_after_fork
  self.class._native_reset_after_fork(self)
end

#serializeObject



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/datadog/profiling/stack_recorder.rb', line 19

def serialize
  status, result = @no_concurrent_synchronize_mutex.synchronize { self.class._native_serialize(self) }

  if status == :ok
    start, finish, encoded_pprof = result

    Datadog.logger.debug { "Encoded profile covering #{start.iso8601} to #{finish.iso8601}" }

    [start, finish, encoded_pprof]
  else
    error_message = result

    Datadog.logger.error("Failed to serialize profiling data: #{error_message}")

    nil
  end
end

#serialize!Object



37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/datadog/profiling/stack_recorder.rb', line 37

def serialize!
  status, result = @no_concurrent_synchronize_mutex.synchronize { self.class._native_serialize(self) }

  if status == :ok
    _start, _finish, encoded_pprof = result

    encoded_pprof
  else
    error_message = result

    raise("Failed to serialize profiling data: #{error_message}")
  end
end