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

Calling git on module import could be avoided #948

Open
DominikJaniec opened this issue Feb 20, 2023 · 2 comments
Open

Calling git on module import could be avoided #948

DominikJaniec opened this issue Feb 20, 2023 · 2 comments

Comments

@DominikJaniec
Copy link

DominikJaniec commented Feb 20, 2023

This is a feature proposal rather than a bug.

I've found that, when git execution is skipped within Import-Module call, it can save about 100 milliseconds of module startup time. It's not that much even on my machine, but the same framework allowing this, could be "easily" used to entirely disable prompt support, which can save 1/3 of total module import time, or about 1/4 of everything when including pwsh startup too.

This could be done through support for setting posh-git module prerequisites via beforehand prepared global key-value hash set (i.e. @{}) with:

  • old module parameters
  • current git version
  • additional config

Some time ago, I've decided to find out a way to speed up posh-git module import time. Then, I've figured out that skipping whole prompt-support could be a useful thing - e.g. #927

However, avoiding "dot-sourcing" everything related to prompt, could be problematic to integrate with "bundling everything into a single file" as proposed in #698 - but will we finalize it?

Moreover, setting module arguments with array of numbers (i.e. -ArgumentList 0,0,0) is kind of hard to grasp at the call site, as one need to know meaning and order of module parameters. On the other side, I'm not sure if using global-dictionary is a "tolerable" way to pass configuration into PowersShell module.

This feature could be also used to toggle additional features, like setting strict-mode, or enabling warnings from exceptions occurred while generating a completion result - what was useful when I've been discovering what is required for completion without Posh-Git prompt support.

I'm suggesting something like:

$global:PoshGit_InitProps = @{
  DisablePoshGitPrompt = $true;
  UseFunctionCompletion = $true;
  ShowCompletionErrors = $true;
  LocalGitVersion = [System.Version]"2.39.2";
  LocalGitExtensions = @{ flow = $true }
}

Import-Module posh-git

Thus, I would love to bring support for providing prerequisites into posh-git module. I've explored that possibility in my private fork, and I would like to prepare a little bit more "serious" Pull-Request to be merged here:

Based on my pwsh-profile-benchmarker.ps1, where pwsh -NoProfile was called with different scripts as "profiles", I've found that my machine has two modes: "slow", and "twice-slower" 😅. However, lower values and trend-lines of different series, show improvements described above:
pwsh-profile-results

@domsleee
Copy link

domsleee commented Mar 5, 2023

I like the performance energy here, I also had a look at this

I found that a $PROFILE with a single line of Import-Module ~\git\posh-git\src\posh-git.psd1 adds 412ms to my startup time of 214ms.

❯ hyperfine --warmup 2 'pwsh -c "echo hello world"' 'pwsh -NoProfile -c "echo hello world"'
Benchmark 1: pwsh -c "echo hello world"
  Time (mean ± σ):     626.3 ms ±   3.9 ms    [User: 3.1 ms, System: 10.9 ms]
  Range (min … max):   619.2 ms … 631.8 ms    10 runs

Benchmark 2: pwsh -NoProfile -c "echo hello world"
  Time (mean ± σ):     214.5 ms ±   2.6 ms    [User: 2.4 ms, System: 6.7 ms]
  Range (min … max):   210.6 ms … 220.1 ms    13 runs

Summary
  'pwsh -NoProfile -c "echo hello world"' ran
    2.92 ± 0.04 times faster than 'pwsh -c "echo hello world"'

Using feature/profiling of posh-git and feature/human-readable-duration of PSProfiler to profile , I found some of the hotspots:

 pwsh -NoProfile {
    Import-Module ~\git\PSProfiler\src\PSProfiler.psd1
    Measure-Script -HumanReadable -Path ~\git\posh-git\src\posh-git.ps1
}
...
 1    10             42ms . $PSScriptRoot\CheckRequirements.ps1 > $null
 0    11              0ms
 1    12             34ms . $PSScriptRoot\ConsoleMode.ps1
 1    13             24ms . $PSScriptRoot\Utils.ps1
 1    14              8ms . $PSScriptRoot\AnsiUtils.ps1
 1    15              8ms . $PSScriptRoot\WindowTitle.ps1
 1    16             12ms . $PSScriptRoot\PoshGitTypes.ps1
 1    17             15ms . $PSScriptRoot\GitUtils.ps1
 1    18             65ms . $PSScriptRoot\GitPrompt.ps1
 1    19             15ms . $PSScriptRoot\GitParamTabExpansion.ps1
 1    20             63ms . $PSScriptRoot\GitTabExpansion.ps1
 1    21              5ms . $PSScriptRoot\TortoiseGit.ps1
...

By removing code that isn't related to tab completion, I could get a measured startup time of 486ms in hyperfine, which 271ms for the module, a 34% improvement (271 / 412).
If anybody is interested to try, the code is on feature/profiling of posh-git.

However, avoiding "dot-sourcing" everything related to prompt, could be problematic to integrate with "bundling everything into a single file" as proposed in #698 - but will we finalize it?

I wanted to say about this one, it would be nice if we could have a bundle just with the tab completion logic? Like we could have two bundles, one with prompt + tab completion, and the other with just tab completion, and choose which one to source based on $DisablePromptSupport or similar. Or we could split tab completion to an entirely new PSModule?

@DominikJaniec
Copy link
Author

Nice, I saw similar distribution of times related to "dot-sourcing" respective files.


In the matter of separated modules with different set of bundled code. I think, this could be a very neat option to have, e.g. posh-git and posh-git-completion, where the latest will not support prompt at all. However, I believe this would bring more burden for maintainers, and could rise possible issues with confusion of what do what, and which module who should use - but maybe this should be a way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants