Android: How much overhead is created by an empty method?

I created a class to handle my debugging outputs, so I don’t need to allocate all of my logical outputs before release.

public class Debug { public static void debug( String module, String message) { if( Release.DEBUG ) Log.d(module, message); } } 

After reading another question, I found out that the contents of the if statement are not compiled if the Release.DEBUG constant is false.

What do I want to know about how much overhead is generated by running this empty method? (As soon as the if clause is removed, there is no code in the method). Will this have any effect on my application? Obviously, performance is a big problem when writing mobile phones = P

thanks

Gary

+7
java performance android overhead
source share
5 answers

Measurements taken on the Nexus S with Android 2.3.2:

 10^6 iterations of 1000 calls to an empty static void function: 21s <==> 21ns/call 10^6 iterations of 1000 calls to an empty non-static void function: 65s <==> 65ns/call 10^6 iterations of 500 calls to an empty static void function: 3.5s <==> 7ns/call 10^6 iterations of 500 calls to an empty non-static void function: 28s <==> 56ns/call 10^6 iterations of 100 calls to an empty static void function: 2.4s <==> 24ns/call 10^6 iterations of 100 calls to an empty non-static void function: 2.9s <==> 29ns/call 

management:

 10^6 iterations of an empty loop: 41ms <==> 41ns/iteration 10^7 iterations of an empty loop: 560ms <==> 56ns/iteration 10^9 iterations of an empty loop: 9300ms <==> 9.3ns/iteration 

I repeated measurements several times. No significant deviations were found. You can see that the cost of each call can vary greatly depending on the workload (possibly due to JIT compilation), but 3 conclusions can be made:

  • dalvik / java sucks in optimizing dead code

  • static function calls can be optimized much better than non-static (non-static functions are virtual and need to be looked up in a virtual table)

  • communication costs do not exceed 70 ns / call (this is ~ 70 processor cycles) and is comparable to the cost of one empty iteration of the cycle (i.e., one increment and one condition for checking for a local variable)

Note that in your case the string argument will always be evaluated. If you are concatenating strings, this will involve creating intermediate strings. It will be very expensive and require a lot of gc. For example, executing a function:

 void empty(String string){ } 

called with arguments such as

 empty("Hello " + 42 + " this is a string " + count ); 

10 ^ 4 iterations out of 100 such calls takes 10 seconds. This is 10us / call, i.e. ~ 1000 times slower than just an empty call. It also produces a huge amount of GC activity. The only way to avoid this is to manually enable the function, i.e. use → if <instead of calling the debug function. This is ugly, but the only way to make it work.

+14
source share

If you did not call this from a deeply nested cycle, I would not worry about it.

+2
source share

A good compiler removes the entire empty method, resulting in no overhead at all. I'm not sure that the Dalvik compiler is already doing this, but I suspect that this is possible, at least since the introduction of the Just-in-time compiler with Froyo.

See also: Built-in extension

+2
source share

In terms of performance, the overhead of generating messages that are passed to the debug function will be much more serious, since they are likely to allocate memory, for example

 Debug.debug(mymodule, "My error message" + myerrorcode); 

This will happen even through the message. Unfortunately, you really need an “if (Release.DEBUG)” around the calls to this function, and not inside the function itself, if your goal is performance, and you will see this in many Android codecs.

+2
source share

This is an interesting question, and I like the analysis of @misiu_mp, so I decided to update it with the 2016 test on Nexus 7 running Android 6.0.1. Here is the test code:

 public void runSpeedTest() { long startTime; long[] times = new long[100000]; long[] staticTimes = new long[100000]; for (int i = 0; i < times.length; i++) { startTime = System.nanoTime(); for (int j = 0; j < 1000; j++) { emptyMethod(); } times[i] = (System.nanoTime() - startTime) / 1000; startTime = System.nanoTime(); for (int j = 0; j < 1000; j++) { emptyStaticMethod(); } staticTimes[i] = (System.nanoTime() - startTime) / 1000; } int timesSum = 0; for (int i = 0; i < times.length; i++) { timesSum += times[i]; Log.d("status", "time," + times[i]); sleep(); } int timesStaticSum = 0; for (int i = 0; i < times.length; i++) { timesStaticSum += staticTimes[i]; Log.d("status", "statictime," + staticTimes[i]); sleep(); } sleep(); Log.d("status", "final speed = " + (timesSum / times.length)); Log.d("status", "final static speed = " + (timesStaticSum / times.length)); } private void sleep() { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void emptyMethod() { } private static void emptyStaticMethod() { } 

Added sleep() to prevent Log.d buffer Log.d .

I played with him many times, and the results were pretty compatible with @misiu_mp:

 10^5 iterations of 1000 calls to an empty static void function: 29ns/call 10^5 iterations of 1000 calls to an empty non-static void function: 34ns/call 

A static method call has always been a little faster than a non-static method call, but it would seem that a) the gap has narrowed significantly since Android 2.3.2 and b) the cost of calls to an empty method is still static or not.

Looking at the histogram once reveals something interesting. Most calls, whether static or not, take between 30-40 ns and carefully look at the data, they are almost all 30ns for sure.

enter image description here

Running the same code with empty cycles (commenting on method calls) leads to an average speed of 8 ns, however, about 3/4 of the measured times is 0ns, while the remainder is exactly 30 ns.

I am not sure how to account for this data, but I am not sure that the conclusions of @misiu_mp are still saved. The difference between empty static and non-stationary methods is insignificant, and the predominance of measurements is exactly 30 ns. At the same time, it seems that there is still an unnecessary cost of empty methods.

+1
source share

All Articles