0

I'm going to measure performance of some code. For the purpose, I introduced the following method:

def timed[T](body: => T) = {
  val start = System.currentTimeMillis
  blackHole = body
  val end = System.currentTimeMillis
  end - start
}

The blackHole variable introduced in order to preserve body result. This is done to prevent dead code elimination by JVM.

In some books there is a statement that blackHole should be declared as follows:

@volatile
var blackHole: Any = _

Why should one mark the variable volatile?

Aliaxander
  • 2,547
  • 4
  • 20
  • 45
  • 1
    unless your method runs for > 1second you probably should use a microbenchmark framework like jmh, see http://stackoverflow.com/q/504103/1362755 – the8472 Nov 19 '16 at 17:01
  • Please reference the book. And ideally quote the whole statement you'd like to get clarified. Also the title of your question doesn't match well the question you've asked here – Ivan Nov 19 '16 at 17:01
  • @the8472 Yes, I know, but in my particular case I'm trying to understand why volatility matters here. – Aliaxander Nov 19 '16 at 17:11
  • @Ivan Learning Concurrent Programming in Scala: `Certain runtime optimizations in the JVM, such as the dead-code elimination, can potentially remove the invocation of the body block, causing us to measure an incorrect running time. To prevent this, we assign the return value of the body block to a volatile field` – Aliaxander Nov 19 '16 at 17:12
  • That seems to be wishful thinking. Whether dead code elimination applies or not, depends on whether the JVM can detect that the result is actually unused. Adding `volatile` to the variable adds a *hint*, that other threads might be using it, but this is mostly irrelevant. The JVM has to assume other threads potentially reading the value at the next write barrier anyway and there will be at least one, the thread’s end. If, however, the variable has a local scope, e.g is a member of an object that is never seen by other threads, the `volatile` modifier doesn’t help either. – Holger Nov 21 '16 at 13:05

2 Answers2

2

When you run code for quite a while, you will have Just In Time compiler (JIT) invoked for critical code parts. There are a few optimizations it will try to perform.

Dead code elimination. The code has no observable side effects, it can be removed.

You counter that by assigning the result to an instance variable you make harder to prove that the value is 'unused'. Potentially somebody from another class / thread can use that value later.

Volatile part wasn't really necessary in my benchmark. One of the blogs I read mentioned that JIT can drop writes for variables without it (link) though.

Ivan
  • 3,781
  • 16
  • 20
  • #2 seems relevant but I cannot find any info about this particular type of optimization. Could you provide the reference? – Aliaxander Nov 19 '16 at 18:06
  • this is especially applicable when the whole thing is executed in a loop, the compiler might decide to only use the last result of the loop execution, which in turn leads to all previous iterations being subject to DCE. – the8472 Nov 19 '16 at 18:19
  • @Aliaxander re: #2, that was on a blog I've read at some point. I created a small benchmark to test that and in my case (`build 1.8.0_45-b14`) volatile was not necessary. Dima's answer may have some merit in it re this point. I'll update my answer to exclude that unconfirmed part – Ivan Nov 19 '16 at 19:06
  • 1
    It must be emphasized that JVMs can drop writes to `volatile` variables too. A `volatile` modifier only guarantees a *happens-before* relationship between writes and subsequent reads *of the same variable*. If there is no subsequent read, which can be proven for instance fields of a local object, the `volatile` modifier has no effect. However, if the object does escape its context, the write can’t be elided even without `volatile`, it might only be postponed to the next write barrier. – Holger Nov 21 '16 at 13:11
  • @Holger does it mean that the tip to mark the field `volatile` is senseless? – Aliaxander Nov 22 '16 at 14:19
  • @Aliaxander: without further context, yes, it does not add safety. You are much safer by assigning it to a local variable (to avoid adding costs), then, after measuring the execution time, just *print* the result to the console. Obviously, a JVM can’t eliminate the calculation if the result is printed, whether you ever read it or not. Since you print only after taking the time, the printing costs are not measured. It’s not bullet-proof, but there is no bullet-proof technique anyway. By the way, you should use `System.nanoTime()` to measure *elapsed time*, as this is immune to, e.g. NTP updates – Holger Nov 22 '16 at 14:34
1

The reason is that without volatile, that code is as dead as it was without the assignment. When you write to a non-volatile variable, the result of that operation is not guaranteed to be seen by other threads accessing that variable. So, as long as you are not reading the result back in the same thread, the write has never happened, as far as the outside world is concerned.

Dima
  • 39,570
  • 6
  • 44
  • 70