-
Notifications
You must be signed in to change notification settings - Fork 5k
Ensure Http Telemetry correctness #40338
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
Conversation
Tagging subscribers to this area: @dotnet/ncl |
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs
Outdated
Show resolved
Hide resolved
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.
LGTM, needs look someone familiar with telemetry
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.
Instead, this PR removes an optimization for HttpConnectionPool where we avoid using a finalizer if maxConnections is int.MaxValue. With this change, we always use a finalizable HttpConnectionPool.
To my knowledge, unlimited number of HTTP 1.1 connections is the most common case, thus I'm concerned with this change will decrease performance for the most of the users.
It will reduce perf, but not by much. A quick benchmark of the overhead of having a suppressed finalizer yields:
We are talking about a difference in the area of ~50 ns per HttpConnection. I don't think this is a significant performance hit in the context of creating connections. For comparison, every Do you have a suggestion for an alternative approach that would avoid the finalizer overhead? |
internal void MarkAsTrackedByTelemetry() | ||
{ | ||
Debug.Assert(_sendStatus != MessageShouldEmitTelemetry); | ||
_sendStatus = MessageShouldEmitTelemetry; |
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.
Isn't this going to overwrite the MessageAlreadySent set as part of MarkAsSent?
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.
Oh, I see, you consider both MessageAlreadySent and MessageShouldEmitTelemetry to mean already sent. That naming is strange to me.
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.
Would
private const int MessageNotYetSent = 0;
private const int MessageAlreadySent = 1;
-private const int MessageShouldEmitTelemetry = 2;
+private const int MessageAlreadySent_StopNotYetCalled = 2;
be more clear?
|
||
internal void OnStopped(bool aborted = false) | ||
{ | ||
if (_sendStatus == MessageShouldEmitTelemetry && Interlocked.Exchange(ref _sendStatus, MessageAlreadySent) == MessageShouldEmitTelemetry) |
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.
Why is this exchange necessary?
src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestMessage.cs
Outdated
Show resolved
Hide resolved
cc: @geoffkizer |
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.
Ok, if it's really 50 ns per connection, that's fine. Let's proceed with this PR after all other comments were resolved.
Ok, if it's really 50 ns per connection, that's fine. Let's proceed with this PR after all other comments were resolved.
/azp run runtime-libraries outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run runtime-libraries outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
e7f0589
to
902a13d
Compare
/azp run runtime-libraries outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run runtime-libraries outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run runtime-libraries outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
The Http Telemetry implementation from #37619 has a few problems:
This PR solves these issues by keeping the telemetry state on the HttpRequestMessage object.
This way we only call Stop if we called Start.
This PR is an alternative fix over #38876, avoiding using a new finalizable object to track each request when Telemetry is enabled.
Instead, this PR removes an optimization for
HttpConnection
where we avoid using a finalizer if maxConnections isint.MaxValue
. With this change, we always use a finalizableHttpConnection
.Contributes to #37428
Note: It might seem that the PR is removing calls to Telemetry - it is moving those calls that were always before a CompleteResponse/Dispose to those methods instead.