0

I've been working on a cryptographic (POT) protocol in Java for my master's thesis. It uses cryptographic Pairings and therefore makes use of an external java library called jPBC (http://gas.dia.unisa.it/projects/jpbc/).

As I want one side of the protocol to run on a mobile device, I 've made a simple GUI in Android ADT with a single button that starts the protocol. However, the protocol runs about 200 times slower on my phone (Samsung S2 plus, ARM Cortex A9 32 bit processor) than on my laptop (Intel Core i7, but only using half a core). As the difference in processors might explain a factor 10 but certainly not a factor 100/200 I figured the difference in performance would be due to the inefficiency of the jPBC library on Android.

The jPBC library makes extensive use of BigInteger for all of its calculations so I decided to investigate if BigInteger could be extra inefficient on android (it's not super efficient on normal computers either). I executed a loop of 1200 bit BigInteger calculations on the phone and the laptop. I've come up with some results that I cannot explain:

10^6 Additions and subtractions take 205ms on laptop, 48 025ms on phone (x 200).

10^5 Multiplications and divisions take 814 ms on laptop and 13 705ms on phone (x 17).

10^3 Modular Exponentiations (modPow) take 5079ms on laptop and 22 153ms on phone (x 4.5)

As there is much to be said about these results, I'll just stick to this simple question:

Can anyone either reproduce these results and confirm that BigInteger addition is immensively slow on Android, or tell me what I've done wrong?

The code:

Java method:

public static long bigIntCalculations(){
    System.out.println("starting bigIntCalculations");
    Random random = new Random();
    BigInteger start = new BigInteger(1200, random);
    BigInteger temp = new BigInteger(start.toString());
    long nOfIterations = 1000000L;
    long time1 = System.nanoTime()/1000000;
    for (long i = 0; i < nOfIterations; i++) {
        start = start.add(temp);
        start = start.subtract(temp);

    }
    long result = (System.nanoTime()/1000000)-time1;
    System.out.println(result);
    return result;

}

In Android:

/** Called when the user clicks the button1*/
public void runProtocol(View view) {
long duration = Test.bigIntCalculations();
String result ="Calculations take: " + duration + " ms";    
Intent intent = new Intent(this, DisplayMessageActivity.class);
            intent.putExtra(CALC_RESULT, result);
            startActivity(intent);  
}

Many thanks!

  • I have the same issue with DiffieHellman key exchange, not really sure why I get bigger execution times ... i think the processing power of a smartphone isn't as good as a laptop. furthermore http://stackoverflow.com/questions/3446540/what-is-the-difference-between-dvm-and-jvm might be a hint to the solution – cristi _b Jun 23 '13 at 11:42

1 Answers1

0

Only x4.5 for 1200-bit modular exponentiation is a terrific result, considering the underpowered hardware. It's also a testament to how bad the JDK's BigInteger implementation is.

The Android standard library uses OpenSSL BigNum for some under-the-hood operations. Without peeking, I would guess modular exponentiation and modular inverse are handled in native code, while simpler arithmetic is handled in Java code.

For tight loops of addition and multiplication you would be generating lots of garbage, and GC performance disparity between platforms could also be having a large impact -- my guess is that some warmup + a much smaller benchmark will show closer results.

My performance pain point is modular exponentiation, so I'm pretty happy with Android performance. If that were not the case, I'd be looking at porting libraries such as gmp4j or gmp-java (two libraries by that name) to Android. Two of these provide a BigInteger-compatible API. Another offers a more direct mapping to GMPLib, which can be ideal in terms of memory management (GMP numbers are mutable).

nadavwr
  • 1,820
  • 16
  • 20