Loop unrolling in Scala vs Java - 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.

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.

How does java array (primitive type) support forEach loop mechanism [duplicate]

I understand that new for each loop works with Iterable and arrays, but I don't know what goes behind the scenes when working with arrays.
Can anyone help me understand this? Thanks in advance.
int[] number = new int[10];
for(int i: number) {
}
The loop is equivalent to:
for(int j = 0; j < number.length; j++) {
int i = number[j];
...
}
where j is an internally generated reference that does not conflict with normal user identifiers.
A bit late, but here it is.
The compiler knows if you are using the for-each loop statement for a collection or for an array.
If used for collection,
the compiler translates the for-each loop to the equivalent for loop using an Iterator.
If used for an array,
the compiler translates the for-each loop to the equivalent for loop using an index variable.
Here is a description at oracle.com
In your code, you allocate an array of 10 integers in the memory and obtain a reference to it. In the for-loop you simply iterate over every item in the array, which initially will be 0 for all the items. The value of every item will be stored in the variable i declared in your for-loop as you iterate the array elements.
this is equivalent to:
for(int x = 0; x < number.length; x++) {
int i = number[x];
}
This is the equivalent to:
final int len = number.length;
for(int j = 0; j < len; j++) {
int i = number[j];
}
Note that the forEach will not evaluate the .length in each loop.
This might be also be eliminated by the JVM, but especially in case of collections,
where some would use
for(int j = 0; j < collection.size(); j++) {
it makes a (small) difference to the faster
int len = collection.size()
for(int j = 0; j < len; j++) {
The for each over arrays is essentially "sugar" over this construct:
for(int i = 0;i<number.length;i++)
{
}
I would imagine this was provided as a construct of the language so that people could use the enhanced for loop over a structure that was iterated over in the old way.
IntStream.range(1,4) can be used, if using java 8.

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.

Java for-loop best practice

What is the best way to loop through an array when you need the index?
Option 1:
int len = array.length;
for (int i = 0; i < len; ++i) {
array[i] = foo(i);
}
Option 2:
for (int i = 0; i < array.length; i++) {
array[i] = foo(i);
}
Or, does it not matter? Or is there a better way to do it?
Just to point out the differences: In one case, the length of the array is evaluated as part of the test in the loop, although the compiler should normally optimize that.
Secondly, is ++i any different here from i++? I definitely prefer ++i if it is C++ but am not sure for Java.
i++ vs ++i does not matter in this particular case. While C masters will tell you to store array.length in a variable, modern optimizing compilers make that unnecessary in this case as long as the length does not change in the loop. If you're really concerned you can benchmark both, but since .length doesn't actually need to traverse the entire array each time you'll be OK.
Generally those two methods are equivalent. You should note that in
for (int i = 0 ; i < foo() ; i++) {
...
}
the foo() is called once before each iteration (as opposed to only once before the first iteration), so you might want to take this into account for more complicated situations by perhaps doing something like
int n = foo();
for (int i = 0 ; i < n ; i++) {
...
}
which is analogous to your Option 1. So I would say Option 1 is certainly the safer of the two, but most of the time it should not make a significant difference which you use.
As for your second question: ++i first increments your variable and then retrieves it's value, i++ first retrieves the value and then increments. Just try these two pieces of code:
int i = 0;
System.out.println(++i);
------------------------
int i = 0;
System.out.println(i++);
The first prints 1 but the second prints 0. Of course when ++i and i++ are alone it makes no difference.
for whether to use "array.length" in for loop:
Generally the compiler will do some optimization, as a result it is equivalent to using a variable in the for loop
for "i++" and "++i"
In C++, ++i is preferred and more efficient, but in Java, they are equivalent in this case.
In addition to arshaji response I wanted to know if there was a performance benefit of using size() in a loop vs storing it in advance. I believe the result show that the compiler does optimize things and accessing the length of a list is the same as accessing a variable ( I was worried that the fact it had to go through a function would slow down things).
Here is the time it takes for those two for different method of loop:
for(long i = 0 ; i < mylist.size(); i++){}
VS
for(long i = 0 ; i < 10_000_000; i++){}
Here is the result for a list of ten million elems:
fixed length:
,162,157,151,157,156,159,157,149,150,170,158,153,152,158,151,151,156,156,151,153
getSize:
,164,156,159,154,151,160,162,152,154,152,151,149,168,156,152,150,157,150,156,157
import java.util.ArrayList;
import java.util.List;
public class Main {
final static int LENGTH_SAMPLE = 20;
final static long LENGTH = 10_000_000;
public static void main(String[] args) {
List<Long> mylist = new ArrayList<>();
for(long i = 0 ; i < LENGTH; i++){
mylist.add(i);
}
System.out.println("fixed length:");
for(int i = 0 ; i < LENGTH_SAMPLE; i++){
System.out.printf("," + fixedSize(mylist));
}
System.out.println("");
System.out.println("getSize:");
for(int i = 0 ; i < LENGTH_SAMPLE; i++){
System.out.printf("," + fctSize(mylist));
}
}
private static long fixedSize(List list){
long start = System.currentTimeMillis();
for(long i = 0 ; i < LENGTH; i++){
System.currentTimeMillis();
}
return System.currentTimeMillis() - start;
}
private static long fctSize(List list){
long start = System.currentTimeMillis();
for(long i = 0 ; i < list.size(); i++){
System.currentTimeMillis();
}
return System.currentTimeMillis() - start;
}
}

How to use less logger.isDebugEnabled()

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.

Categories