Skip to content

Commit e1dd873

Browse files
authored
Merge pull request #4460 from DataDog/ivoanjo/prof-11394-heap-profiling-graduate-try2
[PROF-11405] Graduate heap profiling from alpha to preview, second try
2 parents 62a9e03 + 749b2f0 commit e1dd873

File tree

18 files changed

+537
-548
lines changed

18 files changed

+537
-548
lines changed

Rakefile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -453,13 +453,13 @@ namespace :changelog do
453453
end
454454

455455
NATIVE_EXTS = [
456+
Rake::ExtensionTask.new("libdatadog_api.#{RUBY_VERSION[/\d+.\d+/]}_#{RUBY_PLATFORM}") do |ext|
457+
ext.ext_dir = 'ext/libdatadog_api'
458+
end,
459+
456460
Rake::ExtensionTask.new("datadog_profiling_native_extension.#{RUBY_VERSION}_#{RUBY_PLATFORM}") do |ext|
457461
ext.ext_dir = 'ext/datadog_profiling_native_extension'
458462
end,
459-
460-
Rake::ExtensionTask.new("libdatadog_api.#{RUBY_VERSION[/\d+.\d+/]}_#{RUBY_PLATFORM}") do |ext|
461-
ext.ext_dir = 'ext/libdatadog_api'
462-
end
463463
].freeze
464464

465465
NATIVE_CLEAN = ::Rake::FileList[]

benchmarks/README.md

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,16 @@
44

55
1. Use one of the following prefixes:
66

7-
- `library_`
8-
- `profiling_`
9-
- `tracing_`
10-
- `di_`
11-
- `error_tracking_`
7+
- `library_` (spec in `spec/validate_benchmarks_spec.rb`)
8+
- `profiling_` (spec in `./spec/datadog/profiling/validate_benchmarks_spec.rb`)
9+
- `tracing_` (spec in `./spec/datadog/tracing/validate_benchmarks_spec.rb`)
10+
- `di_` (spec in `./spec/datadog/di/validate_benchmarks_spec.rb`)
11+
- `error_tracking` (spec in `./spec/datadog/error_tracing/validate_benchmarks_spec.rb`)
1212

1313
2. Add the new file to `run_all.sh` in this directory.
1414

1515
3. Depending on the prefix, add the new file to the correct
16-
`validate_benchmarks_spec.rb` as follows:
17-
18-
- `library_` prefix: `spec/validate_benchmarks_spec.rb`
19-
- `profiling_` prefix: `./spec/datadog/profiling/validate_benchmarks_spec.rb`
20-
- `tracing_` prefix: `./spec/datadog/tracing/validate_benchmarks_spec.rb`
21-
- `di_` prefix: `./spec/datadog/di/validate_benchmarks_spec.rb`
22-
- `error_tracking_` prefix: `./spec/datadog/error_tracing/validate_benchmarks_spec.rb`
16+
`validate_benchmarks_spec.rb` as listed above
2317

2418
## Adding Benchmarks For a New Product
2519

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Used to quickly run benchmark under RSpec as part of the usual test suite, to validate it didn't bitrot
2+
VALIDATE_BENCHMARK_MODE = ENV['VALIDATE_BENCHMARK'] == 'true'
3+
4+
return unless __FILE__ == $PROGRAM_NAME || VALIDATE_BENCHMARK_MODE
5+
6+
require_relative 'benchmarks_helper'
7+
8+
# This benchmark measures the performance of string storage-related APIs
9+
10+
# Temporary hack to make CI happy. Our CI tries to compare benchmarks between master and branches, and if benchmarks
11+
# are not backwards-compatible between them (e.g. a new API was added...) it breaks. As a workaround, I'm disabling this
12+
# benchmark so we can merge it to master, and then I'll follow up with a micro-PR to re-enable it.
13+
TEMPORARY_DISABLE_BENCHMARK = true
14+
15+
class ProfilerStringStorageIntern
16+
def initialize
17+
@recorder = Datadog::Profiling::StackRecorder.for_testing(heap_samples_enabled: true)
18+
end
19+
20+
def run_benchmark
21+
Benchmark.ips do |x|
22+
benchmark_time = VALIDATE_BENCHMARK_MODE ? { time: 0.01, warmup: 0 } : { time: 10, warmup: 2 }
23+
x.config(
24+
**benchmark_time,
25+
)
26+
x.report('intern_all 1000 repeated strings') do
27+
Datadog::Profiling::StackRecorder::Testing._native_benchmark_intern(@recorder, "hello, world!", 1000, true) unless TEMPORARY_DISABLE_BENCHMARK
28+
end
29+
30+
x.save! "#{File.basename(__FILE__)}-1-results.json" unless VALIDATE_BENCHMARK_MODE
31+
x.compare!
32+
end
33+
34+
Benchmark.ips do |x|
35+
benchmark_time = VALIDATE_BENCHMARK_MODE ? { time: 0.01, warmup: 0 } : { time: 10, warmup: 2 }
36+
x.config(
37+
**benchmark_time,
38+
)
39+
40+
x.report('intern mixed existing and new') do
41+
recorder = Datadog::Profiling::StackRecorder.for_testing(heap_samples_enabled: true)
42+
43+
strings_to_intern = 100_000
44+
existing_strings = (strings_to_intern * 0.9).to_i
45+
new_strings = strings_to_intern - existing_strings
46+
47+
new_strings.times do |i|
48+
Datadog::Profiling::StackRecorder::Testing._native_benchmark_intern(recorder, ("%010d" % i), 1, false) unless TEMPORARY_DISABLE_BENCHMARK
49+
end
50+
51+
existing_strings.times do |i|
52+
Datadog::Profiling::StackRecorder::Testing._native_benchmark_intern(recorder, "hello, world!", 1, false) unless TEMPORARY_DISABLE_BENCHMARK
53+
end
54+
end
55+
56+
x.save! "#{File.basename(__FILE__)}-2-results.json" unless VALIDATE_BENCHMARK_MODE
57+
x.compare!
58+
end
59+
end
60+
end
61+
62+
puts "Current pid is #{Process.pid}"
63+
64+
ProfilerStringStorageIntern.new.instance_exec do
65+
run_benchmark
66+
end

benchmarks/run_all.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ for file in \
1818
`dirname "$0"`/profiling_sample_loop_v2.rb \
1919
`dirname "$0"`/profiling_sample_serialize.rb \
2020
`dirname "$0"`/profiling_sample_gvl.rb \
21+
`dirname "$0"`/profiling_string_storage_intern.rb \
2122
`dirname "$0"`/tracing_trace.rb;
2223
do
2324
bundle exec ruby "$file"

ext/datadog_profiling_native_extension/collectors_thread_context.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,7 @@ static per_thread_context *get_or_create_context_for(VALUE thread, thread_contex
10231023
if (st_lookup(state->hash_map_per_thread_context, (st_data_t) thread, &value_context)) {
10241024
thread_context = (per_thread_context*) value_context;
10251025
} else {
1026-
thread_context = ruby_xcalloc(1, sizeof(per_thread_context));
1026+
thread_context = calloc(1, sizeof(per_thread_context)); // See "note on calloc vs ruby_xcalloc use" in heap_recorder.c
10271027
initialize_context(thread, thread_context, state);
10281028
st_insert(state->hash_map_per_thread_context, (st_data_t) thread, (st_data_t) thread_context);
10291029
}
@@ -1122,7 +1122,7 @@ static void initialize_context(VALUE thread, per_thread_context *thread_context,
11221122

11231123
static void free_context(per_thread_context* thread_context) {
11241124
sampling_buffer_free(thread_context->sampling_buffer);
1125-
ruby_xfree(thread_context);
1125+
free(thread_context); // See "note on calloc vs ruby_xcalloc use" in heap_recorder.c
11261126
}
11271127

11281128
static VALUE _native_inspect(DDTRACE_UNUSED VALUE _self, VALUE collector_instance) {

0 commit comments

Comments
 (0)