javapathfinder / jpf-core

JPF is an extensible software analysis framework for Java bytecode. jpf-core is the basis for all JPF projects; you always need to install it. It contains the basic VM and model checking infrastructure, and can be used to check for concurrency defects like deadlocks, and unhandled exceptions like NullPointerExceptions and AssertionErrors.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`testStackWalkerInCaseOfChoiceGenerator` is very slow

cyrille-artho opened this issue · comments

The unit test testStackWalkerInCaseOfChoiceGenerator inStackWalkerTest is very slow (taking almost a minute?). Please check it.

Hi, @cyrille-artho . On my machine, it is testStackWalkerInCaseOfChoiceGenerator that runs very slow (up to 1 min). I think it is because many states are generated during this test execution. I'll try to use a simpler call in the case of multithread. You can compare these two:

time ./gradlew clean test --tests gov.nasa.jpf.test.java.lang.StackWalkerTest.testStackWalkerInCaseOfChoiceGenerator

and

time ./gradlew clean test --tests gov.nasa.jpf.test.java.lang.StackWalkerTest.testDeepStack

Yes, you are right, it is that one. I wonder why it is so slow.

I guess maybe these function calls using stream operations are rather complicated and might use synchronizations internally. I will first try to invoke a smaller function in Thread.run(). If it doesn't help, I'll look into the execution trace to see what happens.

Maybe you get too many interleavings where you need only two? Try making the run methods synchronized and see what happens.

Maybe you get too many interleavings where you need only two? Try making the run methods synchronized and see what happens.

This didn't seem to work for me. So the overhead is probably in the stream processing/stack walking itself.

Strange, this works for me. How do you change the test case. I change it to:

  @Test
  public void testStackWalkerInCaseOfChoiceGenerator() {
    Object lock = this;
    if (verifyNoPropertyViolation()){
      Thread t1 = new Thread() {
        @Override
        public void run() {
          synchronized (lock) {
            callIt();
          }
        }
      };
      Thread t2 = new Thread() {
        @Override
        public void run() {
          synchronized (lock) {
            callIt();
          }
        }
      };
      t1.start();
      t2.start();
    }
  }

And the time reduces to 8s.

Great, please make a PR. I hope I can also get the speed-up on my machine after the PR went through.

Ok, but I still have a question: all the objects we created in the callIt() are local. Why are there so many interleavings (JPF should have optimized them out)? I'll look into the traces later.

Not sure. Sometimes, the partial-order cannot determine for sure if actions are thread-local.

Make sense.