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

Refresh limit system makes performance bad on Windows #280

Closed
Tyriar opened this issue Sep 19, 2016 · 7 comments
Closed

Refresh limit system makes performance bad on Windows #280

Tyriar opened this issue Sep 19, 2016 · 7 comments
Assignees
Labels
type/bug Something is misbehaving
Milestone

Comments

@Tyriar
Copy link
Member

Tyriar commented Sep 19, 2016

The integrated terminal in VS Code has a performance issue on Windows outlined here microsoft/vscode#10328 (comment), @codec-abc suggests it's due to the limit system in the refresh function:

setTimeout(function () {
  self.refresh(start, end, false);
}, 34)

Details

  • Browser and browser version: vscode v1.6/electron
  • OS version: Windows 10
  • xterm.js version: 3c9d8b0
@codec-abc
Copy link

This may be not totally related but do you think the refresh frequency could be dynamic ? Because I think it would be better for the user experience to have a default 60 fps refresh rate. The terminal will probably feel more responsive.

@jerch
Copy link
Member

jerch commented Sep 20, 2016

@codec-abc 60fps is unrealistic for high output programs. High output means many changes of the DOM which increases the penalty for the reflow. Sticking to 60fps would therefore slow down the output flow. It might be a goal though if the stream parsing and state handling would have their own thread.

@Tyriar I suggest to bind the refresh to an animation frame to avoid cancelled reflows:
requestAnimationFrame(function() {self.refresh(start, end, false);});
(maybe in combination with setTimeout from above, if throttling is still needed).

@Tyriar
Copy link
Member Author

Tyriar commented Sep 28, 2016

Far too long is spent in Viewport.syncScrollArea:

image

Also strangely Viewport.refresh is being triggered multiple times during a single syncScrollArea, not sure why.

@jerch
Copy link
Member

jerch commented Sep 28, 2016

@Tyriar I think this due to the fact that syncScrollArea is bound to the scroll-event of the terminal, which is likely to be triggered several times in term.write.
The bad runtime is mostly caused by forced reflows by accessing getBoundingClientRect and this.viewportElement.scrollTop in syncScrollArea.

I append a small patch which reduces getBoundingClientRect calls and avoids scrollTop read access completely. Not sure if it generates still the same output, playing around with charMeasureElement showed weird changes in the output (missing lines and such).

diff --git a/src/Viewport.js b/src/Viewport.js
index d23ba7c..df87799 100644
--- a/src/Viewport.js
+++ b/src/Viewport.js
@@ -16,6 +16,8 @@ function Viewport(terminal, viewportElement, scrollArea, charMeasureElement) {
   this.viewportElement = viewportElement;
   this.scrollArea = scrollArea;
   this.charMeasureElement = charMeasureElement;
+  this.charSize = this.charMeasureElement.getBoundingClientRect();
+  this.scrollPending = false;
   this.currentRowHeight = 0;
   this.lastRecordedBufferLength = 0;
   this.lastRecordedViewportHeight = 0;
@@ -34,7 +36,7 @@ function Viewport(terminal, viewportElement, scrollArea, charMeasureElement) {
  *   doesn't exist it will be created.
  */
 Viewport.prototype.refresh = function(charSize) {
-  var size = charSize || this.charMeasureElement.getBoundingClientRect();
+  var size = charSize || this.charSize;
   if (size.height > 0) {
     var rowHeightChanged = size.height !== this.currentRowHeight;
     if (rowHeightChanged) {
@@ -78,9 +80,15 @@ Viewport.prototype.syncScrollArea = function() {
   }

   // Sync scrollTop
-  var scrollTop = this.terminal.ydisp * this.currentRowHeight;
-  if (this.viewportElement.scrollTop !== scrollTop) {
-    this.viewportElement.scrollTop = scrollTop;
+  var self = this;
+  if (!this.scrollPending) {
+    this.scrollPending = true;
+    requestAnimationFrame(function(){
+      // hack - simply scroll to bottom assuming container
+      // is never higher than the hardcoded value
+      self.viewportElement.scrollTop = 3000000000;
+      self.scrollPending = false;
+    });
   }
 };

Just tested it in VSCode 1.5.3 under Windows - it will not work there without a few changes (for some reasons the metrics of this.charMeasureElement is zeroed at the beginning while it isn't with the xterm.js demo. Also it seems more like a hack than a real solution ;)

@Tyriar
Copy link
Member Author

Tyriar commented Dec 12, 2016

This is very obvious when you compare xterm.js within vscode to hyper, it helps that their scroll bar seems to be only for show though (no need to deal with scroll events).

@parisk
Copy link
Contributor

parisk commented Dec 13, 2016

Stating the obvious: I think we should tear down the whole rendering part and reduce as much waste as possible for start.

I am not sure if I can get on top of this right now, but I can definitely help if you are willing to take this over @Tyriar.

@Tyriar
Copy link
Member Author

Tyriar commented Dec 14, 2016

I'd still like to do it when I get a chance, the CircularList scrollback stuff seems like a good starting point for the performance issues.

@Tyriar Tyriar changed the title Refresh limit system supposedly makes performance bad on Windows Refresh limit system makes performance bad on Windows Dec 21, 2016
Tyriar added a commit to Tyriar/xterm.js that referenced this issue Dec 31, 2016
Use requestAnimationFrame in addition to a queue to refresh every animation
frame but only when a refresh is needed.

Fixes xtermjs#280
@Tyriar Tyriar added this to the 2.3.0 milestone Dec 31, 2016
Tyriar added a commit to Tyriar/xterm.js that referenced this issue Dec 31, 2016
Use requestAnimationFrame in addition to a queue to refresh every animation
frame but only when a refresh is needed.

Fixes xtermjs#280
Fixes xtermjs#290
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type/bug Something is misbehaving
Projects
None yet
Development

No branches or pull requests

4 participants