-2

I am trying to check performance of following code but every time I am getting sequential operation gives better performance as compared to fork join.

Problem I want to find max integer:

public class GetMaxIntegerProblem {

    private final int[] intArray;
    private int start;
    private int end;
    private int size;

    public GetMaxIntegerProblem(int[] intArray, int start, int end) {
        super();
        this.intArray = intArray;
        this.start = start;
        this.end = end;
        size = end - start;
    }

    public int getMaxSequentially() {
        int max = Integer.MIN_VALUE;
        for (int i = start; i < end; i++) {
            int n = intArray[i];
            max = n > max ? n : max;
        }
        return max;
    }

    public int getSize() {
        return size;
    }


    public GetMaxIntegerProblem getMaxIntegerSubProblem(int subStart, int subEnd) {
        return new GetMaxIntegerProblem(this.intArray, start + subStart, start + subEnd);
    }
}

My action for fork join:

import java.util.concurrent.RecursiveAction;


public class GetMaxIntegerAction extends RecursiveAction {
    private final int threshold;
    private final GetMaxIntegerProblem problem;
    private int result;

    public GetMaxIntegerAction(int threshold, GetMaxIntegerProblem problem) {
        super();
        this.threshold = threshold;
        this.problem = problem;
    }

    @Override
    protected void compute() {
        if (problem.getSize() < threshold) {
            result = problem.getMaxSequentially();
        } else {
            int midPoint = problem.getSize() / 2;
            GetMaxIntegerProblem leftProblem = problem.getMaxIntegerSubProblem(0, midPoint);
            GetMaxIntegerProblem rightProblem = problem.getMaxIntegerSubProblem(midPoint + 1, problem.getSize());
            GetMaxIntegerAction left = new GetMaxIntegerAction(threshold, leftProblem);
            GetMaxIntegerAction right = new GetMaxIntegerAction(threshold, rightProblem);
            invokeAll(left, right);
            result = Math.max(left.result, right.result);
        }

    }

}

My Main program for testing:

import java.util.Random;
import java.util.concurrent.ForkJoinPool;

public class GetMaxIntegerMain {

    public GetMaxIntegerMain() {
        // TODO Auto-generated constructor stub
    }

    private Random random = new Random();

    private void fillRandomArray(int[] randomArray) {
        for (int i = 0; i < randomArray.length; i++) {
            randomArray[i] = random.nextInt(10000);
        }
    }


    /**
     * @param args
     */
    public static void main(String[] args) {
        GetMaxIntegerMain mainexcution=new GetMaxIntegerMain();
        int arrayLength = 10_00_000;
        int array[] = new int[arrayLength];
        mainexcution.fillRandomArray(array);
        GetMaxIntegerProblem problem=new GetMaxIntegerProblem(array, 0, array.length);
         //No. of times sequential & 
        //Parallel operation should be performed to warm up HotSpot JVM
        final int iterations = 10;
        long start = System.nanoTime();
        int maxSeq=0;
        for (int i = 0; i < iterations; i++) {
            maxSeq=problem.getMaxSequentially();
         }
        long endSeq=System.nanoTime();
        long totalSeq=endSeq-start;
        System.out.println(" time for seq "+(endSeq-start));

        System.out.println("Number of processor available: " + Runtime.getRuntime().availableProcessors());
        //Default parallelism level = Runtime.getRuntime().availableProcessors()
        int threads=Runtime.getRuntime().availableProcessors();
        ForkJoinPool fjpool = new ForkJoinPool(64);

        long startParallel = System.nanoTime();
        for (int i = 0; i < iterations; i++) {
            GetMaxIntegerAction action=new GetMaxIntegerAction(5000, problem);  
            fjpool.invoke(action);
        }
        long endParallel = System.nanoTime();
        long totalP=endParallel-startParallel;
        System.out.println(" time for parallel "+totalP);
        double speedup=(double)(totalSeq/totalP);
        System.out.println(" speedup "+speedup);
        System.out.println("Number of steals: " + fjpool.getStealCount() + "\n");


    }

}

Every time I am running this code, I am getting forkjoin specific code takes 400% more time. I tried with various combination of threshold but I) am not getting to success.

I am running this code on Intel Core i3 Processor 3.3 GHz 64 bit on windows 10.

It would be great help if someone could provide some pointers on this problem.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Ganesh Pol
  • 21
  • 2
  • You are using inappropriate way for estimation performance. This should be micro benchmark test. – Andremoniy Feb 08 '17 at 14:23
  • http://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java – Andremoniy Feb 08 '17 at 14:23
  • 3
    `new ForkJoinPool(64);`? Either you're running on quite a beast, or you've misunderstood how FJP works. – Kayaman Feb 08 '17 at 14:29
  • 2
    How many cores do you have as you are unlikely to get good scalability beyond that. If you overhead is too high I suggest creaking your problem into larger pieces of work, e.g. if you have 2 cores, try splitting the work in two. – Peter Lawrey Feb 08 '17 at 14:29
  • It’s all about how easy the optimizer can recognize that you don’t use the result at all. In a sequential execution, that’s much easier. And one million elements is not challenging anyway. And, by the way, casting the result of an integer division to `double` after the fact, doesn’t improve the precision in any way. – Holger Feb 08 '17 at 16:16
  • sorry for responding bit late and pardon me if I misunderstood something. but I tried ForkJoinPool(4) and with number of cores in my machine also. but In all cases I am getting similar results – Ganesh Pol Mar 08 '17 at 10:44
  • I made some test about Fork/Join framework performances in order to figure out when it's actually worth to use it. You can find here the in depth analysis and the results: [Java Fork/Join framework performances: when is it worth?](http://www.davismol.net/2016/01/24/java-forkjoin-framework-performances-when-is-it-worth/) – Davis Molinari Apr 18 '17 at 07:40

1 Answers1

0

There are very many cases where you shouldn't expect better performance when using fork join since overhead of forking and joining might get quite big. See, for example this talk (mostly second half) https://www.youtube.com/watch?v=2nup6Oizpcw

Pavel Rozenblioum
  • 144
  • 1
  • 2
  • 5