8000 Refactor ReadConsole P/Invoke in ConsoleHost by iSazonov · Pull Request #9165 · PowerShell/PowerShell · GitHub
[go: up one dir, main page]

Skip to content

Refactor ReadConsole P/Invoke in ConsoleHost#9165

Merged
daxian-dbw merged 7 commits intoPowerShell:masterfrom
iSazonov:clean-consoleread
Mar 22, 2019
Merged

Refactor ReadConsole P/Invoke in ConsoleHost#9165
daxian-dbw merged 7 commits intoPowerShell:masterfrom
iSazonov:clean-consoleread

Conversation

@iSazonov
Copy link
Collaborator
@iSazonov iSazonov commented Mar 19, 2019

PR Summary

Replace StringBuilder with stack allocated Span<char> to avoid extra allocation/copies during P/Invoke.

PR Context

Using StringBuilder in P/Invoke causes extra allocations and buffer copies.
Related #9139

PR Checklist

@iSazonov iSazonov requested a review from lzybkr March 19, 2019 06:54
@iSazonov
Copy link
Collaborator Author
iSazonov commented Mar 19, 2019

Windows uses 8 Kb buffer to read from console
Unix uses 1 Kb buffer to read from console

If we could use a buffer of the same size on Windows, we could use a stackalloc instead of an ArrayPool.
We can?

Performance ArrayPool vs allocation https://adamsitnik.com/Array-Pool/
With stackalloc we could be faster.

@iSazonov iSazonov added the CL-CodeCleanup Indicates that a PR should be marked as a Code Cleanup change in the Change Log label Mar 19, 2019
@iSazonov iSazonov marked this pull request as ready for review March 19, 2019 14:31
@iSazonov iSazonov requested a review from anmenaga as a code owner March 19, 2019 14:31
lastCompletion = completedInput;
}

lastInput = completedInput;
Copy link
Member

Choose a reason for hiding this comment

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

Does tab completion still work when PSReadLine isn't loaded?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, it does not work. I will look more closely.
I see and wonder that tab completion doesn't work on Unix without PSReadline at all.

Copy link
Member

Choose a reason for hiding this comment

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

@iSazonov Unix has a very simple readline implementation while Windows still enables the tab-complete experience (using Windows APIs for rendering). Want to make sure we don't introduce a regression here.

Copy link
Contributor

Choose a reason for hiding this comment

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

On Windows, the cooked input mode supports ending on Tab to support tab completion in a cli like PowerShell or cmd, see here.

On Unix, cooked mode does not end on Tab and a cli typically ends up in raw mode if it wants tab completion.

@lzybkr
Copy link
Contributor
lzybkr commented Mar 20, 2019

@iSazonov - the initialContent parameter was an optimization where we displayed the prompt in native code where possible (no custom prompt) because startup was so slow. That optimization is no longer necessary, so it's safe to remove the code.

As for buffer Windows/Unix buffer sizes - I believe the code you're looking at only matters if PSReadLine is not in use, so it's mostly not interesting.

@daxian-dbw daxian-dbw self-assigned this Mar 20, 2019
@iSazonov
Copy link
Collaborator Author

@lzybkr Thanks! Although you have approved this change, I still have to restore tab completion on Windows, yes?
Also make sense to unify the behavior for all platforms?

8000

@lzybkr
Copy link
Contributor
lzybkr commented Mar 20, 2019

Oh, I probably didn't look closely enough at this, you shouldn't regress tab completion w/o PSReadLine.

I was thinking the initialContent parameter was introduced for the performance optimization I mentioned, but I'm probably misremembering, it seems like that parameter was always there in at least one place.

@lzybkr lzybkr self-requested a review March 20, 2019 04:09
@iSazonov
Copy link
Collaborator Author
iSazonov commented Mar 20, 2019

The feature request to enhance Console.ReadKey() to complete at Tab.
https://github.com/dotnet/corefx/issues/36175

Update: already implemented!

@iSazonov iSazonov force-pushed the clean-consoleread branch from bf12348 to dd0514d Compare March 20, 2019 15:48
@iSazonov iSazonov force-pushed the clean-consoleread branch from dd0514d to 4bbf15d Compare March 20, 2019 15:56
@iSazonov
Copy link
Collaborator Author

I pushed new commit to revert previous changes and use stack edit buffer (size reduced from 8Kb to 1Kb).
I could try to improve the code in ReadLineFromConsole() and above or leave it for follow PR.

Copy link
Member
@daxian-dbw daxian-dbw left a comment

Choose a reason for hiding this comment

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

LGTM, with one comment

@daxian-dbw daxian-dbw merged commit bc95a8e into PowerShell:master Mar 22, 2019
@daxian-dbw
Copy link
Member

@iSazonov Thank you for getting started on #9139 ! Now we have example code to follow :)

@iSazonov iSazonov deleted the clean-consoleread branch March 22, 2019 17:46
@iSazonov
Copy link
Collaborator Author

On Windows, the cooked input mode supports ending on Tab to support tab completion in a cli like PowerShell or cmd, see here.
On Unix, cooked mode does not end on Tab and a cli typically ends up in raw mode if it wants tab completion.

@lzybkr After some investigations I discovered that canonical (cooked) input mode on Unix may ends line input by VEOL which can be set to TAB by termios API
http://man7.org/linux/man-pages/man3/termios.3.html
https://github.com/hyc/OpenSSH-LINEMODE/wiki

If this is the right direction I could open new tracking Issue.

Maybe there is still a problem getting the cursor position.
https://thoughtsordiscoveries.wordpress.com/2017/04/26/set-and-read-cursor-position-in-terminal-windows-and-linux/

@lzybkr
Copy link
Contributor
lzybkr commented Mar 24, 2019

There's little harm in opening an issue, but I'd have a hard time justifying spending much time on that. Windows has the support because that code was written before PSReadLine existed.

We opted to more or less require PSReadLine on non-Windows because it wasn't hard to port and had all of the key functionality folks expect on non-Windows.

@iSazonov
Copy link
Collaborator Author

@lzybkr Thanks for your comment!

I also discover that we call TryInvokeUserDefinedReadLine() for every new input line where we do search PSConsoleHostReadLine. This looks expensive. We could register PSConsoleHostReadLine() as a delegate on event onLoad() and unregister on event onUnload() in PSReadline module. Also we could use cached PowerShell object. What do you think?

@lzybkr
Copy link
Contributor
lzybkr commented Mar 25, 2019

It’s probably not worth the trouble.

The biggest performance problem was searching for external commands and that is no longer an issue, the search skips those now.

I had a similar idea when we included PSReadLine in Windows and actually implemented my idea to call the C# api directly. It caused problems with custom scriptblock handlers. I decided that in this case it was best to keep the code simple.

}

private const int maxInputLineLength = 8192;
private const int MaxInputLineLength = 1024;

Choose a reason for hiding this comment

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

Why reduce it?

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

Labels

CL-CodeCleanup Indicates that a PR should be marked as a Code Cleanup change in the Change Log

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

0