[GH-ISSUE #1664] CLI display flickers in SSH session on pull #26695

Closed
opened 2026-04-22 03:07:59 -05:00 by GiteaMirror · 13 comments
Owner

Originally created by @BruceMacD on GitHub (Dec 21, 2023).
Original GitHub issue: https://github.com/ollama/ollama/issues/1664

When pulling occasionally I see the loading bar flicker during and after download. This can be seen more dramatically on a fast connection.

System details:

OS: Debian 11
Terminal: Warp
Ollama: v0.1.17

https://github.com/jmorganca/ollama/assets/5853428/ec9c2410-f5c0-4a41-a9ef-73bee50b99f2

Originally created by @BruceMacD on GitHub (Dec 21, 2023). Original GitHub issue: https://github.com/ollama/ollama/issues/1664 When pulling occasionally I see the loading bar flicker during and after download. This can be seen more dramatically on a fast connection. System details: ``` OS: Debian 11 Terminal: Warp Ollama: v0.1.17 ``` https://github.com/jmorganca/ollama/assets/5853428/ec9c2410-f5c0-4a41-a9ef-73bee50b99f2
GiteaMirror added the bug label 2026-04-22 03:07:59 -05:00
Author
Owner

@vtrenton commented on GitHub (Dec 21, 2023):

This looks like a hardware acceleration issue with the terminal emulator. I could be way off here but I remember seeing stuff like this with Alacritty (another hardware accelerated terminal emulator) with other applications that use this style of loading bar. Also, unless I'm mistaken - it doesn't seem Warp is available for Linux yet (as per the site: https://www.warp.dev/) and doesn't seem to be open source. So im not sure how you're running this emulator (sorry if this is dumb and I'm missing something obvious here). Can you reproduce this in any other terminal emulators?

<!-- gh-comment-id:1867024813 --> @vtrenton commented on GitHub (Dec 21, 2023): This looks like a hardware acceleration issue with the terminal emulator. I could be way off here but I remember seeing stuff like this with Alacritty (another hardware accelerated terminal emulator) with other applications that use this style of loading bar. Also, unless I'm mistaken - it doesn't seem Warp is available for Linux yet (as per the site: https://www.warp.dev/) and doesn't seem to be open source. So im not sure how you're running this emulator (sorry if this is dumb and I'm missing something obvious here). Can you reproduce this in any other terminal emulators?
Author
Owner

@joshka commented on GitHub (Jan 11, 2024):

I see the same problem with iTerm2 on macOS.

<!-- gh-comment-id:1887106661 --> @joshka commented on GitHub (Jan 11, 2024): I see the same problem with iTerm2 on macOS.
Author
Owner

@pdevine commented on GitHub (May 17, 2024):

I tested this again in Terminal and iTerm2 and I'm not seeing it in either. I checked iTerm2 and it does have hw acceleration turned on. I'm going to go ahead and close this.

<!-- gh-comment-id:2118402642 --> @pdevine commented on GitHub (May 17, 2024): I tested this again in Terminal and iTerm2 and I'm not seeing it in either. I checked iTerm2 and it does have hw acceleration turned on. I'm going to go ahead and close this.
Author
Owner

@egmontkob commented on GitHub (Nov 6, 2024):

Kindly reopen.

This issue was closed incorrectly, without proper investigation, just blindly blaming two different terminal emulators and their hardware acceleration.

The flicker occurs with at least 10 different terminal emulators, some of which don't even have hardware acceleration.

ollama explicitly sends out \e[2K escape sequences that do ask for the bottom two rows to be cleared momentarily, that is, to flicker.

Please see the detailed analysis at https://gitlab.gnome.org/GNOME/vte/-/issues/2837.

<!-- gh-comment-id:2459946062 --> @egmontkob commented on GitHub (Nov 6, 2024): Kindly reopen. This issue was closed incorrectly, without proper investigation, just blindly blaming two different terminal emulators and their hardware acceleration. The flicker occurs with at least 10 different terminal emulators, some of which don't even have hardware acceleration. ollama explicitly sends out `\e[2K` escape sequences that do ask for the bottom two rows to be cleared momentarily, that is, to flicker. Please see the detailed analysis at https://gitlab.gnome.org/GNOME/vte/-/issues/2837.
Author
Owner

@kaueraal commented on GitHub (Jan 30, 2025):

I can observe this on macOS with various terminals (iTerm, macOS' own terminal, kitty, ghostty) with zellij as terminal multiplexer.

<!-- gh-comment-id:2625029319 --> @kaueraal commented on GitHub (Jan 30, 2025): I can observe this on macOS with various terminals (iTerm, macOS' own terminal, kitty, ghostty) with zellij as terminal multiplexer.
Author
Owner

@jeremyschlatter commented on GitHub (Feb 17, 2025):

I believe this issue is caused by the terminal rendering a frame in the middle of a UI update. In particular, rendering a frame after the previous line is cleared:

0667baddc6/progress/progress.go (L87-L93)

but before the updated line is rendered:

0667baddc6/progress/progress.go (L95-L101)

Some terminals support a synchronized output feature, where the program can send a pair of begin, end escape codes to the terminal so that the terminal will not render any partial content it sees between begin and end.

But there's also an even simpler solution that solves the problem on my machine: emit the entire state update as a single write. This requires writing the partial updates to a buffer, and then writing out the entire buffer in one go. That's what I implemented in #9079. As far as I know, this does not guarantee that the terminal won't render a partial frame. But I predict that it solves the problem in practice in almost all cases. I'd be interested to find out how it works for other folks who have observed this issue.

<!-- gh-comment-id:2664051677 --> @jeremyschlatter commented on GitHub (Feb 17, 2025): I believe this issue is caused by the terminal rendering a frame in the middle of a UI update. In particular, rendering a frame _after_ the previous line is cleared: https://github.com/ollama/ollama/blob/0667baddc658d3f556a369701819e7695477f59a/progress/progress.go#L87-L93 but _before_ the updated line is rendered: https://github.com/ollama/ollama/blob/0667baddc658d3f556a369701819e7695477f59a/progress/progress.go#L95-L101 Some terminals support a [synchronized output](https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036) feature, where the program can send a pair of _begin_, _end_ escape codes to the terminal so that the terminal will not render any partial content it sees between _begin_ and _end_. But there's also an even simpler solution that solves the problem on my machine: emit the entire state update as a single write. This requires writing the partial updates to a buffer, and then writing out the entire buffer in one go. That's what I implemented in #9079. As far as I know, this does not guarantee that the terminal won't render a partial frame. But I predict that it solves the problem in practice in almost all cases. I'd be interested to find out how it works for other folks who have observed this issue.
Author
Owner

@egmontkob commented on GitHub (Feb 17, 2025):

Synchronized output / atomic update, by far not supported by all terminals out there, can only be a hint. You can't enforce it, because if the closing sequence doesn't arrive within a reasonably short deadline, the terminal has to move on and print the already received data; it cannot afford to delay processing indefinitely and thus make the terminal entirely unusable for the user if the escape sequences don't actually arrive in pairs due to faulty / interrupted output.

Emitting the changes in a single write isn't a guarantee either. The writer may intent to emit a single chunk but may result in a short write which is later continued. The terminal line discipline, or any intermediate layer in between (e.g. ssh, tmux) can split the packet into smaller ones. Any terminal emulator might read smaller chunks and decide to update its UI after one of them.

These techniques could more or less lower the risk of flicker, but could not fully eliminate.

Why go for a fragile solution rather than a robust one, which is also probably the simplest? Just don't clear the display. Simply overwrite the old contents with the desired new one. (Clear to the end of the line after printing the new contents of the line, if you're not yet at the right margin and there's a chance that the old contents were wider than the new one.)

<!-- gh-comment-id:2664079745 --> @egmontkob commented on GitHub (Feb 17, 2025): Synchronized output / atomic update, by far not supported by all terminals out there, can only be a _hint_. You can't enforce it, because if the closing sequence doesn't arrive within a reasonably short deadline, the terminal has to move on and print the already received data; it cannot afford to delay processing indefinitely and thus make the terminal entirely unusable for the user if the escape sequences don't actually arrive in pairs due to faulty / interrupted output. Emitting the changes in a single write isn't a guarantee either. The writer may intent to emit a single chunk but may result in a short write which is later continued. The terminal line discipline, or any intermediate layer in between (e.g. ssh, tmux) can split the packet into smaller ones. Any terminal emulator might read smaller chunks and decide to update its UI after one of them. These techniques could more or less lower the risk of flicker, but could not fully eliminate. Why go for a fragile solution rather than a robust one, which is also probably the simplest? Just don't clear the display. Simply overwrite the old contents with the desired new one. (Clear to the end of the line _after_ printing the new contents of the line, if you're not yet at the right margin and there's a chance that the old contents were wider than the new one.)
Author
Owner

@jeremyschlatter commented on GitHub (Feb 17, 2025):

Thanks, @egmontkob! Your comments both here and in the vte thread were very helpful. I didn't read the vte thread closely enough when I wrote the first PR draft. I agree, the right solution is to just not clear the display. I've updated #9079 accordingly.

<!-- gh-comment-id:2664133672 --> @jeremyschlatter commented on GitHub (Feb 17, 2025): Thanks, @egmontkob! Your comments both here and in the vte thread were very helpful. I didn't read the vte thread closely enough when I wrote the first PR draft. I agree, the right solution is to just not clear the display. I've updated #9079 accordingly.
Author
Owner

@jeremyschlatter commented on GitHub (Feb 17, 2025):

Hmm. Though now I'm noticing that in this implementation the cursor still flickers, since we hide the cursor at the beginning of an update and show it again at the end of the update. Any terminal frames that render during the update now have progress bar content, but don't have a cursor, so the cursor flickers. I'm not sure what to do about this other than buffer the updates so the window of time with no cursor is small.

0667baddc6/progress/progress.go (L84-L85)

https://github.com/user-attachments/assets/00be8837-842b-4556-b3ff-444ba9583af4

<!-- gh-comment-id:2664153558 --> @jeremyschlatter commented on GitHub (Feb 17, 2025): Hmm. Though now I'm noticing that in this implementation the cursor still flickers, since we hide the cursor at the beginning of an update and show it again at the end of the update. Any terminal frames that render during the update now have progress bar content, but don't have a cursor, so the cursor flickers. I'm not sure what to do about this other than buffer the updates so the window of time with no cursor is small. https://github.com/ollama/ollama/blob/0667baddc658d3f556a369701819e7695477f59a/progress/progress.go#L84-L85 https://github.com/user-attachments/assets/00be8837-842b-4556-b3ff-444ba9583af4
Author
Owner

@jeremyschlatter commented on GitHub (Feb 17, 2025):

Ah, I see this was also addressed in the VTE thread: https://gitlab.gnome.org/GNOME/vte/-/issues/2837#note_2269501

I'll add buffering back in to minimize cursor flickers.

<!-- gh-comment-id:2664189851 --> @jeremyschlatter commented on GitHub (Feb 17, 2025): Ah, I see this was also addressed in the VTE thread: https://gitlab.gnome.org/GNOME/vte/-/issues/2837#note_2269501 I'll add buffering back in to minimize cursor flickers.
Author
Owner

@CoryLR commented on GitHub (Feb 18, 2025):

Just adding that I believe this is the same issue that was mistakenly reported in the Ghostty discussions:

This is an ollama bug, not Ghostty. They need to send synchronized output sequences to prevent tearing.

https://github.com/ghostty-org/ghostty/discussions/4048#discussioncomment-11699754

<!-- gh-comment-id:2664342722 --> @CoryLR commented on GitHub (Feb 18, 2025): Just adding that I believe this is the same issue that was mistakenly reported in the Ghostty discussions: > This is an ollama bug, not Ghostty. They need to send [synchronized output](https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036) sequences to prevent tearing. https://github.com/ghostty-org/ghostty/discussions/4048#discussioncomment-11699754
Author
Owner

@jeremyschlatter commented on GitHub (Feb 18, 2025):

Yes, same issue. I'm using Ghostty too. I can confirm that the fixes in #9079 work in Ghostty.

<!-- gh-comment-id:2664575207 --> @jeremyschlatter commented on GitHub (Feb 18, 2025): Yes, same issue. I'm using Ghostty too. I can confirm that the fixes in #9079 work in Ghostty.
Author
Owner

@egmontkob commented on GitHub (Feb 18, 2025):

Yes, unfortunately there's no way to make the cursor flicker-free, unless you permanently hide it. With the exception of a couple of scrolling/erasing sequence, in order to print new content you have to move the cursor there.

It's much less of an annoyance, and affects pretty much every app out there, it's not an issue I recall people complaining about.

That being said, emitting everything in a single step, and/or applying the synchronized update escape sequences (in addition to not erasing the contents you're about to overwrite) could help mitigate that problem of flickering cursor and make it almost nonexistent.

Thanks for working on a fix for this issue!

<!-- gh-comment-id:2664792670 --> @egmontkob commented on GitHub (Feb 18, 2025): Yes, unfortunately there's no way to make the cursor flicker-free, unless you permanently hide it. With the exception of a couple of scrolling/erasing sequence, in order to print new content you have to move the cursor there. It's much less of an annoyance, and affects pretty much every app out there, it's not an issue I recall people complaining about. That being said, emitting everything in a single step, and/or applying the synchronized update escape sequences (_in addition to_ not erasing the contents you're about to overwrite) could help mitigate that problem of flickering cursor and make it almost nonexistent. Thanks for working on a fix for this issue!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/ollama#26695