Skip to content

Commit 039c700

Browse files
authored
Merge pull request #1178 from bergmeister/Performance_RunspacePool_AndSpeedupAvoidAlias
Speedup cold runs of PSSA by using a runspace pool and parallelizing the slowest rule (AvoidAlias)
2 parents 9d19209 + 29d99cb commit 039c700

File tree

2 files changed

+18
-7
lines changed

2 files changed

+18
-7
lines changed

Engine/CommandInfoCache.cs

+7-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Collections.Concurrent;
66
using System.Management.Automation;
77
using System.Linq;
8+
using System.Management.Automation.Runspaces;
89

910
namespace Microsoft.Windows.PowerShell.ScriptAnalyzer
1011
{
@@ -14,16 +15,17 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer
1415
internal class CommandInfoCache
1516
{
1617
private readonly ConcurrentDictionary<CommandLookupKey, Lazy<CommandInfo>> _commandInfoCache;
17-
1818
private readonly Helper _helperInstance;
19+
private readonly RunspacePool _runspacePool;
1920

2021
/// <summary>
2122
/// Create a fresh command info cache instance.
2223
/// </summary>
23-
public CommandInfoCache(Helper pssaHelperInstance)
24+
public CommandInfoCache(Helper pssaHelperInstance, RunspacePool runspacePool)
2425
{
2526
_commandInfoCache = new ConcurrentDictionary<CommandLookupKey, Lazy<CommandInfo>>();
2627
_helperInstance = pssaHelperInstance;
28+
_runspacePool = runspacePool;
2729
}
2830

2931
/// <summary>
@@ -64,14 +66,16 @@ public CommandInfo GetCommandInfoLegacy(string commandOrAliasName, CommandTypes?
6466
/// Get a CommandInfo object of the given command name
6567
/// </summary>
6668
/// <returns>Returns null if command does not exists</returns>
67-
private static CommandInfo GetCommandInfoInternal(string cmdName, CommandTypes? commandType)
69+
private CommandInfo GetCommandInfoInternal(string cmdName, CommandTypes? commandType)
6870
{
6971
// 'Get-Command ?' would return % for example due to PowerShell interpreting is a single-character-wildcard search and not just the ? alias.
7072
// For more details see https://github.com/PowerShell/PowerShell/issues/9308
7173
cmdName = WildcardPattern.Escape(cmdName);
7274

7375
using (var ps = System.Management.Automation.PowerShell.Create())
7476
{
77+
ps.RunspacePool = _runspacePool;
78+
7579
ps.AddCommand("Get-Command")
7680
.AddParameter("Name", cmdName)
7781
.AddParameter("ErrorAction", "SilentlyContinue");

Engine/Helper.cs

+11-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using System.Linq;
1212
using System.Management.Automation;
1313
using System.Management.Automation.Language;
14+
using System.Management.Automation.Runspaces;
1415

1516
namespace Microsoft.Windows.PowerShell.ScriptAnalyzer
1617
{
@@ -29,6 +30,7 @@ public class Helper
2930
private PSVersionTable psVersionTable;
3031

3132
private readonly Lazy<CommandInfoCache> _commandInfoCacheLazy;
33+
private readonly RunspacePool _runSpacePool;
3234

3335
#endregion
3436

@@ -113,7 +115,11 @@ internal set
113115
/// </summary>
114116
private Helper()
115117
{
116-
_commandInfoCacheLazy = new Lazy<CommandInfoCache>(() => new CommandInfoCache(pssaHelperInstance: this));
118+
// There are 5 rules that use the CommandInfo cache but one rule (AvoidAlias) makes parallel queries.
119+
// Therefore 10 runspaces was a heuristic measure where no more speed improvement was seen.
120+
_runSpacePool = RunspaceFactory.CreateRunspacePool(1, 10);
121+
_runSpacePool.Open();
122+
_commandInfoCacheLazy = new Lazy<CommandInfoCache>(() => new CommandInfoCache(pssaHelperInstance: this, runspacePool: _runSpacePool));
117123
}
118124

119125
/// <summary>
@@ -299,11 +305,12 @@ public PSModuleInfo GetModuleManifest(string filePath, out IEnumerable<ErrorReco
299305
Collection<PSObject> psObj = null;
300306
using (var ps = System.Management.Automation.PowerShell.Create())
301307
{
308+
ps.RunspacePool = _runSpacePool;
309+
ps.AddCommand("Test-ModuleManifest")
310+
.AddParameter("Path", filePath)
311+
.AddParameter("WarningAction", ActionPreference.SilentlyContinue);
302312
try
303313
{
304-
ps.AddCommand("Test-ModuleManifest");
305-
ps.AddParameter("Path", filePath);
306-
ps.AddParameter("WarningAction", ActionPreference.SilentlyContinue);
307314
psObj = ps.Invoke();
308315
}
309316
catch (CmdletInvocationException e)

0 commit comments

Comments
 (0)