The postings on this site are the contributor's and don’t necessarily represent IBM’s positions, strategies or opinions.
October 22nd, 2009 Alex Moffat Posted in GWT | No Comments »
I’ve done some more work on my distributed GWT compilation system and it’s now at the point where I’m able to use it for development compilation at work. There are three parts to the system, one of which I had hoped to avoid.
First, there is the PrecompileAndLink program. This is a drop-in replacement for the com.google.gwt.dev.Compiler that accepts the same command line arguments (well the publicly documented ones anyway). If no other parts of the system are running PrecompileAndLink will behave the same as the google Compiler, it precompiles the Java to an AST (abstract syntax tree), uses that to create the JavaScript for each permutation, and then links the results.
The next piece is RemoteCompile. You want to arrange to have as many people as possible each run an instance of RemoteCompile on their computer. RemoteCompile performs just the compilation step, the conversion from the AST to JavaScript, and doesn’t need access to any of the source code being compiled to do it. The plan is that PrecompileAndLink does the precompilation and then offloads as much compilation work as possible onto RemoteCompile instances running on other machines. Though it takes time to send the AST over the network the gains made by being able to run many more compilations in parallel will outweigh this, especially if you have lots of permutations because, for example, you are building localized versions of your application. RemoteCompile sends the JavaScript it creates back to PrecompileAndLink instance the AST came from.
Finally there is CompileRegistry. This keeps track of the RemoteCompile instances that are available and is used by PrecompileAndLink to find them. I had hoped to avoid creating something like this. My original implementation used JmDNS to let PrecompileAndLink instances discover RemoterCompile instances without needing any configuration. However, this had a couple of problems. Firstly, there sometimes wasn’t time between when PrecompileAndLink started running and when it needed the information for JmDNS to discover the RemoteCompile instances that were available. Secondly, the network at work is segmented in such a way that the multi-cast DNS messages needed for JmDNS to work can’t pass between some of the machines. To solve these problem I decided to have a central registry.
If you want to try this out here are some simple steps that will compile your code with GWT 1.7.0.
1. Download the distributedcompile-nogwt.jar file.
2. Start the CompileRegistry. You can choose any port number you want greater than 1024. The program prints out the address that it’s listening on. You need to provide both distributedcompile-nogwt.jar and your platform specific gwt-dev jar file on the class path.
java -cp distributedcompile-nogwt.jar:gwt-dev-mac.jar com.lombardi.tools.registry.CompileRegistry -port 1099 Listening on 192.168.1.164:1099
3. Start a RemoteCompile instance. You need to tell this how many local worker threads it should use and what the address of the CompileRegistry is. As with CompileRegistry you need to supply the gwt-dev jar file as well.
java -Xmx1024m -cp distributedcompile-nogwt.jar:gwt-dev-mac.jar com.lombardi.tools.remotecompile.RemoteCompile \ -registry 192.168.1.164:1099 -localWorkers 2 -logLevel INFO RemoteCompile is ready. Listening on 192.168.1.164:65160. Providing 2 worker threads.
The CompileRegistry will print out a message showing that the RemoteCompile instance has connected.
Currently aware of 1 compile server(s)
RegisteredServer{address=alex-moffats-macbook-pro-15.local/192.168.1.164, port=65160, gwtVersion='1.7.0'}
4. Modify your compile script so that distributedcompile-nogwt.jar appears in your classpath, and change from com.google.gwt.dev.Compiler to com.lombardi.tools.precompileandlink.PrecompileAndLink. You need to be using GWT 1.7.0. Provide “-logLevel INFO” argument to the compile.
When the compile runs you’ll see output like this
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] PrecompileAndLink starting.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] Loading module.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] Module loaded in 1.054 seconds.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] Starting precompile.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] Precompile produced 6 permutations in 11.811 seconds.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] Found 1 remote RemoteCompile servers.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] 2 permutations sent for remote compilation.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] 4 permutations remain.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] Will compile 2 locally now.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] Found 1 remote RemoteCompile servers.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] 0 permutations sent for remote compilation.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] 2 permutations remain.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] Will compile 1 locally now.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] Found 1 remote RemoteCompile servers.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] 0 permutations sent for remote compilation.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] 1 permutations remain.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] Will compile 1 locally now.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] Compilation completed.
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] Link started.
[java] Link succeeded
[java] [com.lombardi.examples.distributedcompile.DistributedCompile] Link finished.
You’ll also see the RemoteCompile instance report as it compiles permutations provided by the PrecompileAndLink program. For example
Compiling perm 0 of com.lombardi.examples.distributedcompile.DistributedCompile Compiling perm 1 of com.lombardi.examples.distributedcompile.DistributedCompile Finished perm 0 of com.lombardi.examples.distributedcompile.DistributedCompile Finished perm 1 of com.lombardi.examples.distributedcompile.DistributedCompile
Just use Control-C to shutdown the RemoteCompile and CompileRegistry programs.
There are still a few cleanup tasks to complete. First, PrecompileAndLink should prefer to use remote RemoteCompile instances over local ones. Second, RemoteCompile could monitor its memory usage to help it decide whether to accept another compile request. Third, some way to pause a RemoteCompile instance so that it doesn’t accept any more compile requests. This would make it easier to leave a RemoteCompile instance running on a machine and pause it when the machine is needed for some other work. Fourth, I still need to implement some retry logic if PrecompileAndLink doesn’t receive a result from a compile it has submitted within a reasonable amount of time.
Anyway, here’s the compiled code for you to try distributedcompile-nogwt.jar and the source for you to look at distributedcompile-src.tar.
Leave a Reply