Skip to content
This repository has been archived by the owner on Apr 25, 2020. It is now read-only.

Support multiple projects with a single ghc-modi instance #253

Closed
darthdeus opened this issue May 11, 2014 · 33 comments
Closed

Support multiple projects with a single ghc-modi instance #253

darthdeus opened this issue May 11, 2014 · 33 comments

Comments

@darthdeus
Copy link

I'm not sure if I'm not doing something wrong, but I've just installed ghc-mod after using hdevtools for a while, and found that it's order of magnitude slower, even on a small project (2-5 seconds, while hdevtools was kinda instant).

I asked around on IRC and people told me that it runs pretty fast for them, so I'm not sure if I could me missing something? I also have a clean install of GHC 7.8.2, maybe there's a performance regression on the newer version? (I'm not sure if that's even possible)

@DanielG
Copy link
Owner

DanielG commented May 11, 2014

What version of ghc-mod are you using and what operation exactly is taking long?

What kind of disk are you using, and can you try time ghc-mod boot >/dev/null in that project you mention.

@darthdeus
Copy link
Author

I'm using an SSD drive with i7 quad core processor.

$ time ghc-mod boot > /dev/null                                       
ghc-mod boot > /dev/null  0.30s user 0.07s system 79% cpu 0.470 total

I've tried ghc-mod type, which in a sample yesod app is

$ time ghc-mod type app/main.hs Main 8 10 
ghc-mod type app/main.hs Main 8 10  3.26s user 0.72s system 72% cpu 5.450 total

in a trivial 30 line source file

$ time ghc-mod type main.hs Main 14 1
ghc-mod type main.hs Main 14 1  0.46s user 0.15s system 88% cpu 0.689 total

It seems that when I invoke :GhcModType in VIM it takes a bit longer, but that's probably expected.

Just for comparison here's hdevtools, unfortunately I couldn't get it to work with the yesod app so I only have the example from the small app, but it's still about 20 times faster.

$ time hdevtools type main.hs 14 1
hdevtools type main.hs 14 1  0.00s user 0.01s system 28% cpu 0.035 total

@darthdeus
Copy link
Author

It's also probably worth mentioning, that if I run :GhcModType once and then immediately again, it is almost instant, but once I do :GhcModTypeClear and run :GhcModType again it takes the same amount of time as initially.

@DanielG
Copy link
Owner

DanielG commented May 11, 2014

hmm ghc-mod type has always been rather slow for me too but I'm using an ancient T60 so that's expected ;) but on an i7 with an SSD it should be fairly snappy but I'm not sure.

I was going to do some profiling and possibly optimization of ghc-mod anyways so I'll see if I can find out why it's so slow when I get around to it.

In the meantime you might want to suggest to the author of your VIM plugin to add support for ghc-modi wich should only incur the delay on startup or when visiting a new file.

@darthdeus
Copy link
Author

As it turns out you were right. I tried using ghc-modi and it's basically instant, so the problem is in the VIM plugin. I've opened an issue in there eaglemt/ghcmod-vim#48, but I'm not sure if this is possible to be solved on VIM's side.

I thought that maybe as a workaround I could write a wrapper script on ghc-modi, which would run it as a separate process on the background the first time it's invoked, and the next time it would just proxy the command to the background process and return a response. This would mean that the vim plugin would just have to change the executable name it's using, as it doesn't seem to be easy to manage processes in VIM itself.

Does that sound reasonable, or do you think there's a better way to solve this?

@DanielG
Copy link
Owner

DanielG commented May 17, 2014

That sounds like a pretty good workaround.

@kazu-yamamoto
Copy link
Collaborator

Maybe, ghc-mod should provide such a feature if possible.

@darthdeus
Copy link
Author

@kazu-yamamoto It shouldn't be too hard to implement. I haven't looked at ghc-mod source code yet.

But out of curiosity I wrote a small wrapper as described which runs ghc-modi on background and communicates with the client via a unix socket. Here's a proof of concept https://github.com/darthdeus/ghc-modi-wrapper.

It will be a lot easier if this is done in ghc-mod itself, since all the necessary logic is already there and we would just need to add something like ghc-mod --start/stop and then maybe a flag which would cause things like ghc-mod check to use the server process running on the background and talk to it via a socket, instead of parsing things every time. What do you think?

@kazu-yamamoto
Copy link
Collaborator

Yes, I think you are right. If you kindly contribute such a code, it would be highly appreciated.

@DanielG
Copy link
Owner

DanielG commented May 18, 2014

Yeah, I was thinking about that. Doing a bunch of caching stuff and speeding up ghc-mod is definitely on my TODO list anyways. I was mostly thinking about speeding up module/function completion by having a frontend with minimal dependencies that checks a cache and calls the real ghc-mod executable on demand if the cache is invalid or nonexistent (minimal dependencies because on some of my slower machines with little memory just loading the 200MiB+ ghc-mod executable takes a considerable amount of time and caching doesn't help much because I have so little memory on those machines that the cache gets constantly invalidated). So having a long running ghc-mod process that we can query as well when a look up fails (or is something we can't cache properly like the type) would fit this model pretty well too but for the sake of supporting machines with scarce memory weather or not we spawn a server process should probably be configurable.

@darthdeus
Copy link
Author

I agree that this should be configurable. I also have a tiny laptop which barely runs anything, so I can totally see that usecase.

So I guess I'll try to port my gem to ghc-mod and see how it works out.

@kazu-yamamoto
Copy link
Collaborator

Just in case, I designed that one ghc-modi process runs for one package. It cannot be not shared by multiple packages at this moment.

@darthdeus
Copy link
Author

But running multiple ghc-modi instances at the same time in different packages shouldn't be a problem, right?

@DanielG
Copy link
Owner

DanielG commented May 18, 2014

Apart from the insane memory consumption ;)

@DanielG
Copy link
Owner

DanielG commented May 18, 2014

Allowing multiple projects in ghc-modi shouldn't be too hard basically you need seperate HscEnvs, Cradles and Options' (all part of GhcModEnv in Language.Haskell.GhcMod.Monad) for all the projects and then use local to switch between them based on the cradleRootDir (in turn based on the CWD of the frontend process, which should be passed to ghc-modi) in loop, in GhcModi.hs

@kazu-yamamoto
Copy link
Collaborator

As @DanielG said, there is no problem to run multiple ghc-modi (except memory usage). Emacs front-end actually does this.

To support multiple packages in ghc-modi, the protocol should be changed so that clients can identify their packages.

@kazu-yamamoto
Copy link
Collaborator

Before merging the pull request above, I would like to make consensus on two items:

  1. Protocol syntax
  2. Package management

For (1): ghc-modi should be independent from working directory if multiple packages are supported. That means that ghc-modi should not search a sandbox when executed, resulting in no cache of packages in advance. This is a problem. Also, we need to change the protocol syntax so that client can identify a package name. E.g. check <file> <path_to_package>. Maybe, ghc-modi should try to find a sandbox, cache packages and use it as default environment. This makes the <path_to_package> is optional. If omitted, the default environment (for the package guessed from the current directory) is used.

For (2): if a sandbox is used, the cache of package may be small enough at this moment. But if not, all user packages, which may be large, should be cached. This is a problem described in #243. We need to consider how to manage the cache efficiently when multiple packages are supported. This issue is not caused by multiple packages but I would like to discuss at the same time. Honestly, I have no idea to resolve this.

@DanielG
Copy link
Owner

DanielG commented May 19, 2014

I would just add a command line option (like --server) to ghc-modi that tells it that it's being used as a backend for multiple projects, in this case it would not search for a sandbox in the CWD but rather defer this until it gets commands. If this flag is not passed it just behaves like it does now. So adding an optional path argument to all ghc-modi commands should be fine.

@kazu-yamamoto kazu-yamamoto changed the title Very slow GhcMod server (was: Very slow) Aug 13, 2014
@DanielG DanielG changed the title GhcMod server (was: Very slow) Support multiple projects with a single ghc-modi instance Aug 20, 2014
@kazu-yamamoto
Copy link
Collaborator

According to IRC chat with @DanielG, we will not implement the server (daemon) feature (at least in the near future). ghc-modi is designed as an interactive process like shell, not a server. This design ensures that ghc-modi is certainly terminated, for example, by Emacs. The problem of multiple lib/exec/test-suites in a package should be fixed in the no-set branch.

@DanielG
Copy link
Owner

DanielG commented Sep 19, 2014

I think you misunderstood, I do plan to make ghc-mod --interactive talk to a daemon process (that is yet to be named) over TCP which ensures we can count how many connected fronted processes there are and kill the daemon when it's unused. I am working on adding a datatype for the protocol that the daemon is going to use as we speak.

@kazu-yamamoto
Copy link
Collaborator

Let me clarify:

  • Are you talking about ghc-mod, not ghc-modi?
  • Is ghc-mod --interactive an alternative to ghci?

@DanielG
Copy link
Owner

DanielG commented Sep 19, 2014

  • ghc-mod --interactive is going to be the ghci compatible interface that I was talking about.
  • I am definitely planning on having ghc-mod talk to the daemon.
  • ghc-modi could also benefit from talking to the daemon but I'm not planning on doing that soon.

@kazu-yamamoto
Copy link
Collaborator

OK, I understand.

@kazu-yamamoto
Copy link
Collaborator

Is one daemon executed on a PC node? Or is one daemon executed for each Haskell project?

@DanielG
Copy link
Owner

DanielG commented Sep 19, 2014

I'm not sure yet, I'll decide when I get around to that.

@kazu-yamamoto
Copy link
Collaborator

I'm worry about how to ensure that the daemon is terminated.

@kazu-yamamoto
Copy link
Collaborator

Also, I'm afraid that daemons cannot be implemented on Windows because the "unix" package is necessary.

@DanielG
Copy link
Owner

DanielG commented Sep 19, 2014

Well every frontend process (ghc-mod, ghc-mod --interactive, [ghc-modi]) would connect to the daemon via a SOCK_STREAM (i.e. connection oriented) socket. In this mode sockets notify the server when clients disconnect so we can count how many clients the daemon has and as soon as no one is left wait for another few seconds (in the case of consecutive calls to ghc-mod) and then terminated if no one is connected.

unix is not necessary the BSD socket API was adopted by most UNIXies and Windows. Also http://hackage.haskell.org/package/network doesn't depend on unix.

@kazu-yamamoto
Copy link
Collaborator

To daemozie a process, forkProcess is necessary.

@DanielG
Copy link
Owner

DanielG commented Sep 19, 2014

Oh, I see what you mean. There is a way to do it on windows I'm sure, I'll check once I get around to it.

As a fallback we could simply disable the demonetization on windows and start the daemon in a separate IO thread.

@denibertovic
Copy link

@DanielG @kazu-yamamoto is this still happening or? what's the status?

@DanielG
Copy link
Owner

DanielG commented Oct 15, 2014

I got stuck working on the wire protocol because university started up again, but this is certainly still on the roadmap, it's just a matter of when ;)

@DanielG
Copy link
Owner

DanielG commented Jan 8, 2016

I think this has become out of scope for ghc-mod and is going to be implemented in haskell-ide-engine instead.

@DanielG DanielG closed this as completed Jan 8, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants