Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stuck in GC loop even with high xmx #209

Open
maxhillaert opened this issue Mar 27, 2019 · 7 comments
Open

Stuck in GC loop even with high xmx #209

maxhillaert opened this issue Mar 27, 2019 · 7 comments

Comments

@maxhillaert
Copy link

Hi,

I've added cover with scalameter to an algorithm. I then intentionally make it worse by doing a bad concat of lists in a tight loop.

Problem is that its so bad it never seems to fail and scalameter output keeps saying "GC detected " and sometimes "Reinstating BenchMark Value"

The memory will have exploded to 4GB, but just sit there,, even though I set XMX 10000m.

This is how the JVM is loaded:

Starting new JVM: java -server -Xmx10048m -Xms4048m -cp C:\Users\hillmax\AppData\Local\Temp\classpath1003926506.jar;C:\Users\hillmax\AppData\Roaming\JetBrains\IntelliJ IDEA Community Edition 2018.1.1\lib\idea_rt.jar org.scalameter.execution.Main C:\Users\hillmax\AppData\Local\Temp\newjvm-5758005586671152155-io

Is XMX really working in this case? Why am I hitting a GC wall at nowhere near the heap size?

@ghost
Copy link

ghost commented Mar 29, 2019

Did you try to decrease the default warmup iteration count, the iteration count, and the fork count? Maybe it's just that the algorithm is taking a long time.

  override def defaultConfig = Context(
    exec.minWarmupRuns -> 1,
    exec.maxWarmupRuns -> 1,
    exec.benchRuns -> 4,
    exec.independentSamples -> 1,
    verbose -> true
  )

This is taken from this example:

https://github.com/reactors-io/reactors/blob/master/reactors-common/jvm/src/bench/scala/io/reactors/common/concurrent/cache-trie-benches.scala

Another example if you're using it from Java (at the bottom of the page):

https://scalameter.github.io/home/gettingstarted/0.7/javausage/index.html

Also, if you add verbose -> true, you will see more detailed output about what ScalaMeter is doing.

@ghost
Copy link

ghost commented Mar 29, 2019

The default ScalaMeter benchmark configuration is re-creating the dataset every once in a while, and then doing a GC, in order to reduce the probability that the GC cycle disturbs the measurement. This is done by the Measurer.PeriodicReinstantiation trait. So, the GC's that you see are possibly manually requested.

https://github.com/scalameter/scalameter/blob/master/scalameter-core/src/main/scala/org/scalameter/Measurer.scala

https://github.com/scalameter/scalameter/blob/master/scalameter-core/src/main/scala/org/scalameter/Measurer.scala#L209

You can, of course, disable this by implementing your own Measurer class, or instantiating another Measurer implementation in ScalaMeter (see source code, you should get rid of PeriodicReinstantiation).
You should, in that case, specify the measurer in your concrete test (i.e. override the measurer method). This is relatively easy to do, but it sounds that in your case the test is taking long because the default warmup iteration count might have to be reduced.

@maxhillaert
Copy link
Author

maxhillaert commented Mar 29, 2019 via email

@ghost
Copy link

ghost commented Mar 29, 2019

It’s just that I want to make sure if someone reintroduces the
concatenation bug , it fails the test rather than get stuck in a loop
trying to measure it.

One approach could be to implement a custom Measurer that starts a new thread to run the workload, and then stops the thread after a timeout or exits the process.

@maxhillaert
Copy link
Author

maxhillaert commented Mar 29, 2019 via email

@maxhillaert
Copy link
Author

So I've tried creating a warmer with a timeout:

var i = 0
    while (i < maxwarmups) {

      setup()
      nogc = true
      val start = System.nanoTime

      if(maxRunningTime.nonEmpty){
        val ftr = Future(f(i))
        Await.result(ftr, maxRunningTime.get )
      }
      else{
        f(i)
      }

It blows up the whole test suite of course, so a bit blunt. Any idea's on how to let it end the test run more gracefully and continue with next test?

@ghost
Copy link

ghost commented Mar 29, 2019

I would use Await.ready here, as it does not throw an exception.

But, I would not use futures at all, since Await does not cancel the computation in the future - i.e. your job will still be running. Starting a new thread, and force-stopping it with Thread.stop would be the best way to go if you want to kill the algorithm.

I think that you would then have to implement a custom Reporter that checks if a timeout occurred, and then override the reporter method in your test to decide whether the test failed or passed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant