Enter iserv-proxy
ClosedPublic

Authored by angerman on Feb 27 2017, 11:15 PM.

Details

Summary

With the introduction of -fexternal-interpreter we are
now able to compile template haskell via an extern iserv process.

This however is restricted to the same host, and can therefore
not be used with crosscompilers where the iserv slave process
needs to run on a different machine than the cross compiling
haskell compiler.

This diff breaks up iserv into a library and the iserv-bin binary.
It also introduces the iserv-proxy, a proxy instance that the
haskell compiler can talk to, and which forwards the calls
to the iserv slave on a different machine, as well as providing
some extra functionarily (sending files that are not available
on the machine the slave runs on), as well as forwarding from
the slave to the haskell compiler, when the slave needs to
interrogate the haskell compiler.

The iserv library now also exports the startSlave function to be
called by the application that implements the slave on the target.

The simplest such app would probably look something like:

extern void startServ(bool, const char *);

int main(int argc, char * argv[]) {
  hs_init(NULL, NULL);
  startServ(false,"/tmp");
  while(1);
}

Special thanks to Shea Levy for the first draft of the iserv-remote,
from which I took some inspiration.

The Buildable flags are due to ghc-cabal not being able to build
more than a single target. Please note that only the stock iserv-bin
is supposed to be built *with* ghc. The library and proxy are supposed
to be built outside of ghc. Yet I believe that this code should live
together with iserv.

Diff Detail

Repository
rGHC Glasgow Haskell Compiler
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.
angerman created this revision.Feb 27 2017, 11:15 PM
ezyang edited edge metadata.Feb 27 2017, 11:24 PM

Thanks, this is very interesting. What kind of documentation do you think would be appropriate for a feature like this?

In D3233#93640, @ezyang wrote:

Thanks, this is very interesting. What kind of documentation do you think would be appropriate for a feature like this?

For, now I'd prefer this to be a somewhat dormant feature, without too much visible information just yet. Ideally though,
we'd have some sample iOS, Android and RPi programs, and then a section in the user manual about installing and running
those apps, and pointing ghc to them for CC with TH.

I'd therefore advocate to not add much documentation for this just yet. Focus on the other moving parts (independent of
iserv) and once we have a coherent story (iserv-proxy, linker and slave programs), add a section to the user guide.

@ezyang Does that sound reasonable to you?

simonmar edited the summary of this revision. (Show Details)Feb 28 2017, 7:40 AM
simonmar edited edge metadata.Feb 28 2017, 8:07 AM

Why does the proxy need to understand the content of messages, rather than just forwarding data in both directions whenever it arrives? In fact, it makes me wonder whether the proxy can't be a script wrapping netcat or something like that. Perhaps the answer to this is the extra SlaveMessage protocol for sending files - but I wouldn't object to making this part of the main protocol, unused in the case of a local server. It's quite confusing that we have these extra messages exchanged between the slave and proxy in certain circumstances.

iserv/iserv-bin.cabal
10–59

spelling & capitalise: "Template Haskell"

30

-pgmi, not -fpgmi, -opti not -fopti

34

"following recipe"

36

I think you want some markup here (and in general over the rest of the description)

38–39

Why does this have to be a C program? Why can't we have a Haskell executable for iserv-slave?

iserv/proxy-src/Remote.hs
8

"might"

12

"GHC", "actual", "Haskell"

16

to what?

26–31

Nice diagram!

105

Maybe the port number should be configurable?

iserv/src/Remote/Message.hs
4

Please fix the long lines.

angerman updated this revision to Diff 11440.Feb 28 2017, 8:17 PM
  • Update wrt Simons change request.
angerman marked 11 inline comments as done.Feb 28 2017, 8:48 PM

Why does the proxy need to understand the content of messages, rather than just forwarding data in both directions whenever it arrives? In fact, it makes me wonder whether the proxy can't be a script wrapping netcat or something like that. Perhaps the answer to this is the extra SlaveMessage protocol for sending files - but I wouldn't object to making this part of the main protocol, unused in the case of a local server. It's quite confusing that we have these extra messages exchanged between the slave and proxy in certain circumstances.

@simonmar Thank you for taking the time and giving this a thorough review!

The need to understand the messages is a bit of an annoyance, I concur. We currently have Three types of Messages:

  • GHC -- proxy -> iserv: Message, which is the communication from GHC to iserv (to instruct iserv what to do)
  • GHC <- proxy -- iserv: THMessage which is the communication from iserv to GHC (for TH interrogation)
  • proxy <- iserv: SlaveMessage which is the communication from iserv to the proxy. (for File lookup).

Making SlaveMessage part of Message would be the wrong direction I believe.

Another case I'd like to make for SlaveMessage, is that the iserv-proxy and iserv-library are both optional. And not
built by default. Hence do not incur any extra dependencies on the libraries ghc needs to ship. Hence there is a bit more
freedom in the use of libraries in for the proxy <-> iserv-slave logic.

Can't we replace the proxy with netcat? Right now, I believe if we moved the file lookup logic into ghc. If we opted for
a wrapper script, without the file lookup logic in ghc, the wrapper script still needed to be able to understand the
messages. I'm also in favor of having the proxy in haskell and not depend on some other external tool.

However the main reason why I believe having the proxy in haskell is, that I do not believe that the current functionality
of the proxy is where things will end.

There are a few more things that need to be figured out down the lane. (Right now this does in fact already work.)

  • How do we handle IO Actions in the Q Monad on the target (iserv slave)? Do we want those to be evaluated on the target or on the host? Do we even want to distinguish which IO actions to run on the target and which on the host?
    • file-embed or git-embed come to mind for IO actions that should be evaluated on the host rather than the target (or the target needs some virtual file system reflecting that of the host),
    • other TH tricks I've heard of use IO to play tricks with pointers and compute sizes, these I would believe should be evaluated on the target.
  • GHC calls iserv and simply expects it to work. However depending on the target platform, we might need to actually launch the iserv slave (if possible). E.g. on iOS, I currently start the iserv slave by hand.
  • We might only have a single iserv slave, as the target can't run multiple applications in parallel. (iOS for example; Even if you try to circumvent background suspension via VoIP exemptions, you are still limited on the number of development apps that can be installed in parallel -- and you would have to graft custom application ids for each).
  • Thus the proxy might need to grow the capability of launching the slaves, and possibly multiplexing the incoming compilation requests on a number of targets (say, 2 iphones, 2 ipads)

Note that these features are not implemented, and might need some changes to how things are performed right now. I prefer
a gradual implementation of this, and start with the very basic solution, as posted, and keep improving upon it, while seeing
what other requirements arise.

iserv/iserv-bin.cabal
38–39

It doesn't necessarily have to be a c program. I tried to clarify that point a little. This likely depends on the
capabilities of the target where the iserv is running, if it is possible to deploy a haskell app right away or
if some target specific glue code in some target specific language is required.

Let's take for example this iOS main.m Obj-C file:

extern void startSlave(bool, int, const char *);

int main(int argc, char * argv[]) {
    const char * documents_path = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject].path.UTF8String;
    
    hs_init(NULL, NULL);

    startSlave(false, 5000, documents_path);
    
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, nil);
    }
}

We could technically write this in Haskell (if we had TH support already (yey for bootstrapping issues), we could probably even use InlineObjC or something like that for this.).

However, the above code is probably easier to write and read than making that work with Haskell right now.

iserv/proxy-src/Remote.hs
16

I hope the addition of that makes this understandable? If not I might have to reword this completely.

What I'm trying to say is, that there is a slave to which ghc delegates compilation of Template Haskell.

26–31

Thanks! :) I found myself getting easily confused, as to which part
of I was actually working with, so I drew this up.

angerman updated this revision to Diff 11522.Mar 2 2017, 7:25 PM
angerman marked 3 inline comments as done.
  • rebase onto master
simonmar accepted this revision.Mar 6 2017, 3:59 AM

Ok, thanks for taking the time to explain the rationale for the design. I understand that things are evolving, my main concern is that we should be careful to capture the rationale in such a way that someone reading the code in the future can understand the constraints on the design - so preferably include Notes that explain why things are the way they are (in particular why we need to parse messages in the proxy), or use wiki pages with links from the code.

I would execute all the IO on the target, to get a simple compilation model. If you're running IO on the host, then you need to have another iserv, compile all the code twice, etc., it gets really complicated.

This revision is now accepted and ready to land.Mar 6 2017, 3:59 AM
angerman updated this revision to Diff 12029.Apr 7 2017, 4:53 AM
  • rebase against master
This revision was automatically updated to reflect the committed changes.