PowerShell / PSScriptAnalyzer

Download ScriptAnalyzer from PowerShellGallery
https://www.powershellgallery.com/packages/PSScriptAnalyzer/
MIT License
1.87k stars 378 forks source link

Improve compatibility profile performance and make profiles a part of central configuration #1484

Open rjmholt opened 4 years ago

rjmholt commented 4 years ago

Compatibility profiles are currently very slow to start up and use opaque and duplicated configurations across rules.

Instead:

iRon7 commented 1 year ago

We are using PSScriptAnalyzer in our GitLab street and currently experiencing the issue described here:

After opening a new PowerShell session, the initial Invoke-ScriptAnalyzer with the following settings takes more than 15 secondes:

Measure-Command {
    Invoke-ScriptAnalyzer -Path .\Test.ps1 -Settings @{
        Rules = @{
            PSUseCompatibleCommands = @{
                Enable = $true
                TargetProfiles = @(
                    'win-8_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework',
                    'win-8_x64_10.0.17763.0_7.0.0_x64_3.1.2_core'
                )
            }
            PSUseCompatibleSyntax = @{
                Enable = $true
                TargetVersions = @(
                    '5.1',
                    '7.0'
                )
            }
        }
    }
}

Any successive invocation takes less than .5 seconds. Is there any way to workaround this issue?

PSScriptAnalyzer version: 1.20 PowerShell version table (it also happens on PowerShell 7):

Name                           Value
----                           -----
PSVersion                      5.1.19041.2673
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.19041.2673
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
rjmholt commented 1 year ago

Is there any way to workaround this issue?

The performance issues here occur because the profiles are stored in very large JSON files, which are parsed using reflection with Newtonsoft code. There's probably also some large object heap involvement too. Those files have to be loaded up on cold start, and even parsing them lazily doesn't avoid the huge memory consumption that probably drives much of the performance issues.

A workaround might be to amortise cold starts by turning this into a service shared across CI workers.

An interim solution would be to change out the JSON parsing code to use pre-generated stream parsing, probably using Microsoft's JSON parsing library.

The best solution would be to convert the compatibility profiles into a Sqlite DB and ship PSSA with bindings for that

iRon7 commented 1 year ago

@rjmholt,

A workaround might be to amortise cold starts by turning this into a service shared across CI workers.

Thank you for the feedback. Unfortunately, this is quiet hard for us to implement. Anyways, as we actually only using the script analyzer to automatically generate issues/emails on a commit and do not preventing it from still building a merge request, we now have script analyzer completely asynchrone with the rest.

From the reply from @bergmeister

I don't think so although I cannot speak for PS team. Your referenced issue is isolated to the workings of compatibility rules and not related to PSSA rewrite

Does that mean that I actually should create a separate issue for this?

rjmholt commented 1 year ago

Unfortunately, this is quiet hard for us to implement.

Yeah PSSA as a service is just something I suggest if no changes will be made to the compatibility rules. I suspect it would be easier to implement than rewriting the compatibility rules yourself.

I no longer work at Microsoft so I don't know what the plans or processes are beyond what you know already, but I don't imagine a separate issue would help here

Glober777 commented 10 months ago

I'm also observing a performance issue which is related to the cold start. In my case, every time I run the tests, they start in a fresh PS Session, so I'm always hitting the fresh start penalty. Usually, the delay out of initialization is longer than all the PSSA related tests. It would be great, if there was a way to trigger the cold start process in the very beginning (i.e. before all the other tests and prep tasks) so that it would run asynchronously (i.e. in a separate thread or runspace) and by the time my script gets to running PSSA tests, those large JSONs should already be loaded, i.e.:

1. Initialize-PSSA (starts init task in the background and returns back the prompt on the main thread)
2. Prepare the folder for the tests (cleanup artifacts folder, check dependencies and update if needed, etc.)
3. Start all the other Tests (leaving PSSA tests to the end)
4. Wait-PSSAInit (a cmdlet that would hold the main thread until the PSSA is fully initialized)
5. Run PSSA Tests
... other steps ...