We said that there are two types of snooping coherence approaches.
One was write update, the other was write invalidate.
So going back to our optimized write update setup where we had the valid and
the tag bits, also the dirty bit for write back cashes and
a shared bit that tells us whether we are alone in this.
A write invalidate protocol will broadcast writes on the Bus so
that they can be seen by everybody.
But instead of updating their copies, they will invalidate them.
So let's see how this works.
Let's say this core reads A.
We send this, get the value from memory.
Now we have it as valid, not dirty.
The tag is A, the value is, let's say 0, and it's not shared.
Let's say now we have the write to A, and write 1 to it.
We have a cache miss, we broadcast the write.
We now don't need to broadcast the value with it because the other caches don't
need this value.
What's going to happen is as we send this to the Bus,
it's going to be snooped by this cache and
it sees that somebody's trying to write to the block that they have in my cache.
In our write update protocol we will now need the value to put it here.
In a write invalidate protocol all we do is change the valid bit to 0.
So now we will miss in the cache next time we read,
this particular cache now gets the valid.
It's not shared, every time we do a write with broadcast
we know it's not shared because all the other copies have been destroyed so
our write makes., The block non shared in the writing processor.
It is dirty and now it has a value of one.
So now a read of A here, in a write update protocol would be a hit and
just read here, but
in a write invalidate protocol, the read will still get the new value.
It's not going to be incoherent, because it doesn't get the value of zero.
It will not be a miss, and be sent to the Bus.
Now the memory has bot been updated yet, but the processor who has the dirty data
and matches the address of the blog will see that there is a read request on
the Bus and respond with the data, so now the blog becomes valid.
Somebody gave us the data, so definitely now it's shared.
We get the data, and the cache where we wrote
now also know's it's shared because we gave it to somebody.
So, clearly we are not the only one who has it anymore.
So now note that just like in a write update protocol,
if we have a lot of reads now they can have cache hits.
Another write will invalidate this so there will be a cache miss also.
So, the disadvantage of writing invalidate protocols is that there is
a miss on all the readers when somebody writes.
However, there is an advantage to it as well in that if you need to update
the same block twice, let's say write two to A.
We invalidate this copy by broadcasting.
Now the block is no longer shared.
We put two there.
So we have the broadcast for this first write.
If we now do some more reads and writes, they can all be done locally.
We don't have to broadcast them.
So basically by invalidating this copy, we made ourselves be the only one
who has the block and now we don't need to broadcast all the writes.
So, for anything where one core works on it for a while,
then another one works on it for a while, if the work involves writing,
only the first write really has to be broadcast.
After that, it's a local access for both reads and writes.
In contrast with write update,
we would have to keep updating the other cache until it replaces the block.
Just like with write update.
Writing validate can benefit from the type of optimization when we are writing
to different blocks and accessing it later.
So in that case B is fetched here is not shared becomes dirty and
C is fetched here is not shared becomes dirty and gets a value of 1.
And now we can have cache hits on both reads and
writes without going to the Bus for B here.
And we can access C here with no going to the Bus.
So for blocks that are only accessed on one core we have the same behavior for
both write update and write invalidate.
But for blocks that are shared we get different behavior.
Write update tends to result in more hits but
does more broadcasts, if we repeatedly update.
Write invalidate generates a miss on all the readers after a write occurred.
But it allows us to locally write after the first write.
Note that with write update, we ensured for
A that the second property of coherence is maintained.
By updating all the copies.
So when a write occurs, all copies are up to date, and
thus they will return the new value of the write.
With write invalidate,
we ensure the same property by the write invalidating all the other copies so
that now they have no choice but to get the new version of the data.
So either way, reads will get the new version of the data but
that is achieved in different ways.
The third property of coherence is
still ensured by snooping in a write invalidate protocol with snooping.
So basically snooping on the Bus still ensures that
any writes that need to go to the Bus because there is sharing
will be ordered by the order by which they go to the Bus.
So for example, a write here will invalidate everything.
Now a write here has to put a request on the Bus because it's a miss.
And also train the copy from here and now everybody knows what the order was.
In fact, at any given time, only the last version really survives in caches.
Because a write invalidates all the other copies.
So it's pretty clear whose version was last,
because all the readers need to get the copy that was written last anyway.