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

ChildSyntaxList.ItemInternal optimization #73650

Merged

Conversation

ToddGrun
Copy link
Contributor

@ToddGrun ToddGrun commented May 22, 2024

ChildSyntaxList.ItemInternal has shown up in many profiles that I've looked at. I finally dug in a bit to it, and think I've identified a potential optimization opportunity.

This optimization takes advantage that the first loop was previously always iterating through all the slots until it had found index items. However, as this method is commonly called from inside the ChildSyntaxList.Enumerator, it can use knowledge from previous calls to start that first loop at a more appropriate location.

Running the benchmark.net tests in the PR yield the following output. Essentially, the tree walk is ~10% faster while the line walk is much closer to 50% faster (depending on the file size)

*** without changes ***
Run1:

Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
WalkLines_Small 2.792 ms 0.0100 ms 0.0089 ms 39.0625 - - 408 KB
WalkLines_Medium 49.311 ms 0.0907 ms 0.0758 ms 272.7273 - - 3,115 KB
WalkLines_Large 1,962.582 ms 4.9003 ms 4.3440 ms 4000.0000 - - 49,784 KB
WalkTree_Small 48.747 ms 0.0986 ms 0.0874 ms - - - 259 KB
WalkTree_Medium 330.527 ms 0.8990 ms 0.7507 ms - - - 466 KB
WalkTree_Large 4,046.432 ms 10.3293 ms 8.6254 ms - - - 3,155 KB
WalkClassifications_Small 2.273 ms 0.0052 ms 0.0047 ms - - - 47 B
WalkClassifications_Medium 37.415 ms 0.0288 ms 0.0256 ms - - - 15,257 B
WalkClassifications_Large 1,233.854 ms 2.7014 ms 2.5269 ms - - - 2,967,000 B

Run2:

Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
WalkLines_Small 2.799 ms 0.0157 ms 0.0146 ms 39.0625 - - 408 KB
WalkLines_Medium 45.714 ms 0.0579 ms 0.0484 ms 272.7273 - - 3,115 KB
WalkLines_Large 1,914.537 ms 2.2995 ms 2.0384 ms 4000.0000 - - 49,784 KB
WalkTree_Small 48.578 ms 0.0511 ms 0.0478 ms - - - 259 KB
WalkTree_Medium 341.976 ms 0.5460 ms 0.4840 ms - - - 466 KB
WalkTree_Large 3,846.922 ms 19.6948 ms 17.4589 ms - - - 3,155 KB
WalkClassifications_Small 2.231 ms 0.0076 ms 0.0068 ms - - - 47 B
WalkClassifications_Medium 37.379 ms 0.0805 ms 0.0672 ms - - - 15,257 B
WalkClassifications_Large 1,113.740 ms 2.1410 ms 1.7879 ms - - - 2,967,000 B

*** with changes ***
Run 1:

Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
WalkLines_Small 1.826 ms 0.0065 ms 0.0061 ms 39.0625 - - 408 KB
WalkLines_Medium 21.893 ms 0.0929 ms 0.0776 ms 281.2500 - - 3,103 KB
WalkLines_Large 629.993 ms 4.4575 ms 3.9515 ms 4000.0000 - - 49,784 KB
WalkTree_Small 46.546 ms 0.2303 ms 0.2154 ms - - - 259 KB
WalkTree_Medium 322.603 ms 0.7319 ms 0.6847 ms - - - 466 KB
WalkTree_Large 3,734.326 ms 9.9091 ms 9.2690 ms - - - 3,155 KB
WalkClassifications_Small 1.569 ms 0.0046 ms 0.0043 ms - - - 24 B
WalkClassifications_Medium 19.329 ms 0.0631 ms 0.0590 ms - - - 6,675 B
WalkClassifications_Large 459.593 ms 2.4224 ms 2.1474 ms - - - 2,967,000 B

Run2:

Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
WalkLines_Small 1.793 ms 0.0093 ms 0.0087 ms 39.0625 - - 408 KB
WalkLines_Medium 22.862 ms 0.4528 ms 0.5032 ms 281.2500 - - 3,103 KB
WalkLines_Large 690.992 ms 2.0962 ms 1.7504 ms 4000.0000 - - 49,784 KB
WalkTree_Small 45.063 ms 0.1223 ms 0.1144 ms - - - 259 KB
WalkTree_Medium 320.729 ms 0.9224 ms 0.8177 ms - - - 466 KB
WalkTree_Large 3,864.808 ms 20.0134 ms 18.7205 ms - - - 3,155 KB
WalkClassifications_Small 1.569 ms 0.0088 ms 0.0082 ms - - - 24 B
WalkClassifications_Medium 19.573 ms 0.0679 ms 0.0635 ms - - - 6,675 B
WalkClassifications_Large 458.431 ms 2.5393 ms 2.3752 ms - - - 2,967,000 B

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels May 22, 2024
@ToddGrun ToddGrun changed the title WIP: ChildSyntaxListlist.ItemInternal optimization WIP: ChildSyntaxList.ItemInternal optimization May 22, 2024
@ToddGrun ToddGrun marked this pull request as ready for review May 23, 2024 01:03
@ToddGrun ToddGrun requested review from a team as code owners May 23, 2024 01:04
@ToddGrun ToddGrun requested a review from jaredpar May 23, 2024 01:04
@ToddGrun
Copy link
Contributor Author

@jaredpar -- Who would be appropriate compiler reviewers?

@ToddGrun ToddGrun changed the title WIP: ChildSyntaxList.ItemInternal optimization ChildSyntaxList.ItemInternal optimization May 23, 2024
@CyrusNajmabadi
Copy link
Member

For context, the "line walk" simulates how 'syntactic classification' works, where the editor calls into us to classify lines in view (including as the view is scrolled).

So we get N calls to classify certain subspans of the document, and each of those N calls needs to walk the tree to find the tokens intersecting that subspan. Improvements to the tree-walk make a big difference. Here, it's about 66% better (from 1,962.582ms to 629.993ms). This is because to walk the tree, we're constantly hitting nodes and doing .ChildNodesAndTokens on it. Speeding that up from N^2 to linear for each node we hit makes a significant difference.

We were looking at this because we were seeing expenses in Roslyn in classification/scrolling higher than what we wanted. This alone drops our current syntactic classification time by about 50%.

@CyrusNajmabadi
Copy link
Member

Note; while classification was the core scenario we cared about (as it is such a hot spot), this shows up everywhere, since we're constantly walking trees. Everything benefits form this :)

@CyrusNajmabadi
Copy link
Member

CyrusNajmabadi commented May 23, 2024

With my tests, i get this speedup on the walking algorithm that classification uses:

before:

|  WalkClassification_Large | 1,119.638 ms | 2.8996 ms | 2.7122 ms |         - |         - |     - |  1,490,944 B |

After

|  WalkClassification_Large | 572.202 ms | 2.7666 ms | 2.4525 ms |         - |         - |     - |  1,490,944 B |

So basically 50% faster.

Also, the classification walk is much better than .DescendantTokens wrt to memory:

|           WalkLines_Large | 941.099 ms | 3.0237 ms | 2.8284 ms | 6000.0000 | 6000.0000 |     - | 31,531,432 B |
|  WalkClassification_Large | 572.202 ms | 2.7666 ms | 2.4525 ms |         - |         - |     - |  1,490,944 B |

That's 20x less memory. And nothing in gen0//gen1.

@ToddGrun
Copy link
Contributor Author

Refresh my memory, it was pretty invasive to try and get the DescendantTokens code to have an allocation profile similar to the manual walk done in WalkClassification, right?


In reply to: 2126281448

@CyrusNajmabadi
Copy link
Member

Refresh my memory, it was pretty invasive to try and get the DescendantTokens code to have an allocation profile similar to the manual walk done in WalkClassification, right?

I think it wouldn't be too hard to do. we'd want to potentially invest in some dedicated tests to ensure the same behavior as before (esp. around empty length tokens).

@jaredpar
Copy link
Member

@cston, @333fred and @jjonescz should take a look. But note we are bogged down right now in functional issues.

@ToddGrun
Copy link
Contributor Author

ToddGrun commented Jun 3, 2024

@333fred or @jjonescz for 2nd review

@ToddGrun
Copy link
Contributor Author

ToddGrun commented Jun 5, 2024

ping @333fred or @jjonescz for 2nd review

@ToddGrun
Copy link
Contributor Author

ToddGrun commented Jun 6, 2024

@dotnet/roslyn-compiler -- ptal, need 2nd review

1 similar comment
@ToddGrun
Copy link
Contributor Author

ToddGrun commented Jun 7, 2024

@dotnet/roslyn-compiler -- ptal, need 2nd review

@ToddGrun
Copy link
Contributor Author

Please @333fred or @jjonescz for 2nd review

@ToddGrun
Copy link
Contributor Author

/azp run

Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@jjonescz
Copy link
Member

@dotnet-policy-service rerun

@ToddGrun ToddGrun merged commit 0b83719 into dotnet:main Jun 13, 2024
27 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Jun 13, 2024
@ToddGrun ToddGrun deleted the dev/toddgrun/SyntaxListItemInternalOptimization branch June 19, 2024 16:19
@jjonescz jjonescz modified the milestones: Next, 17.11 P3 Jun 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants