Perf comparison, Re: Simple dynamic language using invokedynamic

Charles Oliver Nutter headius at headius.com
Tue Jun 16 01:20:18 PDT 2009


On Mon, Jun 15, 2009 at 2:18 AM, Charles Oliver Nutter
<headius at headius.com> wrote:
> This is "Juby", a language that simply compiles Ruby's syntax to Java's
> type system. All calls are made using invokedynamic. Operators are also
> calls, and there's some special-cased logic in them to bootstrap
> appropriate utility methods for doing +, ==, etc. Other than primitive
> logics like "puts" compiling as a System.out.println, all calls are made
> through invokedyanamic. This makes the bytecode trivial to construct,
> and only requires a bit of work on the bootstrap side.

I've added enough logic to run "fib" in Juby and thought I'd get a
perf comparison. So here's the Juby source for fib(35):

def fib(a)
  if a < 2
    a
  else
    fib(a - 1) + fib(a - 2)
  end
end

puts fib(35)

(this is essentially identical to the Ruby code)

And here's the Java code, with all the same fully-boxed logic, utility
math methods, and so on:

public class Fib {
  public static void main(String[] args) {
    System.out.println(fib(Long.valueOf(35)));
  }

  public static Long fib(Long a) {
    if (lt(a, Long.valueOf(2))) {
      return a;
    } else {
      return plus(fib(minus(a, Long.valueOf(1))), fib(minus(a,
Long.valueOf(2))));
    }
  }

  public static Long plus(Long a, Long b) {
    return a + b;
  }

  public static Long minus(Long a, Long b) {
    return a - b;
  }

  public static Boolean lt(Long a, Long b) {
    return a < b;
  }
}

A comparison of bytecode generated in both cases...first Juby:

~/projects/juby ➔ javap -c fib
Compiled from "fib.jb"
public class fib extends java.lang.Object {
public static void main(java.lang.String[]);
  Code:
   0:	aconst_null
   1:	pop
   2:	aconst_null
   3:	ldc2_w	#48; //long 35l
   6:	invokestatic	#16; //Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
   9:	invokedynamic	#45,  0; //NameAndType
fib:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
   14:	getstatic	#55; //Field java/lang/System.out:Ljava/io/PrintStream;
   17:	swap
   18:	invokevirtual	#61; //Method
java/io/PrintStream.println:(Ljava/lang/Object;)V
   21:	aconst_null
   22:	pop
   23:	return

public static java.lang.Object fib(java.lang.Object);
  Code:
   0:	aload_0
   1:	ldc2_w	#9; //long 2l
   4:	invokestatic	#16; //Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
   7:	invokedynamic	#34,  0; //NameAndType
__lt__:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
   12:	getstatic	#40; //Field java/lang/Boolean.FALSE:Ljava/lang/Boolean;
   15:	if_acmpeq	22
   18:	aload_0
   19:	goto	63
   22:	aconst_null
   23:	aload_0
   24:	ldc2_w	#41; //long 1l
   27:	invokestatic	#16; //Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
   30:	invokedynamic	#44,  0; //NameAndType
"-":(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
   35:	invokedynamic	#45,  0; //NameAndType
fib:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
   40:	aconst_null
   41:	aload_0
   42:	ldc2_w	#9; //long 2l
   45:	invokestatic	#16; //Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
   48:	invokedynamic	#44,  0; //NameAndType
"-":(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
   53:	invokedynamic	#45,  0; //NameAndType
fib:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
   58:	invokedynamic	#47,  0; //NameAndType
"+":(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
   63:	areturn

static {};
  Code:
   0:	ldc	#19; //String fib
   2:	invokestatic	#25; //Method
java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
   5:	invokestatic	#31; //Method
com/headius/juby/SimpleJavaBootstrap.registerBootstrap:(Ljava/lang/Class;)V
   8:	return

}

And the Java code:

~/projects/juby ➔ javap -c Fib
Compiled from "Fib.java"
public class Fib extends java.lang.Object {
public Fib();
  Code:
   0:	aload_0
   1:	invokespecial	#1; //Method java/lang/Object."<init>":()V
   4:	return

public static void main(java.lang.String[]);
  Code:
   0:	getstatic	#2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:	ldc2_w	#3; //long 35l
   6:	invokestatic	#5; //Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
   9:	invokestatic	#6; //Method fib:(Ljava/lang/Long;)Ljava/lang/Long;
   12:	invokevirtual	#7; //Method
java/io/PrintStream.println:(Ljava/lang/Object;)V
   15:	return

public static java.lang.Long fib(java.lang.Long);
  Code:
   0:	aload_0
   1:	ldc2_w	#8; //long 2l
   4:	invokestatic	#5; //Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
   7:	invokestatic	#10; //Method
lt:(Ljava/lang/Long;Ljava/lang/Long;)Ljava/lang/Boolean;
   10:	invokevirtual	#11; //Method java/lang/Boolean.booleanValue:()Z
   13:	ifeq	18
   16:	aload_0
   17:	areturn
   18:	aload_0
   19:	lconst_1
   20:	invokestatic	#5; //Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
   23:	invokestatic	#12; //Method
minus:(Ljava/lang/Long;Ljava/lang/Long;)Ljava/lang/Long;
   26:	invokestatic	#6; //Method fib:(Ljava/lang/Long;)Ljava/lang/Long;
   29:	aload_0
   30:	ldc2_w	#8; //long 2l
   33:	invokestatic	#5; //Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
   36:	invokestatic	#12; //Method
minus:(Ljava/lang/Long;Ljava/lang/Long;)Ljava/lang/Long;
   39:	invokestatic	#6; //Method fib:(Ljava/lang/Long;)Ljava/lang/Long;
   42:	invokestatic	#13; //Method
plus:(Ljava/lang/Long;Ljava/lang/Long;)Ljava/lang/Long;
   45:	areturn

(utility methods omitted; they're basically identical to the ones in
Juby's one runtime class)

The logic is not a whole lot different. I've got a little extra
overhead in Juby because it inherits Ruby's "everything is an
expression" so I have a bit more bogus value pushing + popping, but
the resulting code is still pretty clean.

The benchmark is to simply run both of these, precompiled, with -Xint.
This doesn't show us what the optimized performance of each would be,
because indy doesn't jit or optimize right now. But it does show what
overhead we're paying for the indy + method handles at the moment.

Juby:

~/projects/juby ➔ time java -Xint -XX:+EnableInvokeDynamic -cp src:. fib
9227465

real	0m19.616s
user	0m19.307s
sys	0m0.104s

Java:

~/projects/juby ➔ time java -Xint Fib
9227465

real	0m17.857s
user	0m17.540s
sys	0m0.095s

This is very exciting to me. I'm looking forward to seeing the
jitted/optimized performance.

- Charlie



More information about the mlvm-dev mailing list