Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

Make emacs's internel more multi-threaded and user's editing flow smoother #378

Closed
harryfei opened this issue Aug 27, 2021 · 13 comments
Closed
Labels
discussion Discussion/Requested Feedback

Comments

@harryfei
Copy link
Member

harryfei commented Aug 27, 2021

Some heavy tasks in emacs tends to block user's editing flow. We could rewrite key functions of those tasks in a multi-thread manner.

We can collect the top-blocking things in this issue and discuss the proper solution to optimize them.

@harryfei harryfei changed the title Make emacs's internel more multi-threaded and user's editing flow more smooth Make emacs's internel more multi-threaded and user's editing flow smoother Aug 27, 2021
@black7375
Copy link
Contributor

black7375 commented Aug 27, 2021

This is a feature I really want.
Here are some ideas.

  • I/O is handled by TOKIO (Node.js's reactor pattern)
    • I think the biggest reason why Emacs is currently slow is because of blocking.
    • Tasks that require low latency, such as text typing, can be handled by classifying them as micro tasks, such as Flutter.
  • Treesitter as default highlighter
  • Decoupling scrolling from Lisp machine. Currently Pixel-Scrolling is done with lisp and it performs very poorly.

In addition, I think that performance can be improved by replacing some functions.

Editors to refer to written in rust

  • Zee: treesitter, ropey, fuzzy matching with walkdir
  • Helix: treesitter, ropey, lsp support
  • Xi Editor: rope, asynchronous operations, front-backend seperated

Currently, Emacs' built-in lisp functions and many c codes are not asynchronous, so some operations will be quite laborious.

@harryfei
Copy link
Member Author

harryfei commented Aug 27, 2021

Actually, Emacs have a poor but true async ability. emacs-aio wraps it in a nice way. However, it's not popular.

Emacs run itself in a single event loop drive by pselect.

@black7375
Copy link
Contributor

It was possible. I wonder why the emacs team doesn't care about async.

@CeleritasCelery
Copy link

My understand is that using a rope based buffer would preclude using the rust regex crate, since it does not support streams. Is that not the case?

Also is there any benchmarks demonstrating that ropey is faster then a gap buffer? It's hard to beat a gap buffer in the general case.

@dgutov
Copy link
Contributor

dgutov commented Aug 27, 2021

Any regexp implementation should be non-trivial to integrate anyway: Emacs regexps both have extra syntax and have operators dependent on the values of text properties in the buffer (the syntax-table text property, at least).

@black7375
Copy link
Contributor

black7375 commented Aug 28, 2021

  1. You're right. That's why I'm linking to the issue and not the RFC.
    If we want to use Rope we have to use regex-automata.
  1. Here is the benchmark code for ropey.
    There is no direct benchmark, but I expect the following differences in structure.
  • Gap buffer: Very light and fast for small files(kb). It is not good for multi-cursor because the gap position changes depending on the cursor position.
  • Rope: Fast for relatively large files(MB), and decent performance even in the worst case. But inefficient when files and edits are small.
    As mentioned earlier, support for async is relatively easy. (roepy issue, xi-editor README)

@harryfei
Copy link
Member Author

harryfei commented Aug 28, 2021

Rope: Fast for relatively large files(MB), and decent performance even in the worst case. But inefficient when files and edits are small.

But code source file tends to be small

@black7375
Copy link
Contributor

Yeah. it's a trade-off.
The disclaimer is that rope's easy to implement asynchronously, and on a small scale it's hard for humans to notice that it's slow. https://josephg.com/ropereport/ropes/ropey/1000000/report/index.html

@cessen
Copy link

cessen commented Aug 28, 2021

Author of Ropey here. Please note, in no way am I trying to push Ropey's usage here. I just find the discussion interesting, and wanted to toss in a couple thoughts.

I don't think the tradeoff between gap buffers and ropes is really about file size. At small file sizes anything will work. You could just use a plain contiguous string if you wanted, and it would be totally fine. The whole point of using something like a gap buffer or rope or piece table or whatever is to avoid the shortcomings of something like a contiguous string as files get larger.

Gap buffers are actually great for large files, as long as the editing patterns are favorable. Specifically, for localized edits gap buffers are O(1), which is amazing. And for single-cursor editors, localized edits are pretty much the only case that needs to be handled interactively. So gap buffers are great (even with huge files) for such editors. However, gap buffers degrade to O(N) as edits get less and less localized. So if you want your editor to support non-localized editing patterns, gap buffers probably aren't great.

Ropes make a different performance trade-off, being a sort of "jack of all trades". They're not amazing at anything, but they're always solidly good with O(log N) performance. They're not the best choice for an editor that only supports local editing patterns, since they leave a lot of performance on the table compared to gap buffers in that case (again, even for huge documents). But for an editor that encourages non-localized edits, or just wants flexibility in that regard, they're a great choice because they always have good performance, whereas gap buffers degrade poorly with unfavorable editing patterns.

In other words, regardless of file size, gap buffers have both a better best case and worse worst case compared to ropes.*

It's worth noting, however, that even multiple cursors are frequently quite localized. Most of the time I use them, for example, all cursors are still in view (or nearly so). It's really only with editors that are built around multiple cursors as the way to edit things that you commonly do interactive non-local edits.

So for something like emacs, I suspect any real arguments in favor of ropes or piece tables (or whatever else) aren't going to be about editing performance, but rather are going to be about secondary features like cheaply taking "snapshots" of a document to save it asynchronously, etc.

* (Well... in practice many ropes have large leaf nodes--Ropey's are between 512 and 1024 bytes, for example. So you do need to get to at least a few kilobytes or so before that's true in practice. But you also have to get even larger than that before using a contiguous string would be a problem, so that's not really the scale where any of this is relevant anyway.)

@harryfei
Copy link
Member Author

Do anyone have idea how can we integrate tree sitter?

@CeleritasCelery
Copy link

Why not just use the package?

https://emacs-tree-sitter.github.io/

@brotzeit brotzeit added the discussion Discussion/Requested Feedback label Aug 30, 2021
@shaunsingh
Copy link

IMO treesitter (and anything else that can be shipped as a standalone package) should be left that way.

@ReggieMarr
Copy link

IMHO decoupling scrolling from the lisp machine and potentially using ropey would be high value items. I currently find that when opening multiple large files (particularily on large monitors) emacs just can't cope (as in i/o starts lagging considerably).

I'd be willing to assist in this effort however I'm not entirely sure where to start.

@emacs-ng emacs-ng locked and limited conversation to collaborators Feb 20, 2023
@declantsien declantsien converted this issue into discussion #471 Feb 20, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
discussion Discussion/Requested Feedback
Projects
None yet
Development

No branches or pull requests

8 participants