-
-
Notifications
You must be signed in to change notification settings - Fork 864
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
[Discussion] json dynamic module #676
Comments
It sounds like opening up a world of hurt, when we have to have a compiled module available on all the platforms that emacs supports. Perhaps if it could be something that can be used if available, but falls back to the current one if needed. And having some sort of wrapper executable that can talk s-exps on the one side and JSON-RPC on the other might provide a solution too. |
That's the plan.
Yes, this is an option too - we could use a tool to convert the json to the s-exps and then use built-in (Haskell is also on the table via https://github.com/sergv/emacs-module ) |
What are the pros and cons of each option? What tool do you have in mind to convert between JSON to sexps? Is there anything already available? What's the benefit of using Haskell for this instead of C++/Rust? |
We need to investigate what will work best given the present limitations. E. g. if we cannot do fast conversion to Elisp structures in emacs dynamic module then we may try the intermediate conversion to s-exps.
I am not aware of such tool. We may write a command line tool or dynamic module which converts the jsons to serializes elisp data structures .
I added it for completenes. If it is easy to distribute it and if it is fast enough I think that there is no reason stopping us from using haskell...(and if someone wants to do it). |
There is an article on how to write a async dynamic module by @skeeto - https://nullprogram.com/blog/2017/02/14/ . |
Will it be possible to port Emacs 27's json.c to dynamic module in a simple way? |
@cireu - it is an option too - IMO the main problem is how to convert effectively the parsed structure to elisp data structure and we cannot use json.c code for that since it has access to the internal emacs api(e. g. it can call the methods directly). There is also: https://github.com/syohex/emacs-parson (which I havent had a chance to test). |
I found the following post by @Alexander-Miller : https://www.reddit.com/r/emacs/comments/8plc1c/a_recipe_for_creating_parallel_futures_using/ It shows how to do async processing in emacs module which seems like exactly what we want to do. |
I haven't done any real performance testing with this thing, so you should be careful with that. One basic optimization I can think of is not to spawn a new elisp thread for every call that is being made. By the way have you tried async.el for non-blocking parsing? This seems like the kind of use-case it'd be well suited for.
IME a native module will do you little good if you're constantly calling back to the emacs runtime to make your conversions. That comes with its own considerable call and marshalling overhead, especially when you're dealing with strings. Whatever you do, you should do it in one go. Creating a string and feeding it straight into the interpreter is definitely worth trying, and I successfully used this method in treemacs where one of my python scripts directly returns a string like "#s(hash-table ...)". And a note about languages: I tried to write a small dynamic module for treemacs in both C and Rust. The C version was incredibly verbose and error- and segfault-prone and just plain took a great deal of time and effort to get working (admittedly I don't really know any C). Rust was the complete opposite, its emacs bindings provide a great set of abstractions, so for the most part I didn't even notice that I was writing code for emacs. I didn't cause a single segfault or memory error either. The Rust code was even significantly faster, thanks to the WalkDir library. So yeah, rustc is not as widely available as gcc, but it will make actually writing a working module a whole lot easier. |
@Alexander-Miller thank you for jumping in.
We need non-blocking and fast(fast is more important). Correct me if I am wrong but if we delegate the parsing to emacs-async process this will slow down the parsing.
Thanks for the info. We still need to benchmark such code vs json.el parsing but it seems like it may not result in the needed speedup. |
It's non-blocking, but it won't be faster - you still have the launch and marshal overhead from the secondary emacs process.
You're probably better off transforming the json into sexps. Also depending on the same of the responses you might be better off deserializing into hash tables instead of alists. The cut-off point for the former being faster is at about 20 elements. |
I think this is the most promising approach. If we keep doing it in the UI thread, there will still be UI freezes, even with json.c, for large payloads. Moreover, a dynamic module won't have access to Emacs internals, like json.c does, so there will be more overhead (data copies, calls into Emacs runtime, unavoidable string validations, ...).
There shouldn't be an issue here. It's a matter of correctly using the ref-count interface (
This is my worry as well. One solution would be wrapping the parsed native messages in opaque Do we have some automated editing scenarios, e.g. replaying editing command sequences on a particular codebase? They would be useful in prototyping/benchmarking solutions. |
Both dynamic modules and json.c are considered external code and both perform validation of the strings which at this point is very slow because it may trigger external hooks, see https://lists.gnu.org/archive/html/bug-gnu-emacs/2019-03/msg00722.html .
I wonder whether that conversion could be optional in Emacs e. g. whether emacs could have a flag "trust-this-source and do not do the conversion/validation"(actually whether emacs-devel will accept such a behavour). If we have that we will be able to match the performance of native Emacs code?
Are you saying that emacs dynamic module could create a thread use the Env to create emacs primitives?
I was thinking about the same but I wonder whether there is the same performance overhead when you are calling dynamic module from elisp code and we will end up with worse performance when you want to consume the whole input.
No, I have few sample responses. |
We can request emacs-devel to add the ability to bypass string validation with a flag, as you suggested, or through new additions to
There are 2 potential approaches:
I'm not sure yet whether 2. will work. It depends on how functions from
If we consume the whole output, the total overhead will be the same. Threads and |
Thank you for mentioning that option.. Few comments:
You might be right but that would require lsp-mode to be able to work against two different structures since in case we make the dynamic module optional. |
I did some experiment and checked
Right. I think we should further investigate option 1 with full conversion, and experiment with:
|
Closing as won't fix - apparently, this is not going to be implemented generally due to the emacs dynamic module limitations. Feel free to reopen it if you want to work on that |
Just want to resurrect this old idea. With lsp-protocol.el we have almost abstracted all of the access to the protocol data structures so the ability to work against 2 data structures is kind of for free. |
The performance bottleneck of
lsp-mode
is json parsing(50%+ of the time) and we already have a solution for Emacs 27+ via new native parsing. This PR is for tracking the discussion about solving this problem for emacs 25-26 with writing emacs dynamic module - https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Modules.html .We have some code in https://github.com/sebastiencs/emacs-json (see sebastiencs/emacs-json#1 )
@innerout volunteered to work on a such module In C/C++(and eventually RUST?) but we need a general agreement for the approach from the team members and the active contributors.
Also, I was thinking about creating a JSONRPC dynamic module which will do the message handling in separate thread(not blocking the Emacs UI thread) and then post the messages to Emacs. (not sure whether this is possible or whether it might cause Elisp GC failures)
(cc @MaskRay @sebastiencs @innerout @vibhavp @danielmartin @alanz)
The text was updated successfully, but these errors were encountered: