<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Beburrou</id>
	<title>Expertiza_Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Beburrou"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Beburrou"/>
	<updated>2026-06-03T16:48:56Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45281</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45281"/>
		<updated>2011-04-23T20:40:41Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Solihin 11.4 Resolution */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(Unless otherwise noted, the contents of this article is derived from the IEEE standardization document titled &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI)&amp;quot;&amp;lt;sup&amp;gt;&amp;lt;span class = &amp;quot;plainlinks&amp;quot;&amp;gt;[[#References|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; .)&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
These states are used by the coherency model to determine the state of the cache line when memory transactions are performed by individual processors.  Likewise, these memory states are impacted when these memory transactions occur.&lt;br /&gt;
&lt;br /&gt;
Below is a state diagram that depicts the transition between these memory states:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:memory_state.png|center]]&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL, and the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
====States of the Typical Set====&lt;br /&gt;
&lt;br /&gt;
Following are the states defined for the Typical set.  (Note that other states may be supported to provide certain interoperability with nodes implementing the Full set, but are not used when all nodes support the Typical set.)&lt;br /&gt;
&lt;br /&gt;
* '''ONLY_DIRTY''' - only one processor has the memory block in its cache.  This block is writable, and the processor has written (or intends) to write to it.  This state is set when the processor requests the block with read/write privileges, and no other processor currently caches the block.&lt;br /&gt;
* '''ONLY_FRESH''' - only one processor had the memory block in its cache.  This block is writeable, but processor has not written to it.  This state is set when the processor requests the block with read privileges, and no other processor currently caches the block.&lt;br /&gt;
* '''HEAD_DIRTY''' - more than one processor has the memory block in its cache.  This block is writable, and the processor has written (or intends) to write to it.  This state is set when the processor requests the block with read/write privileges, and another processors already caches the block.&lt;br /&gt;
* '''HEAD_FRESH''' - more than one processor had the memory block in its cache.  This block is writeable, but processor has not written to it.  This state is set when the processor requests the block with read privileges, and another processors already caches the block.&lt;br /&gt;
* '''MID_VALID''' - more than two processors have the memory in its cache, and it is readable.  The processor cache with this state is neither the Head or the Tail of the of the sharing list.&lt;br /&gt;
* '''TAIL_VALID''' - more than two processors have the memory in its cache, and it is readable.  The processor cache with this state is the Tail of the of the sharing list.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Below is a state diagram that depicts these states:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
The request sub-actions of memory transactions that expect a response from the directory include 17 variations of reads, writes, and locks based on the number of bytes requested and the coherency requirements.  For convenience, the notation on the edges of the above graph is derived from the terms used in the SCI specification to describe the memory transactions. &lt;br /&gt;
&lt;br /&gt;
The first value indicates the request to the directory by a node for memory access:&lt;br /&gt;
* '''Fetch R''' - indicates a request for a memory block with read privileges.&lt;br /&gt;
* '''Fetch RW''' - indicates a request for a memory block with read/write privileges.&lt;br /&gt;
* '''Data Modify''' - indicates that a processor (the HEAD or the ONLY processor caching the block) writes to the cache line.&lt;br /&gt;
&lt;br /&gt;
The value in the parenthesis indicates the memory state at the time of the request.&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as querying memory for a data or invalidating a node's cache.  This usually takes the form a a request-response pair, where the initiating node sends a request to another node and waits for the response.  The transaction is not complete until the response returns.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, having requested a block of data from memory and not having received a response, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' will be in the ''PENDING''&amp;lt;sup&amp;gt;&amp;lt;span class = &amp;quot;plainlinks&amp;quot;&amp;gt;[[#Definitions_and_Terms|[definitions]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; state, so any requests to demote it from the ''Head'' position will be delayed..  This could lead to a chaining of nodes in the ''PENDING'' state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
The design of the SCI protocol prevents many race conditions from occurring, as has already been shown.  Here are two other conditions that may arise, with a discussion of how the protocol resolves the issue.&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
Even though the ''Head'' node performs most of the coherence actions for a shard list, the individual nodes are able to invalidate themselves, such as when they evict the block from their cache.  This is referred to in the SCI standard as a &amp;quot;deletion&amp;quot; from the sharing list.  Deletion is accomplished by having the invalidating node &amp;quot;lock&amp;quot; itself and then inform its forward and back nodes that they should now point to each other.  This &amp;quot;locking&amp;quot; is essentially another ''PENDING'' state.  A problem could arise, then, when two neighboring nodes try to invalidate themselves at the same time, as they would both be locked and not respond to each other's message.  In this case, though, the protocol specifies that the node that is closest to the tail takes priority (IEEE pg156)&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;1body&amp;quot;&amp;gt;[[#1foot|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;.  So, the deadlock and/or race condition is averted by ordering the deletion from the tail towards the head.&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
Another potential race condition occurs when the ''Head'' node tries to purge the list of sharers at the same time as a node in the list tries to remove itself from the list.  Suppose that the ''Head'' node is trying to purge node ''A'', which has node ''B'' as its next node in the list, while at the same time, node ''B'' is trying to remove itself from the list.  Node ''B'' needs to tell node ''A'' to update its next pointer, but the ''Head'' node will need to access node ''A'''s next pointer to know what the next node in the list is.  An illustration is shown below.  The ''1'' and the ''2'' represent the messages being sent from the respective node to node ''A'' that have not yet arrived.&lt;br /&gt;
[[Image:PurgeDelete.png|center]]&lt;br /&gt;
What will happen is that one of the messages will reach node ''A'' first.  While ''A'' is responding to this message, it will tell other nodes that it is busy, in a similar manner to the notion of the atomic transactions.  If node ''B'''s message arrives first, causing the message from the ''Head'' node to be rejected.  Node ''A'' will have its forward pointer changed at this point, so when the ''Head'' node resends its request, all will work as expected.&lt;br /&gt;
The second option is more difficult.  If the ''Head'' node's message arrives first, node ''A'' will be invalidated, so that when the message from node ''B'' is sent again, node ''A'' will simply inform node ''B'' that it is no longer part of the list.  As well, the ''Head'' node will now have its forward pointer pointing at node ''B''.  Node ''A'' has thus been successfully purged, but we arrive at an impasse, as now the ''Head'' node will try to invalidate the locked node ''B'', while node ''B'' will try to tell the ''Head'' node to change its forward pointer, with both nodes being inside a transaction.  This situation is illustrated by the following figure.&lt;br /&gt;
[[Image:PurgeDelete2.png|center]]&lt;br /&gt;
The protocol does not specify how to handle this situation, but it would make sense for the protocol to allow one of the messages through, presumably the ''Head'' node's message.  Node ''B'' could simply respond in the affirmative, telling the ''Head'' node what the following node is, but this would only work if node ''B'' notifies the next node of the deletion after it notifies node ''A''.  Otherwise, the node following ''B'' would have its back pointer pointing to the wrong node.  The protocol standard seems to suggest that this is the case (IEEE, pg162)&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;1body&amp;quot;&amp;gt;[[#1foot|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''PENDING state'' - The intermediate state for a node while it is attempting to become the ''Head'' node in the sharing list.  This includes the transaction involved in querying the ''Home'' node and the transaction involved in demoting the current ''Head'' node.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45231</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45231"/>
		<updated>2011-04-19T03:53:53Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Concurrent List Deletions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(Unless otherwise noted, the contents of this article is derived from the IEEE standardization document titled &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI)&amp;quot;&amp;lt;sup&amp;gt;&amp;lt;span class = &amp;quot;plainlinks&amp;quot;&amp;gt;[[#References|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; .)&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
These states are used by the coherency model to determine the state of the cache line when memory transactions are performed by individual processors.  Likewise, these memory states are impacted when these memory transactions occur.&lt;br /&gt;
&lt;br /&gt;
Below is a state diagram that depicts the transition between these memory states:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:memory_state.png|center]]&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL, and the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
====States of the Typical Set====&lt;br /&gt;
&lt;br /&gt;
Following are the states defined for the Typical set.  (Note that other states may be supported to provide certain interoperability with nodes implementing the Full set, but are not used when all nodes support the Typical set.)&lt;br /&gt;
&lt;br /&gt;
* '''ONLY_DIRTY''' - only one processor has the memory block in its cache.  This block is writable, and the processor has written (or intends) to write to it.  This state is set when the processor requests the block with read/write privileges, and no other processor currently caches the block.&lt;br /&gt;
* '''ONLY_FRESH''' - only one processor had the memory block in its cache.  This block is writeable, but processor has not written to it.  This state is set when the processor requests the block with read privileges, and no other processor currently caches the block.&lt;br /&gt;
* '''HEAD_DIRTY''' - more than one processor has the memory block in its cache.  This block is writable, and the processor has written (or intends) to write to it.  This state is set when the processor requests the block with read/write privileges, and another processors already caches the block.&lt;br /&gt;
* '''HEAD_FRESH''' - more than one processor had the memory block in its cache.  This block is writeable, but processor has not written to it.  This state is set when the processor requests the block with read privileges, and another processors already caches the block.&lt;br /&gt;
* '''MID_VALID''' - more than two processors have the memory in its cache, and it is readable.  The processor cache with this state is neither the Head or the Tail of the of the sharing list.&lt;br /&gt;
* '''TAIL_VALID''' - more than two processors have the memory in its cache, and it is readable.  The processor cache with this state is the Tail of the of the sharing list.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Below is a state diagram that depicts these states:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
The request sub-actions of memory transactions that expect a response from the directory include 17 variations of reads, writes, and locks based on the number of bytes requested and the coherency requirements.  For convenience, the notation on the edges of the above graph is derived from the terms used in the SCI specification to describe the memory transactions. &lt;br /&gt;
&lt;br /&gt;
The first value indicates the request to the directory by a node for memory access:&lt;br /&gt;
* '''Fetch R''' - indicates a request for a memory block with read privileges.&lt;br /&gt;
* '''Fetch RW''' - indicates a request for a memory block with read/write privileges.&lt;br /&gt;
* '''Data Modify''' - indicates that a processor (the HEAD or the ONLY processor caching the block) writes to the cache line.&lt;br /&gt;
&lt;br /&gt;
The value in the parenthesis indicates the memory state at the time of the request.&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as querying memory for a data or invalidating a node's cache.  This usually takes the form a a request-response pair, where the initiating node sends a request to another node and waits for the response.  The transaction is not complete until the response returns.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, having requested a block of data from memory and not having received a response, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' will be in the ''PENDING''&amp;lt;sup&amp;gt;&amp;lt;span class = &amp;quot;plainlinks&amp;quot;&amp;gt;[[#Definitions_and_Terms|[def]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; state, so any requests to demote it from the ''Head'' position will be delayed..  This could lead to a chaining of nodes in the ''PENDING'' state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
The design of the SCI protocol prevents many race conditions from occurring, as has already been shown.  Here are two other conditions that may arise, with a discussion of how the protocol resolves the issue.&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
Even though the ''Head'' node performs most of the coherence actions for a shard list, the individual nodes are able to invalidate themselves, such as when they evict the block from their cache.  This is referred to in the SCI standard as a &amp;quot;deletion&amp;quot; from the sharing list.  Deletion is accomplished by having the invalidating node &amp;quot;lock&amp;quot; itself and then inform its forward and back nodes that they should now point to each other.  This &amp;quot;locking&amp;quot; is essentially another ''PENDING'' state.  A problem could arise, then, when two neighboring nodes try to invalidate themselves at the same time, as they would both be locked and not respond to each other's message.  In this case, though, the protocol specifies that the node that is closest to the tail takes priority (IEEE pg156)&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;1body&amp;quot;&amp;gt;[[#1foot|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;.  So, the deadlock and/or race condition is averted by ordering the deletion from the tail towards the head.&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
Another potential race condition occurs when the ''Head'' node tries to purge the list of sharers at the same time as a node in the list tries to remove itself from the list.  Suppose that the ''Head'' node is trying to purge node ''A'', which has node ''B'' as its next node in the list, while at the same time, node ''B'' is trying to remove itself from the list.  Node ''B'' needs to tell node ''A'' to update its next pointer, but the ''Head'' node will need to access node ''A'''s next pointer to know what the next node in the list is.  An illustration is shown below.  The ''1'' and the ''2'' represent the messages being sent from the respective node to node ''A'' that have not yet arrived.&lt;br /&gt;
[[Image:PurgeDelete.png|center]]&lt;br /&gt;
What will happen is that one of the messages will reach node ''A'' first.  While ''A'' is responding to this message, it will tell other nodes that it is busy, in a similar manner to the notion of the atomic transactions.  If node ''B'''s message arrives first, causing the message from the ''Head'' node to be rejected.  Node ''A'' will have its forward pointer changed at this point, so when the ''Head'' node resends its request, all will work as expected.&lt;br /&gt;
The second option is more difficult.  If the ''Head'' node's message arrives first, node ''A'' will be invalidated, so that when the message from node ''B'' is sent again, node ''A'' will simply inform node ''B'' that it is no longer part of the list.  As well, the ''Head'' node will now have its forward pointer pointing at node ''B''.  Node ''A'' has thus been successfully purged, but we arrive at an impasse, as now the ''Head'' node will try to invalidate the locked node ''B'', while node ''B'' will try to tell the ''Head'' node to change its forward pointer, with both nodes being inside a transaction.  This situation is illustrated by the following figure.&lt;br /&gt;
[[Image:PurgeDelete2.png|center]]&lt;br /&gt;
The protocol does not specify how to handle this situation, but it would make sense for the protocol to allow one of the messages through, presumably the ''Head'' node's message.  Node ''B'' could simply respond in the affirmative, telling the ''Head'' node what the following node is, but this would only work if node ''B'' notifies the next node of the deletion after it notifies node ''A''.  Otherwise, the node following ''B'' would have its back pointer pointing to the wrong node.  The protocol standard seems to suggest that this is the case (IEEE, pg162)&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;1body&amp;quot;&amp;gt;[[#1foot|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''PENDING state'' - The intermediate state for a node while it is attempting to become the ''Head'' node in the sharing list.  This includes the transaction involved in querying the ''Home'' node and the transaction involved in demoting the current ''Head'' node.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45230</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45230"/>
		<updated>2011-04-19T03:50:53Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Simultaneous Deletion and Invalidation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(Unless otherwise noted, the contents of this article is derived from the IEEE standardization document titled &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI)&amp;quot;&amp;lt;sup&amp;gt;&amp;lt;span class = &amp;quot;plainlinks&amp;quot;&amp;gt;[[#References|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; .)&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
These states are used by the coherency model to determine the state of the cache line when memory transactions are performed by individual processors.  Likewise, these memory states are impacted when these memory transactions occur.&lt;br /&gt;
&lt;br /&gt;
Below is a state diagram that depicts the transition between these memory states:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:memory_state.png|center]]&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL, and the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
====States of the Typical Set====&lt;br /&gt;
&lt;br /&gt;
Following are the states defined for the Typical set.  (Note that other states may be supported to provide certain interoperability with nodes implementing the Full set, but are not used when all nodes support the Typical set.)&lt;br /&gt;
&lt;br /&gt;
* '''ONLY_DIRTY''' - only one processor has the memory block in its cache.  This block is writable, and the processor has written (or intends) to write to it.  This state is set when the processor requests the block with read/write privileges, and no other processor currently caches the block.&lt;br /&gt;
* '''ONLY_FRESH''' - only one processor had the memory block in its cache.  This block is writeable, but processor has not written to it.  This state is set when the processor requests the block with read privileges, and no other processor currently caches the block.&lt;br /&gt;
* '''HEAD_DIRTY''' - more than one processor has the memory block in its cache.  This block is writable, and the processor has written (or intends) to write to it.  This state is set when the processor requests the block with read/write privileges, and another processors already caches the block.&lt;br /&gt;
* '''HEAD_FRESH''' - more than one processor had the memory block in its cache.  This block is writeable, but processor has not written to it.  This state is set when the processor requests the block with read privileges, and another processors already caches the block.&lt;br /&gt;
* '''MID_VALID''' - more than two processors have the memory in its cache, and it is readable.  The processor cache with this state is neither the Head or the Tail of the of the sharing list.&lt;br /&gt;
* '''TAIL_VALID''' - more than two processors have the memory in its cache, and it is readable.  The processor cache with this state is the Tail of the of the sharing list.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Below is a state diagram that depicts these states:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
The request sub-actions of memory transactions that expect a response from the directory include 17 variations of reads, writes, and locks based on the number of bytes requested and the coherency requirements.  For convenience, the notation on the edges of the above graph is derived from the terms used in the SCI specification to describe the memory transactions. &lt;br /&gt;
&lt;br /&gt;
The first value indicates the request to the directory by a node for memory access:&lt;br /&gt;
* '''Fetch R''' - indicates a request for a memory block with read privileges.&lt;br /&gt;
* '''Fetch RW''' - indicates a request for a memory block with read/write privileges.&lt;br /&gt;
* '''Data Modify''' - indicates that a processor (the HEAD or the ONLY processor caching the block) writes to the cache line.&lt;br /&gt;
&lt;br /&gt;
The value in the parenthesis indicates the memory state at the time of the request.&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as querying memory for a data or invalidating a node's cache.  This usually takes the form a a request-response pair, where the initiating node sends a request to another node and waits for the response.  The transaction is not complete until the response returns.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, having requested a block of data from memory and not having received a response, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' will be in the ''PENDING''&amp;lt;sup&amp;gt;&amp;lt;span class = &amp;quot;plainlinks&amp;quot;&amp;gt;[[#Definitions_and_Terms|[def]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; state, so any requests to demote it from the ''Head'' position will be delayed..  This could lead to a chaining of nodes in the ''PENDING'' state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
The design of the SCI protocol prevents many race conditions from occurring, as has already been shown.  Here are two other conditions that may arise, with a discussion of how the protocol resolves the issue.&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
Even though the ''Head'' node performs most of the coherence actions for a shard list, the individual nodes are able to invalidate themselves, such as when they evict the block from their cache.  This is referred to in the SCI standard as a &amp;quot;deletion&amp;quot; from the sharing list.  Deletion is accomplished by having the invalidating node &amp;quot;lock&amp;quot; itself and then inform its forward and back nodes that they should now point to each other.  This &amp;quot;locking&amp;quot; is essentially another ''PENDING'' state.  A problem could arise, then, when two neighboring nodes try to invalidate themselves at the same time, as they would both be locked and not respond to each other's message.  In this case, though, the protocol specifies that the node that is closest to the tail takes priority.  So, the deadlock and/or race condition is averted by ordering the deletion from the tail towards the head.&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
Another potential race condition occurs when the ''Head'' node tries to purge the list of sharers at the same time as a node in the list tries to remove itself from the list.  Suppose that the ''Head'' node is trying to purge node ''A'', which has node ''B'' as its next node in the list, while at the same time, node ''B'' is trying to remove itself from the list.  Node ''B'' needs to tell node ''A'' to update its next pointer, but the ''Head'' node will need to access node ''A'''s next pointer to know what the next node in the list is.  An illustration is shown below.  The ''1'' and the ''2'' represent the messages being sent from the respective node to node ''A'' that have not yet arrived.&lt;br /&gt;
[[Image:PurgeDelete.png|center]]&lt;br /&gt;
What will happen is that one of the messages will reach node ''A'' first.  While ''A'' is responding to this message, it will tell other nodes that it is busy, in a similar manner to the notion of the atomic transactions.  If node ''B'''s message arrives first, causing the message from the ''Head'' node to be rejected.  Node ''A'' will have its forward pointer changed at this point, so when the ''Head'' node resends its request, all will work as expected.&lt;br /&gt;
The second option is more difficult.  If the ''Head'' node's message arrives first, node ''A'' will be invalidated, so that when the message from node ''B'' is sent again, node ''A'' will simply inform node ''B'' that it is no longer part of the list.  As well, the ''Head'' node will now have its forward pointer pointing at node ''B''.  Node ''A'' has thus been successfully purged, but we arrive at an impasse, as now the ''Head'' node will try to invalidate the locked node ''B'', while node ''B'' will try to tell the ''Head'' node to change its forward pointer, with both nodes being inside a transaction.  This situation is illustrated by the following figure.&lt;br /&gt;
[[Image:PurgeDelete2.png|center]]&lt;br /&gt;
The protocol does not specify how to handle this situation, but it would make sense for the protocol to allow one of the messages through, presumably the ''Head'' node's message.  Node ''B'' could simply respond in the affirmative, telling the ''Head'' node what the following node is, but this would only work if node ''B'' notifies the next node of the deletion after it notifies node ''A''.  Otherwise, the node following ''B'' would have its back pointer pointing to the wrong node.  The protocol standard seems to suggest that this is the case (IEEE, pg162)&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;1body&amp;quot;&amp;gt;[[#1foot|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''PENDING state'' - The intermediate state for a node while it is attempting to become the ''Head'' node in the sharing list.  This includes the transaction involved in querying the ''Home'' node and the transaction involved in demoting the current ''Head'' node.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45229</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45229"/>
		<updated>2011-04-19T03:49:30Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Simultaneous Deletion and Invalidation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(Unless otherwise noted, the contents of this article is derived from the IEEE standardization document titled &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI)&amp;quot;&amp;lt;sup&amp;gt;&amp;lt;span class = &amp;quot;plainlinks&amp;quot;&amp;gt;[[#References|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; .)&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
These states are used by the coherency model to determine the state of the cache line when memory transactions are performed by individual processors.  Likewise, these memory states are impacted when these memory transactions occur.&lt;br /&gt;
&lt;br /&gt;
Below is a state diagram that depicts the transition between these memory states:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:memory_state.png|center]]&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL, and the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
====States of the Typical Set====&lt;br /&gt;
&lt;br /&gt;
Following are the states defined for the Typical set.  (Note that other states may be supported to provide certain interoperability with nodes implementing the Full set, but are not used when all nodes support the Typical set.)&lt;br /&gt;
&lt;br /&gt;
* '''ONLY_DIRTY''' - only one processor has the memory block in its cache.  This block is writable, and the processor has written (or intends) to write to it.  This state is set when the processor requests the block with read/write privileges, and no other processor currently caches the block.&lt;br /&gt;
* '''ONLY_FRESH''' - only one processor had the memory block in its cache.  This block is writeable, but processor has not written to it.  This state is set when the processor requests the block with read privileges, and no other processor currently caches the block.&lt;br /&gt;
* '''HEAD_DIRTY''' - more than one processor has the memory block in its cache.  This block is writable, and the processor has written (or intends) to write to it.  This state is set when the processor requests the block with read/write privileges, and another processors already caches the block.&lt;br /&gt;
* '''HEAD_FRESH''' - more than one processor had the memory block in its cache.  This block is writeable, but processor has not written to it.  This state is set when the processor requests the block with read privileges, and another processors already caches the block.&lt;br /&gt;
* '''MID_VALID''' - more than two processors have the memory in its cache, and it is readable.  The processor cache with this state is neither the Head or the Tail of the of the sharing list.&lt;br /&gt;
* '''TAIL_VALID''' - more than two processors have the memory in its cache, and it is readable.  The processor cache with this state is the Tail of the of the sharing list.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Below is a state diagram that depicts these states:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
The request sub-actions of memory transactions that expect a response from the directory include 17 variations of reads, writes, and locks based on the number of bytes requested and the coherency requirements.  For convenience, the notation on the edges of the above graph is derived from the terms used in the SCI specification to describe the memory transactions. &lt;br /&gt;
&lt;br /&gt;
The first value indicates the request to the directory by a node for memory access:&lt;br /&gt;
* '''Fetch R''' - indicates a request for a memory block with read privileges.&lt;br /&gt;
* '''Fetch RW''' - indicates a request for a memory block with read/write privileges.&lt;br /&gt;
* '''Data Modify''' - indicates that a processor (the HEAD or the ONLY processor caching the block) writes to the cache line.&lt;br /&gt;
&lt;br /&gt;
The value in the parenthesis indicates the memory state at the time of the request.&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as querying memory for a data or invalidating a node's cache.  This usually takes the form a a request-response pair, where the initiating node sends a request to another node and waits for the response.  The transaction is not complete until the response returns.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, having requested a block of data from memory and not having received a response, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' will be in the ''PENDING''&amp;lt;sup&amp;gt;&amp;lt;span class = &amp;quot;plainlinks&amp;quot;&amp;gt;[[#Definitions_and_Terms|[def]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; state, so any requests to demote it from the ''Head'' position will be delayed..  This could lead to a chaining of nodes in the ''PENDING'' state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
The design of the SCI protocol prevents many race conditions from occurring, as has already been shown.  Here are two other conditions that may arise, with a discussion of how the protocol resolves the issue.&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
Even though the ''Head'' node performs most of the coherence actions for a shard list, the individual nodes are able to invalidate themselves, such as when they evict the block from their cache.  This is referred to in the SCI standard as a &amp;quot;deletion&amp;quot; from the sharing list.  Deletion is accomplished by having the invalidating node &amp;quot;lock&amp;quot; itself and then inform its forward and back nodes that they should now point to each other.  This &amp;quot;locking&amp;quot; is essentially another ''PENDING'' state.  A problem could arise, then, when two neighboring nodes try to invalidate themselves at the same time, as they would both be locked and not respond to each other's message.  In this case, though, the protocol specifies that the node that is closest to the tail takes priority.  So, the deadlock and/or race condition is averted by ordering the deletion from the tail towards the head.&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
Another potential race condition occurs when the ''Head'' node tries to purge the list of sharers at the same time as a node in the list tries to remove itself from the list.  Suppose that the ''Head'' node is trying to purge node ''A'', which has node ''B'' as its next node in the list, while at the same time, node ''B'' is trying to remove itself from the list.  Node ''B'' needs to tell node ''A'' to update its next pointer, but the ''Head'' node will need to access node ''A'''s next pointer to know what the next node in the list is.  An illustration is shown below.  The ''1'' and the ''2'' represent the messages being sent from the respective node to node ''A'' that have not yet arrived.&lt;br /&gt;
[[Image:PurgeDelete.png|center]]&lt;br /&gt;
What will happen is that one of the messages will reach node ''A'' first.  While ''A'' is responding to this message, it will tell other nodes that it is busy, in a similar manner to the notion of the atomic transactions.  If node ''B'''s message arrives first, causing the message from the ''Head'' node to be rejected.  Node ''A'' will have its forward pointer changed at this point, so when the ''Head'' node resends its request, all will work as expected.&lt;br /&gt;
The second option is more difficult.  If the ''Head'' node's message arrives first, node ''A'' will be invalidated, so that when the message from node ''B'' is sent again, node ''A'' will simply inform node ''B'' that it is no longer part of the list.  As well, the ''Head'' node will now have its forward pointer pointing at node ''B''.  Node ''A'' has thus been successfully purged, but we arrive at an impasse, as now the ''Head'' node will try to invalidate the locked node ''B'', while node ''B'' will try to tell the ''Head'' node to change its forward pointer, with both nodes being inside a transaction.  This situation is illustrated by the following figure.&lt;br /&gt;
[[Image:PurgeDelete2.png|center]]&lt;br /&gt;
The protocol does not specify how to handle this situation, but it would make sense for the protocol to allow one of the messages through, presumably the ''Head'' node's message.  Node ''B'' could simply respond in the affirmative, telling the ''Head'' node what the following node is, but this would only work if node ''B'' notifies the next node of the deletion after it notifies node ''A''.  Otherwise, the node following ''B'' would have its back pointer pointing to the wrong node.  The protocol standard seems to suggest that this is the case (IEEE, pg162).&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''PENDING state'' - The intermediate state for a node while it is attempting to become the ''Head'' node in the sharing list.  This includes the transaction involved in querying the ''Home'' node and the transaction involved in demoting the current ''Head'' node.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:PurgeDelete2.png&amp;diff=45225</id>
		<title>File:PurgeDelete2.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:PurgeDelete2.png&amp;diff=45225"/>
		<updated>2011-04-19T03:30:10Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:PurgeDelete.png&amp;diff=45212</id>
		<title>File:PurgeDelete.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:PurgeDelete.png&amp;diff=45212"/>
		<updated>2011-04-19T03:17:22Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45191</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45191"/>
		<updated>2011-04-19T02:06:03Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Concurrent List Deletions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(Unless otherwise noted, the contents of this article is derived from the IEEE standardization document titled &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI)&amp;quot;&amp;lt;sup&amp;gt;&amp;lt;span class = &amp;quot;plainlinks&amp;quot;&amp;gt;[[#References|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; .)&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
These states are used by the coherency model to determine the state of the cache line when memory transactions are performed by individual processors.  Likewise, these memory states are impacted when these memory transactions occur.&lt;br /&gt;
&lt;br /&gt;
Below is a state diagram that depicts the transition between these memory states:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:memory_state.png|center]]&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL, and the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
====States of the Typical Set====&lt;br /&gt;
&lt;br /&gt;
Following are the states defined for the Typical set.  (Note that other states may be supported to provide certain interoperability with nodes implementing the Full set, but are not used when all nodes support the Typical set.)&lt;br /&gt;
&lt;br /&gt;
* '''ONLY_DIRTY''' - only one processor has the memory block in its cache.  This block is writable, and the processor has written (or intends) to write to it.  This state is set when the processor requests the block with read/write privileges, and no other processor currently caches the block.&lt;br /&gt;
* '''ONLY_FRESH''' - only one processor had the memory block in its cache.  This block is writeable, but processor has not written to it.  This state is set when the processor requests the block with read privileges, and no other processor currently caches the block.&lt;br /&gt;
* '''HEAD_DIRTY''' - more than one processor has the memory block in its cache.  This block is writable, and the processor has written (or intends) to write to it.  This state is set when the processor requests the block with read/write privileges, and another processors already caches the block.&lt;br /&gt;
* '''HEAD_FRESH''' - more than one processor had the memory block in its cache.  This block is writeable, but processor has not written to it.  This state is set when the processor requests the block with read privileges, and another processors already caches the block.&lt;br /&gt;
* '''MID_VALID''' - more than two processors have the memory in its cache, and it is readable.  The processor cache with this state is neither the Head or the Tail of the of the sharing list.&lt;br /&gt;
* '''TAIL_VALID''' - more than two processors have the memory in its cache, and it is readable.  The processor cache with this state is the Tail of the of the sharing list.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Below is a state diagram that depicts these states:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
The request sub-actions of memory transactions that expect a response from the directory include 17 variations of reads, writes, and locks based on the number of bytes requested and the coherency requirements.  For convenience, the notation on the edges of the above graph is derived from the terms used in the SCI specification to describe the memory transactions. &lt;br /&gt;
&lt;br /&gt;
The first value indicates the request to the directory by a node for memory access:&lt;br /&gt;
* '''Fetch R''' - indicates a request for a memory block with read privileges.&lt;br /&gt;
* '''Fetch RW''' - indicates a request for a memory block with read/write privileges.&lt;br /&gt;
* '''Data Modify''' - indicates that a processor (the HEAD or the ONLY processor caching the block) writes to the cache line.&lt;br /&gt;
&lt;br /&gt;
The value in the parenthesis indicates the memory state at the time of the request.&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as querying memory for a data or invalidating a node's cache.  This usually takes the form a a request-response pair, where the initiating node sends a request to another node and waits for the response.  The transaction is not complete until the response returns.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, having requested a block of data from memory and not having received a response, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' will be in the ''PENDING''&amp;lt;sup&amp;gt;&amp;lt;span class = &amp;quot;plainlinks&amp;quot;&amp;gt;[[#Definitions_and_Terms|[def]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; state, so any requests to demote it from the ''Head'' position will be delayed..  This could lead to a chaining of nodes in the ''PENDING'' state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
The design of the SCI protocol prevents many race conditions from occurring, as has already been shown.  Here are two other conditions that may arise, with a discussion of how the protocol resolves the issue.&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
Even though the ''Head'' node performs most of the coherence actions for a shard list, the individual nodes are able to invalidate themselves, such as when they evict the block from their cache.  This is referred to in the SCI standard as a &amp;quot;deletion&amp;quot; from the sharing list.  Deletion is accomplished by having the invalidating node &amp;quot;lock&amp;quot; itself and then inform its forward and back nodes that they should now point to each other.  This &amp;quot;locking&amp;quot; is essentially another ''PENDING'' state.  A problem could arise, then, when two neighboring nodes try to invalidate themselves at the same time, as they would both be locked and not respond to each other's message.  In this case, though, the protocol specifies that the node that is closest to the tail takes priority.  So, the deadlock and/or race condition is averted by ordering the deletion from the tail towards the head.&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''PENDING state'' - The intermediate state for a node while it is attempting to become the ''Head'' node in the sharing list.  This includes the transaction involved in querying the ''Home'' node and the transaction involved in demoting the current ''Head'' node.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45190</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45190"/>
		<updated>2011-04-19T02:05:55Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Simultaneous Deletion and Invalidation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(Unless otherwise noted, the contents of this article is derived from the IEEE standardization document titled &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI)&amp;quot;&amp;lt;sup&amp;gt;&amp;lt;span class = &amp;quot;plainlinks&amp;quot;&amp;gt;[[#References|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; .)&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
These states are used by the coherency model to determine the state of the cache line when memory transactions are performed by individual processors.  Likewise, these memory states are impacted when these memory transactions occur.&lt;br /&gt;
&lt;br /&gt;
Below is a state diagram that depicts the transition between these memory states:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:memory_state.png|center]]&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL, and the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
====States of the Typical Set====&lt;br /&gt;
&lt;br /&gt;
Following are the states defined for the Typical set.  (Note that other states may be supported to provide certain interoperability with nodes implementing the Full set, but are not used when all nodes support the Typical set.)&lt;br /&gt;
&lt;br /&gt;
* '''ONLY_DIRTY''' - only one processor has the memory block in its cache.  This block is writable, and the processor has written (or intends) to write to it.  This state is set when the processor requests the block with read/write privileges, and no other processor currently caches the block.&lt;br /&gt;
* '''ONLY_FRESH''' - only one processor had the memory block in its cache.  This block is writeable, but processor has not written to it.  This state is set when the processor requests the block with read privileges, and no other processor currently caches the block.&lt;br /&gt;
* '''HEAD_DIRTY''' - more than one processor has the memory block in its cache.  This block is writable, and the processor has written (or intends) to write to it.  This state is set when the processor requests the block with read/write privileges, and another processors already caches the block.&lt;br /&gt;
* '''HEAD_FRESH''' - more than one processor had the memory block in its cache.  This block is writeable, but processor has not written to it.  This state is set when the processor requests the block with read privileges, and another processors already caches the block.&lt;br /&gt;
* '''MID_VALID''' - more than two processors have the memory in its cache, and it is readable.  The processor cache with this state is neither the Head or the Tail of the of the sharing list.&lt;br /&gt;
* '''TAIL_VALID''' - more than two processors have the memory in its cache, and it is readable.  The processor cache with this state is the Tail of the of the sharing list.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Below is a state diagram that depicts these states:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
The request sub-actions of memory transactions that expect a response from the directory include 17 variations of reads, writes, and locks based on the number of bytes requested and the coherency requirements.  For convenience, the notation on the edges of the above graph is derived from the terms used in the SCI specification to describe the memory transactions. &lt;br /&gt;
&lt;br /&gt;
The first value indicates the request to the directory by a node for memory access:&lt;br /&gt;
* '''Fetch R''' - indicates a request for a memory block with read privileges.&lt;br /&gt;
* '''Fetch RW''' - indicates a request for a memory block with read/write privileges.&lt;br /&gt;
* '''Data Modify''' - indicates that a processor (the HEAD or the ONLY processor caching the block) writes to the cache line.&lt;br /&gt;
&lt;br /&gt;
The value in the parenthesis indicates the memory state at the time of the request.&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as querying memory for a data or invalidating a node's cache.  This usually takes the form a a request-response pair, where the initiating node sends a request to another node and waits for the response.  The transaction is not complete until the response returns.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, having requested a block of data from memory and not having received a response, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' will be in the ''PENDING''&amp;lt;sup&amp;gt;&amp;lt;span class = &amp;quot;plainlinks&amp;quot;&amp;gt;[[#Definitions_and_Terms|[def]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; state, so any requests to demote it from the ''Head'' position will be delayed..  This could lead to a chaining of nodes in the ''PENDING'' state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
The design of the SCI protocol prevents many race conditions from occurring, as has already been shown.  Here are two other conditions that may arise, with a discussion of how the protocol resolves the issue.&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''PENDING state'' - The intermediate state for a node while it is attempting to become the ''Head'' node in the sharing list.  This includes the transaction involved in querying the ''Home'' node and the transaction involved in demoting the current ''Head'' node.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45125</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45125"/>
		<updated>2011-04-18T23:07:23Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Simultaneous Deletion and Invalidation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL, and the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as querying memory for a data or invalidating a node's cache.  This usually takes the form a a request-response pair, where the initiating node sends a request to another node and waits for the response.  The transaction is not complete until the response returns.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, having requested a block of data from memory and not having received a response, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' will be in the ''PENDING''&amp;lt;sup&amp;gt;&amp;lt;span class = &amp;quot;plainlinks&amp;quot;&amp;gt;[[#Definitions_and_Terms|[def]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; state, so any requests to demote it from the ''Head'' position will be delayed..  This could lead to a chaining of nodes in the ''PENDING'' state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
The design of the SCI protocol prevents many race conditions from occurring, as has already been shown.  Here are two other conditions that may arise, with a discussion of how the protocol resolves the issue.&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
Even though the ''Head'' node performs most of the coherence actions for a shard list, the individual nodes are able to invalidate themselves, such as when they evict the block from their cache.  This is referred to in the SCI standard as a &amp;quot;deletion&amp;quot; from the sharing list.  Deletion is accomplished by having the invalidating node &amp;quot;lock&amp;quot; itself and then inform its forward and back nodes that they should now point to each other.  This &amp;quot;locking&amp;quot; is essentially another ''PENDING'' state.  A problem could arise, then, when two neighboring nodes try to invalidate themselves at the same time, as they would both be locked and not respond to each other's message.  In this case, though, the protocol specifies that the node that is closest to the tail takes priority.  So, the deadlock and/or race condition is averted by ordering the deletion from the tail towards the head.&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''PENDING state'' - The intermediate state for a node while it is attempting to become the ''Head'' node in the sharing list.  This includes the transaction involved in querying the ''Home'' node and the transaction involved in demoting the current ''Head'' node.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45124</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45124"/>
		<updated>2011-04-18T23:06:18Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Simultaneous Deletion and Invalidation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL, and the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as querying memory for a data or invalidating a node's cache.  This usually takes the form a a request-response pair, where the initiating node sends a request to another node and waits for the response.  The transaction is not complete until the response returns.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, having requested a block of data from memory and not having received a response, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' will be in the ''PENDING''&amp;lt;sup&amp;gt;&amp;lt;span class = &amp;quot;plainlinks&amp;quot;&amp;gt;[[#Definitions_and_Terms|[def]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; state, so any requests to demote it from the ''Head'' position will be delayed..  This could lead to a chaining of nodes in the ''PENDING'' state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
The design of the SCI protocol prevents many race conditions from occurring, as has already been shown.  Here are two other conditions that may arise, with a discussion of how the protocol resolves the issue.&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''PENDING state'' - The intermediate state for a node while it is attempting to become the ''Head'' node in the sharing list.  This includes the transaction involved in querying the ''Home'' node and the transaction involved in demoting the current ''Head'' node.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45123</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45123"/>
		<updated>2011-04-18T23:05:48Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Solihin 11.4 Resolution */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL, and the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as querying memory for a data or invalidating a node's cache.  This usually takes the form a a request-response pair, where the initiating node sends a request to another node and waits for the response.  The transaction is not complete until the response returns.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, having requested a block of data from memory and not having received a response, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' will be in the ''PENDING''&amp;lt;sup&amp;gt;&amp;lt;span class = &amp;quot;plainlinks&amp;quot;&amp;gt;[[#Definitions_and_Terms|[def]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; state, so any requests to demote it from the ''Head'' position will be delayed..  This could lead to a chaining of nodes in the ''PENDING'' state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
The design of the SCI protocol prevents many race conditions from occurring, as has already been shown.  Here are two other conditions that may arise, with a discussion of how the protocol resolves the issue.&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
Even though the ''Head'' node performs most of the coherence actions for a shard list, the individual nodes are able to invalidate themselves, such as when they evict the block from their cache.  This is referred to in the SCI standard as a &amp;quot;deletion&amp;quot; from the sharing list.  Deletion is accomplished by having the invalidating node &amp;quot;lock&amp;quot; itself and then inform its forward and back nodes that they should now point to each other.  This &amp;quot;locking&amp;quot; is essentially another busy state.  A problem could arise, then, when two neighboring nodes try to invalidate themselves at the same time, as they would both be locked and not respond to each other's message.  In this case, though, the protocol specifies that the node that is closest to the tail takes priority.  So, the deadlock and/or race condition is averted by ordering the deletion from the tail towards the head.&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''PENDING state'' - The intermediate state for a node while it is attempting to become the ''Head'' node in the sharing list.  This includes the transaction involved in querying the ''Home'' node and the transaction involved in demoting the current ''Head'' node.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45122</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45122"/>
		<updated>2011-04-18T22:59:46Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Solihin 11.4 Resolution */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL, and the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as querying memory for a data or invalidating a node's cache.  This usually takes the form a a request-response pair, where the initiating node sends a request to another node and waits for the response.  The transaction is not complete until the response returns.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, having requested a block of data from memory and not having received a response, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' will be in the ''PENDING''&amp;lt;span class = &amp;quot;plainlinks&amp;quot;&amp;gt;&amp;lt;sup&amp;gt;[http://pg-server.csc.ncsu.edu/mediawiki/index.php/CSC/ECE_506_Spring_2011/ch11_BB_EP#Definitions_and_Terms [def]]&amp;lt;/sup&amp;gt;&amp;lt;/span&amp;gt; state, so any requests to demote it from the ''Head'' position will be delayed..  This could lead to a chaining of nodes in the ''PENDING'' state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
The design of the SCI protocol prevents many race conditions from occurring, as has already been shown.  Here are two other conditions that may arise, with a discussion of how the protocol resolves the issue.&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
Even though the ''Head'' node performs most of the coherence actions for a shard list, the individual nodes are able to invalidate themselves, such as when they evict the block from their cache.  This is referred to in the SCI standard as a &amp;quot;deletion&amp;quot; from the sharing list.  Deletion is accomplished by having the invalidating node &amp;quot;lock&amp;quot; itself and then inform its forward and back nodes that they should now point to each other.  This &amp;quot;locking&amp;quot; is essentially another busy state.  A problem could arise, then, when two neighboring nodes try to invalidate themselves at the same time, as they would both be locked and not respond to each other's message.  In this case, though, the protocol specifies that the node that is closest to the tail takes priority.  So, the deadlock and/or race condition is averted by ordering the deletion from the tail towards the head.&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''PENDING state'' - The intermediate state for a node while it is attempting to become the ''Head'' node in the sharing list.  This includes the transaction involved in querying the ''Home'' node and the transaction involved in demoting the current ''Head'' node.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45121</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45121"/>
		<updated>2011-04-18T22:53:17Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Solihin 11.4 Resolution */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL, and the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as querying memory for a data or invalidating a node's cache.  This usually takes the form a a request-response pair, where the initiating node sends a request to another node and waits for the response.  The transaction is not complete until the response returns.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, having requested a block of data from memory and not having received a response, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' will be in the ''PENDING''[http://pg-server.csc.ncsu.edu/mediawiki/index.php/CSC/ECE_506_Spring_2011/ch11_BB_EP#Definitions_and_Terms &amp;lt;sup&amp;gt;[def]&amp;lt;/sup&amp;gt; ] state, so any requests to demote it from the ''Head'' position will be delayed..  This could lead to a chaining of nodes in the ''PENDING'' state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
The design of the SCI protocol prevents many race conditions from occurring, as has already been shown.  Here are two other conditions that may arise, with a discussion of how the protocol resolves the issue.&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
Even though the ''Head'' node performs most of the coherence actions for a shard list, the individual nodes are able to invalidate themselves, such as when they evict the block from their cache.  This is referred to in the SCI standard as a &amp;quot;deletion&amp;quot; from the sharing list.  Deletion is accomplished by having the invalidating node &amp;quot;lock&amp;quot; itself and then inform its forward and back nodes that they should now point to each other.  This &amp;quot;locking&amp;quot; is essentially another busy state.  A problem could arise, then, when two neighboring nodes try to invalidate themselves at the same time, as they would both be locked and not respond to each other's message.  In this case, though, the protocol specifies that the node that is closest to the tail takes priority.  So, the deadlock and/or race condition is averted by ordering the deletion from the tail towards the head.&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''PENDING state'' - The intermediate state for a node while it is attempting to become the ''Head'' node in the sharing list.  This includes the transaction involved in querying the ''Home'' node and the transaction involved in demoting the current ''Head'' node.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45120</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45120"/>
		<updated>2011-04-18T22:51:55Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Definitions and Terms */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL, and the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as querying memory for a data or invalidating a node's cache.  This usually takes the form a a request-response pair, where the initiating node sends a request to another node and waits for the response.  The transaction is not complete until the response returns.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, having requested a block of data from memory and not having received a response, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' will be in the ''PENDING'' state, so any requests to demote it from the ''Head'' position will be delayed..  This could lead to a chaining of nodes in the ''PENDING'' state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
The design of the SCI protocol prevents many race conditions from occurring, as has already been shown.  Here are two other conditions that may arise, with a discussion of how the protocol resolves the issue.&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
Even though the ''Head'' node performs most of the coherence actions for a shard list, the individual nodes are able to invalidate themselves, such as when they evict the block from their cache.  This is referred to in the SCI standard as a &amp;quot;deletion&amp;quot; from the sharing list.  Deletion is accomplished by having the invalidating node &amp;quot;lock&amp;quot; itself and then inform its forward and back nodes that they should now point to each other.  This &amp;quot;locking&amp;quot; is essentially another busy state.  A problem could arise, then, when two neighboring nodes try to invalidate themselves at the same time, as they would both be locked and not respond to each other's message.  In this case, though, the protocol specifies that the node that is closest to the tail takes priority.  So, the deadlock and/or race condition is averted by ordering the deletion from the tail towards the head.&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''PENDING state'' - The intermediate state for a node while it is attempting to become the ''Head'' node in the sharing list.  This includes the transaction involved in querying the ''Home'' node and the transaction involved in demoting the current ''Head'' node.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45118</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45118"/>
		<updated>2011-04-18T22:50:07Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Solihin 11.4 Resolution */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL, and the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as querying memory for a data or invalidating a node's cache.  This usually takes the form a a request-response pair, where the initiating node sends a request to another node and waits for the response.  The transaction is not complete until the response returns.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, having requested a block of data from memory and not having received a response, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' will be in the ''PENDING'' state, so any requests to demote it from the ''Head'' position will be delayed..  This could lead to a chaining of nodes in the ''PENDING'' state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
The design of the SCI protocol prevents many race conditions from occurring, as has already been shown.  Here are two other conditions that may arise, with a discussion of how the protocol resolves the issue.&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
Even though the ''Head'' node performs most of the coherence actions for a shard list, the individual nodes are able to invalidate themselves, such as when they evict the block from their cache.  This is referred to in the SCI standard as a &amp;quot;deletion&amp;quot; from the sharing list.  Deletion is accomplished by having the invalidating node &amp;quot;lock&amp;quot; itself and then inform its forward and back nodes that they should now point to each other.  This &amp;quot;locking&amp;quot; is essentially another busy state.  A problem could arise, then, when two neighboring nodes try to invalidate themselves at the same time, as they would both be locked and not respond to each other's message.  In this case, though, the protocol specifies that the node that is closest to the tail takes priority.  So, the deadlock and/or race condition is averted by ordering the deletion from the tail towards the head.&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45115</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45115"/>
		<updated>2011-04-18T22:49:28Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Solihin 11.4 Resolution */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL, and the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as querying memory for a data or invalidating a node's cache.  This usually takes the form a a request-response pair, where the initiating node sends a request to another node and waits for the response.  The transaction is not complete until the response returns.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, having requested a block of data from memory and not having received a response, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' will be in the ''PENDING'' state, as described above, so any requests to demote it from the ''Head'' position will be delayed..  This could lead to a chaining of nodes in the ''PENDING'' state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
The design of the SCI protocol prevents many race conditions from occurring, as has already been shown.  Here are two other conditions that may arise, with a discussion of how the protocol resolves the issue.&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
Even though the ''Head'' node performs most of the coherence actions for a shard list, the individual nodes are able to invalidate themselves, such as when they evict the block from their cache.  This is referred to in the SCI standard as a &amp;quot;deletion&amp;quot; from the sharing list.  Deletion is accomplished by having the invalidating node &amp;quot;lock&amp;quot; itself and then inform its forward and back nodes that they should now point to each other.  This &amp;quot;locking&amp;quot; is essentially another busy state.  A problem could arise, then, when two neighboring nodes try to invalidate themselves at the same time, as they would both be locked and not respond to each other's message.  In this case, though, the protocol specifies that the node that is closest to the tail takes priority.  So, the deadlock and/or race condition is averted by ordering the deletion from the tail towards the head.&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45114</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45114"/>
		<updated>2011-04-18T22:47:50Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Atomic Transactions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL, and the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as querying memory for a data or invalidating a node's cache.  This usually takes the form a a request-response pair, where the initiating node sends a request to another node and waits for the response.  The transaction is not complete until the response returns.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, having requested a block of data from memory and not having received a response, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' is also in the busy state, so any requests made of it will also be rejected.  This could lead to a chaining of nodes in the busy state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
The design of the SCI protocol prevents many race conditions from occurring, as has already been shown.  Here are two other conditions that may arise, with a discussion of how the protocol resolves the issue.&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
Even though the ''Head'' node performs most of the coherence actions for a shard list, the individual nodes are able to invalidate themselves, such as when they evict the block from their cache.  This is referred to in the SCI standard as a &amp;quot;deletion&amp;quot; from the sharing list.  Deletion is accomplished by having the invalidating node &amp;quot;lock&amp;quot; itself and then inform its forward and back nodes that they should now point to each other.  This &amp;quot;locking&amp;quot; is essentially another busy state.  A problem could arise, then, when two neighboring nodes try to invalidate themselves at the same time, as they would both be locked and not respond to each other's message.  In this case, though, the protocol specifies that the node that is closest to the tail takes priority.  So, the deadlock and/or race condition is averted by ordering the deletion from the tail towards the head.&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45108</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45108"/>
		<updated>2011-04-18T22:40:18Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Simultaneous Deletion and Invalidation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL, and the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' is also in the busy state, so any requests made of it will also be rejected.  This could lead to a chaining of nodes in the busy state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
The design of the SCI protocol prevents many race conditions from occurring, as has already been shown.  Here are two other conditions that may arise, with a discussion of how the protocol resolves the issue.&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
Even though the ''Head'' node performs most of the coherence actions for a shard list, the individual nodes are able to invalidate themselves, such as when they evict the block from their cache.  This is referred to in the SCI standard as a &amp;quot;deletion&amp;quot; from the sharing list.  Deletion is accomplished by having the invalidating node &amp;quot;lock&amp;quot; itself and then inform its forward and back nodes that they should now point to each other.  This &amp;quot;locking&amp;quot; is essentially another busy state.  A problem could arise, then, when two neighboring nodes try to invalidate themselves at the same time, as they would both be locked and not respond to each other's message.  In this case, though, the protocol specifies that the node that is closest to the tail takes priority.  So, the deadlock and/or race condition is averted by ordering the deletion from the tail towards the head.&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45106</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45106"/>
		<updated>2011-04-18T22:35:38Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Other Possible Race Conditions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL, and the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' is also in the busy state, so any requests made of it will also be rejected.  This could lead to a chaining of nodes in the busy state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
The design of the SCI protocol prevents many race conditions from occurring, as has already been shown.  Here are two other conditions that may arise, with a discussion of how the protocol resolves the issue.&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45071</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45071"/>
		<updated>2011-04-18T20:21:50Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Summary */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL&lt;br /&gt;
the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' is also in the busy state, so any requests made of it will also be rejected.  This could lead to a chaining of nodes in the busy state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45069</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45069"/>
		<updated>2011-04-18T20:07:27Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* References */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL&lt;br /&gt;
the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' is also in the busy state, so any requests made of it will also be rejected.  This could lead to a chaining of nodes in the busy state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049 &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; [http://www.scizzl.com/HowSCIcohWorks.html How SCI Coherence Works] &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45064</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45064"/>
		<updated>2011-04-18T19:26:30Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Definitions and Terms */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL&lt;br /&gt;
the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' is also in the busy state, so any requests made of it will also be rejected.  This could lead to a chaining of nodes in the busy state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
* ''Head Node'' - The node at the beginning of the sharing list&lt;br /&gt;
* ''Home Node'' - The node responsible for keeping track of the ''Head'' node for a sharing list for a memory block, usually the node at which the memory block resides.&lt;br /&gt;
* ''SCI'' - Scalable Coherent Interface&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45063</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45063"/>
		<updated>2011-04-18T19:23:45Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* References */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL&lt;br /&gt;
the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' is also in the busy state, so any requests made of it will also be rejected.  This could lead to a chaining of nodes in the busy state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45062</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45062"/>
		<updated>2011-04-18T19:20:37Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Possible Race Conditions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL&lt;br /&gt;
the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' is also in the busy state, so any requests made of it will also be rejected.  This could lead to a chaining of nodes in the busy state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Other Possible Race Conditions ===&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
[1] &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45061</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45061"/>
		<updated>2011-04-18T19:17:35Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Atomic Transactions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL&lt;br /&gt;
the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.  Note, however, that nodes will not stay in the busy state indefinitely.  Doing so would lead to potential deadlocks, so all transactions have time outs that will eventually cause the transaction to fail, thus moving the node out of the busy state, making it able to respond to requests again.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' is also in the busy state, so any requests made of it will also be rejected.  This could lead to a chaining of nodes in the busy state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Possible Race Conditions ===&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
[1] &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45060</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45060"/>
		<updated>2011-04-18T19:15:42Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Head Node */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL&lt;br /&gt;
the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the ''Head'' node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current ''Head'' node as the node that can write.  All state changes in the sharing list occur at the behest of the ''Head'' node, with the exception of nodes deleting themselves from the list.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the ''Head'' node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the ''Head'' node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the ''Head'' node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the ''Head'' node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the ''Head'' node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' is also in the busy state, so any requests made of it will also be rejected.  This could lead to a chaining of nodes in the busy state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Possible Race Conditions ===&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
[1] &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45059</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45059"/>
		<updated>2011-04-18T19:11:29Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Solihin 11.4 Resolution */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL&lt;br /&gt;
the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the Head Node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current Head Node as the node that can write.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the Head Node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the Head Node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the Head Node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the Head Node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the Head Node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
It should be noted that ''B'' is also in the busy state, so any requests made of it will also be rejected.  This could lead to a chaining of nodes in the busy state, but as soon as node ''A'' receives its response from ''Home'' or times out, the requests in the chain will be successively accepted and processed.&lt;br /&gt;
&lt;br /&gt;
=== Possible Race Conditions ===&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
[1] &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45058</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45058"/>
		<updated>2011-04-18T19:08:01Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Possible Race Conditions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Memory States &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL&lt;br /&gt;
the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the Head Node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current Head Node as the node that can write.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the Head Node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the Head Node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the Head Node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the Head Node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the Head Node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
=== Possible Race Conditions ===&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
[1] &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45033</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45033"/>
		<updated>2011-04-18T04:31:02Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Example Resolution */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;5&amp;quot;| Table 1: Recent Architectures and their Cache Characteristics &lt;br /&gt;
|----&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL&lt;br /&gt;
the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the Head Node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current Head Node as the node that can write.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the Head Node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the Head Node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the Head Node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the Head Node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the Head Node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Solihin 11.4 Resolution ====&lt;br /&gt;
The three previous sections discussed individual parts of how the SCI protocol reduces race conditions.  Putting all three of these parts together yields the following scenario which resolves the Early Invalidation race as described in the text.&lt;br /&gt;
[[Image:SolihinSCI.png|center]]&lt;br /&gt;
&lt;br /&gt;
# ''A'' sends a request to ''Home'' for access to the memory block.  It then goes into a busy state while it waits for a response.&lt;br /&gt;
# ''B'' also sends a request to ''Home'' for access to the same memory block.  ''A'''s request is received first&lt;br /&gt;
# ''Home'' responds to ''A'' with the data, but this response gets caught in network traffic and delayed.  This response is sent before ''Home'' processes the request from ''B''.&lt;br /&gt;
# ''Home'' responds to the request from ''B'', telling it that ''A'' is the current ''Head'' node.&lt;br /&gt;
# ''B'' then sends a request to ''A'' to tell it to demote itself.&lt;br /&gt;
# ''A'' still hasn't received the response from ''Home'', so it is still in a transaction, and it tells ''B'' that it is busy.  ''B'' will have to retry the request.&lt;br /&gt;
&lt;br /&gt;
=== Possible Race Conditions ===&lt;br /&gt;
==== Communication Delays ====&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
[1] &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:SolihinSCI.png&amp;diff=45031</id>
		<title>File:SolihinSCI.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:SolihinSCI.png&amp;diff=45031"/>
		<updated>2011-04-18T04:21:22Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45029</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45029"/>
		<updated>2011-04-18T04:05:55Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Background */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
* '''Minimal''' - for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
* '''Typical''' - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
* '''Full''' - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL&lt;br /&gt;
the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the Head Node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current Head Node as the node that can write.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the Head Node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the Head Node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the Head Node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the Head Node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the Head Node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Example Resolution ====&lt;br /&gt;
&lt;br /&gt;
=== Possible Race Conditions ===&lt;br /&gt;
==== Communication Delays ====&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
[1] &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45028</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45028"/>
		<updated>2011-04-18T04:03:29Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* = Example Resolution */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
minimal - is for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
typical - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
full - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL&lt;br /&gt;
the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the Head Node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current Head Node as the node that can write.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the Head Node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the Head Node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the Head Node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the Head Node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the Head Node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Example Resolution ====&lt;br /&gt;
&lt;br /&gt;
=== Possible Race Conditions ===&lt;br /&gt;
==== Communication Delays ====&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
[1] &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45027</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45027"/>
		<updated>2011-04-18T04:03:18Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Prevention in the SCI Protocol */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
minimal - is for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
typical - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
full - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL&lt;br /&gt;
the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the Head Node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current Head Node as the node that can write.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the Head Node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the Head Node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the Head Node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the Head Node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the Head Node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Example Resolution ===&lt;br /&gt;
&lt;br /&gt;
=== Possible Race Conditions ===&lt;br /&gt;
==== Communication Delays ====&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
[1] &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45025</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45025"/>
		<updated>2011-04-18T04:01:55Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Memory Access */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Scalable Coherent Interface (SCI) cache coherence protocol defines a set of states for memory, a set of states for cache lines, and a set of actions that transition between these states when processors access memory.&lt;br /&gt;
&lt;br /&gt;
Three sets of these attributes are defined for minimal, typical, and full applications:&lt;br /&gt;
&lt;br /&gt;
minimal - is for ‘trivial but correct’ applications that require the presence of the memory in only one cache line.  It does not enable read-sharing, and is appropriate for small multi-processors or applications that don’t require significant sharing.&lt;br /&gt;
&lt;br /&gt;
typical - enables read-sharing of a memory location and provisions for efficiency, such as DMA transfers, local caching of data, and error recovery.  This set adds an additional stable memory state (FRESH) and multiple cache states.  This set will be the focus of this article going forward.&lt;br /&gt;
&lt;br /&gt;
full - adds support for pair-wise sharing, QOLB lock bit synchronization, and cleansing and washing of cache lines.&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
The memory states define the state of the memory block from the perspective of the home directory.  This 2-bit field is maintained in the memory tag by the home directory along with the pointer to the head of the sharing list (forwId).  This simple state model includes three stable states and one semi-stable state.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
!State&lt;br /&gt;
!Description&lt;br /&gt;
!Minimal&lt;br /&gt;
!Typical&lt;br /&gt;
!Full&lt;br /&gt;
|----&lt;br /&gt;
|HOME&lt;br /&gt;
|no sharing list&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|FRESH&lt;br /&gt;
|sharing-list copy is the same as memory&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|GONE&lt;br /&gt;
|sharing-list copy may be different from memory&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|WASH*&lt;br /&gt;
|transitional state (GONE to FRESH)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Y&lt;br /&gt;
|----&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
The cache-line states are maintained by each processors cache-coherency controller.  This 7-bit field is stored in each cache line in the sharing list, along with the pointer to the next sharing-list node (forwId) and the previous sharing-list node (backID).  Seven bits enable up to 128 possible values, and SCI defines twenty-nine stable-states for use in the minimal, typical, and full sets.  &lt;br /&gt;
&lt;br /&gt;
Stable states are those cache states that exist when a memory transaction is not in process.  Their names are derived from a combination of&lt;br /&gt;
the position of the node in the sharing list, such as ONLY, HEAD, MID, and TAIL&lt;br /&gt;
the state of the data for that node, such as FRESH, CLEAN, DIRTY, VALID, STALE, etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the Head Node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current Head Node as the node that can write.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the Head Node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the Head Node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the Head Node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the Head Node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the Head Node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head''.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  In the event that the data is already being used, the ''Home'' node will include in its response the address of the ''Head'' node of the sharing list.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.  As well, whichever node is the ''Head'' of the sharing list will be notified by the new ''Head'' when it is demoted.  All parties involved in a potential race are thus talking to each other, preventing the race from occurring in the first place.&lt;br /&gt;
&lt;br /&gt;
Because of this requirement, the projected race condition from the previous section, where the ''Head'' node is in a ''FRESH'' state and wants to write while another node also wants to read, cannot occur.  This is because both nodes must make their request to the ''Home'' node; the ''Head'' node must request the ability to write, and the other node must request the data from the ''Home'' node.  One of these requests will make it to the ''Home'' node first, resulting in the second request being deferred to the first node to reach to ''Home'' node.  Such a scenario is pictured below.&lt;br /&gt;
[[Image:MemoryAccess.png|center]]&lt;br /&gt;
&lt;br /&gt;
=== Possible Race Conditions ===&lt;br /&gt;
==== Communication Delays ====&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
[1] &amp;quot;IEEE Standard for Scalable Coherent Interface (SCI).,&amp;quot; IEEE Std 1596-1992 , vol., no., pp.i, 1993. doi: 10.1109/IEEESTD.1993.120366&lt;br /&gt;
URL: http://ieeexplore.ieee.org.proxied.lib.ncsu.edu/stamp/stamp.jsp?tp=&amp;amp;arnumber=347683&amp;amp;isnumber=8049&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:MemoryAccess.png&amp;diff=45024</id>
		<title>File:MemoryAccess.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:MemoryAccess.png&amp;diff=45024"/>
		<updated>2011-04-18T04:00:03Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: Diagram of memory access race&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diagram of memory access race&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45017</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45017"/>
		<updated>2011-04-18T03:39:37Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Memory Access */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory States ===&lt;br /&gt;
&lt;br /&gt;
=== Cache States ===&lt;br /&gt;
[[Image:cache_states.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the Head Node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current Head Node as the node that can write.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the Head Node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the Head Node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the Head Node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the Head Node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the Head Node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
The final way that the SCI protocol minimizes race conditions is by changing the directory structure.  In Solihin 11.4, there is a ''Home'' node which keeps track of the cache state and has a certain amount of knowledge about the system as a result.  In the SCI protocol, there is still a ''Home'' node of sorts, but this node is only responsible for keeping track of who the current ''Head'' node is.  Such a ''Home'' node is usually the node where the memory block physically resides.  When a node wants to access a block of memory, it sends a request to the ''Home'' node of that memory block, assuming it isn't already in the sharing list for that block.  This requirement necessarily serializes the order of access, as one access request is not serviced at the ''Home'' node until the previous request is finished, and the requests are processed in FIFO order.&lt;br /&gt;
&lt;br /&gt;
=== Possible Race Conditions ===&lt;br /&gt;
==== Communication Delays ====&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45012</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45012"/>
		<updated>2011-04-18T03:05:25Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Head Node */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory ===&lt;br /&gt;
&lt;br /&gt;
=== Processors ===&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the Head Node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current Head Node as the node that can write.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the Head Node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the Head Node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the Head Node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the Head Node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'', the Head Node wants to write, and another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Possible Race Conditions ===&lt;br /&gt;
==== Communication Delays ====&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45011</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45011"/>
		<updated>2011-04-18T03:04:49Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Head Node */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory ===&lt;br /&gt;
&lt;br /&gt;
=== Processors ===&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the Head Node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current Head Node as the node that can write.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the Head Node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the Head Node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty, or ''GONE'', memory state, as long as the Head Node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the Head Node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'' but the Head Node wants to write, but another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Possible Race Conditions ===&lt;br /&gt;
==== Communication Delays ====&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45010</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45010"/>
		<updated>2011-04-18T03:03:58Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Head Node */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory ===&lt;br /&gt;
&lt;br /&gt;
=== Processors ===&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the Head Node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current Head Node as the node that can write.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the Head Node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the Head Node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty or ''GONE'' memory state, as long as the Head Node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the Head Node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.&lt;br /&gt;
&lt;br /&gt;
This, however, does not protect against a race condition where the memory is ''FRESH'' but the Head Node wants to write, but another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Possible Race Conditions ===&lt;br /&gt;
==== Communication Delays ====&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45009</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45009"/>
		<updated>2011-04-18T03:02:35Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Head Node */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory ===&lt;br /&gt;
&lt;br /&gt;
=== Processors ===&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the Head Node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current Head Node as the node that can write.&lt;br /&gt;
&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the Head Node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  If any node wants to write, including the Head Node, it must perform an additional action in order to do so.  Likewise, when a sharing list is sharing a line of data in the dirty or ''GONE'' memory state, as long as the Head Node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the Head Node wants to write, it can write its data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.  This, however, does not protect against a race condition where the memory is ''FRESH'' but the Head Node wants to write, but another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Possible Race Conditions ===&lt;br /&gt;
==== Communication Delays ====&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45008</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45008"/>
		<updated>2011-04-18T03:00:52Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Race Conditions */  first submisson&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory ===&lt;br /&gt;
&lt;br /&gt;
=== Processors ===&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions, as shown below.&lt;br /&gt;
&lt;br /&gt;
[[Image:EarlyInValidationRace.png|400px|center]]&lt;br /&gt;
The circled actions are as follows:&lt;br /&gt;
# ''A'' sends a read request to ''Home''.&lt;br /&gt;
# ''Home'' replies with data (but the message gets delayed).&lt;br /&gt;
# ''B'' sends a write request to ''Home''.&lt;br /&gt;
# ''Home'' sends invalidation to ''A'', and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The SCI protocol has a way to handle this race condition, as well as many others, and the following sections will discuss how the SCI protocol design can prevent this race condition.&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.  A brief discussion of how this is accomplished follows, followed by a discussion showing what happens if this condition arises in the SCI protocol.&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
SCI's primary method for preventing race conditions is having atomic transactions.  A transaction is defined as a set of sub-actions necessary to complete some requested action, such as reading from memory or writing to a variable.  Suppose, for example, that node ''A'' is in the middle of a transaction with node ''B''.  Node ''C'' then tries to make a request of node ''A''.  Node ''A'' will respond to node ''C'' that it is busy, telling node ''C'' to try again, as shown in the following diagram.&lt;br /&gt;
[[Image:AtomicBusy.png|center]]&lt;br /&gt;
Thus, in the Early Invalidation race, node ''A'' would be in the middle of a transaction, which would prevent node ''B'' from invalidating it.&lt;br /&gt;
&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
Another method for preventing race conditions is to have the Head Node of a sharing list perform many of the coherence actions.  As a result, only one node is performing actions such as writes and invalidations of other sharers.  Since only one node is performing these actions, the possibility of concurrent actions is decreased.  If another node wants to write, for instance, it must become the Head Node of the sharing list for the cache line to which it wants to write, displacing the current Head Node as the node that can write.&lt;br /&gt;
When simply sharing a read-only copy of a node, as in when the memory is a ''FRESH'' state, the Head Node is somewhat irrelevant.  All the sharing nodes have their own cached value of the cache line.  Likewise, when a sharing list is sharing a line of data in the dirty or ''GONE'' memory state, as long as the Head Node has not written to the line, then all the sharing nodes stay in the list with their cached line.  However, at the point the Head Node wants to write, it can write it's data immediately, but it then must invalidate all other shared copies, via the forward pointers in the sharing list.  This, however, does not protect against a race condition where the memory is ''FRESH'' but the Head Node wants to write, but another node also wants to join the list.  The Memory Access mechanism prevents this condition.&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Possible Race Conditions ===&lt;br /&gt;
==== Communication Delays ====&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:AtomicBusy.png&amp;diff=45007</id>
		<title>File:AtomicBusy.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:AtomicBusy.png&amp;diff=45007"/>
		<updated>2011-04-18T02:30:20Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: Diagram of how an atomic transaction blocks another node's request&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diagram of how an atomic transaction blocks another node's request&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:EarlyInValidationRace.png&amp;diff=45006</id>
		<title>File:EarlyInValidationRace.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:EarlyInValidationRace.png&amp;diff=45006"/>
		<updated>2011-04-18T01:38:04Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: Early Invalidation Race Condition example from Section 11.4 of Yan Solihin's [i]Fundamentals of Parallel Computer Architecture[/i], 2008

1.	A sends a read request to home.
2.	Home replies with data (but the message gets delayed).
3.	B sends a write reque&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Early Invalidation Race Condition example from Section 11.4 of Yan Solihin's [i]Fundamentals of Parallel Computer Architecture[/i], 2008&lt;br /&gt;
&lt;br /&gt;
1.	A sends a read request to home.&lt;br /&gt;
2.	Home replies with data (but the message gets delayed).&lt;br /&gt;
3.	B sends a write request to home.&lt;br /&gt;
4.	Home sends invalidation to A, and it arrives before the ReplyD&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45005</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45005"/>
		<updated>2011-04-18T01:35:35Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Race Conditions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory ===&lt;br /&gt;
&lt;br /&gt;
=== Processors ===&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
In a distributed shared memory system with caching, the emergence of race conditions is extremely likely.  This is mainly due to the lack of a bus for serialization of actions.  It is further compounded by the problem of network errors and congestion.&lt;br /&gt;
&lt;br /&gt;
The early invalidation case from Section 11.4 in Solihin is an excellent example of a race condition that can arise in a distributed system.  Recall the diagram from the text, and the cache coherence actions.&lt;br /&gt;
&lt;br /&gt;
1.	A sends a read request to home.&lt;br /&gt;
2.	Home replies with data (but the message gets delayed).&lt;br /&gt;
3.	B sends a write request to home.&lt;br /&gt;
4.	Home sends invalidation to A, and it arrives before the ReplyD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Prevention in the SCI Protocol ===&lt;br /&gt;
Race conditions are almost non-existent in the SCI protocol, due primarily to the protocol's design.&lt;br /&gt;
==== Head Node ====&lt;br /&gt;
&lt;br /&gt;
==== Memory Access ====&lt;br /&gt;
&lt;br /&gt;
==== Atomic Transactions ====&lt;br /&gt;
&lt;br /&gt;
=== Possible Race Conditions ===&lt;br /&gt;
==== Communication Delays ====&lt;br /&gt;
&lt;br /&gt;
==== Concurrent List Deletions ====&lt;br /&gt;
&lt;br /&gt;
==== Simultaneous Deletion and Invalidation ====&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45004</id>
		<title>CSC/ECE 506 Spring 2011/ch11 BB EP</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch11_BB_EP&amp;diff=45004"/>
		<updated>2011-04-17T23:59:20Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== State Diagrams ==&lt;br /&gt;
=== Memory ===&lt;br /&gt;
&lt;br /&gt;
=== Processors ===&lt;br /&gt;
&lt;br /&gt;
== Race Conditions ==&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
== Definitions and Terms ==&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch4a_bm&amp;diff=44103</id>
		<title>CSC/ECE 506 Spring 2011/ch4a bm</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch4a_bm&amp;diff=44103"/>
		<updated>2011-02-28T05:09:44Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Shared Memory */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
Many algorithms can be parallelized effectively.  Some of them can even be parellelized using different parallel models.  Gaussian elimination is one such algorithm.  It can be implemented in the Data Parallel, Shared Memory, and Message passing models.  This article discusses implementations of Gaussian elimination in all three models, using High Performance FORTRAN (HPF), OpenMP, MPI.&lt;br /&gt;
&lt;br /&gt;
= Gaussian Elimination =&lt;br /&gt;
Gaussian Elimination is a common method used to solve a system of linear equations.  The method was popularized by Issac Newton and is today taught in most elementary linear algebra textbooks.&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;5body&amp;quot;&amp;gt;[[#5foot|[5]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;  The method consists of two steps:  forward reduction and back substitution.  The method is not strictly matrix based, but since any system of equations can be represented in matrix form, we will only work with the matrix forms for convenience.&lt;br /&gt;
&lt;br /&gt;
'''Forward Reduction'''&lt;br /&gt;
&lt;br /&gt;
The first step is to reduce the equation matrix to [http://en.wikipedia.org/wiki/Echelon_form row-echelon form].  In this form, each row has at least one more zero in a column on the left than the previous row, and the first non-zero element is 1.  A couple of examples will help to illustrate row-echelon form:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;5&amp;quot; cellpadding=&amp;quot;8&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| 1 &lt;br /&gt;
| 2 &lt;br /&gt;
| -4 &lt;br /&gt;
|&lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
| 3 &lt;br /&gt;
| = &lt;br /&gt;
| 5 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
|&lt;br /&gt;
| 1 &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;5&amp;quot; cellpadding=&amp;quot;8&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| 1 &lt;br /&gt;
| 7 &lt;br /&gt;
| 3&lt;br /&gt;
| 0 &lt;br /&gt;
|&lt;br /&gt;
| -4 &lt;br /&gt;
|-  &lt;br /&gt;
| 0&lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
| 10&lt;br /&gt;
| = &lt;br /&gt;
| 0.5 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
| 0&lt;br /&gt;
| 1 &lt;br /&gt;
|&lt;br /&gt;
| 6 &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Back Substitution'''&lt;br /&gt;
&lt;br /&gt;
In this step, we begin with the last row of the matrix and substitute the result into the previous row.  We solve that row and substitute into the previous row, continuing like this until the system is solved.  For example, we will solve this matrix:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;5&amp;quot; cellpadding=&amp;quot;8&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| 1 &lt;br /&gt;
| 2 &lt;br /&gt;
| -4 &lt;br /&gt;
|&lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
| 3 &lt;br /&gt;
| = &lt;br /&gt;
| 5 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
|&lt;br /&gt;
| 1 &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Substitute 1 for the third element in equation 2, and subtract 3 from both sides:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;5&amp;quot; cellpadding=&amp;quot;8&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| 1 &lt;br /&gt;
| 2 &lt;br /&gt;
| -4 &lt;br /&gt;
|&lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
| 0 &lt;br /&gt;
| = &lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
|&lt;br /&gt;
| 1 &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Substitute 1 for the third element and 2 for the second element in equation 1, and solve:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;5&amp;quot; cellpadding=&amp;quot;8&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| 1 &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
|&lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
| 0 &lt;br /&gt;
| = &lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
|&lt;br /&gt;
| 1 &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= FORTRAN Background =&lt;br /&gt;
The code samples below are given in FORTRAN.  FORTRAN has some differences from C-based languages.  They are listed below.  Assume that there exists an array &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;&lt;br /&gt;
* Arrays are 1-based instead of 0-based, and array subscripts are specified using parentheses instead of brackets.&lt;br /&gt;
* All elements of an array can be set to a value by simply setting the array variable equal to a value, as in &amp;lt;code&amp;gt;A = 0&amp;lt;/code&amp;gt;&lt;br /&gt;
* A &amp;lt;code&amp;gt;DO&amp;lt;/code&amp;gt; loop is not necessary to perform the same action on a set of items in an array.  Rather, one can simply specify a subset of the array on which to perform the action, as in &amp;lt;code&amp;gt;A(a:b) = A(a:b) * 2&amp;lt;/code&amp;gt;&lt;br /&gt;
* In a multi-dimensional array, using a colon as a range of array elements in one of the dimensions will perform the operation on all elements in that dimension, as in &amp;lt;code&amp;gt;A(1, :) = 2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Parallel Implementations =&lt;br /&gt;
&lt;br /&gt;
== Data Parallel ==&lt;br /&gt;
&lt;br /&gt;
The following section of code implements Gaussian Elimination via data parallel with HPF.  It is found in the book ''Designing and Building Parallel Programs (Online)'' by Ian Foster.&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;2body&amp;quot;&amp;gt;[[#2foot|[2]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  1: subroutine gauss(n, A, X)&lt;br /&gt;
  2: 	integer n&lt;br /&gt;
  3: 	real A(n, n+1)&lt;br /&gt;
  5: 	real X(n), Fac(n), Row(n+1)&lt;br /&gt;
  6: 	integer Indx(n), Itmp(1)&lt;br /&gt;
  7: 	integer i, j, k, max_indx&lt;br /&gt;
  8: 	real maxval&lt;br /&gt;
  9: &lt;br /&gt;
  10: 	Indx = 0						! Initialize mask array&lt;br /&gt;
  11: 	do i = 1, n&lt;br /&gt;
  12: 		Itmp = MAXLOC(ABS(A(:,i)), MASK=Indx .EQ. 0)	! find pivot&lt;br /&gt;
  13: 		max_indx = Itmp(1)				! Extract pivot index&lt;br /&gt;
  14: 		Indx(max_indx) = i				! Update indirection array&lt;br /&gt;
  15: 		Fac = A(:,i)/A(max_indx,i)			! scale factors for column&lt;br /&gt;
  16: 		Row = A(max_indx,:)				! Extract pivot row&lt;br /&gt;
  17: 								&lt;br /&gt;
  18:		FORALL (j=1:n, k=i:n+1, Indx(j) .EQ. 0)		! Row Update&lt;br /&gt;
  19: 			A(j,k) = A(j,k) - Fac(j) * Row(k)&lt;br /&gt;
  20: 	end do&lt;br /&gt;
  21: &lt;br /&gt;
  22: 	FORALL (j=1:n)&lt;br /&gt;
  23: 		A(Indx(j),:) = A(j,:)				! Row exchange&lt;br /&gt;
  24: &lt;br /&gt;
  25: 	DO j = n,1,-1						! Back substitution&lt;br /&gt;
  26: 		X(j) = A(j,n+1) / A(j,j)&lt;br /&gt;
  27: 		A(1:j-1,n+1) = A(1:j-1,n+1) - A(1:j-1,j)*X(j)&lt;br /&gt;
  28: 	ENDDO&lt;br /&gt;
  29: end sub&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This data parallel code works by performing operations on entire rows of the equation matrix.  In the first loop, the forward reduction is performed.  The variable &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt; is an index which keeps track of the column (and thus row) that is currently being reduced.&lt;br /&gt;
&lt;br /&gt;
Instead of reducing the rows starting with row 1, we will instead work with the row that has the largest element in the pivot column that hasn't already been used.  We will find the row with which to work at the beginning of each iteration. (lines 12-14)&lt;br /&gt;
&lt;br /&gt;
Next, we divide every element in the current row by the value in the column we are reducing. (lines 15-16)&lt;br /&gt;
&lt;br /&gt;
To finish the forward reduction, we subtract the current row from all remaining rows the needed number of times (so that the current column becomes 0).  This part of the algorithm is extremely parallelizable.  The &amp;lt;code&amp;gt;FORALL&amp;lt;/code&amp;gt; statement tells the compiler that this statement is parallelizable, and this statement implies data parallelism. (lines 18-20)&lt;br /&gt;
&lt;br /&gt;
Lines 22-24 exchange rows to put the matrix in row-echelon form, and the &amp;lt;code&amp;gt;FORALL&amp;lt;/code&amp;gt; statement again shows that this operation is highly parallelizable.&lt;br /&gt;
&lt;br /&gt;
The last loop does the back substitution.  The loop starts on the end and works its way to the first row.&lt;br /&gt;
&lt;br /&gt;
First, the last row is solved. (line 26)&lt;br /&gt;
Then, the just found solution is immediately substituted into all remaining rows and added to the right side of the matrix (the n+1 column). (line 27)&lt;br /&gt;
&lt;br /&gt;
== Shared Memory ==&lt;br /&gt;
&lt;br /&gt;
The following section of code implements Gaussian Elimination with a shared memory scheme, using HPF.  It was taken from a paper by S.F.McGinn and R.E.Shaw from the University of New Brunswick, New Brunswick, Canada.&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;1body&amp;quot;&amp;gt;[[#1foot|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  1: do pivot = 1, (n-1)&lt;br /&gt;
  2: !$omp parallel do private(xmult) schedule(runtime)&lt;br /&gt;
  3: 	do i = (pivot+1), n&lt;br /&gt;
  4: 		xmult = a(i,pivot) / a(pivot,pivot)&lt;br /&gt;
  5: 		do j = (pivot+1), n&lt;br /&gt;
  6: 			a(i,j) = a(i,j) - (xmult * a(pivot,j))&lt;br /&gt;
  7: 		end do&lt;br /&gt;
  8: 		b(i) = b(i) - (xmult * b(pivot))&lt;br /&gt;
  9: 	end do&lt;br /&gt;
  10:   1: !$omp end parallel do&lt;br /&gt;
  11: end do&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As is readily seen, this code is short and simple, so we will analyze it line by line.  To summarize the method, each row is solved serially, with the columns each being normalized and subtracted from the remaining rows in parallel.  &lt;br /&gt;
&lt;br /&gt;
The pivot column is the column currently being reduced (and subsequently, also the row).&lt;br /&gt;
&lt;br /&gt;
  1: do pivot = 1, (n-1)&lt;br /&gt;
Loop through each row for forward reduction.&lt;br /&gt;
  2: !$omp parallel do private(xmult) schedule(runtime)&lt;br /&gt;
Spawn parallel threads here, making &amp;lt;code&amp;gt;xmult&amp;lt;/code&amp;gt; private.&lt;br /&gt;
  3: 	do i = (pivot+1), n&lt;br /&gt;
Loop through all columns in the current row starting from the pivot.&lt;br /&gt;
  4: 		xmult = a(i,pivot) / a(pivot,pivot)&lt;br /&gt;
Divide the i'th column by the pivot column.  This is the normalization step.&lt;br /&gt;
  5: 		do j = (pivot+1), n&lt;br /&gt;
  6: 			a(i,j) = a(i,j) - (xmult * a(pivot,j))&lt;br /&gt;
  7: 		end do&lt;br /&gt;
Now, we loop through all other rows and update them with the just normalized column.  This involves subtracting it the needed number of times.&lt;br /&gt;
  8: 		b(i) = b(i) - (xmult * b(pivot))&lt;br /&gt;
We also update the solution column, which is in the &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; array.&lt;br /&gt;
  9: 	end do&lt;br /&gt;
  10:   1: !$omp end parallel do&lt;br /&gt;
  11: end do&lt;br /&gt;
Back substitution would be done next, but is not shown.&lt;br /&gt;
&lt;br /&gt;
== Message Passing ==&lt;br /&gt;
The following section of code implements Gaussian Elimination via message passing, using MPI.  It was taken from a paper by S.F.McGinn and R.E.Shaw from the University of New Brunswick, New Brunswick, Canada.&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;1body&amp;quot;&amp;gt;[[#1foot|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  1: root = 0&lt;br /&gt;
  2: chunk = n**2/p&lt;br /&gt;
  3: ! main loop&lt;br /&gt;
  4: do pivot = 1, n-1&lt;br /&gt;
  5:     ! root maintains communication&lt;br /&gt;
  6:     if (my_rank.eq.0) then&lt;br /&gt;
  7:        ! adjust the chunk size&lt;br /&gt;
  8:        if (MOD(pivot, p).eq.0) then&lt;br /&gt;
  9:           chunk = chunk - n&lt;br /&gt;
 10:        endif&lt;br /&gt;
 11: &lt;br /&gt;
 12:        ! calculate chunk vectors&lt;br /&gt;
 13:        rem = MOD((n**2-(n*pivot)),chunk)&lt;br /&gt;
 14:        tmp = 0&lt;br /&gt;
 15:        do i = 1, p&lt;br /&gt;
 16:           tmp = tmp + chunk&lt;br /&gt;
 17:           if (tmp.le.(n**2-(n*pivot))) then&lt;br /&gt;
 18:              a_chnk_vec(i) = chunk&lt;br /&gt;
 19:              b_chnk_vec(i) = chunk / n&lt;br /&gt;
 20:           else&lt;br /&gt;
 21:              a_chnk_vec(i) = rem&lt;br /&gt;
 22:              b_chnk_vec(i) = rem / n&lt;br /&gt;
 23:              rem = 0&lt;br /&gt;
 24:           endif&lt;br /&gt;
 25:        continue&lt;br /&gt;
 26: &lt;br /&gt;
 27:        ! calculate displacement vectors&lt;br /&gt;
 28:        a_disp_vec(1) = (pivot*n)&lt;br /&gt;
 29:        b_disp_vec(1) = pivot&lt;br /&gt;
 30:        do i = 2, p&lt;br /&gt;
 31:           a_disp_vec(i) = a_disp_vec(i-1) + a_chnk_vec(i-1)&lt;br /&gt;
 32:           b_disp_vec(i) = b_disp_vec(i-1) + b_chnk_vec(i-1)&lt;br /&gt;
 33:        continue&lt;br /&gt;
 34:  &lt;br /&gt;
 35:        ! fetch the pivot equation&lt;br /&gt;
 36:        do i = 1, n&lt;br /&gt;
 37:           pivot_eqn(i) = a(n-(i-1),pivot)&lt;br /&gt;
 38:        continue&lt;br /&gt;
 39:  &lt;br /&gt;
 40:        pivot_b = b(pivot)&lt;br /&gt;
 41:     endif ! my_rank.eq.0&lt;br /&gt;
 42:  &lt;br /&gt;
 43:     ! distribute the pivot equation&lt;br /&gt;
 44:     call MPI_BCAST(pivot_eqn, n,&lt;br /&gt;
 45:                    MPI_DOUBLE_PRECISION,&lt;br /&gt;
 46:                    root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 47:  &lt;br /&gt;
 48:     call MPI_BCAST(pivot_b, 1,&lt;br /&gt;
 49:                    MPI_DOUBLE_PRECISION,&lt;br /&gt;
 50:                    root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 51:  &lt;br /&gt;
 52:     ! distribute the chunk vector&lt;br /&gt;
 53:     call MPI_SCATTER(a_chnk_vec, 1, MPI_INTEGER,&lt;br /&gt;
 54:                      chunk, 1, MPI_INTEGER,&lt;br /&gt;
 55:                      root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 56:  &lt;br /&gt;
 57:     ! distribute the data&lt;br /&gt;
 58:     call MPI_SCATTERV(a, a_chnk_vec, a_disp_vec,&lt;br /&gt;
 59:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 60:                       local_a, chunk,&lt;br /&gt;
 61:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 62:                       root, MPI_COMM_WORLD,ierr)&lt;br /&gt;
 63:  &lt;br /&gt;
 64:     call MPI_SCATTERV(b, b_chnk_vec, b_disp_vec,&lt;br /&gt;
 65:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 66:                       local_b, chunk/n,&lt;br /&gt;
 67:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 68:                       root, MPI_COMM_WORLD,ierr)&lt;br /&gt;
 69:  &lt;br /&gt;
 70:     ! forward elimination&lt;br /&gt;
 71:     do j = 1, (chunk/n)&lt;br /&gt;
 72:        xmult = local_a((n-(pivot-1)),j) / pivot_eqn(pivot)&lt;br /&gt;
 73:        do i = (n-pivot), 1, -1&lt;br /&gt;
 74:           local_a(i,j) = local_a(i,j) - (xmult * pivot_eqn(n-(i-1)))&lt;br /&gt;
 75:        continue&lt;br /&gt;
 76:  &lt;br /&gt;
 77:        local_b(j) = local_b(j) - (xmult * pivot_b)&lt;br /&gt;
 78:     continue&lt;br /&gt;
 79:  &lt;br /&gt;
 80:     ! restore the data to root&lt;br /&gt;
 81:     call MPI_GATHERV(local_a, chunk,&lt;br /&gt;
 82:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 83:                      a, a_chnk_vec, a_disp_vec,&lt;br /&gt;
 84:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 85:                      root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 86:  &lt;br /&gt;
 87:     call MPI_GATHERV(local_b, chunk/n,&lt;br /&gt;
 88:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 89:                      b, b_chnk_vec, b_disp_vec,&lt;br /&gt;
 90:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 91:                      root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 92:  continue ! end of main loop&lt;br /&gt;
 93: &lt;br /&gt;
 94:  ! backwards substitution done in parallel (not shown)&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
This code lacks some of the declarations for the variables, but most of the variables are self-explanatory.  The code also attempts to do some load balancing via the &amp;lt;code&amp;gt;chunk&amp;lt;/code&amp;gt; variable.  &amp;lt;code&amp;gt;chunk&amp;lt;/code&amp;gt; is also used to determine how much data to send, as the amount of data needed in each step gets progressively smaller.  Making &amp;lt;code&amp;gt;chunk&amp;lt;/code&amp;gt; smaller will therefor decrease the amount of time spent in communication, thus yielding better runtimes.  The other variable of note is &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt;, which refers to the root processor, the processor that controls the rest of the processors.&lt;br /&gt;
&lt;br /&gt;
The code effectively begins its parallel section at line 4.  Lines 5-41 have the root processor setting the chunk size and setting up the data to be passed to the other processors.  In lines 43-68, the root processor sends the necessary data to the other processors.  The functions &amp;lt;code&amp;gt;MPI_BCAST&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MPI_SCATTER&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;MPI_SCATTERV&amp;lt;/code&amp;gt; serve as either a &amp;quot;send&amp;quot; or a &amp;quot;receive&amp;quot;, depending on which processor is executing them; on the root, they act as a send, while on all other processors, they act as a receive&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;[[#3foot|[3]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;.  In lines 70-78, each processor is performing the forward elimination on its chunk of data.  Finally, the data from each processor is sent back to the root processor using the &amp;lt;code&amp;gt;MPI_GATHERV&amp;lt;/code&amp;gt; function, which also functions as either a &amp;quot;send&amp;quot; or a receive&amp;quot;, only the root processor is now the receiver and the other processors are the senders.  All of this code is executed for each pivot point in the matrix.  Backwards substitution is then done sequentially on the root processor.&lt;br /&gt;
&lt;br /&gt;
The key elements of Message Passing in this code example are the communication via the &amp;lt;code&amp;gt;MPI_&amp;lt;/code&amp;gt; functions and the root processor performing some set-up of data to be passed on its own.  This code is using the MPI library to support parallelization.&lt;br /&gt;
&lt;br /&gt;
= Definitions =&lt;br /&gt;
* ''HPF'' - High Performance FORTRAN&lt;br /&gt;
* ''MPI'' - Message Passing Interface, an API used for supporting message passing across processes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; S.F.McGinn and R.E.Shaw, University of New Brunswick, [http://hpds.ee.kuas.edu.tw/download/parallel_processing/96/96present/20071212/Gaussian.pdf Parallel Gaussian Elimination Using OpenMP and MPI] &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; Ian Foster, Argonne National Laboratory, [http://www.mcs.anl.gov/~itf/dbpp/text/node90.html Case Study: Gaussian Elimination] &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;3foot&amp;quot;&amp;gt;[[#3body|3.]]&amp;lt;/span&amp;gt; [http://www.mpi-forum.org/docs/mpi-11-html/mpi-report.html MPI: A Message-Passing Interface Standard] &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;4foot&amp;quot;&amp;gt;[[#4body|4.]]&amp;lt;/span&amp;gt; Wikipedia's [http://en.wikipedia.org/wiki/Fortran FORTRAN] page &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;5foot&amp;quot;&amp;gt;[[#5body|5.]]&amp;lt;/span&amp;gt; Wikipedia's [http://en.wikipedia.org/wiki/Gaussian_elimination Gaussian Elimination] page &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch4a_bm&amp;diff=44102</id>
		<title>CSC/ECE 506 Spring 2011/ch4a bm</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch4a_bm&amp;diff=44102"/>
		<updated>2011-02-28T05:08:02Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Data Parallel */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
Many algorithms can be parallelized effectively.  Some of them can even be parellelized using different parallel models.  Gaussian elimination is one such algorithm.  It can be implemented in the Data Parallel, Shared Memory, and Message passing models.  This article discusses implementations of Gaussian elimination in all three models, using High Performance FORTRAN (HPF), OpenMP, MPI.&lt;br /&gt;
&lt;br /&gt;
= Gaussian Elimination =&lt;br /&gt;
Gaussian Elimination is a common method used to solve a system of linear equations.  The method was popularized by Issac Newton and is today taught in most elementary linear algebra textbooks.&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;5body&amp;quot;&amp;gt;[[#5foot|[5]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;  The method consists of two steps:  forward reduction and back substitution.  The method is not strictly matrix based, but since any system of equations can be represented in matrix form, we will only work with the matrix forms for convenience.&lt;br /&gt;
&lt;br /&gt;
'''Forward Reduction'''&lt;br /&gt;
&lt;br /&gt;
The first step is to reduce the equation matrix to [http://en.wikipedia.org/wiki/Echelon_form row-echelon form].  In this form, each row has at least one more zero in a column on the left than the previous row, and the first non-zero element is 1.  A couple of examples will help to illustrate row-echelon form:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;5&amp;quot; cellpadding=&amp;quot;8&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| 1 &lt;br /&gt;
| 2 &lt;br /&gt;
| -4 &lt;br /&gt;
|&lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
| 3 &lt;br /&gt;
| = &lt;br /&gt;
| 5 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
|&lt;br /&gt;
| 1 &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;5&amp;quot; cellpadding=&amp;quot;8&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| 1 &lt;br /&gt;
| 7 &lt;br /&gt;
| 3&lt;br /&gt;
| 0 &lt;br /&gt;
|&lt;br /&gt;
| -4 &lt;br /&gt;
|-  &lt;br /&gt;
| 0&lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
| 10&lt;br /&gt;
| = &lt;br /&gt;
| 0.5 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
| 0&lt;br /&gt;
| 1 &lt;br /&gt;
|&lt;br /&gt;
| 6 &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Back Substitution'''&lt;br /&gt;
&lt;br /&gt;
In this step, we begin with the last row of the matrix and substitute the result into the previous row.  We solve that row and substitute into the previous row, continuing like this until the system is solved.  For example, we will solve this matrix:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;5&amp;quot; cellpadding=&amp;quot;8&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| 1 &lt;br /&gt;
| 2 &lt;br /&gt;
| -4 &lt;br /&gt;
|&lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
| 3 &lt;br /&gt;
| = &lt;br /&gt;
| 5 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
|&lt;br /&gt;
| 1 &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Substitute 1 for the third element in equation 2, and subtract 3 from both sides:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;5&amp;quot; cellpadding=&amp;quot;8&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| 1 &lt;br /&gt;
| 2 &lt;br /&gt;
| -4 &lt;br /&gt;
|&lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
| 0 &lt;br /&gt;
| = &lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
|&lt;br /&gt;
| 1 &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Substitute 1 for the third element and 2 for the second element in equation 1, and solve:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;5&amp;quot; cellpadding=&amp;quot;8&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| 1 &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
|&lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
| 0 &lt;br /&gt;
| = &lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
|&lt;br /&gt;
| 1 &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= FORTRAN Background =&lt;br /&gt;
The code samples below are given in FORTRAN.  FORTRAN has some differences from C-based languages.  They are listed below.  Assume that there exists an array &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;&lt;br /&gt;
* Arrays are 1-based instead of 0-based, and array subscripts are specified using parentheses instead of brackets.&lt;br /&gt;
* All elements of an array can be set to a value by simply setting the array variable equal to a value, as in &amp;lt;code&amp;gt;A = 0&amp;lt;/code&amp;gt;&lt;br /&gt;
* A &amp;lt;code&amp;gt;DO&amp;lt;/code&amp;gt; loop is not necessary to perform the same action on a set of items in an array.  Rather, one can simply specify a subset of the array on which to perform the action, as in &amp;lt;code&amp;gt;A(a:b) = A(a:b) * 2&amp;lt;/code&amp;gt;&lt;br /&gt;
* In a multi-dimensional array, using a colon as a range of array elements in one of the dimensions will perform the operation on all elements in that dimension, as in &amp;lt;code&amp;gt;A(1, :) = 2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Parallel Implementations =&lt;br /&gt;
&lt;br /&gt;
== Data Parallel ==&lt;br /&gt;
&lt;br /&gt;
The following section of code implements Gaussian Elimination via data parallel with HPF.  It is found in the book ''Designing and Building Parallel Programs (Online)'' by Ian Foster.&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;2body&amp;quot;&amp;gt;[[#2foot|[2]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  1: subroutine gauss(n, A, X)&lt;br /&gt;
  2: 	integer n&lt;br /&gt;
  3: 	real A(n, n+1)&lt;br /&gt;
  5: 	real X(n), Fac(n), Row(n+1)&lt;br /&gt;
  6: 	integer Indx(n), Itmp(1)&lt;br /&gt;
  7: 	integer i, j, k, max_indx&lt;br /&gt;
  8: 	real maxval&lt;br /&gt;
  9: &lt;br /&gt;
  10: 	Indx = 0						! Initialize mask array&lt;br /&gt;
  11: 	do i = 1, n&lt;br /&gt;
  12: 		Itmp = MAXLOC(ABS(A(:,i)), MASK=Indx .EQ. 0)	! find pivot&lt;br /&gt;
  13: 		max_indx = Itmp(1)				! Extract pivot index&lt;br /&gt;
  14: 		Indx(max_indx) = i				! Update indirection array&lt;br /&gt;
  15: 		Fac = A(:,i)/A(max_indx,i)			! scale factors for column&lt;br /&gt;
  16: 		Row = A(max_indx,:)				! Extract pivot row&lt;br /&gt;
  17: 								&lt;br /&gt;
  18:		FORALL (j=1:n, k=i:n+1, Indx(j) .EQ. 0)		! Row Update&lt;br /&gt;
  19: 			A(j,k) = A(j,k) - Fac(j) * Row(k)&lt;br /&gt;
  20: 	end do&lt;br /&gt;
  21: &lt;br /&gt;
  22: 	FORALL (j=1:n)&lt;br /&gt;
  23: 		A(Indx(j),:) = A(j,:)				! Row exchange&lt;br /&gt;
  24: &lt;br /&gt;
  25: 	DO j = n,1,-1						! Back substitution&lt;br /&gt;
  26: 		X(j) = A(j,n+1) / A(j,j)&lt;br /&gt;
  27: 		A(1:j-1,n+1) = A(1:j-1,n+1) - A(1:j-1,j)*X(j)&lt;br /&gt;
  28: 	ENDDO&lt;br /&gt;
  29: end sub&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This data parallel code works by performing operations on entire rows of the equation matrix.  In the first loop, the forward reduction is performed.  The variable &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt; is an index which keeps track of the column (and thus row) that is currently being reduced.&lt;br /&gt;
&lt;br /&gt;
Instead of reducing the rows starting with row 1, we will instead work with the row that has the largest element in the pivot column that hasn't already been used.  We will find the row with which to work at the beginning of each iteration. (lines 12-14)&lt;br /&gt;
&lt;br /&gt;
Next, we divide every element in the current row by the value in the column we are reducing. (lines 15-16)&lt;br /&gt;
&lt;br /&gt;
To finish the forward reduction, we subtract the current row from all remaining rows the needed number of times (so that the current column becomes 0).  This part of the algorithm is extremely parallelizable.  The &amp;lt;code&amp;gt;FORALL&amp;lt;/code&amp;gt; statement tells the compiler that this statement is parallelizable, and this statement implies data parallelism. (lines 18-20)&lt;br /&gt;
&lt;br /&gt;
Lines 22-24 exchange rows to put the matrix in row-echelon form, and the &amp;lt;code&amp;gt;FORALL&amp;lt;/code&amp;gt; statement again shows that this operation is highly parallelizable.&lt;br /&gt;
&lt;br /&gt;
The last loop does the back substitution.  The loop starts on the end and works its way to the first row.&lt;br /&gt;
&lt;br /&gt;
First, the last row is solved. (line 26)&lt;br /&gt;
Then, the just found solution is immediately substituted into all remaining rows and added to the right side of the matrix (the n+1 column). (line 27)&lt;br /&gt;
&lt;br /&gt;
== Shared Memory ==&lt;br /&gt;
&lt;br /&gt;
The following section of code implements Gaussian Elimination with a shared memory scheme, using HPF.  It was taken from a paper by S.F.McGinn and R.E.Shaw from the University of New Brunswick, New Brunswick, Canada.&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;1body&amp;quot;&amp;gt;[[#1foot|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  1: do pivot = 1, (n-1)&lt;br /&gt;
  2: !$omp parallel do private(xmult) schedule(runtime)&lt;br /&gt;
  3: 	do i = (pivot+1), n&lt;br /&gt;
  4: 		xmult = a(i,pivot) / a(pivot,pivot)&lt;br /&gt;
  5: 		do j = (pivot+1), n&lt;br /&gt;
  6: 			a(i,j) = a(i,j) - (xmult * a(pivot,j))&lt;br /&gt;
  7: 		end do&lt;br /&gt;
  8: 		b(i) = b(i) - (xmult * b(pivot))&lt;br /&gt;
  9: 	end do&lt;br /&gt;
  10:   1: !$omp end parallel do&lt;br /&gt;
  11: end do&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As is readily seen, this code is short and simple, so we will analyze it line by line.  To summarize the method, each row is solved serially, with the columns each being normalized and subtracted the remaining rows in parallel.  &lt;br /&gt;
&lt;br /&gt;
The pivot column is the column currently being reduced (and subsequently, also the row).&lt;br /&gt;
&lt;br /&gt;
  1: do pivot = 1, (n-1)&lt;br /&gt;
Loop through each row for forward reduction.&lt;br /&gt;
  2: !$omp parallel do private(xmult) schedule(runtime)&lt;br /&gt;
Spawn parallel threads here, making &amp;lt;code&amp;gt;xmult&amp;lt;/code&amp;gt; private.&lt;br /&gt;
  3: 	do i = (pivot+1), n&lt;br /&gt;
Loop through all columns in the current row starting from the pivot.&lt;br /&gt;
  4: 		xmult = a(i,pivot) / a(pivot,pivot)&lt;br /&gt;
Divide the i'th column by the pivot column.  This is the normalization step.&lt;br /&gt;
  5: 		do j = (pivot+1), n&lt;br /&gt;
  6: 			a(i,j) = a(i,j) - (xmult * a(pivot,j))&lt;br /&gt;
  7: 		end do&lt;br /&gt;
Now, we loop through all other rows and update them with the just normalized column.  This involves subtracting it the needed number of times.&lt;br /&gt;
  8: 		b(i) = b(i) - (xmult * b(pivot))&lt;br /&gt;
We also update the solution column, which is here &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt;&lt;br /&gt;
  9: 	end do&lt;br /&gt;
  10:   1: !$omp end parallel do&lt;br /&gt;
  11: end do&lt;br /&gt;
Back substitution is done next, but is not shown.&lt;br /&gt;
&lt;br /&gt;
== Message Passing ==&lt;br /&gt;
The following section of code implements Gaussian Elimination via message passing, using MPI.  It was taken from a paper by S.F.McGinn and R.E.Shaw from the University of New Brunswick, New Brunswick, Canada.&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;1body&amp;quot;&amp;gt;[[#1foot|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  1: root = 0&lt;br /&gt;
  2: chunk = n**2/p&lt;br /&gt;
  3: ! main loop&lt;br /&gt;
  4: do pivot = 1, n-1&lt;br /&gt;
  5:     ! root maintains communication&lt;br /&gt;
  6:     if (my_rank.eq.0) then&lt;br /&gt;
  7:        ! adjust the chunk size&lt;br /&gt;
  8:        if (MOD(pivot, p).eq.0) then&lt;br /&gt;
  9:           chunk = chunk - n&lt;br /&gt;
 10:        endif&lt;br /&gt;
 11: &lt;br /&gt;
 12:        ! calculate chunk vectors&lt;br /&gt;
 13:        rem = MOD((n**2-(n*pivot)),chunk)&lt;br /&gt;
 14:        tmp = 0&lt;br /&gt;
 15:        do i = 1, p&lt;br /&gt;
 16:           tmp = tmp + chunk&lt;br /&gt;
 17:           if (tmp.le.(n**2-(n*pivot))) then&lt;br /&gt;
 18:              a_chnk_vec(i) = chunk&lt;br /&gt;
 19:              b_chnk_vec(i) = chunk / n&lt;br /&gt;
 20:           else&lt;br /&gt;
 21:              a_chnk_vec(i) = rem&lt;br /&gt;
 22:              b_chnk_vec(i) = rem / n&lt;br /&gt;
 23:              rem = 0&lt;br /&gt;
 24:           endif&lt;br /&gt;
 25:        continue&lt;br /&gt;
 26: &lt;br /&gt;
 27:        ! calculate displacement vectors&lt;br /&gt;
 28:        a_disp_vec(1) = (pivot*n)&lt;br /&gt;
 29:        b_disp_vec(1) = pivot&lt;br /&gt;
 30:        do i = 2, p&lt;br /&gt;
 31:           a_disp_vec(i) = a_disp_vec(i-1) + a_chnk_vec(i-1)&lt;br /&gt;
 32:           b_disp_vec(i) = b_disp_vec(i-1) + b_chnk_vec(i-1)&lt;br /&gt;
 33:        continue&lt;br /&gt;
 34:  &lt;br /&gt;
 35:        ! fetch the pivot equation&lt;br /&gt;
 36:        do i = 1, n&lt;br /&gt;
 37:           pivot_eqn(i) = a(n-(i-1),pivot)&lt;br /&gt;
 38:        continue&lt;br /&gt;
 39:  &lt;br /&gt;
 40:        pivot_b = b(pivot)&lt;br /&gt;
 41:     endif ! my_rank.eq.0&lt;br /&gt;
 42:  &lt;br /&gt;
 43:     ! distribute the pivot equation&lt;br /&gt;
 44:     call MPI_BCAST(pivot_eqn, n,&lt;br /&gt;
 45:                    MPI_DOUBLE_PRECISION,&lt;br /&gt;
 46:                    root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 47:  &lt;br /&gt;
 48:     call MPI_BCAST(pivot_b, 1,&lt;br /&gt;
 49:                    MPI_DOUBLE_PRECISION,&lt;br /&gt;
 50:                    root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 51:  &lt;br /&gt;
 52:     ! distribute the chunk vector&lt;br /&gt;
 53:     call MPI_SCATTER(a_chnk_vec, 1, MPI_INTEGER,&lt;br /&gt;
 54:                      chunk, 1, MPI_INTEGER,&lt;br /&gt;
 55:                      root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 56:  &lt;br /&gt;
 57:     ! distribute the data&lt;br /&gt;
 58:     call MPI_SCATTERV(a, a_chnk_vec, a_disp_vec,&lt;br /&gt;
 59:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 60:                       local_a, chunk,&lt;br /&gt;
 61:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 62:                       root, MPI_COMM_WORLD,ierr)&lt;br /&gt;
 63:  &lt;br /&gt;
 64:     call MPI_SCATTERV(b, b_chnk_vec, b_disp_vec,&lt;br /&gt;
 65:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 66:                       local_b, chunk/n,&lt;br /&gt;
 67:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 68:                       root, MPI_COMM_WORLD,ierr)&lt;br /&gt;
 69:  &lt;br /&gt;
 70:     ! forward elimination&lt;br /&gt;
 71:     do j = 1, (chunk/n)&lt;br /&gt;
 72:        xmult = local_a((n-(pivot-1)),j) / pivot_eqn(pivot)&lt;br /&gt;
 73:        do i = (n-pivot), 1, -1&lt;br /&gt;
 74:           local_a(i,j) = local_a(i,j) - (xmult * pivot_eqn(n-(i-1)))&lt;br /&gt;
 75:        continue&lt;br /&gt;
 76:  &lt;br /&gt;
 77:        local_b(j) = local_b(j) - (xmult * pivot_b)&lt;br /&gt;
 78:     continue&lt;br /&gt;
 79:  &lt;br /&gt;
 80:     ! restore the data to root&lt;br /&gt;
 81:     call MPI_GATHERV(local_a, chunk,&lt;br /&gt;
 82:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 83:                      a, a_chnk_vec, a_disp_vec,&lt;br /&gt;
 84:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 85:                      root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 86:  &lt;br /&gt;
 87:     call MPI_GATHERV(local_b, chunk/n,&lt;br /&gt;
 88:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 89:                      b, b_chnk_vec, b_disp_vec,&lt;br /&gt;
 90:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 91:                      root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 92:  continue ! end of main loop&lt;br /&gt;
 93: &lt;br /&gt;
 94:  ! backwards substitution done in parallel (not shown)&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
This code lacks some of the declarations for the variables, but most of the variables are self-explanatory.  The code also attempts to do some load balancing via the &amp;lt;code&amp;gt;chunk&amp;lt;/code&amp;gt; variable.  &amp;lt;code&amp;gt;chunk&amp;lt;/code&amp;gt; is also used to determine how much data to send, as the amount of data needed in each step gets progressively smaller.  Making &amp;lt;code&amp;gt;chunk&amp;lt;/code&amp;gt; smaller will therefor decrease the amount of time spent in communication, thus yielding better runtimes.  The other variable of note is &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt;, which refers to the root processor, the processor that controls the rest of the processors.&lt;br /&gt;
&lt;br /&gt;
The code effectively begins its parallel section at line 4.  Lines 5-41 have the root processor setting the chunk size and setting up the data to be passed to the other processors.  In lines 43-68, the root processor sends the necessary data to the other processors.  The functions &amp;lt;code&amp;gt;MPI_BCAST&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MPI_SCATTER&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;MPI_SCATTERV&amp;lt;/code&amp;gt; serve as either a &amp;quot;send&amp;quot; or a &amp;quot;receive&amp;quot;, depending on which processor is executing them; on the root, they act as a send, while on all other processors, they act as a receive&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;[[#3foot|[3]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;.  In lines 70-78, each processor is performing the forward elimination on its chunk of data.  Finally, the data from each processor is sent back to the root processor using the &amp;lt;code&amp;gt;MPI_GATHERV&amp;lt;/code&amp;gt; function, which also functions as either a &amp;quot;send&amp;quot; or a receive&amp;quot;, only the root processor is now the receiver and the other processors are the senders.  All of this code is executed for each pivot point in the matrix.  Backwards substitution is then done sequentially on the root processor.&lt;br /&gt;
&lt;br /&gt;
The key elements of Message Passing in this code example are the communication via the &amp;lt;code&amp;gt;MPI_&amp;lt;/code&amp;gt; functions and the root processor performing some set-up of data to be passed on its own.  This code is using the MPI library to support parallelization.&lt;br /&gt;
&lt;br /&gt;
= Definitions =&lt;br /&gt;
* ''HPF'' - High Performance FORTRAN&lt;br /&gt;
* ''MPI'' - Message Passing Interface, an API used for supporting message passing across processes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; S.F.McGinn and R.E.Shaw, University of New Brunswick, [http://hpds.ee.kuas.edu.tw/download/parallel_processing/96/96present/20071212/Gaussian.pdf Parallel Gaussian Elimination Using OpenMP and MPI] &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; Ian Foster, Argonne National Laboratory, [http://www.mcs.anl.gov/~itf/dbpp/text/node90.html Case Study: Gaussian Elimination] &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;3foot&amp;quot;&amp;gt;[[#3body|3.]]&amp;lt;/span&amp;gt; [http://www.mpi-forum.org/docs/mpi-11-html/mpi-report.html MPI: A Message-Passing Interface Standard] &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;4foot&amp;quot;&amp;gt;[[#4body|4.]]&amp;lt;/span&amp;gt; Wikipedia's [http://en.wikipedia.org/wiki/Fortran FORTRAN] page &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;5foot&amp;quot;&amp;gt;[[#5body|5.]]&amp;lt;/span&amp;gt; Wikipedia's [http://en.wikipedia.org/wiki/Gaussian_elimination Gaussian Elimination] page &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch4a_bm&amp;diff=44088</id>
		<title>CSC/ECE 506 Spring 2011/ch4a bm</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch4a_bm&amp;diff=44088"/>
		<updated>2011-02-28T04:47:34Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Gaussian Elimination */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
Many algorithms can be parallelized effectively.  Some of them can even be parellelized using different parallel models.  Gaussian elimination is one such algorithm.  It can be implemented in the Data Parallel, Shared Memory, and Message passing models.  This article discusses implementations of Gaussian elimination in all three models, using High Performance FORTRAN (HPF), OpenMP, MPI.&lt;br /&gt;
&lt;br /&gt;
= Gaussian Elimination =&lt;br /&gt;
Gaussian Elimination is a common method used to solve a system of linear equations.  The method was popularized by Issac Newton and is today taught in most elementary linear algebra textbooks.&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;5body&amp;quot;&amp;gt;[[#5foot|[5]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;  The method consists of two steps:  forward reduction and back substitution.  The method is not strictly matrix based, but since any system of equations can be represented in matrix form, we will only work with the matrix forms for convenience.&lt;br /&gt;
&lt;br /&gt;
'''Forward Reduction'''&lt;br /&gt;
&lt;br /&gt;
The first step is to reduce the equation matrix to [http://en.wikipedia.org/wiki/Echelon_form row-echelon form].  In this form, each row has at least one more zero in a column on the left than the previous row, and the first non-zero element is 1.  A couple of examples will help to illustrate row-echelon form:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;5&amp;quot; cellpadding=&amp;quot;8&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| 1 &lt;br /&gt;
| 2 &lt;br /&gt;
| -4 &lt;br /&gt;
|&lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
| 3 &lt;br /&gt;
| = &lt;br /&gt;
| 5 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
|&lt;br /&gt;
| 1 &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;5&amp;quot; cellpadding=&amp;quot;8&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| 1 &lt;br /&gt;
| 7 &lt;br /&gt;
| 3&lt;br /&gt;
| 0 &lt;br /&gt;
|&lt;br /&gt;
| -4 &lt;br /&gt;
|-  &lt;br /&gt;
| 0&lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
| 10&lt;br /&gt;
| = &lt;br /&gt;
| 0.5 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
| 0&lt;br /&gt;
| 1 &lt;br /&gt;
|&lt;br /&gt;
| 6 &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Back Substitution'''&lt;br /&gt;
&lt;br /&gt;
In this step, we begin with the last row of the matrix and substitute the result into the previous row.  We solve that row and substitute into the previous row, continuing like this until the system is solved.  For example, we will solve this matrix:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;5&amp;quot; cellpadding=&amp;quot;8&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| 1 &lt;br /&gt;
| 2 &lt;br /&gt;
| -4 &lt;br /&gt;
|&lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
| 3 &lt;br /&gt;
| = &lt;br /&gt;
| 5 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
|&lt;br /&gt;
| 1 &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Substitute 1 for the third element in equation 2, and subtract 3 from both sides:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;5&amp;quot; cellpadding=&amp;quot;8&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| 1 &lt;br /&gt;
| 2 &lt;br /&gt;
| -4 &lt;br /&gt;
|&lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
| 0 &lt;br /&gt;
| = &lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
|&lt;br /&gt;
| 1 &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Substitute 1 for the third element and 2 for the second element in equation 1, and solve:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;5&amp;quot; cellpadding=&amp;quot;8&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| 1 &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
|&lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
| 0 &lt;br /&gt;
| = &lt;br /&gt;
| 2 &lt;br /&gt;
|-  &lt;br /&gt;
| 0 &lt;br /&gt;
| 0 &lt;br /&gt;
| 1 &lt;br /&gt;
|&lt;br /&gt;
| 1 &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= FORTRAN Background =&lt;br /&gt;
The code samples below are given in FORTRAN.  FORTRAN has some differences from C-based languages.  They are listed below.  Assume that there exists an array &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;&lt;br /&gt;
* Arrays are 1-based instead of 0-based, and array subscripts are specified using parentheses instead of brackets.&lt;br /&gt;
* All elements of an array can be set to a value by simply setting the array variable equal to a value, as in &amp;lt;code&amp;gt;A = 0&amp;lt;/code&amp;gt;&lt;br /&gt;
* A &amp;lt;code&amp;gt;DO&amp;lt;/code&amp;gt; loop is not necessary to perform the same action on a set of items in an array.  Rather, one can simply specify a subset of the array on which to perform the action, as in &amp;lt;code&amp;gt;A(a:b) = A(a:b) * 2&amp;lt;/code&amp;gt;&lt;br /&gt;
* In a multi-dimensional array, using a colon as a range of array elements in one of the dimensions will perform the operation on all elements in that dimension, as in &amp;lt;code&amp;gt;A(1, :) = 2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Parallel Implementations =&lt;br /&gt;
&lt;br /&gt;
== Data Parallel ==&lt;br /&gt;
&lt;br /&gt;
The following section of code implements Gaussian Elimination via data parallel with HPF.  It is found in the book ''Designing and Building Parallel Programs (Online)'' by Ian Foster.&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;2body&amp;quot;&amp;gt;[[#2foot|[2]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  1: subroutine gauss(n, A, X)&lt;br /&gt;
  2: 	integer n&lt;br /&gt;
  3: 	real A(n, n+1)&lt;br /&gt;
  5: 	real X(n), Fac(n), Row(n+1)&lt;br /&gt;
  6: 	integer Indx(n), Itmp(1)&lt;br /&gt;
  7: 	integer i, j, k, max_indx&lt;br /&gt;
  8: 	real maxval&lt;br /&gt;
  9: &lt;br /&gt;
  10: 	Indx = 0						! Initialize mask array&lt;br /&gt;
  11: 	do i = 1, n&lt;br /&gt;
  12: 		Itmp = MAXLOC(ABS(A(:,i)), MASK=Indx .EQ. 0)	! find pivot&lt;br /&gt;
  13: 		max_indx = Itmp(1)				! Extract pivot index&lt;br /&gt;
  14: 		Indx(max_indx) = i				! Update indirection array&lt;br /&gt;
  15: 		Fac = A(:,i)/A(max_indx,i)			! scale factors for column&lt;br /&gt;
  16: 		Row = A(max_indx,:)				! Extract pivot row&lt;br /&gt;
  17: 								&lt;br /&gt;
  18:		FORALL (j=1:n, k=i:n+1, Indx(j) .EQ. 0)		! Row Update&lt;br /&gt;
  19: 			A(j,k) = A(j,k) - Fac(j) * Row(k)&lt;br /&gt;
  20: 	end do&lt;br /&gt;
  21: &lt;br /&gt;
  22: 	FORALL (j=1:n)&lt;br /&gt;
  23: 		A(Indx(j),:) = A(j,:)				! Row exchange&lt;br /&gt;
  24: &lt;br /&gt;
  25: 	DO j = n,1,-1						! Back substitution&lt;br /&gt;
  26: 		X(j) = A(j,n+1) / A(j,j)&lt;br /&gt;
  27: 		A(1:j-1,n+1) = A(1:j-1,n+1) - A(1:j-1,j)*X(j)&lt;br /&gt;
  28: 	ENDDO&lt;br /&gt;
  29: end sub&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This data parallel code works by performing operations on entire rows of the equation matrix.  In the first loop, the forward reduction is performed.  The variable &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt; is an index which keeps track of the column (and thus row) that is currently being reduced.&lt;br /&gt;
&lt;br /&gt;
Instead of reducing the rows starting with row 1, we will swap row 1 with the row that has the largest element in column 1.  We will do this at the beginning of each iteration. (lines 12-14)&lt;br /&gt;
&lt;br /&gt;
Next, we divide every element in the current row by the value in the column we are reducing. (line 15-16)&lt;br /&gt;
&lt;br /&gt;
To finish the forward reduction, we subtract the current row from all remaining rows the needed number of times (so that the current column becomes 0).  This part of the algorithm is extremely parallelizable. (lines 18-20)&lt;br /&gt;
&lt;br /&gt;
The last loop does the back substitution.  The loop starts on the end and works its way to the first row.&lt;br /&gt;
&lt;br /&gt;
First, the current row is solved. (line 26)&lt;br /&gt;
Then, the just found solution is immediately substituted into all remaining rows and added to the right side of the matrix (the n+1 column). (line 27)&lt;br /&gt;
&lt;br /&gt;
== Shared Memory ==&lt;br /&gt;
&lt;br /&gt;
The following section of code implements Gaussian Elimination with a shared memory scheme, using HPF.  It was taken from a paper by S.F.McGinn and R.E.Shaw from the University of New Brunswick, New Brunswick, Canada.&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;1body&amp;quot;&amp;gt;[[#1foot|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  1: do pivot = 1, (n-1)&lt;br /&gt;
  2: !$omp parallel do private(xmult) schedule(runtime)&lt;br /&gt;
  3: 	do i = (pivot+1), n&lt;br /&gt;
  4: 		xmult = a(i,pivot) / a(pivot,pivot)&lt;br /&gt;
  5: 		do j = (pivot+1), n&lt;br /&gt;
  6: 			a(i,j) = a(i,j) - (xmult * a(pivot,j))&lt;br /&gt;
  7: 		end do&lt;br /&gt;
  8: 		b(i) = b(i) - (xmult * b(pivot))&lt;br /&gt;
  9: 	end do&lt;br /&gt;
  10:   1: !$omp end parallel do&lt;br /&gt;
  11: end do&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As is readily seen, this code is short and simple, so we will analyze it line by line.  To summarize the method, each row is solved serially, with the columns each being normalized and subtracted the remaining rows in parallel.  &lt;br /&gt;
&lt;br /&gt;
The pivot column is the column currently being reduced (and subsequently, also the row).&lt;br /&gt;
&lt;br /&gt;
  1: do pivot = 1, (n-1)&lt;br /&gt;
Loop through each row for forward reduction.&lt;br /&gt;
  2: !$omp parallel do private(xmult) schedule(runtime)&lt;br /&gt;
Spawn parallel threads here, making &amp;lt;code&amp;gt;xmult&amp;lt;/code&amp;gt; private.&lt;br /&gt;
  3: 	do i = (pivot+1), n&lt;br /&gt;
Loop through all columns in the current row starting from the pivot.&lt;br /&gt;
  4: 		xmult = a(i,pivot) / a(pivot,pivot)&lt;br /&gt;
Divide the i'th column by the pivot column.  This is the normalization step.&lt;br /&gt;
  5: 		do j = (pivot+1), n&lt;br /&gt;
  6: 			a(i,j) = a(i,j) - (xmult * a(pivot,j))&lt;br /&gt;
  7: 		end do&lt;br /&gt;
Now, we loop through all other rows and update them with the just normalized column.  This involves subtracting it the needed number of times.&lt;br /&gt;
  8: 		b(i) = b(i) - (xmult * b(pivot))&lt;br /&gt;
We also update the solution column, which is here &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt;&lt;br /&gt;
  9: 	end do&lt;br /&gt;
  10:   1: !$omp end parallel do&lt;br /&gt;
  11: end do&lt;br /&gt;
Back substitution is done next, but is not shown.&lt;br /&gt;
&lt;br /&gt;
== Message Passing ==&lt;br /&gt;
The following section of code implements Gaussian Elimination via message passing, using MPI.  It was taken from a paper by S.F.McGinn and R.E.Shaw from the University of New Brunswick, New Brunswick, Canada.&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;1body&amp;quot;&amp;gt;[[#1foot|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  1: root = 0&lt;br /&gt;
  2: chunk = n**2/p&lt;br /&gt;
  3: ! main loop&lt;br /&gt;
  4: do pivot = 1, n-1&lt;br /&gt;
  5:     ! root maintains communication&lt;br /&gt;
  6:     if (my_rank.eq.0) then&lt;br /&gt;
  7:        ! adjust the chunk size&lt;br /&gt;
  8:        if (MOD(pivot, p).eq.0) then&lt;br /&gt;
  9:           chunk = chunk - n&lt;br /&gt;
 10:        endif&lt;br /&gt;
 11: &lt;br /&gt;
 12:        ! calculate chunk vectors&lt;br /&gt;
 13:        rem = MOD((n**2-(n*pivot)),chunk)&lt;br /&gt;
 14:        tmp = 0&lt;br /&gt;
 15:        do i = 1, p&lt;br /&gt;
 16:           tmp = tmp + chunk&lt;br /&gt;
 17:           if (tmp.le.(n**2-(n*pivot))) then&lt;br /&gt;
 18:              a_chnk_vec(i) = chunk&lt;br /&gt;
 19:              b_chnk_vec(i) = chunk / n&lt;br /&gt;
 20:           else&lt;br /&gt;
 21:              a_chnk_vec(i) = rem&lt;br /&gt;
 22:              b_chnk_vec(i) = rem / n&lt;br /&gt;
 23:              rem = 0&lt;br /&gt;
 24:           endif&lt;br /&gt;
 25:        continue&lt;br /&gt;
 26: &lt;br /&gt;
 27:        ! calculate displacement vectors&lt;br /&gt;
 28:        a_disp_vec(1) = (pivot*n)&lt;br /&gt;
 29:        b_disp_vec(1) = pivot&lt;br /&gt;
 30:        do i = 2, p&lt;br /&gt;
 31:           a_disp_vec(i) = a_disp_vec(i-1) + a_chnk_vec(i-1)&lt;br /&gt;
 32:           b_disp_vec(i) = b_disp_vec(i-1) + b_chnk_vec(i-1)&lt;br /&gt;
 33:        continue&lt;br /&gt;
 34:  &lt;br /&gt;
 35:        ! fetch the pivot equation&lt;br /&gt;
 36:        do i = 1, n&lt;br /&gt;
 37:           pivot_eqn(i) = a(n-(i-1),pivot)&lt;br /&gt;
 38:        continue&lt;br /&gt;
 39:  &lt;br /&gt;
 40:        pivot_b = b(pivot)&lt;br /&gt;
 41:     endif ! my_rank.eq.0&lt;br /&gt;
 42:  &lt;br /&gt;
 43:     ! distribute the pivot equation&lt;br /&gt;
 44:     call MPI_BCAST(pivot_eqn, n,&lt;br /&gt;
 45:                    MPI_DOUBLE_PRECISION,&lt;br /&gt;
 46:                    root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 47:  &lt;br /&gt;
 48:     call MPI_BCAST(pivot_b, 1,&lt;br /&gt;
 49:                    MPI_DOUBLE_PRECISION,&lt;br /&gt;
 50:                    root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 51:  &lt;br /&gt;
 52:     ! distribute the chunk vector&lt;br /&gt;
 53:     call MPI_SCATTER(a_chnk_vec, 1, MPI_INTEGER,&lt;br /&gt;
 54:                      chunk, 1, MPI_INTEGER,&lt;br /&gt;
 55:                      root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 56:  &lt;br /&gt;
 57:     ! distribute the data&lt;br /&gt;
 58:     call MPI_SCATTERV(a, a_chnk_vec, a_disp_vec,&lt;br /&gt;
 59:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 60:                       local_a, chunk,&lt;br /&gt;
 61:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 62:                       root, MPI_COMM_WORLD,ierr)&lt;br /&gt;
 63:  &lt;br /&gt;
 64:     call MPI_SCATTERV(b, b_chnk_vec, b_disp_vec,&lt;br /&gt;
 65:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 66:                       local_b, chunk/n,&lt;br /&gt;
 67:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 68:                       root, MPI_COMM_WORLD,ierr)&lt;br /&gt;
 69:  &lt;br /&gt;
 70:     ! forward elimination&lt;br /&gt;
 71:     do j = 1, (chunk/n)&lt;br /&gt;
 72:        xmult = local_a((n-(pivot-1)),j) / pivot_eqn(pivot)&lt;br /&gt;
 73:        do i = (n-pivot), 1, -1&lt;br /&gt;
 74:           local_a(i,j) = local_a(i,j) - (xmult * pivot_eqn(n-(i-1)))&lt;br /&gt;
 75:        continue&lt;br /&gt;
 76:  &lt;br /&gt;
 77:        local_b(j) = local_b(j) - (xmult * pivot_b)&lt;br /&gt;
 78:     continue&lt;br /&gt;
 79:  &lt;br /&gt;
 80:     ! restore the data to root&lt;br /&gt;
 81:     call MPI_GATHERV(local_a, chunk,&lt;br /&gt;
 82:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 83:                      a, a_chnk_vec, a_disp_vec,&lt;br /&gt;
 84:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 85:                      root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 86:  &lt;br /&gt;
 87:     call MPI_GATHERV(local_b, chunk/n,&lt;br /&gt;
 88:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 89:                      b, b_chnk_vec, b_disp_vec,&lt;br /&gt;
 90:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 91:                      root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 92:  continue ! end of main loop&lt;br /&gt;
 93: &lt;br /&gt;
 94:  ! backwards substitution done in parallel (not shown)&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
This code lacks some of the declarations for the variables, but most of the variables are self-explanatory.  The code also attempts to do some load balancing via the &amp;lt;code&amp;gt;chunk&amp;lt;/code&amp;gt; variable.  &amp;lt;code&amp;gt;chunk&amp;lt;/code&amp;gt; is also used to determine how much data to send, as the amount of data needed in each step gets progressively smaller.  Making &amp;lt;code&amp;gt;chunk&amp;lt;/code&amp;gt; smaller will therefor decrease the amount of time spent in communication, thus yielding better runtimes.  The other variable of note is &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt;, which refers to the root processor, the processor that controls the rest of the processors.&lt;br /&gt;
&lt;br /&gt;
The code effectively begins its parallel section at line 4.  Lines 5-41 have the root processor setting the chunk size and setting up the data to be passed to the other processors.  In lines 43-68, the root processor sends the necessary data to the other processors.  The functions &amp;lt;code&amp;gt;MPI_BCAST&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MPI_SCATTER&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;MPI_SCATTERV&amp;lt;/code&amp;gt; serve as either a &amp;quot;send&amp;quot; or a &amp;quot;receive&amp;quot;, depending on which processor is executing them; on the root, they act as a send, while on all other processors, they act as a receive&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;[[#3foot|[3]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;.  In lines 70-78, each processor is performing the forward elimination on its chunk of data.  Finally, the data from each processor is sent back to the root processor using the &amp;lt;code&amp;gt;MPI_GATHERV&amp;lt;/code&amp;gt; function, which also functions as either a &amp;quot;send&amp;quot; or a receive&amp;quot;, only the root processor is now the receiver and the other processors are the senders.  All of this code is executed for each pivot point in the matrix.  Backwards substitution is then done sequentially on the root processor.&lt;br /&gt;
&lt;br /&gt;
The key elements of Message Passing in this code example are the communication via the &amp;lt;code&amp;gt;MPI_&amp;lt;/code&amp;gt; functions and the root processor performing some set-up of data to be passed on its own.  This code is using the MPI library to support parallelization.&lt;br /&gt;
&lt;br /&gt;
= Definitions =&lt;br /&gt;
* ''HPF'' - High Performance FORTRAN&lt;br /&gt;
* ''MPI'' - Message Passing Interface, an API used for supporting message passing across processes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; S.F.McGinn and R.E.Shaw, University of New Brunswick, [http://hpds.ee.kuas.edu.tw/download/parallel_processing/96/96present/20071212/Gaussian.pdf Parallel Gaussian Elimination Using OpenMP and MPI] &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; Ian Foster, Argonne National Laboratory, [http://www.mcs.anl.gov/~itf/dbpp/text/node90.html Case Study: Gaussian Elimination] &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;3foot&amp;quot;&amp;gt;[[#3body|3.]]&amp;lt;/span&amp;gt; [http://www.mpi-forum.org/docs/mpi-11-html/mpi-report.html MPI: A Message-Passing Interface Standard] &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;4foot&amp;quot;&amp;gt;[[#4body|4.]]&amp;lt;/span&amp;gt; Wikipedia's [http://en.wikipedia.org/wiki/Fortran FORTRAN] page &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;5foot&amp;quot;&amp;gt;[[#5body|5.]]&amp;lt;/span&amp;gt; Wikipedia's [http://en.wikipedia.org/wiki/Gaussian_elimination Gaussian Elimination] page &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch4a_bm&amp;diff=43963</id>
		<title>CSC/ECE 506 Spring 2011/ch4a bm</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch4a_bm&amp;diff=43963"/>
		<updated>2011-02-27T21:59:53Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Definitions */   Added MPI&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
Many algorithms can be parallelized effectively.  Some of them can even be parellelized using different parallel models.  Gaussian elimination is one such algorithm.  It can be implemented in the Data Parallel, Shared Memory, and Message passing models.  This article discusses implementations of Gaussian elimination in all three models, using High Performance FORTRAN (HPF), OpenMP, MPI.&lt;br /&gt;
&lt;br /&gt;
= Gaussian Elimination =&lt;br /&gt;
&lt;br /&gt;
= FORTRAN Background =&lt;br /&gt;
FORTRAN has some differences from C-based languages.  They are listed below.  Assume that there exists an array &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;&lt;br /&gt;
* Arrays are 1-based instead of 0-based, and array subscripts are specified using parentheses instead of brackets.&lt;br /&gt;
* All elements of an array can be set to a value by simply setting the array variable equal to a value, as in &amp;lt;code&amp;gt;A = 0&amp;lt;/code&amp;gt;&lt;br /&gt;
* A &amp;lt;code&amp;gt;DO&amp;lt;/code&amp;gt; loop is not necessary to perform the same action on a set of items in an array.  Rather, one can simply specify a subset of the array on which to perform the action, as in &amp;lt;code&amp;gt;A(a:b) = A(a:b) * 2&amp;lt;/code&amp;gt;&lt;br /&gt;
* In a multi-dimensional array, using a colon as a range of array elements in one of the dimensions will perform the operation on all elements in that dimension, as in &amp;lt;code&amp;gt;A(1, :) = 2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Parallel Implementations =&lt;br /&gt;
&lt;br /&gt;
== Data Parallel ==&lt;br /&gt;
&lt;br /&gt;
== Shared Memory ==&lt;br /&gt;
&lt;br /&gt;
== Message Passing ==&lt;br /&gt;
The following section of code implements Gaussian Elimination via message passing, using MPI.  It was taken from a paper by S.F.McGinn and R.E.Shaw from the University of New Brunswick, New Brunswick, Canada.&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;1body&amp;quot;&amp;gt;[[#1foot|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  1: root = 0&lt;br /&gt;
  2: chunk = n**2/p&lt;br /&gt;
  3: ! main loop&lt;br /&gt;
  4: do pivot = 1, n-1&lt;br /&gt;
  5:     ! root maintains communication&lt;br /&gt;
  6:     if (my_rank.eq.0) then&lt;br /&gt;
  7:        ! adjust the chunk size&lt;br /&gt;
  8:        if (MOD(pivot, p).eq.0) then&lt;br /&gt;
  9:           chunk = chunk - n&lt;br /&gt;
 10:        endif&lt;br /&gt;
 11: &lt;br /&gt;
 12:        ! calculate chunk vectors&lt;br /&gt;
 13:        rem = MOD((n**2-(n*pivot)),chunk)&lt;br /&gt;
 14:        tmp = 0&lt;br /&gt;
 15:        do i = 1, p&lt;br /&gt;
 16:           tmp = tmp + chunk&lt;br /&gt;
 17:           if (tmp.le.(n**2-(n*pivot))) then&lt;br /&gt;
 18:              a_chnk_vec(i) = chunk&lt;br /&gt;
 19:              b_chnk_vec(i) = chunk / n&lt;br /&gt;
 20:           else&lt;br /&gt;
 21:              a_chnk_vec(i) = rem&lt;br /&gt;
 22:              b_chnk_vec(i) = rem / n&lt;br /&gt;
 23:              rem = 0&lt;br /&gt;
 24:           endif&lt;br /&gt;
 25:        continue&lt;br /&gt;
 26: &lt;br /&gt;
 27:        ! calculate displacement vectors&lt;br /&gt;
 28:        a_disp_vec(1) = (pivot*n)&lt;br /&gt;
 29:        b_disp_vec(1) = pivot&lt;br /&gt;
 30:        do i = 2, p&lt;br /&gt;
 31:           a_disp_vec(i) = a_disp_vec(i-1) + a_chnk_vec(i-1)&lt;br /&gt;
 32:           b_disp_vec(i) = b_disp_vec(i-1) + b_chnk_vec(i-1)&lt;br /&gt;
 33:        continue&lt;br /&gt;
 34:  &lt;br /&gt;
 35:        ! fetch the pivot equation&lt;br /&gt;
 36:        do i = 1, n&lt;br /&gt;
 37:           pivot_eqn(i) = a(n-(i-1),pivot)&lt;br /&gt;
 38:        continue&lt;br /&gt;
 39:  &lt;br /&gt;
 40:        pivot_b = b(pivot)&lt;br /&gt;
 41:     endif ! my_rank.eq.0&lt;br /&gt;
 42:  &lt;br /&gt;
 43:     ! distribute the pivot equation&lt;br /&gt;
 44:     call MPI_BCAST(pivot_eqn, n,&lt;br /&gt;
 45:                    MPI_DOUBLE_PRECISION,&lt;br /&gt;
 46:                    root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 47:  &lt;br /&gt;
 48:     call MPI_BCAST(pivot_b, 1,&lt;br /&gt;
 49:                    MPI_DOUBLE_PRECISION,&lt;br /&gt;
 50:                    root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 51:  &lt;br /&gt;
 52:     ! distribute the chunk vector&lt;br /&gt;
 53:     call MPI_SCATTER(a_chnk_vec, 1, MPI_INTEGER,&lt;br /&gt;
 54:                      chunk, 1, MPI_INTEGER,&lt;br /&gt;
 55:                      root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 56:  &lt;br /&gt;
 57:     ! distribute the data&lt;br /&gt;
 58:     call MPI_SCATTERV(a, a_chnk_vec, a_disp_vec,&lt;br /&gt;
 59:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 60:                       local_a, chunk,&lt;br /&gt;
 61:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 62:                       root, MPI_COMM_WORLD,ierr)&lt;br /&gt;
 63:  &lt;br /&gt;
 64:     call MPI_SCATTERV(b, b_chnk_vec, b_disp_vec,&lt;br /&gt;
 65:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 66:                       local_b, chunk/n,&lt;br /&gt;
 67:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 68:                       root, MPI_COMM_WORLD,ierr)&lt;br /&gt;
 69:  &lt;br /&gt;
 70:     ! forward elimination&lt;br /&gt;
 71:     do j = 1, (chunk/n)&lt;br /&gt;
 72:        xmult = local_a((n-(pivot-1)),j) / pivot_eqn(pivot)&lt;br /&gt;
 73:        do i = (n-pivot), 1, -1&lt;br /&gt;
 74:           local_a(i,j) = local_a(i,j) - (xmult * pivot_eqn(n-(i-1)))&lt;br /&gt;
 75:        continue&lt;br /&gt;
 76:  &lt;br /&gt;
 77:        local_b(j) = local_b(j) - (xmult * pivot_b)&lt;br /&gt;
 78:     continue&lt;br /&gt;
 79:  &lt;br /&gt;
 80:     ! restore the data to root&lt;br /&gt;
 81:     call MPI_GATHERV(local_a, chunk,&lt;br /&gt;
 82:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 83:                      a, a_chnk_vec, a_disp_vec,&lt;br /&gt;
 84:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 85:                      root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 86:  &lt;br /&gt;
 87:     call MPI_GATHERV(local_b, chunk/n,&lt;br /&gt;
 88:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 89:                      b, b_chnk_vec, b_disp_vec,&lt;br /&gt;
 90:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 91:                      root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 92:  continue ! end of main loop&lt;br /&gt;
 93: &lt;br /&gt;
 94:  ! backwards substitution done in parallel (not shown)&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
This code lacks some of the declarations for the variables, but most of the variables are self-explanatory.  The code also attempts to do some load balancing via the &amp;lt;code&amp;gt;chunk&amp;lt;/code&amp;gt; variable.  &amp;lt;code&amp;gt;chunk&amp;lt;/code&amp;gt; is also used to determine how much data to send, as the amount of data needed in each step gets progressively smaller.  Making &amp;lt;code&amp;gt;chunk&amp;lt;/code&amp;gt; smaller will therefor decrease the amount of time spent in communication, thus yielding better runtimes.  The other variable of note is &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt;, which refers to the root processor, the processor that controls the rest of the processors.&lt;br /&gt;
&lt;br /&gt;
The code effectively begins its parallel section at line 4.  Lines 5-41 have the root processor setting the chunk size and setting up the data to be passed to the other processors.  In lines 43-68, the root processor sends the necessary data to the other processors.  The functions &amp;lt;code&amp;gt;MPI_BCAST&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MPI_SCATTER&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;MPI_SCATTERV&amp;lt;/code&amp;gt; serve as either a &amp;quot;send&amp;quot; or a &amp;quot;receive&amp;quot;, depending on which processor is executing them; on the root, they act as a send, while on all other processors, they act as a receive&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;[[#3foot|[3]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;.  In lines 70-78, each processor is performing the forward elimination on its chunk of data.  Finally, the data from each processor is sent back to the root processor using the &amp;lt;code&amp;gt;MPI_GATHERV&amp;lt;/code&amp;gt; function, which also functions as either a &amp;quot;send&amp;quot; or a receive&amp;quot;, only the root processor is now the receiver and the other processors are the senders.  All of this code is executed for each pivot point in the matrix.  Backwards substitution is then done sequentially on the root processor.&lt;br /&gt;
&lt;br /&gt;
The key elements of Message Passing in this code example are the communication via the &amp;lt;code&amp;gt;MPI_&amp;lt;/code&amp;gt; functions and the root processor performing some set-up of data to be passed on its own.  This code is using the MPI library to support parallelization.&lt;br /&gt;
&lt;br /&gt;
= Definitions =&lt;br /&gt;
* ''HPF'' - High Performance FORTRAN&lt;br /&gt;
* ''MPI'' - Message Passing Interface, an API used for supporting message passing across processes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; S.F.McGinn and R.E.Shaw, University of New Brunswick, [http://hpds.ee.kuas.edu.tw/download/parallel_processing/96/96present/20071212/Gaussian.pdf Parallel Gaussian Elimination Using OpenMP and MPI] &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; Ian Foster, Argonne National Laboratory, [http://www.mcs.anl.gov/~itf/dbpp/text/node90.html Case Study: Gaussian Elimination] &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;3foot&amp;quot;&amp;gt;[[#3body|3.]]&amp;lt;/span&amp;gt; [http://www.mpi-forum.org/docs/mpi-11-html/mpi-report.html MPI: A Message-Passing Interface Standard] &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;4foot&amp;quot;&amp;gt;[[#4body|4.]]&amp;lt;/span&amp;gt; Wikipedia's [http://en.wikipedia.org/wiki/Fortran FORTRAN] page &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch4a_bm&amp;diff=43962</id>
		<title>CSC/ECE 506 Spring 2011/ch4a bm</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2011/ch4a_bm&amp;diff=43962"/>
		<updated>2011-02-27T21:57:33Z</updated>

		<summary type="html">&lt;p&gt;Beburrou: /* Message Passing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
Many algorithms can be parallelized effectively.  Some of them can even be parellelized using different parallel models.  Gaussian elimination is one such algorithm.  It can be implemented in the Data Parallel, Shared Memory, and Message passing models.  This article discusses implementations of Gaussian elimination in all three models, using High Performance FORTRAN (HPF), OpenMP, MPI.&lt;br /&gt;
&lt;br /&gt;
= Gaussian Elimination =&lt;br /&gt;
&lt;br /&gt;
= FORTRAN Background =&lt;br /&gt;
FORTRAN has some differences from C-based languages.  They are listed below.  Assume that there exists an array &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;&lt;br /&gt;
* Arrays are 1-based instead of 0-based, and array subscripts are specified using parentheses instead of brackets.&lt;br /&gt;
* All elements of an array can be set to a value by simply setting the array variable equal to a value, as in &amp;lt;code&amp;gt;A = 0&amp;lt;/code&amp;gt;&lt;br /&gt;
* A &amp;lt;code&amp;gt;DO&amp;lt;/code&amp;gt; loop is not necessary to perform the same action on a set of items in an array.  Rather, one can simply specify a subset of the array on which to perform the action, as in &amp;lt;code&amp;gt;A(a:b) = A(a:b) * 2&amp;lt;/code&amp;gt;&lt;br /&gt;
* In a multi-dimensional array, using a colon as a range of array elements in one of the dimensions will perform the operation on all elements in that dimension, as in &amp;lt;code&amp;gt;A(1, :) = 2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Parallel Implementations =&lt;br /&gt;
&lt;br /&gt;
== Data Parallel ==&lt;br /&gt;
&lt;br /&gt;
== Shared Memory ==&lt;br /&gt;
&lt;br /&gt;
== Message Passing ==&lt;br /&gt;
The following section of code implements Gaussian Elimination via message passing, using MPI.  It was taken from a paper by S.F.McGinn and R.E.Shaw from the University of New Brunswick, New Brunswick, Canada.&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;1body&amp;quot;&amp;gt;[[#1foot|[1]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  1: root = 0&lt;br /&gt;
  2: chunk = n**2/p&lt;br /&gt;
  3: ! main loop&lt;br /&gt;
  4: do pivot = 1, n-1&lt;br /&gt;
  5:     ! root maintains communication&lt;br /&gt;
  6:     if (my_rank.eq.0) then&lt;br /&gt;
  7:        ! adjust the chunk size&lt;br /&gt;
  8:        if (MOD(pivot, p).eq.0) then&lt;br /&gt;
  9:           chunk = chunk - n&lt;br /&gt;
 10:        endif&lt;br /&gt;
 11: &lt;br /&gt;
 12:        ! calculate chunk vectors&lt;br /&gt;
 13:        rem = MOD((n**2-(n*pivot)),chunk)&lt;br /&gt;
 14:        tmp = 0&lt;br /&gt;
 15:        do i = 1, p&lt;br /&gt;
 16:           tmp = tmp + chunk&lt;br /&gt;
 17:           if (tmp.le.(n**2-(n*pivot))) then&lt;br /&gt;
 18:              a_chnk_vec(i) = chunk&lt;br /&gt;
 19:              b_chnk_vec(i) = chunk / n&lt;br /&gt;
 20:           else&lt;br /&gt;
 21:              a_chnk_vec(i) = rem&lt;br /&gt;
 22:              b_chnk_vec(i) = rem / n&lt;br /&gt;
 23:              rem = 0&lt;br /&gt;
 24:           endif&lt;br /&gt;
 25:        continue&lt;br /&gt;
 26: &lt;br /&gt;
 27:        ! calculate displacement vectors&lt;br /&gt;
 28:        a_disp_vec(1) = (pivot*n)&lt;br /&gt;
 29:        b_disp_vec(1) = pivot&lt;br /&gt;
 30:        do i = 2, p&lt;br /&gt;
 31:           a_disp_vec(i) = a_disp_vec(i-1) + a_chnk_vec(i-1)&lt;br /&gt;
 32:           b_disp_vec(i) = b_disp_vec(i-1) + b_chnk_vec(i-1)&lt;br /&gt;
 33:        continue&lt;br /&gt;
 34:  &lt;br /&gt;
 35:        ! fetch the pivot equation&lt;br /&gt;
 36:        do i = 1, n&lt;br /&gt;
 37:           pivot_eqn(i) = a(n-(i-1),pivot)&lt;br /&gt;
 38:        continue&lt;br /&gt;
 39:  &lt;br /&gt;
 40:        pivot_b = b(pivot)&lt;br /&gt;
 41:     endif ! my_rank.eq.0&lt;br /&gt;
 42:  &lt;br /&gt;
 43:     ! distribute the pivot equation&lt;br /&gt;
 44:     call MPI_BCAST(pivot_eqn, n,&lt;br /&gt;
 45:                    MPI_DOUBLE_PRECISION,&lt;br /&gt;
 46:                    root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 47:  &lt;br /&gt;
 48:     call MPI_BCAST(pivot_b, 1,&lt;br /&gt;
 49:                    MPI_DOUBLE_PRECISION,&lt;br /&gt;
 50:                    root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 51:  &lt;br /&gt;
 52:     ! distribute the chunk vector&lt;br /&gt;
 53:     call MPI_SCATTER(a_chnk_vec, 1, MPI_INTEGER,&lt;br /&gt;
 54:                      chunk, 1, MPI_INTEGER,&lt;br /&gt;
 55:                      root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 56:  &lt;br /&gt;
 57:     ! distribute the data&lt;br /&gt;
 58:     call MPI_SCATTERV(a, a_chnk_vec, a_disp_vec,&lt;br /&gt;
 59:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 60:                       local_a, chunk,&lt;br /&gt;
 61:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 62:                       root, MPI_COMM_WORLD,ierr)&lt;br /&gt;
 63:  &lt;br /&gt;
 64:     call MPI_SCATTERV(b, b_chnk_vec, b_disp_vec,&lt;br /&gt;
 65:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 66:                       local_b, chunk/n,&lt;br /&gt;
 67:                       MPI_DOUBLE_PRECISION,&lt;br /&gt;
 68:                       root, MPI_COMM_WORLD,ierr)&lt;br /&gt;
 69:  &lt;br /&gt;
 70:     ! forward elimination&lt;br /&gt;
 71:     do j = 1, (chunk/n)&lt;br /&gt;
 72:        xmult = local_a((n-(pivot-1)),j) / pivot_eqn(pivot)&lt;br /&gt;
 73:        do i = (n-pivot), 1, -1&lt;br /&gt;
 74:           local_a(i,j) = local_a(i,j) - (xmult * pivot_eqn(n-(i-1)))&lt;br /&gt;
 75:        continue&lt;br /&gt;
 76:  &lt;br /&gt;
 77:        local_b(j) = local_b(j) - (xmult * pivot_b)&lt;br /&gt;
 78:     continue&lt;br /&gt;
 79:  &lt;br /&gt;
 80:     ! restore the data to root&lt;br /&gt;
 81:     call MPI_GATHERV(local_a, chunk,&lt;br /&gt;
 82:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 83:                      a, a_chnk_vec, a_disp_vec,&lt;br /&gt;
 84:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 85:                      root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 86:  &lt;br /&gt;
 87:     call MPI_GATHERV(local_b, chunk/n,&lt;br /&gt;
 88:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 89:                      b, b_chnk_vec, b_disp_vec,&lt;br /&gt;
 90:                      MPI_DOUBLE_PRECISION,&lt;br /&gt;
 91:                      root, MPI_COMM_WORLD, ierr)&lt;br /&gt;
 92:  continue ! end of main loop&lt;br /&gt;
 93: &lt;br /&gt;
 94:  ! backwards substitution done in parallel (not shown)&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
This code lacks some of the declarations for the variables, but most of the variables are self-explanatory.  The code also attempts to do some load balancing via the &amp;lt;code&amp;gt;chunk&amp;lt;/code&amp;gt; variable.  &amp;lt;code&amp;gt;chunk&amp;lt;/code&amp;gt; is also used to determine how much data to send, as the amount of data needed in each step gets progressively smaller.  Making &amp;lt;code&amp;gt;chunk&amp;lt;/code&amp;gt; smaller will therefor decrease the amount of time spent in communication, thus yielding better runtimes.  The other variable of note is &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt;, which refers to the root processor, the processor that controls the rest of the processors.&lt;br /&gt;
&lt;br /&gt;
The code effectively begins its parallel section at line 4.  Lines 5-41 have the root processor setting the chunk size and setting up the data to be passed to the other processors.  In lines 43-68, the root processor sends the necessary data to the other processors.  The functions &amp;lt;code&amp;gt;MPI_BCAST&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MPI_SCATTER&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;MPI_SCATTERV&amp;lt;/code&amp;gt; serve as either a &amp;quot;send&amp;quot; or a &amp;quot;receive&amp;quot;, depending on which processor is executing them; on the root, they act as a send, while on all other processors, they act as a receive&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;[[#3foot|[3]]]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;.  In lines 70-78, each processor is performing the forward elimination on its chunk of data.  Finally, the data from each processor is sent back to the root processor using the &amp;lt;code&amp;gt;MPI_GATHERV&amp;lt;/code&amp;gt; function, which also functions as either a &amp;quot;send&amp;quot; or a receive&amp;quot;, only the root processor is now the receiver and the other processors are the senders.  All of this code is executed for each pivot point in the matrix.  Backwards substitution is then done sequentially on the root processor.&lt;br /&gt;
&lt;br /&gt;
The key elements of Message Passing in this code example are the communication via the &amp;lt;code&amp;gt;MPI_&amp;lt;/code&amp;gt; functions and the root processor performing some set-up of data to be passed on its own.  This code is using the MPI library to support parallelization.&lt;br /&gt;
&lt;br /&gt;
= Definitions =&lt;br /&gt;
* ''HPF'' - High Performance FORTRAN&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;span id=&amp;quot;1foot&amp;quot;&amp;gt;[[#1body|1.]]&amp;lt;/span&amp;gt; S.F.McGinn and R.E.Shaw, University of New Brunswick, [http://hpds.ee.kuas.edu.tw/download/parallel_processing/96/96present/20071212/Gaussian.pdf Parallel Gaussian Elimination Using OpenMP and MPI] &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;2foot&amp;quot;&amp;gt;[[#2body|2.]]&amp;lt;/span&amp;gt; Ian Foster, Argonne National Laboratory, [http://www.mcs.anl.gov/~itf/dbpp/text/node90.html Case Study: Gaussian Elimination] &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;3foot&amp;quot;&amp;gt;[[#3body|3.]]&amp;lt;/span&amp;gt; [http://www.mpi-forum.org/docs/mpi-11-html/mpi-report.html MPI: A Message-Passing Interface Standard] &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;4foot&amp;quot;&amp;gt;[[#4body|4.]]&amp;lt;/span&amp;gt; Wikipedia's [http://en.wikipedia.org/wiki/Fortran FORTRAN] page &amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Beburrou</name></author>
	</entry>
</feed>