Skip to content
This repository was archived by the owner on Dec 19, 2018. It is now read-only.

[Perf] High Allocator LoggingScope when no loggers #367

Closed
benaadams opened this issue Sep 21, 2015 · 11 comments
Closed

[Perf] High Allocator LoggingScope when no loggers #367

benaadams opened this issue Sep 21, 2015 · 11 comments

Comments

@benaadams
Copy link
Contributor

Using works with null references, so this is simpler than outlined below; added change to logging to improve efficiency.


Creating a scope is expensive (at benchmarking speeds) and the techempower benchmarks specify in general requirements item 2:

All test implementations must disable all disk logging. For many reasons, we expect all tests will run without writing logs to disk. Most importantly, the volume of requests is sufficiently high to fill up disks even with only a single line written to disk per request. Please disable all forms of disk logging. We recommend but do not require disabling console logging as well.

For fair comparison, only create the logging scope if logging is enabled:

Add LogLevel of None = 7?

Change the following from:

var logger = _applicationServices.GetRequiredService<ILogger<HostingEngine>>();
...
var server = ServerFactory.Start(_serverInstance,
    async features =>
    {
        try
        {
            using (logger.BeginScope("Request Id: {RequestId}", requestIdentifier))
            {
                contextAccessor.HttpContext = httpContext;
                await application(httpContext);
            }
        }
        catch (Exception ex)
        {
            if (telemetrySource.IsEnabled("Microsoft.AspNet.Hosting.UnhandledException"))
            {
                telemetrySource.WriteTelemetry("Microsoft.AspNet.Hosting.UnhandledException", new { httpContext = httpContext, exception = ex });
            }

            throw;
        }

To something similar to:

var logger = _applicationServices.GetRequiredService<ILogger<HostingEngine>>();
...
var isLogging = logger.IsEnabled(LogLevel.Critical); // ? not sure about how not logging is checked
var server = ServerFactory.Start(_serverInstance,
    async features =>
    {
        ILogger loggerScope;
        try
        {
            if (isLogging) 
            {
                loggerScope = logger.BeginScope("Request Id: {RequestId}", requestIdentifier);
            }

            contextAccessor.HttpContext = httpContext;
            await application(httpContext);
        }
        catch (Exception ex)
        {
            if (telemetrySource.IsEnabled("Microsoft.AspNet.Hosting.UnhandledException"))
            {
                telemetrySource.WriteTelemetry("Microsoft.AspNet.Hosting.UnhandledException", new { httpContext = httpContext, exception = ex });
            }

            throw;
        }
        finally
        {
            if (loggerScope != null) loggerScope.Dispose();
        }

Ensure having no local logging scope doesn't cause issues.

@benaadams
Copy link
Contributor Author

For reference 437 kBytes for 4k requests; or 672 Mbytes/s for 6M rps.
40 GBytes/min for the GC to clean up:

logging scope

@benaadams
Copy link
Contributor Author

Would be partially resolved by aspnet/Logging#254

Before Allocations 12000 per 4k

pre-allocs

Before Bytes 448kB per 4k

pre-bytes

After Allocations 8000 per 4k

post-allocs

After Bytes 256kB per 4k

post-bytes

@benaadams
Copy link
Contributor Author

Taking it a little further and changing

using (logger.BeginScope("Request Id: {RequestId}", requestIdentifier))

to

using (logger.IsEnabled(LogLevel.Critical) 
    ? logger.BeginScope("Request Id: {RequestId}", requestIdentifier) 
    : null)

With this change reduces it to zero allocations

post-allocs

And zero bytes

post-bytes

@davidfowl davidfowl self-assigned this Sep 30, 2015
@davidfowl davidfowl added this to the 1.0.0-rc1 milestone Sep 30, 2015
@benaadams benaadams changed the title [Design] Make logging scope dependent on if logging is enabled [Perf] High Allocator LoggingScope when no loggers Oct 25, 2015
@benaadams
Copy link
Contributor Author

@davidfowl please reopen; commit Reduce logging overhead in hosting has brought this back but with even higher byte allocation.

For 2003 requests

Drill down on Issue aspnet/KestrelHttpServer#288
Measurements post PR aspnet/KestrelHttpServer#287

Allocations (Same as previous)

hc-new

Bytes (256kB per 4k -> 352kB per 4k; up 96kB)

hc-new

@davidfowl davidfowl reopened this Oct 25, 2015
@davidfowl
Copy link
Member

/cc @lodejard

@lodejard
Copy link
Contributor

Too many cross-references, history, and screen shots! :) I can't tell how much of this is from before the current changes, or what the recommendation is.

Can we discuss this in a more direct way?

@davidfowl
Copy link
Member

@benaadams @lodejard this still relevant? If so reopen

@davidfowl davidfowl removed their assignment Feb 19, 2016
@davidfowl davidfowl removed this from the 1.0.0-rc2 milestone Feb 19, 2016
@benaadams
Copy link
Contributor Author

Still features (just under highlighted line)

After-QueueUserWorkItemCallback

Don't know how urgent it is

@benaadams
Copy link
Contributor Author

Also other than string and QUWICDC is the only thing on that list that can't be pooled (am guessing RequestServicesFeature can be optionally removed)

@davidfowl
Copy link
Member

@benaadams what are those strings?

@benaadams
Copy link
Contributor Author

Header, host, path values - is what I did the StringCache for back in the day aspnet/KestrelHttpServer#411 (comment)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants