-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
custom flow control and discard limit #2122
Conversation
- adding watermark for write buffers - low and high watermark to toggle flow control - sanity watermark to discard data
Very interesting stuff! |
src/Terminal.ts
Outdated
this.writeBufferUtf8.push(data); | ||
// safety measure: dont allow the backend to crash | ||
// the terminal by writing to much data to fast. | ||
if (this._watermark > DISCARD_WATERMARK) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need this check here, jsdoc in API (and more docs when we improve that) should be enough
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean like no DISCARD check at all? It is meant to stop malicious or faulty backends (those that ignore the PAUSE) from crashing ppls browsers. Sure we dont want that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could discard some important things which would corrupt the terminal, for example ls -lR / && vim
may not enter the alt buffer. I guess the main reason I don't think it's needed is I haven't seen the demo crash for a long time and we could avoid this critical path check if people implement correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I see with ./fast_producer
in the demo on master:
- FF: +2.5 GB / min, kernel eventually kills it for being this memory hungry (happens for me around minute 3 to 5 in several runs)
- Chrome: +1 GB / min in the beginning, after 2-3 min this drops back to ~250 MB and is stable there, devtools die after 30s
No clue what going on with Chrome, I think they are cheating once a process hit some memory limit (killing the Websocket? - idk, did not investigate further). Firefox shows the expected linear memory exhaustion.
I am abit uneasy about not having this security setting, since it might kill the browser (under FF at least the kernel killed the whole browser with all tabs). Maybe we should set DISCARD_WATERMARK
higher even higher to avoid losing data in your example?
Did some fine tuning of the limits in the demo with the last commits (still contains debug logs). There is a tradeoff between raw throughput speed and response to interrupts like Ctrl-C. Furthermore fast producers behave differently than slower ones due to different buffer fill states. The numbers I have found are the compromise between no/low negative impact on frequently used semi fast producers like Currently I see the following:
To get there I also had to introduce a buffer cap in the server.js pty --> xterm buffer, otherwise chunks from running @Tyriar Could you test if these numbers will do on MacOS? With its bigger pty buffer |
Ctrl+C on |
@Tyriar Hmm 2s is quite long, but I cannot lower that much further without sacraficing throughput performance. Can we live with it taking this long? Imho |
I don't think this is a WIP anymore right? |
fast_producer.c
Outdated
|
||
int main(int argc, char **argv) { | ||
while (1) { | ||
putchar('#'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes
seems to work fine, and I see the pausing and catching up in the log of yarn start
. fast_producer however really starts to chug things and it's hard to tell if the pausing is working at all as all the logs say 1024.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additionally I placed a console.log(this._watermark)
in write to test the flowing with fast_producer.
I was expecting this to run less responsive on MacOS, MacOS has a dynamic pty buffer size depending on incoming data pressure (typically ranges from 16-64kB). Thus a single message will be like 64kB, alot to chew for xterm.js in one step.
fast_producer is an extreme example an IMHO not worth optimizing for. Since yes
runs ok for you I think the numbers will do as they are?
@Tyriar Added a better fast producer snippet. This is fastest I was able to find with some more structured output (almost twice as fast as Edit: Wow, the PAUSE signal takes really long to get through in the demo, watermark easily goes up to 5MB, although it gets send at 120kB, WTH. This means with a slightly longer connection latency the watermark easily will go over 10MB. Edit2: The reason is fairly simple, server.js already sent 2 - 7 MB before the PAUSE signal arrives in server.js. Once its seen the pty blocks rather fast. With worse latency the amount of already sent data will explode. Imho we can only circumvent this with the ACK idea. |
src/Terminal.ts
Outdated
/** | ||
* send ACK every ACK_WATERMARK-th byte | ||
*/ | ||
const ACK_WATERMARK = 131072;//524288; // 2^19 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we may want to instead send some request ack sequence from the server and then once this is hit in the parser we can send back. Extra awesome super-duper benefit of this is that it could all be done via the xterm.js API via a custom handler 😮
So server asks '\x1b^reqack;1\x1b\\'
(not sure if an ID, the 1, is needed or not yet), then our custom ESC handler sends back '\x1b^ack;1\x1b\\'
.
Closing this PR for now. We still have to work out the details for the offscreen core lib (some downgraded Terminal.ts thingy), prolly with some input service like thingy as well. Any attempts towards better flow control should go there once we have that. |
This PR introduces a new flow control mechanism based on recent changes in
node-pty
. The flow control works similar to the current XON/XOFF way with writing special messages to the backend to indicate whether data streaming should be paused/resumed. Main differences are customizable PAUSE/RESUME messages. Those will be filtered innode-pty
to pause/resume the pty slave program by buffer back pressure.Changes:
TODO:
node-pty
backendsFixes #2077, #1918.