2

I want to multiply two matrices, so I decided to split matrices into some parts. I wrote two different matriceSplit functions but I confused. One of my functions uses system arraycopy and the other uses a for loop. I observed the for loop run faster than the arraycopy method.

 private static int[][] getPartOfMatrix(int[][] matrix, int size, int part) {

        int[][] newMatrix = new int[size][matrix[0].length];

        for (int i = part * size; i < (part + 1) * size; i++) {
            System.arraycopy(matrix[i], 0, newMatrix[i], 0, matrix[i].length);
        }

        return newMatrix;
    }

 private static int[][] getPartOfMatrix2(int[][] matrix, int size, int part) {

        int[][] newMatrix = new int[size][matrix[0].length];

        for (int i = part * size, r = 0; i < (part + 1) * size; i++, r++) {
            for (int j = 0; j < matrix[0].length; j++) {
                newMatrix[r][j] = matrix[i][j];
            }
        }

        return newMatrix;
    }

Which should I use and why ?

Daryl Bennett
  • 462
  • 10
  • 22
gokhan
  • 627
  • 1
  • 6
  • 16
  • I'd use the faster method. – Daryl Bennett Nov 16 '14 at 23:39
  • 3
    How did you determine which was faster? Determining which of two implementations is fastest in Java is _hard._ – Louis Wasserman Nov 16 '14 at 23:40
  • @Mitch Wheat why It is important for me because i multiplication of matrices at different machines and before sending matrices i purge matrice with copying function so i prevent sending unnecessary data – gokhan Nov 16 '14 at 23:41
  • I used system.currentTimeMilis() – gokhan Nov 16 '14 at 23:42
  • 2
    Possible duplicate: [Link](http://stackoverflow.com/questions/8526907/is-javas-system-arraycopy-efficient-for-small-arrays) – Olavi Mustanoja Nov 16 '14 at 23:44
  • The benchmark code in Ethaniel's answer to that question should help @gokhan. – Paul Hicks Nov 16 '14 at 23:57
  • 1
    There a loads of potential pitfalls in profiling. But by far the two important points are: Did you run each method loads of times in your test (probably hundreds of thousands of times) and did you run each method many times before starting your tests to "warm up the JVM" – Richard Tingle Nov 17 '14 at 00:02
  • @Olavi, I was going to write about it, but you already provided a link )) Upvoting... – Mixaz Nov 17 '14 at 00:08
  • @gokhan if performance is critical, do you have to copy at all? sometimes a flyweight is all that one needs. – Chris K Nov 17 '14 at 11:53
  • @ChrisK I copy because i divide matrice to small parts and send it to different machines and after i combine results – gokhan Nov 17 '14 at 12:47

1 Answers1

1
package tests;

import org.openjdk.jmh.annotations.*;

import java.util.concurrent.TimeUnit;

@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class CopyArray implements UnsafeConstants {

    @Param({"0", "1", "10", "16", "1000", "1024", "8192"})
    public int arraySize;
    public int[] a;
    public int[] copy;

    @Setup
    public void setup() {
        a = new int[arraySize];
        copy = new int[arraySize];
    }

    @Benchmark
    public int[] arrayCopy(CopyArray state) {
        int[] a = state.a;
        int[] copy = state.copy;
        System.arraycopy(a, 0, copy, 0, a.length);
        return copy;
    }

    @Benchmark
    public int[] forLoop(CopyArray state) {
        int[] a = state.a;
        int arraySize = a.length;
        int[] copy = state.copy;
        for (int i = 0; i < arraySize; i++) {
            copy[i] = a[i];
        }
        return copy;
    }

    @Benchmark
    public int[] unsafeCopyMemory(CopyArray state) {
        int[] a = state.a;
        int arraySize = a.length;
        int[] copy = state.copy;
        U.copyMemory(a, INT_BASE, copy, INT_BASE, arraySize << INT_SCALE_SHIFT);
        return copy;
    }
}

Results:

Benchmark                       (arraySize)  Mode  Samples     Score     Error  Units
t.CopyArray.arrayCopy                     0  avgt       10     3,598 ▒   0,385  ns/op
t.CopyArray.arrayCopy                     1  avgt       10     7,566 ▒   0,961  ns/op
t.CopyArray.arrayCopy                    10  avgt       10     8,629 ▒   0,988  ns/op
t.CopyArray.arrayCopy                    16  avgt       10     9,994 ▒   0,667  ns/op
t.CopyArray.arrayCopy                  1000  avgt       10   164,613 ▒  19,103  ns/op
t.CopyArray.arrayCopy                  1024  avgt       10   320,658 ▒  26,458  ns/op
t.CopyArray.arrayCopy                  8192  avgt       10  2468,847 ▒ 204,341  ns/op
t.CopyArray.forLoop                       0  avgt       10     2,598 ▒   0,194  ns/op
t.CopyArray.forLoop                       1  avgt       10     4,161 ▒   0,841  ns/op
t.CopyArray.forLoop                      10  avgt       10    10,056 ▒   1,166  ns/op
t.CopyArray.forLoop                      16  avgt       10    11,004 ▒   1,477  ns/op
t.CopyArray.forLoop                    1000  avgt       10   207,118 ▒  36,371  ns/op
t.CopyArray.forLoop                    1024  avgt       10   206,291 ▒  26,327  ns/op
t.CopyArray.forLoop                    8192  avgt       10  1867,073 ▒ 238,488  ns/op
t.CopyArray.unsafeCopyMemory              0  avgt       10     7,080 ▒   0,082  ns/op
t.CopyArray.unsafeCopyMemory              1  avgt       10     8,257 ▒   0,184  ns/op
t.CopyArray.unsafeCopyMemory             10  avgt       10     8,424 ▒   0,365  ns/op
t.CopyArray.unsafeCopyMemory             16  avgt       10    10,129 ▒   0,076  ns/op
t.CopyArray.unsafeCopyMemory           1000  avgt       10   213,239 ▒  30,729  ns/op
t.CopyArray.unsafeCopyMemory           1024  avgt       10   310,881 ▒  34,527  ns/op
t.CopyArray.unsafeCopyMemory           8192  avgt       10  2419,456 ▒  66,557  ns/op

Conclusion:

  • Unsafe.copyMemory is never an option.
  • When array size is large power of 2, for loop is preferable over System.arraycopy.
  • Otherwise additional research is needed with your particular matrix row width.
leventov
  • 14,760
  • 11
  • 69
  • 98