You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The current implementation of Oh My Posh necessitates launching the oh-my-posh executable for each invocation of the terminal prompt. While care has been taken to minimise external imports and optimise the startup time, there's always going to be an overhead to launching a process.
On Linux and other Unix(-like) platforms this overhead is generally negligible, but on Windows it can be significant (at least in relative terms) due to the fundamental differences in how processes are managed by these operating systems. The problem is often further compounded by Windows security software which monitors the startup of processes and can add significant additional startup overhead (e.g. virus scanners, IPS sensors).
A simple (though unscientific) way to observe the difference is to hold the Enter key down in a terminal session using Oh My Posh on a Linux or macOS system, then contrast with a Windows system. The latter will almost definitely be significantly more "laggy", with new prompts appearing at a far slower rate. In addition, on releasing the Enter key new prompts will usually stop appearing on Linux or macOS immediately, while on Windows they'll continue to appear as the backlog of input events is processed.
A potential solution
What if Oh My Posh had a mode where its process was long-lived for a given terminal session, allowing the terminal to send commands over a simple IPC facility and receive the results back, thereby avoiding paying the process startup cost on every invocation of the terminal prompt. This would have a major performance benefit on Windows systems, and could be of value on other platforms as well.
What follows are some initial thoughts on how this could be implemented in a way that aims to maximise implementation simplicity while obtaining the performance benefits. Although Windows users are the expected primary beneficiary, an approach which aims to be platform agnostic has been taken.
IPC mechanism
What mechanism should be used for IPC between the Oh My Posh process and the terminal? I'd argue for Unix domain sockets: they're fast, simple, cross-platform, and delegate security to the file system (avoiding the need to handle the security of more abstract resources). Windows introduced support for Unix domain sockets in Windows 10, version 1803, so it has been supported on Windows for a while now.
Process startup
The wrapper function responsible for displaying the prompt in a given shell and launching Oh My Posh would be extended to handle launching in "server mode" (if configured by the user). The socket path to use would be provided as a parameter, and on successful startup, would be stored as a shell variable for the lifetime of the session. Failure handling could also be added where if the expected socket doesn't exist the server process is relaunched a set number of times before falling back to the "traditional" per-prompt invocation of Oh My Posh.
IPC communication
The parameters that would normally be passed to Oh My Posh as command-line arguments would instead be passed over the socket. This should allow their processing by the existing code after any initial handling by the socket server. There's no need to create a separate "protocol" for communicating the terminal state; though it would be more efficient the volume is so low (both in quantity and size of an individual request) as to be irrelevant.
Server process lifetime
If the terminal which launched the Oh My Posh server exits, then the Oh My Posh process should as well. One way to implement this would be an explicit "shutdown" command that can be sent to the server. This should be implemented regardless to facilitate e.g. Oh My Posh updates without relaunching the terminal, but it's not a durable method to use for ensuring we avoid lingering Oh My Posh processes given the originating terminal may crash, leaving no opportunity to instruct the process to gracefully shutdown (assuming the underlying shell even has a facility we can use to do that in the form of an exit trap or event handler).
On Windows, we should be able to handle this durably by using Job Objects. On Linux, specifying PR_SET_PDEATHSIG to prctl() is probably best. I'm unsure what the best approach is on other operating systems. An inactivity timer could also be implemented as a fallback approach which would cause the server process to initiate shutdown itself if it hasn't received any commands for a configurable duration.
Terminal association
Each Oh My Posh process should serve a single terminal session. Multiple terminal sessions means multiple long-lived Oh My Posh processes. A given Oh My Posh process acting as an IPC server will process requests serially; this naturally mirrors the expected interaction with the "owning" terminal.
Security considerations
The Unix domain socket should be secured to only allow access to the user who spawned the process. On Windows it should probably reside under %TEMP%, while on Linux it's probably best placed under whatever $TMPDIR points to, falling back to /tmp. On Windows, placing the socket under %TEMP% should ensure the socket is correctly secured without any further configuration. On Linux, some additional changes may be required if the socket is placed under /tmp, subject to the umask.
Conclusion
Implementing this feature would provide significant performance benefits beyond what Oh My Posh annd other prompt enhancers are able to deliver on Windows, and is I think less work to implement than may at first be expected (while still involving a number of changes). I hope this issue can be used to discuss the viability and potential problems of the suggested approach, and of course whether the maintainer has any interest in it at all.
Either way, thanks for all your work creating a fantastic terminal prompt!
The text was updated successfully, but these errors were encountered:
@ralish this has been on my mind for a while now and it could work. I always held back because it's not trivial and requires a lot of time to get right. But maybe the time is now :-)
@ralish so, I'm actually stuck on this one. To make it work, it still needs an executable to call the long lived process. Why? Most shells do not support sockets natively so you still need to implement a solution in another language. That goes against the principle here, as it won't solve much. I'll keep this in mind, but so far, other than theory, I haven't found a way that'll work. Additionally, it could work in PowerShell, but that requires dotnet libs which is known to get blocked on a lot of enterprise devices. Unless there's an easy, universal way to connect, this is a no go.
@JanDeDobbeleer Thanks for investigating and in full agreement this feature would be difficult to implement.
I suspect realistically it can't be implemented universally (i.e. for all shells across all platforms) without an insane amount of work. For example, how would it work in a cmd shell? The only answer that comes to mind would require DLL injection into the cmd shell as the facilities needed are otherwise not going to be present. I'm optimistic it could work on *nix shells without support from external utilities, but I'm definitely not certain, and the approach may not be consistent due to differences in supported IPC mechanisms.
PowerShell is easiest because suitable IPC facilities are built-in. PowerShell 7+ can use Unix-domain sockets as I think the "optimal" IPC approach, but older PowerShell releases can presumably use a TCP socket on the loopback interface. Given the scale of work involved to support all shells (assuming that's technically even possible), it feels support would realistically need to be introduced for individual shells and platforms overtime to make it manageable.
Given this is a performance feature, rather than a functionality feature (it doesn't affect the prompt output itself), is there a world where you'd be willing to merge in support for a subset of shells/platforms, assuming the code passes review and the feature can be enabled in a way where it transparently falls-back to the regular "spawn a process" approach?
Code of Conduct
What would you like to see added?
Background
The current implementation of Oh My Posh necessitates launching the
oh-my-posh
executable for each invocation of the terminal prompt. While care has been taken to minimise external imports and optimise the startup time, there's always going to be an overhead to launching a process.On Linux and other Unix(-like) platforms this overhead is generally negligible, but on Windows it can be significant (at least in relative terms) due to the fundamental differences in how processes are managed by these operating systems. The problem is often further compounded by Windows security software which monitors the startup of processes and can add significant additional startup overhead (e.g. virus scanners, IPS sensors).
A simple (though unscientific) way to observe the difference is to hold the Enter key down in a terminal session using Oh My Posh on a Linux or macOS system, then contrast with a Windows system. The latter will almost definitely be significantly more "laggy", with new prompts appearing at a far slower rate. In addition, on releasing the Enter key new prompts will usually stop appearing on Linux or macOS immediately, while on Windows they'll continue to appear as the backlog of input events is processed.
A potential solution
What if Oh My Posh had a mode where its process was long-lived for a given terminal session, allowing the terminal to send commands over a simple IPC facility and receive the results back, thereby avoiding paying the process startup cost on every invocation of the terminal prompt. This would have a major performance benefit on Windows systems, and could be of value on other platforms as well.
What follows are some initial thoughts on how this could be implemented in a way that aims to maximise implementation simplicity while obtaining the performance benefits. Although Windows users are the expected primary beneficiary, an approach which aims to be platform agnostic has been taken.
IPC mechanism
What mechanism should be used for IPC between the Oh My Posh process and the terminal? I'd argue for Unix domain sockets: they're fast, simple, cross-platform, and delegate security to the file system (avoiding the need to handle the security of more abstract resources). Windows introduced support for Unix domain sockets in Windows 10, version 1803, so it has been supported on Windows for a while now.
Process startup
The wrapper function responsible for displaying the prompt in a given shell and launching Oh My Posh would be extended to handle launching in "server mode" (if configured by the user). The socket path to use would be provided as a parameter, and on successful startup, would be stored as a shell variable for the lifetime of the session. Failure handling could also be added where if the expected socket doesn't exist the server process is relaunched a set number of times before falling back to the "traditional" per-prompt invocation of Oh My Posh.
IPC communication
The parameters that would normally be passed to Oh My Posh as command-line arguments would instead be passed over the socket. This should allow their processing by the existing code after any initial handling by the socket server. There's no need to create a separate "protocol" for communicating the terminal state; though it would be more efficient the volume is so low (both in quantity and size of an individual request) as to be irrelevant.
Server process lifetime
If the terminal which launched the Oh My Posh server exits, then the Oh My Posh process should as well. One way to implement this would be an explicit "shutdown" command that can be sent to the server. This should be implemented regardless to facilitate e.g. Oh My Posh updates without relaunching the terminal, but it's not a durable method to use for ensuring we avoid lingering Oh My Posh processes given the originating terminal may crash, leaving no opportunity to instruct the process to gracefully shutdown (assuming the underlying shell even has a facility we can use to do that in the form of an exit trap or event handler).
On Windows, we should be able to handle this durably by using Job Objects. On Linux, specifying
PR_SET_PDEATHSIG
toprctl()
is probably best. I'm unsure what the best approach is on other operating systems. An inactivity timer could also be implemented as a fallback approach which would cause the server process to initiate shutdown itself if it hasn't received any commands for a configurable duration.Terminal association
Each Oh My Posh process should serve a single terminal session. Multiple terminal sessions means multiple long-lived Oh My Posh processes. A given Oh My Posh process acting as an IPC server will process requests serially; this naturally mirrors the expected interaction with the "owning" terminal.
Security considerations
The Unix domain socket should be secured to only allow access to the user who spawned the process. On Windows it should probably reside under
%TEMP%
, while on Linux it's probably best placed under whatever$TMPDIR
points to, falling back to/tmp
. On Windows, placing the socket under%TEMP%
should ensure the socket is correctly secured without any further configuration. On Linux, some additional changes may be required if the socket is placed under/tmp
, subject to theumask
.Conclusion
Implementing this feature would provide significant performance benefits beyond what Oh My Posh annd other prompt enhancers are able to deliver on Windows, and is I think less work to implement than may at first be expected (while still involving a number of changes). I hope this issue can be used to discuss the viability and potential problems of the suggested approach, and of course whether the maintainer has any interest in it at all.
Either way, thanks for all your work creating a fantastic terminal prompt!
The text was updated successfully, but these errors were encountered: