cursive icon indicating copy to clipboard operation
cursive copied to clipboard

Termion backend is slow

Open gyscos opened this issue 7 years ago • 14 comments

When running the lorem example with the termion backend in debug mode, a serious flickering can be observed. Running in release mode seems to solve this. Running in debug mode with the ncurses backend is also fine. It may be caused by a slow backend. All the calls to print! have to lock individually the standard output.

Note: to be clear, this issue is about the wrapper code in the cursive repository, not about termion itself.

gyscos avatar Jun 13 '17 06:06 gyscos

@gyscos Don't forget that using the ncurses backend, ncurses is still compiled in release mode, while only cursive will have unoptimized code. In the case of termion, since it's all pure Rust code, it will also be compiled without optimizations.

In my case, I have flickering in both release and debug modes, when resizing out(resizing in is ok, in debug mode). Note that I did not try to see if the flickering is present with other backends(don't want to install additional dependencies... that's why I love that there is the termion backend - I can compile a hello world application with Musl and strip it down to a 604K static binary).

lilianmoraru avatar Aug 15 '17 11:08 lilianmoraru

Experiencing flicker in release mode with the termion-backend as well, specifically when the screen is updated often such as when typing into an EditView or scrolling. Noticeably less flicker than debug of course.

ncurses-backend and pancurses-backend did not flicker in release mode while testing the examples.

I absolutely love the Cursive api and am thrilled to see termion as a backend option, especially because of the support for Redox. Well done 🙏

memoryruins avatar Dec 05 '17 18:12 memoryruins

First, I'm very glad you like this library! Don't hesitate to give feedback on any part you feel deserves more work!

My main idea for now is to lock the standard output once instead of at every print. Unfortunately it doesn't look trivial, since StdoutLock needs to borrow Stdout, which means storing them in the termion backend would require a self-borrowing structure.

Maybe this can't be avoided. We already depend on owning_ref, I'll see if it can help there.

gyscos avatar Dec 05 '17 19:12 gyscos

Is there any news on this? On latest release (0.9.0 on MacOS) the flickering is still very bad, even in release builds, and even with single paints (with that, I mean without using set_fps to set a fixed frame-rate).

Is there anything needed on the termion side? I may try to contact the maintainers (I think it's currently under the Redox team) if it helps.

HenryTheCat avatar Aug 30 '18 11:08 HenryTheCat

No news yet - I need to find some time to focus on that.

In addition to locking stdout, another idea might be to buffer the whole screen, and flush it to the terminal after each step. Doing it without allocating everytime may need some more thinking.

We'll need to do this eventually to fix #100 (though interestingly, the issue doesn't affect termion).

gyscos avatar Aug 30 '18 16:08 gyscos

I think Termion has already a double buffer mechanism:

https://docs.rs/termion/1.5.1/termion/screen/index.html

And if so, I would put double buffering into backend (by for instance adding method called "end_frame" or "swap_buffers"), not re-implement it on library level.

@gyscos is "Backend::clear" called only in begin of new frame, or has also other uses?

njskalski avatar Sep 07 '18 14:09 njskalski

@njskalski The screen switching is not a double-buffer mechanism. It is intended for full-screen programs such as Vim or Midnight Commander. As an example, when you start vim, it switches to the alternate screen, and when you quit or suspend vim, it switches back and the terminal shows its content from before you started vim.

FreeFull avatar Sep 08 '18 12:09 FreeFull

@gyscos I have created a buffering backend for any Cursive backend. See here. I used it with Termion and the flickering is gone

agavrilov avatar Oct 24 '18 21:10 agavrilov

Wow - awesome! Congratulations!

I'll have a look, but it may be a great workaround until we get a better buffering story inside Cursive itself - which might take a cue from your work! :)

Note: you may need to update the buffer size whenever the WindowResize event is sent.

gyscos avatar Oct 24 '18 21:10 gyscos

I'm checking the terminal size in 'Backend::clear' method and resize if necessary.

Let me know if you need any help with adding a buffering to Cursive

agavrilov avatar Oct 25 '18 00:10 agavrilov

I'll probably bring this caching system to the core of cursive, where it will apply to all backends.

In the meantime, I updated the termion backend to:

  • Access /dev/tty directly so stdin/stdout can be used for other things (well, almost, retrieving the terminal size still uses stdout for now)
  • Use buffered file io fall all input/output, so we don't need to lock on every print.

This brings the termion performance on par with the ncurses backend.

gyscos avatar Mar 01 '19 00:03 gyscos

I'll probably bring this caching system to the core of cursive, where it will apply to all backends.

I suppose it would ideally be switched based on backend. This would definitely be nice to have for termion and crossterm. I've noticed the flicker as well.

For *ncurses and bearlibterm, which already do their own character cell buffering, it might increase the overhead.

I think Termion has already a double buffer mechanism:

Please don't use it for that :sweat: The alternate screen—which is implemented by terminals, not by termion itself—is there to restore the state of the terminal after exiting an application.

vmedea avatar Oct 28 '19 09:10 vmedea

I know this issue is being worked on, but is there anything that users can do in the meantime to solve or mitigate the issue? With either termion or crossterm backends, I get a very noticeable flickering. I tried to batch calls to the Printer in the View::draw method of my Views, so that I would print a whole line at a time rather than a single character, but that didn't help at all (I have little understanding of the inner working of terminals).

HenryTheCat avatar Aug 03 '20 18:08 HenryTheCat

know this issue is being worked on, but is there anything that users can do in the meantime to solve or mitigate the issue?

Yes, I'm using @agavrilov's cursive_buffered_backend in my own project to work around this. It performs similar kind of buffering that curses does, queuing up changes then sending them at once at refresh, instead of sending every little update directly to the terminal. That solves the issue for me without having to do anything besides initialize it at start of the program.

vmedea avatar Aug 13 '20 09:08 vmedea