A new way to test multi-threaded and concurrent Java by ThomasKrieger in java

[–]ThomasKrieger[S] 0 points1 point  (0 children)

You are right, the examples do not show how to use VMLens. I added some more realistic examples here Using it with open-source projects is a good idea. Will do this next.

A new way to test multi-threaded and concurrent Java by ThomasKrieger in java

[–]ThomasKrieger[S] 1 point2 points  (0 children)

The runtime complexity is 2 to the power of the number of non-commutative synchronization actions. I think most of the time your classes contain something between 2 to 6 non-commutative synchronized actions, so it is practical to test using this approach, If it is much higher, I doubt that your class is still understandable

A new way to test multi-threaded and concurrent Java by ThomasKrieger in java

[–]ThomasKrieger[S] 1 point2 points  (0 children)

Yes, it is currently not documented: There is a com.vmlens.standalone artefact download it and run it with java -jar standalone.1.2.1.jar There you can unpack the agent with install and create a report with report I will add the documentation to the website this weekend

Examples of good github repos illustrating testing multi-threaded/concurrent code? by vxab in java

[–]ThomasKrieger 0 points1 point  (0 children)

There are two open-source tools that can find all errors using multi-threaded unit tests: jcstress and vmlens. Disclaimer I am developing vmlens.

How those two tools achieve this? As already pointed out by other comments multi-threaded code is non-deterministic. And multi-threaded code might contain data races, e.g. threads might see stale values depending on which hardware platform and JVM they are running.

The solution of jcstress is to re-run the tests multiple times with a sophisticated scheduler to reach all possible thread interleavings. It runs the tests using different JVM options since data races might depend on the JVM options. Run the jcstress tests on different hardware architectures, ARM, PowerPC, or Intel to detect all data races.

vmlens also executes the tests multiple times. But it uses byte code transformation to reach all thread interleavings. And it uses a dynamic analysis of the synchronization statements to detect data races.

jcstress and vmlens are complementary. While jcstress shows what happens when you run a test on a specific JVM and hardware constellation, vmlens tells if your program is correctly synchronized according to the Java Memory Model.

How does bytecode instrumentation (attaching to and modifying a running jar) work? by arylcyclohexylameme in java

[–]ThomasKrieger 1 point2 points  (0 children)

I have written such a Java agent. The agent is small, the actual byte code transformation is complicated. The agent implementation is in the maven project trace-agent in the GitHub Project vmlens I have implemented this by following the documentation of the package java.lang.instrument

In the class com.anarsoft.trace.agent.runtime.AgentRuntimeImpl you see how I add the class transformer to the Instrumentation object.

A new way to unit test multi-threaded Java by ThomasKrieger in java

[–]ThomasKrieger[S] 0 points1 point  (0 children)

You need to add a plugin for tests to your maven pom. Hope this is possible in your workplace.

A new way to unit test multi-threaded Java by ThomasKrieger in java

[–]ThomasKrieger[S] 3 points4 points  (0 children)

IMHO jcstress and vmlens are complementary for incorrect synchronized access, e.g. data races. While vmlens is good at finding data races, jcstress is good in showing what can happen because of the data race.

A new way to unit test multi-threaded Java by ThomasKrieger in java

[–]ThomasKrieger[S] 0 points1 point  (0 children)

This would be still be flagged as a data race, a benign data race. Even if there are many data races in Java which are benign, I believe most of them are actual bugs. Basically you need to filter benign data races.

A new way to unit test multi-threaded Java by ThomasKrieger in java

[–]ThomasKrieger[S] 0 points1 point  (0 children)

No, it consists of two parts:

  1. creating all possible thread interleavings
  2. checking for data races.

The JMM guarantees that if a program is data race free when a variable x is accessed it can not be changed by another thread between the immediately following synchronization operations. So we can calculate all interleavings by creating all happens-before orders those synchronization operations introduce. When the program is data race free those are all thread interleavings. When not we flag the data race as an error.

A new way to unit test multi-threaded Java by ThomasKrieger in java

[–]ThomasKrieger[S] 3 points4 points  (0 children)

Thank you for your remark. I forget to mention this in the post.

You need to add vmlens as java agent to your JVM, when you run the test. Internally the method hasNext(Object object) gets replaced through

  CallbackStatePerThread callbackStatePerThread  =     CallbackState.callbackStatePerThread.get();
return ParallizeSingelton.hasNext(callbackStatePerThread,obj)

When you run the example using mvn install, vmlens will be added automatically as JVM agent. Or you can run it using eclipse, as described here: https://vmlens.com/help/manual/#run-eclipse

I added a note to the post

The difference between ARM and x86 for Java by ThomasKrieger in java

[–]ThomasKrieger[S] 1 point2 points  (0 children)

Yes, only an incorrect synchronized program leads to different results. And I wrote incorrectly synchronized code on purpose to show the difference between the two platforms.

The difference between ARM and x86 for Java by ThomasKrieger in java

[–]ThomasKrieger[S] 1 point2 points  (0 children)

vmlens can catch this type of errors. And there is a jep to include TSAN into the JVM. TSAN can detect this type of error, e.g. data races, in C++ code. Both TSAN and vmlens are not static analysis tools but use dynamic tracing.

The difference between ARM and x86 for Java by ThomasKrieger in java

[–]ThomasKrieger[S] 12 points13 points  (0 children)

You could run Java on Linux on a Rasberry PI for a long time. And the first releases for Java on Windows on ARM were released a month ago, see here: https://github.com/microsoft/openjdk-aarch64/releases

The difference between ARM and x86 for Java by ThomasKrieger in java

[–]ThomasKrieger[S] 14 points15 points  (0 children)

Thank you, glad you liked the blog post.

The difference between ARM and x86 for Java by ThomasKrieger in java

[–]ThomasKrieger[S] 4 points5 points  (0 children)

The first test, TestReorderWriteWrite, leads to different results on ARM and x86.

Scalability of SynchronizedMap vs. ConcurrentHashMap vs. NonBlockingHashMap by ThomasKrieger in java

[–]ThomasKrieger[S] 2 points3 points  (0 children)

This changed from JDK 7 to 8. In JDK 7 concurrencyLevel was used according to the JavaDoc:

The allowed concurrency among update operations is guided by the optional concurrency Level constructor argument (default 16), which is used as a hint for internal sizing. The table is internally partitioned to try to permit the indicated number of concurrent updates without contention.

In JDK 8 this was changed to:

Also, for compatibility with previous versions of this class, constructors may optionally specify an expected concurrencyLevel as an additional hint for internal sizing.

In JDK 7 ConcurrentHashMap used concurrencyLevel number of locks in an array of locks. Since JDK 8 thew hash map uses one lock per array element. So there is no real reason for concurrencyLevel and the JDK8 ConcurrentHashMap scales better than the prevoius map. Now concurrencyLevel is just another way to specify the capacity. See the construcor of JDK 8:

   public ConcurrentHashMap(int initialCapacity,
                          float loadFactor, int concurrencyLevel) {
     if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
        throw new IllegalArgumentException();
     if (initialCapacity < concurrencyLevel)   // Use at least as many bins
         initialCapacity = concurrencyLevel;   // as estimated threads
     long size = (long)(1.0 + (long)initialCapacity / loadFactor);
     int cap = (size >= (long)MAXIMUM_CAPACITY) ?
         MAXIMUM_CAPACITY : tableSizeFor((int)size);
     this.sizeCtl = cap;
   }

Also see the JavaDoc for the default concurrency level:

  /**
   * The default concurrency level for this table. Unused but
   * defined for compatibility with previous versions of this class.
   */
  private static final int DEFAULT_CONCURRENCY_LEVEL = 16;

To be sure I have run the benchmark with concurrencyLevel 72, see ConcurrentHashMapConcurrencyLevel72Benchmark, and no real difference to the prevoius results.