Reduce allocations when Activity is enabled (#11020)

- Remove string allocations caused by DiagnosticSource.Stop/StartActivity
- Pass the HttpContext directly as the object for StartActivity and StopActivity to avoid the anonymous object allocation.
- Though it's a bit ugly, added an HttpContext property to DefaultHttpContext to avoid breaking back-compat (which had to do reflection to get the HttpContext property anyways)
This commit is contained in:
David Fowler 2019-06-10 13:37:15 -07:00 committed by GitHub
parent c89055b9b0
commit d4a982fefa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 33 additions and 3 deletions

View File

@ -16,7 +16,8 @@ namespace Microsoft.AspNetCore.Hosting.Internal
private static readonly double TimestampToTicks = TimeSpan.TicksPerSecond / (double)Stopwatch.Frequency;
private const string ActivityName = "Microsoft.AspNetCore.Hosting.HttpRequestIn";
private const string ActivityStartKey = "Microsoft.AspNetCore.Hosting.HttpRequestIn.Start";
private const string ActivityStartKey = ActivityName + ".Start";
private const string ActivityStopKey = ActivityName + ".Stop";
private const string DeprecatedDiagnosticsBeginRequestKey = "Microsoft.AspNetCore.Hosting.BeginRequest";
private const string DeprecatedDiagnosticsEndRequestKey = "Microsoft.AspNetCore.Hosting.EndRequest";
@ -278,7 +279,7 @@ namespace Microsoft.AspNetCore.Hosting.Internal
if (_diagnosticListener.IsEnabled(ActivityStartKey))
{
hasDiagnosticListener = true;
_diagnosticListener.StartActivity(activity, new { HttpContext = httpContext });
StartActivity(activity, httpContext);
}
else
{
@ -293,12 +294,32 @@ namespace Microsoft.AspNetCore.Hosting.Internal
{
if (hasDiagnosticListener)
{
_diagnosticListener.StopActivity(activity, new { HttpContext = httpContext });
StopActivity(activity, httpContext);
}
else
{
activity.Stop();
}
}
// These are versions of DiagnosticSource.Start/StopActivity that don't allocate strings per call (see https://github.com/dotnet/corefx/issues/37055)
private Activity StartActivity(Activity activity, HttpContext httpContext)
{
activity.Start();
_diagnosticListener.Write(ActivityStartKey, httpContext);
return activity;
}
private void StopActivity(Activity activity, HttpContext httpContext)
{
// Stop sets the end time if it was unset, but we want it set before we issue the write
// so we do it now.
if (activity.Duration == TimeSpan.Zero)
{
activity.SetEndTime(DateTime.UtcNow);
}
_diagnosticListener.Write(ActivityStopKey, httpContext);
activity.Stop(); // Resets Activity.Current (we want this after the Write)
}
}
}

View File

@ -24,6 +24,8 @@ namespace Microsoft.AspNetCore.Http
public override Microsoft.AspNetCore.Http.ConnectionInfo Connection { get { throw null; } }
public override Microsoft.AspNetCore.Http.Features.IFeatureCollection Features { get { throw null; } }
public Microsoft.AspNetCore.Http.Features.FormOptions FormOptions { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public Microsoft.AspNetCore.Http.HttpContext HttpContext { get { throw null; } }
public override System.Collections.Generic.IDictionary<object, object> Items { get { throw null; } set { } }
public override Microsoft.AspNetCore.Http.HttpRequest Request { get { throw null; } }
public override System.Threading.CancellationToken RequestAborted { get { throw null; } set { } }

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Security.Claims;
using System.Threading;
using Microsoft.AspNetCore.Http.Features;
@ -157,6 +158,12 @@ namespace Microsoft.AspNetCore.Http
}
}
// This property exists because of backwards compatibility.
// We send an anonymous object with an HttpContext property
// via DiagnosticSource in various events throughout the pipeline. Instead
// we just send the HttpContext to avoid extra allocations
[EditorBrowsable(EditorBrowsableState.Never)]
public HttpContext HttpContext => this;
public override void Abort()
{