-1

Which is faster:

if(this.foo != 1234)
   this.foo = 1234;

or

this.foo = 1234;

is the penalty of write high enough that one should check value before writing or is it faster to just write?

wouldn't having a branch cause possible mispredictions and screwup cpu pipleine? but what is the field is volatile, with writes having higher cost than reads?

yes, it is easy to say that in isolation these operations themselves are 'free' or benchmark it but that is not an answer.

user207421
  • 305,947
  • 44
  • 307
  • 483
pdeva
  • 43,605
  • 46
  • 133
  • 171
  • 4
    Why is this tagged assembly? – Thilo Oct 26 '14 at 01:32
  • cause i believe a good answer would probably talk about machine level code – pdeva Oct 26 '14 at 01:33
  • Your first case has to push `1234` on the stack, push a reference to `this`, access field `foo` on that reference, push its value on the stack, compare the values on the stack, branch if not equal. – Sotirios Delimanolis Oct 26 '14 at 01:50
  • 2
    Machine code != assembly. In java we call our 'machine' code byte code. Seriously give the assembly guys a break and ditch the tag. – candied_orange Oct 26 '14 at 01:51
  • This is a very complicated question, actually, and depends on a lot of variables. In certain scenarios where writing is expensive the first form can be faster, on average. (It's often very expensive to "dirty" a cache line.) – Hot Licks Oct 26 '14 at 02:02
  • 2
    On a specific architecture either might be faster. Branches frequently lose time because they are generally associated with pipeline flushes. However, the test _might_ be worthwhile on a multi-core/multiprocessor machine where a write voids the cache because the value might be shared. Never ever code wonky stuff like this, however, unless it's fixing a known problem. – Gene Oct 26 '14 at 02:09

5 Answers5

2

There is a nice example illustrating this dilemma in the very recent talk by Sergey Kuksenko about hardware counters (slides 45-49), where the right answer for the same code depends on the data size! The idea is that "compare and set" approach cause more branch misses and loads, but less stores and L1 store misses. The difference is subtle, and I can't even rationalize why one factors overweight different on small data sizes, but become less signigicant on large data sizes.

So, measure, don't guess.

leventov
  • 14,760
  • 11
  • 69
  • 98
1

Both those operations are free: they really take almost no time!

Now if this code is in a loop, you should definitely favor the second option as it will minimize branch mispredictions.

Otherwise, what matters here is what makes the code the more readable. And again in my opinion, the second option is clearer.

Also as mentionned in the comments, assigning is an atomic operation which makes it thread safe. An other advantage for the second option.

Jean Logeart
  • 52,687
  • 11
  • 83
  • 118
  • what about a volatile variable, where a write is usually more expensive than read – pdeva Oct 26 '14 at 01:35
  • @Thilo: Are you sure about that? My understanding of the Java Memory Model was that it doesn't allow completely spurious values to be perceived; I don't *think* that `if(this.foo != 1234) this.foo = 1234;` is any less threadsafe than `this.foo = 1234;`. (Just because it's `1234` both times. Obviously if the condition were different, that would not be true.) – ruakh Oct 26 '14 at 01:41
  • @ruakh: You won't get completely spurious values, but I think if some other thread changed the value of `foo` between the two lines, you may get an unexpected outcome. (But you are right, maybe not in this particular case, the "worst" that can happen is probably a redundant assignment) – Thilo Oct 26 '14 at 02:00
1

They are not free. They cost time and space. And branching in a tight loop can actually be very costly because of branch prediction (kid's these days and their modern CPUs) . See Mysticial's answer.

But mostly it's pointless. Either just set to what it should be or throw when it's not what you expect.
Any code you make me read had better have a good reason to exist.

What I think you are trying to do is express what you expect it's value to be and assert that it should be that. Without context I can't tell you if you should throw when your expectations are violated or simply assign to assert what it should be. But making your expectations clear and enforcing them one way or another is certainly worth a few CPU cycles. I'd rather you were a little slower than quickly giving me garbage in and garbage out.

Community
  • 1
  • 1
candied_orange
  • 7,036
  • 2
  • 28
  • 62
  • 1
    By free I mean costless in an app. And you say nothing different than me here. – Jean Logeart Oct 26 '14 at 01:53
  • I could say the same to you. Could we be decent about this? I just broke 1000. Don't spoil my good mood : ) – candied_orange Oct 26 '14 at 02:09
  • And congratulations for this. Every answer is welcome. I was just mentioning that your answer does not really bring more information. But you are free to post, and people are free to vote. – Jean Logeart Oct 26 '14 at 02:35
1

I believe this is actually a general question rather than java-related because of low level of this operations (CPU, not JVM level).

First of all, let's see what the choice is. On one hand we have reading from memory + comparison + (optionally) writing to memory, on other hand - writing to memory.

Memory access is much more expensive than registry operations (operations on data, already loaded to CPU). Therefore, choise is read + (sometimes) write vs write.

What is more expensive, read or write? Short answer - write. Long answer - write, but difference is probably small and depends on system caching strategy. It is not easy to explain in a few words, you can learn more about caching in the beautiful book "Operating Systems" by William Stallings.

I think in practice you can ignore distinction between read and write operations and just write without a test. That is because (returning back to Java) your object with all it's fields will be in cache for this moment.

Another thing to consider is branch prediction - others already mentioned that this is the reason to just write value without test too.

Stanislav Lukyanov
  • 2,147
  • 10
  • 20
  • +1 Actually that's a good point. In a tight loop where something like this is going to even matter, it's probably already in the registry if not merely the cache. One means we have both foo, 1234, and foo - 1234 in the registry. The other means we only have foo and 1234. So even if the CPU cycles are a wash there is going to be a space difference. – candied_orange Oct 26 '14 at 02:26
0

It depends on what you're really interested in.

If this is a plain old vanilla program, not only does the fetch/compare/branch of the first scheme take extra time, but it's extra code and complexity, and even if the first scheme did actually save a miniscule amount of time (instead of costing time) it wouldn't be worth doing it.

However, there are scenarios where it would be different. In an intensely multi-threaded environment with multiple processors modifying shared storage can be expensive, since changes to that storage need to be propagated to other processors. In such an environment it could be well worth it to spend a few extra instructions to avoid "dirtying" cache.

Hot Licks
  • 47,103
  • 17
  • 93
  • 151