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

Perf bottleneck because of SortedDictionary in Annotatable.FindAnnotation #25488

Closed
Tracked by #22952
roji opened this issue Aug 11, 2021 · 6 comments
Closed
Tracked by #22952

Perf bottleneck because of SortedDictionary in Annotatable.FindAnnotation #25488

roji opened this issue Aug 11, 2021 · 6 comments
Labels
area-model-building area-perf closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. punted-for-7.0 Originally planned for the EF Core 7.0 (EF7) release, but moved out due to resource constraints. type-enhancement
Milestone

Comments

@roji
Copy link
Member

roji commented Aug 11, 2021

The following was reported offline by @feng-yuan (thanks!)

Found an expensive EF stack:

stacktrace

GetValueComparer is costing 139 k CPU samples, 6% in this hot stream, mostly due to SortedDictionary lookup in Annotable.FindAnnotation.

We know sorted dictionary is slower than dictionary because its lookup is O(Ln(N)), but there is something more to make the code slower, or even incorrect here.

protected virtual Annotation SetAnnotation([NotNull] string name, [NotNull] Annotation annotation, [CanBeNull] Annotation oldAnnotation)
{
    if (this._annotations == null)
    {
        this._annotations = new SortedDictionary<string, Annotation>();
    }
    this._annotations[name] = annotation;
    return this.OnAnnotationSet(name, annotation, oldAnnotation);
}

SortedDictionary<string, Annotation> is allocated with default constructor. So the comparer is using String.Compare which is using current culture. Here is the evidence:

stacktrace2

String.CompareTo is on the right. Zoom-in:

stacktrace3

So lookup is now dependent on current thread culture.

At least, you need to change the code to :

if (this._annotations == null)
{
    this._annotations = new SortedDictionary<string, Annotation>(StringComparer.Ordinal);
}

If order is not important, Dictionary<string, Annotation> would be even faster and smaller.

@roji
Copy link
Member Author

roji commented Aug 11, 2021

Split off the (possible) correctness issue to #25489 (use ordinal comparison)

@ajcvickers ajcvickers added this to the Backlog milestone Aug 12, 2021
@AndriySvyryd
Copy link
Member

In 6.0.0 we introduced the optimized runtime model and RuntimeProperty.GetValueComparer() doesn't look for an annotation, as it's now stored in a field. So this bottleneck should be gone.

@roji roji added the verify-fixed This issue is likely fixed in new query pipeline. label Aug 13, 2021
@roji
Copy link
Member Author

roji commented Aug 13, 2021

Great, have added verified-fixed to make sure.

@roji
Copy link
Member Author

roji commented Sep 6, 2021

Profiling the repro application in #20135 shows that almost 30% of the model building time is spent doing SortedDictionary.TryGetValue inside Annotatable.FindAnnotation... We may still want to revisit this even if it no longer impacts runtime (and even if we have compiled models).

(but confirm first that runtime isn't impacted)

@roji roji added area-model-building and removed verify-fixed This issue is likely fixed in new query pipeline. labels Sep 6, 2021
@AndriySvyryd
Copy link
Member

Since GetAnnotations isn't used frequently we could sort on demand and use Hashtable/Dictionary<string, Annotation>

@ajcvickers ajcvickers modified the milestones: Backlog, 7.0.0 Oct 27, 2021
@ajcvickers ajcvickers added propose-punt punted-for-7.0 Originally planned for the EF Core 7.0 (EF7) release, but moved out due to resource constraints. and removed propose-punt labels Jul 6, 2022
@ajcvickers ajcvickers modified the milestones: 7.0.0, Backlog Jul 7, 2022
@AndriySvyryd
Copy link
Member

Done in d8e9f61

@AndriySvyryd AndriySvyryd added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Feb 10, 2024
@AndriySvyryd AndriySvyryd modified the milestones: Backlog, 9.0.0, 9.0.0-preview1 Feb 10, 2024
@AndriySvyryd AndriySvyryd removed their assignment Mar 15, 2024
@roji roji modified the milestones: 9.0.0-preview1, 9.0.0 Oct 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-model-building area-perf closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. punted-for-7.0 Originally planned for the EF Core 7.0 (EF7) release, but moved out due to resource constraints. type-enhancement
Projects
None yet
Development

No branches or pull requests

3 participants