8000 Update `PSConfiguration.ReadValueFromFile` to make it faster and more memory efficient by daxian-dbw · Pull Request #10839 · PowerShell/PowerShell · GitHub
[go: up one dir, main page]

Skip to content

Conversation

@daxian-dbw
Copy link
Member
@daxian-dbw daxian-dbw commented Oct 18, 2019

PR Summary

There are 2 changes included here:

  1. Change how configuration file is accessed to make it faster and memory efficient.
  2. Change TypeCatalogGen to generate slightly faster dictionary initialization code.

The TypeCatalogGen is more of a cleanup change, to use the collection initializer, which is slightly faster than the dict[xxx] = "..." operation.

Benchmark results for the PSConfiguration change

For the PSConfiguration change, I ran a benchmark. The benchmark code and results can be found below.
The new implementation is a lot faster than the current, but overall it won't affect much the startup of pwsh, because we spent very little time in PSConfiguraiton.
The new implementation has a lot less allocation (88.63KB vs. 1.69KB). This is the more interesting part.

    class Program
    {
        static void Main(string[] args)
        {
            var summary = BenchmarkRunner.Run<Benchmark_ReadConfigData>();
        }
    }

    [DisassemblyDiagnoser(printAsm: true, printSource: true, recursiveDepth: 2)]
    [MemoryDiagnoser]
    public class Benchmark_ReadConfigData
    {
        [Benchmark(Baseline = true)]
        public void ReadConfigUsingCurrentImpl()
        {
            // Those methods are called during the startup of 'pwsh', so using them as the operations for the benchmark.
            PowerShellConfig.Instance.GetExperimentalFeatures();
            PowerShellConfig.Instance.GetModulePath(ConfigScope.AllUsers);
            PowerShellConfig.Instance.GetModulePath(ConfigScope.CurrentUser);
            PowerShellConfig.Instance.GetPowerShellPolicies(ConfigScope.CurrentUser);
            PowerShellConfig.Instance.GetPowerShellPolicies(ConfigScope.AllUsers);
            PowerShellConfig.Instance.GetExecutionPolicy(ConfigScope.CurrentUser, "Microsoft.PowerShell");
            PowerShellConfig.Instance.GetExecutionPolicy(ConfigScope.AllUsers, "Microsoft.PowerShell");
        }

        [Benchmark]
        public void ReadConfigUsingNewImpl()
        {
            // Those methods are called during the startup of 'pwsh', so using them as the operations for the benchmark.
            NewPowerShellConfig.Instance.GetExperimentalFeatures();
            NewPowerShellConfig.Instance.GetModulePath(ConfigScope.AllUsers);
            NewPowerShellConfig.Instance.GetModulePath(ConfigScope.CurrentUser);
            NewPowerShellConfig.Instance.GetPowerShellPolicies(ConfigScope.CurrentUser);
            NewPowerShellConfig.Instance.GetPowerShellPolicies(ConfigScope.AllUsers);
            NewPowerShellConfig.Instance.GetExecutionPolicy(ConfigScope.CurrentUser, "Microsoft.PowerShell");
            NewPowerShellConfig.Instance.GetExecutionPolicy(ConfigScope.AllUsers, "Microsoft.PowerShell");
        }
    }

image

PR Checklist

Comment on lines 66 to 68
private readonly JObject[] configRoots = new JObject[2];
private readonly JObject emptyConfig;
private readonly JsonSerializer serializer;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Should we use _ prefix for private field names?
  2. We initialize configRoots here and in constructor too.
  3. We could initialize configRoots with " empty config" that could simplify to introduce "DefaultConfig".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For (1) I don't plan to make that change in this PR given it's a style change that will make the PR harder to review.
For (2) good catch. Fixed.
For (3) emtpyConfig means we have attempted reading the file, and there is not configuration defined in the corresponding file (either an empty file, or file doesn't exist). So configRoots cannot be initialized to emptyConfig. They mean different things.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For (3) In the case emptyConfig is not reflect the purpose.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate why you think it doesn't reflect the purpose?

@daxian-dbw daxian-dbw changed the title WIP: Update PSConfiguration.ReadValueFromFile to make it faster and more memory efficient Update PSConfiguration.ReadValueFromFile to make it faster and more memory efficient Oct 21, 2019
foreach (KeyValuePair<string, TypeMetadata> pair in typeNameToAssemblyMap)
{
sourceCode.AppendLine(string.Format(CultureInfo.InvariantCulture, SourceFormat, pair.Key, pair.Value.AssemblyName));
sourceCode.Append(string.Format(CultureInfo.InvariantCulture, SourceFormat, pair.Key, pair.Value.AssemblyName, Environment.NewLine));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Environment.NewLine on first position it would be more clear.

@adityapatwardhan adityapatwardhan merged commit 7772418 into PowerShell:master Oct 30, 2019
@adityapatwardhan adityapatwardhan added the CL-Engine Indicates that a PR should be marked as an engine change in the Change Log label Oct 30, 2019
@adityapatwardhan adityapatwardhan added this to the 7.0.0-preview.6 milestone Oct 30, 2019
@daxian-dbw daxian-dbw deleted the perf branch November 1, 2019 06:25
@daxian-dbw daxian-dbw added CL-Performance Indicates that a PR should be marked as a performance improvement in the Change Log and removed CL-Engine Indicates that a PR should be marked as an engine change in the Change Log labels Nov 1, 2019
@ghost
Copy link
ghost commented Nov 21, 2019

🎉v7.0.0-preview.6 has been released which incorporates this pull request.:tada:

Handy links:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CL-Performance Indicates that a PR should be marked as a performance improvement in the Change Log

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

0