-
Notifications
You must be signed in to change notification settings - Fork 382
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
Improve performance with better CommandInfo cache locking making Invoke-ScriptAnalyzer nearly twice as fast #1162
Improve performance with better CommandInfo cache locking making Invoke-ScriptAnalyzer nearly twice as fast #1162
Conversation
The principle at work here seems not unlike that I wrote for the profile cache (which had to optimise for concurrent callers wanting optimum parallel execution): Lines 108 to 130 in dff9522
I think we could easily avoid the duplicated work in (2) with lazy task entries -- it would probably also decrease the amount of logic you've had to write here. If you'd prefer, I could also give this a shot myself. |
Hmm, I think our 2 scenarios are still a bit different. I for example have 2 concurrent dictionaries, one is for the results and one is a way of managing and retrieving currently running requests. This is to keep the memory usage minimal and release allocations of finished tasks because my result dictionary will potentially hold thousands of objects. I don't see how Lazy would be useful in my case. Also, I am not async yet (this would be another PR using runspaces). |
I'll look into it and see what I come up with |
I had a look and talked about it a bit with @daxian-dbw, who made the point that if we want the result immediately, there may not be a good reason to use a I just wrote a simple implementation around more granular locks in #1166, which seems to get the same performance (compared both modules with current |
I also did some experimentation with async, since the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
very nice - I wonder if there's a way that we can target tests at this (I couldn't immediately think of anything)? It also makes me think that we really need some performance benchmarking (a much longer-term thing). Should we have some sort of xunit tests as we have in PowerShell?
do we have a clear favorite between this and #1166 @rjmholt?
Rob's version is a bit better performance wise but before his version gets merged we'd have to revert 1 small change as per my comment to preserve legacy behaviour |
PR Summary
This nearly halves the execution time (measured using PS 5.1 and 6.2). For example when recursively analyzing the
test
folder of the PowerShell repo, the time goes down from 170 seconds to 100 seconds. When analysing thebuild.psm1
module of the PowerShell repo (clean, fresh, shell), then the time went down from 11 seconds to 7 seconds.Background: The bottleneck of PSSA's performance are the
CommandInfo
lookups (where basicallyGet-Command
gets called), not just because they are expensive but even when results are cached, there was was 1 heavy lock (all PSSA rules are executing in parallel threads and access the SingletonHelper
class) around the 3 following operations:Get-Command
to get details. This is the most expensive partThis PR improves it by:
ConcurrentDictionary
for the Cache instead to avoid the heavy lock. This means effectively that step 1 is only under a read lock and step 3 under a write lock.Get-Command
request, therefore resulting in unnecessary CPU churn and potentially slowing down execution. To counteract this, step 2 now submits its requests as aTask
to another ConcurrentDictionary so that one can check if there is already a request for a particular command, get that task and wait for its result.outputwriter
field on theHelper
class is not used and therefore removed. Some other members could be madereadonly
In the future we might enhance it further to
PR Checklist
.cs
,.ps1
and.psm1
files have the correct copyright headerWIP:
to the beginning of the title and remove the prefix when the PR is ready.