ddtrace 1.14.0 → 1.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +165 -2
- data/ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md +3 -5
- data/ext/ddtrace_profiling_native_extension/clock_id.h +0 -3
- data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +0 -22
- data/ext/ddtrace_profiling_native_extension/clock_id_noop.c +0 -1
- data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +41 -6
- data/ext/ddtrace_profiling_native_extension/collectors_idle_sampling_helper.c +3 -0
- data/ext/ddtrace_profiling_native_extension/collectors_stack.c +76 -24
- data/ext/ddtrace_profiling_native_extension/collectors_stack.h +1 -1
- data/ext/ddtrace_profiling_native_extension/collectors_thread_context.c +207 -32
- data/ext/ddtrace_profiling_native_extension/collectors_thread_context.h +1 -1
- data/ext/ddtrace_profiling_native_extension/extconf.rb +8 -2
- data/ext/ddtrace_profiling_native_extension/http_transport.c +26 -10
- data/ext/ddtrace_profiling_native_extension/libdatadog_helpers.c +42 -0
- data/ext/ddtrace_profiling_native_extension/libdatadog_helpers.h +6 -0
- data/ext/ddtrace_profiling_native_extension/native_extension_helpers.rb +1 -16
- data/ext/ddtrace_profiling_native_extension/pid_controller.c +57 -0
- data/ext/ddtrace_profiling_native_extension/pid_controller.h +45 -0
- data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +17 -12
- data/ext/ddtrace_profiling_native_extension/profiling.c +0 -2
- data/ext/ddtrace_profiling_native_extension/stack_recorder.c +74 -37
- data/ext/ddtrace_profiling_native_extension/stack_recorder.h +13 -3
- data/lib/datadog/appsec/assets/waf_rules/processors.json +92 -0
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +698 -75
- data/lib/datadog/appsec/assets/waf_rules/scanners.json +114 -0
- data/lib/datadog/appsec/assets/waf_rules/strict.json +98 -8
- data/lib/datadog/appsec/assets.rb +8 -0
- data/lib/datadog/appsec/component.rb +9 -2
- data/lib/datadog/appsec/configuration/settings.rb +61 -2
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +6 -2
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +8 -6
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +2 -7
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +2 -5
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +2 -5
- data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +3 -2
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +24 -10
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +3 -2
- data/lib/datadog/appsec/contrib/rails/patcher.rb +9 -3
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +2 -5
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +6 -4
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +13 -7
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +2 -5
- data/lib/datadog/appsec/event.rb +106 -50
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +3 -3
- data/lib/datadog/appsec/monitor/reactive/set_user.rb +2 -5
- data/lib/datadog/appsec/processor/actions.rb +49 -0
- data/lib/datadog/appsec/processor/rule_merger.rb +22 -2
- data/lib/datadog/appsec/processor.rb +34 -6
- data/lib/datadog/appsec/remote.rb +4 -1
- data/lib/datadog/appsec/response.rb +82 -4
- data/lib/datadog/appsec/sample_rate.rb +21 -0
- data/lib/datadog/appsec.rb +2 -2
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +29 -24
- data/lib/datadog/core/configuration/base.rb +1 -11
- data/lib/datadog/core/configuration/components.rb +7 -2
- data/lib/datadog/core/configuration/ext.rb +21 -0
- data/lib/datadog/core/configuration/option.rb +2 -4
- data/lib/datadog/core/configuration/option_definition.rb +17 -41
- data/lib/datadog/core/configuration/options.rb +5 -5
- data/lib/datadog/core/configuration/settings.rb +47 -45
- data/lib/datadog/core/environment/execution.rb +47 -9
- data/lib/datadog/core/environment/variable_helpers.rb +0 -69
- data/lib/datadog/core/error.rb +1 -0
- data/lib/datadog/core/git/ext.rb +2 -0
- data/lib/datadog/core/remote/client/capabilities.rb +1 -1
- data/lib/datadog/core/remote/component.rb +2 -2
- data/lib/datadog/core/remote/negotiation.rb +2 -2
- data/lib/datadog/core/remote/transport/config.rb +60 -0
- data/lib/datadog/core/remote/transport/http/api/instance.rb +39 -0
- data/lib/datadog/core/remote/transport/http/api/spec.rb +21 -0
- data/lib/datadog/core/remote/transport/http/api.rb +58 -0
- data/lib/datadog/core/remote/transport/http/builder.rb +219 -0
- data/lib/datadog/core/remote/transport/http/client.rb +48 -0
- data/lib/datadog/core/remote/transport/http/config.rb +280 -0
- data/lib/datadog/core/remote/transport/http/negotiation.rb +146 -0
- data/lib/datadog/core/remote/transport/http.rb +179 -0
- data/lib/datadog/core/{transport → remote/transport}/negotiation.rb +25 -23
- data/lib/datadog/core/remote/worker.rb +3 -1
- data/lib/datadog/core/telemetry/collector.rb +3 -2
- data/lib/datadog/core/telemetry/http/transport.rb +2 -1
- data/lib/datadog/core/transport/ext.rb +47 -0
- data/lib/datadog/core/transport/http/adapters/net.rb +168 -0
- data/lib/datadog/core/transport/http/adapters/registry.rb +29 -0
- data/lib/datadog/core/transport/http/adapters/test.rb +89 -0
- data/lib/datadog/core/transport/http/adapters/unix_socket.rb +83 -0
- data/lib/datadog/core/transport/http/api/endpoint.rb +31 -0
- data/lib/datadog/core/transport/http/api/fallbacks.rb +26 -0
- data/lib/datadog/core/transport/http/api/map.rb +18 -0
- data/lib/datadog/core/transport/http/env.rb +62 -0
- data/lib/datadog/core/transport/http/response.rb +60 -0
- data/lib/datadog/core/transport/parcel.rb +22 -0
- data/lib/datadog/core/transport/request.rb +17 -0
- data/lib/datadog/core/transport/response.rb +64 -0
- data/lib/datadog/core/workers/polling.rb +2 -2
- data/lib/datadog/opentelemetry/api/context.rb +10 -3
- data/lib/datadog/opentelemetry/sdk/propagator.rb +2 -1
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +14 -2
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +68 -0
- data/lib/datadog/opentelemetry/trace.rb +58 -0
- data/lib/datadog/opentelemetry.rb +1 -0
- data/lib/datadog/opentracer.rb +9 -0
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +14 -19
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -1
- data/lib/datadog/profiling/collectors/thread_context.rb +9 -1
- data/lib/datadog/profiling/component.rb +24 -99
- data/lib/datadog/profiling/ext.rb +0 -12
- data/lib/datadog/profiling/flush.rb +0 -3
- data/lib/datadog/profiling/http_transport.rb +6 -3
- data/lib/datadog/profiling/native_extension.rb +0 -21
- data/lib/datadog/profiling/profiler.rb +36 -13
- data/lib/datadog/profiling/scheduler.rb +16 -9
- data/lib/datadog/profiling.rb +8 -81
- data/lib/datadog/tracing/component.rb +10 -4
- data/lib/datadog/tracing/configuration/agent_settings_resolver.rb +13 -0
- data/lib/datadog/tracing/configuration/ext.rb +4 -2
- data/lib/datadog/tracing/configuration/settings.rb +14 -7
- data/lib/datadog/tracing/contrib/action_pack/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +4 -0
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +106 -197
- data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +3 -0
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +7 -0
- data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +14 -14
- data/lib/datadog/tracing/contrib/concurrent_ruby/future_patch.rb +3 -10
- data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +2 -1
- data/lib/datadog/tracing/contrib/concurrent_ruby/patcher.rb +8 -1
- data/lib/datadog/tracing/contrib/concurrent_ruby/promises_future_patch.rb +22 -0
- data/lib/datadog/tracing/contrib/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/dalli/configuration/settings.rb +6 -0
- data/lib/datadog/tracing/contrib/dalli/ext.rb +7 -0
- data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +9 -2
- data/lib/datadog/tracing/contrib/delayed_job/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +5 -0
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +5 -0
- data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +8 -0
- data/lib/datadog/tracing/contrib/excon/middleware.rb +5 -0
- data/lib/datadog/tracing/contrib/ext.rb +3 -0
- data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +5 -0
- data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +21 -1
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +11 -1
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +18 -0
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor.rb +0 -4
- data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +3 -3
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +5 -0
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +5 -0
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +5 -0
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +7 -0
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +13 -3
- data/lib/datadog/tracing/contrib/opensearch/integration.rb +2 -2
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +7 -0
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +5 -0
- data/lib/datadog/tracing/contrib/presto/instrumentation.rb +5 -0
- data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +1 -1
- data/lib/datadog/tracing/contrib/que/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/racecar/event.rb +5 -0
- data/lib/datadog/tracing/contrib/rack/header_tagging.rb +14 -4
- data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +4 -4
- data/lib/datadog/tracing/contrib/rake/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/redis/instrumentation.rb +3 -38
- data/lib/datadog/tracing/contrib/redis/tags.rb +7 -2
- data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +46 -33
- data/lib/datadog/tracing/contrib/resque/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +5 -0
- data/lib/datadog/tracing/contrib/sequel/utils.rb +5 -0
- data/lib/datadog/tracing/contrib/shoryuken/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/sneakers/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/utils/quantization/http.rb +2 -2
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +6 -0
- data/lib/datadog/tracing/distributed/propagation.rb +13 -33
- data/lib/datadog/tracing/metadata/tagging.rb +3 -3
- data/lib/datadog/tracing/sync_writer.rb +3 -3
- data/lib/datadog/tracing/tracer.rb +2 -0
- data/lib/datadog/{core → tracing}/transport/http/api/instance.rb +1 -1
- data/lib/datadog/{core → tracing}/transport/http/api/spec.rb +1 -1
- data/lib/datadog/tracing/transport/http/api.rb +43 -0
- data/lib/datadog/{core → tracing}/transport/http/builder.rb +13 -68
- data/lib/datadog/tracing/transport/http/client.rb +57 -0
- data/lib/datadog/tracing/transport/http/statistics.rb +47 -0
- data/lib/datadog/tracing/transport/http/traces.rb +152 -0
- data/lib/datadog/tracing/transport/http.rb +124 -0
- data/lib/datadog/tracing/transport/io/client.rb +89 -0
- data/lib/datadog/tracing/transport/io/response.rb +27 -0
- data/lib/datadog/tracing/transport/io/traces.rb +101 -0
- data/lib/datadog/tracing/transport/io.rb +30 -0
- data/lib/datadog/tracing/transport/serializable_trace.rb +126 -0
- data/lib/datadog/tracing/transport/statistics.rb +77 -0
- data/lib/datadog/tracing/transport/trace_formatter.rb +209 -0
- data/lib/datadog/tracing/transport/traces.rb +224 -0
- data/lib/datadog/tracing/workers/trace_writer.rb +5 -3
- data/lib/datadog/tracing/workers.rb +3 -2
- data/lib/datadog/tracing/writer.rb +5 -2
- data/lib/ddtrace/transport/ext.rb +17 -15
- data/lib/ddtrace/version.rb +2 -2
- data/lib/ddtrace.rb +1 -1
- metadata +73 -96
- data/lib/datadog/ci/configuration/components.rb +0 -32
- data/lib/datadog/ci/configuration/settings.rb +0 -51
- data/lib/datadog/ci/contrib/cucumber/configuration/settings.rb +0 -35
- data/lib/datadog/ci/contrib/cucumber/ext.rb +0 -22
- data/lib/datadog/ci/contrib/cucumber/formatter.rb +0 -94
- data/lib/datadog/ci/contrib/cucumber/instrumentation.rb +0 -28
- data/lib/datadog/ci/contrib/cucumber/integration.rb +0 -47
- data/lib/datadog/ci/contrib/cucumber/patcher.rb +0 -27
- data/lib/datadog/ci/contrib/minitest/configuration/settings.rb +0 -35
- data/lib/datadog/ci/contrib/minitest/ext.rb +0 -21
- data/lib/datadog/ci/contrib/minitest/integration.rb +0 -49
- data/lib/datadog/ci/contrib/minitest/patcher.rb +0 -27
- data/lib/datadog/ci/contrib/minitest/test_helper.rb +0 -68
- data/lib/datadog/ci/contrib/rspec/configuration/settings.rb +0 -35
- data/lib/datadog/ci/contrib/rspec/example.rb +0 -68
- data/lib/datadog/ci/contrib/rspec/ext.rb +0 -21
- data/lib/datadog/ci/contrib/rspec/integration.rb +0 -48
- data/lib/datadog/ci/contrib/rspec/patcher.rb +0 -27
- data/lib/datadog/ci/ext/app_types.rb +0 -9
- data/lib/datadog/ci/ext/environment.rb +0 -575
- data/lib/datadog/ci/ext/settings.rb +0 -10
- data/lib/datadog/ci/ext/test.rb +0 -35
- data/lib/datadog/ci/extensions.rb +0 -19
- data/lib/datadog/ci/flush.rb +0 -38
- data/lib/datadog/ci/test.rb +0 -81
- data/lib/datadog/ci.rb +0 -21
- data/lib/datadog/core/configuration/dependency_resolver.rb +0 -28
- data/lib/datadog/core/configuration/option_definition_set.rb +0 -22
- data/lib/datadog/core/configuration/option_set.rb +0 -10
- data/lib/datadog/core/transport/config.rb +0 -58
- data/lib/datadog/core/transport/http/api.rb +0 -57
- data/lib/datadog/core/transport/http/client.rb +0 -45
- data/lib/datadog/core/transport/http/config.rb +0 -278
- data/lib/datadog/core/transport/http/negotiation.rb +0 -144
- data/lib/datadog/core/transport/http.rb +0 -169
- data/lib/datadog/core/utils/object_set.rb +0 -43
- data/lib/datadog/core/utils/string_table.rb +0 -47
- data/lib/datadog/profiling/backtrace_location.rb +0 -34
- data/lib/datadog/profiling/buffer.rb +0 -43
- data/lib/datadog/profiling/collectors/old_stack.rb +0 -301
- data/lib/datadog/profiling/encoding/profile.rb +0 -41
- data/lib/datadog/profiling/event.rb +0 -15
- data/lib/datadog/profiling/events/stack.rb +0 -82
- data/lib/datadog/profiling/old_recorder.rb +0 -107
- data/lib/datadog/profiling/pprof/builder.rb +0 -125
- data/lib/datadog/profiling/pprof/converter.rb +0 -102
- data/lib/datadog/profiling/pprof/message_set.rb +0 -16
- data/lib/datadog/profiling/pprof/payload.rb +0 -20
- data/lib/datadog/profiling/pprof/pprof.proto +0 -212
- data/lib/datadog/profiling/pprof/pprof_pb.rb +0 -81
- data/lib/datadog/profiling/pprof/stack_sample.rb +0 -139
- data/lib/datadog/profiling/pprof/string_table.rb +0 -12
- data/lib/datadog/profiling/pprof/template.rb +0 -118
- data/lib/datadog/profiling/trace_identifiers/ddtrace.rb +0 -43
- data/lib/datadog/profiling/trace_identifiers/helper.rb +0 -45
- data/lib/ddtrace/transport/http/adapters/net.rb +0 -168
- data/lib/ddtrace/transport/http/adapters/registry.rb +0 -27
- data/lib/ddtrace/transport/http/adapters/test.rb +0 -85
- data/lib/ddtrace/transport/http/adapters/unix_socket.rb +0 -77
- data/lib/ddtrace/transport/http/api/endpoint.rb +0 -29
- data/lib/ddtrace/transport/http/api/fallbacks.rb +0 -24
- data/lib/ddtrace/transport/http/api/instance.rb +0 -35
- data/lib/ddtrace/transport/http/api/map.rb +0 -16
- data/lib/ddtrace/transport/http/api/spec.rb +0 -17
- data/lib/ddtrace/transport/http/api.rb +0 -39
- data/lib/ddtrace/transport/http/builder.rb +0 -176
- data/lib/ddtrace/transport/http/client.rb +0 -52
- data/lib/ddtrace/transport/http/env.rb +0 -58
- data/lib/ddtrace/transport/http/response.rb +0 -58
- data/lib/ddtrace/transport/http/statistics.rb +0 -43
- data/lib/ddtrace/transport/http/traces.rb +0 -144
- data/lib/ddtrace/transport/http.rb +0 -117
- data/lib/ddtrace/transport/io/client.rb +0 -85
- data/lib/ddtrace/transport/io/response.rb +0 -25
- data/lib/ddtrace/transport/io/traces.rb +0 -99
- data/lib/ddtrace/transport/io.rb +0 -28
- data/lib/ddtrace/transport/parcel.rb +0 -20
- data/lib/ddtrace/transport/request.rb +0 -15
- data/lib/ddtrace/transport/response.rb +0 -60
- data/lib/ddtrace/transport/serializable_trace.rb +0 -122
- data/lib/ddtrace/transport/statistics.rb +0 -75
- data/lib/ddtrace/transport/trace_formatter.rb +0 -207
- data/lib/ddtrace/transport/traces.rb +0 -216
|
@@ -82,9 +82,9 @@ end
|
|
|
82
82
|
# Because we can't control what compiler versions our customers use, shipping with -Werror by default is a no-go.
|
|
83
83
|
# But we can enable it in CI, so that we quickly spot any new warnings that just got introduced.
|
|
84
84
|
#
|
|
85
|
-
# @ivoanjo TODO:
|
|
85
|
+
# @ivoanjo TODO: 3.3.0-preview releases are causing issues in CI because `have_header('vm_core.h')` below triggers warnings;
|
|
86
86
|
# I've chosen to disable `-Werror` for this Ruby version for now, and we can revisit this on a later 3.3 release.
|
|
87
|
-
add_compiler_flag '-Werror' if ENV['DDTRACE_CI'] == 'true' && !RUBY_DESCRIPTION.include?('3.3.
|
|
87
|
+
add_compiler_flag '-Werror' if ENV['DDTRACE_CI'] == 'true' && !RUBY_DESCRIPTION.include?('3.3.0preview')
|
|
88
88
|
|
|
89
89
|
# Older gcc releases may not default to C99 and we need to ask for this. This is also used:
|
|
90
90
|
# * by upstream Ruby -- search for gnu99 in the codebase
|
|
@@ -146,6 +146,9 @@ $defs << '-DNO_RB_THREAD_SCHED' if RUBY_VERSION < '3.2'
|
|
|
146
146
|
# On older Rubies, the first_lineno inside a location was a VALUE and not a int (https://github.com/ruby/ruby/pull/6430)
|
|
147
147
|
$defs << '-DNO_INT_FIRST_LINENO' if RUBY_VERSION < '3.2'
|
|
148
148
|
|
|
149
|
+
# On older Rubies, "pop" was not a primitive operation
|
|
150
|
+
$defs << '-DNO_PRIMITIVE_POP' if RUBY_VERSION < '3.2'
|
|
151
|
+
|
|
149
152
|
# On older Rubies, there was no tid member in the internal thread structure
|
|
150
153
|
$defs << '-DNO_THREAD_TID' if RUBY_VERSION < '3.1'
|
|
151
154
|
|
|
@@ -155,6 +158,9 @@ $defs << '-DUSE_BACKPORTED_RB_PROFILE_FRAME_METHOD_NAME' if RUBY_VERSION < '3'
|
|
|
155
158
|
# On older Rubies, there are no Ractors
|
|
156
159
|
$defs << '-DNO_RACTORS' if RUBY_VERSION < '3'
|
|
157
160
|
|
|
161
|
+
# On older Rubies, objects would not move
|
|
162
|
+
$defs << '-DNO_T_MOVED' if RUBY_VERSION < '2.7'
|
|
163
|
+
|
|
158
164
|
# On older Rubies, rb_global_vm_lock_struct did not include the owner field
|
|
159
165
|
$defs << '-DNO_GVL_OWNER' if RUBY_VERSION < '2.6'
|
|
160
166
|
|
|
@@ -201,7 +201,8 @@ static VALUE perform_export(
|
|
|
201
201
|
ddog_prof_Exporter *exporter,
|
|
202
202
|
ddog_Timespec start,
|
|
203
203
|
ddog_Timespec finish,
|
|
204
|
-
ddog_prof_Exporter_Slice_File
|
|
204
|
+
ddog_prof_Exporter_Slice_File files_to_compress_and_export,
|
|
205
|
+
ddog_prof_Exporter_Slice_File files_to_export_unmodified,
|
|
205
206
|
ddog_Vec_Tag *additional_tags,
|
|
206
207
|
ddog_CharSlice internal_metadata,
|
|
207
208
|
uint64_t timeout_milliseconds
|
|
@@ -211,7 +212,8 @@ static VALUE perform_export(
|
|
|
211
212
|
exporter,
|
|
212
213
|
start,
|
|
213
214
|
finish,
|
|
214
|
-
|
|
215
|
+
files_to_compress_and_export,
|
|
216
|
+
files_to_export_unmodified,
|
|
215
217
|
additional_tags,
|
|
216
218
|
endpoints_stats,
|
|
217
219
|
&internal_metadata,
|
|
@@ -308,18 +310,23 @@ static VALUE _native_do_export(
|
|
|
308
310
|
ddog_Timespec finish =
|
|
309
311
|
{.seconds = NUM2LONG(finish_timespec_seconds), .nanoseconds = NUM2UINT(finish_timespec_nanoseconds)};
|
|
310
312
|
|
|
311
|
-
int
|
|
312
|
-
ddog_prof_Exporter_File
|
|
313
|
-
|
|
313
|
+
int to_compress_length = have_code_provenance ? 1 : 0;
|
|
314
|
+
ddog_prof_Exporter_File to_compress[to_compress_length];
|
|
315
|
+
int already_compressed_length = 1; // pprof
|
|
316
|
+
ddog_prof_Exporter_File already_compressed[already_compressed_length];
|
|
314
317
|
|
|
315
|
-
|
|
318
|
+
ddog_prof_Exporter_Slice_File files_to_compress_and_export = {.ptr = to_compress, .len = to_compress_length};
|
|
319
|
+
ddog_prof_Exporter_Slice_File files_to_export_unmodified = {.ptr = already_compressed, .len = already_compressed_length};
|
|
320
|
+
|
|
321
|
+
already_compressed[0] = (ddog_prof_Exporter_File) {
|
|
316
322
|
.name = char_slice_from_ruby_string(pprof_file_name),
|
|
317
|
-
.file = byte_slice_from_ruby_string(pprof_data)
|
|
323
|
+
.file = byte_slice_from_ruby_string(pprof_data),
|
|
318
324
|
};
|
|
325
|
+
|
|
319
326
|
if (have_code_provenance) {
|
|
320
|
-
|
|
327
|
+
to_compress[0] = (ddog_prof_Exporter_File) {
|
|
321
328
|
.name = char_slice_from_ruby_string(code_provenance_file_name),
|
|
322
|
-
.file = byte_slice_from_ruby_string(code_provenance_data)
|
|
329
|
+
.file = byte_slice_from_ruby_string(code_provenance_data),
|
|
323
330
|
};
|
|
324
331
|
}
|
|
325
332
|
|
|
@@ -332,7 +339,16 @@ static VALUE _native_do_export(
|
|
|
332
339
|
VALUE failure_tuple = handle_exporter_failure(exporter_result);
|
|
333
340
|
if (!NIL_P(failure_tuple)) return failure_tuple;
|
|
334
341
|
|
|
335
|
-
return perform_export(
|
|
342
|
+
return perform_export(
|
|
343
|
+
exporter_result.ok,
|
|
344
|
+
start,
|
|
345
|
+
finish,
|
|
346
|
+
files_to_compress_and_export,
|
|
347
|
+
files_to_export_unmodified,
|
|
348
|
+
null_additional_tags,
|
|
349
|
+
internal_metadata,
|
|
350
|
+
timeout_milliseconds
|
|
351
|
+
);
|
|
336
352
|
}
|
|
337
353
|
|
|
338
354
|
static void *call_exporter_without_gvl(void *call_args) {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#include "libdatadog_helpers.h"
|
|
2
|
+
|
|
3
|
+
#include <ruby.h>
|
|
4
|
+
|
|
5
|
+
const char *ruby_value_type_to_string(enum ruby_value_type type) {
|
|
6
|
+
return ruby_value_type_to_char_slice(type).ptr;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
ddog_CharSlice ruby_value_type_to_char_slice(enum ruby_value_type type) {
|
|
10
|
+
switch (type) {
|
|
11
|
+
case(RUBY_T_NONE ): return DDOG_CHARSLICE_C("T_NONE");
|
|
12
|
+
case(RUBY_T_OBJECT ): return DDOG_CHARSLICE_C("T_OBJECT");
|
|
13
|
+
case(RUBY_T_CLASS ): return DDOG_CHARSLICE_C("T_CLASS");
|
|
14
|
+
case(RUBY_T_MODULE ): return DDOG_CHARSLICE_C("T_MODULE");
|
|
15
|
+
case(RUBY_T_FLOAT ): return DDOG_CHARSLICE_C("T_FLOAT");
|
|
16
|
+
case(RUBY_T_STRING ): return DDOG_CHARSLICE_C("T_STRING");
|
|
17
|
+
case(RUBY_T_REGEXP ): return DDOG_CHARSLICE_C("T_REGEXP");
|
|
18
|
+
case(RUBY_T_ARRAY ): return DDOG_CHARSLICE_C("T_ARRAY");
|
|
19
|
+
case(RUBY_T_HASH ): return DDOG_CHARSLICE_C("T_HASH");
|
|
20
|
+
case(RUBY_T_STRUCT ): return DDOG_CHARSLICE_C("T_STRUCT");
|
|
21
|
+
case(RUBY_T_BIGNUM ): return DDOG_CHARSLICE_C("T_BIGNUM");
|
|
22
|
+
case(RUBY_T_FILE ): return DDOG_CHARSLICE_C("T_FILE");
|
|
23
|
+
case(RUBY_T_DATA ): return DDOG_CHARSLICE_C("T_DATA");
|
|
24
|
+
case(RUBY_T_MATCH ): return DDOG_CHARSLICE_C("T_MATCH");
|
|
25
|
+
case(RUBY_T_COMPLEX ): return DDOG_CHARSLICE_C("T_COMPLEX");
|
|
26
|
+
case(RUBY_T_RATIONAL): return DDOG_CHARSLICE_C("T_RATIONAL");
|
|
27
|
+
case(RUBY_T_NIL ): return DDOG_CHARSLICE_C("T_NIL");
|
|
28
|
+
case(RUBY_T_TRUE ): return DDOG_CHARSLICE_C("T_TRUE");
|
|
29
|
+
case(RUBY_T_FALSE ): return DDOG_CHARSLICE_C("T_FALSE");
|
|
30
|
+
case(RUBY_T_SYMBOL ): return DDOG_CHARSLICE_C("T_SYMBOL");
|
|
31
|
+
case(RUBY_T_FIXNUM ): return DDOG_CHARSLICE_C("T_FIXNUM");
|
|
32
|
+
case(RUBY_T_UNDEF ): return DDOG_CHARSLICE_C("T_UNDEF");
|
|
33
|
+
case(RUBY_T_IMEMO ): return DDOG_CHARSLICE_C("T_IMEMO");
|
|
34
|
+
case(RUBY_T_NODE ): return DDOG_CHARSLICE_C("T_NODE");
|
|
35
|
+
case(RUBY_T_ICLASS ): return DDOG_CHARSLICE_C("T_ICLASS");
|
|
36
|
+
case(RUBY_T_ZOMBIE ): return DDOG_CHARSLICE_C("T_ZOMBIE");
|
|
37
|
+
#ifndef NO_T_MOVED
|
|
38
|
+
case(RUBY_T_MOVED ): return DDOG_CHARSLICE_C("T_MOVED");
|
|
39
|
+
#endif
|
|
40
|
+
default: return DDOG_CHARSLICE_C("BUG: Unknown value for ruby_value_type");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -23,3 +23,9 @@ inline static VALUE get_error_details_and_drop(ddog_Error *error) {
|
|
|
23
23
|
ddog_Error_drop(error);
|
|
24
24
|
return result;
|
|
25
25
|
}
|
|
26
|
+
|
|
27
|
+
// Used for pretty printing this Ruby enum. Returns "T_UNKNOWN_OR_MISSING_RUBY_VALUE_TYPE_ENTRY" for unknown elements.
|
|
28
|
+
// In practice, there's a few types that the profiler will probably never encounter, but I've added all entries of
|
|
29
|
+
// ruby_value_type that Ruby uses so that we can also use this for debugging.
|
|
30
|
+
const char *ruby_value_type_to_string(enum ruby_value_type type);
|
|
31
|
+
ddog_CharSlice ruby_value_type_to_char_slice(enum ruby_value_type type);
|
|
@@ -15,7 +15,7 @@ module Datadog
|
|
|
15
15
|
# The MJIT header was introduced on 2.6 and removed on 3.3; for other Rubies we rely on debase-ruby_core_source
|
|
16
16
|
CAN_USE_MJIT_HEADER = RUBY_VERSION.start_with?('2.6', '2.7', '3.0.', '3.1.', '3.2.')
|
|
17
17
|
|
|
18
|
-
LIBDATADOG_VERSION = '~>
|
|
18
|
+
LIBDATADOG_VERSION = '~> 5.0.0.1.0'
|
|
19
19
|
|
|
20
20
|
def self.fail_install_if_missing_extension?
|
|
21
21
|
ENV[ENV_FAIL_INSTALL_IF_MISSING_EXTENSION].to_s.strip.downcase == 'true'
|
|
@@ -87,7 +87,6 @@ module Datadog
|
|
|
87
87
|
on_unknown_os? ||
|
|
88
88
|
on_unsupported_cpu_arch? ||
|
|
89
89
|
on_unsupported_ruby_version? ||
|
|
90
|
-
on_ruby_3_3? ||
|
|
91
90
|
expected_to_use_mjit_but_mjit_is_disabled? ||
|
|
92
91
|
libdatadog_not_available? ||
|
|
93
92
|
libdatadog_not_usable?
|
|
@@ -270,20 +269,6 @@ module Datadog
|
|
|
270
269
|
ruby_version_not_supported if RUBY_VERSION.start_with?('2.1.', '2.2.')
|
|
271
270
|
end
|
|
272
271
|
|
|
273
|
-
private_class_method def self.on_ruby_3_3?
|
|
274
|
-
incompatible_with_3_3 = explain_issue(
|
|
275
|
-
'the profiler in the current version of ddtrace does not yet support',
|
|
276
|
-
'Ruby version 3.3.',
|
|
277
|
-
'(See https://github.com/datadog/dd-trace-rb/issues/3053 for details).',
|
|
278
|
-
suggested: [
|
|
279
|
-
'Try upgrading to the latest ddtrace, as this issue may have been',
|
|
280
|
-
'fixed by now.',
|
|
281
|
-
] + CONTACT_SUPPORT,
|
|
282
|
-
)
|
|
283
|
-
|
|
284
|
-
incompatible_with_3_3 if RUBY_VERSION.start_with?('3.3.')
|
|
285
|
-
end
|
|
286
|
-
|
|
287
272
|
# On some Rubies, we require the mjit header to be present. If Ruby was installed without MJIT support, we also skip
|
|
288
273
|
# building the extension.
|
|
289
274
|
private_class_method def self.expected_to_use_mjit_but_mjit_is_disabled?
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 Datadog, Inc
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// Originally imported from https://github.com/DataDog/java-profiler/blob/11fe6206c31a14c6e5134e8401eaec8b22c618d7/ddprof-lib/src/main/cpp/pidController.cpp
|
|
18
|
+
|
|
19
|
+
#include "pid_controller.h"
|
|
20
|
+
|
|
21
|
+
#include <math.h>
|
|
22
|
+
|
|
23
|
+
inline static double computeAlpha(float cutoff) {
|
|
24
|
+
if (cutoff <= 0)
|
|
25
|
+
return 1;
|
|
26
|
+
// α(fₙ) = cos(2πfₙ) - 1 + √( cos(2πfₙ)² - 4 cos(2πfₙ) + 3 )
|
|
27
|
+
const double c = cos(2 * ((double) M_PI) * cutoff);
|
|
28
|
+
return c - 1 + sqrt(c * c - 4 * c + 3);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
void pid_controller_init(pid_controller *controller, u64 target_per_second, double proportional_gain, double integral_gain, double derivative_gain, int sampling_window, double cutoff_secs) {
|
|
32
|
+
controller->_target = target_per_second * sampling_window;
|
|
33
|
+
controller->_proportional_gain = proportional_gain;
|
|
34
|
+
controller->_integral_gain = integral_gain * sampling_window;
|
|
35
|
+
controller->_derivative_gain = derivative_gain / sampling_window;
|
|
36
|
+
controller->_alpha = computeAlpha(sampling_window / cutoff_secs);
|
|
37
|
+
controller->_avg_error= 0;
|
|
38
|
+
controller->_integral_value = 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
double pid_controller_compute(pid_controller *controller, u64 input, double time_delta_coefficient) {
|
|
42
|
+
// time_delta_coefficient allows variable sampling window
|
|
43
|
+
// the values are linearly scaled using that coefficient to reinterpret the given value within the expected sampling window
|
|
44
|
+
double absolute_error = (((double) controller->_target) - ((double) input)) * time_delta_coefficient;
|
|
45
|
+
|
|
46
|
+
double avg_error = (controller->_alpha * absolute_error) + ((1 - controller->_alpha) * controller->_avg_error);
|
|
47
|
+
double derivative = avg_error - controller->_avg_error;
|
|
48
|
+
|
|
49
|
+
// PID formula:
|
|
50
|
+
// u[k] = Kp e[k] + Ki e_i[k] + Kd e_d[k], control signal
|
|
51
|
+
double signal = controller->_proportional_gain * absolute_error + controller->_integral_gain * controller->_integral_value + controller->_derivative_gain * derivative;
|
|
52
|
+
|
|
53
|
+
controller->_integral_value += absolute_error;
|
|
54
|
+
controller->_avg_error = avg_error;
|
|
55
|
+
|
|
56
|
+
return signal;
|
|
57
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 Datadog, Inc
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// Originally imported from https://github.com/DataDog/java-profiler/blob/11fe6206c31a14c6e5134e8401eaec8b22c618d7/ddprof-lib/src/main/cpp/pidController.h
|
|
18
|
+
|
|
19
|
+
#ifndef _PIDCONTROLLER_H
|
|
20
|
+
#define _PIDCONTROLLER_H
|
|
21
|
+
|
|
22
|
+
// From arch.h in java-profiler
|
|
23
|
+
typedef unsigned long long u64;
|
|
24
|
+
|
|
25
|
+
/*
|
|
26
|
+
* A simple implementation of a PID controller.
|
|
27
|
+
* Heavily influenced by https://tttapa.github.io/Pages/Arduino/Control-Theory/Motor-Fader/PID-Cpp-Implementation.html
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
typedef struct {
|
|
31
|
+
u64 _target;
|
|
32
|
+
double _proportional_gain;
|
|
33
|
+
double _derivative_gain;
|
|
34
|
+
double _integral_gain;
|
|
35
|
+
double _alpha;
|
|
36
|
+
|
|
37
|
+
double _avg_error;
|
|
38
|
+
long long _integral_value;
|
|
39
|
+
} pid_controller;
|
|
40
|
+
|
|
41
|
+
void pid_controller_init(pid_controller *controller, u64 target_per_second, double proportional_gain, double integral_gain, double derivative_gain, int sampling_window, double cutoff_secs);
|
|
42
|
+
|
|
43
|
+
double pid_controller_compute(pid_controller *controller, u64 input, double time_delta_seconds);
|
|
44
|
+
|
|
45
|
+
#endif
|
|
@@ -82,6 +82,16 @@ bool is_current_thread_holding_the_gvl(void) {
|
|
|
82
82
|
return owner.valid && pthread_equal(pthread_self(), owner.owner);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
#ifdef HAVE_RUBY_RACTOR_H
|
|
86
|
+
static inline rb_ractor_t *ddtrace_get_ractor(void) {
|
|
87
|
+
#ifndef USE_RACTOR_INTERNAL_APIS_DIRECTLY // Ruby >= 3.3
|
|
88
|
+
return thread_struct_from_object(rb_thread_current())->ractor;
|
|
89
|
+
#else
|
|
90
|
+
return GET_RACTOR();
|
|
91
|
+
#endif
|
|
92
|
+
}
|
|
93
|
+
#endif
|
|
94
|
+
|
|
85
95
|
#ifndef NO_GVL_OWNER // Ruby < 2.6 doesn't have the owner/running field
|
|
86
96
|
// NOTE: Reading the owner in this is a racy read, because we're not grabbing the lock that Ruby uses to protect it.
|
|
87
97
|
//
|
|
@@ -94,9 +104,9 @@ bool is_current_thread_holding_the_gvl(void) {
|
|
|
94
104
|
current_gvl_owner gvl_owner(void) {
|
|
95
105
|
const rb_thread_t *current_owner =
|
|
96
106
|
#ifndef NO_RB_THREAD_SCHED // Introduced in Ruby 3.2 as a replacement for struct rb_global_vm_lock_struct
|
|
97
|
-
|
|
107
|
+
ddtrace_get_ractor()->threads.sched.running;
|
|
98
108
|
#elif HAVE_RUBY_RACTOR_H
|
|
99
|
-
|
|
109
|
+
ddtrace_get_ractor()->threads.gvl.owner;
|
|
100
110
|
#else
|
|
101
111
|
GET_VM()->gvl.owner;
|
|
102
112
|
#endif
|
|
@@ -234,7 +244,7 @@ void ddtrace_thread_list(VALUE result_array) {
|
|
|
234
244
|
// I suspect the design in `rb_ractor_thread_list` may be done that way to perhaps in the future expose it to be
|
|
235
245
|
// called from a different Ractor, but I'm not sure...
|
|
236
246
|
#ifdef HAVE_RUBY_RACTOR_H
|
|
237
|
-
rb_ractor_t *current_ractor =
|
|
247
|
+
rb_ractor_t *current_ractor = ddtrace_get_ractor();
|
|
238
248
|
ccan_list_for_each(¤t_ractor->threads.set, thread, lt_node) {
|
|
239
249
|
#else
|
|
240
250
|
rb_vm_t *vm =
|
|
@@ -736,15 +746,10 @@ check_method_entry(VALUE obj, int can_be_svar)
|
|
|
736
746
|
// versions, so we need to do a bit more work.
|
|
737
747
|
struct rb_ractor_struct *ruby_single_main_ractor = NULL;
|
|
738
748
|
|
|
739
|
-
//
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
bool rb_ractor_main_p_(void)
|
|
744
|
-
{
|
|
745
|
-
VM_ASSERT(rb_multi_ractor_p());
|
|
746
|
-
rb_execution_context_t *ec = GET_EC();
|
|
747
|
-
return rb_ec_ractor_ptr(ec) == rb_ec_vm_ptr(ec)->ractor.main_ractor;
|
|
749
|
+
// Alternative implementation of rb_ractor_main_p_ that avoids relying on non-public symbols
|
|
750
|
+
bool rb_ractor_main_p_(void) {
|
|
751
|
+
// We need to get the main ractor in a bit of a roundabout way, since Ruby >= 3.3 hid `GET_VM()`
|
|
752
|
+
return ddtrace_get_ractor() == thread_struct_from_object(rb_thread_current())->vm->ractor.main_ractor;
|
|
748
753
|
}
|
|
749
754
|
#else
|
|
750
755
|
// Directly access Ruby internal fast path for detecting multiple Ractors.
|
|
@@ -41,8 +41,6 @@ void DDTRACE_EXPORT Init_ddtrace_profiling_native_extension(void) {
|
|
|
41
41
|
rb_define_singleton_method(native_extension_module, "native_working?", native_working_p, 0);
|
|
42
42
|
rb_funcall(native_extension_module, rb_intern("private_class_method"), 1, ID2SYM(rb_intern("native_working?")));
|
|
43
43
|
|
|
44
|
-
rb_define_singleton_method(native_extension_module, "clock_id_for", clock_id_for, 1); // from clock_id.h
|
|
45
|
-
|
|
46
44
|
collectors_cpu_and_wall_time_worker_init(profiling_module);
|
|
47
45
|
collectors_dynamic_sampling_rate_init(profiling_module);
|
|
48
46
|
collectors_idle_sampling_helper_init(profiling_module);
|
|
@@ -165,10 +165,10 @@ static const uint8_t all_value_types_positions[] = {CPU_TIME_VALUE_ID, CPU_SAMPL
|
|
|
165
165
|
// Contains native state for each instance
|
|
166
166
|
struct stack_recorder_state {
|
|
167
167
|
pthread_mutex_t slot_one_mutex;
|
|
168
|
-
ddog_prof_Profile
|
|
168
|
+
ddog_prof_Profile slot_one_profile;
|
|
169
169
|
|
|
170
170
|
pthread_mutex_t slot_two_mutex;
|
|
171
|
-
ddog_prof_Profile
|
|
171
|
+
ddog_prof_Profile slot_two_profile;
|
|
172
172
|
|
|
173
173
|
short active_slot; // MUST NEVER BE ACCESSED FROM record_sample; this is NOT for the sampler thread to use.
|
|
174
174
|
|
|
@@ -197,6 +197,7 @@ struct call_serialize_without_gvl_arguments {
|
|
|
197
197
|
|
|
198
198
|
static VALUE _native_new(VALUE klass);
|
|
199
199
|
static void initialize_slot_concurrency_control(struct stack_recorder_state *state);
|
|
200
|
+
static void initialize_profiles(struct stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types);
|
|
200
201
|
static void stack_recorder_typed_data_free(void *data);
|
|
201
202
|
static VALUE _native_initialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE cpu_time_enabled, VALUE alloc_samples_enabled);
|
|
202
203
|
static VALUE _native_serialize(VALUE self, VALUE recorder_instance);
|
|
@@ -211,8 +212,9 @@ static VALUE _native_is_slot_two_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE
|
|
|
211
212
|
static VALUE test_slot_mutex_state(VALUE recorder_instance, int slot);
|
|
212
213
|
static ddog_Timespec system_epoch_now_timespec(void);
|
|
213
214
|
static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_instance);
|
|
214
|
-
static void serializer_set_start_timestamp_for_next_profile(struct stack_recorder_state *state, ddog_Timespec
|
|
215
|
+
static void serializer_set_start_timestamp_for_next_profile(struct stack_recorder_state *state, ddog_Timespec start_time);
|
|
215
216
|
static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE local_root_span_id, VALUE endpoint);
|
|
217
|
+
static void reset_profile(ddog_prof_Profile *profile, ddog_Timespec *start_time /* Can be null */);
|
|
216
218
|
|
|
217
219
|
void stack_recorder_init(VALUE profiling_module) {
|
|
218
220
|
stack_recorder_class = rb_define_class_under(profiling_module, "StackRecorder", rb_cObject);
|
|
@@ -256,18 +258,25 @@ static const rb_data_type_t stack_recorder_typed_data = {
|
|
|
256
258
|
static VALUE _native_new(VALUE klass) {
|
|
257
259
|
struct stack_recorder_state *state = ruby_xcalloc(1, sizeof(struct stack_recorder_state));
|
|
258
260
|
|
|
261
|
+
// Note: Any exceptions raised from this note until the TypedData_Wrap_Struct call will lead to the state memory
|
|
262
|
+
// being leaked.
|
|
263
|
+
|
|
259
264
|
ddog_prof_Slice_ValueType sample_types = {.ptr = all_value_types, .len = ALL_VALUE_TYPES_COUNT};
|
|
260
265
|
|
|
261
266
|
initialize_slot_concurrency_control(state);
|
|
262
267
|
for (uint8_t i = 0; i < ALL_VALUE_TYPES_COUNT; i++) { state->position_for[i] = all_value_types_positions[i]; }
|
|
263
268
|
state->enabled_values_count = ALL_VALUE_TYPES_COUNT;
|
|
264
269
|
|
|
270
|
+
// Note: At this point, slot_one_profile and slot_two_profile contain null pointers. Libdatadog validates pointers
|
|
271
|
+
// before using them so it's ok for us to go ahead and create the StackRecorder object.
|
|
272
|
+
|
|
273
|
+
VALUE stack_recorder = TypedData_Wrap_Struct(klass, &stack_recorder_typed_data, state);
|
|
274
|
+
|
|
265
275
|
// Note: Don't raise exceptions after this point, since it'll lead to libdatadog memory leaking!
|
|
266
276
|
|
|
267
|
-
state
|
|
268
|
-
state->slot_two_profile = ddog_prof_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
|
|
277
|
+
initialize_profiles(state, sample_types);
|
|
269
278
|
|
|
270
|
-
return
|
|
279
|
+
return stack_recorder;
|
|
271
280
|
}
|
|
272
281
|
|
|
273
282
|
static void initialize_slot_concurrency_control(struct stack_recorder_state *state) {
|
|
@@ -280,14 +289,36 @@ static void initialize_slot_concurrency_control(struct stack_recorder_state *sta
|
|
|
280
289
|
state->active_slot = 1;
|
|
281
290
|
}
|
|
282
291
|
|
|
292
|
+
static void initialize_profiles(struct stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types) {
|
|
293
|
+
ddog_prof_Profile_NewResult slot_one_profile_result =
|
|
294
|
+
ddog_prof_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
|
|
295
|
+
|
|
296
|
+
if (slot_one_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
|
|
297
|
+
rb_raise(rb_eRuntimeError, "Failed to initialize slot one profile: %"PRIsVALUE, get_error_details_and_drop(&slot_one_profile_result.err));
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
ddog_prof_Profile_NewResult slot_two_profile_result =
|
|
301
|
+
ddog_prof_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
|
|
302
|
+
|
|
303
|
+
if (slot_two_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
|
|
304
|
+
// Uff! Though spot. We need to make sure to properly clean up the other profile as well first
|
|
305
|
+
ddog_prof_Profile_drop(&slot_one_profile_result.ok);
|
|
306
|
+
// And now we can raise...
|
|
307
|
+
rb_raise(rb_eRuntimeError, "Failed to initialize slot two profile: %"PRIsVALUE, get_error_details_and_drop(&slot_two_profile_result.err));
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
state->slot_one_profile = slot_one_profile_result.ok;
|
|
311
|
+
state->slot_two_profile = slot_two_profile_result.ok;
|
|
312
|
+
}
|
|
313
|
+
|
|
283
314
|
static void stack_recorder_typed_data_free(void *state_ptr) {
|
|
284
315
|
struct stack_recorder_state *state = (struct stack_recorder_state *) state_ptr;
|
|
285
316
|
|
|
286
317
|
pthread_mutex_destroy(&state->slot_one_mutex);
|
|
287
|
-
ddog_prof_Profile_drop(state->slot_one_profile);
|
|
318
|
+
ddog_prof_Profile_drop(&state->slot_one_profile);
|
|
288
319
|
|
|
289
320
|
pthread_mutex_destroy(&state->slot_two_mutex);
|
|
290
|
-
ddog_prof_Profile_drop(state->slot_two_profile);
|
|
321
|
+
ddog_prof_Profile_drop(&state->slot_two_profile);
|
|
291
322
|
|
|
292
323
|
ruby_xfree(state);
|
|
293
324
|
}
|
|
@@ -333,13 +364,11 @@ static VALUE _native_initialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_insta
|
|
|
333
364
|
state->position_for[ALLOC_SAMPLES_VALUE_ID] = next_disabled_pos++;
|
|
334
365
|
}
|
|
335
366
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
ddog_prof_Profile_drop(state->slot_one_profile);
|
|
339
|
-
ddog_prof_Profile_drop(state->slot_two_profile);
|
|
367
|
+
ddog_prof_Profile_drop(&state->slot_one_profile);
|
|
368
|
+
ddog_prof_Profile_drop(&state->slot_two_profile);
|
|
340
369
|
|
|
341
|
-
|
|
342
|
-
state
|
|
370
|
+
ddog_prof_Slice_ValueType sample_types = {.ptr = enabled_value_types, .len = state->enabled_values_count};
|
|
371
|
+
initialize_profiles(state, sample_types);
|
|
343
372
|
|
|
344
373
|
return Qtrue;
|
|
345
374
|
}
|
|
@@ -386,10 +415,6 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
|
|
|
386
415
|
VALUE start = ruby_time_from(ddprof_start);
|
|
387
416
|
VALUE finish = ruby_time_from(ddprof_finish);
|
|
388
417
|
|
|
389
|
-
if (!ddog_prof_Profile_reset(args.profile, NULL /* start_time is optional */ )) {
|
|
390
|
-
return rb_ary_new_from_args(2, error_symbol, rb_str_new_cstr("Failed to reset profile"));
|
|
391
|
-
}
|
|
392
|
-
|
|
393
418
|
return rb_ary_new_from_args(2, ok_symbol, rb_ary_new_from_args(3, start, finish, encoded_pprof));
|
|
394
419
|
}
|
|
395
420
|
|
|
@@ -399,7 +424,7 @@ static VALUE ruby_time_from(ddog_Timespec ddprof_time) {
|
|
|
399
424
|
return rb_time_timespec_new(&time, utc);
|
|
400
425
|
}
|
|
401
426
|
|
|
402
|
-
void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations, sample_values values,
|
|
427
|
+
void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations, sample_values values, sample_labels labels) {
|
|
403
428
|
struct stack_recorder_state *state;
|
|
404
429
|
TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
|
|
405
430
|
|
|
@@ -413,22 +438,23 @@ void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations,
|
|
|
413
438
|
uint8_t *position_for = state->position_for;
|
|
414
439
|
|
|
415
440
|
metric_values[position_for[CPU_TIME_VALUE_ID]] = values.cpu_time_ns;
|
|
416
|
-
metric_values[position_for[CPU_SAMPLES_VALUE_ID]] = values.
|
|
441
|
+
metric_values[position_for[CPU_SAMPLES_VALUE_ID]] = values.cpu_or_wall_samples;
|
|
417
442
|
metric_values[position_for[WALL_TIME_VALUE_ID]] = values.wall_time_ns;
|
|
418
443
|
metric_values[position_for[ALLOC_SAMPLES_VALUE_ID]] = values.alloc_samples;
|
|
419
444
|
|
|
420
|
-
|
|
445
|
+
ddog_prof_Profile_Result result = ddog_prof_Profile_add(
|
|
421
446
|
active_slot.profile,
|
|
422
447
|
(ddog_prof_Sample) {
|
|
423
448
|
.locations = locations,
|
|
424
449
|
.values = (ddog_Slice_I64) {.ptr = metric_values, .len = state->enabled_values_count},
|
|
425
|
-
.labels = labels
|
|
426
|
-
}
|
|
450
|
+
.labels = labels.labels
|
|
451
|
+
},
|
|
452
|
+
labels.end_timestamp_ns
|
|
427
453
|
);
|
|
428
454
|
|
|
429
455
|
sampler_unlock_active_profile(active_slot);
|
|
430
456
|
|
|
431
|
-
if (result.tag ==
|
|
457
|
+
if (result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
|
|
432
458
|
rb_raise(rb_eArgError, "Failed to record sample: %"PRIsVALUE, get_error_details_and_drop(&result.err));
|
|
433
459
|
}
|
|
434
460
|
}
|
|
@@ -439,16 +465,21 @@ void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_
|
|
|
439
465
|
|
|
440
466
|
struct active_slot_pair active_slot = sampler_lock_active_profile(state);
|
|
441
467
|
|
|
442
|
-
ddog_prof_Profile_set_endpoint(active_slot.profile, local_root_span_id, endpoint);
|
|
468
|
+
ddog_prof_Profile_Result result = ddog_prof_Profile_set_endpoint(active_slot.profile, local_root_span_id, endpoint);
|
|
443
469
|
|
|
444
470
|
sampler_unlock_active_profile(active_slot);
|
|
471
|
+
|
|
472
|
+
if (result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
|
|
473
|
+
rb_raise(rb_eArgError, "Failed to record endpoint: %"PRIsVALUE, get_error_details_and_drop(&result.err));
|
|
474
|
+
}
|
|
445
475
|
}
|
|
446
476
|
|
|
447
477
|
static void *call_serialize_without_gvl(void *call_args) {
|
|
448
478
|
struct call_serialize_without_gvl_arguments *args = (struct call_serialize_without_gvl_arguments *) call_args;
|
|
449
479
|
|
|
450
480
|
args->profile = serializer_flip_active_and_inactive_slots(args->state);
|
|
451
|
-
|
|
481
|
+
// Note: The profile gets reset by the serialize call
|
|
482
|
+
args->result = ddog_prof_Profile_serialize(args->profile, &args->finish_timestamp, NULL /* duration_nanos is optional */, NULL /* start_time is optional */);
|
|
452
483
|
args->serialize_ran = true;
|
|
453
484
|
|
|
454
485
|
return NULL; // Unused
|
|
@@ -467,7 +498,7 @@ static struct active_slot_pair sampler_lock_active_profile(struct stack_recorder
|
|
|
467
498
|
if (error && error != EBUSY) ENFORCE_SUCCESS_GVL(error);
|
|
468
499
|
|
|
469
500
|
// Slot one is active
|
|
470
|
-
if (!error) return (struct active_slot_pair) {.mutex = &state->slot_one_mutex, .profile = state->slot_one_profile};
|
|
501
|
+
if (!error) return (struct active_slot_pair) {.mutex = &state->slot_one_mutex, .profile = &state->slot_one_profile};
|
|
471
502
|
|
|
472
503
|
// If we got here, slot one was not active, let's try slot two
|
|
473
504
|
|
|
@@ -475,7 +506,7 @@ static struct active_slot_pair sampler_lock_active_profile(struct stack_recorder
|
|
|
475
506
|
if (error && error != EBUSY) ENFORCE_SUCCESS_GVL(error);
|
|
476
507
|
|
|
477
508
|
// Slot two is active
|
|
478
|
-
if (!error) return (struct active_slot_pair) {.mutex = &state->slot_two_mutex, .profile = state->slot_two_profile};
|
|
509
|
+
if (!error) return (struct active_slot_pair) {.mutex = &state->slot_two_mutex, .profile = &state->slot_two_profile};
|
|
479
510
|
}
|
|
480
511
|
|
|
481
512
|
// We already tried both multiple times, and we did not succeed. This is not expected to happen. Let's stop sampling.
|
|
@@ -506,7 +537,7 @@ static ddog_prof_Profile *serializer_flip_active_and_inactive_slots(struct stack
|
|
|
506
537
|
state->active_slot = (previously_active_slot == 1) ? 2 : 1;
|
|
507
538
|
|
|
508
539
|
// Return profile for previously active slot (now inactive)
|
|
509
|
-
return (previously_active_slot == 1) ? state->slot_one_profile : state->slot_two_profile;
|
|
540
|
+
return (previously_active_slot == 1) ? &state->slot_one_profile : &state->slot_two_profile;
|
|
510
541
|
}
|
|
511
542
|
|
|
512
543
|
// This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
|
|
@@ -565,19 +596,18 @@ static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_
|
|
|
565
596
|
// resulting state is inconsistent, we make sure to reset it back to the initial state.
|
|
566
597
|
initialize_slot_concurrency_control(state);
|
|
567
598
|
|
|
568
|
-
|
|
569
|
-
|
|
599
|
+
reset_profile(&state->slot_one_profile, /* start_time: */ NULL);
|
|
600
|
+
reset_profile(&state->slot_two_profile, /* start_time: */ NULL);
|
|
570
601
|
|
|
571
602
|
return Qtrue;
|
|
572
603
|
}
|
|
573
604
|
|
|
574
|
-
// Assumption 1: This method is called with the GVL being held, because `ddog_prof_Profile_reset` mutates the profile and
|
|
605
|
+
// Assumption 1: This method is called with the GVL being held, because `ddog_prof_Profile_reset` mutates the profile and must
|
|
575
606
|
// not be interrupted part-way through by a VM fork.
|
|
576
|
-
static void serializer_set_start_timestamp_for_next_profile(struct stack_recorder_state *state, ddog_Timespec
|
|
577
|
-
// Before making this profile active, we reset it so that it uses the correct
|
|
578
|
-
ddog_prof_Profile *next_profile = (state->active_slot == 1) ? state->slot_two_profile : state->slot_one_profile;
|
|
579
|
-
|
|
580
|
-
if (!ddog_prof_Profile_reset(next_profile, ×tamp)) rb_raise(rb_eRuntimeError, "Failed to reset profile");
|
|
607
|
+
static void serializer_set_start_timestamp_for_next_profile(struct stack_recorder_state *state, ddog_Timespec start_time) {
|
|
608
|
+
// Before making this profile active, we reset it so that it uses the correct start_time for its start
|
|
609
|
+
ddog_prof_Profile *next_profile = (state->active_slot == 1) ? &state->slot_two_profile : &state->slot_one_profile;
|
|
610
|
+
reset_profile(next_profile, &start_time);
|
|
581
611
|
}
|
|
582
612
|
|
|
583
613
|
static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE local_root_span_id, VALUE endpoint) {
|
|
@@ -585,3 +615,10 @@ static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_
|
|
|
585
615
|
record_endpoint(recorder_instance, NUM2ULL(local_root_span_id), char_slice_from_ruby_string(endpoint));
|
|
586
616
|
return Qtrue;
|
|
587
617
|
}
|
|
618
|
+
|
|
619
|
+
static void reset_profile(ddog_prof_Profile *profile, ddog_Timespec *start_time /* Can be null */) {
|
|
620
|
+
ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(profile, start_time);
|
|
621
|
+
if (reset_result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
|
|
622
|
+
rb_raise(rb_eRuntimeError, "Failed to reset profile: %"PRIsVALUE, get_error_details_and_drop(&reset_result.err));
|
|
623
|
+
}
|
|
624
|
+
}
|
|
@@ -2,13 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
#include <datadog/profiling.h>
|
|
4
4
|
|
|
5
|
-
typedef struct
|
|
5
|
+
typedef struct {
|
|
6
6
|
int64_t cpu_time_ns;
|
|
7
7
|
int64_t wall_time_ns;
|
|
8
|
-
uint32_t
|
|
8
|
+
uint32_t cpu_or_wall_samples;
|
|
9
9
|
uint32_t alloc_samples;
|
|
10
10
|
} sample_values;
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
typedef struct sample_labels {
|
|
13
|
+
ddog_prof_Slice_Label labels;
|
|
14
|
+
|
|
15
|
+
// This is used to allow the `Collectors::Stack` to modify the existing label, if any. This MUST be NULL or point
|
|
16
|
+
// somewhere inside the labels slice above.
|
|
17
|
+
ddog_prof_Label *state_label;
|
|
18
|
+
|
|
19
|
+
int64_t end_timestamp_ns;
|
|
20
|
+
} sample_labels;
|
|
21
|
+
|
|
22
|
+
void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations, sample_values values, sample_labels labels);
|
|
13
23
|
void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_CharSlice endpoint);
|
|
14
24
|
VALUE enforce_recorder_instance(VALUE object);
|