0

Here is my code - it is just a basic introduction to parallel computing that was done in class. There was supposed to be a speedup of around 2 for numbers being added up in a random array. All but about four people were getting the correct results. To note, I am using a 2020 MacBook Air with a 1.2Ghz Quad-Core I7.

import java.util.Arrays;

public class TestProgram
{
    public static double addSequential(double\[\] values) //method that adds numbers in an array.
    {
        double sum = 0;
        for(int i=0; i\<values.length; i++)
        sum += values\[i\];
        return sum;
    }

    public static double addParallel(double[] values) //method that adds code to potentially do parallel computing.
    {
        int mid = values.length / 2; //calculates a mid point.
        
        SumArrayTask left = new SumArrayTask(0, mid, values);
        SumArrayTask right = new SumArrayTask(mid, values.length, values);
        
        left.fork();
        right.compute();
        left.join();
        
        return left.getResult() + right.getResult();
        
    }
    
    public static void main(String[] args)
    {
        double[] arr = new double[10]; 
        for(int i = 0; i<arr.length; i++) //create an array with 10 RANDOM values 0-100
            arr[i] = Math.floor(100*Math.random()); //Math.random picks a random # between 0-1, so we multiply by 100.
        System.out.println(Arrays.toString(arr));
        
        long start, sequentialTime, parallelTime;
        
        start = System.nanoTime();
        System.out.println("Result (sequential): " + addSequential(arr)); //Prints out all elements of array added up.
        System.out.println("Time: " + (sequentialTime = System.nanoTime() - start) + " ns"); //Prints how many nanoseconds the processing takes.
        
        start = System.nanoTime();
        System.out.println("Result (parallel): " + addParallel(arr)); //Prints out all elements of array added up with parallel
        System.out.println("Time: " + (parallelTime = System.nanoTime() - start) + " ns"); //Prints how many nanoseconds the parallel processing takes.
        
        System.out.println("Speedup: " + sequentialTime / parallelTime);
    }

}

import java.util.concurrent.RecursiveAction;

public class SumArrayTask extends RecursiveAction
{
private int start;
private int end;
private double[] data;
private double result;

    public SumArrayTask(int startIndex, int endIndex, double[] arr)
    {
        start = startIndex;
        end = endIndex;
        data = arr;
    }
    
    public double getResult() //getter method for result
    {
        return result;
    }
    
    protected void compute()
    {
        double sum = 0;
        for(int i = start; i<end; i++)
            sum += data[i];
        result = sum;
    }

}

My result:

My result

I was expecting a speedup of around 2. I've had others try and they get a completely different result with their pc's. I am completely unsure if it may have something to do with my setup or the code itself. I appreciate any help.

SternK
  • 11,649
  • 22
  • 32
  • 46
  • Afaik this can be because creating new threads is also time consuming, especially in Java. If you do small tasks, creating the threads and running them than takes more time than doing it sequentially. Edit: You could try creating a MUCH longer array to see the difference – marxlaml Jan 19 '23 at 23:26
  • 3
    For an array of length 10? Especially for the problematic way you're benchmarking? I'm surprised it's _only_ twice as fast to do sequentially. Parallelism usually _hurts_ performance unless you're working with a lot of data on a JVM that's been running for a while. – Louis Wasserman Jan 19 '23 at 23:33
  • 1
    And just to summarize that last two comments: your benchmarking methodology is problematic **and** even if you benchmarked correctly it wouldn't be faster to do it in parallel with such a small data set (due to the overhead of creating/joining threads). And in the future [please do not upload images of code/data/errors.](//meta.stackoverflow.com/q/285551) – Joachim Sauer Jan 20 '23 at 10:24
  • 1
    @LouisWasserman well, in the posted result the sequential code is already more than 35 times faster than the parallel code. But the OP tried very hard to distort the result, mixing the operation and time measuring with printing and string concatenation. When removing these distortions, you easily get factor 400… – Holger Jan 20 '23 at 12:02

1 Answers1

1

First of all, your way of "benchmarking" will always give misleading results:

  • You do I/O (System.out()) within the benchmarked code. This alone will take much longer than adding ten numbers.
  • You do not execute the code multiple times. The first executions in Java will always be slower than later ones, due to the "learning phase" of the Hotspot compiler.

Seeing that a simple "add ten doubles" task seemingly takes more than 100,000 clock cycles could already have alarmed you that your measuring must be wrong. Ten additions should not take more than maybe 100 cycles or so.

Now let's talk about parallel execution. There is a cost to creating and managing a thread (or letting the java.util.concurrent package do it for you), and this can be quite high. So, although each parallel task will probably (*) consume less time than the full loop, the management time for the threads will outweigh that by far in your case.

So, in general, only think about parallel execution for code that takes seconds, not microseconds.

(*) It's not even as clear that the half-array loops will take less time than the full-array loop, as there are more variables involved, making it harder for the Hotspot compiler to do aggressive optimizations like e.g. loop unfolding.

Ralf Kleberhoff
  • 6,990
  • 1
  • 13
  • 7