How to use less logger.isDebugEnabled() - java

Here i will add logger.isDebugEnabled() conditional statement for logger.debug().
But sometime there are many logger.debug() in loop. For example:
Logger log = Logger.getLogger(Test.class);
for(int i = 0; i < 1000; i++) {
...
log.debug("aaaaa");
...
for(int j = 0; i < 100; j++) {
...
log.debug("bbbb");
}
}
If i add it directly, as follows:
for(int i = 0; i < 1000; i++) {
...
if(log.isDebugEnabled()) {
log.debug("aaaaa");
}
...
for(int j = 0; i < 100; j++) {
...
if(log.isDebugEnabled()) {
log.debug("bbbb");
}
}
}
So, in the loop, it will if() many times. How could i use less if(logger.isDebugEnabled())?
Does anyone have some idea ?
thanks.

What i care is that so may if() in loop whether will affect performance ?
Consider this code:
boolean logging = log.isDebugEnabled();
for (int i = 0; i < 1000; i++) {
// stuff
if (logging) {
log.debug("Hi Mum!");
}
// more stuff
}
The cost of the if test could be as small as 2 instructions, depending how the JIT compiler's register allocation pans out. This is most likely insignificant, unless you are doing ridiculous amounts of logging.
However, if the performance hit of those 2 to 4 instructions really matters, then you could consider:
removing the call to log entirely,
making it conditional on a compile time constant (so that the optimizer can prune the code), or
hoisting the test out of the loop; e.g. restructuring the code as follows:
boolean logging = log.isDebugEnabled();
if (logging) {
for (int i = 0; i < 1000; i++) {
// stuff
log.debug("Hi Mum!");
// more stuff
}
} else {
for (int i = 0; i < 1000; i++) {
// stuff
// more stuff
}
}
However, IMO, the cure is worse than the disease.
#Vineet's point is important too. In practice, the expensive part of something like this:
log.debug("Today is " + date);
is that the String concatenation expression is evaluated irrespective of the actual logging level. There are other ways to avoid this overhead apart from an if test ... though they will be more expensive than an if test on a cached flag.

Use slf4j.

Store the value of log.isDebugEnabled() in a local variable, like this:
// Calculate once and cache the answer
boolean areLogging = log.isDebugEnabled();
for (int i = 0; i < 1000; i++) {
...
if (areLogging) {
log.debug("aaaaa");
}
...
for (int j = 0; i < 100; j++) {
...
if (areLogging) {
log.debug("bbbb");
}
}
}

Using slf4j has already been pointed out. Specifically, you ought to be using the "parameterized messages" feature of slf4j.
The posted code does not demonstrate the utility in using parameterized messages. Apparently, "bbbb" will be treated as a String literal (for the compiler can compute it's value at runtime and place it in the constant pool of the class) that will be loaded by the JVM when the class is loaded and pooled in the internal String pool; there is apparently no cost in constructing the log message, and the log.isDebugEnabled() invocation is redundant. I'll therefore illustrate the use of parameterized messages with a more descriptive example that demonstrates it's benefits
for(int j = 0; i < 100; j++) {
...
if(log.isDebugEnabled()) { // this is required by log4j. Without this, on every iteration, a new String object will be created in the following statement.
log.debug("Loop counter is" + j); // This constructs a new String object only if DEBUG is enabled.
}
}
can be reduced to:
for(int j = 0; i < 100; j++) {
...
log.debug("Loop counter is {}", j); //There is no explicit call to log.isDebugEnabled() in this case. The log message will be created only if DEBUG is enabled.
}
The String literal Loop counter is {} is again pooled in the String intern pool, but at runtime the String object with values Loop counter is 0, Loop counter is 1 etc. will be created by slf4j, only if the DEBUG level is enabled.

Related

Complexity of three for loops [duplicate]

This question already has answers here:
How can I find the time complexity of an algorithm?
(10 answers)
Closed 8 months ago.
I was wondering if time complexity of the following code is O(n^3) or O(n^2)
public void firstMethod() {
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 6; j++) {
secondMethod();
}
}
}
public void secondMethod(){
for (int i = 0; i < 6; i++) {
System.out.println("This is a test to observe complexity");
}
}
This is O(1) because the runtime is constant. The bounds of each loop never change, so the method's runtime will never change.
Now, had you written the following:
public void firstMethod(int n) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
secondMethod(n);
}
}
}
public void secondMethod(int n) {
for (int i = 0; i < n; i++) {
System.out.println("This is a test to observe complexity");
}
}
Then firstMethod would be O(n^3) for runtime complexity.
E.g., a runtime complexity like O(n³) means that, when varying n, the runtime increases like n³.
So, as there is no n in your code, you can vary n as much as you want, without any effect on the runtime. In fact, there is nothing variable in your code that has any effect on its runtime, meaning it is constant, and we express that as O(1).
Even a notation like O(n²) is often used in a quite sloppy way. It should always be accompanied by a clear definition what n means. But quite often, we are forced to assume that n might mean the length of an array, or the number of bits in an input number or whatever.
To sum it up:
If the runtime of your code does not depend on some variable input, you get O(1).
In the O(xyz) notation, you need to use variable names that are clearly defined.

Loop unrolling in Scala vs Java

Does loop unrolling works for loops where iteration count is determined during runtime? E.g. will the inner loop will be considered for unrolling in this code:
for(int j = 0; j < HUGE_NUMBER; j++) {
int N = getCount(); // say N = 5
for(int i = 0; i < N; i++) {
doSomething(i);
}
}
Does loop unrolling works differently in Scala? Will the JIT compiler treat the following code snippets the same way?
// Java
int N = getCount();
for(int i = 0; i < N; i++) {
doSomething(i);
}
// Scala
val N = getCount();
var i = 0
while(i < N) {
doSomething(i);
i+=1
}
The JIT compiler works on the Java bytecode so the unroll behaviour is independent of the original language and will depend on the particular JVM/compiler that is being used.
I don't believe that the Scala compiler implements its own loop unrolling. It is quite rare to use this kind of counting loop in Scala so it is probably not worth optimising it.

Java For-Loop - Termination Expression speed

In my java program I have a for-loop looking roughly like this:
ArrayList<MyObject> myList = new ArrayList<MyObject>();
putThingsInList(myList);
for (int i = 0; i < myList.size(); i++) {
doWhatsoever();
}
Since the size of the list isn't changing, I tried to accelerate the loop by replacing the termination expression of the loop with a variable.
My idea was: Since the size of an ArrayList can possibly change while iterating it, the termination expression has to be executed each loop cycle. If I know (but the JVM doesn't), that its size will stay constant, the usage of a variable might speed things up.
ArrayList<MyObject> myList = new ArrayList<MyObject>();
putThingsInList(myList);
int myListSize = myList.size();
for (int i = 0; i < myListSize; i++) {
doWhatsoever();
}
However, this solution is slower, way slower; also making myListSize final doesn't change anything to that! I mean I could understand, if the speed didn't change at all; because maybe JVM just found out, that the size doesn't change and optimized the code. But why is it slower?
However, I rewrote the program; now the size of the list changes with each cycle: if i%2==0, I remove the last element of the list, else I add one element to the end of the list. So now the myList.size() operation has to be called within each iteration, I guessed.
I don't know if that's actually correct, but still the myList.size() termination expression is faster than using just a variable that remains constant all the time as termination expression...
Any ideas why?
Edit (I'm new here, I hope this is the way, how to do it)
My whole test program looks like this:
ArrayList<Integer> myList = new ArrayList<Integer>();
for (int i = 0; i < 1000000; i++)
{
myList.add(i);
}
final long myListSize = myList.size();
long sum = 0;
long timeStarted = System.nanoTime();
for (int i = 0; i < 500; i++)
{
for (int j = 0; j < myList.size(); j++)
{
sum += j;
if (j%2==0)
{
myList.add(999999);
}
else
{
myList.remove(999999);
}
}
}
long timeNeeded = (System.nanoTime() - timeStarted)/1000000;
System.out.println(timeNeeded);
System.out.println(sum);
Performance of the posted code (average of 10 executions):
4102ms for myList.size()
4230ms for myListSize
Without the if-then-else statements (so with constant myList size)
172ms for myList.size()
329ms for myListSize
So the speed different of both versions is still there. In the version with the if-then-else parts the percentaged differences are of course smaller because a lot of the time is invested for the add and remove operations of the list.
The problem is with this line:
final long myListSize = myList.size();
Change this to an int and lo and behold, running times will be identical. Why? Because comparing an int to a long for every iteration requires a widening conversion of the int, and that takes time.
Note that the difference also largely (but probably not completely) disappears when the code is compiled and optimised, as can be seen from the following JMH benchmark results:
# JMH 1.11.2 (released 7 days ago)
# VM version: JDK 1.8.0_51, VM 25.51-b03
# VM options: <none>
# Warmup: 20 iterations, 1 s each
# Measurement: 20 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
...
# Run complete. Total time: 00:02:01
Benchmark Mode Cnt Score Error Units
MyBenchmark.testIntLocalVariable thrpt 20 81892.018 ± 734.621 ops/s
MyBenchmark.testLongLocalVariable thrpt 20 74180.774 ± 1289.338 ops/s
MyBenchmark.testMethodInvocation thrpt 20 82732.317 ± 749.430 ops/s
And here's the benchmark code for it:
public class MyBenchmark {
#State( Scope.Benchmark)
public static class Values {
private final ArrayList<Double> values;
public Values() {
this.values = new ArrayList<Double>(10000);
for (int i = 0; i < 10000; i++) {
this.values.add(Math.random());
}
}
}
#Benchmark
public double testMethodInvocation(Values v) {
double sum = 0;
for (int i = 0; i < v.values.size(); i++) {
sum += v.values.get(i);
}
return sum;
}
#Benchmark
public double testIntLocalVariable(Values v) {
double sum = 0;
int max = v.values.size();
for (int i = 0; i < max; i++) {
sum += v.values.get(i);
}
return sum;
}
#Benchmark
public double testLongLocalVariable(Values v) {
double sum = 0;
long max = v.values.size();
for (int i = 0; i < max; i++) {
sum += v.values.get(i);
}
return sum;
}
}
P.s.:
My idea was: Since the size of an ArrayList can possibly change while
iterating it, the termination expression has to be executed each loop
cycle. If I know (but the JVM doesn't), that its size will stay
constant, the usage of a variable might speed things up.
Your assumption is wrong for two reasons: first of all, the VM can easily determine via escape analysis that the list stored in myList doesn't escape the method (so it's free to allocate it on the stack for example).
More importantly, even if the list was shared between multiple threads, and therefore could potentially be modified from the outside while we run our loop, in the absence of any synchronization it is perfectly valid for the thread running our loop to pretend those changes haven't happened at all.
As always, things are not always what they seem...
First things first, ArrayList.size() doesn't get recomputed on every invocation, only when the proper mutator is invoked. So calling it frequently is quite cheap.
Which of these loops is the fastest?
// array1 and array2 are the same size.
int sum;
for (int i = 0; i < array1.length; i++) {
sum += array1[i];
}
for (int i = 0; i < array2.length; i++) {
sum += array2[i];
}
or
int sum;
for (int i = 0; i < array1.length; i++) {
sum += array1[i];
sum += array2[i];
}
Instinctively, you would say that the second loop is the fastest since it doesn't iterate twice. However, some optimizations actually cause the first loop to be the fastest depending, for instance, on memory walking strides that cause a lot of memory cache misses.
Side-note: this compiler optimization technique is called loop
jamming.
This loop:
int sum;
for (int i = 0; i < 1000000; i++) {
sum += list.get(i);
}
is not the same as:
// Assume that list.size() == 1000000
int sum;
for (int i = 0; i < list.size(); i++) {
sum += list.get(i);
}
In the first case, the compile absolutely knows that it must iterate a million times and puts the constant in the Constant Pool, so certain optimizations can take place.
A closer equivalent would be:
int sum;
final int listSize = list.size();
for (int i = 0; i < listSize; i++) {
sum += list.get(i);
}
but only after the JVM has figured out what the value of listSize is. The final keyword gives the compiler/run-time certain guarantees that can be exploited. If the loop runs long enough, JIT-compiling will kick in, making execution faster.
Because this sparked interest in me I decided to do a quick test:
public class fortest {
public static void main(String[] args) {
long mean = 0;
for (int cnt = 0; cnt < 100000; cnt++) {
if (mean > 0)
mean /= 2;
ArrayList<String> myList = new ArrayList<String>();
putThingsInList(myList);
long start = System.nanoTime();
int myListSize = myList.size();
for (int i = 0; i < myListSize; i++) doWhatsoever(i, myList);
long end = System.nanoTime();
mean += end - start;
}
System.out.println("Mean exec: " + mean/2);
}
private static void doWhatsoever(int i, ArrayList<String> myList) {
if (i % 2 == 0)
myList.set(i, "0");
}
private static void putThingsInList(ArrayList<String> myList) {
for (int i = 0; i < 1000; i++) myList.add(String.valueOf(i));
}
}
I do not see the kind of behavior you are seeing.
2500ns mean execution time over 100000 iterations with myList.size()
1800ns mean execution time over 100000 iterations with myListSize
I therefore suspect that it's your code that is executed by the functions that is at fault. In the above example you can sometimes see faster execution if you only fill the ArrayList once, because doWhatsoever() will only do something on the first loop. I suspect the rest is being optimized away and significantly drops execution time therefore. You might have a similar case, but without seeing your code it might be close to impossible to figure that one out.
There is another way to speed up the code using for each loop
ArrayList<MyObject> myList = new ArrayList<MyObject>();
putThingsInList(myList);
for (MyObject ob: myList) {
doWhatsoever();
}
But I agree with #showp1984 that some other part is slowing the code.

Performance tips questions

public void zero() {
int sum = 0;
for (int i = 0; i < mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}
public void one() {
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;
for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
}
According to Android documentation, in above code, zero is slower. But I don't understand why ? well I haven't learn that much deep but as I know length is a field not method. So when loop retrieves its value, how its different from retrieving from local variable ? and array length is always fixed once initialized. What am I missing ?
Well I guess this is because at zero, he always needs to retrieve the information from mArray and in one, he has it accessible. This means, zero needs two "methods":
Access mArray
Access mArray.length
But one only needs one "methods":
Access len
In the first example, the JVM needs to first fetch the reference to the array and then access its length field.
In the second example, it only accesses one local variable.
On desktop JVMs this is generally optimised and the two methods are equivalent but it seems that Android's JVM does not do it... yet...
It is a matter of scope. Accessing an instance variable is slower than a method variable because it is not stored in the same memory places. (because method variables are likely to be accessed more often).
Same goes for len, but with an extra optimization. len cannot be changed from outside the method, and the compiler can see that it will never change. Therefore, its value is more predictable and the loop can be further optimized.
public void zero() {
int sum = 0;
for (int i = 0; i < mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}
Here if you look at the for loop array length is calculated for every iteration, that degrades
the performance.
public void one() {
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;
for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
}
In this case the length is calculated before for loop and then used in the loop.

charAt() or substring? Which is faster?

I want to go through each character in a String and pass each character of the String as a String to another function.
String s = "abcdefg";
for(int i = 0; i < s.length(); i++){
newFunction(s.substring(i, i+1));}
or
String s = "abcdefg";
for(int i = 0; i < s.length(); i++){
newFunction(Character.toString(s.charAt(i)));}
The final result needs to be a String. So any idea which will be faster or more efficient?
As usual: it doesn't matter but if you insist on spending time on micro-optimization or if you really like to optimize for your very special use case, try this:
import org.junit.Assert;
import org.junit.Test;
public class StringCharTest {
// Times:
// 1. Initialization of "s" outside the loop
// 2. Init of "s" inside the loop
// 3. newFunction() actually checks the string length,
// so the function will not be optimized away by the hotstop compiler
#Test
// Fastest: 237ms / 562ms / 2434ms
public void testCacheStrings() throws Exception {
// Cache all possible Char strings
String[] char2string = new String[Character.MAX_VALUE];
for (char i = Character.MIN_VALUE; i < Character.MAX_VALUE; i++) {
char2string[i] = Character.toString(i);
}
for (int x = 0; x < 10000000; x++) {
char[] s = "abcdefg".toCharArray();
for (int i = 0; i < s.length; i++) {
newFunction(char2string[s[i]]);
}
}
}
#Test
// Fast: 1687ms / 1725ms / 3382ms
public void testCharToString() throws Exception {
for (int x = 0; x < 10000000; x++) {
String s = "abcdefg";
for (int i = 0; i < s.length(); i++) {
// Fast: Creates new String objects, but does not copy an array
newFunction(Character.toString(s.charAt(i)));
}
}
}
#Test
// Very fast: 1331 ms/ 1414ms / 3190ms
public void testSubstring() throws Exception {
for (int x = 0; x < 10000000; x++) {
String s = "abcdefg";
for (int i = 0; i < s.length(); i++) {
// The fastest! Reuses the internal char array
newFunction(s.substring(i, i + 1));
}
}
}
#Test
// Slowest: 2525ms / 2961ms / 4703ms
public void testNewString() throws Exception {
char[] value = new char[1];
for (int x = 0; x < 10000000; x++) {
char[] s = "abcdefg".toCharArray();
for (int i = 0; i < s.length; i++) {
value[0] = s[i];
// Slow! Copies the array
newFunction(new String(value));
}
}
}
private void newFunction(String string) {
// Do something with the one-character string
Assert.assertEquals(1, string.length());
}
}
The answer is: it doesn't matter.
Profile your code. Is this your bottleneck?
Does newFunction really need to take a String? It would be better if you could make newFunction take a char and call it like this:
newFunction(s.charAt(i));
That way, you avoid creating a temporary String object.
To answer your question: It's hard to say which one is more efficient. In both examples, a String object has to be created which contains only one character. Which is more efficient depends on how exactly String.substring(...) and Character.toString(...) are implemented on your particular Java implementation. The only way to find it out is running your program through a profiler and seeing which version uses more CPU and/or more memory. Normally, you shouldn't worry about micro-optimizations like this - only spend time on this when you've discovered that this is the cause of a performance and/or memory problem.
Of the two snippets you've posted, I wouldn't want to say. I'd agree with Will that it almost certainly is irrelevant in the overall performance of your code - and if it's not, you can just make the change and determine for yourself which is fastest for your data with your JVM on your hardware.
That said, it's likely that the second snippet would be better if you converted the String into a char array first, and then performed your iterations over the array. Doing it this way would perform the String overhead once only (converting to the array) instead of every call. Additionally, you could then pass the array directly to the String constructor with some indices, which is more efficient than taking a char out of an array to pass it individually (which then gets turned into a one character array):
String s = "abcdefg";
char[] chars = s.toCharArray();
for(int i = 0; i < chars.length; i++) {
newFunction(String.valueOf(chars, i, 1));
}
But to reinforce my first point, when you look at what you're actually avoiding on each call of String.charAt() - it's two bounds checks, a (lazy) boolean OR, and an addition. This is not going to make any noticeable difference. Neither is the difference in the String constructors.
Essentially, both idioms are fine in terms of performance (neither is immediately obviously inefficient) so you should not spend any more time working on them unless a profiler shows that this takes up a large amount of your application's runtime. And even then you could almost certainly get more performance gains by restructuring your supporting code in this area (e.g. have newFunction take the whole string itself); java.lang.String is pretty well optimised by this point.
I would first obtain the underlying char[] from the source String using String.toCharArray() and then proceed to call newFunction.
But I do agree with Jesper that it would be best if you could just deal with characters and avoid all the String functions...
Leetcode seems to prefer the substring option here.
This is how I solved that problem:
class Solution {
public int strStr(String haystack, String needle) {
if(needle.length() == 0) {
return 0;
}
if(haystack.length() == 0) {
return -1;
}
for(int i=0; i<=haystack.length()-needle.length(); i++) {
int count = 0;
for(int j=0; j<needle.length(); j++) {
if(haystack.charAt(i+j) == needle.charAt(j)) {
count++;
}
}
if(count == needle.length()) {
return i;
}
}
return -1;
}
}
And this is the optimal solution they give:
class Solution {
public int strStr(String haystack, String needle) {
int length;
int n=needle.length();
int h=haystack.length();
if(n==0)
return 0;
// if(n==h)
// length = h;
// else
length = h-n;
if(h==n && haystack.charAt(0)!=needle.charAt(0))
return -1;
for(int i=0; i<=length; i++){
if(haystack.substring(i, i+needle.length()).equals(needle))
return i;
}
return -1;
}
}
Honestly, I can't figure out why it would matter.

Categories