Skip to content
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

ApplyServices() in DbContextOptionsBuilder.IsConfigured is problematic for perf #16045

Closed
roji opened this issue Jun 12, 2019 · 1 comment · Fixed by #16118
Closed

ApplyServices() in DbContextOptionsBuilder.IsConfigured is problematic for perf #16045

roji opened this issue Jun 12, 2019 · 1 comment · Fixed by #16118
Labels
area-perf closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-enhancement
Milestone

Comments

@roji
Copy link
Member

roji commented Jun 12, 2019

Commit 188dbf4 changed the DbContextOptionsBuilder.IsConfigured property to call ApplyServices() on all options extensions, in order to fix #13228. Calling TryAdd on all EF services has a significant perf cost.

Discovered as a result of #15173, where ApplyServices() also caused a DiagnosticListener leak.


Here are some benchmark results:

BenchmarkDotNet=v0.11.5, OS=Windows 10.0.17763.437 (1809/October2018Update/Redstone5)
Intel Xeon W-2133 CPU 3.60GHz, 1 CPU, 12 logical and 6 physical cores
.NET Core SDK=2.2.103
[Host] : .NET Core 2.2.4 (CoreCLR 4.6.27521.02, CoreFX 4.6.27521.01), 64bit RyuJIT
DefaultJob : .NET Core 2.2.4 (CoreCLR 4.6.27521.02, CoreFX 4.6.27521.01), 64bit RyuJIT

Current IsConfiguring (with ApplyServices)

Method Mean Error StdDev
Go 257.9 us 0.5106 us 0.4263 us

Previous (light):

Previous IsConfiguring (without ApplyServices)

Method Mean Error StdDev
Go 156.8 us 0.4933 us 0.4373 us

Benchmark code

class Program
{
    static void Main(string[] args) => new BenchmarkSwitcher(typeof(Program).GetTypeInfo().Assembly).Run(args);
}

public class IsConfigured
{
    private static DbContextOptions<BlogContext> _options;

    [GlobalSetup]
    public void Setup()
    {
        var builder = new DbContextOptionsBuilder<BlogContext>();
        builder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Initial Catalog=DiagnosticListenersEverywhere");
        _options = builder.Options;

        using (var ctx = new BlogContext(_options))
        {
            ctx.Database.EnsureDeleted();
            ctx.Database.EnsureCreated();
        }
    }

    [Benchmark]
    public void Go()
    {
        using (var ctx = new BlogContext(_options))
        {
            var entities = ctx.Blogs.ToList();
        }
    }

    public class BlogContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }

        public BlogContext(DbContextOptions<BlogContext> options)
            : base(options)
        {
        }

        protected override void OnConfiguring(DbContextOptionsBuilder options)
        {
            _ = options.IsConfigured;   // Calling the getter triggers the issue
        }
    }

    public class Blog
    {
        [Key]
        public int Id { get; set; }
        public string Title { get; set; }
    }
}
@roji roji added the area-perf label Jun 12, 2019
@roji roji mentioned this issue Jun 12, 2019
@ajcvickers ajcvickers added this to the 3.0.0 milestone Jun 14, 2019
@ajcvickers ajcvickers self-assigned this Jun 14, 2019
@ajcvickers ajcvickers modified the milestones: 3.0.0, Backlog Jun 14, 2019
ajcvickers added a commit that referenced this issue Jun 16, 2019
Also stop calling ApplyServices to find out if an extension is a database provider.

Fixes #16045

Doing this refactoring because we keep having to add/change methods here, so putting them in a composed abstract base class to avoid breaking the interface each time.
@ajcvickers ajcvickers added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Jun 16, 2019
@ajcvickers
Copy link
Contributor

Broke out the breaking change into a separate issue: #16119

ajcvickers added a commit that referenced this issue Jun 17, 2019
Also stop calling ApplyServices to find out if an extension is a database provider.

Fixes #16119
Fixes #16045

Doing this refactoring because we keep having to add/change methods here, so putting them in a composed abstract base class to avoid breaking the interface each time.
ajcvickers added a commit that referenced this issue Jun 17, 2019
Also stop calling ApplyServices to find out if an extension is a database provider.

Fixes #16119
Fixes #16045

Doing this refactoring because we keep having to add/change methods here, so putting them in a composed abstract base class to avoid breaking the interface each time.
@ajcvickers ajcvickers modified the milestones: 3.0.0, 3.0.0-preview7 Jul 2, 2019
@ajcvickers ajcvickers modified the milestones: 3.0.0-preview7, 3.0.0 Nov 11, 2019
@ajcvickers ajcvickers removed their assignment Sep 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-perf closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants