Hardware Transactional Memory in JAVA

Viewed 494

I asked myself: What happend with Transactional Memory and the Intel TSX Extension? I found a lot about TSX-bugs in CPUs, but I did not find examples, tutorials, best practices.

But I found the "-server -XX:+UseRTMLocking" JVM-option. I wrote a little testprogram and I was surprised about the effect this option can have on execution time. (Intel i7 6700K, jvm 8.131)

Does anybody have experience with this flag?

Greetings, Thomas

Here the program:

import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TSXTest {
    final int N;
    final Object o = new Object();
    final int[] variables;
    public TSXTest(int n) {
        this.N = n;
        variables = new int[N];
    }

    public static void main(String[] args) throws InterruptedException {
        int n = 100000;
        while (true) {
            new TSXTest(n).go(false);
            if (n == 1) {
                break;
            }
            n = n / 10;
        }

        n = 100000;
        while (true) {
            new TSXTest(n).go(true);
            if (n == 1) {
                break;
            }
            n = n / 10;
        }
    }

    private void go(boolean doSync) throws InterruptedException {
        //  -XX:+UseRTMLocking
        ExecutorService es = Executors.newFixedThreadPool(4);
        Collection cs = new ArrayList<>();
        cs.add(new Task(100, doSync));
        cs.add(new Task(200, doSync));
        cs.add(new Task(300, doSync));
        cs.add(new Task(400, doSync));

        long start = System.nanoTime();
        es.invokeAll(cs);
        es.shutdown();
        System.out.println("synchronized: "+ doSync + "; Nmb of Variables:" + N + ";  Duration:" + ((System.nanoTime() - start) / 1000000));

    }

    public class Task implements Callable<Void> {

        final Random r;
        private int seed;
        private boolean sync;
        private int[] rnd = new int[N];

        public Task(int seed, boolean sync) {
            r = new Random(seed);
            this.seed = seed;
            this.sync = sync;
            List<Integer> rndList = new ArrayList<>();
            for (int i = 0; i < N; i++) {
                rndList.add(i);
            }

            Collections.shuffle(rndList, r);
            for (int i = 0; i < N; i++) {
                rnd[i] = rndList.get(i).intValue();
            }
        }

        @Override
        public Void call() throws Exception {
            for (int i = 0; i < 100000000; i++) {
                if (sync)
                    synchronized (o) {
                        variables[rnd[i % N]]++;
                    }
                else variables[rnd[i % N]]++;

            }
            return null;
        }
    }
}

And the results:

with "-server -XX:+UseRTMLocking"
synchronized: false; Nmb of Variables:100000;  Duration:1092
synchronized: false; Nmb of Variables:10000;  Duration:1390
synchronized: false; Nmb of Variables:1000;  Duration:1561
synchronized: false; Nmb of Variables:100;  Duration:2466
synchronized: false; Nmb of Variables:10;  Duration:2118
synchronized: false; Nmb of Variables:1;  Duration:391
synchronized: true; Nmb of Variables:100000;  Duration:3133
synchronized: true; Nmb of Variables:10000;  Duration:3400
synchronized: true; Nmb of Variables:1000;  Duration:5406
synchronized: true; Nmb of Variables:100;  Duration:15246
synchronized: true; Nmb of Variables:10;  Duration:24955
synchronized: true; Nmb of Variables:1;  Duration:23940

with "-server"
synchronized: false; Nmb of Variables:100000;  Duration:1053
synchronized: false; Nmb of Variables:10000;  Duration:1313
synchronized: false; Nmb of Variables:1000;  Duration:1524
synchronized: false; Nmb of Variables:100;  Duration:2242
synchronized: false; Nmb of Variables:10;  Duration:2121
synchronized: false; Nmb of Variables:1;  Duration:432
synchronized: true; Nmb of Variables:100000;  Duration:39720
synchronized: true; Nmb of Variables:10000;  Duration:23748
synchronized: true; Nmb of Variables:1000;  Duration:21648
synchronized: true; Nmb of Variables:100;  Duration:21243
synchronized: true; Nmb of Variables:10;  Duration:17058
synchronized: true; Nmb of Variables:1;  Duration:20845

What happens?

4 threads are modifying 100000000 times one of N variables.

The fastest version is, when there is no synchronisation at all.

When using TSX, the executiontime grows with growing conflict rate (big N --> small N ; short execution time --> long execution time)

With standard synchronisation, the execution time seams to grow with data size???

More complex operation: When using a slightly more complex operation, where synchronized cannot be replaced by the use of AtomicInteger, the result is similar.

        ...
        @Override
        public Void call() throws Exception {
            for (int i = 0; i < 100000000; i++) {
                if (sync)
                    synchronized (o) {
                        operation(i);
                    }
                else  operation(i);

            }
            return null;
        }

        private void operation(int i){
            int i1 = variables[rnd[i % N]]++;
            variables[rnd[(i+1) % N]] = i1 + 17;
        }
    }
}


with "-server -XX:+UseRTMLocking":
synchronized: false; Nmb of Variables:100000;  Duration:1259
synchronized: false; Nmb of Variables:10000;  Duration:876
synchronized: false; Nmb of Variables:1000;  Duration:1351
synchronized: false; Nmb of Variables:100;  Duration:2014
synchronized: false; Nmb of Variables:10;  Duration:408
synchronized: false; Nmb of Variables:1;  Duration:367
synchronized: true; Nmb of Variables:100000;  Duration:4234
synchronized: true; Nmb of Variables:10000;  Duration:3886
synchronized: true; Nmb of Variables:1000;  Duration:7826
synchronized: true; Nmb of Variables:100;  Duration:24587
synchronized: true; Nmb of Variables:10;  Duration:23480
synchronized: true; Nmb of Variables:1;  Duration:22382


with "-server":
synchronized: false; Nmb of Variables:100000;  Duration:1264
synchronized: false; Nmb of Variables:10000;  Duration:893
synchronized: false; Nmb of Variables:1000;  Duration:1342
synchronized: false; Nmb of Variables:100;  Duration:2036
synchronized: false; Nmb of Variables:10;  Duration:402
synchronized: false; Nmb of Variables:1;  Duration:333
synchronized: true; Nmb of Variables:100000;  Duration:35944
synchronized: true; Nmb of Variables:10000;  Duration:23031
synchronized: true; Nmb of Variables:1000;  Duration:22476
synchronized: true; Nmb of Variables:100;  Duration:24387
synchronized: true; Nmb of Variables:10;  Duration:20457
synchronized: true; Nmb of Variables:1;  Duration:22227
0 Answers
Related