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

Speed Up info_pkgs #161

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft

Conversation

Carterpersall
Copy link
Contributor

@Carterpersall Carterpersall commented Oct 10, 2022

Speeds up the retrieval of packages

Gets the quantity of folders at `$env:ChocolateyInstall\lib`, which contains the programs Chocolatey has installed.
@rashil2000
Copy link
Member

Gets the quantity of folders at $env:ChocolateyInstall\lib, which contains the programs Chocolatey has installed.

This method can also be used for info_ps_pkgs (by enumerating over $env:PSModulePath), which currently takes up a lot of time.

@Carterpersall Carterpersall mentioned this pull request Oct 12, 2022
16 tasks
@Carterpersall
Copy link
Contributor Author

Carterpersall commented Oct 12, 2022

Gets the quantity of folders at $env:ChocolateyInstall\lib, which contains the programs Chocolatey has installed.

This method can also be used for info_ps_pkgs (by enumerating over $env:PSModulePath), which currently takes up a lot of time.

Unless we can figure out how to differentiate which packages were installed using PowershellGet, using $env:PSModulePath won't work.
I tried reverse engineering the PackageManagement module, and found that Get-InstalledModule runs PackageManagement\Get-Package @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object {New-PSGetItemInfo -SoftwareIdentity $_ -Type 'Module'} where New-PSGetItemInfo is a function that is contained within the same file. I then tried to find the source of Get-Package, which led me to a C# DLL file which I then followed to www.github.com/OneGet/oneget , which then I tracked back to the function GetInstalledPackages() at www.github.com/OneGet/oneget/blob/WIP/src/Microsoft.PackageManagement.CoreProviders/Bootstrap/BootstrapProvider.cs#L241 where I got stuck.
Some time may be able to be saved though by running Get-Package instead of Get-InstalledModule, which causes about a 13% speedup

@rashil2000
Copy link
Member

rashil2000 commented Oct 13, 2022

Unless we can figure out how to differentiate which packages were installed using PowershellGet, using $env:PSModulePath won't work.

I mean yes, not all directories of $env:PSModulePath - we need only those that are explicitly installed.

image

In this, only the top directory has explicitly installed modules. The below 2 are ones that are included in Windows by default, so we don't need to enumerate over them. PowerShell Core can be handled similarly.

I have an implementation ready, will handle it in a separate PR.

@Carterpersall
Copy link
Contributor Author

I mean yes, not all directories of $env:PSModulePath - we need only those that are explicitly installed.

image

In this, only the top directory has explicitly installed modules. The below 2 are ones that are included in Windows by default, so we don't need to enumerate over them. PowerShell Core can be handled similarly.

The issue I'm having with this implementation is that the quantity of folders in the directory don't line up with the quantity of modules returned by Get-InstalledModule

Powershell 7:
$env:PSModulePath Method:
image

  • 8 Modules shown

Current Method:
image

  • 6 Modules shown

Powershell 5:
$env:PSModulePath Method:
image

  • 3 Modules shown

Current Method:
image

  • 1 Module shown

Some modules I had installed were also located within the 2 locations that're included by default.

- Added "system" to info_pkgs as a faster alternative to "winget"
  - Returns the total quantity of 'uninstallable' programs
  - Quantity is different from what Winget returns due to the lack of its index, so this couldn't be used as a faster implementation of "winget"
  - Added "system" to default config file
  - Changed the returned string in "winget" to clarify that it is Winget and not the entire system
@rashil2000
Copy link
Member

rashil2000 commented Oct 13, 2022

Just a heads up: Apps installed by winget will show up as both winget and system. We should prevent double counting.

@Carterpersall
Copy link
Contributor Author

Just a heads up: Apps installed by winget will show up as both winget and system. We should prevent double counting.

While usually I would agree, I think this could be an exception as this method cannot replace the implementation for Winget because of its lack of an index and UWP apps but is significantly faster than the Winget method.

- Missed two registry paths for 64-bit programs
- Somehow tanking the errors is slightly faster than checking if $program had a value
- Duplicate and null entries weren't being filtered out because I was using arraylists instead of hashtables
  - Filtering null entries via if-statements is now very slightly faster (1-3ms)
@Carterpersall
Copy link
Contributor Author

Carterpersall commented Feb 27, 2023

  • I've added caching of Winget's result to the config file
    • Puts the caching script into a PS1 file in $Env:TEMP and runs it in a new PowerShell instance
      • Window is hidden
      • Runs in a new instance so it can continue running even if Winfetch finishes executing
      • Tried to run the script using a scriptblock instead of a file, but for some reason PowerShell was not cooperating
    • While this does mean Winget's package count is always 1 execution behind, the speed gain obtained is worth it in my opinion
    • 2590ms → 46ms
      • 56x Faster

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

Successfully merging this pull request may close these issues.

None yet

2 participants