Class: Datadog::Profiling::Pprof::Builder

Inherits:
Object
  • Object
show all
Defined in:
lib/ddtrace/profiling/pprof/builder.rb

Overview

Accumulates profile data and produces a Perftools::Profiles::Profile

Constant Summary collapse

DEFAULT_ENCODING =
'UTF-8'
DESC_FRAME_OMITTED =
'frame omitted'
DESC_FRAMES_OMITTED =
'frames omitted'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeBuilder

Returns a new instance of Builder.



26
27
28
29
30
31
32
33
34
35
36
# File 'lib/ddtrace/profiling/pprof/builder.rb', line 26

def initialize
  @functions = MessageSet.new(1)
  @locations = initialize_locations_hash
  @mappings = MessageSet.new(1)
  @sample_types = MessageSet.new
  @samples = []
  @string_table = StringTable.new

  # Cache this proc, since it's pretty expensive to keep recreating it
  @build_function = method(:build_function).to_proc
end

Instance Attribute Details

#functionsObject (readonly)

Returns the value of attribute functions.



18
19
20
# File 'lib/ddtrace/profiling/pprof/builder.rb', line 18

def functions
  @functions
end

#locationsObject (readonly)

Returns the value of attribute locations.



18
19
20
# File 'lib/ddtrace/profiling/pprof/builder.rb', line 18

def locations
  @locations
end

#mappingsObject (readonly)

Returns the value of attribute mappings.



18
19
20
# File 'lib/ddtrace/profiling/pprof/builder.rb', line 18

def mappings
  @mappings
end

#sample_typesObject (readonly)

Returns the value of attribute sample_types.



18
19
20
# File 'lib/ddtrace/profiling/pprof/builder.rb', line 18

def sample_types
  @sample_types
end

#samplesObject (readonly)

Returns the value of attribute samples.



18
19
20
# File 'lib/ddtrace/profiling/pprof/builder.rb', line 18

def samples
  @samples
end

#string_tableObject (readonly)

Returns the value of attribute string_table.



18
19
20
# File 'lib/ddtrace/profiling/pprof/builder.rb', line 18

def string_table
  @string_table
end

Instance Method Details

#build_function(id, filename, function_name) ⇒ Object



109
110
111
112
113
114
115
# File 'lib/ddtrace/profiling/pprof/builder.rb', line 109

def build_function(id, filename, function_name)
  Perftools::Profiles::Function.new(
    id: id,
    name: @string_table.fetch(function_name),
    filename: @string_table.fetch(filename)
  )
end

#build_line(function_id, line_number) ⇒ Object



102
103
104
105
106
107
# File 'lib/ddtrace/profiling/pprof/builder.rb', line 102

def build_line(function_id, line_number)
  Perftools::Profiles::Line.new(
    function_id: function_id,
    line: line_number
  )
end

#build_location(id, backtrace_location) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/ddtrace/profiling/pprof/builder.rb', line 88

def build_location(id, backtrace_location)
  Perftools::Profiles::Location.new(
    id: id,
    line: [build_line(
      @functions.fetch(
        backtrace_location.path,
        backtrace_location.base_label,
        &@build_function
      ).id,
      backtrace_location.lineno
    )]
  )
end

#build_locations(backtrace_locations, length) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/ddtrace/profiling/pprof/builder.rb', line 74

def build_locations(backtrace_locations, length)
  locations = backtrace_locations.collect { |backtrace_location| @locations[backtrace_location] }

  omitted = length - backtrace_locations.length

  # Add placeholder stack frame if frames were truncated
  if omitted > 0
    desc = omitted == 1 ? DESC_FRAME_OMITTED : DESC_FRAMES_OMITTED
    locations << @locations[Profiling::BacktraceLocation.new('', 0, "#{omitted} #{desc}")]
  end

  locations
end

#build_mapping(id, filename) ⇒ Object



117
118
119
120
121
122
# File 'lib/ddtrace/profiling/pprof/builder.rb', line 117

def build_mapping(id, filename)
  Perftools::Profiles::Mapping.new(
    id: id,
    filename: @string_table.fetch(filename)
  )
end

#build_profile(start:, finish:) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/ddtrace/profiling/pprof/builder.rb', line 51

def build_profile(start:, finish:)
  start_ns = Datadog::Utils::Time.as_utc_epoch_ns(start)
  finish_ns = Datadog::Utils::Time.as_utc_epoch_ns(finish)

  Perftools::Profiles::Profile.new(
    sample_type: @sample_types.messages,
    sample: @samples,
    mapping: @mappings.messages,
    location: @locations.values,
    function: @functions.messages,
    string_table: @string_table.strings,
    time_nanos: start_ns,
    duration_nanos: finish_ns - start_ns,
  )
end

#build_value_type(type, unit) ⇒ Object



67
68
69
70
71
72
# File 'lib/ddtrace/profiling/pprof/builder.rb', line 67

def build_value_type(type, unit)
  Perftools::Profiles::ValueType.new(
    type: @string_table.fetch(type),
    unit: @string_table.fetch(unit)
  )
end

#encode_profile(profile) ⇒ Object



47
48
49
# File 'lib/ddtrace/profiling/pprof/builder.rb', line 47

def encode_profile(profile)
  Perftools::Profiles::Profile.encode(profile).force_encoding(DEFAULT_ENCODING)
end

#initialize_locations_hashObject

The locations hash maps unique BacktraceLocation instances to their corresponding pprof Location objects; there's a 1:1 correspondence, since BacktraceLocations were already deduped



40
41
42
43
44
45
# File 'lib/ddtrace/profiling/pprof/builder.rb', line 40

def initialize_locations_hash
  sequence = Utils::Sequence.new(1)
  Hash.new do |locations_hash, backtrace_location|
    locations_hash[backtrace_location] = build_location(sequence.next, backtrace_location)
  end
end