-
Notifications
You must be signed in to change notification settings - Fork 250
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Reduce allocations on GraphQL hot paths #1544
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -282,7 +282,7 @@ def to_span_data | |
end | ||
|
||
# @api private | ||
def initialize(context, parent_context, parent_span, name, kind, parent_span_id, span_limits, span_processors, attributes, links, start_timestamp, resource, instrumentation_scope) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity | ||
def initialize(context, parent_context, parent_span, name, kind, parent_span_id, span_limits, span_processors, attributes, links, start_timestamp, resource, instrumentation_scope) # rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity | ||
super(span_context: context) | ||
@mutex = Mutex.new | ||
@name = name | ||
|
@@ -297,7 +297,7 @@ def initialize(context, parent_context, parent_span, name, kind, parent_span_id, | |
@total_recorded_events = 0 | ||
@total_recorded_links = links&.size || 0 | ||
@total_recorded_attributes = attributes&.size || 0 | ||
@attributes = attributes.nil? ? nil : Hash[attributes] # We need a mutable copy of attributes. | ||
@attributes = attributes | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sometimes, this line was calling an already- I didn't find any other callers to this class -- was that a safe substitution? |
||
trim_span_attributes(@attributes) | ||
@events = nil | ||
@links = trim_links(links, span_limits.link_count_limit, span_limits.link_attribute_count_limit) | ||
|
@@ -317,7 +317,7 @@ def initialize(context, parent_context, parent_span, name, kind, parent_span_id, | |
# SpanData. | ||
@monotonic_start_timestamp = monotonic_now | ||
@realtime_start_timestamp = if parent_span.recording? | ||
relative_realtime(parent_span.realtime_start_timestamp, parent_span.monotonic_start_timestamp) | ||
relative_realtime(parent_span.realtime_start_timestamp, parent_span.monotonic_start_timestamp, @monotonic_start_timestamp) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, every Another use of |
||
else | ||
realtime_now | ||
end | ||
|
@@ -419,15 +419,15 @@ def append_event(events, event) # rubocop:disable Metrics/CyclomaticComplexity, | |
def relative_timestamp(timestamp) | ||
return time_in_nanoseconds(timestamp) unless timestamp.nil? | ||
|
||
relative_realtime(realtime_start_timestamp, monotonic_start_timestamp) | ||
relative_realtime(realtime_start_timestamp, monotonic_start_timestamp, monotonic_now) | ||
end | ||
|
||
def time_in_nanoseconds(timestamp) | ||
(timestamp.to_r * 1_000_000_000).to_i | ||
end | ||
|
||
def relative_realtime(realtime_base, monotonic_base) | ||
realtime_base + (monotonic_now - monotonic_base) | ||
def relative_realtime(realtime_base, monotonic_base, now) | ||
realtime_base + (now - monotonic_base) | ||
end | ||
|
||
def realtime_now | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -141,7 +141,7 @@ def internal_start_span(name, kind, attributes, links, start_timestamp, parent_c | |
if result.recording? && !@stopped | ||
trace_flags = result.sampled? ? OpenTelemetry::Trace::TraceFlags::SAMPLED : OpenTelemetry::Trace::TraceFlags::DEFAULT | ||
context = OpenTelemetry::Trace::SpanContext.new(trace_id: trace_id, span_id: span_id, trace_flags: trace_flags, tracestate: result.tracestate) | ||
attributes = attributes&.merge(result.attributes) || result.attributes | ||
attributes = attributes&.merge(result.attributes) || result.attributes.dup | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Previously, this hash was duped inside |
||
Span.new( | ||
context, | ||
parent_context, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't exactly understand it, but this was the top allocating location in my benchmark. By switching to
each
(presumably, a simpler implementation under the hood?), the allocation was removed:allocated objects by location ----------------------------------- - 1941 /Users/rmosolgo/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/opentelemetry-sdk-1.3.1/lib/opentelemetry/sdk/internal.rb:52 1568 /Users/rmosolgo/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/opentelemetry-sdk-1.3.1/lib/opentelemetry/sdk/trace/tracer_provider.rb:143 803 /Users/rmosolgo/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/graphql-2.1.6/lib/graphql/execution/lazy.rb:21 784 /Users/rmosolgo/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/opentelemetry-api-1.2.3/lib/opentelemetry/context.rb:151 784 /Users/rmosolgo/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/opentelemetry-api-1.2.3/lib/opentelemetry/context.rb:153 784 /Users/rmosolgo/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/opentelemetry-api-1.2.3/lib/opentelemetry/trace.rb:39
Looking at the breakdown by class, I'm guessing that Ruby makes an Array in there, somewhere:
(The difference in Hash allocations is probably best explained by the other part of this PR.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Weirdly, this is failing CI. I'll have to think through the logic, but we're keeping some Event attributes that we should drop.