I've been on a journey to find a way to run PicoLisp on my windows laptop for web development. At one point I started to extend miniPicolisp with win32 socket calls but that proved to be more work than I would like. Next, I tried running a virtual linux through qemu. That worked pretty well, but I wanted to see if I could eke out better performance. I then switched to coLinux and acheived even getter performance. I still wanted more, so I started looking into ersatz.

TODO:

I'd like to further this example by adding methods for the response as well and then build a complete example

Test Setup:

1. jmeter with 30 threads

All tests were running from my windows box. The virtual linux examples (qemu and coLinux) I set up a port forward to enable an outside connection from the host to the guest. For qemu, the networking performance of the usermode driver was the major limiter. When I ran it using apache bench on the guest, I saw around ~120 requests/sec but only ~10 when connecting external.

Benchmarks:

  1. PicoLisp running under qemu (~10 requests/sec) *need to rerun to confirm
  2. PicoLisp running under coLinux (120 requests/sec)
  3. ersatz w/simplewebframework (700 requests/sec)
  4. simplewebframework (1300 requests/sec)


Overall, I was very happy with the speed of ersatz. 2x penalty for reflection and the indirection of the ActionEvent is fine. I can't run a native PicoLisp comparison because I don't dual boot on this machine. I was really happy to see it use both cores and that memory didn't climb.

TEST #1/#2 - PicoLisp Example

I used a very basic example:
(html 0 "Hello" "@lib.css" NIL
   "Hello World!" )


TEST #3 - ersatz example

Due to this issue I could not figure out how to write the code completely in ersatz. My first workaround was to create a simple class that took a Runnable instance and ran it. This failed for some unknown reflection exception. So, I took the swing repl example and created a custom EventAction to receive the arguments

Runner.java

import org.simpleframework.http.core.Container;
import org.simpleframework.http.Response;
import org.simpleframework.http.Request;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.PrintStream;
import java.io.IOException;

public class Runner implements Container {

  ActionListener evt;

  public void addActionListener(ActionListener evt) {
    this.evt = evt;
  }
  public class RequestEvent extends ActionEvent {
    public RequestEvent(Object src) {
      super(src, 1, "foo");
    }

    //needed because I can't access this through java reflection api
    public PrintStream getBody() {
      try {
        Response r = (Response)this.getSource();
        return r.getPrintStream();
      } catch (IOException e) {
        System.out.println(e.toString());
        return null;
      }
    }
  }
  public void handle(Request request, Response response) {
    evt.actionPerformed(new RequestEvent(response));
  }
}


go.l

(setq Container (java "Runner" T))
(java Container "addActionListener"
  (interface "java.awt.event.ActionListener" 'actionPerformed
      '((Resp)
         (setq Body (java Resp 'getBody))
         (java Body 'println "hello world")
         (java Body 'close) ) ) )
(setq Con (java "org.simpleframework.transport.connect.SocketConnection" T Container))
(setq Addr (java "java.net.InetSocketAddress" T 8005))
(java Con 'connect Addr)


TEST #4 - HelloWorld.java

This one ran the fastest, but it's also pure java

import org.simpleframework.http.core.Container;
import org.simpleframework.transport.connect.Connection;
import org.simpleframework.transport.connect.SocketConnection;
import org.simpleframework.http.Response;
import org.simpleframework.http.Request;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.io.PrintStream;
import java.io.IOException;

public class HelloWorld implements Container {

   public void handle(Request request, Response response) {
	try {
      PrintStream body = response.getPrintStream();
      long time = System.currentTimeMillis();

      response.set("Content-Type", "text/plain");
      response.set("Server", "HelloWorld/1.0 (Simple 4.0)");
      response.setDate("Date", time);
      response.setDate("Last-Modified", time);

      body.println("Hello World");
      body.close();
      	} catch (IOException e) { }

   }

   public static void main(String[] list) throws Exception {
      Container container = new HelloWorld();
      Connection connection = new SocketConnection(container);
      SocketAddress address = new InetSocketAddress(8080);

      connection.connect(address);
   }
}

http://picolisp.com/wiki/?exampleersatzwebserver

28jan12    joebo