Powershell: Powershell startup time

Created on 3 Mar 2017  路  29Comments  路  Source: PowerShell/PowerShell

Are there any plans to improve Powershell startup time to make it a viable contender to zsh/bash etc as an interactive shell. Right now I hit Win+Enter and zsh starts in what seems like sub 200ms. I can then time l pin<Ctrl-p> to get my last ping command, hit enter and get a ping in less than 100 ms and then hit . In this time, powershell hasn't even started once.

I wouldn't mind constantly running a "server/daemon" of some sort that allows me to instantly open multiple shells with fresh sessions.

PS: I hope I don't sound rude with this request- Powershell, for what it's worth, runs circles around zsh and bash in how brilliantly designed and powerful it is. But one has to be able to use it to harness that power :)

Issue-Enhancement Resolution-Answered WG-Engine-Performance

Most helpful comment

I did a ton of work on startup in 5.1 - I got Windows PowerShell startup to be roughly in the 250ms range.

The code in PowerShell Core is basically the same, but I've still found surprising differences where PowerShell Core is slower.

So it might be possible to get acceptable startup on Core, but I think a long-lived server process communicating with a full native exe is the key to getting sub 50ms startup.

All 29 comments

I assume you mean Windows PowerShell? Because Powershell Core starts very fast.

@iSazonov I'm on Linux (Arch) but I'm using an AppImage. Could it be the AppImage? I see that the last release was 16 days back (same day that AppImage issue was resolved). Maybe I'll wait till the next AppImage.

@SRGOM not rude at all. Startup performance is something we've always strived to improve. It's a difficult problem, unfortunately, but I absolutely agree we could improve it more.

As I understand it, most of the difficulty lies around loading CoreCLR into memory so that we can host PowerShell. If we had a CoreCLR hanging out memory (i.e. the "server/daemon" that you wouldn't mind) that we could attach to, I think it would certainly help things, but I'm not technical enough to know the feasability of that.

I also know that "ngen"-ing or "cross-gen"ing the binaries down to native code helps with performance (classic space/time tradeoff), but I have no idea if we're already doing that. /cc @daxian-dbw

Currently we temporaryly disable "cross-gen" because there is a bug in CoreCLR.
Update: it is only for CI builds so distributives is not affected.

Cc @PowerShell/area-performance

I did a ton of work on startup in 5.1 - I got Windows PowerShell startup to be roughly in the 250ms range.

The code in PowerShell Core is basically the same, but I've still found surprising differences where PowerShell Core is slower.

So it might be possible to get acceptable startup on Core, but I think a long-lived server process communicating with a full native exe is the key to getting sub 50ms startup.

powershell core release packages are with corssgen'ed assemblies, but I still find it very slow at the first startup, at least on Windows from my experience. I'm using powershell core on Win as my default shell, and the startup time is sometimes frustrating. We need to get to the root of this problem to make it really a usable shell.

Confirm - first startup (on Windows) is slower than subsequent.

We should do some profiling

I wouldn't mind constantly running a "server/daemon" of some sort that allows me to instantly open multiple shells with fresh sessions.

I would. So this should be optional at best.

@probonopd - would you even notice?

The Roslyn C# compiler is implemented this way - csc.exe is 100% native code. If no server is running, it starts one. It then communicates with the server via pipe.

The server automatically exits if there is no client connecting after some time, like 15 minutes.

One big benefit to this approach - if you run identical scripts in different sessions, the server would naturally share the code, parsing/compilation gets skipped when it's been done already for another client.

@probonopd @lzybkr I think it definitely depends on the implementation, but we'll make sure to discuss it heavily if/when we choose to implement it.

Start-CrossGen only NGen's certain assemblies (the space/time balance). CrossGen'ing everything would improve perf a bit, but not enough to justify the bloated size, last time we checked.

Related to #1954.

@lzybkr I would notice too. Happens quite often that I kill powershell processes because of hangs or some other sort of misbehavior. If all runspaces were in one server it would be an issue, not to mention the lack of isolation for threading etc.

For what it's worth, I just downloaded the latest alpha (17?) and compared to alpha 9- I'm seeing some improvements.

time /lib/AppImages/powershell-6.0.0-alpha.9-x86_64.AppImage -c 'exit'

~1.9s total average

time ~/Downloads/powershell-6.0.0-alpha.-x86_64.AppImage -c 'exit'

~1.9s total average

time ~/Downloads/PowerShell-x86_64.AppImage -c 'exit'

~1.5s total average

I'm glad there is improvement but I still think it's not quite there...

Thank you for thinking about it though.

I guess I will close since you guys already have this thing in mind. Feel free to reopen if you want.

@iSazonov

It's only for CI so distributives are not affected.

So how does one "compile" their powershell CLR assembly to native code on a Linux distro? I'd like to use the crossgen'd binary.

Use crossgen. You can see sample in our Build.psm1 module. Also you can open Issue-Question to get in-depth answer.

Start-PSBuild -CrossGen -PSModuleRestore should work if you are running on a supported platform. You can find an example in our nightly build script: https://github.com/PowerShell/PowerShell/blob/master/docker/nightly/ubuntu14.04/Dockerfile#L13

@SteveL-MSFT Please review milestone.
~Should we open (re-open) tracking Issue for the performance considerations?~
Sorry, we have already #1954

There were a lot of important discussion in this thread and I probably shouldn't have closed this since it seems that PSH still takes a while to open, nowhere fast enough for me to quickly send a ping.

I will reopen and the repo-owner can decide what if anything to do, including closing this. I liked the idea of having a persistent server running.

[11:09:44 ~]time bash -c 'exit'
bash -c 'exit'  0.00s user 0.00s system 89% cpu 0.006 total
[11:09:46 ~]time zsh -c 'exit' 
zsh -c 'exit'  0.01s user 0.00s system 91% cpu 0.006 total
[11:09:49 ~]time psh -c 'exit' 
psh -c 'exit'  0.54s user 0.04s system 125% cpu 0.463 total

Updated timing from my mac using PowerShell 6.2

$ time pwsh -noprofile -c exit

real    0m0.426s
user    0m0.414s
sys 0m0.093s

$ time bash -c 'exit'

real    0m0.013s
user    0m0.004s
sys 0m0.007s

$ time zsh -c 'exit'

real    0m0.017s
user    0m0.005s
sys 0m0.009s

Since, AppImage is a virtualization, it will not be as fast.

.Net Core 3.0 has some improvements that will hopefully improve startup time, but certainly won't be comparable to bash or zsh

I remember here the idea was mentioned (Jason) to use a hosted solution to improve startup time.

@iSazonov yes, that is something we've thought about but isn't something we're targeting for 7.0

Make sense to have a tracking issue for this?

Was this page helpful?
0 / 5 - 0 ratings