about non-compatible optimization (was: Re: patch to bring java vtables closer to g++ abi conformance)

shudo@computer.org shudo@computer.org
Fri Jan 25 22:30:00 GMT 2002


Bryce McKinlay <bryce@waitaki.otago.ac.nz> wrote:

> I am curious why you mentioned "dynamic invocations" or "method lookup"
> as being slow. It isn't. In fact a virtual method call (in a loop) in
> GCJ is *faster* than a static method call (in Java or C). Try it if you
> don't believe me!

It sounds curious.  But I could confirm it.

I measured the time taken to invoke a method 10,000,000
times for GCJ.  Java source files attached to this mail
are compiled with -O option and executed on a 600 MHz
Pentium III PC.

  invokevirtual:   234  (faster than invokestatic)
  invokespecial:    68
  invokeinterface: 554
  invokestatic:    319
    (msec)

The version of GCC is as follows:

  % gcj -v
  ...
  gcc version 3.1 20020115 (Red Hat Linux Rawhide 3.1-0.18)


  Kazuyuki Shudo	shudo@computer.org	http://www.shudo.net/
-------------- next part --------------
public class InvocationBenchmark implements InvocationBenchmarkIntf {
  public final static int REPEAT = 10000000;

  public int aVirtualMethod(int n) {
    return n - 1;
  }

  private int aSpecialMethod(int n) {
    return n - 1;
  }

  public int aInterfaceMethod(int n) {
    return n - 1;
  }

  public static int aStaticMethod(int n) {
    return n - 1;
  }


  public static void main(String[] args) {
    InvocationBenchmark obj = new InvocationBenchmarkDerived();

    benchmark(obj);
  }

  public static void benchmark(InvocationBenchmark obj) {
    long t0, t1, t2, t3;
    int n;

    InvocationBenchmarkIntf intf = (InvocationBenchmarkIntf)obj;

    // Invoke these methods in advance to compile them
    System.out.print(obj.aVirtualMethod(1));
    System.out.print(obj.aSpecialMethod(1));
    System.out.print(obj.aInterfaceMethod(1));
    System.out.print(obj.aStaticMethod(1));


    // invokevirtual
    n = REPEAT;
    t0 = -System.currentTimeMillis();
    while (n > 0) {
      n = obj.aVirtualMethod(n);
	// This invocation certainly raises a dynamic resolution of
	// the callee method.  This invocation may be treated as
	// a static invocation if this benchmark() method is inlined
	// into main() and type propagation is performed.
	// But this case may not happen.
    }
    t0 += System.currentTimeMillis();

    System.out.print(n);


    // invokespecial
    n = REPEAT;
    t1 = -System.currentTimeMillis();
    while (n > 0) {
      n = obj.aSpecialMethod(n);
    }
    t1 += System.currentTimeMillis();

    System.out.print(n);


    // invokeinterface
    n = REPEAT;
    t2 = -System.currentTimeMillis();
    while (n > 0) {
      n = intf.aInterfaceMethod(n);
    }
    t2 += System.currentTimeMillis();

    System.out.print(n);


    // invokestatic
    n = REPEAT;
    t3 = -System.currentTimeMillis();
    while (n > 0) {
      n = InvocationBenchmark.aStaticMethod(n);
    }
    t3 += System.currentTimeMillis();

    System.out.print(n);
    System.out.println();


    System.out.println("virtual  : " + t0);
    System.out.println("special  : " + t1);
    System.out.println("interface: " + t2);
    System.out.println("static   : " + t3);

    System.out.println("           (msec / " + REPEAT + " times)");
  }
}
-------------- next part --------------
public class InvocationBenchmarkDerived extends InvocationBenchmark {
}
-------------- next part --------------
interface InvocationBenchmarkIntf {
  public int aInterfaceMethod(int n);
}


More information about the Java mailing list