<?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=Xzhang26</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=Xzhang26"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Xzhang26"/>
	<updated>2026-09-18T23:56:32Z</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_2012/7b_yw&amp;diff=59885</id>
		<title>CSC/ECE 506 Spring 2012/7b yw</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59885"/>
		<updated>2012-03-19T02:34:45Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* Quiz */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addressed caches are discussed. Then we discuss the need for TLB, a cache-like construct that translate virtual address to physical address. Then we raise the issue of TLB coherence. &lt;br /&gt;
&lt;br /&gt;
=== Virtually addressed caches ===&lt;br /&gt;
&lt;br /&gt;
Virtual memory is a memory management technology developed for multithread operating systems. This technique virtualizes a computer architecture's various forms of computer data storage (such as random-access memory and disk storage), allowing a program to be designed as though there is only one kind of memory, &amp;quot;virtual&amp;quot; memory, which behaves like directly addressable read/write memory (RAM). &lt;br /&gt;
&lt;br /&gt;
[[Image:virtualM.PNG|thumbnail|right|200px|Virtual Memory in modern computer systems&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
This technique greatly simplifies programmers job because modern operating system runs each process on its own dedicated virtual memory space. Thus each program runs as if it has the sole access of the virtual memory. In this way, programmers don't have to worry about how operating system switches between processes or how other process operates. Also, Virtual memory makes application programming easier by hiding fragmentation of physical memory; by delegating to the kernel the burden of managing the memory hierarchy (eliminating the need for the program to handle overlays explicitly); and, when each process is run in its own dedicated address space, by obviating the need to relocate program code or to access memory with relative addressing.&lt;br /&gt;
&lt;br /&gt;
The introducing of virtual memory raise the problem of translating virtual address to physical address since we need physical address to access the actual content stored in cache. And that's where Translation Lookaside Buffer comes into use.&lt;br /&gt;
&lt;br /&gt;
=== What is TLB ===&lt;br /&gt;
&lt;br /&gt;
A TLB has a fixed number of slots that contain page table entries, which map virtual addresses to physical addresses. The virtual memory is the space seen from a process. This space is segmented in pages of a prefixed size. The page table (generally loaded in memory) keeps track of where the virtual pages are loaded in the physical memory. The TLB is a cache of the page table; that is, only a subset of its content are stored.&lt;br /&gt;
The TLB references physical memory addresses in its table. It may reside between the CPU and the CPU cache, between the CPU cache and primary storage memory, or between levels of a multi-level cache. The placement determines whether the cache uses physical or virtual addressing. If the cache is virtually addressed, requests are sent directly from the CPU to the cache, and the TLB is accessed only on a cache miss. If the cache is physically addressed, the CPU does a TLB lookup on every memory operation and the resulting physical address is sent to the cache. There are pros and cons to both implementations. Caches that use virtual addressing have for their key part of the virtual address plus, optionally, a key called an &amp;quot;address space identifier&amp;quot; (ASID). Caches that don't have ASIDs must be flushed every context switch in a multiprocessing environment.&lt;br /&gt;
In a Harvard architecture or hybrid thereof, a separate virtual address space or memory access hardware may exist for instructions and data. This can lead to distinct TLBs for each access type.&lt;br /&gt;
A common optimization for physically addressed caches is to perform the TLB lookup in parallel with the cache access. The low-order bits of any virtual address (e.g., in a virtual memory system having 4 KB pages, the lower 12 bits of the virtual address) represent the offset of the desired address within the page, and thus they do not change in the virtual-to-physical translation. During a cache access, two steps are performed: an index is used to find an entry in the cache's data store, and then the tags for the cache line found are compared. If the cache is structured in such a way that it can be indexed using only the bits that do not change in translation, the cache can perform its &amp;quot;index&amp;quot; operation while the TLB translates the upper bits of the address. Then, the translated address from the TLB is passed to the cache. The cache performs a tag comparison to determine if this access was a hit or miss. It is possible to perform the TLB lookup in parallel with the cache access even if the cache must be indexed using some bits that may change upon address translation; see the address translation section in the cache article for more details about virtual addressing as it pertains to caches and TLBs.&lt;br /&gt;
&lt;br /&gt;
[[Image:tlb.PNG|thumbnail|right|200px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And here is generally how a typical TLB is working. Note that X is the virtual page number to be translated into a physical page number, X' is the Physical number corresponding to X. and V is the Virtual page number of a victim page(that is a page to be kicked off the table). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:tlbOP.PNG|thumbnail|right|200px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next in this chapter we are going to discuss problems that are going to occur when we extend this TLB structure to multi-processor systems. The solution to these problems is presented in next chapter.&lt;br /&gt;
&lt;br /&gt;
=== TLB Coherence issues ===&lt;br /&gt;
&lt;br /&gt;
Problems occur when we extend TLB table into multi-processor systems. That is when memory is shared, two processors may have different virtual names for the same block. &lt;br /&gt;
&lt;br /&gt;
[[Image:tlbCo.PNG|thumbnail|right|200px|Virtual Memory in modern computer systems&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
This cause inconsistent loads and stores when more than one processors are trying to access the same blocks of data. &lt;br /&gt;
&lt;br /&gt;
For example, Assume:&lt;br /&gt;
* The processor has been running Process 1&lt;br /&gt;
* It then switches to Process 2&lt;br /&gt;
* Later it switches back to Process 1&lt;br /&gt;
&lt;br /&gt;
Now Process 2 caches a different copy of the information than Process 1. When Process 2 makes a change, that change is not reflected in Process 1's copy of the information.&lt;br /&gt;
&lt;br /&gt;
==Solutions==&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
In this section, we will talk about several solutions to handle TLB coherence problem. We will focus most on the last approach - TLB shootdown - a commonlly used software approach to enforce TLB coherence. Some other approaches will be briefly introduced. &lt;br /&gt;
&lt;br /&gt;
===Virtually addressed caches===&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
This method is to get rid of TLB. If we do not need TLB, we will not have the Coherence problem. &lt;br /&gt;
&lt;br /&gt;
When virtually addressed cache is used, address translations only happen when there is a cache miss. Since it is not frequently to access page mappings, we do not need to use TLB any more. Figure shows how virtually addressed cache works.&lt;br /&gt;
[[File:yw1.jpg|200px|thumb|right|procedure block of addressing cache&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The key distinction between virtually and physically addressed caches is that Virtually addressed caches are indexed using part of a virtual address rather than a physical address. Virtually addressed caches offer potentially faster access times by avoiding the delay associated with address translation. &amp;lt;ref&amp;gt;the effects of virtually addressed caches on virtual memory design and performance  JonInouye - et al.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Figure shows the organization of virtually addressed caches.&lt;br /&gt;
[[File:yw2.jpg|200px|thumb|right|Organization of Virtual Addressed Caches&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
From the figure “ASID” means “address-space identifier,” which is often called a process identifier (PID) in some books. The diagram shows the “V-index” overlapping the (virtual) page number. If not, we wouldn’t need a virtually addressed cache. We could do address translation in parallel with cache access with a physically addressed cache. Also the V-index actually does not stored in the cache. Like the index (“set” or “line”) field in physically addressed caches, it is not stored, but just tells what line or set to look in for the data&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Given the virtually addressed cache which can help us get rid of TLB, problems of coherent still exist to some level. Swap-out and protection information(read or read/write) coherent still need to be enforced. However, since there is no TLB, such information is stored in cache, the coherence problem will be handled by cache-coherence hardware.&lt;br /&gt;
&lt;br /&gt;
=== Invalidate instructions&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;===&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
Some processors, notably the PowerPC, have a “TLB_invalidate_entry” instruction.&lt;br /&gt;
&lt;br /&gt;
This instruction broadcasts the page address on the bus so that the snooping hardware on other processors can automatically invalidate the corresponding TLB entries without interrupting the processor.&lt;br /&gt;
&lt;br /&gt;
A processor simply issues a TLB_invalidate_entry instruction immediately after changing a page-table entry. This works well on a shared-bus system; if two processors change the same entry at the same time, only one change can be broadcast first on the bus.&lt;br /&gt;
&lt;br /&gt;
===TLB shootdown===&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
====General Concept====&lt;br /&gt;
TLB shootdown is another approach to enforce TLB coherence. It is a software approach using inter-processor interrupts. Also, it is a very common technique to enforce TLB coherence. How it works? In general, when a processor changes a TLB entry, it will make the other processors which contain the same TLB entries to invalidate their copies. A quick example as below may explain it more clearly.&lt;br /&gt;
&lt;br /&gt;
Assuming you have some memory shared by all of the processors in your system. One of your processors restricts access to a page of that shared memory now, all of the processors have to flush their TLBs, so that the ones that aren't allowed to access that page can't do so anymore.The actions of one processor causing the TLBs to be flushed on other processors is what is called a TLB shootdown&amp;lt;ref&amp;gt;http://stackoverflow.com/questions/3748384/what-is-tlb-shootdown&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Detailed Steps====&lt;br /&gt;
Some steps are needed to implement this approach.&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Step 1.  A processor p that wants to modify a page table disables inter-processor interrupts and locks the page table.  It also clears its active flag, which indicates whether it is actively using any page table.&lt;br /&gt;
Step 2.  Processor p sends an interrupt to other processors that might be using the page table, describing the TLB actions to be performed.&lt;br /&gt;
Step 3.  Each processor that receives the interrupt clears its active flag.&lt;br /&gt;
Step 4.  Processor p busy-waits till the active flags of all interrupted processors are clear, then modifies the page table.  Processor p then releases the page-table lock, sets its active flag, and resumes execution.&lt;br /&gt;
Step 5.  Each interrupted processor busy-waits until none of the page tables it is using are locked.  After executing the required TLB actions and setting its active flag, it resumes execution.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
An example of TLB shootdown solution is the one described in Mach VM System. In this module, when an action may potentially cause TLB inconsistency, it will invoke the shootdown algorithm. The algorithm proceeds in four phases after it is invoked&amp;lt;ref&amp;gt;Translation Look aside Buffer Consistency: A Software Approach, David L. Black - et al. 1989&amp;lt;/ref&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
1 Initiator: The initiator queues consistency action  requests for all processors using the pmap  and sets their “action  needed” flags. It then sends interrupts to the processors and waits for responses. &lt;br /&gt;
2 Responders: Each responder receives its interrupt and removes itself from the set of active processors to acknowledge the interrupt. The responders then spin until  the  initiator completes its changes to pmap. (This  spinning  is  necessary  to ensure  that  responders  neither read nor write the pmap while the  update  is  in  progress.) &lt;br /&gt;
3 Initiator: The initiator performs its pmap changes after all responders using the pmap are spinning. It unlocks the  pmap when it is done. &lt;br /&gt;
4 Responders: The responders perform their required TLB invalidations after the pmap is unlocked and dequeue the corresponding actions. They also clear their “action needed” flags and rejoin the set of active processors.&lt;br /&gt;
&lt;br /&gt;
The Pseudo-Code of Mach Shootdown Algorithm is as below&amp;lt;ref&amp;gt;Translation Look aside Buffer Consistency: A Software Approach, David L. Black - et al. 1989&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Initiator: &lt;br /&gt;
s  =  disable_interrupts(); &lt;br /&gt;
active[mycpul  =  FALSE; &lt;br /&gt;
lockgmap(pmap); &lt;br /&gt;
if  (inconsistent  TLB  may  result) { &lt;br /&gt;
	if  (pmap-&amp;gt;in-uselmycpul)  { &lt;br /&gt;
	invalidate-tlb(pmap,start,end); &lt;br /&gt;
	}&lt;br /&gt;
	/*  Phase  1  */ &lt;br /&gt;
	if  (other  cpus  using  pmap)  {&lt;br /&gt;
		list_type  shoot-list  =  EMPTY-LIST; &lt;br /&gt;
		for  (every  cpu  in  system)  {&lt;br /&gt;
			if  (pmap-&amp;gt;in-uselcpul  &amp;amp;&amp;amp; cpu  !=  mycpu) {&lt;br /&gt;
				lock-action-structure(cpu): &lt;br /&gt;
				queue_action(cpu,pmap,start,end); &lt;br /&gt;
				action-neededlcpul  =  TRUE; &lt;br /&gt;
				unlock-action-structure(cpu); &lt;br /&gt;
				if  (idle[cpul  ==  FALSE)  { &lt;br /&gt;
					add  cpu  to  shoot-list &lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	for  (every  cpu  on  shoot-list)  { &lt;br /&gt;
		send-shootdown-interrupt(cpu); &lt;br /&gt;
	}&lt;br /&gt;
	for  (every  cpu  on  shoot-list)  { &lt;br /&gt;
		while  (activelcpul  &amp;amp;&amp;amp; pmap-&amp;gt;in-uselcpul)  {&lt;br /&gt;
			pmap-&amp;gt;in_use[cpu]){&lt;br /&gt;
			/*  spin  */  ; &lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}	&lt;br /&gt;
	&lt;br /&gt;
/*  Phase  3  */ &lt;br /&gt;
make  changes  to  physical  map &lt;br /&gt;
&lt;br /&gt;
unlock-pmap(pmap); &lt;br /&gt;
active[mycpu]  =  TRUE; &lt;br /&gt;
restore-interrupt-state(s); &lt;br /&gt;
&lt;br /&gt;
Responders:  /*  Phase  2  */ &lt;br /&gt;
s  =  disable-interrupts(); &lt;br /&gt;
	while  (action-needed[mycpu])  {&lt;br /&gt;
		active[mycpu]  =  FALSE; &lt;br /&gt;
		while  (pmap  is  locked(kernel-pmap)  &amp;amp;&amp;amp; pmapIisIlocked(user-pmap(mycpu))) &lt;br /&gt;
		/*  spin  */  ; &lt;br /&gt;
		&lt;br /&gt;
	/*  Phase  4  */ &lt;br /&gt;
	lock-action-structure(mycpu); &lt;br /&gt;
	process-queuedactions(mycpu); &lt;br /&gt;
	action-neededlmycpul  =  FALSE; &lt;br /&gt;
	unlock-action-structure(mycpu); &lt;br /&gt;
	active[mycpu]  =  TRUE; &lt;br /&gt;
}&lt;br /&gt;
restore-interrupt-state(s); &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Performance Analysis====&lt;br /&gt;
Apparently, as number of processors increases, the overhead of this approach scales linearly. Because number of interprocessors interrupts invoked will be O(n) to the number of processors. &lt;br /&gt;
&lt;br /&gt;
Figure indicates the latency increases linearly as number of cores goes up.[[File:yw3.jpg|200px|thumb|right|TLB shootdown latency &amp;lt;ref&amp;gt;UNified Instruction/Translation/Data (UNITD) Coherence: One Protocol to Rule Them All - Bogdan F. Romanescu et al.&amp;lt;/ref&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
===Some Other Approaches&amp;lt;ref&amp;gt;Translation-Lookaside Buffer Consistency Patricia J. Teller - et al.&amp;lt;/ref&amp;gt;===&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
1. Modified TLB shootdown&lt;br /&gt;
Overhead is the same as for TLB shootdown with two exceptions: Interrupted processors are not idled, and their participation is small and possibly constant. Page-table modification and use are not serialized.&lt;br /&gt;
&lt;br /&gt;
2. Lazy devaluation&lt;br /&gt;
The counter is updated on each TLB reload, invalidation, and replacement. When an unsafe change cannot be postponed, overhead is the same as for TLB shootdown.&lt;br /&gt;
&lt;br /&gt;
3. Validation&lt;br /&gt;
Memory requests contain a generation count. The modifying processor updates the generation count. An extra network trip is needed when a stale TLB entry is used. Overhead also includes a solution to the generation-count wraparound problem.&lt;br /&gt;
&lt;br /&gt;
==Summary==&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
The main goal of multiprocessor is to increase the execution speed. While enforcing the TLB coherent, we should well understand the trade-off of different approaches. Some of the approaches require specific hardware and others(like shootdown) don't. Actually, in real design, it is difficult to conclude which solution will be better, it all depends on what applications running in what kind of environment.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Quiz==&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
1.  Which below is(are) solution(s) to TLB coherence problem &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. MESI protocol&amp;lt;br /&amp;gt;&lt;br /&gt;
	B. TLB shootdown&amp;lt;br /&amp;gt;&lt;br /&gt;
	C. using virtually addressed cache&amp;lt;br /&amp;gt;&lt;br /&gt;
	D. all of above&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2.  which is(are) true below &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. TLB shootdown is a software approach&amp;lt;br /&amp;gt;&lt;br /&gt;
	B. using virually addressed cache will decrease cache misses&amp;lt;br /&amp;gt;&lt;br /&gt;
	C. PowerPC has a unique instruction to handle TLB coherence problem&amp;lt;br /&amp;gt;&lt;br /&gt;
	D. TLB is shared by different processors&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3.  what is(are) step(s) of TLB shootdown &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. Locks the page table&amp;lt;br /&amp;gt;&lt;br /&gt;
	B. Busy-wait the other processors to inactivate the flags&amp;lt;br /&amp;gt;&lt;br /&gt;
	C. Send interrupt signal&amp;lt;br /&amp;gt;&lt;br /&gt;
	D. Release Locks&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4.	Which is(are) incorrect about virtually addressed caches &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. It can be used to decrease the frequency to access map table &amp;lt;br /&amp;gt;&lt;br /&gt;
	B. It can only addressed by virtual address &amp;lt;br /&amp;gt;&lt;br /&gt;
	C. V-index should overlap the page number &amp;lt;br /&amp;gt;&lt;br /&gt;
	D. V-index number is stored in the cache &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Which is the correct order of phases in shootdown algorithm &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. responders initiators responders initiators &amp;lt;br /&amp;gt;&lt;br /&gt;
	B. initiators initiators responders responders &amp;lt;br /&amp;gt;&lt;br /&gt;
	C. initiators responders initiators responders &amp;lt;br /&amp;gt;&lt;br /&gt;
	D. responders responders initiators initiators&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. What's the typical function of a TLB in modern microarchitecture? &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. What's the main advantage of adding a virtual address layer rather than using physical addresses directly? &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
8. From the function of TLB described in this wiki, what's the best possible placement policy of a TLB? &amp;lt;br /&amp;gt;&lt;br /&gt;
        A. Direct-mapped &amp;lt;br /&amp;gt;&lt;br /&gt;
        B. Set-Associative &amp;lt;br /&amp;gt;&lt;br /&gt;
        C. Fully-Associative &amp;lt;br /&amp;gt;&lt;br /&gt;
        D. Non of the above &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
9. What's the main coherence issue discussed in this wiki? &amp;lt;br /&amp;gt;&lt;br /&gt;
        A. Two physical address share a same virtual address &amp;lt;br /&amp;gt;&lt;br /&gt;
        B. Two virtual addresses share a same physical page &amp;lt;br /&amp;gt;&lt;br /&gt;
        C. Processes might be kicking each others page table off &amp;lt;br /&amp;gt;&lt;br /&gt;
        C. None of the above &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
10. According to this wiki, who is running the page table, software or hardware? &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59883</id>
		<title>CSC/ECE 506 Spring 2012/7b yw</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59883"/>
		<updated>2012-03-19T02:33:30Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addressed caches are discussed. Then we discuss the need for TLB, a cache-like construct that translate virtual address to physical address. Then we raise the issue of TLB coherence. &lt;br /&gt;
&lt;br /&gt;
=== Virtually addressed caches ===&lt;br /&gt;
&lt;br /&gt;
Virtual memory is a memory management technology developed for multithread operating systems. This technique virtualizes a computer architecture's various forms of computer data storage (such as random-access memory and disk storage), allowing a program to be designed as though there is only one kind of memory, &amp;quot;virtual&amp;quot; memory, which behaves like directly addressable read/write memory (RAM). &lt;br /&gt;
&lt;br /&gt;
[[Image:virtualM.PNG|thumbnail|right|200px|Virtual Memory in modern computer systems&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
This technique greatly simplifies programmers job because modern operating system runs each process on its own dedicated virtual memory space. Thus each program runs as if it has the sole access of the virtual memory. In this way, programmers don't have to worry about how operating system switches between processes or how other process operates. Also, Virtual memory makes application programming easier by hiding fragmentation of physical memory; by delegating to the kernel the burden of managing the memory hierarchy (eliminating the need for the program to handle overlays explicitly); and, when each process is run in its own dedicated address space, by obviating the need to relocate program code or to access memory with relative addressing.&lt;br /&gt;
&lt;br /&gt;
The introducing of virtual memory raise the problem of translating virtual address to physical address since we need physical address to access the actual content stored in cache. And that's where Translation Lookaside Buffer comes into use.&lt;br /&gt;
&lt;br /&gt;
=== What is TLB ===&lt;br /&gt;
&lt;br /&gt;
A TLB has a fixed number of slots that contain page table entries, which map virtual addresses to physical addresses. The virtual memory is the space seen from a process. This space is segmented in pages of a prefixed size. The page table (generally loaded in memory) keeps track of where the virtual pages are loaded in the physical memory. The TLB is a cache of the page table; that is, only a subset of its content are stored.&lt;br /&gt;
The TLB references physical memory addresses in its table. It may reside between the CPU and the CPU cache, between the CPU cache and primary storage memory, or between levels of a multi-level cache. The placement determines whether the cache uses physical or virtual addressing. If the cache is virtually addressed, requests are sent directly from the CPU to the cache, and the TLB is accessed only on a cache miss. If the cache is physically addressed, the CPU does a TLB lookup on every memory operation and the resulting physical address is sent to the cache. There are pros and cons to both implementations. Caches that use virtual addressing have for their key part of the virtual address plus, optionally, a key called an &amp;quot;address space identifier&amp;quot; (ASID). Caches that don't have ASIDs must be flushed every context switch in a multiprocessing environment.&lt;br /&gt;
In a Harvard architecture or hybrid thereof, a separate virtual address space or memory access hardware may exist for instructions and data. This can lead to distinct TLBs for each access type.&lt;br /&gt;
A common optimization for physically addressed caches is to perform the TLB lookup in parallel with the cache access. The low-order bits of any virtual address (e.g., in a virtual memory system having 4 KB pages, the lower 12 bits of the virtual address) represent the offset of the desired address within the page, and thus they do not change in the virtual-to-physical translation. During a cache access, two steps are performed: an index is used to find an entry in the cache's data store, and then the tags for the cache line found are compared. If the cache is structured in such a way that it can be indexed using only the bits that do not change in translation, the cache can perform its &amp;quot;index&amp;quot; operation while the TLB translates the upper bits of the address. Then, the translated address from the TLB is passed to the cache. The cache performs a tag comparison to determine if this access was a hit or miss. It is possible to perform the TLB lookup in parallel with the cache access even if the cache must be indexed using some bits that may change upon address translation; see the address translation section in the cache article for more details about virtual addressing as it pertains to caches and TLBs.&lt;br /&gt;
&lt;br /&gt;
[[Image:tlb.PNG|thumbnail|right|200px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And here is generally how a typical TLB is working. Note that X is the virtual page number to be translated into a physical page number, X' is the Physical number corresponding to X. and V is the Virtual page number of a victim page(that is a page to be kicked off the table). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:tlbOP.PNG|thumbnail|right|200px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next in this chapter we are going to discuss problems that are going to occur when we extend this TLB structure to multi-processor systems. The solution to these problems is presented in next chapter.&lt;br /&gt;
&lt;br /&gt;
=== TLB Coherence issues ===&lt;br /&gt;
&lt;br /&gt;
Problems occur when we extend TLB table into multi-processor systems. That is when memory is shared, two processors may have different virtual names for the same block. &lt;br /&gt;
&lt;br /&gt;
[[Image:tlbCo.PNG|thumbnail|right|200px|Virtual Memory in modern computer systems&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
This cause inconsistent loads and stores when more than one processors are trying to access the same blocks of data. &lt;br /&gt;
&lt;br /&gt;
For example, Assume:&lt;br /&gt;
* The processor has been running Process 1&lt;br /&gt;
* It then switches to Process 2&lt;br /&gt;
* Later it switches back to Process 1&lt;br /&gt;
&lt;br /&gt;
Now Process 2 caches a different copy of the information than Process 1. When Process 2 makes a change, that change is not reflected in Process 1's copy of the information.&lt;br /&gt;
&lt;br /&gt;
==Solutions==&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
In this section, we will talk about several solutions to handle TLB coherence problem. We will focus most on the last approach - TLB shootdown - a commonlly used software approach to enforce TLB coherence. Some other approaches will be briefly introduced. &lt;br /&gt;
&lt;br /&gt;
===Virtually addressed caches===&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
This method is to get rid of TLB. If we do not need TLB, we will not have the Coherence problem. &lt;br /&gt;
&lt;br /&gt;
When virtually addressed cache is used, address translations only happen when there is a cache miss. Since it is not frequently to access page mappings, we do not need to use TLB any more. Figure shows how virtually addressed cache works.&lt;br /&gt;
[[File:yw1.jpg|200px|thumb|right|procedure block of addressing cache&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The key distinction between virtually and physically addressed caches is that Virtually addressed caches are indexed using part of a virtual address rather than a physical address. Virtually addressed caches offer potentially faster access times by avoiding the delay associated with address translation. &amp;lt;ref&amp;gt;the effects of virtually addressed caches on virtual memory design and performance  JonInouye - et al.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Figure shows the organization of virtually addressed caches.&lt;br /&gt;
[[File:yw2.jpg|200px|thumb|right|Organization of Virtual Addressed Caches&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
From the figure “ASID” means “address-space identifier,” which is often called a process identifier (PID) in some books. The diagram shows the “V-index” overlapping the (virtual) page number. If not, we wouldn’t need a virtually addressed cache. We could do address translation in parallel with cache access with a physically addressed cache. Also the V-index actually does not stored in the cache. Like the index (“set” or “line”) field in physically addressed caches, it is not stored, but just tells what line or set to look in for the data&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Given the virtually addressed cache which can help us get rid of TLB, problems of coherent still exist to some level. Swap-out and protection information(read or read/write) coherent still need to be enforced. However, since there is no TLB, such information is stored in cache, the coherence problem will be handled by cache-coherence hardware.&lt;br /&gt;
&lt;br /&gt;
=== Invalidate instructions&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;===&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
Some processors, notably the PowerPC, have a “TLB_invalidate_entry” instruction.&lt;br /&gt;
&lt;br /&gt;
This instruction broadcasts the page address on the bus so that the snooping hardware on other processors can automatically invalidate the corresponding TLB entries without interrupting the processor.&lt;br /&gt;
&lt;br /&gt;
A processor simply issues a TLB_invalidate_entry instruction immediately after changing a page-table entry. This works well on a shared-bus system; if two processors change the same entry at the same time, only one change can be broadcast first on the bus.&lt;br /&gt;
&lt;br /&gt;
===TLB shootdown===&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
====General Concept====&lt;br /&gt;
TLB shootdown is another approach to enforce TLB coherence. It is a software approach using inter-processor interrupts. Also, it is a very common technique to enforce TLB coherence. How it works? In general, when a processor changes a TLB entry, it will make the other processors which contain the same TLB entries to invalidate their copies. A quick example as below may explain it more clearly.&lt;br /&gt;
&lt;br /&gt;
Assuming you have some memory shared by all of the processors in your system. One of your processors restricts access to a page of that shared memory now, all of the processors have to flush their TLBs, so that the ones that aren't allowed to access that page can't do so anymore.The actions of one processor causing the TLBs to be flushed on other processors is what is called a TLB shootdown&amp;lt;ref&amp;gt;http://stackoverflow.com/questions/3748384/what-is-tlb-shootdown&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Detailed Steps====&lt;br /&gt;
Some steps are needed to implement this approach.&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Step 1.  A processor p that wants to modify a page table disables inter-processor interrupts and locks the page table.  It also clears its active flag, which indicates whether it is actively using any page table.&lt;br /&gt;
Step 2.  Processor p sends an interrupt to other processors that might be using the page table, describing the TLB actions to be performed.&lt;br /&gt;
Step 3.  Each processor that receives the interrupt clears its active flag.&lt;br /&gt;
Step 4.  Processor p busy-waits till the active flags of all interrupted processors are clear, then modifies the page table.  Processor p then releases the page-table lock, sets its active flag, and resumes execution.&lt;br /&gt;
Step 5.  Each interrupted processor busy-waits until none of the page tables it is using are locked.  After executing the required TLB actions and setting its active flag, it resumes execution.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
An example of TLB shootdown solution is the one described in Mach VM System. In this module, when an action may potentially cause TLB inconsistency, it will invoke the shootdown algorithm. The algorithm proceeds in four phases after it is invoked&amp;lt;ref&amp;gt;Translation Look aside Buffer Consistency: A Software Approach, David L. Black - et al. 1989&amp;lt;/ref&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
1 Initiator: The initiator queues consistency action  requests for all processors using the pmap  and sets their “action  needed” flags. It then sends interrupts to the processors and waits for responses. &lt;br /&gt;
2 Responders: Each responder receives its interrupt and removes itself from the set of active processors to acknowledge the interrupt. The responders then spin until  the  initiator completes its changes to pmap. (This  spinning  is  necessary  to ensure  that  responders  neither read nor write the pmap while the  update  is  in  progress.) &lt;br /&gt;
3 Initiator: The initiator performs its pmap changes after all responders using the pmap are spinning. It unlocks the  pmap when it is done. &lt;br /&gt;
4 Responders: The responders perform their required TLB invalidations after the pmap is unlocked and dequeue the corresponding actions. They also clear their “action needed” flags and rejoin the set of active processors.&lt;br /&gt;
&lt;br /&gt;
The Pseudo-Code of Mach Shootdown Algorithm is as below&amp;lt;ref&amp;gt;Translation Look aside Buffer Consistency: A Software Approach, David L. Black - et al. 1989&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Initiator: &lt;br /&gt;
s  =  disable_interrupts(); &lt;br /&gt;
active[mycpul  =  FALSE; &lt;br /&gt;
lockgmap(pmap); &lt;br /&gt;
if  (inconsistent  TLB  may  result) { &lt;br /&gt;
	if  (pmap-&amp;gt;in-uselmycpul)  { &lt;br /&gt;
	invalidate-tlb(pmap,start,end); &lt;br /&gt;
	}&lt;br /&gt;
	/*  Phase  1  */ &lt;br /&gt;
	if  (other  cpus  using  pmap)  {&lt;br /&gt;
		list_type  shoot-list  =  EMPTY-LIST; &lt;br /&gt;
		for  (every  cpu  in  system)  {&lt;br /&gt;
			if  (pmap-&amp;gt;in-uselcpul  &amp;amp;&amp;amp; cpu  !=  mycpu) {&lt;br /&gt;
				lock-action-structure(cpu): &lt;br /&gt;
				queue_action(cpu,pmap,start,end); &lt;br /&gt;
				action-neededlcpul  =  TRUE; &lt;br /&gt;
				unlock-action-structure(cpu); &lt;br /&gt;
				if  (idle[cpul  ==  FALSE)  { &lt;br /&gt;
					add  cpu  to  shoot-list &lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	for  (every  cpu  on  shoot-list)  { &lt;br /&gt;
		send-shootdown-interrupt(cpu); &lt;br /&gt;
	}&lt;br /&gt;
	for  (every  cpu  on  shoot-list)  { &lt;br /&gt;
		while  (activelcpul  &amp;amp;&amp;amp; pmap-&amp;gt;in-uselcpul)  {&lt;br /&gt;
			pmap-&amp;gt;in_use[cpu]){&lt;br /&gt;
			/*  spin  */  ; &lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}	&lt;br /&gt;
	&lt;br /&gt;
/*  Phase  3  */ &lt;br /&gt;
make  changes  to  physical  map &lt;br /&gt;
&lt;br /&gt;
unlock-pmap(pmap); &lt;br /&gt;
active[mycpu]  =  TRUE; &lt;br /&gt;
restore-interrupt-state(s); &lt;br /&gt;
&lt;br /&gt;
Responders:  /*  Phase  2  */ &lt;br /&gt;
s  =  disable-interrupts(); &lt;br /&gt;
	while  (action-needed[mycpu])  {&lt;br /&gt;
		active[mycpu]  =  FALSE; &lt;br /&gt;
		while  (pmap  is  locked(kernel-pmap)  &amp;amp;&amp;amp; pmapIisIlocked(user-pmap(mycpu))) &lt;br /&gt;
		/*  spin  */  ; &lt;br /&gt;
		&lt;br /&gt;
	/*  Phase  4  */ &lt;br /&gt;
	lock-action-structure(mycpu); &lt;br /&gt;
	process-queuedactions(mycpu); &lt;br /&gt;
	action-neededlmycpul  =  FALSE; &lt;br /&gt;
	unlock-action-structure(mycpu); &lt;br /&gt;
	active[mycpu]  =  TRUE; &lt;br /&gt;
}&lt;br /&gt;
restore-interrupt-state(s); &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Performance Analysis====&lt;br /&gt;
Apparently, as number of processors increases, the overhead of this approach scales linearly. Because number of interprocessors interrupts invoked will be O(n) to the number of processors. &lt;br /&gt;
&lt;br /&gt;
Figure indicates the latency increases linearly as number of cores goes up.[[File:yw3.jpg|200px|thumb|right|TLB shootdown latency &amp;lt;ref&amp;gt;UNified Instruction/Translation/Data (UNITD) Coherence: One Protocol to Rule Them All - Bogdan F. Romanescu et al.&amp;lt;/ref&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
===Some Other Approaches&amp;lt;ref&amp;gt;Translation-Lookaside Buffer Consistency Patricia J. Teller - et al.&amp;lt;/ref&amp;gt;===&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
1. Modified TLB shootdown&lt;br /&gt;
Overhead is the same as for TLB shootdown with two exceptions: Interrupted processors are not idled, and their participation is small and possibly constant. Page-table modification and use are not serialized.&lt;br /&gt;
&lt;br /&gt;
2. Lazy devaluation&lt;br /&gt;
The counter is updated on each TLB reload, invalidation, and replacement. When an unsafe change cannot be postponed, overhead is the same as for TLB shootdown.&lt;br /&gt;
&lt;br /&gt;
3. Validation&lt;br /&gt;
Memory requests contain a generation count. The modifying processor updates the generation count. An extra network trip is needed when a stale TLB entry is used. Overhead also includes a solution to the generation-count wraparound problem.&lt;br /&gt;
&lt;br /&gt;
==Summary==&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
The main goal of multiprocessor is to increase the execution speed. While enforcing the TLB coherent, we should well understand the trade-off of different approaches. Some of the approaches require specific hardware and others(like shootdown) don't. Actually, in real design, it is difficult to conclude which solution will be better, it all depends on what applications running in what kind of environment.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Quiz==&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
1.  Which below is(are) solution(s) to TLB coherence problem &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. MESI protocol&amp;lt;br /&amp;gt;&lt;br /&gt;
	B. TLB shootdown&amp;lt;br /&amp;gt;&lt;br /&gt;
	C. using virtually addressed cache&amp;lt;br /&amp;gt;&lt;br /&gt;
	D. all of above&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2.  which is(are) true below &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. TLB shootdown is a software approach&amp;lt;br /&amp;gt;&lt;br /&gt;
	B. using virually addressed cache will decrease cache misses&amp;lt;br /&amp;gt;&lt;br /&gt;
	C. PowerPC has a unique instruction to handle TLB coherence problem&amp;lt;br /&amp;gt;&lt;br /&gt;
	D. TLB is shared by different processors&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3.  what is(are) step(s) of TLB shootdown &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. Locks the page table&amp;lt;br /&amp;gt;&lt;br /&gt;
	B. Busy-wait the other processors to inactivate the flags&amp;lt;br /&amp;gt;&lt;br /&gt;
	C. Send interrupt signal&amp;lt;br /&amp;gt;&lt;br /&gt;
	D. Release Locks&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4.	Which is(are) incorrect about virtually addressed caches &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. It can be used to decrease the frequency to access map table &amp;lt;br /&amp;gt;&lt;br /&gt;
	B. It can only addressed by virtual address &amp;lt;br /&amp;gt;&lt;br /&gt;
	C. V-index should overlap the page number &amp;lt;br /&amp;gt;&lt;br /&gt;
	D. V-index number is stored in the cache &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Which is the correct order of phases in shootdown algorithm &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. responders initiators responders initiators &amp;lt;br /&amp;gt;&lt;br /&gt;
	B. initiators initiators responders responders &amp;lt;br /&amp;gt;&lt;br /&gt;
	C. initiators responders initiators responders &amp;lt;br /&amp;gt;&lt;br /&gt;
	D. responders responders initiators initiators&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. What's the typical function of a TLB in modern microarchitecture? &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
7. What's the main advantage of adding a virtual address layer rather than using physical addresses directly? &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
8. From the function of TLB described in this wiki, what's the best possible placement policy of a TLB? &amp;lt;br /&amp;gt;&lt;br /&gt;
        A. Direct-mapped &amp;lt;br /&amp;gt;&lt;br /&gt;
        B. Set-Associative &amp;lt;br /&amp;gt;&lt;br /&gt;
        C. Fully-Associative &amp;lt;br /&amp;gt;&lt;br /&gt;
        D. Non of the above &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
9. What's the main coherence issue discussed in this wiki? &amp;lt;br /&amp;gt;&lt;br /&gt;
        A. Two physical address share a same virtual address &amp;lt;br /&amp;gt;&lt;br /&gt;
        B. Two virtual addresses share a same physical page &amp;lt;br /&amp;gt;&lt;br /&gt;
        C. Processes might be kicking each others page table off &amp;lt;br /&amp;gt;&lt;br /&gt;
        C. None of the above &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
10.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59874</id>
		<title>CSC/ECE 506 Spring 2012/7b yw</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59874"/>
		<updated>2012-03-19T02:20:29Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* TLB Coherence issues */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addressed caches are discussed. Then we discuss the need for TLB, a cache-like construct that translate virtual address to physical address. Then we raise the issue of TLB coherence. &lt;br /&gt;
&lt;br /&gt;
=== Virtually addressed caches ===&lt;br /&gt;
&lt;br /&gt;
Virtual memory is a memory management technology developed for multithread operating systems. This technique virtualizes a computer architecture's various forms of computer data storage (such as random-access memory and disk storage), allowing a program to be designed as though there is only one kind of memory, &amp;quot;virtual&amp;quot; memory, which behaves like directly addressable read/write memory (RAM). &lt;br /&gt;
&lt;br /&gt;
[[Image:virtualM.PNG|thumbnail|right|200px|Virtual Memory in modern computer systems&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
This technique greatly simplifies programmers job because modern operating system runs each process on its own dedicated virtual memory space. Thus each program runs as if it has the sole access of the virtual memory. In this way, programmers don't have to worry about how operating system switches between processes or how other process operates. Also, Virtual memory makes application programming easier by hiding fragmentation of physical memory; by delegating to the kernel the burden of managing the memory hierarchy (eliminating the need for the program to handle overlays explicitly); and, when each process is run in its own dedicated address space, by obviating the need to relocate program code or to access memory with relative addressing.&lt;br /&gt;
&lt;br /&gt;
The introducing of virtual memory raise the problem of translating virtual address to physical address since we need physical address to access the actual content stored in cache. And that's where Translation Lookaside Buffer comes into use.&lt;br /&gt;
&lt;br /&gt;
=== What is TLB ===&lt;br /&gt;
&lt;br /&gt;
A TLB has a fixed number of slots that contain page table entries, which map virtual addresses to physical addresses. The virtual memory is the space seen from a process. This space is segmented in pages of a prefixed size. The page table (generally loaded in memory) keeps track of where the virtual pages are loaded in the physical memory. The TLB is a cache of the page table; that is, only a subset of its content are stored.&lt;br /&gt;
The TLB references physical memory addresses in its table. It may reside between the CPU and the CPU cache, between the CPU cache and primary storage memory, or between levels of a multi-level cache. The placement determines whether the cache uses physical or virtual addressing. If the cache is virtually addressed, requests are sent directly from the CPU to the cache, and the TLB is accessed only on a cache miss. If the cache is physically addressed, the CPU does a TLB lookup on every memory operation and the resulting physical address is sent to the cache. There are pros and cons to both implementations. Caches that use virtual addressing have for their key part of the virtual address plus, optionally, a key called an &amp;quot;address space identifier&amp;quot; (ASID). Caches that don't have ASIDs must be flushed every context switch in a multiprocessing environment.&lt;br /&gt;
In a Harvard architecture or hybrid thereof, a separate virtual address space or memory access hardware may exist for instructions and data. This can lead to distinct TLBs for each access type.&lt;br /&gt;
A common optimization for physically addressed caches is to perform the TLB lookup in parallel with the cache access. The low-order bits of any virtual address (e.g., in a virtual memory system having 4 KB pages, the lower 12 bits of the virtual address) represent the offset of the desired address within the page, and thus they do not change in the virtual-to-physical translation. During a cache access, two steps are performed: an index is used to find an entry in the cache's data store, and then the tags for the cache line found are compared. If the cache is structured in such a way that it can be indexed using only the bits that do not change in translation, the cache can perform its &amp;quot;index&amp;quot; operation while the TLB translates the upper bits of the address. Then, the translated address from the TLB is passed to the cache. The cache performs a tag comparison to determine if this access was a hit or miss. It is possible to perform the TLB lookup in parallel with the cache access even if the cache must be indexed using some bits that may change upon address translation; see the address translation section in the cache article for more details about virtual addressing as it pertains to caches and TLBs.&lt;br /&gt;
&lt;br /&gt;
[[Image:tlb.PNG|thumbnail|right|200px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And here is generally how a typical TLB is working. Note that X is the virtual page number to be translated into a physical page number, X' is the Physical number corresponding to X. and V is the Virtual page number of a victim page(that is a page to be kicked off the table). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:tlbOP.PNG|thumbnail|right|200px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next in this chapter we are going to discuss problems that are going to occur when we extend this TLB structure to multi-processor systems. The solution to these problems is presented in next chapter.&lt;br /&gt;
&lt;br /&gt;
=== TLB Coherence issues ===&lt;br /&gt;
&lt;br /&gt;
Problems occur when we extend TLB table into multi-processor systems. That is when memory is shared, two processors may have different virtual names for the same block. &lt;br /&gt;
&lt;br /&gt;
[[Image:tlbCo.PNG|thumbnail|right|200px|Virtual Memory in modern computer systems&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
This cause inconsistent loads and stores when more than one processors are trying to access the same blocks of data. &lt;br /&gt;
&lt;br /&gt;
For example, Assume:&lt;br /&gt;
* The processor has been running Process 1&lt;br /&gt;
* It then switches to Process 2&lt;br /&gt;
* Later it switches back to Process 1&lt;br /&gt;
&lt;br /&gt;
Now Process 2 caches a different copy of the information than Process 1. When Process 2 makes a change, that change is not reflected in Process 1's copy of the information.&lt;br /&gt;
&lt;br /&gt;
==Solutions==&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
In this section, we will talk about several solutions to handle TLB coherence problem. We will focus most on the last approach - TLB shootdown - a commonlly used software approach to enforce TLB coherence. Some other approaches will be briefly introduced. &lt;br /&gt;
&lt;br /&gt;
===Virtually addressed caches===&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
This method is to get rid of TLB. If we do not need TLB, we will not have the Coherence problem. &lt;br /&gt;
&lt;br /&gt;
When virtually addressed cache is used, address translations only happen when there is a cache miss. Since it is not frequently to access page mappings, we do not need to use TLB any more. Figure shows how virtually addressed cache works.&lt;br /&gt;
[[File:yw1.jpg|200px|thumb|right|procedure block of addressing cache&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The key distinction between virtually and physically addressed caches is that Virtually addressed caches are indexed using part of a virtual address rather than a physical address. Virtually addressed caches offer potentially faster access times by avoiding the delay associated with address translation. &amp;lt;ref&amp;gt;the effects of virtually addressed caches on virtual memory design and performance  JonInouye - et al.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Figure shows the organization of virtually addressed caches.&lt;br /&gt;
[[File:yw2.jpg|200px|thumb|right|Organization of Virtual Addressed Caches&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
From the figure “ASID” means “address-space identifier,” which is often called a process identifier (PID) in some books. The diagram shows the “V-index” overlapping the (virtual) page number. If not, we wouldn’t need a virtually addressed cache. We could do address translation in parallel with cache access with a physically addressed cache. Also the V-index actually does not stored in the cache. Like the index (“set” or “line”) field in physically addressed caches, it is not stored, but just tells what line or set to look in for the data&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Given the virtually addressed cache which can help us get rid of TLB, problems of coherent still exist to some level. Swap-out and protection information(read or read/write) coherent still need to be enforced. However, since there is no TLB, such information is stored in cache, the coherence problem will be handled by cache-coherence hardware.&lt;br /&gt;
&lt;br /&gt;
=== Invalidate instructions&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;===&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
Some processors, notably the PowerPC, have a “TLB_invalidate_entry” instruction.&lt;br /&gt;
&lt;br /&gt;
This instruction broadcasts the page address on the bus so that the snooping hardware on other processors can automatically invalidate the corresponding TLB entries without interrupting the processor.&lt;br /&gt;
&lt;br /&gt;
A processor simply issues a TLB_invalidate_entry instruction immediately after changing a page-table entry. This works well on a shared-bus system; if two processors change the same entry at the same time, only one change can be broadcast first on the bus.&lt;br /&gt;
&lt;br /&gt;
===TLB shootdown===&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
====General Concept====&lt;br /&gt;
TLB shootdown is another approach to enforce TLB coherence. It is a software approach using inter-processor interrupts. Also, it is a very common technique to enforce TLB coherence. How it works? In general, when a processor changes a TLB entry, it will make the other processors which contain the same TLB entries to invalidate their copies. A quick example as below may explain it more clearly.&lt;br /&gt;
&lt;br /&gt;
Assuming you have some memory shared by all of the processors in your system. One of your processors restricts access to a page of that shared memory now, all of the processors have to flush their TLBs, so that the ones that aren't allowed to access that page can't do so anymore.The actions of one processor causing the TLBs to be flushed on other processors is what is called a TLB shootdown&amp;lt;ref&amp;gt;http://stackoverflow.com/questions/3748384/what-is-tlb-shootdown&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Detailed Steps====&lt;br /&gt;
Some steps are needed to implement this approach.&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Step 1.  A processor p that wants to modify a page table disables inter-processor interrupts and locks the page table.  It also clears its active flag, which indicates whether it is actively using any page table.&lt;br /&gt;
Step 2.  Processor p sends an interrupt to other processors that might be using the page table, describing the TLB actions to be performed.&lt;br /&gt;
Step 3.  Each processor that receives the interrupt clears its active flag.&lt;br /&gt;
Step 4.  Processor p busy-waits till the active flags of all interrupted processors are clear, then modifies the page table.  Processor p then releases the page-table lock, sets its active flag, and resumes execution.&lt;br /&gt;
Step 5.  Each interrupted processor busy-waits until none of the page tables it is using are locked.  After executing the required TLB actions and setting its active flag, it resumes execution.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
An example of TLB shootdown solution is the one described in Mach VM System. In this module, when an action may potentially cause TLB inconsistency, it will invoke the shootdown algorithm. The algorithm proceeds in four phases after it is invoked&amp;lt;ref&amp;gt;Translation Look aside Buffer Consistency: A Software Approach, David L. Black - et al. 1989&amp;lt;/ref&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
1 Initiator: The initiator queues consistency action  requests for all processors using the pmap  and sets their “action  needed” flags. It then sends interrupts to the processors and waits for responses. &lt;br /&gt;
2 Responders: Each responder receives its interrupt and removes itself from the set of active processors to acknowledge the interrupt. The responders then spin until  the  initiator completes its changes to pmap. (This  spinning  is  necessary  to ensure  that  responders  neither read nor write the pmap while the  update  is  in  progress.) &lt;br /&gt;
3 Initiator: The initiator performs its pmap changes after all responders using the pmap are spinning. It unlocks the  pmap when it is done. &lt;br /&gt;
4 Responders: The responders perform their required TLB invalidations after the pmap is unlocked and dequeue the corresponding actions. They also clear their “action needed” flags and rejoin the set of active processors.&lt;br /&gt;
&lt;br /&gt;
The Pseudo-Code of Mach Shootdown Algorithm is as below&amp;lt;ref&amp;gt;Translation Look aside Buffer Consistency: A Software Approach, David L. Black - et al. 1989&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Initiator: &lt;br /&gt;
s  =  disable_interrupts(); &lt;br /&gt;
active[mycpul  =  FALSE; &lt;br /&gt;
lockgmap(pmap); &lt;br /&gt;
if  (inconsistent  TLB  may  result) { &lt;br /&gt;
	if  (pmap-&amp;gt;in-uselmycpul)  { &lt;br /&gt;
	invalidate-tlb(pmap,start,end); &lt;br /&gt;
	}&lt;br /&gt;
	/*  Phase  1  */ &lt;br /&gt;
	if  (other  cpus  using  pmap)  {&lt;br /&gt;
		list_type  shoot-list  =  EMPTY-LIST; &lt;br /&gt;
		for  (every  cpu  in  system)  {&lt;br /&gt;
			if  (pmap-&amp;gt;in-uselcpul  &amp;amp;&amp;amp; cpu  !=  mycpu) {&lt;br /&gt;
				lock-action-structure(cpu): &lt;br /&gt;
				queue_action(cpu,pmap,start,end); &lt;br /&gt;
				action-neededlcpul  =  TRUE; &lt;br /&gt;
				unlock-action-structure(cpu); &lt;br /&gt;
				if  (idle[cpul  ==  FALSE)  { &lt;br /&gt;
					add  cpu  to  shoot-list &lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	for  (every  cpu  on  shoot-list)  { &lt;br /&gt;
		send-shootdown-interrupt(cpu); &lt;br /&gt;
	}&lt;br /&gt;
	for  (every  cpu  on  shoot-list)  { &lt;br /&gt;
		while  (activelcpul  &amp;amp;&amp;amp; pmap-&amp;gt;in-uselcpul)  {&lt;br /&gt;
			pmap-&amp;gt;in_use[cpu]){&lt;br /&gt;
			/*  spin  */  ; &lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}	&lt;br /&gt;
	&lt;br /&gt;
/*  Phase  3  */ &lt;br /&gt;
make  changes  to  physical  map &lt;br /&gt;
&lt;br /&gt;
unlock-pmap(pmap); &lt;br /&gt;
active[mycpu]  =  TRUE; &lt;br /&gt;
restore-interrupt-state(s); &lt;br /&gt;
&lt;br /&gt;
Responders:  /*  Phase  2  */ &lt;br /&gt;
s  =  disable-interrupts(); &lt;br /&gt;
	while  (action-needed[mycpu])  {&lt;br /&gt;
		active[mycpu]  =  FALSE; &lt;br /&gt;
		while  (pmap  is  locked(kernel-pmap)  &amp;amp;&amp;amp; pmapIisIlocked(user-pmap(mycpu))) &lt;br /&gt;
		/*  spin  */  ; &lt;br /&gt;
		&lt;br /&gt;
	/*  Phase  4  */ &lt;br /&gt;
	lock-action-structure(mycpu); &lt;br /&gt;
	process-queuedactions(mycpu); &lt;br /&gt;
	action-neededlmycpul  =  FALSE; &lt;br /&gt;
	unlock-action-structure(mycpu); &lt;br /&gt;
	active[mycpu]  =  TRUE; &lt;br /&gt;
}&lt;br /&gt;
restore-interrupt-state(s); &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Performance Analysis====&lt;br /&gt;
Apparently, as number of processors increases, the overhead of this approach scales linearly. Because number of interprocessors interrupts invoked will be O(n) to the number of processors. &lt;br /&gt;
&lt;br /&gt;
Figure indicates the latency increases linearly as number of cores goes up.[[File:yw3.jpg|200px|thumb|right|TLB shootdown latency &amp;lt;ref&amp;gt;UNified Instruction/Translation/Data (UNITD) Coherence: One Protocol to Rule Them All - Bogdan F. Romanescu et al.&amp;lt;/ref&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
===Some Other Approaches&amp;lt;ref&amp;gt;Translation-Lookaside Buffer Consistency Patricia J. Teller - et al.&amp;lt;/ref&amp;gt;===&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
1. Modified TLB shootdown&lt;br /&gt;
Overhead is the same as for TLB shootdown with two exceptions: Interrupted processors are not idled, and their participation is small and possibly constant. Page-table modification and use are not serialized.&lt;br /&gt;
&lt;br /&gt;
2. Lazy devaluation&lt;br /&gt;
The counter is updated on each TLB reload, invalidation, and replacement. When an unsafe change cannot be postponed, overhead is the same as for TLB shootdown.&lt;br /&gt;
&lt;br /&gt;
3. Validation&lt;br /&gt;
Memory requests contain a generation count. The modifying processor updates the generation count. An extra network trip is needed when a stale TLB entry is used. Overhead also includes a solution to the generation-count wraparound problem.&lt;br /&gt;
&lt;br /&gt;
==Summary==&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
The main goal of multiprocessor is to increase the execution speed. While enforcing the TLB coherent, we should well understand the trade-off of different approaches. Some of the approaches require specific hardware and others(like shootdown) don't. Actually, in real design, it is difficult to conclude which solution will be better, it all depends on what applications running in what kind of environment.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Quiz==&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
1.  Which below is(are) solution(s) to TLB coherence problem &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. MESI protocol&amp;lt;br /&amp;gt;&lt;br /&gt;
	B. TLB shootdown&amp;lt;br /&amp;gt;&lt;br /&gt;
	C. using virtually addressed cache&amp;lt;br /&amp;gt;&lt;br /&gt;
	D. all of above&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2.  which is(are) true below &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. TLB shootdown is a software approach&amp;lt;br /&amp;gt;&lt;br /&gt;
	B. using virually addressed cache will decrease cache misses&amp;lt;br /&amp;gt;&lt;br /&gt;
	C. PowerPC has a unique instruction to handle TLB coherence problem&amp;lt;br /&amp;gt;&lt;br /&gt;
	D. TLB is shared by different processors&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3.  what is(are) step(s) of TLB shootdown &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. Locks the page table&amp;lt;br /&amp;gt;&lt;br /&gt;
	B. Busy-wait the other processors to inactivate the flags&amp;lt;br /&amp;gt;&lt;br /&gt;
	C. Send interrupt signal&amp;lt;br /&amp;gt;&lt;br /&gt;
	D. Release Locks&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4.	Which is(are) incorrect about virtually addressed caches &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. It can be used to decrease the frequency to access map table &amp;lt;br /&amp;gt;&lt;br /&gt;
	B. It can only addressed by virtual address &amp;lt;br /&amp;gt;&lt;br /&gt;
	C. V-index should overlap the page number &amp;lt;br /&amp;gt;&lt;br /&gt;
	D. V-index number is stored in the cache &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Which is the correct order of phases in shootdown algorithm &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. responders initiators responders initiators &amp;lt;br /&amp;gt;&lt;br /&gt;
	B. initiators initiators responders responders &amp;lt;br /&amp;gt;&lt;br /&gt;
	C. initiators responders initiators responders &amp;lt;br /&amp;gt;&lt;br /&gt;
	D. responders responders initiators initiators&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:TlbCo.PNG&amp;diff=59866</id>
		<title>File:TlbCo.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:TlbCo.PNG&amp;diff=59866"/>
		<updated>2012-03-19T02:18:25Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59864</id>
		<title>CSC/ECE 506 Spring 2012/7b yw</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59864"/>
		<updated>2012-03-19T02:17:59Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* TLB Coherence issues */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addressed caches are discussed. Then we discuss the need for TLB, a cache-like construct that translate virtual address to physical address. Then we raise the issue of TLB coherence. &lt;br /&gt;
&lt;br /&gt;
=== Virtually addressed caches ===&lt;br /&gt;
&lt;br /&gt;
Virtual memory is a memory management technology developed for multithread operating systems. This technique virtualizes a computer architecture's various forms of computer data storage (such as random-access memory and disk storage), allowing a program to be designed as though there is only one kind of memory, &amp;quot;virtual&amp;quot; memory, which behaves like directly addressable read/write memory (RAM). &lt;br /&gt;
&lt;br /&gt;
[[Image:virtualM.PNG|thumbnail|right|200px|Virtual Memory in modern computer systems&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
This technique greatly simplifies programmers job because modern operating system runs each process on its own dedicated virtual memory space. Thus each program runs as if it has the sole access of the virtual memory. In this way, programmers don't have to worry about how operating system switches between processes or how other process operates. Also, Virtual memory makes application programming easier by hiding fragmentation of physical memory; by delegating to the kernel the burden of managing the memory hierarchy (eliminating the need for the program to handle overlays explicitly); and, when each process is run in its own dedicated address space, by obviating the need to relocate program code or to access memory with relative addressing.&lt;br /&gt;
&lt;br /&gt;
The introducing of virtual memory raise the problem of translating virtual address to physical address since we need physical address to access the actual content stored in cache. And that's where Translation Lookaside Buffer comes into use.&lt;br /&gt;
&lt;br /&gt;
=== What is TLB ===&lt;br /&gt;
&lt;br /&gt;
A TLB has a fixed number of slots that contain page table entries, which map virtual addresses to physical addresses. The virtual memory is the space seen from a process. This space is segmented in pages of a prefixed size. The page table (generally loaded in memory) keeps track of where the virtual pages are loaded in the physical memory. The TLB is a cache of the page table; that is, only a subset of its content are stored.&lt;br /&gt;
The TLB references physical memory addresses in its table. It may reside between the CPU and the CPU cache, between the CPU cache and primary storage memory, or between levels of a multi-level cache. The placement determines whether the cache uses physical or virtual addressing. If the cache is virtually addressed, requests are sent directly from the CPU to the cache, and the TLB is accessed only on a cache miss. If the cache is physically addressed, the CPU does a TLB lookup on every memory operation and the resulting physical address is sent to the cache. There are pros and cons to both implementations. Caches that use virtual addressing have for their key part of the virtual address plus, optionally, a key called an &amp;quot;address space identifier&amp;quot; (ASID). Caches that don't have ASIDs must be flushed every context switch in a multiprocessing environment.&lt;br /&gt;
In a Harvard architecture or hybrid thereof, a separate virtual address space or memory access hardware may exist for instructions and data. This can lead to distinct TLBs for each access type.&lt;br /&gt;
A common optimization for physically addressed caches is to perform the TLB lookup in parallel with the cache access. The low-order bits of any virtual address (e.g., in a virtual memory system having 4 KB pages, the lower 12 bits of the virtual address) represent the offset of the desired address within the page, and thus they do not change in the virtual-to-physical translation. During a cache access, two steps are performed: an index is used to find an entry in the cache's data store, and then the tags for the cache line found are compared. If the cache is structured in such a way that it can be indexed using only the bits that do not change in translation, the cache can perform its &amp;quot;index&amp;quot; operation while the TLB translates the upper bits of the address. Then, the translated address from the TLB is passed to the cache. The cache performs a tag comparison to determine if this access was a hit or miss. It is possible to perform the TLB lookup in parallel with the cache access even if the cache must be indexed using some bits that may change upon address translation; see the address translation section in the cache article for more details about virtual addressing as it pertains to caches and TLBs.&lt;br /&gt;
&lt;br /&gt;
[[Image:tlb.PNG|thumbnail|right|200px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And here is generally how a typical TLB is working. Note that X is the virtual page number to be translated into a physical page number, X' is the Physical number corresponding to X. and V is the Virtual page number of a victim page(that is a page to be kicked off the table). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:tlbOP.PNG|thumbnail|right|200px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next in this chapter we are going to discuss problems that are going to occur when we extend this TLB structure to multi-processor systems. The solution to these problems is presented in next chapter.&lt;br /&gt;
&lt;br /&gt;
=== TLB Coherence issues ===&lt;br /&gt;
&lt;br /&gt;
Problems occur when we extend TLB table into multi-processor systems. That is when memory is shared, two processors may have different virtual names for the same block. &lt;br /&gt;
&lt;br /&gt;
tlbCo.PNG&lt;br /&gt;
&lt;br /&gt;
This cause inconsistent loads and stores when more than one processors are trying to access the same blocks of data. &lt;br /&gt;
&lt;br /&gt;
For example, Assume:&lt;br /&gt;
* The processor has been running Process 1&lt;br /&gt;
* It then switches to Process 2&lt;br /&gt;
* Later it switches back to Process 1&lt;br /&gt;
&lt;br /&gt;
Now Process 2 caches a different copy of the information than Process 1. When Process 2 makes a change, that change is not reflected in Process 1's copy of the information.&lt;br /&gt;
&lt;br /&gt;
==Solutions==&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
In this section, we will talk about several solutions to handle TLB coherence problem. We will focus most on the last approach - TLB shootdown - a commonlly used software approach to enforce TLB coherence. Some other approaches will be briefly introduced. &lt;br /&gt;
&lt;br /&gt;
===Virtually addressed caches===&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
This method is to get rid of TLB. If we do not need TLB, we will not have the Coherence problem. &lt;br /&gt;
&lt;br /&gt;
When virtually addressed cache is used, address translations only happen when there is a cache miss. Since it is not frequently to access page mappings, we do not need to use TLB any more. Figure shows how virtually addressed cache works.&lt;br /&gt;
[[File:yw1.jpg|200px|thumb|right|procedure block of addressing cache&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The key distinction between virtually and physically addressed caches is that Virtually addressed caches are indexed using part of a virtual address rather than a physical address. Virtually addressed caches offer potentially faster access times by avoiding the delay associated with address translation. &amp;lt;ref&amp;gt;the effects of virtually addressed caches on virtual memory design and performance  JonInouye - et al.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Figure shows the organization of virtually addressed caches.&lt;br /&gt;
[[File:yw2.jpg|200px|thumb|right|Organization of Virtual Addressed Caches&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
From the figure “ASID” means “address-space identifier,” which is often called a process identifier (PID) in some books. The diagram shows the “V-index” overlapping the (virtual) page number. If not, we wouldn’t need a virtually addressed cache. We could do address translation in parallel with cache access with a physically addressed cache. Also the V-index actually does not stored in the cache. Like the index (“set” or “line”) field in physically addressed caches, it is not stored, but just tells what line or set to look in for the data&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Given the virtually addressed cache which can help us get rid of TLB, problems of coherent still exist to some level. Swap-out and protection information(read or read/write) coherent still need to be enforced. However, since there is no TLB, such information is stored in cache, the coherence problem will be handled by cache-coherence hardware.&lt;br /&gt;
&lt;br /&gt;
=== Invalidate instructions&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;===&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
Some processors, notably the PowerPC, have a “TLB_invalidate_entry” instruction.&lt;br /&gt;
&lt;br /&gt;
This instruction broadcasts the page address on the bus so that the snooping hardware on other processors can automatically invalidate the corresponding TLB entries without interrupting the processor.&lt;br /&gt;
&lt;br /&gt;
A processor simply issues a TLB_invalidate_entry instruction immediately after changing a page-table entry. This works well on a shared-bus system; if two processors change the same entry at the same time, only one change can be broadcast first on the bus.&lt;br /&gt;
&lt;br /&gt;
===TLB shootdown===&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
====General Concept====&lt;br /&gt;
TLB shootdown is another approach to enforce TLB coherence. It is a software approach using inter-processor interrupts. Also, it is a very common technique to enforce TLB coherence. How it works? In general, when a processor changes a TLB entry, it will make the other processors which contain the same TLB entries to invalidate their copies. A quick example as below may explain it more clearly.&lt;br /&gt;
&lt;br /&gt;
Assuming you have some memory shared by all of the processors in your system. One of your processors restricts access to a page of that shared memory now, all of the processors have to flush their TLBs, so that the ones that aren't allowed to access that page can't do so anymore.The actions of one processor causing the TLBs to be flushed on other processors is what is called a TLB shootdown&amp;lt;ref&amp;gt;http://stackoverflow.com/questions/3748384/what-is-tlb-shootdown&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Detailed Steps====&lt;br /&gt;
Some steps are needed to implement this approach.&amp;lt;ref&amp;gt;lec15 from NCSU ECE506&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Step 1.  A processor p that wants to modify a page table disables inter-processor interrupts and locks the page table.  It also clears its active flag, which indicates whether it is actively using any page table.&lt;br /&gt;
Step 2.  Processor p sends an interrupt to other processors that might be using the page table, describing the TLB actions to be performed.&lt;br /&gt;
Step 3.  Each processor that receives the interrupt clears its active flag.&lt;br /&gt;
Step 4.  Processor p busy-waits till the active flags of all interrupted processors are clear, then modifies the page table.  Processor p then releases the page-table lock, sets its active flag, and resumes execution.&lt;br /&gt;
Step 5.  Each interrupted processor busy-waits until none of the page tables it is using are locked.  After executing the required TLB actions and setting its active flag, it resumes execution.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
An example of TLB shootdown solution is the one described in Mach VM System. In this module, when an action may potentially cause TLB inconsistency, it will invoke the shootdown algorithm. The algorithm proceeds in four phases after it is invoked&amp;lt;ref&amp;gt;Translation Look aside Buffer Consistency: A Software Approach, David L. Black - et al. 1989&amp;lt;/ref&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
1 Initiator: The initiator queues consistency action  requests for all processors using the pmap  and sets their “action  needed” flags. It then sends interrupts to the processors and waits for responses. &lt;br /&gt;
2 Responders: Each responder receives its interrupt and removes itself from the set of active processors to acknowledge the interrupt. The responders then spin until  the  initiator completes its changes to pmap. (This  spinning  is  necessary  to ensure  that  responders  neither read nor write the pmap while the  update  is  in  progress.) &lt;br /&gt;
3 Initiator: The initiator performs its pmap changes after all responders using the pmap are spinning. It unlocks the  pmap when it is done. &lt;br /&gt;
4 Responders: The responders perform their required TLB invalidations after the pmap is unlocked and dequeue the corresponding actions. They also clear their “action needed” flags and rejoin the set of active processors.&lt;br /&gt;
&lt;br /&gt;
The Pseudo-Code of Mach Shootdown Algorithm is as below&amp;lt;ref&amp;gt;Translation Look aside Buffer Consistency: A Software Approach, David L. Black - et al. 1989&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Initiator: &lt;br /&gt;
s  =  disable_interrupts(); &lt;br /&gt;
active[mycpul  =  FALSE; &lt;br /&gt;
lockgmap(pmap); &lt;br /&gt;
if  (inconsistent  TLB  may  result) { &lt;br /&gt;
	if  (pmap-&amp;gt;in-uselmycpul)  { &lt;br /&gt;
	invalidate-tlb(pmap,start,end); &lt;br /&gt;
	}&lt;br /&gt;
	/*  Phase  1  */ &lt;br /&gt;
	if  (other  cpus  using  pmap)  {&lt;br /&gt;
		list_type  shoot-list  =  EMPTY-LIST; &lt;br /&gt;
		for  (every  cpu  in  system)  {&lt;br /&gt;
			if  (pmap-&amp;gt;in-uselcpul  &amp;amp;&amp;amp; cpu  !=  mycpu) {&lt;br /&gt;
				lock-action-structure(cpu): &lt;br /&gt;
				queue_action(cpu,pmap,start,end); &lt;br /&gt;
				action-neededlcpul  =  TRUE; &lt;br /&gt;
				unlock-action-structure(cpu); &lt;br /&gt;
				if  (idle[cpul  ==  FALSE)  { &lt;br /&gt;
					add  cpu  to  shoot-list &lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	for  (every  cpu  on  shoot-list)  { &lt;br /&gt;
		send-shootdown-interrupt(cpu); &lt;br /&gt;
	}&lt;br /&gt;
	for  (every  cpu  on  shoot-list)  { &lt;br /&gt;
		while  (activelcpul  &amp;amp;&amp;amp; pmap-&amp;gt;in-uselcpul)  {&lt;br /&gt;
			pmap-&amp;gt;in_use[cpu]){&lt;br /&gt;
			/*  spin  */  ; &lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}	&lt;br /&gt;
	&lt;br /&gt;
/*  Phase  3  */ &lt;br /&gt;
make  changes  to  physical  map &lt;br /&gt;
&lt;br /&gt;
unlock-pmap(pmap); &lt;br /&gt;
active[mycpu]  =  TRUE; &lt;br /&gt;
restore-interrupt-state(s); &lt;br /&gt;
&lt;br /&gt;
Responders:  /*  Phase  2  */ &lt;br /&gt;
s  =  disable-interrupts(); &lt;br /&gt;
	while  (action-needed[mycpu])  {&lt;br /&gt;
		active[mycpu]  =  FALSE; &lt;br /&gt;
		while  (pmap  is  locked(kernel-pmap)  &amp;amp;&amp;amp; pmapIisIlocked(user-pmap(mycpu))) &lt;br /&gt;
		/*  spin  */  ; &lt;br /&gt;
		&lt;br /&gt;
	/*  Phase  4  */ &lt;br /&gt;
	lock-action-structure(mycpu); &lt;br /&gt;
	process-queuedactions(mycpu); &lt;br /&gt;
	action-neededlmycpul  =  FALSE; &lt;br /&gt;
	unlock-action-structure(mycpu); &lt;br /&gt;
	active[mycpu]  =  TRUE; &lt;br /&gt;
}&lt;br /&gt;
restore-interrupt-state(s); &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Performance Analysis====&lt;br /&gt;
Apparently, as number of processors increases, the overhead of this approach scales linearly. Because number of interprocessors interrupts invoked will be O(n) to the number of processors. &lt;br /&gt;
&lt;br /&gt;
Figure indicates the latency increases linearly as number of cores goes up.[[File:yw3.jpg|200px|thumb|right|TLB shootdown latency &amp;lt;ref&amp;gt;UNified Instruction/Translation/Data (UNITD) Coherence: One Protocol to Rule Them All - Bogdan F. Romanescu et al.&amp;lt;/ref&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
===Some Other Approaches&amp;lt;ref&amp;gt;Translation-Lookaside Buffer Consistency Patricia J. Teller - et al.&amp;lt;/ref&amp;gt;===&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
1. Modified TLB shootdown&lt;br /&gt;
Overhead is the same as for TLB shootdown with two exceptions: Interrupted processors are not idled, and their participation is small and possibly constant. Page-table modification and use are not serialized.&lt;br /&gt;
&lt;br /&gt;
2. Lazy devaluation&lt;br /&gt;
The counter is updated on each TLB reload, invalidation, and replacement. When an unsafe change cannot be postponed, overhead is the same as for TLB shootdown.&lt;br /&gt;
&lt;br /&gt;
3. Validation&lt;br /&gt;
Memory requests contain a generation count. The modifying processor updates the generation count. An extra network trip is needed when a stale TLB entry is used. Overhead also includes a solution to the generation-count wraparound problem.&lt;br /&gt;
&lt;br /&gt;
==Summary==&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
The main goal of multiprocessor is to increase the execution speed. While enforcing the TLB coherent, we should well understand the trade-off of different approaches. Some of the approaches require specific hardware and others(like shootdown) don't. Actually, in real design, it is difficult to conclude which solution will be better, it all depends on what applications running in what kind of environment.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Quiz==&lt;br /&gt;
--------------------------------------------------------------&lt;br /&gt;
1.  Which below is(are) solution(s) to TLB coherence problem &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. MESI protocol&amp;lt;br /&amp;gt;&lt;br /&gt;
	B. TLB shootdown&amp;lt;br /&amp;gt;&lt;br /&gt;
	C. using virtually addressed cache&amp;lt;br /&amp;gt;&lt;br /&gt;
	D. all of above&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2.  which is(are) true below &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. TLB shootdown is a software approach&amp;lt;br /&amp;gt;&lt;br /&gt;
	B. using virually addressed cache will decrease cache misses&amp;lt;br /&amp;gt;&lt;br /&gt;
	C. PowerPC has a unique instruction to handle TLB coherence problem&amp;lt;br /&amp;gt;&lt;br /&gt;
	D. TLB is shared by different processors&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3.  what is(are) step(s) of TLB shootdown &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. Locks the page table&amp;lt;br /&amp;gt;&lt;br /&gt;
	B. Busy-wait the other processors to inactivate the flags&amp;lt;br /&amp;gt;&lt;br /&gt;
	C. Send interrupt signal&amp;lt;br /&amp;gt;&lt;br /&gt;
	D. Release Locks&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4.	Which is(are) incorrect about virtually addressed caches &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. It can be used to decrease the frequency to access map table &amp;lt;br /&amp;gt;&lt;br /&gt;
	B. It can only addressed by virtual address &amp;lt;br /&amp;gt;&lt;br /&gt;
	C. V-index should overlap the page number &amp;lt;br /&amp;gt;&lt;br /&gt;
	D. V-index number is stored in the cache &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Which is the correct order of phases in shootdown algorithm &amp;lt;br /&amp;gt;&lt;br /&gt;
	A. responders initiators responders initiators &amp;lt;br /&amp;gt;&lt;br /&gt;
	B. initiators initiators responders responders &amp;lt;br /&amp;gt;&lt;br /&gt;
	C. initiators responders initiators responders &amp;lt;br /&amp;gt;&lt;br /&gt;
	D. responders responders initiators initiators&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59738</id>
		<title>CSC/ECE 506 Spring 2012/7b yw</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59738"/>
		<updated>2012-03-18T22:10:43Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* What is TLB */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addressed caches are discussed. Then we discuss the need for TLB, a cache-like construct that translate virtual address to physical address. Then we raise the issue of TLB coherence. &lt;br /&gt;
&lt;br /&gt;
=== Virtually addressed caches ===&lt;br /&gt;
&lt;br /&gt;
Virtual memory is a memory management technology developed for multithread operating systems. This technique virtualizes a computer architecture's various forms of computer data storage (such as random-access memory and disk storage), allowing a program to be designed as though there is only one kind of memory, &amp;quot;virtual&amp;quot; memory, which behaves like directly addressable read/write memory (RAM). &lt;br /&gt;
&lt;br /&gt;
[[Image:virtualM.PNG|thumbnail|right|600px|Virtual Memory in modern computer systems&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
This technique greatly simplifies programmers job because modern operating system runs each process on its own dedicated virtual memory space. Thus each program runs as if it has the sole access of the virtual memory. In this way, programmers don't have to worry about how operating system switches between processes or how other process operates. Also, Virtual memory makes application programming easier by hiding fragmentation of physical memory; by delegating to the kernel the burden of managing the memory hierarchy (eliminating the need for the program to handle overlays explicitly); and, when each process is run in its own dedicated address space, by obviating the need to relocate program code or to access memory with relative addressing.&lt;br /&gt;
&lt;br /&gt;
The introducing of virtual memory raise the problem of translating virtual address to physical address since we need physical address to access the actual content stored in cache. And that's where Translation Lookaside Buffer comes into use.&lt;br /&gt;
&lt;br /&gt;
=== What is TLB ===&lt;br /&gt;
&lt;br /&gt;
A TLB has a fixed number of slots that contain page table entries, which map virtual addresses to physical addresses. The virtual memory is the space seen from a process. This space is segmented in pages of a prefixed size. The page table (generally loaded in memory) keeps track of where the virtual pages are loaded in the physical memory. The TLB is a cache of the page table; that is, only a subset of its content are stored.&lt;br /&gt;
The TLB references physical memory addresses in its table. It may reside between the CPU and the CPU cache, between the CPU cache and primary storage memory, or between levels of a multi-level cache. The placement determines whether the cache uses physical or virtual addressing. If the cache is virtually addressed, requests are sent directly from the CPU to the cache, and the TLB is accessed only on a cache miss. If the cache is physically addressed, the CPU does a TLB lookup on every memory operation and the resulting physical address is sent to the cache. There are pros and cons to both implementations. Caches that use virtual addressing have for their key part of the virtual address plus, optionally, a key called an &amp;quot;address space identifier&amp;quot; (ASID). Caches that don't have ASIDs must be flushed every context switch in a multiprocessing environment.&lt;br /&gt;
In a Harvard architecture or hybrid thereof, a separate virtual address space or memory access hardware may exist for instructions and data. This can lead to distinct TLBs for each access type.&lt;br /&gt;
A common optimization for physically addressed caches is to perform the TLB lookup in parallel with the cache access. The low-order bits of any virtual address (e.g., in a virtual memory system having 4 KB pages, the lower 12 bits of the virtual address) represent the offset of the desired address within the page, and thus they do not change in the virtual-to-physical translation. During a cache access, two steps are performed: an index is used to find an entry in the cache's data store, and then the tags for the cache line found are compared. If the cache is structured in such a way that it can be indexed using only the bits that do not change in translation, the cache can perform its &amp;quot;index&amp;quot; operation while the TLB translates the upper bits of the address. Then, the translated address from the TLB is passed to the cache. The cache performs a tag comparison to determine if this access was a hit or miss. It is possible to perform the TLB lookup in parallel with the cache access even if the cache must be indexed using some bits that may change upon address translation; see the address translation section in the cache article for more details about virtual addressing as it pertains to caches and TLBs.&lt;br /&gt;
&lt;br /&gt;
[[Image:tlb.PNG|thumbnail|right|600px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And here is generally how a typical TLB is working. Note that X is the virtual page number to be translated into a physical page number, X' is the Physical number corresponding to X. and V is the Virtual page number of a victim page(that is a page to be kicked off the table). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:tlbOP.PNG|thumbnail|right|600px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next in this chapter we are going to discuss problems that are going to occur when we extend this TLB structure to multi-processor systems. The solution to these problems is presented in next chapter.&lt;br /&gt;
&lt;br /&gt;
=== TLB Coherence issues ===&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59737</id>
		<title>CSC/ECE 506 Spring 2012/7b yw</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59737"/>
		<updated>2012-03-18T22:10:26Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* What is TLB */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addressed caches are discussed. Then we discuss the need for TLB, a cache-like construct that translate virtual address to physical address. Then we raise the issue of TLB coherence. &lt;br /&gt;
&lt;br /&gt;
=== Virtually addressed caches ===&lt;br /&gt;
&lt;br /&gt;
Virtual memory is a memory management technology developed for multithread operating systems. This technique virtualizes a computer architecture's various forms of computer data storage (such as random-access memory and disk storage), allowing a program to be designed as though there is only one kind of memory, &amp;quot;virtual&amp;quot; memory, which behaves like directly addressable read/write memory (RAM). &lt;br /&gt;
&lt;br /&gt;
[[Image:virtualM.PNG|thumbnail|right|600px|Virtual Memory in modern computer systems&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
This technique greatly simplifies programmers job because modern operating system runs each process on its own dedicated virtual memory space. Thus each program runs as if it has the sole access of the virtual memory. In this way, programmers don't have to worry about how operating system switches between processes or how other process operates. Also, Virtual memory makes application programming easier by hiding fragmentation of physical memory; by delegating to the kernel the burden of managing the memory hierarchy (eliminating the need for the program to handle overlays explicitly); and, when each process is run in its own dedicated address space, by obviating the need to relocate program code or to access memory with relative addressing.&lt;br /&gt;
&lt;br /&gt;
The introducing of virtual memory raise the problem of translating virtual address to physical address since we need physical address to access the actual content stored in cache. And that's where Translation Lookaside Buffer comes into use.&lt;br /&gt;
&lt;br /&gt;
=== What is TLB ===&lt;br /&gt;
&lt;br /&gt;
A TLB has a fixed number of slots that contain page table entries, which map virtual addresses to physical addresses. The virtual memory is the space seen from a process. This space is segmented in pages of a prefixed size. The page table (generally loaded in memory) keeps track of where the virtual pages are loaded in the physical memory. The TLB is a cache of the page table; that is, only a subset of its content are stored.&lt;br /&gt;
The TLB references physical memory addresses in its table. It may reside between the CPU and the CPU cache, between the CPU cache and primary storage memory, or between levels of a multi-level cache. The placement determines whether the cache uses physical or virtual addressing. If the cache is virtually addressed, requests are sent directly from the CPU to the cache, and the TLB is accessed only on a cache miss. If the cache is physically addressed, the CPU does a TLB lookup on every memory operation and the resulting physical address is sent to the cache. There are pros and cons to both implementations. Caches that use virtual addressing have for their key part of the virtual address plus, optionally, a key called an &amp;quot;address space identifier&amp;quot; (ASID). Caches that don't have ASIDs must be flushed every context switch in a multiprocessing environment.&lt;br /&gt;
In a Harvard architecture or hybrid thereof, a separate virtual address space or memory access hardware may exist for instructions and data. This can lead to distinct TLBs for each access type.&lt;br /&gt;
A common optimization for physically addressed caches is to perform the TLB lookup in parallel with the cache access. The low-order bits of any virtual address (e.g., in a virtual memory system having 4 KB pages, the lower 12 bits of the virtual address) represent the offset of the desired address within the page, and thus they do not change in the virtual-to-physical translation. During a cache access, two steps are performed: an index is used to find an entry in the cache's data store, and then the tags for the cache line found are compared. If the cache is structured in such a way that it can be indexed using only the bits that do not change in translation, the cache can perform its &amp;quot;index&amp;quot; operation while the TLB translates the upper bits of the address. Then, the translated address from the TLB is passed to the cache. The cache performs a tag comparison to determine if this access was a hit or miss. It is possible to perform the TLB lookup in parallel with the cache access even if the cache must be indexed using some bits that may change upon address translation; see the address translation section in the cache article for more details about virtual addressing as it pertains to caches and TLBs.&lt;br /&gt;
&lt;br /&gt;
[[Image:tlb.PNG|thumbnail|right|300px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And here is generally how a typical TLB is working. Note that X is the virtual page number to be translated into a physical page number, X' is the Physical number corresponding to X. and V is the Virtual page number of a victim page(that is a page to be kicked off the table). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:tlbOP.PNG|thumbnail|right|600px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next in this chapter we are going to discuss problems that are going to occur when we extend this TLB structure to multi-processor systems. The solution to these problems is presented in next chapter.&lt;br /&gt;
&lt;br /&gt;
=== TLB Coherence issues ===&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59736</id>
		<title>CSC/ECE 506 Spring 2012/7b yw</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59736"/>
		<updated>2012-03-18T22:09:39Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* What is TLB */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addressed caches are discussed. Then we discuss the need for TLB, a cache-like construct that translate virtual address to physical address. Then we raise the issue of TLB coherence. &lt;br /&gt;
&lt;br /&gt;
=== Virtually addressed caches ===&lt;br /&gt;
&lt;br /&gt;
Virtual memory is a memory management technology developed for multithread operating systems. This technique virtualizes a computer architecture's various forms of computer data storage (such as random-access memory and disk storage), allowing a program to be designed as though there is only one kind of memory, &amp;quot;virtual&amp;quot; memory, which behaves like directly addressable read/write memory (RAM). &lt;br /&gt;
&lt;br /&gt;
[[Image:virtualM.PNG|thumbnail|right|600px|Virtual Memory in modern computer systems&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
This technique greatly simplifies programmers job because modern operating system runs each process on its own dedicated virtual memory space. Thus each program runs as if it has the sole access of the virtual memory. In this way, programmers don't have to worry about how operating system switches between processes or how other process operates. Also, Virtual memory makes application programming easier by hiding fragmentation of physical memory; by delegating to the kernel the burden of managing the memory hierarchy (eliminating the need for the program to handle overlays explicitly); and, when each process is run in its own dedicated address space, by obviating the need to relocate program code or to access memory with relative addressing.&lt;br /&gt;
&lt;br /&gt;
The introducing of virtual memory raise the problem of translating virtual address to physical address since we need physical address to access the actual content stored in cache. And that's where Translation Lookaside Buffer comes into use.&lt;br /&gt;
&lt;br /&gt;
=== What is TLB ===&lt;br /&gt;
&lt;br /&gt;
A TLB has a fixed number of slots that contain page table entries, which map virtual addresses to physical addresses. The virtual memory is the space seen from a process. This space is segmented in pages of a prefixed size. The page table (generally loaded in memory) keeps track of where the virtual pages are loaded in the physical memory. The TLB is a cache of the page table; that is, only a subset of its content are stored.&lt;br /&gt;
The TLB references physical memory addresses in its table. It may reside between the CPU and the CPU cache, between the CPU cache and primary storage memory, or between levels of a multi-level cache. The placement determines whether the cache uses physical or virtual addressing. If the cache is virtually addressed, requests are sent directly from the CPU to the cache, and the TLB is accessed only on a cache miss. If the cache is physically addressed, the CPU does a TLB lookup on every memory operation and the resulting physical address is sent to the cache. There are pros and cons to both implementations. Caches that use virtual addressing have for their key part of the virtual address plus, optionally, a key called an &amp;quot;address space identifier&amp;quot; (ASID). Caches that don't have ASIDs must be flushed every context switch in a multiprocessing environment.&lt;br /&gt;
In a Harvard architecture or hybrid thereof, a separate virtual address space or memory access hardware may exist for instructions and data. This can lead to distinct TLBs for each access type.&lt;br /&gt;
A common optimization for physically addressed caches is to perform the TLB lookup in parallel with the cache access. The low-order bits of any virtual address (e.g., in a virtual memory system having 4 KB pages, the lower 12 bits of the virtual address) represent the offset of the desired address within the page, and thus they do not change in the virtual-to-physical translation. During a cache access, two steps are performed: an index is used to find an entry in the cache's data store, and then the tags for the cache line found are compared. If the cache is structured in such a way that it can be indexed using only the bits that do not change in translation, the cache can perform its &amp;quot;index&amp;quot; operation while the TLB translates the upper bits of the address. Then, the translated address from the TLB is passed to the cache. The cache performs a tag comparison to determine if this access was a hit or miss. It is possible to perform the TLB lookup in parallel with the cache access even if the cache must be indexed using some bits that may change upon address translation; see the address translation section in the cache article for more details about virtual addressing as it pertains to caches and TLBs.&lt;br /&gt;
&lt;br /&gt;
[[Image:tlb.PNG|thumbnail|middle|600px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And here is generally how a typical TLB is working. Note that X is the virtual page number to be translated into a physical page number, X' is the Physical number corresponding to X. and V is the Virtual page number of a victim page(that is a page to be kicked off the table). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:tlbOP.PNG|thumbnail|right|600px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next in this chapter we are going to discuss problems that are going to occur when we extend this TLB structure to multi-processor systems. The solution to these problems is presented in next chapter.&lt;br /&gt;
&lt;br /&gt;
=== TLB Coherence issues ===&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59735</id>
		<title>CSC/ECE 506 Spring 2012/7b yw</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59735"/>
		<updated>2012-03-18T22:06:48Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* What is TLB */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addressed caches are discussed. Then we discuss the need for TLB, a cache-like construct that translate virtual address to physical address. Then we raise the issue of TLB coherence. &lt;br /&gt;
&lt;br /&gt;
=== Virtually addressed caches ===&lt;br /&gt;
&lt;br /&gt;
Virtual memory is a memory management technology developed for multithread operating systems. This technique virtualizes a computer architecture's various forms of computer data storage (such as random-access memory and disk storage), allowing a program to be designed as though there is only one kind of memory, &amp;quot;virtual&amp;quot; memory, which behaves like directly addressable read/write memory (RAM). &lt;br /&gt;
&lt;br /&gt;
[[Image:virtualM.PNG|thumbnail|right|600px|Virtual Memory in modern computer systems&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
This technique greatly simplifies programmers job because modern operating system runs each process on its own dedicated virtual memory space. Thus each program runs as if it has the sole access of the virtual memory. In this way, programmers don't have to worry about how operating system switches between processes or how other process operates. Also, Virtual memory makes application programming easier by hiding fragmentation of physical memory; by delegating to the kernel the burden of managing the memory hierarchy (eliminating the need for the program to handle overlays explicitly); and, when each process is run in its own dedicated address space, by obviating the need to relocate program code or to access memory with relative addressing.&lt;br /&gt;
&lt;br /&gt;
The introducing of virtual memory raise the problem of translating virtual address to physical address since we need physical address to access the actual content stored in cache. And that's where Translation Lookaside Buffer comes into use.&lt;br /&gt;
&lt;br /&gt;
=== What is TLB ===&lt;br /&gt;
&lt;br /&gt;
A TLB has a fixed number of slots that contain page table entries, which map virtual addresses to physical addresses. The virtual memory is the space seen from a process. This space is segmented in pages of a prefixed size. The page table (generally loaded in memory) keeps track of where the virtual pages are loaded in the physical memory. The TLB is a cache of the page table; that is, only a subset of its content are stored.&lt;br /&gt;
The TLB references physical memory addresses in its table. It may reside between the CPU and the CPU cache, between the CPU cache and primary storage memory, or between levels of a multi-level cache. The placement determines whether the cache uses physical or virtual addressing. If the cache is virtually addressed, requests are sent directly from the CPU to the cache, and the TLB is accessed only on a cache miss. If the cache is physically addressed, the CPU does a TLB lookup on every memory operation and the resulting physical address is sent to the cache. There are pros and cons to both implementations. Caches that use virtual addressing have for their key part of the virtual address plus, optionally, a key called an &amp;quot;address space identifier&amp;quot; (ASID). Caches that don't have ASIDs must be flushed every context switch in a multiprocessing environment.&lt;br /&gt;
In a Harvard architecture or hybrid thereof, a separate virtual address space or memory access hardware may exist for instructions and data. This can lead to distinct TLBs for each access type.&lt;br /&gt;
A common optimization for physically addressed caches is to perform the TLB lookup in parallel with the cache access. The low-order bits of any virtual address (e.g., in a virtual memory system having 4 KB pages, the lower 12 bits of the virtual address) represent the offset of the desired address within the page, and thus they do not change in the virtual-to-physical translation. During a cache access, two steps are performed: an index is used to find an entry in the cache's data store, and then the tags for the cache line found are compared. If the cache is structured in such a way that it can be indexed using only the bits that do not change in translation, the cache can perform its &amp;quot;index&amp;quot; operation while the TLB translates the upper bits of the address. Then, the translated address from the TLB is passed to the cache. The cache performs a tag comparison to determine if this access was a hit or miss. It is possible to perform the TLB lookup in parallel with the cache access even if the cache must be indexed using some bits that may change upon address translation; see the address translation section in the cache article for more details about virtual addressing as it pertains to caches and TLBs.&lt;br /&gt;
&lt;br /&gt;
[[Image:tlb.PNG|thumbnail|right|600px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And here is generally how a typical TLB is working. Note that X is the virtual page number to be translated into a physical page number, X' is the Physical number corresponding to X. and V is the Virtual page number of a victim page(that is a page to be kicked off the table). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:tlbOP.PNG|thumbnail|right|600px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next in this chapter we are going to discuss problems that are going to occur when we extend this TLB structure to multi-processor systems. The solution to these problems is presented in next chapter.&lt;br /&gt;
&lt;br /&gt;
=== TLB Coherence issues ===&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59734</id>
		<title>CSC/ECE 506 Spring 2012/7b yw</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59734"/>
		<updated>2012-03-18T22:05:43Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* What is TLB */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addressed caches are discussed. Then we discuss the need for TLB, a cache-like construct that translate virtual address to physical address. Then we raise the issue of TLB coherence. &lt;br /&gt;
&lt;br /&gt;
=== Virtually addressed caches ===&lt;br /&gt;
&lt;br /&gt;
Virtual memory is a memory management technology developed for multithread operating systems. This technique virtualizes a computer architecture's various forms of computer data storage (such as random-access memory and disk storage), allowing a program to be designed as though there is only one kind of memory, &amp;quot;virtual&amp;quot; memory, which behaves like directly addressable read/write memory (RAM). &lt;br /&gt;
&lt;br /&gt;
[[Image:virtualM.PNG|thumbnail|right|600px|Virtual Memory in modern computer systems&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
This technique greatly simplifies programmers job because modern operating system runs each process on its own dedicated virtual memory space. Thus each program runs as if it has the sole access of the virtual memory. In this way, programmers don't have to worry about how operating system switches between processes or how other process operates. Also, Virtual memory makes application programming easier by hiding fragmentation of physical memory; by delegating to the kernel the burden of managing the memory hierarchy (eliminating the need for the program to handle overlays explicitly); and, when each process is run in its own dedicated address space, by obviating the need to relocate program code or to access memory with relative addressing.&lt;br /&gt;
&lt;br /&gt;
The introducing of virtual memory raise the problem of translating virtual address to physical address since we need physical address to access the actual content stored in cache. And that's where Translation Lookaside Buffer comes into use.&lt;br /&gt;
&lt;br /&gt;
=== What is TLB ===&lt;br /&gt;
&lt;br /&gt;
A TLB has a fixed number of slots that contain page table entries, which map virtual addresses to physical addresses. The virtual memory is the space seen from a process. This space is segmented in pages of a prefixed size. The page table (generally loaded in memory) keeps track of where the virtual pages are loaded in the physical memory. The TLB is a cache of the page table; that is, only a subset of its content are stored.&lt;br /&gt;
The TLB references physical memory addresses in its table. It may reside between the CPU and the CPU cache, between the CPU cache and primary storage memory, or between levels of a multi-level cache. The placement determines whether the cache uses physical or virtual addressing. If the cache is virtually addressed, requests are sent directly from the CPU to the cache, and the TLB is accessed only on a cache miss. If the cache is physically addressed, the CPU does a TLB lookup on every memory operation and the resulting physical address is sent to the cache. There are pros and cons to both implementations. Caches that use virtual addressing have for their key part of the virtual address plus, optionally, a key called an &amp;quot;address space identifier&amp;quot; (ASID). Caches that don't have ASIDs must be flushed every context switch in a multiprocessing environment.&lt;br /&gt;
In a Harvard architecture or hybrid thereof, a separate virtual address space or memory access hardware may exist for instructions and data. This can lead to distinct TLBs for each access type.&lt;br /&gt;
A common optimization for physically addressed caches is to perform the TLB lookup in parallel with the cache access. The low-order bits of any virtual address (e.g., in a virtual memory system having 4 KB pages, the lower 12 bits of the virtual address) represent the offset of the desired address within the page, and thus they do not change in the virtual-to-physical translation. During a cache access, two steps are performed: an index is used to find an entry in the cache's data store, and then the tags for the cache line found are compared. If the cache is structured in such a way that it can be indexed using only the bits that do not change in translation, the cache can perform its &amp;quot;index&amp;quot; operation while the TLB translates the upper bits of the address. Then, the translated address from the TLB is passed to the cache. The cache performs a tag comparison to determine if this access was a hit or miss. It is possible to perform the TLB lookup in parallel with the cache access even if the cache must be indexed using some bits that may change upon address translation; see the address translation section in the cache article for more details about virtual addressing as it pertains to caches and TLBs.&lt;br /&gt;
&lt;br /&gt;
[[Image:tlb.PNG|thumbnail|right|600px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
And here is generally how a typical TLB is working. Note that X is the virtual page number to be translated into a physical page number, X' is the Physical number corresponding to X. and V is the Virtual page number of a victim page(that is a page to be kicked off the table). &lt;br /&gt;
&lt;br /&gt;
[[Image:tlbOP.PNG|thumbnail|right|600px|Translation Lookaside Buffer&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
Next in this chapter we are going to discuss problems that are going to occur when we extend this TLB structure to multi-processor systems. The solution to these problems is presented in next chapter.&lt;br /&gt;
&lt;br /&gt;
=== TLB Coherence issues ===&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59733</id>
		<title>CSC/ECE 506 Spring 2012/7b yw</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59733"/>
		<updated>2012-03-18T22:04:14Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* Virtually addressed caches */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addressed caches are discussed. Then we discuss the need for TLB, a cache-like construct that translate virtual address to physical address. Then we raise the issue of TLB coherence. &lt;br /&gt;
&lt;br /&gt;
=== Virtually addressed caches ===&lt;br /&gt;
&lt;br /&gt;
Virtual memory is a memory management technology developed for multithread operating systems. This technique virtualizes a computer architecture's various forms of computer data storage (such as random-access memory and disk storage), allowing a program to be designed as though there is only one kind of memory, &amp;quot;virtual&amp;quot; memory, which behaves like directly addressable read/write memory (RAM). &lt;br /&gt;
&lt;br /&gt;
[[Image:virtualM.PNG|thumbnail|right|600px|Virtual Memory in modern computer systems&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
This technique greatly simplifies programmers job because modern operating system runs each process on its own dedicated virtual memory space. Thus each program runs as if it has the sole access of the virtual memory. In this way, programmers don't have to worry about how operating system switches between processes or how other process operates. Also, Virtual memory makes application programming easier by hiding fragmentation of physical memory; by delegating to the kernel the burden of managing the memory hierarchy (eliminating the need for the program to handle overlays explicitly); and, when each process is run in its own dedicated address space, by obviating the need to relocate program code or to access memory with relative addressing.&lt;br /&gt;
&lt;br /&gt;
The introducing of virtual memory raise the problem of translating virtual address to physical address since we need physical address to access the actual content stored in cache. And that's where Translation Lookaside Buffer comes into use.&lt;br /&gt;
&lt;br /&gt;
=== What is TLB ===&lt;br /&gt;
&lt;br /&gt;
A TLB has a fixed number of slots that contain page table entries, which map virtual addresses to physical addresses. The virtual memory is the space seen from a process. This space is segmented in pages of a prefixed size. The page table (generally loaded in memory) keeps track of where the virtual pages are loaded in the physical memory. The TLB is a cache of the page table; that is, only a subset of its content are stored.&lt;br /&gt;
The TLB references physical memory addresses in its table. It may reside between the CPU and the CPU cache, between the CPU cache and primary storage memory, or between levels of a multi-level cache. The placement determines whether the cache uses physical or virtual addressing. If the cache is virtually addressed, requests are sent directly from the CPU to the cache, and the TLB is accessed only on a cache miss. If the cache is physically addressed, the CPU does a TLB lookup on every memory operation and the resulting physical address is sent to the cache. There are pros and cons to both implementations. Caches that use virtual addressing have for their key part of the virtual address plus, optionally, a key called an &amp;quot;address space identifier&amp;quot; (ASID). Caches that don't have ASIDs must be flushed every context switch in a multiprocessing environment.&lt;br /&gt;
In a Harvard architecture or hybrid thereof, a separate virtual address space or memory access hardware may exist for instructions and data. This can lead to distinct TLBs for each access type.&lt;br /&gt;
A common optimization for physically addressed caches is to perform the TLB lookup in parallel with the cache access. The low-order bits of any virtual address (e.g., in a virtual memory system having 4 KB pages, the lower 12 bits of the virtual address) represent the offset of the desired address within the page, and thus they do not change in the virtual-to-physical translation. During a cache access, two steps are performed: an index is used to find an entry in the cache's data store, and then the tags for the cache line found are compared. If the cache is structured in such a way that it can be indexed using only the bits that do not change in translation, the cache can perform its &amp;quot;index&amp;quot; operation while the TLB translates the upper bits of the address. Then, the translated address from the TLB is passed to the cache. The cache performs a tag comparison to determine if this access was a hit or miss. It is possible to perform the TLB lookup in parallel with the cache access even if the cache must be indexed using some bits that may change upon address translation; see the address translation section in the cache article for more details about virtual addressing as it pertains to caches and TLBs.&lt;br /&gt;
&lt;br /&gt;
tlb.PNG&lt;br /&gt;
&lt;br /&gt;
And here is generally how a typical TLB is working. Note that X is the virtual page number to be translated into a physical page number, X' is the Physical number corresponding to X. and V is the Virtual page number of a victim page(that is a page to be kicked off the table). &lt;br /&gt;
&lt;br /&gt;
tlbOP.PNG&lt;br /&gt;
&lt;br /&gt;
Next in this chapter we are going to discuss problems that are going to occur when we extend this TLB structure to multi-processor systems. The solution to these problems is presented in next chapter.&lt;br /&gt;
&lt;br /&gt;
=== TLB Coherence issues ===&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59732</id>
		<title>CSC/ECE 506 Spring 2012/7b yw</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59732"/>
		<updated>2012-03-18T22:03:51Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* Virtually addressed caches */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addressed caches are discussed. Then we discuss the need for TLB, a cache-like construct that translate virtual address to physical address. Then we raise the issue of TLB coherence. &lt;br /&gt;
&lt;br /&gt;
=== Virtually addressed caches ===&lt;br /&gt;
&lt;br /&gt;
Virtual memory is a memory management technology developed for multithread operating systems. This technique virtualizes a computer architecture's various forms of computer data storage (such as random-access memory and disk storage), allowing a program to be designed as though there is only one kind of memory, &amp;quot;virtual&amp;quot; memory, which behaves like directly addressable read/write memory (RAM). &lt;br /&gt;
&lt;br /&gt;
virtualM.png&lt;br /&gt;
[[Image:virtualM.PNG|thumbnail|right|600px|Virtual Memory in modern computer systems&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
This technique greatly simplifies programmers job because modern operating system runs each process on its own dedicated virtual memory space. Thus each program runs as if it has the sole access of the virtual memory. In this way, programmers don't have to worry about how operating system switches between processes or how other process operates. Also, Virtual memory makes application programming easier by hiding fragmentation of physical memory; by delegating to the kernel the burden of managing the memory hierarchy (eliminating the need for the program to handle overlays explicitly); and, when each process is run in its own dedicated address space, by obviating the need to relocate program code or to access memory with relative addressing.&lt;br /&gt;
&lt;br /&gt;
The introducing of virtual memory raise the problem of translating virtual address to physical address since we need physical address to access the actual content stored in cache. And that's where Translation Lookaside Buffer comes into use.&lt;br /&gt;
&lt;br /&gt;
=== What is TLB ===&lt;br /&gt;
&lt;br /&gt;
A TLB has a fixed number of slots that contain page table entries, which map virtual addresses to physical addresses. The virtual memory is the space seen from a process. This space is segmented in pages of a prefixed size. The page table (generally loaded in memory) keeps track of where the virtual pages are loaded in the physical memory. The TLB is a cache of the page table; that is, only a subset of its content are stored.&lt;br /&gt;
The TLB references physical memory addresses in its table. It may reside between the CPU and the CPU cache, between the CPU cache and primary storage memory, or between levels of a multi-level cache. The placement determines whether the cache uses physical or virtual addressing. If the cache is virtually addressed, requests are sent directly from the CPU to the cache, and the TLB is accessed only on a cache miss. If the cache is physically addressed, the CPU does a TLB lookup on every memory operation and the resulting physical address is sent to the cache. There are pros and cons to both implementations. Caches that use virtual addressing have for their key part of the virtual address plus, optionally, a key called an &amp;quot;address space identifier&amp;quot; (ASID). Caches that don't have ASIDs must be flushed every context switch in a multiprocessing environment.&lt;br /&gt;
In a Harvard architecture or hybrid thereof, a separate virtual address space or memory access hardware may exist for instructions and data. This can lead to distinct TLBs for each access type.&lt;br /&gt;
A common optimization for physically addressed caches is to perform the TLB lookup in parallel with the cache access. The low-order bits of any virtual address (e.g., in a virtual memory system having 4 KB pages, the lower 12 bits of the virtual address) represent the offset of the desired address within the page, and thus they do not change in the virtual-to-physical translation. During a cache access, two steps are performed: an index is used to find an entry in the cache's data store, and then the tags for the cache line found are compared. If the cache is structured in such a way that it can be indexed using only the bits that do not change in translation, the cache can perform its &amp;quot;index&amp;quot; operation while the TLB translates the upper bits of the address. Then, the translated address from the TLB is passed to the cache. The cache performs a tag comparison to determine if this access was a hit or miss. It is possible to perform the TLB lookup in parallel with the cache access even if the cache must be indexed using some bits that may change upon address translation; see the address translation section in the cache article for more details about virtual addressing as it pertains to caches and TLBs.&lt;br /&gt;
&lt;br /&gt;
tlb.PNG&lt;br /&gt;
&lt;br /&gt;
And here is generally how a typical TLB is working. Note that X is the virtual page number to be translated into a physical page number, X' is the Physical number corresponding to X. and V is the Virtual page number of a victim page(that is a page to be kicked off the table). &lt;br /&gt;
&lt;br /&gt;
tlbOP.PNG&lt;br /&gt;
&lt;br /&gt;
Next in this chapter we are going to discuss problems that are going to occur when we extend this TLB structure to multi-processor systems. The solution to these problems is presented in next chapter.&lt;br /&gt;
&lt;br /&gt;
=== TLB Coherence issues ===&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59731</id>
		<title>CSC/ECE 506 Spring 2012/7b yw</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59731"/>
		<updated>2012-03-18T22:03:21Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* Virtually addressed caches */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addressed caches are discussed. Then we discuss the need for TLB, a cache-like construct that translate virtual address to physical address. Then we raise the issue of TLB coherence. &lt;br /&gt;
&lt;br /&gt;
=== Virtually addressed caches ===&lt;br /&gt;
&lt;br /&gt;
Virtual memory is a memory management technology developed for multithread operating systems. This technique virtualizes a computer architecture's various forms of computer data storage (such as random-access memory and disk storage), allowing a program to be designed as though there is only one kind of memory, &amp;quot;virtual&amp;quot; memory, which behaves like directly addressable read/write memory (RAM). &lt;br /&gt;
&lt;br /&gt;
virtualM.png&lt;br /&gt;
[[Image:virtualM.PNG|thumbnail|right|600px|Virtual Memory in modern computer systems&amp;lt;sup&amp;gt;&amp;lt;span id=&amp;quot;3body&amp;quot;&amp;gt;]&amp;lt;/span&amp;gt;&amp;lt;/sup&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
This technique greatly simplifies programmers job because modern operating system runs each process on its own dedicated virtual memory space. Thus each program runs as if it has the sole access of the virtual memory. In this way, programmers don't have to worry about how operating system switches between processes or how other process operates. Also, Virtual memory makes application programming easier by hiding fragmentation of physical memory; by delegating to the kernel the burden of managing the memory hierarchy (eliminating the need for the program to handle overlays explicitly); and, when each process is run in its own dedicated address space, by obviating the need to relocate program code or to access memory with relative addressing.&lt;br /&gt;
&lt;br /&gt;
The introducing of virtual memory raise the problem of translating virtual address to physical address since we need physical address to access the actual content stored in cache. And that's where Translation Lookaside Buffer comes into use.&lt;br /&gt;
&lt;br /&gt;
=== What is TLB ===&lt;br /&gt;
&lt;br /&gt;
A TLB has a fixed number of slots that contain page table entries, which map virtual addresses to physical addresses. The virtual memory is the space seen from a process. This space is segmented in pages of a prefixed size. The page table (generally loaded in memory) keeps track of where the virtual pages are loaded in the physical memory. The TLB is a cache of the page table; that is, only a subset of its content are stored.&lt;br /&gt;
The TLB references physical memory addresses in its table. It may reside between the CPU and the CPU cache, between the CPU cache and primary storage memory, or between levels of a multi-level cache. The placement determines whether the cache uses physical or virtual addressing. If the cache is virtually addressed, requests are sent directly from the CPU to the cache, and the TLB is accessed only on a cache miss. If the cache is physically addressed, the CPU does a TLB lookup on every memory operation and the resulting physical address is sent to the cache. There are pros and cons to both implementations. Caches that use virtual addressing have for their key part of the virtual address plus, optionally, a key called an &amp;quot;address space identifier&amp;quot; (ASID). Caches that don't have ASIDs must be flushed every context switch in a multiprocessing environment.&lt;br /&gt;
In a Harvard architecture or hybrid thereof, a separate virtual address space or memory access hardware may exist for instructions and data. This can lead to distinct TLBs for each access type.&lt;br /&gt;
A common optimization for physically addressed caches is to perform the TLB lookup in parallel with the cache access. The low-order bits of any virtual address (e.g., in a virtual memory system having 4 KB pages, the lower 12 bits of the virtual address) represent the offset of the desired address within the page, and thus they do not change in the virtual-to-physical translation. During a cache access, two steps are performed: an index is used to find an entry in the cache's data store, and then the tags for the cache line found are compared. If the cache is structured in such a way that it can be indexed using only the bits that do not change in translation, the cache can perform its &amp;quot;index&amp;quot; operation while the TLB translates the upper bits of the address. Then, the translated address from the TLB is passed to the cache. The cache performs a tag comparison to determine if this access was a hit or miss. It is possible to perform the TLB lookup in parallel with the cache access even if the cache must be indexed using some bits that may change upon address translation; see the address translation section in the cache article for more details about virtual addressing as it pertains to caches and TLBs.&lt;br /&gt;
&lt;br /&gt;
tlb.PNG&lt;br /&gt;
&lt;br /&gt;
And here is generally how a typical TLB is working. Note that X is the virtual page number to be translated into a physical page number, X' is the Physical number corresponding to X. and V is the Virtual page number of a victim page(that is a page to be kicked off the table). &lt;br /&gt;
&lt;br /&gt;
tlbOP.PNG&lt;br /&gt;
&lt;br /&gt;
Next in this chapter we are going to discuss problems that are going to occur when we extend this TLB structure to multi-processor systems. The solution to these problems is presented in next chapter.&lt;br /&gt;
&lt;br /&gt;
=== TLB Coherence issues ===&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:TlbOP.PNG&amp;diff=59730</id>
		<title>File:TlbOP.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:TlbOP.PNG&amp;diff=59730"/>
		<updated>2012-03-18T22:00:27Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59729</id>
		<title>CSC/ECE 506 Spring 2012/7b yw</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59729"/>
		<updated>2012-03-18T22:00:09Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* What is TLB */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addressed caches are discussed. Then we discuss the need for TLB, a cache-like construct that translate virtual address to physical address. Then we raise the issue of TLB coherence. &lt;br /&gt;
&lt;br /&gt;
=== Virtually addressed caches ===&lt;br /&gt;
&lt;br /&gt;
Virtual memory is a memory management technology developed for multithread operating systems. This technique virtualizes a computer architecture's various forms of computer data storage (such as random-access memory and disk storage), allowing a program to be designed as though there is only one kind of memory, &amp;quot;virtual&amp;quot; memory, which behaves like directly addressable read/write memory (RAM). &lt;br /&gt;
&lt;br /&gt;
virtualM.png&lt;br /&gt;
&lt;br /&gt;
This technique greatly simplifies programmers job because modern operating system runs each process on its own dedicated virtual memory space. Thus each program runs as if it has the sole access of the virtual memory. In this way, programmers don't have to worry about how operating system switches between processes or how other process operates. Also, Virtual memory makes application programming easier by hiding fragmentation of physical memory; by delegating to the kernel the burden of managing the memory hierarchy (eliminating the need for the program to handle overlays explicitly); and, when each process is run in its own dedicated address space, by obviating the need to relocate program code or to access memory with relative addressing.&lt;br /&gt;
&lt;br /&gt;
The introducing of virtual memory raise the problem of translating virtual address to physical address since we need physical address to access the actual content stored in cache. And that's where Translation Lookaside Buffer comes into use.&lt;br /&gt;
&lt;br /&gt;
=== What is TLB ===&lt;br /&gt;
&lt;br /&gt;
A TLB has a fixed number of slots that contain page table entries, which map virtual addresses to physical addresses. The virtual memory is the space seen from a process. This space is segmented in pages of a prefixed size. The page table (generally loaded in memory) keeps track of where the virtual pages are loaded in the physical memory. The TLB is a cache of the page table; that is, only a subset of its content are stored.&lt;br /&gt;
The TLB references physical memory addresses in its table. It may reside between the CPU and the CPU cache, between the CPU cache and primary storage memory, or between levels of a multi-level cache. The placement determines whether the cache uses physical or virtual addressing. If the cache is virtually addressed, requests are sent directly from the CPU to the cache, and the TLB is accessed only on a cache miss. If the cache is physically addressed, the CPU does a TLB lookup on every memory operation and the resulting physical address is sent to the cache. There are pros and cons to both implementations. Caches that use virtual addressing have for their key part of the virtual address plus, optionally, a key called an &amp;quot;address space identifier&amp;quot; (ASID). Caches that don't have ASIDs must be flushed every context switch in a multiprocessing environment.&lt;br /&gt;
In a Harvard architecture or hybrid thereof, a separate virtual address space or memory access hardware may exist for instructions and data. This can lead to distinct TLBs for each access type.&lt;br /&gt;
A common optimization for physically addressed caches is to perform the TLB lookup in parallel with the cache access. The low-order bits of any virtual address (e.g., in a virtual memory system having 4 KB pages, the lower 12 bits of the virtual address) represent the offset of the desired address within the page, and thus they do not change in the virtual-to-physical translation. During a cache access, two steps are performed: an index is used to find an entry in the cache's data store, and then the tags for the cache line found are compared. If the cache is structured in such a way that it can be indexed using only the bits that do not change in translation, the cache can perform its &amp;quot;index&amp;quot; operation while the TLB translates the upper bits of the address. Then, the translated address from the TLB is passed to the cache. The cache performs a tag comparison to determine if this access was a hit or miss. It is possible to perform the TLB lookup in parallel with the cache access even if the cache must be indexed using some bits that may change upon address translation; see the address translation section in the cache article for more details about virtual addressing as it pertains to caches and TLBs.&lt;br /&gt;
&lt;br /&gt;
tlb.PNG&lt;br /&gt;
&lt;br /&gt;
And here is generally how a typical TLB is working. Note that X is the virtual page number to be translated into a physical page number, X' is the Physical number corresponding to X. and V is the Virtual page number of a victim page(that is a page to be kicked off the table). &lt;br /&gt;
&lt;br /&gt;
tlbOP.PNG&lt;br /&gt;
&lt;br /&gt;
Next in this chapter we are going to discuss problems that are going to occur when we extend this TLB structure to multi-processor systems. The solution to these problems is presented in next chapter.&lt;br /&gt;
&lt;br /&gt;
=== TLB Coherence issues ===&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59728</id>
		<title>CSC/ECE 506 Spring 2012/7b yw</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59728"/>
		<updated>2012-03-18T21:49:07Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* What is TLB */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addressed caches are discussed. Then we discuss the need for TLB, a cache-like construct that translate virtual address to physical address. Then we raise the issue of TLB coherence. &lt;br /&gt;
&lt;br /&gt;
=== Virtually addressed caches ===&lt;br /&gt;
&lt;br /&gt;
Virtual memory is a memory management technology developed for multithread operating systems. This technique virtualizes a computer architecture's various forms of computer data storage (such as random-access memory and disk storage), allowing a program to be designed as though there is only one kind of memory, &amp;quot;virtual&amp;quot; memory, which behaves like directly addressable read/write memory (RAM). &lt;br /&gt;
&lt;br /&gt;
virtualM.png&lt;br /&gt;
&lt;br /&gt;
This technique greatly simplifies programmers job because modern operating system runs each process on its own dedicated virtual memory space. Thus each program runs as if it has the sole access of the virtual memory. In this way, programmers don't have to worry about how operating system switches between processes or how other process operates. Also, Virtual memory makes application programming easier by hiding fragmentation of physical memory; by delegating to the kernel the burden of managing the memory hierarchy (eliminating the need for the program to handle overlays explicitly); and, when each process is run in its own dedicated address space, by obviating the need to relocate program code or to access memory with relative addressing.&lt;br /&gt;
&lt;br /&gt;
The introducing of virtual memory raise the problem of translating virtual address to physical address since we need physical address to access the actual content stored in cache. And that's where Translation Lookaside Buffer comes into use.&lt;br /&gt;
&lt;br /&gt;
=== What is TLB ===&lt;br /&gt;
&lt;br /&gt;
A translation lookaside buffer (TLB) is a cache that memory management hardware uses to improve virtual address translation speed. All current desktop, notebook, and server processors use a TLB to map virtual and physical address spaces, and it is nearly always present in any hardware which utilizes virtual memory.&lt;br /&gt;
The TLB is typically implemented as content-addressable memory (CAM). The CAM search key is the virtual address and the search result is a physical address. If the requested address is present in the TLB, the CAM search yields a match quickly and the retrieved physical address can be used to access memory. This is called a TLB hit. If the requested address is not in the TLB, it is a miss, and the translation proceeds by looking up the page table in a process called a page walk. The page walk is an expensive process, as it involves reading the contents of multiple memory locations and using them to compute the physical address. After the physical address is determined by the page walk, the virtual address to physical address mapping is entered into the TLB.&lt;br /&gt;
&lt;br /&gt;
tlb.PNG&lt;br /&gt;
&lt;br /&gt;
=== TLB Coherence issues ===&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Tlb.PNG&amp;diff=59727</id>
		<title>File:Tlb.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Tlb.PNG&amp;diff=59727"/>
		<updated>2012-03-18T21:48:19Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:VirtualM.PNG&amp;diff=59726</id>
		<title>File:VirtualM.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:VirtualM.PNG&amp;diff=59726"/>
		<updated>2012-03-18T21:47:49Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59725</id>
		<title>CSC/ECE 506 Spring 2012/7b yw</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59725"/>
		<updated>2012-03-18T21:47:28Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* Virtually addressed caches */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addressed caches are discussed. Then we discuss the need for TLB, a cache-like construct that translate virtual address to physical address. Then we raise the issue of TLB coherence. &lt;br /&gt;
&lt;br /&gt;
=== Virtually addressed caches ===&lt;br /&gt;
&lt;br /&gt;
Virtual memory is a memory management technology developed for multithread operating systems. This technique virtualizes a computer architecture's various forms of computer data storage (such as random-access memory and disk storage), allowing a program to be designed as though there is only one kind of memory, &amp;quot;virtual&amp;quot; memory, which behaves like directly addressable read/write memory (RAM). &lt;br /&gt;
&lt;br /&gt;
virtualM.png&lt;br /&gt;
&lt;br /&gt;
This technique greatly simplifies programmers job because modern operating system runs each process on its own dedicated virtual memory space. Thus each program runs as if it has the sole access of the virtual memory. In this way, programmers don't have to worry about how operating system switches between processes or how other process operates. Also, Virtual memory makes application programming easier by hiding fragmentation of physical memory; by delegating to the kernel the burden of managing the memory hierarchy (eliminating the need for the program to handle overlays explicitly); and, when each process is run in its own dedicated address space, by obviating the need to relocate program code or to access memory with relative addressing.&lt;br /&gt;
&lt;br /&gt;
The introducing of virtual memory raise the problem of translating virtual address to physical address since we need physical address to access the actual content stored in cache. And that's where Translation Lookaside Buffer comes into use.&lt;br /&gt;
&lt;br /&gt;
=== What is TLB ===&lt;br /&gt;
&lt;br /&gt;
=== TLB Coherence issues ===&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59724</id>
		<title>CSC/ECE 506 Spring 2012/7b yw</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59724"/>
		<updated>2012-03-18T21:28:10Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* Virtually addressed caches */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addressed caches are discussed. Then we discuss the need for TLB, a cache-like construct that translate virtual address to physical address. Then we raise the issue of TLB coherence. &lt;br /&gt;
&lt;br /&gt;
=== Virtually addressed caches ===&lt;br /&gt;
&lt;br /&gt;
Virtual memory is a memory management technology developed for multithread operating systems. This technique virtualizes a computer architecture's various forms of computer data storage (such as random-access memory and disk storage), allowing a program to be designed as though there is only one kind of memory, &amp;quot;virtual&amp;quot; memory, which behaves like directly addressable read/write memory (RAM). &lt;br /&gt;
&lt;br /&gt;
some graph&lt;br /&gt;
&lt;br /&gt;
This technique greatly simplifies programmers job because modern operating system runs each process on its own dedicated virtual memory space. Thus each program runs as if it has the sole access of the virtual memory. In this way, programmers don't have to worry about how operating system switches between processes or how other process operates. Also, Virtual memory makes application programming easier by hiding fragmentation of physical memory; by delegating to the kernel the burden of managing the memory hierarchy (eliminating the need for the program to handle overlays explicitly); and, when each process is run in its own dedicated address space, by obviating the need to relocate program code or to access memory with relative addressing.&lt;br /&gt;
&lt;br /&gt;
=== What is TLB ===&lt;br /&gt;
&lt;br /&gt;
=== TLB Coherence issues ===&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59711</id>
		<title>CSC/ECE 506 Spring 2012/7b yw</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/7b_yw&amp;diff=59711"/>
		<updated>2012-03-18T20:35:17Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: Created page with &amp;quot;== Introduction ==  In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addres...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this chapter we will first introduce the concept of virtual address memories, more precisely, virtually addressed caches. Pros and cons of virtually addressed caches are discussed. Then we discuss the need for TLB, a cache-like construct that translate virtual address to physical address. Then we raise the issue of TLB coherence. &lt;br /&gt;
&lt;br /&gt;
=== Virtually addressed caches ===&lt;br /&gt;
&lt;br /&gt;
=== What is TLB ===&lt;br /&gt;
&lt;br /&gt;
=== TLB Coherence issues ===&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/ch5a_ja&amp;diff=59119</id>
		<title>CSC/ECE 506 Spring 2012/ch5a ja</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/ch5a_ja&amp;diff=59119"/>
		<updated>2012-02-27T21:24:22Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* References */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Chapter 5a CSC/ECE 506 Spring 2012 / ch5a ==&lt;br /&gt;
&lt;br /&gt;
An exploration and summary of concurrency issues as it relates to linked-list based data structures such as hash tables, trees, and graphs.  This topic examines concurrency problems related to each type and possible solutions to allow for parallelization.&lt;br /&gt;
&lt;br /&gt;
= Introduction to Linked-List Parallel Programming =&lt;br /&gt;
&lt;br /&gt;
In determining opportunities for parallel programming during the software design process, many programmers will focus exclusively on loop or array structures, rather than also considering that linked-list pointer-based structures could also provide opportunities to run code in parallel across different processors.&lt;br /&gt;
&lt;br /&gt;
For example, one common parallel technique used in an array processing algorithm is the copy-scan technique.  This technique involves copying rows of data from one processor to another in a log(n) fashion until all processors have their own copy of that row.  From there, you could perform a reduction technique to generate a sum of all the data, all while working in a parallel fashion.  Take the following grid:&lt;br /&gt;
&lt;br /&gt;
The basic process for copy-scan would be to:&lt;br /&gt;
  Step 1) Copy the row 1 array to row 2.&lt;br /&gt;
  Step 2) Copy the row 1 array to row 3, row 2 to row 4, etc on the next run.&lt;br /&gt;
  Step 3) Continue in this manner until all rows have been copied in a log(n) fashion.&lt;br /&gt;
  Step 4) Perform the parallel operations to generate the desired result (reduction for sum, etc.).&lt;br /&gt;
&lt;br /&gt;
[[File:CopyScan.gif]]&lt;br /&gt;
&lt;br /&gt;
But how does this same process work in the linked list world?&lt;br /&gt;
&lt;br /&gt;
With linked lists, there is a concept called pointer doubling, which works in a very similar manner to copy-scan.&lt;br /&gt;
&lt;br /&gt;
  Step 1) Each processor will make a copy of the pointer it holds to it's neighbor.&lt;br /&gt;
  Step 2) Next, each processor will make a pointer to the processor 2 steps away.&lt;br /&gt;
  Step 3) This continues in logarithmic fashion until each processor has a pointer to the end of the chain.&lt;br /&gt;
  Step 4) Perform the parallel operations to generate the desired result.&lt;br /&gt;
&lt;br /&gt;
[[File:linkedlist.gif]]&lt;br /&gt;
&lt;br /&gt;
However, with linked list programming, similar to array-based programming, it becomes imperative to have some sort of locking mechanism on critical sections to avoid race conditions.  To make sure the results are correct, it is important that operations can be serialized appropriately and that data remains current and synchronized.&lt;br /&gt;
&lt;br /&gt;
In this chapter, we will explore 3 linked-list based data structures and the concurrency issues they present: hash tables, trees, and graphs.&lt;br /&gt;
&lt;br /&gt;
= Linked Data Structure algorithms extension =&lt;br /&gt;
== Lock free algorithms ==&lt;br /&gt;
&lt;br /&gt;
In order to overcome the ABA problems (shown in figure blow), we add auxiliary nodes to the data we structure. An auxiliary node is a cell that contains only a next field. We require that every normal cell in the list have an auxiliary node as its predecessor and as its successor. We permit “chains” of auxiliary nodes in the list (i.e., we do not require that every auxiliary node have a normal cell as its predecessor and successor), although such chains are undesirable for performance reasons.&lt;br /&gt;
&lt;br /&gt;
[[File:fig3.PNG]]&lt;br /&gt;
&lt;br /&gt;
The list also contains two dummy cells as the first and last normal cells in the list. These two cells are pointed at by the root pointers First and Last. These dummy cells need not, respectively, be preceded and followed by auxiliary nodes. Thus, m empty list data structure consists of these two dummy cells separated by an auxiliary node.&lt;br /&gt;
&lt;br /&gt;
A cursor is implemented as three pointers into the data structure: target is a pointer to the cell at the position the cursor is visiting. If the cursor is visiting the end-of-list position, then target will be equal to Last. The pointer pre-aux points to an auxiliary node in the data structure. For a cursor c, if c“.pre-aux = c“.target, then the cursor is valid; otherwise it is invalid. The pointer pre.cell points to a regular cell in the data structure. This pointer is used only by the TRYDELETE operation described below. An invalid cursor indicates that the structure of the list in t he vicinity of the cursor has changed (due to a concurrent insert ion or deletion by another process) since the pointers in the cursor were last read. The UPDATE algorithm, given in Figure 5, examines the state of the list and updates the pointers in the cursor so that it becomes valid. Since the list structure contains auxiliary nodes (perhaps more than one in a row), the UPDATE algorithm must skip over them. If two adjacent auxiliary nodes axe found in the list, the UPDATE algorithm will remove one of them. &lt;br /&gt;
&lt;br /&gt;
[[File:fig5.PNG]]&lt;br /&gt;
&lt;br /&gt;
Traversal of the list data structure is accomplished by using the FIRST and NEXT operations, which use the UPDATE operation. Algorithms are given in Figures 6 and 7. The NEXT operation returns FALSE if the cursor is already at the end of the list and cannot be advanced. Adding new cells into the list requires the insertion of both the cell and a new auxiliary node. This insertion is restricted to occur in the following way: The new auxiliary node will follow the new cell in the list, and insertion can only occur between an auxiliary node and a normal cell, as shown in Figure 8. &lt;br /&gt;
&lt;br /&gt;
[[File:fig6.PNG]]&lt;br /&gt;
[[File:fig7.PNG]]&lt;br /&gt;
[[File:fig8.PNG]]&lt;br /&gt;
&lt;br /&gt;
Figure 9 gives an algorithm, which takes as arguments a cursor and pointers to a new cell and auxiliary node. The algorithm will try to insert the new cell and auxiliary node at the position specified by the cursor, returning the value&lt;br /&gt;
TRUE if successful.&lt;br /&gt;
&lt;br /&gt;
[[File:fig9.PNG]]&lt;br /&gt;
&lt;br /&gt;
If the cursor becomes invalid, then the operation returns without inserting the new cell and returns the value FALSE. This allows a higher-level operation to detect that a change to the structure of the list occurred and to take it into account before attempting to insert the new cell again. For example, in the next section we show how the items in the list can be kept sorted using this technique.&lt;br /&gt;
&lt;br /&gt;
Given a valid cursor, the cell that it is visiting can also be deleted from the list. As with the insertion of new cells, if the list structure changes (i.e., the cursor becomes invalid) then the operation fails and must be tried again. Figure 10 gives the TRYDELETE algorithm. The deletion of the cell from the list leaves an “extra” auxiliary node; concurrent processes deleting adjacent cells can result in longer chains. Most of the TRYDELETE algorithm is concerned with removing the extra auxiliary nodes from the list. Normally, removing the extra auxiliary node that results from the deletion of a cell from the list is accomplished by simply swinging the pointer in the cell pointed at by the pre-cell pointer in the cursor. &lt;br /&gt;
&lt;br /&gt;
[[File:fig10.PNG]]&lt;br /&gt;
&lt;br /&gt;
However, this does not always work; in particular, this cell may have itself been deleted from the list, in which case swinging its next pointer will not remove the extra auxiliary node: In order to overcome this problem, we add a back~ink field to the normal cells in the list. When a cell is deleted from the list, the pre.cell field of the cursor is copied into the cell’s backdink field. The TRYDELETE algorithm can then use these pointers to reverse back to a cell that has not been deleted from the list. &lt;br /&gt;
&lt;br /&gt;
With just two processes, it is possible to create a chain of auxiliary nodes (with no intervening normal cells) of any length. However, any such chain can exist in the list only as long as some process is executing the TRYDELETE algorithm.&lt;br /&gt;
&lt;br /&gt;
If all deletions have been completed, then the list will contain no extra auxiliary nodes. To see this, assume that there is a chain of two or more-+ auxiliary nodes in the list. Let z be the normal cell that was deleted from between the first two auxiliary nodes in the chain. Note that this implies that the normal cell that immediately preceded x in the list has not been deleted.&lt;br /&gt;
By assumption, the operation that deleted z has completed. Consider the loop at lines 17–21 of the TRYDELETE algorithm. The only way for the process to exit this 100P, and hence to complete the operation, is for another deletion operation to have extended the chain of auxiliary nodes by deleting the normal cell g immediately following the chain, since the cell z is at the front of the chain.&lt;br /&gt;
Furthermore, the deletion of y must have occurred after the operation deleting x had set its back_link pointer at line 6; otherwise the auxiliary node following y would have been included in the chain found in lines 13–16. Thus, the chain of back_link pointers followed by the process that deleted y will lead to the same normal cell that preceded x. &lt;br /&gt;
&lt;br /&gt;
Now, the only way for the operation that deleted y to have completed is for the same reason as above; i.e., another TRYDELETE operation must extend the chain of auxiliary nodes by deleting a cell z. Since the length of the list must be finite, there must be a last such deletion which, but by the argument above, cannot have completed. Thus this operation must still be in progress, contradicting the assumption that there were no TRYDELETE operations in progress.&lt;br /&gt;
&lt;br /&gt;
[[File:fig11.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Trees ==&lt;br /&gt;
&lt;br /&gt;
This chapter gives a serial code for a tree traversal, and a parallel solution to implement same function. &lt;br /&gt;
&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
Below is a code for tree traversal algorithms&lt;br /&gt;
its behavior is as figure below shows:&lt;br /&gt;
&lt;br /&gt;
[[File: tree.PNG]]&lt;br /&gt;
&lt;br /&gt;
procedure Tree_Traversal is&lt;br /&gt;
   type Node;&lt;br /&gt;
   type Node_Access is access Node;&lt;br /&gt;
   type Node is record&lt;br /&gt;
      Left : Node_Access := null;&lt;br /&gt;
      Right : Node_Access := null;&lt;br /&gt;
      Data : Integer;&lt;br /&gt;
   end record;&lt;br /&gt;
   procedure Destroy_Tree(N : in out Node_Access) is&lt;br /&gt;
      procedure free is new Ada.Unchecked_Deallocation(Node, Node_Access);&lt;br /&gt;
   begin&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Destroy_Tree(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      if N.Right /= null then &lt;br /&gt;
         Destroy_Tree(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
      Free(N);&lt;br /&gt;
   end Destroy_Tree;&lt;br /&gt;
   function Tree(Value : Integer; Left : Node_Access; Right : Node_Access) return Node_Access is&lt;br /&gt;
      Temp : Node_Access := new Node;&lt;br /&gt;
   begin&lt;br /&gt;
      Temp.Data := Value;&lt;br /&gt;
      Temp.Left := Left;&lt;br /&gt;
      Temp.Right := Right;&lt;br /&gt;
      return Temp;&lt;br /&gt;
   end Tree;&lt;br /&gt;
   procedure Preorder(N : Node_Access) is&lt;br /&gt;
   begin&lt;br /&gt;
      Put(Integer'Image(N.Data));&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Preorder(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      if N.Right /= null then&lt;br /&gt;
         Preorder(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
   end Preorder;&lt;br /&gt;
   procedure Inorder(N : Node_Access) is&lt;br /&gt;
   begin&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Inorder(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      Put(Integer'Image(N.Data));&lt;br /&gt;
      if N.Right /= null then&lt;br /&gt;
         Inorder(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
   end Inorder;&lt;br /&gt;
   procedure Postorder(N : Node_Access) is&lt;br /&gt;
   begin&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Postorder(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      if N.Right /= null then&lt;br /&gt;
         Postorder(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
      Put(Integer'Image(N.Data));&lt;br /&gt;
   end Postorder;&lt;br /&gt;
   procedure Levelorder(N : Node_Access) is&lt;br /&gt;
      package Queues is new Ada.Containers.Doubly_Linked_Lists(Node_Access);&lt;br /&gt;
      use Queues;&lt;br /&gt;
      Node_Queue : List;&lt;br /&gt;
      Next : Node_Access;&lt;br /&gt;
   begin&lt;br /&gt;
      Node_Queue.Append(N);&lt;br /&gt;
      while not Is_Empty(Node_Queue) loop&lt;br /&gt;
         Next := First_Element(Node_Queue);&lt;br /&gt;
         Delete_First(Node_Queue);&lt;br /&gt;
         Put(Integer'Image(Next.Data));&lt;br /&gt;
         if Next.Left /= null then&lt;br /&gt;
            Node_Queue.Append(Next.Left);&lt;br /&gt;
         end if;&lt;br /&gt;
         if Next.Right /= null then&lt;br /&gt;
            Node_Queue.Append(Next.Right);&lt;br /&gt;
         end if;&lt;br /&gt;
      end loop;&lt;br /&gt;
   end Levelorder;&lt;br /&gt;
   N : Node_Access;&lt;br /&gt;
begin&lt;br /&gt;
   N := Tree(1, &lt;br /&gt;
      Tree(2,&lt;br /&gt;
         Tree(4,&lt;br /&gt;
            Tree(7, null, null),&lt;br /&gt;
            null),&lt;br /&gt;
         Tree(5, null, null)),&lt;br /&gt;
      Tree(3,&lt;br /&gt;
         Tree(6,&lt;br /&gt;
            Tree(8, null, null),&lt;br /&gt;
            Tree(9, null, null)),&lt;br /&gt;
         null));&lt;br /&gt;
 &lt;br /&gt;
   Put(&amp;quot;preorder:    &amp;quot;);&lt;br /&gt;
   Preorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Put(&amp;quot;inorder:     &amp;quot;);&lt;br /&gt;
   Inorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Put(&amp;quot;postorder:   &amp;quot;);&lt;br /&gt;
   Postorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Put(&amp;quot;level order: &amp;quot;);&lt;br /&gt;
   Levelorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Destroy_Tree(N);&lt;br /&gt;
end Tree_traversal;&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
&lt;br /&gt;
This part we implement a parallel algorithm with the same definition of traversal. &lt;br /&gt;
First, we difine a function NEXT[x].The function NEXT[ x,], defining the successor of a field x, (of node x) in the Euler tour, is given as&lt;br /&gt;
&lt;br /&gt;
[[File: para_tree1.PNG]]&lt;br /&gt;
&lt;br /&gt;
Note that this NEXT function does not provide the successor of the last field of the root-node r in the tour. This is because we break the tour into a linked list such that u, is the starting field and r is the terminal field, where m = no-of-chiidren[r] + 1. The proposed linked list structure can be represented as an array [I . 2n - l] of SNODEREC:&lt;br /&gt;
&lt;br /&gt;
[[File: para2.PNG]]&lt;br /&gt;
This data structure can be constructed from the following algorithm when the input tree is represented&lt;br /&gt;
by a “parent-of” relation with explicit ordering of children. Each field of a tree-node in this algorithm is a record of type SNODEREC.&lt;br /&gt;
&lt;br /&gt;
Algorithm GEN-COMP-NEXT&lt;br /&gt;
[[File: para3.PNG]]&lt;br /&gt;
&lt;br /&gt;
To obtain the required tree-traversals, the following rules are operated on the linked list produced by algorithm GEN-COMP-NEXT: &lt;br /&gt;
&lt;br /&gt;
pre-order traversal: select the first copy of&lt;br /&gt;
each node;&lt;br /&gt;
&lt;br /&gt;
post-order traversal: select the last copy of&lt;br /&gt;
each node;&lt;br /&gt;
&lt;br /&gt;
in-order traversal: delete the first copy of each node if it is not&lt;br /&gt;
a leaf and delete the last copy of each node if it has more than one child.&lt;br /&gt;
&lt;br /&gt;
== Hash Tables ==&lt;br /&gt;
=== Hash Table Intro ===&lt;br /&gt;
&lt;br /&gt;
Hash tables are very efficient data structures often used in searching algorithms for fast lookup operations.  Hash tables contain a series of &amp;quot;buckets&amp;quot; that function like indexes into an array, each of which can be accessed directly using their key value.  The bucket for which a piece of data will be placed is determine by a special hashing function.&lt;br /&gt;
&lt;br /&gt;
The major advantage of a hash table is that lookup times are essentially a constant value, much like an array with a known index.  With a proper hashing function in place, it should be fairly rare that any 2 keys would generate the same value.&lt;br /&gt;
&lt;br /&gt;
In the case that 2 keys do map to the same position, there is a conflict that must be dealt with in some fashion to obtain the correct value.  One way that is relevant to linked list structures is to have a chained hash table in which a linked list is created with all values that have been placed in that particular bucket.  The developer would have to not only take into account the proper bucket for the data being searched for, but also must considered the chained linked list.&lt;br /&gt;
&lt;br /&gt;
[[File:315px-Hash table 3 1 1 0 1 0 0 SP.svg.png]]&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
'''  Insert Example: Create new node if hash bucket doesnt exist, else append to the chain.'''&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Put a key/value pair into the table by hashing the key to get the array&lt;br /&gt;
   *  index of the chain that should hold the node containing the pair.&lt;br /&gt;
   *  If an existing node with the same key is present then overwrite its value,&lt;br /&gt;
   *  otherwise add a new node.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   *@param  val  data object reference&lt;br /&gt;
   */&lt;br /&gt;
  public void put(Object key, Object val)&lt;br /&gt;
  {&lt;br /&gt;
    int index = getIndex(key);&lt;br /&gt;
    Node node = find(key, data[index]);&lt;br /&gt;
    // Use helper method to determine if node with same key is already in&lt;br /&gt;
    // chain. If not, add a new node to head of chain.&lt;br /&gt;
    if (node == null)&lt;br /&gt;
    {&lt;br /&gt;
      data[index] = new Node(data[index], key, val);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      // Otherwise update data value of existing node.&lt;br /&gt;
      node.val = val;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Given a key object, return a data object from the table or&lt;br /&gt;
   *  null if it is not found.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   *@return      data object reference or null if no object found&lt;br /&gt;
   */&lt;br /&gt;
  public Object get(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    Node temp = find(key, data[getIndex(key)]);&lt;br /&gt;
    if (temp != null)&lt;br /&gt;
    {&lt;br /&gt;
      return temp.val;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      return null;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''  Delete Example: Delete a node from the chain.'''&lt;br /&gt;
  /**&lt;br /&gt;
   * Remove a key/value pair from table if present, otherwise make no change.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   */&lt;br /&gt;
  public void remove(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    int index = getIndex(key);&lt;br /&gt;
    Node ref = data[index];&lt;br /&gt;
    Node previous = null;&lt;br /&gt;
    while (ref != null)&lt;br /&gt;
    {&lt;br /&gt;
      if ((ref.key).equals(key))&lt;br /&gt;
      {&lt;br /&gt;
        if (previous == null)&lt;br /&gt;
        {&lt;br /&gt;
          data[index] = ref.next;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
          previous.next = ref.next;&lt;br /&gt;
        }&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      previous = ref;&lt;br /&gt;
      ref = ref.next;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Given a key, use a hash function to obtain the array index of the chain&lt;br /&gt;
   *  corresponding to the key.&lt;br /&gt;
   *  The hashCode method inherited (and possibly overridden)&lt;br /&gt;
   *  from class Object is called to do the hashing, with the returned&lt;br /&gt;
   *  value constrained to the hash table array bounds.&lt;br /&gt;
   *  The distribution of objects in the hash table will depend&lt;br /&gt;
   *  on the quality of the hash function implemented by hashCode.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  reference to object to be hashed&lt;br /&gt;
   *@return      array index of chain corresponding to key&lt;br /&gt;
   */&lt;br /&gt;
  private int getIndex(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    return Math.abs(key.hashCode() % data.length);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Find node given a key and a chain to search.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key    key object reference&lt;br /&gt;
   *@param  ref    node object reference where search will start&lt;br /&gt;
   *@return        node object holding key or null if not found&lt;br /&gt;
   */&lt;br /&gt;
  private Node find(Object key, Node ref)&lt;br /&gt;
  {&lt;br /&gt;
    while (ref != null)&lt;br /&gt;
    {&lt;br /&gt;
      if ((ref.key).equals(key))&lt;br /&gt;
      {&lt;br /&gt;
        return ref;&lt;br /&gt;
      }&lt;br /&gt;
      ref = ref.next;&lt;br /&gt;
    }&lt;br /&gt;
    return null;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
&lt;br /&gt;
The key issue in a hash table in a parallel environment is to make sure any update/insert/delete sequences have been completed properly prior to attempting subsequent operations to make sure the data has been synched appropriately.  However, since access speed is such a critical component of the design of a hash table, it is essential to try and avoid using too many locks for performing synchronization.  Fortunately, a number of lock-free hash designs have been implemented to avoid this bottleneck.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Graphs ==&lt;br /&gt;
=== Graph Intro ===&lt;br /&gt;
&lt;br /&gt;
A graph data structure is another type of linked-list structure that focuses on data that requires linking according to various types of relationships.  For example, in a networking application, one network node may have connections to a variety of other network nodes.  These nodes then also link to a variety of other nodes in the network.  Using this connection of nodes, it would be possible to then find a path from one specific node to another in the chain.  This could be accomplished by having each node contain a linked list of pointers to all other reachable nodes.&lt;br /&gt;
&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Add a new edge to the graph.&lt;br /&gt;
     */&lt;br /&gt;
    public void addEdge( String sourceName, String destName, double cost )&lt;br /&gt;
    {&lt;br /&gt;
        Vertex v = getVertex( sourceName );&lt;br /&gt;
        Vertex w = getVertex( destName );&lt;br /&gt;
        v.adj.add( new Edge( w, cost ) );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Single-source unweighted shortest-path algorithm.&lt;br /&gt;
     */&lt;br /&gt;
    public void unweighted( String startName )&lt;br /&gt;
    {&lt;br /&gt;
        clearAll( ); &lt;br /&gt;
&lt;br /&gt;
        Vertex start = (Vertex) vertexMap.get( startName );&lt;br /&gt;
        if( start == null )&lt;br /&gt;
            throw new NoSuchElementException( &amp;quot;Start vertex not found&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
        LinkedList q = new LinkedList( );&lt;br /&gt;
        q.addLast( start ); start.dist = 0;&lt;br /&gt;
&lt;br /&gt;
        while( !q.isEmpty( ) )&lt;br /&gt;
        {&lt;br /&gt;
            Vertex v = (Vertex) q.removeFirst( );&lt;br /&gt;
&lt;br /&gt;
            for( Iterator itr = v.adj.iterator( ); itr.hasNext( ); )&lt;br /&gt;
            {&lt;br /&gt;
                Edge e = (Edge) itr.next( );&lt;br /&gt;
                Vertex w = e.dest;&lt;br /&gt;
                if( w.dist == INFINITY )&lt;br /&gt;
                {&lt;br /&gt;
                    w.dist = v.dist + 1;&lt;br /&gt;
                    w.prev = v;&lt;br /&gt;
                    q.addLast( w );&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
&lt;br /&gt;
= Quiz =&lt;br /&gt;
= References =&lt;br /&gt;
http://oreilly.com/catalog/masteralgoc/chapter/ch08.pdf&lt;br /&gt;
&lt;br /&gt;
http://www.devjavasoft.org/code/classhashtable.html&lt;br /&gt;
&lt;br /&gt;
http://osr600doc.sco.com/en/SDK_c++/_Intro_graph.html&lt;br /&gt;
&lt;br /&gt;
web.eecs.utk.edu/~berry/cs302s02/src/code/Chap14/Graph.java&lt;br /&gt;
&lt;br /&gt;
http://people.engr.ncsu.edu/efg/506/s01/lectures/notes/lec8.html&lt;br /&gt;
&lt;br /&gt;
http://en.wikipedia.org/wiki/File:Hash_table_3_1_1_0_1_0_0_SP.svg&lt;br /&gt;
&lt;br /&gt;
http://rosettacode.org/wiki/Talk:Tree_traversal&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/ch5a_ja&amp;diff=59118</id>
		<title>CSC/ECE 506 Spring 2012/ch5a ja</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/ch5a_ja&amp;diff=59118"/>
		<updated>2012-02-27T21:23:24Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* Trees */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Chapter 5a CSC/ECE 506 Spring 2012 / ch5a ==&lt;br /&gt;
&lt;br /&gt;
An exploration and summary of concurrency issues as it relates to linked-list based data structures such as hash tables, trees, and graphs.  This topic examines concurrency problems related to each type and possible solutions to allow for parallelization.&lt;br /&gt;
&lt;br /&gt;
= Introduction to Linked-List Parallel Programming =&lt;br /&gt;
&lt;br /&gt;
In determining opportunities for parallel programming during the software design process, many programmers will focus exclusively on loop or array structures, rather than also considering that linked-list pointer-based structures could also provide opportunities to run code in parallel across different processors.&lt;br /&gt;
&lt;br /&gt;
For example, one common parallel technique used in an array processing algorithm is the copy-scan technique.  This technique involves copying rows of data from one processor to another in a log(n) fashion until all processors have their own copy of that row.  From there, you could perform a reduction technique to generate a sum of all the data, all while working in a parallel fashion.  Take the following grid:&lt;br /&gt;
&lt;br /&gt;
The basic process for copy-scan would be to:&lt;br /&gt;
  Step 1) Copy the row 1 array to row 2.&lt;br /&gt;
  Step 2) Copy the row 1 array to row 3, row 2 to row 4, etc on the next run.&lt;br /&gt;
  Step 3) Continue in this manner until all rows have been copied in a log(n) fashion.&lt;br /&gt;
  Step 4) Perform the parallel operations to generate the desired result (reduction for sum, etc.).&lt;br /&gt;
&lt;br /&gt;
[[File:CopyScan.gif]]&lt;br /&gt;
&lt;br /&gt;
But how does this same process work in the linked list world?&lt;br /&gt;
&lt;br /&gt;
With linked lists, there is a concept called pointer doubling, which works in a very similar manner to copy-scan.&lt;br /&gt;
&lt;br /&gt;
  Step 1) Each processor will make a copy of the pointer it holds to it's neighbor.&lt;br /&gt;
  Step 2) Next, each processor will make a pointer to the processor 2 steps away.&lt;br /&gt;
  Step 3) This continues in logarithmic fashion until each processor has a pointer to the end of the chain.&lt;br /&gt;
  Step 4) Perform the parallel operations to generate the desired result.&lt;br /&gt;
&lt;br /&gt;
[[File:linkedlist.gif]]&lt;br /&gt;
&lt;br /&gt;
However, with linked list programming, similar to array-based programming, it becomes imperative to have some sort of locking mechanism on critical sections to avoid race conditions.  To make sure the results are correct, it is important that operations can be serialized appropriately and that data remains current and synchronized.&lt;br /&gt;
&lt;br /&gt;
In this chapter, we will explore 3 linked-list based data structures and the concurrency issues they present: hash tables, trees, and graphs.&lt;br /&gt;
&lt;br /&gt;
= Linked Data Structure algorithms extension =&lt;br /&gt;
== Lock free algorithms ==&lt;br /&gt;
&lt;br /&gt;
In order to overcome the ABA problems (shown in figure blow), we add auxiliary nodes to the data we structure. An auxiliary node is a cell that contains only a next field. We require that every normal cell in the list have an auxiliary node as its predecessor and as its successor. We permit “chains” of auxiliary nodes in the list (i.e., we do not require that every auxiliary node have a normal cell as its predecessor and successor), although such chains are undesirable for performance reasons.&lt;br /&gt;
&lt;br /&gt;
[[File:fig3.PNG]]&lt;br /&gt;
&lt;br /&gt;
The list also contains two dummy cells as the first and last normal cells in the list. These two cells are pointed at by the root pointers First and Last. These dummy cells need not, respectively, be preceded and followed by auxiliary nodes. Thus, m empty list data structure consists of these two dummy cells separated by an auxiliary node.&lt;br /&gt;
&lt;br /&gt;
A cursor is implemented as three pointers into the data structure: target is a pointer to the cell at the position the cursor is visiting. If the cursor is visiting the end-of-list position, then target will be equal to Last. The pointer pre-aux points to an auxiliary node in the data structure. For a cursor c, if c“.pre-aux = c“.target, then the cursor is valid; otherwise it is invalid. The pointer pre.cell points to a regular cell in the data structure. This pointer is used only by the TRYDELETE operation described below. An invalid cursor indicates that the structure of the list in t he vicinity of the cursor has changed (due to a concurrent insert ion or deletion by another process) since the pointers in the cursor were last read. The UPDATE algorithm, given in Figure 5, examines the state of the list and updates the pointers in the cursor so that it becomes valid. Since the list structure contains auxiliary nodes (perhaps more than one in a row), the UPDATE algorithm must skip over them. If two adjacent auxiliary nodes axe found in the list, the UPDATE algorithm will remove one of them. &lt;br /&gt;
&lt;br /&gt;
[[File:fig5.PNG]]&lt;br /&gt;
&lt;br /&gt;
Traversal of the list data structure is accomplished by using the FIRST and NEXT operations, which use the UPDATE operation. Algorithms are given in Figures 6 and 7. The NEXT operation returns FALSE if the cursor is already at the end of the list and cannot be advanced. Adding new cells into the list requires the insertion of both the cell and a new auxiliary node. This insertion is restricted to occur in the following way: The new auxiliary node will follow the new cell in the list, and insertion can only occur between an auxiliary node and a normal cell, as shown in Figure 8. &lt;br /&gt;
&lt;br /&gt;
[[File:fig6.PNG]]&lt;br /&gt;
[[File:fig7.PNG]]&lt;br /&gt;
[[File:fig8.PNG]]&lt;br /&gt;
&lt;br /&gt;
Figure 9 gives an algorithm, which takes as arguments a cursor and pointers to a new cell and auxiliary node. The algorithm will try to insert the new cell and auxiliary node at the position specified by the cursor, returning the value&lt;br /&gt;
TRUE if successful.&lt;br /&gt;
&lt;br /&gt;
[[File:fig9.PNG]]&lt;br /&gt;
&lt;br /&gt;
If the cursor becomes invalid, then the operation returns without inserting the new cell and returns the value FALSE. This allows a higher-level operation to detect that a change to the structure of the list occurred and to take it into account before attempting to insert the new cell again. For example, in the next section we show how the items in the list can be kept sorted using this technique.&lt;br /&gt;
&lt;br /&gt;
Given a valid cursor, the cell that it is visiting can also be deleted from the list. As with the insertion of new cells, if the list structure changes (i.e., the cursor becomes invalid) then the operation fails and must be tried again. Figure 10 gives the TRYDELETE algorithm. The deletion of the cell from the list leaves an “extra” auxiliary node; concurrent processes deleting adjacent cells can result in longer chains. Most of the TRYDELETE algorithm is concerned with removing the extra auxiliary nodes from the list. Normally, removing the extra auxiliary node that results from the deletion of a cell from the list is accomplished by simply swinging the pointer in the cell pointed at by the pre-cell pointer in the cursor. &lt;br /&gt;
&lt;br /&gt;
[[File:fig10.PNG]]&lt;br /&gt;
&lt;br /&gt;
However, this does not always work; in particular, this cell may have itself been deleted from the list, in which case swinging its next pointer will not remove the extra auxiliary node: In order to overcome this problem, we add a back~ink field to the normal cells in the list. When a cell is deleted from the list, the pre.cell field of the cursor is copied into the cell’s backdink field. The TRYDELETE algorithm can then use these pointers to reverse back to a cell that has not been deleted from the list. &lt;br /&gt;
&lt;br /&gt;
With just two processes, it is possible to create a chain of auxiliary nodes (with no intervening normal cells) of any length. However, any such chain can exist in the list only as long as some process is executing the TRYDELETE algorithm.&lt;br /&gt;
&lt;br /&gt;
If all deletions have been completed, then the list will contain no extra auxiliary nodes. To see this, assume that there is a chain of two or more-+ auxiliary nodes in the list. Let z be the normal cell that was deleted from between the first two auxiliary nodes in the chain. Note that this implies that the normal cell that immediately preceded x in the list has not been deleted.&lt;br /&gt;
By assumption, the operation that deleted z has completed. Consider the loop at lines 17–21 of the TRYDELETE algorithm. The only way for the process to exit this 100P, and hence to complete the operation, is for another deletion operation to have extended the chain of auxiliary nodes by deleting the normal cell g immediately following the chain, since the cell z is at the front of the chain.&lt;br /&gt;
Furthermore, the deletion of y must have occurred after the operation deleting x had set its back_link pointer at line 6; otherwise the auxiliary node following y would have been included in the chain found in lines 13–16. Thus, the chain of back_link pointers followed by the process that deleted y will lead to the same normal cell that preceded x. &lt;br /&gt;
&lt;br /&gt;
Now, the only way for the operation that deleted y to have completed is for the same reason as above; i.e., another TRYDELETE operation must extend the chain of auxiliary nodes by deleting a cell z. Since the length of the list must be finite, there must be a last such deletion which, but by the argument above, cannot have completed. Thus this operation must still be in progress, contradicting the assumption that there were no TRYDELETE operations in progress.&lt;br /&gt;
&lt;br /&gt;
[[File:fig11.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Trees ==&lt;br /&gt;
&lt;br /&gt;
This chapter gives a serial code for a tree traversal, and a parallel solution to implement same function. &lt;br /&gt;
&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
Below is a code for tree traversal algorithms&lt;br /&gt;
its behavior is as figure below shows:&lt;br /&gt;
&lt;br /&gt;
[[File: tree.PNG]]&lt;br /&gt;
&lt;br /&gt;
procedure Tree_Traversal is&lt;br /&gt;
   type Node;&lt;br /&gt;
   type Node_Access is access Node;&lt;br /&gt;
   type Node is record&lt;br /&gt;
      Left : Node_Access := null;&lt;br /&gt;
      Right : Node_Access := null;&lt;br /&gt;
      Data : Integer;&lt;br /&gt;
   end record;&lt;br /&gt;
   procedure Destroy_Tree(N : in out Node_Access) is&lt;br /&gt;
      procedure free is new Ada.Unchecked_Deallocation(Node, Node_Access);&lt;br /&gt;
   begin&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Destroy_Tree(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      if N.Right /= null then &lt;br /&gt;
         Destroy_Tree(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
      Free(N);&lt;br /&gt;
   end Destroy_Tree;&lt;br /&gt;
   function Tree(Value : Integer; Left : Node_Access; Right : Node_Access) return Node_Access is&lt;br /&gt;
      Temp : Node_Access := new Node;&lt;br /&gt;
   begin&lt;br /&gt;
      Temp.Data := Value;&lt;br /&gt;
      Temp.Left := Left;&lt;br /&gt;
      Temp.Right := Right;&lt;br /&gt;
      return Temp;&lt;br /&gt;
   end Tree;&lt;br /&gt;
   procedure Preorder(N : Node_Access) is&lt;br /&gt;
   begin&lt;br /&gt;
      Put(Integer'Image(N.Data));&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Preorder(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      if N.Right /= null then&lt;br /&gt;
         Preorder(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
   end Preorder;&lt;br /&gt;
   procedure Inorder(N : Node_Access) is&lt;br /&gt;
   begin&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Inorder(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      Put(Integer'Image(N.Data));&lt;br /&gt;
      if N.Right /= null then&lt;br /&gt;
         Inorder(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
   end Inorder;&lt;br /&gt;
   procedure Postorder(N : Node_Access) is&lt;br /&gt;
   begin&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Postorder(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      if N.Right /= null then&lt;br /&gt;
         Postorder(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
      Put(Integer'Image(N.Data));&lt;br /&gt;
   end Postorder;&lt;br /&gt;
   procedure Levelorder(N : Node_Access) is&lt;br /&gt;
      package Queues is new Ada.Containers.Doubly_Linked_Lists(Node_Access);&lt;br /&gt;
      use Queues;&lt;br /&gt;
      Node_Queue : List;&lt;br /&gt;
      Next : Node_Access;&lt;br /&gt;
   begin&lt;br /&gt;
      Node_Queue.Append(N);&lt;br /&gt;
      while not Is_Empty(Node_Queue) loop&lt;br /&gt;
         Next := First_Element(Node_Queue);&lt;br /&gt;
         Delete_First(Node_Queue);&lt;br /&gt;
         Put(Integer'Image(Next.Data));&lt;br /&gt;
         if Next.Left /= null then&lt;br /&gt;
            Node_Queue.Append(Next.Left);&lt;br /&gt;
         end if;&lt;br /&gt;
         if Next.Right /= null then&lt;br /&gt;
            Node_Queue.Append(Next.Right);&lt;br /&gt;
         end if;&lt;br /&gt;
      end loop;&lt;br /&gt;
   end Levelorder;&lt;br /&gt;
   N : Node_Access;&lt;br /&gt;
begin&lt;br /&gt;
   N := Tree(1, &lt;br /&gt;
      Tree(2,&lt;br /&gt;
         Tree(4,&lt;br /&gt;
            Tree(7, null, null),&lt;br /&gt;
            null),&lt;br /&gt;
         Tree(5, null, null)),&lt;br /&gt;
      Tree(3,&lt;br /&gt;
         Tree(6,&lt;br /&gt;
            Tree(8, null, null),&lt;br /&gt;
            Tree(9, null, null)),&lt;br /&gt;
         null));&lt;br /&gt;
 &lt;br /&gt;
   Put(&amp;quot;preorder:    &amp;quot;);&lt;br /&gt;
   Preorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Put(&amp;quot;inorder:     &amp;quot;);&lt;br /&gt;
   Inorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Put(&amp;quot;postorder:   &amp;quot;);&lt;br /&gt;
   Postorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Put(&amp;quot;level order: &amp;quot;);&lt;br /&gt;
   Levelorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Destroy_Tree(N);&lt;br /&gt;
end Tree_traversal;&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
&lt;br /&gt;
This part we implement a parallel algorithm with the same definition of traversal. &lt;br /&gt;
First, we difine a function NEXT[x].The function NEXT[ x,], defining the successor of a field x, (of node x) in the Euler tour, is given as&lt;br /&gt;
&lt;br /&gt;
[[File: para_tree1.PNG]]&lt;br /&gt;
&lt;br /&gt;
Note that this NEXT function does not provide the successor of the last field of the root-node r in the tour. This is because we break the tour into a linked list such that u, is the starting field and r is the terminal field, where m = no-of-chiidren[r] + 1. The proposed linked list structure can be represented as an array [I . 2n - l] of SNODEREC:&lt;br /&gt;
&lt;br /&gt;
[[File: para2.PNG]]&lt;br /&gt;
This data structure can be constructed from the following algorithm when the input tree is represented&lt;br /&gt;
by a “parent-of” relation with explicit ordering of children. Each field of a tree-node in this algorithm is a record of type SNODEREC.&lt;br /&gt;
&lt;br /&gt;
Algorithm GEN-COMP-NEXT&lt;br /&gt;
[[File: para3.PNG]]&lt;br /&gt;
&lt;br /&gt;
To obtain the required tree-traversals, the following rules are operated on the linked list produced by algorithm GEN-COMP-NEXT: &lt;br /&gt;
&lt;br /&gt;
pre-order traversal: select the first copy of&lt;br /&gt;
each node;&lt;br /&gt;
&lt;br /&gt;
post-order traversal: select the last copy of&lt;br /&gt;
each node;&lt;br /&gt;
&lt;br /&gt;
in-order traversal: delete the first copy of each node if it is not&lt;br /&gt;
a leaf and delete the last copy of each node if it has more than one child.&lt;br /&gt;
&lt;br /&gt;
== Hash Tables ==&lt;br /&gt;
=== Hash Table Intro ===&lt;br /&gt;
&lt;br /&gt;
Hash tables are very efficient data structures often used in searching algorithms for fast lookup operations.  Hash tables contain a series of &amp;quot;buckets&amp;quot; that function like indexes into an array, each of which can be accessed directly using their key value.  The bucket for which a piece of data will be placed is determine by a special hashing function.&lt;br /&gt;
&lt;br /&gt;
The major advantage of a hash table is that lookup times are essentially a constant value, much like an array with a known index.  With a proper hashing function in place, it should be fairly rare that any 2 keys would generate the same value.&lt;br /&gt;
&lt;br /&gt;
In the case that 2 keys do map to the same position, there is a conflict that must be dealt with in some fashion to obtain the correct value.  One way that is relevant to linked list structures is to have a chained hash table in which a linked list is created with all values that have been placed in that particular bucket.  The developer would have to not only take into account the proper bucket for the data being searched for, but also must considered the chained linked list.&lt;br /&gt;
&lt;br /&gt;
[[File:315px-Hash table 3 1 1 0 1 0 0 SP.svg.png]]&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
'''  Insert Example: Create new node if hash bucket doesnt exist, else append to the chain.'''&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Put a key/value pair into the table by hashing the key to get the array&lt;br /&gt;
   *  index of the chain that should hold the node containing the pair.&lt;br /&gt;
   *  If an existing node with the same key is present then overwrite its value,&lt;br /&gt;
   *  otherwise add a new node.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   *@param  val  data object reference&lt;br /&gt;
   */&lt;br /&gt;
  public void put(Object key, Object val)&lt;br /&gt;
  {&lt;br /&gt;
    int index = getIndex(key);&lt;br /&gt;
    Node node = find(key, data[index]);&lt;br /&gt;
    // Use helper method to determine if node with same key is already in&lt;br /&gt;
    // chain. If not, add a new node to head of chain.&lt;br /&gt;
    if (node == null)&lt;br /&gt;
    {&lt;br /&gt;
      data[index] = new Node(data[index], key, val);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      // Otherwise update data value of existing node.&lt;br /&gt;
      node.val = val;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Given a key object, return a data object from the table or&lt;br /&gt;
   *  null if it is not found.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   *@return      data object reference or null if no object found&lt;br /&gt;
   */&lt;br /&gt;
  public Object get(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    Node temp = find(key, data[getIndex(key)]);&lt;br /&gt;
    if (temp != null)&lt;br /&gt;
    {&lt;br /&gt;
      return temp.val;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      return null;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''  Delete Example: Delete a node from the chain.'''&lt;br /&gt;
  /**&lt;br /&gt;
   * Remove a key/value pair from table if present, otherwise make no change.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   */&lt;br /&gt;
  public void remove(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    int index = getIndex(key);&lt;br /&gt;
    Node ref = data[index];&lt;br /&gt;
    Node previous = null;&lt;br /&gt;
    while (ref != null)&lt;br /&gt;
    {&lt;br /&gt;
      if ((ref.key).equals(key))&lt;br /&gt;
      {&lt;br /&gt;
        if (previous == null)&lt;br /&gt;
        {&lt;br /&gt;
          data[index] = ref.next;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
          previous.next = ref.next;&lt;br /&gt;
        }&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      previous = ref;&lt;br /&gt;
      ref = ref.next;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Given a key, use a hash function to obtain the array index of the chain&lt;br /&gt;
   *  corresponding to the key.&lt;br /&gt;
   *  The hashCode method inherited (and possibly overridden)&lt;br /&gt;
   *  from class Object is called to do the hashing, with the returned&lt;br /&gt;
   *  value constrained to the hash table array bounds.&lt;br /&gt;
   *  The distribution of objects in the hash table will depend&lt;br /&gt;
   *  on the quality of the hash function implemented by hashCode.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  reference to object to be hashed&lt;br /&gt;
   *@return      array index of chain corresponding to key&lt;br /&gt;
   */&lt;br /&gt;
  private int getIndex(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    return Math.abs(key.hashCode() % data.length);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Find node given a key and a chain to search.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key    key object reference&lt;br /&gt;
   *@param  ref    node object reference where search will start&lt;br /&gt;
   *@return        node object holding key or null if not found&lt;br /&gt;
   */&lt;br /&gt;
  private Node find(Object key, Node ref)&lt;br /&gt;
  {&lt;br /&gt;
    while (ref != null)&lt;br /&gt;
    {&lt;br /&gt;
      if ((ref.key).equals(key))&lt;br /&gt;
      {&lt;br /&gt;
        return ref;&lt;br /&gt;
      }&lt;br /&gt;
      ref = ref.next;&lt;br /&gt;
    }&lt;br /&gt;
    return null;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
&lt;br /&gt;
The key issue in a hash table in a parallel environment is to make sure any update/insert/delete sequences have been completed properly prior to attempting subsequent operations to make sure the data has been synched appropriately.  However, since access speed is such a critical component of the design of a hash table, it is essential to try and avoid using too many locks for performing synchronization.  Fortunately, a number of lock-free hash designs have been implemented to avoid this bottleneck.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Graphs ==&lt;br /&gt;
=== Graph Intro ===&lt;br /&gt;
&lt;br /&gt;
A graph data structure is another type of linked-list structure that focuses on data that requires linking according to various types of relationships.  For example, in a networking application, one network node may have connections to a variety of other network nodes.  These nodes then also link to a variety of other nodes in the network.  Using this connection of nodes, it would be possible to then find a path from one specific node to another in the chain.  This could be accomplished by having each node contain a linked list of pointers to all other reachable nodes.&lt;br /&gt;
&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Add a new edge to the graph.&lt;br /&gt;
     */&lt;br /&gt;
    public void addEdge( String sourceName, String destName, double cost )&lt;br /&gt;
    {&lt;br /&gt;
        Vertex v = getVertex( sourceName );&lt;br /&gt;
        Vertex w = getVertex( destName );&lt;br /&gt;
        v.adj.add( new Edge( w, cost ) );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Single-source unweighted shortest-path algorithm.&lt;br /&gt;
     */&lt;br /&gt;
    public void unweighted( String startName )&lt;br /&gt;
    {&lt;br /&gt;
        clearAll( ); &lt;br /&gt;
&lt;br /&gt;
        Vertex start = (Vertex) vertexMap.get( startName );&lt;br /&gt;
        if( start == null )&lt;br /&gt;
            throw new NoSuchElementException( &amp;quot;Start vertex not found&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
        LinkedList q = new LinkedList( );&lt;br /&gt;
        q.addLast( start ); start.dist = 0;&lt;br /&gt;
&lt;br /&gt;
        while( !q.isEmpty( ) )&lt;br /&gt;
        {&lt;br /&gt;
            Vertex v = (Vertex) q.removeFirst( );&lt;br /&gt;
&lt;br /&gt;
            for( Iterator itr = v.adj.iterator( ); itr.hasNext( ); )&lt;br /&gt;
            {&lt;br /&gt;
                Edge e = (Edge) itr.next( );&lt;br /&gt;
                Vertex w = e.dest;&lt;br /&gt;
                if( w.dist == INFINITY )&lt;br /&gt;
                {&lt;br /&gt;
                    w.dist = v.dist + 1;&lt;br /&gt;
                    w.prev = v;&lt;br /&gt;
                    q.addLast( w );&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
&lt;br /&gt;
= Quiz =&lt;br /&gt;
= References =&lt;br /&gt;
http://oreilly.com/catalog/masteralgoc/chapter/ch08.pdf&lt;br /&gt;
&lt;br /&gt;
http://www.devjavasoft.org/code/classhashtable.html&lt;br /&gt;
&lt;br /&gt;
http://osr600doc.sco.com/en/SDK_c++/_Intro_graph.html&lt;br /&gt;
&lt;br /&gt;
web.eecs.utk.edu/~berry/cs302s02/src/code/Chap14/Graph.java&lt;br /&gt;
&lt;br /&gt;
http://people.engr.ncsu.edu/efg/506/s01/lectures/notes/lec8.html&lt;br /&gt;
&lt;br /&gt;
http://en.wikipedia.org/wiki/File:Hash_table_3_1_1_0_1_0_0_SP.svg&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/ch5a_ja&amp;diff=59117</id>
		<title>CSC/ECE 506 Spring 2012/ch5a ja</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/ch5a_ja&amp;diff=59117"/>
		<updated>2012-02-27T21:12:03Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* Linked Data Structures */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Chapter 5a CSC/ECE 506 Spring 2012 / ch5a ==&lt;br /&gt;
&lt;br /&gt;
An exploration and summary of concurrency issues as it relates to linked-list based data structures such as hash tables, trees, and graphs.  This topic examines concurrency problems related to each type and possible solutions to allow for parallelization.&lt;br /&gt;
&lt;br /&gt;
= Introduction to Linked-List Parallel Programming =&lt;br /&gt;
&lt;br /&gt;
In determining opportunities for parallel programming during the software design process, many programmers will focus exclusively on loop or array structures, rather than also considering that linked-list pointer-based structures could also provide opportunities to run code in parallel across different processors.&lt;br /&gt;
&lt;br /&gt;
For example, one common parallel technique used in an array processing algorithm is the copy-scan technique.  This technique involves copying rows of data from one processor to another in a log(n) fashion until all processors have their own copy of that row.  From there, you could perform a reduction technique to generate a sum of all the data, all while working in a parallel fashion.  Take the following grid:&lt;br /&gt;
&lt;br /&gt;
The basic process for copy-scan would be to:&lt;br /&gt;
  Step 1) Copy the row 1 array to row 2.&lt;br /&gt;
  Step 2) Copy the row 1 array to row 3, row 2 to row 4, etc on the next run.&lt;br /&gt;
  Step 3) Continue in this manner until all rows have been copied in a log(n) fashion.&lt;br /&gt;
  Step 4) Perform the parallel operations to generate the desired result (reduction for sum, etc.).&lt;br /&gt;
&lt;br /&gt;
[[File:CopyScan.gif]]&lt;br /&gt;
&lt;br /&gt;
But how does this same process work in the linked list world?&lt;br /&gt;
&lt;br /&gt;
With linked lists, there is a concept called pointer doubling, which works in a very similar manner to copy-scan.&lt;br /&gt;
&lt;br /&gt;
  Step 1) Each processor will make a copy of the pointer it holds to it's neighbor.&lt;br /&gt;
  Step 2) Next, each processor will make a pointer to the processor 2 steps away.&lt;br /&gt;
  Step 3) This continues in logarithmic fashion until each processor has a pointer to the end of the chain.&lt;br /&gt;
  Step 4) Perform the parallel operations to generate the desired result.&lt;br /&gt;
&lt;br /&gt;
[[File:linkedlist.gif]]&lt;br /&gt;
&lt;br /&gt;
However, with linked list programming, similar to array-based programming, it becomes imperative to have some sort of locking mechanism on critical sections to avoid race conditions.  To make sure the results are correct, it is important that operations can be serialized appropriately and that data remains current and synchronized.&lt;br /&gt;
&lt;br /&gt;
In this chapter, we will explore 3 linked-list based data structures and the concurrency issues they present: hash tables, trees, and graphs.&lt;br /&gt;
&lt;br /&gt;
= Linked Data Structure algorithms extension =&lt;br /&gt;
== Lock free algorithms ==&lt;br /&gt;
&lt;br /&gt;
In order to overcome the ABA problems (shown in figure blow), we add auxiliary nodes to the data we structure. An auxiliary node is a cell that contains only a next field. We require that every normal cell in the list have an auxiliary node as its predecessor and as its successor. We permit “chains” of auxiliary nodes in the list (i.e., we do not require that every auxiliary node have a normal cell as its predecessor and successor), although such chains are undesirable for performance reasons.&lt;br /&gt;
&lt;br /&gt;
[[File:fig3.PNG]]&lt;br /&gt;
&lt;br /&gt;
The list also contains two dummy cells as the first and last normal cells in the list. These two cells are pointed at by the root pointers First and Last. These dummy cells need not, respectively, be preceded and followed by auxiliary nodes. Thus, m empty list data structure consists of these two dummy cells separated by an auxiliary node.&lt;br /&gt;
&lt;br /&gt;
A cursor is implemented as three pointers into the data structure: target is a pointer to the cell at the position the cursor is visiting. If the cursor is visiting the end-of-list position, then target will be equal to Last. The pointer pre-aux points to an auxiliary node in the data structure. For a cursor c, if c“.pre-aux = c“.target, then the cursor is valid; otherwise it is invalid. The pointer pre.cell points to a regular cell in the data structure. This pointer is used only by the TRYDELETE operation described below. An invalid cursor indicates that the structure of the list in t he vicinity of the cursor has changed (due to a concurrent insert ion or deletion by another process) since the pointers in the cursor were last read. The UPDATE algorithm, given in Figure 5, examines the state of the list and updates the pointers in the cursor so that it becomes valid. Since the list structure contains auxiliary nodes (perhaps more than one in a row), the UPDATE algorithm must skip over them. If two adjacent auxiliary nodes axe found in the list, the UPDATE algorithm will remove one of them. &lt;br /&gt;
&lt;br /&gt;
[[File:fig5.PNG]]&lt;br /&gt;
&lt;br /&gt;
Traversal of the list data structure is accomplished by using the FIRST and NEXT operations, which use the UPDATE operation. Algorithms are given in Figures 6 and 7. The NEXT operation returns FALSE if the cursor is already at the end of the list and cannot be advanced. Adding new cells into the list requires the insertion of both the cell and a new auxiliary node. This insertion is restricted to occur in the following way: The new auxiliary node will follow the new cell in the list, and insertion can only occur between an auxiliary node and a normal cell, as shown in Figure 8. &lt;br /&gt;
&lt;br /&gt;
[[File:fig6.PNG]]&lt;br /&gt;
[[File:fig7.PNG]]&lt;br /&gt;
[[File:fig8.PNG]]&lt;br /&gt;
&lt;br /&gt;
Figure 9 gives an algorithm, which takes as arguments a cursor and pointers to a new cell and auxiliary node. The algorithm will try to insert the new cell and auxiliary node at the position specified by the cursor, returning the value&lt;br /&gt;
TRUE if successful.&lt;br /&gt;
&lt;br /&gt;
[[File:fig9.PNG]]&lt;br /&gt;
&lt;br /&gt;
If the cursor becomes invalid, then the operation returns without inserting the new cell and returns the value FALSE. This allows a higher-level operation to detect that a change to the structure of the list occurred and to take it into account before attempting to insert the new cell again. For example, in the next section we show how the items in the list can be kept sorted using this technique.&lt;br /&gt;
&lt;br /&gt;
Given a valid cursor, the cell that it is visiting can also be deleted from the list. As with the insertion of new cells, if the list structure changes (i.e., the cursor becomes invalid) then the operation fails and must be tried again. Figure 10 gives the TRYDELETE algorithm. The deletion of the cell from the list leaves an “extra” auxiliary node; concurrent processes deleting adjacent cells can result in longer chains. Most of the TRYDELETE algorithm is concerned with removing the extra auxiliary nodes from the list. Normally, removing the extra auxiliary node that results from the deletion of a cell from the list is accomplished by simply swinging the pointer in the cell pointed at by the pre-cell pointer in the cursor. &lt;br /&gt;
&lt;br /&gt;
[[File:fig10.PNG]]&lt;br /&gt;
&lt;br /&gt;
However, this does not always work; in particular, this cell may have itself been deleted from the list, in which case swinging its next pointer will not remove the extra auxiliary node: In order to overcome this problem, we add a back~ink field to the normal cells in the list. When a cell is deleted from the list, the pre.cell field of the cursor is copied into the cell’s backdink field. The TRYDELETE algorithm can then use these pointers to reverse back to a cell that has not been deleted from the list. &lt;br /&gt;
&lt;br /&gt;
With just two processes, it is possible to create a chain of auxiliary nodes (with no intervening normal cells) of any length. However, any such chain can exist in the list only as long as some process is executing the TRYDELETE algorithm.&lt;br /&gt;
&lt;br /&gt;
If all deletions have been completed, then the list will contain no extra auxiliary nodes. To see this, assume that there is a chain of two or more-+ auxiliary nodes in the list. Let z be the normal cell that was deleted from between the first two auxiliary nodes in the chain. Note that this implies that the normal cell that immediately preceded x in the list has not been deleted.&lt;br /&gt;
By assumption, the operation that deleted z has completed. Consider the loop at lines 17–21 of the TRYDELETE algorithm. The only way for the process to exit this 100P, and hence to complete the operation, is for another deletion operation to have extended the chain of auxiliary nodes by deleting the normal cell g immediately following the chain, since the cell z is at the front of the chain.&lt;br /&gt;
Furthermore, the deletion of y must have occurred after the operation deleting x had set its back_link pointer at line 6; otherwise the auxiliary node following y would have been included in the chain found in lines 13–16. Thus, the chain of back_link pointers followed by the process that deleted y will lead to the same normal cell that preceded x. &lt;br /&gt;
&lt;br /&gt;
Now, the only way for the operation that deleted y to have completed is for the same reason as above; i.e., another TRYDELETE operation must extend the chain of auxiliary nodes by deleting a cell z. Since the length of the list must be finite, there must be a last such deletion which, but by the argument above, cannot have completed. Thus this operation must still be in progress, contradicting the assumption that there were no TRYDELETE operations in progress.&lt;br /&gt;
&lt;br /&gt;
[[File:fig11.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Trees ==&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
Below is a code for tree traversal algorithms&lt;br /&gt;
its behavior is as figure below shows:&lt;br /&gt;
&lt;br /&gt;
[[File: tree.PNG]]&lt;br /&gt;
&lt;br /&gt;
procedure Tree_Traversal is&lt;br /&gt;
   type Node;&lt;br /&gt;
   type Node_Access is access Node;&lt;br /&gt;
   type Node is record&lt;br /&gt;
      Left : Node_Access := null;&lt;br /&gt;
      Right : Node_Access := null;&lt;br /&gt;
      Data : Integer;&lt;br /&gt;
   end record;&lt;br /&gt;
   procedure Destroy_Tree(N : in out Node_Access) is&lt;br /&gt;
      procedure free is new Ada.Unchecked_Deallocation(Node, Node_Access);&lt;br /&gt;
   begin&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Destroy_Tree(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      if N.Right /= null then &lt;br /&gt;
         Destroy_Tree(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
      Free(N);&lt;br /&gt;
   end Destroy_Tree;&lt;br /&gt;
   function Tree(Value : Integer; Left : Node_Access; Right : Node_Access) return Node_Access is&lt;br /&gt;
      Temp : Node_Access := new Node;&lt;br /&gt;
   begin&lt;br /&gt;
      Temp.Data := Value;&lt;br /&gt;
      Temp.Left := Left;&lt;br /&gt;
      Temp.Right := Right;&lt;br /&gt;
      return Temp;&lt;br /&gt;
   end Tree;&lt;br /&gt;
   procedure Preorder(N : Node_Access) is&lt;br /&gt;
   begin&lt;br /&gt;
      Put(Integer'Image(N.Data));&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Preorder(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      if N.Right /= null then&lt;br /&gt;
         Preorder(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
   end Preorder;&lt;br /&gt;
   procedure Inorder(N : Node_Access) is&lt;br /&gt;
   begin&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Inorder(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      Put(Integer'Image(N.Data));&lt;br /&gt;
      if N.Right /= null then&lt;br /&gt;
         Inorder(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
   end Inorder;&lt;br /&gt;
   procedure Postorder(N : Node_Access) is&lt;br /&gt;
   begin&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Postorder(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      if N.Right /= null then&lt;br /&gt;
         Postorder(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
      Put(Integer'Image(N.Data));&lt;br /&gt;
   end Postorder;&lt;br /&gt;
   procedure Levelorder(N : Node_Access) is&lt;br /&gt;
      package Queues is new Ada.Containers.Doubly_Linked_Lists(Node_Access);&lt;br /&gt;
      use Queues;&lt;br /&gt;
      Node_Queue : List;&lt;br /&gt;
      Next : Node_Access;&lt;br /&gt;
   begin&lt;br /&gt;
      Node_Queue.Append(N);&lt;br /&gt;
      while not Is_Empty(Node_Queue) loop&lt;br /&gt;
         Next := First_Element(Node_Queue);&lt;br /&gt;
         Delete_First(Node_Queue);&lt;br /&gt;
         Put(Integer'Image(Next.Data));&lt;br /&gt;
         if Next.Left /= null then&lt;br /&gt;
            Node_Queue.Append(Next.Left);&lt;br /&gt;
         end if;&lt;br /&gt;
         if Next.Right /= null then&lt;br /&gt;
            Node_Queue.Append(Next.Right);&lt;br /&gt;
         end if;&lt;br /&gt;
      end loop;&lt;br /&gt;
   end Levelorder;&lt;br /&gt;
   N : Node_Access;&lt;br /&gt;
begin&lt;br /&gt;
   N := Tree(1, &lt;br /&gt;
      Tree(2,&lt;br /&gt;
         Tree(4,&lt;br /&gt;
            Tree(7, null, null),&lt;br /&gt;
            null),&lt;br /&gt;
         Tree(5, null, null)),&lt;br /&gt;
      Tree(3,&lt;br /&gt;
         Tree(6,&lt;br /&gt;
            Tree(8, null, null),&lt;br /&gt;
            Tree(9, null, null)),&lt;br /&gt;
         null));&lt;br /&gt;
 &lt;br /&gt;
   Put(&amp;quot;preorder:    &amp;quot;);&lt;br /&gt;
   Preorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Put(&amp;quot;inorder:     &amp;quot;);&lt;br /&gt;
   Inorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Put(&amp;quot;postorder:   &amp;quot;);&lt;br /&gt;
   Postorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Put(&amp;quot;level order: &amp;quot;);&lt;br /&gt;
   Levelorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Destroy_Tree(N);&lt;br /&gt;
end Tree_traversal;&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
== Hash Tables ==&lt;br /&gt;
=== Hash Table Intro ===&lt;br /&gt;
&lt;br /&gt;
Hash tables are very efficient data structures often used in searching algorithms for fast lookup operations.  Hash tables contain a series of &amp;quot;buckets&amp;quot; that function like indexes into an array, each of which can be accessed directly using their key value.  The bucket for which a piece of data will be placed is determine by a special hashing function.&lt;br /&gt;
&lt;br /&gt;
The major advantage of a hash table is that lookup times are essentially a constant value, much like an array with a known index.  With a proper hashing function in place, it should be fairly rare that any 2 keys would generate the same value.&lt;br /&gt;
&lt;br /&gt;
In the case that 2 keys do map to the same position, there is a conflict that must be dealt with in some fashion to obtain the correct value.  One way that is relevant to linked list structures is to have a chained hash table in which a linked list is created with all values that have been placed in that particular bucket.  The developer would have to not only take into account the proper bucket for the data being searched for, but also must considered the chained linked list.&lt;br /&gt;
&lt;br /&gt;
[[File:315px-Hash table 3 1 1 0 1 0 0 SP.svg.png]]&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
'''  Insert Example: Create new node if hash bucket doesnt exist, else append to the chain.'''&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Put a key/value pair into the table by hashing the key to get the array&lt;br /&gt;
   *  index of the chain that should hold the node containing the pair.&lt;br /&gt;
   *  If an existing node with the same key is present then overwrite its value,&lt;br /&gt;
   *  otherwise add a new node.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   *@param  val  data object reference&lt;br /&gt;
   */&lt;br /&gt;
  public void put(Object key, Object val)&lt;br /&gt;
  {&lt;br /&gt;
    int index = getIndex(key);&lt;br /&gt;
    Node node = find(key, data[index]);&lt;br /&gt;
    // Use helper method to determine if node with same key is already in&lt;br /&gt;
    // chain. If not, add a new node to head of chain.&lt;br /&gt;
    if (node == null)&lt;br /&gt;
    {&lt;br /&gt;
      data[index] = new Node(data[index], key, val);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      // Otherwise update data value of existing node.&lt;br /&gt;
      node.val = val;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Given a key object, return a data object from the table or&lt;br /&gt;
   *  null if it is not found.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   *@return      data object reference or null if no object found&lt;br /&gt;
   */&lt;br /&gt;
  public Object get(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    Node temp = find(key, data[getIndex(key)]);&lt;br /&gt;
    if (temp != null)&lt;br /&gt;
    {&lt;br /&gt;
      return temp.val;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      return null;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''  Delete Example: Delete a node from the chain.'''&lt;br /&gt;
  /**&lt;br /&gt;
   * Remove a key/value pair from table if present, otherwise make no change.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   */&lt;br /&gt;
  public void remove(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    int index = getIndex(key);&lt;br /&gt;
    Node ref = data[index];&lt;br /&gt;
    Node previous = null;&lt;br /&gt;
    while (ref != null)&lt;br /&gt;
    {&lt;br /&gt;
      if ((ref.key).equals(key))&lt;br /&gt;
      {&lt;br /&gt;
        if (previous == null)&lt;br /&gt;
        {&lt;br /&gt;
          data[index] = ref.next;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
          previous.next = ref.next;&lt;br /&gt;
        }&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      previous = ref;&lt;br /&gt;
      ref = ref.next;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Given a key, use a hash function to obtain the array index of the chain&lt;br /&gt;
   *  corresponding to the key.&lt;br /&gt;
   *  The hashCode method inherited (and possibly overridden)&lt;br /&gt;
   *  from class Object is called to do the hashing, with the returned&lt;br /&gt;
   *  value constrained to the hash table array bounds.&lt;br /&gt;
   *  The distribution of objects in the hash table will depend&lt;br /&gt;
   *  on the quality of the hash function implemented by hashCode.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  reference to object to be hashed&lt;br /&gt;
   *@return      array index of chain corresponding to key&lt;br /&gt;
   */&lt;br /&gt;
  private int getIndex(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    return Math.abs(key.hashCode() % data.length);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Find node given a key and a chain to search.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key    key object reference&lt;br /&gt;
   *@param  ref    node object reference where search will start&lt;br /&gt;
   *@return        node object holding key or null if not found&lt;br /&gt;
   */&lt;br /&gt;
  private Node find(Object key, Node ref)&lt;br /&gt;
  {&lt;br /&gt;
    while (ref != null)&lt;br /&gt;
    {&lt;br /&gt;
      if ((ref.key).equals(key))&lt;br /&gt;
      {&lt;br /&gt;
        return ref;&lt;br /&gt;
      }&lt;br /&gt;
      ref = ref.next;&lt;br /&gt;
    }&lt;br /&gt;
    return null;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
&lt;br /&gt;
The key issue in a hash table in a parallel environment is to make sure any update/insert/delete sequences have been completed properly prior to attempting subsequent operations to make sure the data has been synched appropriately.  However, since access speed is such a critical component of the design of a hash table, it is essential to try and avoid using too many locks for performing synchronization.  Fortunately, a number of lock-free hash designs have been implemented to avoid this bottleneck.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Graphs ==&lt;br /&gt;
=== Graph Intro ===&lt;br /&gt;
&lt;br /&gt;
A graph data structure is another type of linked-list structure that focuses on data that requires linking according to various types of relationships.  For example, in a networking application, one network node may have connections to a variety of other network nodes.  These nodes then also link to a variety of other nodes in the network.  Using this connection of nodes, it would be possible to then find a path from one specific node to another in the chain.  This could be accomplished by having each node contain a linked list of pointers to all other reachable nodes.&lt;br /&gt;
&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Add a new edge to the graph.&lt;br /&gt;
     */&lt;br /&gt;
    public void addEdge( String sourceName, String destName, double cost )&lt;br /&gt;
    {&lt;br /&gt;
        Vertex v = getVertex( sourceName );&lt;br /&gt;
        Vertex w = getVertex( destName );&lt;br /&gt;
        v.adj.add( new Edge( w, cost ) );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Single-source unweighted shortest-path algorithm.&lt;br /&gt;
     */&lt;br /&gt;
    public void unweighted( String startName )&lt;br /&gt;
    {&lt;br /&gt;
        clearAll( ); &lt;br /&gt;
&lt;br /&gt;
        Vertex start = (Vertex) vertexMap.get( startName );&lt;br /&gt;
        if( start == null )&lt;br /&gt;
            throw new NoSuchElementException( &amp;quot;Start vertex not found&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
        LinkedList q = new LinkedList( );&lt;br /&gt;
        q.addLast( start ); start.dist = 0;&lt;br /&gt;
&lt;br /&gt;
        while( !q.isEmpty( ) )&lt;br /&gt;
        {&lt;br /&gt;
            Vertex v = (Vertex) q.removeFirst( );&lt;br /&gt;
&lt;br /&gt;
            for( Iterator itr = v.adj.iterator( ); itr.hasNext( ); )&lt;br /&gt;
            {&lt;br /&gt;
                Edge e = (Edge) itr.next( );&lt;br /&gt;
                Vertex w = e.dest;&lt;br /&gt;
                if( w.dist == INFINITY )&lt;br /&gt;
                {&lt;br /&gt;
                    w.dist = v.dist + 1;&lt;br /&gt;
                    w.prev = v;&lt;br /&gt;
                    q.addLast( w );&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
&lt;br /&gt;
= Quiz =&lt;br /&gt;
= References =&lt;br /&gt;
http://oreilly.com/catalog/masteralgoc/chapter/ch08.pdf&lt;br /&gt;
&lt;br /&gt;
http://www.devjavasoft.org/code/classhashtable.html&lt;br /&gt;
&lt;br /&gt;
http://osr600doc.sco.com/en/SDK_c++/_Intro_graph.html&lt;br /&gt;
&lt;br /&gt;
web.eecs.utk.edu/~berry/cs302s02/src/code/Chap14/Graph.java&lt;br /&gt;
&lt;br /&gt;
http://people.engr.ncsu.edu/efg/506/s01/lectures/notes/lec8.html&lt;br /&gt;
&lt;br /&gt;
http://en.wikipedia.org/wiki/File:Hash_table_3_1_1_0_1_0_0_SP.svg&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/ch5a_ja&amp;diff=59116</id>
		<title>CSC/ECE 506 Spring 2012/ch5a ja</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/ch5a_ja&amp;diff=59116"/>
		<updated>2012-02-27T21:10:50Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* Serial Code Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Chapter 5a CSC/ECE 506 Spring 2012 / ch5a ==&lt;br /&gt;
&lt;br /&gt;
An exploration and summary of concurrency issues as it relates to linked-list based data structures such as hash tables, trees, and graphs.  This topic examines concurrency problems related to each type and possible solutions to allow for parallelization.&lt;br /&gt;
&lt;br /&gt;
= Introduction to Linked-List Parallel Programming =&lt;br /&gt;
&lt;br /&gt;
In determining opportunities for parallel programming during the software design process, many programmers will focus exclusively on loop or array structures, rather than also considering that linked-list pointer-based structures could also provide opportunities to run code in parallel across different processors.&lt;br /&gt;
&lt;br /&gt;
For example, one common parallel technique used in an array processing algorithm is the copy-scan technique.  This technique involves copying rows of data from one processor to another in a log(n) fashion until all processors have their own copy of that row.  From there, you could perform a reduction technique to generate a sum of all the data, all while working in a parallel fashion.  Take the following grid:&lt;br /&gt;
&lt;br /&gt;
The basic process for copy-scan would be to:&lt;br /&gt;
  Step 1) Copy the row 1 array to row 2.&lt;br /&gt;
  Step 2) Copy the row 1 array to row 3, row 2 to row 4, etc on the next run.&lt;br /&gt;
  Step 3) Continue in this manner until all rows have been copied in a log(n) fashion.&lt;br /&gt;
  Step 4) Perform the parallel operations to generate the desired result (reduction for sum, etc.).&lt;br /&gt;
&lt;br /&gt;
[[File:CopyScan.gif]]&lt;br /&gt;
&lt;br /&gt;
But how does this same process work in the linked list world?&lt;br /&gt;
&lt;br /&gt;
With linked lists, there is a concept called pointer doubling, which works in a very similar manner to copy-scan.&lt;br /&gt;
&lt;br /&gt;
  Step 1) Each processor will make a copy of the pointer it holds to it's neighbor.&lt;br /&gt;
  Step 2) Next, each processor will make a pointer to the processor 2 steps away.&lt;br /&gt;
  Step 3) This continues in logarithmic fashion until each processor has a pointer to the end of the chain.&lt;br /&gt;
  Step 4) Perform the parallel operations to generate the desired result.&lt;br /&gt;
&lt;br /&gt;
[[File:linkedlist.gif]]&lt;br /&gt;
&lt;br /&gt;
However, with linked list programming, similar to array-based programming, it becomes imperative to have some sort of locking mechanism on critical sections to avoid race conditions.  To make sure the results are correct, it is important that operations can be serialized appropriately and that data remains current and synchronized.&lt;br /&gt;
&lt;br /&gt;
In this chapter, we will explore 3 linked-list based data structures and the concurrency issues they present: hash tables, trees, and graphs.&lt;br /&gt;
&lt;br /&gt;
= Linked Data Structure algorithms extension =&lt;br /&gt;
== Lock free algorithms ==&lt;br /&gt;
&lt;br /&gt;
In order to overcome the ABA problems (shown in figure blow), we add auxiliary nodes to the data we structure. An auxiliary node is a cell that contains only a next field. We require that every normal cell in the list have an auxiliary node as its predecessor and as its successor. We permit “chains” of auxiliary nodes in the list (i.e., we do not require that every auxiliary node have a normal cell as its predecessor and successor), although such chains are undesirable for performance reasons.&lt;br /&gt;
&lt;br /&gt;
[[File:fig3.PNG]]&lt;br /&gt;
&lt;br /&gt;
The list also contains two dummy cells as the first and last normal cells in the list. These two cells are pointed at by the root pointers First and Last. These dummy cells need not, respectively, be preceded and followed by auxiliary nodes. Thus, m empty list data structure consists of these two dummy cells separated by an auxiliary node.&lt;br /&gt;
&lt;br /&gt;
A cursor is implemented as three pointers into the data structure: target is a pointer to the cell at the position the cursor is visiting. If the cursor is visiting the end-of-list position, then target will be equal to Last. The pointer pre-aux points to an auxiliary node in the data structure. For a cursor c, if c“.pre-aux = c“.target, then the cursor is valid; otherwise it is invalid. The pointer pre.cell points to a regular cell in the data structure. This pointer is used only by the TRYDELETE operation described below. An invalid cursor indicates that the structure of the list in t he vicinity of the cursor has changed (due to a concurrent insert ion or deletion by another process) since the pointers in the cursor were last read. The UPDATE algorithm, given in Figure 5, examines the state of the list and updates the pointers in the cursor so that it becomes valid. Since the list structure contains auxiliary nodes (perhaps more than one in a row), the UPDATE algorithm must skip over them. If two adjacent auxiliary nodes axe found in the list, the UPDATE algorithm will remove one of them. &lt;br /&gt;
&lt;br /&gt;
[[File:fig5.PNG]]&lt;br /&gt;
&lt;br /&gt;
Traversal of the list data structure is accomplished by using the FIRST and NEXT operations, which use the UPDATE operation. Algorithms are given in Figures 6 and 7. The NEXT operation returns FALSE if the cursor is already at the end of the list and cannot be advanced. Adding new cells into the list requires the insertion of both the cell and a new auxiliary node. This insertion is restricted to occur in the following way: The new auxiliary node will follow the new cell in the list, and insertion can only occur between an auxiliary node and a normal cell, as shown in Figure 8. &lt;br /&gt;
&lt;br /&gt;
[[File:fig6.PNG]]&lt;br /&gt;
[[File:fig7.PNG]]&lt;br /&gt;
[[File:fig8.PNG]]&lt;br /&gt;
&lt;br /&gt;
Figure 9 gives an algorithm, which takes as arguments a cursor and pointers to a new cell and auxiliary node. The algorithm will try to insert the new cell and auxiliary node at the position specified by the cursor, returning the value&lt;br /&gt;
TRUE if successful.&lt;br /&gt;
&lt;br /&gt;
[[File:fig9.PNG]]&lt;br /&gt;
&lt;br /&gt;
If the cursor becomes invalid, then the operation returns without inserting the new cell and returns the value FALSE. This allows a higher-level operation to detect that a change to the structure of the list occurred and to take it into account before attempting to insert the new cell again. For example, in the next section we show how the items in the list can be kept sorted using this technique.&lt;br /&gt;
&lt;br /&gt;
Given a valid cursor, the cell that it is visiting can also be deleted from the list. As with the insertion of new cells, if the list structure changes (i.e., the cursor becomes invalid) then the operation fails and must be tried again. Figure 10 gives the TRYDELETE algorithm. The deletion of the cell from the list leaves an “extra” auxiliary node; concurrent processes deleting adjacent cells can result in longer chains. Most of the TRYDELETE algorithm is concerned with removing the extra auxiliary nodes from the list. Normally, removing the extra auxiliary node that results from the deletion of a cell from the list is accomplished by simply swinging the pointer in the cell pointed at by the pre-cell pointer in the cursor. &lt;br /&gt;
&lt;br /&gt;
[[File:fig10.PNG]]&lt;br /&gt;
&lt;br /&gt;
However, this does not always work; in particular, this cell may have itself been deleted from the list, in which case swinging its next pointer will not remove the extra auxiliary node: In order to overcome this problem, we add a back~ink field to the normal cells in the list. When a cell is deleted from the list, the pre.cell field of the cursor is copied into the cell’s backdink field. The TRYDELETE algorithm can then use these pointers to reverse back to a cell that has not been deleted from the list. &lt;br /&gt;
&lt;br /&gt;
With just two processes, it is possible to create a chain of auxiliary nodes (with no intervening normal cells) of any length. However, any such chain can exist in the list only as long as some process is executing the TRYDELETE algorithm.&lt;br /&gt;
&lt;br /&gt;
If all deletions have been completed, then the list will contain no extra auxiliary nodes. To see this, assume that there is a chain of two or more-+ auxiliary nodes in the list. Let z be the normal cell that was deleted from between the first two auxiliary nodes in the chain. Note that this implies that the normal cell that immediately preceded x in the list has not been deleted.&lt;br /&gt;
By assumption, the operation that deleted z has completed. Consider the loop at lines 17–21 of the TRYDELETE algorithm. The only way for the process to exit this 100P, and hence to complete the operation, is for another deletion operation to have extended the chain of auxiliary nodes by deleting the normal cell g immediately following the chain, since the cell z is at the front of the chain.&lt;br /&gt;
Furthermore, the deletion of y must have occurred after the operation deleting x had set its back_link pointer at line 6; otherwise the auxiliary node following y would have been included in the chain found in lines 13–16. Thus, the chain of back_link pointers followed by the process that deleted y will lead to the same normal cell that preceded x. &lt;br /&gt;
&lt;br /&gt;
Now, the only way for the operation that deleted y to have completed is for the same reason as above; i.e., another TRYDELETE operation must extend the chain of auxiliary nodes by deleting a cell z. Since the length of the list must be finite, there must be a last such deletion which, but by the argument above, cannot have completed. Thus this operation must still be in progress, contradicting the assumption that there were no TRYDELETE operations in progress.&lt;br /&gt;
&lt;br /&gt;
[[File:fig11.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Linked Data Structures =&lt;br /&gt;
&lt;br /&gt;
Given this background knowledge, we can begin to explore solutions to some specific data structures that also utilized linked lists in some fashion.&lt;br /&gt;
&lt;br /&gt;
== Trees ==&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
Below is a code for tree traversal algorithms&lt;br /&gt;
its behavior is as figure below shows:&lt;br /&gt;
&lt;br /&gt;
[[File: tree.PNG]]&lt;br /&gt;
&lt;br /&gt;
procedure Tree_Traversal is&lt;br /&gt;
   type Node;&lt;br /&gt;
   type Node_Access is access Node;&lt;br /&gt;
   type Node is record&lt;br /&gt;
      Left : Node_Access := null;&lt;br /&gt;
      Right : Node_Access := null;&lt;br /&gt;
      Data : Integer;&lt;br /&gt;
   end record;&lt;br /&gt;
   procedure Destroy_Tree(N : in out Node_Access) is&lt;br /&gt;
      procedure free is new Ada.Unchecked_Deallocation(Node, Node_Access);&lt;br /&gt;
   begin&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Destroy_Tree(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      if N.Right /= null then &lt;br /&gt;
         Destroy_Tree(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
      Free(N);&lt;br /&gt;
   end Destroy_Tree;&lt;br /&gt;
   function Tree(Value : Integer; Left : Node_Access; Right : Node_Access) return Node_Access is&lt;br /&gt;
      Temp : Node_Access := new Node;&lt;br /&gt;
   begin&lt;br /&gt;
      Temp.Data := Value;&lt;br /&gt;
      Temp.Left := Left;&lt;br /&gt;
      Temp.Right := Right;&lt;br /&gt;
      return Temp;&lt;br /&gt;
   end Tree;&lt;br /&gt;
   procedure Preorder(N : Node_Access) is&lt;br /&gt;
   begin&lt;br /&gt;
      Put(Integer'Image(N.Data));&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Preorder(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      if N.Right /= null then&lt;br /&gt;
         Preorder(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
   end Preorder;&lt;br /&gt;
   procedure Inorder(N : Node_Access) is&lt;br /&gt;
   begin&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Inorder(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      Put(Integer'Image(N.Data));&lt;br /&gt;
      if N.Right /= null then&lt;br /&gt;
         Inorder(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
   end Inorder;&lt;br /&gt;
   procedure Postorder(N : Node_Access) is&lt;br /&gt;
   begin&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Postorder(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      if N.Right /= null then&lt;br /&gt;
         Postorder(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
      Put(Integer'Image(N.Data));&lt;br /&gt;
   end Postorder;&lt;br /&gt;
   procedure Levelorder(N : Node_Access) is&lt;br /&gt;
      package Queues is new Ada.Containers.Doubly_Linked_Lists(Node_Access);&lt;br /&gt;
      use Queues;&lt;br /&gt;
      Node_Queue : List;&lt;br /&gt;
      Next : Node_Access;&lt;br /&gt;
   begin&lt;br /&gt;
      Node_Queue.Append(N);&lt;br /&gt;
      while not Is_Empty(Node_Queue) loop&lt;br /&gt;
         Next := First_Element(Node_Queue);&lt;br /&gt;
         Delete_First(Node_Queue);&lt;br /&gt;
         Put(Integer'Image(Next.Data));&lt;br /&gt;
         if Next.Left /= null then&lt;br /&gt;
            Node_Queue.Append(Next.Left);&lt;br /&gt;
         end if;&lt;br /&gt;
         if Next.Right /= null then&lt;br /&gt;
            Node_Queue.Append(Next.Right);&lt;br /&gt;
         end if;&lt;br /&gt;
      end loop;&lt;br /&gt;
   end Levelorder;&lt;br /&gt;
   N : Node_Access;&lt;br /&gt;
begin&lt;br /&gt;
   N := Tree(1, &lt;br /&gt;
      Tree(2,&lt;br /&gt;
         Tree(4,&lt;br /&gt;
            Tree(7, null, null),&lt;br /&gt;
            null),&lt;br /&gt;
         Tree(5, null, null)),&lt;br /&gt;
      Tree(3,&lt;br /&gt;
         Tree(6,&lt;br /&gt;
            Tree(8, null, null),&lt;br /&gt;
            Tree(9, null, null)),&lt;br /&gt;
         null));&lt;br /&gt;
 &lt;br /&gt;
   Put(&amp;quot;preorder:    &amp;quot;);&lt;br /&gt;
   Preorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Put(&amp;quot;inorder:     &amp;quot;);&lt;br /&gt;
   Inorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Put(&amp;quot;postorder:   &amp;quot;);&lt;br /&gt;
   Postorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Put(&amp;quot;level order: &amp;quot;);&lt;br /&gt;
   Levelorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Destroy_Tree(N);&lt;br /&gt;
end Tree_traversal;&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
== Hash Tables ==&lt;br /&gt;
=== Hash Table Intro ===&lt;br /&gt;
&lt;br /&gt;
Hash tables are very efficient data structures often used in searching algorithms for fast lookup operations.  Hash tables contain a series of &amp;quot;buckets&amp;quot; that function like indexes into an array, each of which can be accessed directly using their key value.  The bucket for which a piece of data will be placed is determine by a special hashing function.&lt;br /&gt;
&lt;br /&gt;
The major advantage of a hash table is that lookup times are essentially a constant value, much like an array with a known index.  With a proper hashing function in place, it should be fairly rare that any 2 keys would generate the same value.&lt;br /&gt;
&lt;br /&gt;
In the case that 2 keys do map to the same position, there is a conflict that must be dealt with in some fashion to obtain the correct value.  One way that is relevant to linked list structures is to have a chained hash table in which a linked list is created with all values that have been placed in that particular bucket.  The developer would have to not only take into account the proper bucket for the data being searched for, but also must considered the chained linked list.&lt;br /&gt;
&lt;br /&gt;
[[File:315px-Hash table 3 1 1 0 1 0 0 SP.svg.png]]&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
'''  Insert Example: Create new node if hash bucket doesnt exist, else append to the chain.'''&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Put a key/value pair into the table by hashing the key to get the array&lt;br /&gt;
   *  index of the chain that should hold the node containing the pair.&lt;br /&gt;
   *  If an existing node with the same key is present then overwrite its value,&lt;br /&gt;
   *  otherwise add a new node.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   *@param  val  data object reference&lt;br /&gt;
   */&lt;br /&gt;
  public void put(Object key, Object val)&lt;br /&gt;
  {&lt;br /&gt;
    int index = getIndex(key);&lt;br /&gt;
    Node node = find(key, data[index]);&lt;br /&gt;
    // Use helper method to determine if node with same key is already in&lt;br /&gt;
    // chain. If not, add a new node to head of chain.&lt;br /&gt;
    if (node == null)&lt;br /&gt;
    {&lt;br /&gt;
      data[index] = new Node(data[index], key, val);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      // Otherwise update data value of existing node.&lt;br /&gt;
      node.val = val;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Given a key object, return a data object from the table or&lt;br /&gt;
   *  null if it is not found.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   *@return      data object reference or null if no object found&lt;br /&gt;
   */&lt;br /&gt;
  public Object get(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    Node temp = find(key, data[getIndex(key)]);&lt;br /&gt;
    if (temp != null)&lt;br /&gt;
    {&lt;br /&gt;
      return temp.val;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      return null;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''  Delete Example: Delete a node from the chain.'''&lt;br /&gt;
  /**&lt;br /&gt;
   * Remove a key/value pair from table if present, otherwise make no change.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   */&lt;br /&gt;
  public void remove(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    int index = getIndex(key);&lt;br /&gt;
    Node ref = data[index];&lt;br /&gt;
    Node previous = null;&lt;br /&gt;
    while (ref != null)&lt;br /&gt;
    {&lt;br /&gt;
      if ((ref.key).equals(key))&lt;br /&gt;
      {&lt;br /&gt;
        if (previous == null)&lt;br /&gt;
        {&lt;br /&gt;
          data[index] = ref.next;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
          previous.next = ref.next;&lt;br /&gt;
        }&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      previous = ref;&lt;br /&gt;
      ref = ref.next;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Given a key, use a hash function to obtain the array index of the chain&lt;br /&gt;
   *  corresponding to the key.&lt;br /&gt;
   *  The hashCode method inherited (and possibly overridden)&lt;br /&gt;
   *  from class Object is called to do the hashing, with the returned&lt;br /&gt;
   *  value constrained to the hash table array bounds.&lt;br /&gt;
   *  The distribution of objects in the hash table will depend&lt;br /&gt;
   *  on the quality of the hash function implemented by hashCode.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  reference to object to be hashed&lt;br /&gt;
   *@return      array index of chain corresponding to key&lt;br /&gt;
   */&lt;br /&gt;
  private int getIndex(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    return Math.abs(key.hashCode() % data.length);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Find node given a key and a chain to search.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key    key object reference&lt;br /&gt;
   *@param  ref    node object reference where search will start&lt;br /&gt;
   *@return        node object holding key or null if not found&lt;br /&gt;
   */&lt;br /&gt;
  private Node find(Object key, Node ref)&lt;br /&gt;
  {&lt;br /&gt;
    while (ref != null)&lt;br /&gt;
    {&lt;br /&gt;
      if ((ref.key).equals(key))&lt;br /&gt;
      {&lt;br /&gt;
        return ref;&lt;br /&gt;
      }&lt;br /&gt;
      ref = ref.next;&lt;br /&gt;
    }&lt;br /&gt;
    return null;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
&lt;br /&gt;
The key issue in a hash table in a parallel environment is to make sure any update/insert/delete sequences have been completed properly prior to attempting subsequent operations to make sure the data has been synched appropriately.  However, since access speed is such a critical component of the design of a hash table, it is essential to try and avoid using too many locks for performing synchronization.  Fortunately, a number of lock-free hash designs have been implemented to avoid this bottleneck.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Graphs ==&lt;br /&gt;
=== Graph Intro ===&lt;br /&gt;
&lt;br /&gt;
A graph data structure is another type of linked-list structure that focuses on data that requires linking according to various types of relationships.  For example, in a networking application, one network node may have connections to a variety of other network nodes.  These nodes then also link to a variety of other nodes in the network.  Using this connection of nodes, it would be possible to then find a path from one specific node to another in the chain.  This could be accomplished by having each node contain a linked list of pointers to all other reachable nodes.&lt;br /&gt;
&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Add a new edge to the graph.&lt;br /&gt;
     */&lt;br /&gt;
    public void addEdge( String sourceName, String destName, double cost )&lt;br /&gt;
    {&lt;br /&gt;
        Vertex v = getVertex( sourceName );&lt;br /&gt;
        Vertex w = getVertex( destName );&lt;br /&gt;
        v.adj.add( new Edge( w, cost ) );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Single-source unweighted shortest-path algorithm.&lt;br /&gt;
     */&lt;br /&gt;
    public void unweighted( String startName )&lt;br /&gt;
    {&lt;br /&gt;
        clearAll( ); &lt;br /&gt;
&lt;br /&gt;
        Vertex start = (Vertex) vertexMap.get( startName );&lt;br /&gt;
        if( start == null )&lt;br /&gt;
            throw new NoSuchElementException( &amp;quot;Start vertex not found&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
        LinkedList q = new LinkedList( );&lt;br /&gt;
        q.addLast( start ); start.dist = 0;&lt;br /&gt;
&lt;br /&gt;
        while( !q.isEmpty( ) )&lt;br /&gt;
        {&lt;br /&gt;
            Vertex v = (Vertex) q.removeFirst( );&lt;br /&gt;
&lt;br /&gt;
            for( Iterator itr = v.adj.iterator( ); itr.hasNext( ); )&lt;br /&gt;
            {&lt;br /&gt;
                Edge e = (Edge) itr.next( );&lt;br /&gt;
                Vertex w = e.dest;&lt;br /&gt;
                if( w.dist == INFINITY )&lt;br /&gt;
                {&lt;br /&gt;
                    w.dist = v.dist + 1;&lt;br /&gt;
                    w.prev = v;&lt;br /&gt;
                    q.addLast( w );&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
&lt;br /&gt;
= Quiz =&lt;br /&gt;
= References =&lt;br /&gt;
http://oreilly.com/catalog/masteralgoc/chapter/ch08.pdf&lt;br /&gt;
&lt;br /&gt;
http://www.devjavasoft.org/code/classhashtable.html&lt;br /&gt;
&lt;br /&gt;
http://osr600doc.sco.com/en/SDK_c++/_Intro_graph.html&lt;br /&gt;
&lt;br /&gt;
web.eecs.utk.edu/~berry/cs302s02/src/code/Chap14/Graph.java&lt;br /&gt;
&lt;br /&gt;
http://people.engr.ncsu.edu/efg/506/s01/lectures/notes/lec8.html&lt;br /&gt;
&lt;br /&gt;
http://en.wikipedia.org/wiki/File:Hash_table_3_1_1_0_1_0_0_SP.svg&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Tree.PNG&amp;diff=59115</id>
		<title>File:Tree.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Tree.PNG&amp;diff=59115"/>
		<updated>2012-02-27T21:10:10Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/ch5a_ja&amp;diff=59114</id>
		<title>CSC/ECE 506 Spring 2012/ch5a ja</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/ch5a_ja&amp;diff=59114"/>
		<updated>2012-02-27T21:09:33Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* Serial Code Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Chapter 5a CSC/ECE 506 Spring 2012 / ch5a ==&lt;br /&gt;
&lt;br /&gt;
An exploration and summary of concurrency issues as it relates to linked-list based data structures such as hash tables, trees, and graphs.  This topic examines concurrency problems related to each type and possible solutions to allow for parallelization.&lt;br /&gt;
&lt;br /&gt;
= Introduction to Linked-List Parallel Programming =&lt;br /&gt;
&lt;br /&gt;
In determining opportunities for parallel programming during the software design process, many programmers will focus exclusively on loop or array structures, rather than also considering that linked-list pointer-based structures could also provide opportunities to run code in parallel across different processors.&lt;br /&gt;
&lt;br /&gt;
For example, one common parallel technique used in an array processing algorithm is the copy-scan technique.  This technique involves copying rows of data from one processor to another in a log(n) fashion until all processors have their own copy of that row.  From there, you could perform a reduction technique to generate a sum of all the data, all while working in a parallel fashion.  Take the following grid:&lt;br /&gt;
&lt;br /&gt;
The basic process for copy-scan would be to:&lt;br /&gt;
  Step 1) Copy the row 1 array to row 2.&lt;br /&gt;
  Step 2) Copy the row 1 array to row 3, row 2 to row 4, etc on the next run.&lt;br /&gt;
  Step 3) Continue in this manner until all rows have been copied in a log(n) fashion.&lt;br /&gt;
  Step 4) Perform the parallel operations to generate the desired result (reduction for sum, etc.).&lt;br /&gt;
&lt;br /&gt;
[[File:CopyScan.gif]]&lt;br /&gt;
&lt;br /&gt;
But how does this same process work in the linked list world?&lt;br /&gt;
&lt;br /&gt;
With linked lists, there is a concept called pointer doubling, which works in a very similar manner to copy-scan.&lt;br /&gt;
&lt;br /&gt;
  Step 1) Each processor will make a copy of the pointer it holds to it's neighbor.&lt;br /&gt;
  Step 2) Next, each processor will make a pointer to the processor 2 steps away.&lt;br /&gt;
  Step 3) This continues in logarithmic fashion until each processor has a pointer to the end of the chain.&lt;br /&gt;
  Step 4) Perform the parallel operations to generate the desired result.&lt;br /&gt;
&lt;br /&gt;
[[File:linkedlist.gif]]&lt;br /&gt;
&lt;br /&gt;
However, with linked list programming, similar to array-based programming, it becomes imperative to have some sort of locking mechanism on critical sections to avoid race conditions.  To make sure the results are correct, it is important that operations can be serialized appropriately and that data remains current and synchronized.&lt;br /&gt;
&lt;br /&gt;
In this chapter, we will explore 3 linked-list based data structures and the concurrency issues they present: hash tables, trees, and graphs.&lt;br /&gt;
&lt;br /&gt;
= Linked Data Structure algorithms extension =&lt;br /&gt;
== Lock free algorithms ==&lt;br /&gt;
&lt;br /&gt;
In order to overcome the ABA problems (shown in figure blow), we add auxiliary nodes to the data we structure. An auxiliary node is a cell that contains only a next field. We require that every normal cell in the list have an auxiliary node as its predecessor and as its successor. We permit “chains” of auxiliary nodes in the list (i.e., we do not require that every auxiliary node have a normal cell as its predecessor and successor), although such chains are undesirable for performance reasons.&lt;br /&gt;
&lt;br /&gt;
[[File:fig3.PNG]]&lt;br /&gt;
&lt;br /&gt;
The list also contains two dummy cells as the first and last normal cells in the list. These two cells are pointed at by the root pointers First and Last. These dummy cells need not, respectively, be preceded and followed by auxiliary nodes. Thus, m empty list data structure consists of these two dummy cells separated by an auxiliary node.&lt;br /&gt;
&lt;br /&gt;
A cursor is implemented as three pointers into the data structure: target is a pointer to the cell at the position the cursor is visiting. If the cursor is visiting the end-of-list position, then target will be equal to Last. The pointer pre-aux points to an auxiliary node in the data structure. For a cursor c, if c“.pre-aux = c“.target, then the cursor is valid; otherwise it is invalid. The pointer pre.cell points to a regular cell in the data structure. This pointer is used only by the TRYDELETE operation described below. An invalid cursor indicates that the structure of the list in t he vicinity of the cursor has changed (due to a concurrent insert ion or deletion by another process) since the pointers in the cursor were last read. The UPDATE algorithm, given in Figure 5, examines the state of the list and updates the pointers in the cursor so that it becomes valid. Since the list structure contains auxiliary nodes (perhaps more than one in a row), the UPDATE algorithm must skip over them. If two adjacent auxiliary nodes axe found in the list, the UPDATE algorithm will remove one of them. &lt;br /&gt;
&lt;br /&gt;
[[File:fig5.PNG]]&lt;br /&gt;
&lt;br /&gt;
Traversal of the list data structure is accomplished by using the FIRST and NEXT operations, which use the UPDATE operation. Algorithms are given in Figures 6 and 7. The NEXT operation returns FALSE if the cursor is already at the end of the list and cannot be advanced. Adding new cells into the list requires the insertion of both the cell and a new auxiliary node. This insertion is restricted to occur in the following way: The new auxiliary node will follow the new cell in the list, and insertion can only occur between an auxiliary node and a normal cell, as shown in Figure 8. &lt;br /&gt;
&lt;br /&gt;
[[File:fig6.PNG]]&lt;br /&gt;
[[File:fig7.PNG]]&lt;br /&gt;
[[File:fig8.PNG]]&lt;br /&gt;
&lt;br /&gt;
Figure 9 gives an algorithm, which takes as arguments a cursor and pointers to a new cell and auxiliary node. The algorithm will try to insert the new cell and auxiliary node at the position specified by the cursor, returning the value&lt;br /&gt;
TRUE if successful.&lt;br /&gt;
&lt;br /&gt;
[[File:fig9.PNG]]&lt;br /&gt;
&lt;br /&gt;
If the cursor becomes invalid, then the operation returns without inserting the new cell and returns the value FALSE. This allows a higher-level operation to detect that a change to the structure of the list occurred and to take it into account before attempting to insert the new cell again. For example, in the next section we show how the items in the list can be kept sorted using this technique.&lt;br /&gt;
&lt;br /&gt;
Given a valid cursor, the cell that it is visiting can also be deleted from the list. As with the insertion of new cells, if the list structure changes (i.e., the cursor becomes invalid) then the operation fails and must be tried again. Figure 10 gives the TRYDELETE algorithm. The deletion of the cell from the list leaves an “extra” auxiliary node; concurrent processes deleting adjacent cells can result in longer chains. Most of the TRYDELETE algorithm is concerned with removing the extra auxiliary nodes from the list. Normally, removing the extra auxiliary node that results from the deletion of a cell from the list is accomplished by simply swinging the pointer in the cell pointed at by the pre-cell pointer in the cursor. &lt;br /&gt;
&lt;br /&gt;
[[File:fig10.PNG]]&lt;br /&gt;
&lt;br /&gt;
However, this does not always work; in particular, this cell may have itself been deleted from the list, in which case swinging its next pointer will not remove the extra auxiliary node: In order to overcome this problem, we add a back~ink field to the normal cells in the list. When a cell is deleted from the list, the pre.cell field of the cursor is copied into the cell’s backdink field. The TRYDELETE algorithm can then use these pointers to reverse back to a cell that has not been deleted from the list. &lt;br /&gt;
&lt;br /&gt;
With just two processes, it is possible to create a chain of auxiliary nodes (with no intervening normal cells) of any length. However, any such chain can exist in the list only as long as some process is executing the TRYDELETE algorithm.&lt;br /&gt;
&lt;br /&gt;
If all deletions have been completed, then the list will contain no extra auxiliary nodes. To see this, assume that there is a chain of two or more-+ auxiliary nodes in the list. Let z be the normal cell that was deleted from between the first two auxiliary nodes in the chain. Note that this implies that the normal cell that immediately preceded x in the list has not been deleted.&lt;br /&gt;
By assumption, the operation that deleted z has completed. Consider the loop at lines 17–21 of the TRYDELETE algorithm. The only way for the process to exit this 100P, and hence to complete the operation, is for another deletion operation to have extended the chain of auxiliary nodes by deleting the normal cell g immediately following the chain, since the cell z is at the front of the chain.&lt;br /&gt;
Furthermore, the deletion of y must have occurred after the operation deleting x had set its back_link pointer at line 6; otherwise the auxiliary node following y would have been included in the chain found in lines 13–16. Thus, the chain of back_link pointers followed by the process that deleted y will lead to the same normal cell that preceded x. &lt;br /&gt;
&lt;br /&gt;
Now, the only way for the operation that deleted y to have completed is for the same reason as above; i.e., another TRYDELETE operation must extend the chain of auxiliary nodes by deleting a cell z. Since the length of the list must be finite, there must be a last such deletion which, but by the argument above, cannot have completed. Thus this operation must still be in progress, contradicting the assumption that there were no TRYDELETE operations in progress.&lt;br /&gt;
&lt;br /&gt;
[[File:fig11.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Linked Data Structures =&lt;br /&gt;
&lt;br /&gt;
Given this background knowledge, we can begin to explore solutions to some specific data structures that also utilized linked lists in some fashion.&lt;br /&gt;
&lt;br /&gt;
== Trees ==&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
Below is a code for tree traversal algorithms&lt;br /&gt;
its behavior is as figure below shows:&lt;br /&gt;
&lt;br /&gt;
[[File: tree.PNG]]&lt;br /&gt;
procedure Tree_Traversal is&lt;br /&gt;
   type Node;&lt;br /&gt;
   type Node_Access is access Node;&lt;br /&gt;
   type Node is record&lt;br /&gt;
      Left : Node_Access := null;&lt;br /&gt;
      Right : Node_Access := null;&lt;br /&gt;
      Data : Integer;&lt;br /&gt;
   end record;&lt;br /&gt;
   procedure Destroy_Tree(N : in out Node_Access) is&lt;br /&gt;
      procedure free is new Ada.Unchecked_Deallocation(Node, Node_Access);&lt;br /&gt;
   begin&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Destroy_Tree(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      if N.Right /= null then &lt;br /&gt;
         Destroy_Tree(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
      Free(N);&lt;br /&gt;
   end Destroy_Tree;&lt;br /&gt;
   function Tree(Value : Integer; Left : Node_Access; Right : Node_Access) return Node_Access is&lt;br /&gt;
      Temp : Node_Access := new Node;&lt;br /&gt;
   begin&lt;br /&gt;
      Temp.Data := Value;&lt;br /&gt;
      Temp.Left := Left;&lt;br /&gt;
      Temp.Right := Right;&lt;br /&gt;
      return Temp;&lt;br /&gt;
   end Tree;&lt;br /&gt;
   procedure Preorder(N : Node_Access) is&lt;br /&gt;
   begin&lt;br /&gt;
      Put(Integer'Image(N.Data));&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Preorder(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      if N.Right /= null then&lt;br /&gt;
         Preorder(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
   end Preorder;&lt;br /&gt;
   procedure Inorder(N : Node_Access) is&lt;br /&gt;
   begin&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Inorder(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      Put(Integer'Image(N.Data));&lt;br /&gt;
      if N.Right /= null then&lt;br /&gt;
         Inorder(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
   end Inorder;&lt;br /&gt;
   procedure Postorder(N : Node_Access) is&lt;br /&gt;
   begin&lt;br /&gt;
      if N.Left /= null then&lt;br /&gt;
         Postorder(N.Left);&lt;br /&gt;
      end if;&lt;br /&gt;
      if N.Right /= null then&lt;br /&gt;
         Postorder(N.Right);&lt;br /&gt;
      end if;&lt;br /&gt;
      Put(Integer'Image(N.Data));&lt;br /&gt;
   end Postorder;&lt;br /&gt;
   procedure Levelorder(N : Node_Access) is&lt;br /&gt;
      package Queues is new Ada.Containers.Doubly_Linked_Lists(Node_Access);&lt;br /&gt;
      use Queues;&lt;br /&gt;
      Node_Queue : List;&lt;br /&gt;
      Next : Node_Access;&lt;br /&gt;
   begin&lt;br /&gt;
      Node_Queue.Append(N);&lt;br /&gt;
      while not Is_Empty(Node_Queue) loop&lt;br /&gt;
         Next := First_Element(Node_Queue);&lt;br /&gt;
         Delete_First(Node_Queue);&lt;br /&gt;
         Put(Integer'Image(Next.Data));&lt;br /&gt;
         if Next.Left /= null then&lt;br /&gt;
            Node_Queue.Append(Next.Left);&lt;br /&gt;
         end if;&lt;br /&gt;
         if Next.Right /= null then&lt;br /&gt;
            Node_Queue.Append(Next.Right);&lt;br /&gt;
         end if;&lt;br /&gt;
      end loop;&lt;br /&gt;
   end Levelorder;&lt;br /&gt;
   N : Node_Access;&lt;br /&gt;
begin&lt;br /&gt;
   N := Tree(1, &lt;br /&gt;
      Tree(2,&lt;br /&gt;
         Tree(4,&lt;br /&gt;
            Tree(7, null, null),&lt;br /&gt;
            null),&lt;br /&gt;
         Tree(5, null, null)),&lt;br /&gt;
      Tree(3,&lt;br /&gt;
         Tree(6,&lt;br /&gt;
            Tree(8, null, null),&lt;br /&gt;
            Tree(9, null, null)),&lt;br /&gt;
         null));&lt;br /&gt;
 &lt;br /&gt;
   Put(&amp;quot;preorder:    &amp;quot;);&lt;br /&gt;
   Preorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Put(&amp;quot;inorder:     &amp;quot;);&lt;br /&gt;
   Inorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Put(&amp;quot;postorder:   &amp;quot;);&lt;br /&gt;
   Postorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Put(&amp;quot;level order: &amp;quot;);&lt;br /&gt;
   Levelorder(N);&lt;br /&gt;
   New_Line;&lt;br /&gt;
   Destroy_Tree(N);&lt;br /&gt;
end Tree_traversal;&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
== Hash Tables ==&lt;br /&gt;
=== Hash Table Intro ===&lt;br /&gt;
&lt;br /&gt;
Hash tables are very efficient data structures often used in searching algorithms for fast lookup operations.  Hash tables contain a series of &amp;quot;buckets&amp;quot; that function like indexes into an array, each of which can be accessed directly using their key value.  The bucket for which a piece of data will be placed is determine by a special hashing function.&lt;br /&gt;
&lt;br /&gt;
The major advantage of a hash table is that lookup times are essentially a constant value, much like an array with a known index.  With a proper hashing function in place, it should be fairly rare that any 2 keys would generate the same value.&lt;br /&gt;
&lt;br /&gt;
In the case that 2 keys do map to the same position, there is a conflict that must be dealt with in some fashion to obtain the correct value.  One way that is relevant to linked list structures is to have a chained hash table in which a linked list is created with all values that have been placed in that particular bucket.  The developer would have to not only take into account the proper bucket for the data being searched for, but also must considered the chained linked list.&lt;br /&gt;
&lt;br /&gt;
[[File:315px-Hash table 3 1 1 0 1 0 0 SP.svg.png]]&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
'''  Insert Example: Create new node if hash bucket doesnt exist, else append to the chain.'''&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Put a key/value pair into the table by hashing the key to get the array&lt;br /&gt;
   *  index of the chain that should hold the node containing the pair.&lt;br /&gt;
   *  If an existing node with the same key is present then overwrite its value,&lt;br /&gt;
   *  otherwise add a new node.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   *@param  val  data object reference&lt;br /&gt;
   */&lt;br /&gt;
  public void put(Object key, Object val)&lt;br /&gt;
  {&lt;br /&gt;
    int index = getIndex(key);&lt;br /&gt;
    Node node = find(key, data[index]);&lt;br /&gt;
    // Use helper method to determine if node with same key is already in&lt;br /&gt;
    // chain. If not, add a new node to head of chain.&lt;br /&gt;
    if (node == null)&lt;br /&gt;
    {&lt;br /&gt;
      data[index] = new Node(data[index], key, val);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      // Otherwise update data value of existing node.&lt;br /&gt;
      node.val = val;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Given a key object, return a data object from the table or&lt;br /&gt;
   *  null if it is not found.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   *@return      data object reference or null if no object found&lt;br /&gt;
   */&lt;br /&gt;
  public Object get(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    Node temp = find(key, data[getIndex(key)]);&lt;br /&gt;
    if (temp != null)&lt;br /&gt;
    {&lt;br /&gt;
      return temp.val;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      return null;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''  Delete Example: Delete a node from the chain.'''&lt;br /&gt;
  /**&lt;br /&gt;
   * Remove a key/value pair from table if present, otherwise make no change.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   */&lt;br /&gt;
  public void remove(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    int index = getIndex(key);&lt;br /&gt;
    Node ref = data[index];&lt;br /&gt;
    Node previous = null;&lt;br /&gt;
    while (ref != null)&lt;br /&gt;
    {&lt;br /&gt;
      if ((ref.key).equals(key))&lt;br /&gt;
      {&lt;br /&gt;
        if (previous == null)&lt;br /&gt;
        {&lt;br /&gt;
          data[index] = ref.next;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
          previous.next = ref.next;&lt;br /&gt;
        }&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      previous = ref;&lt;br /&gt;
      ref = ref.next;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Given a key, use a hash function to obtain the array index of the chain&lt;br /&gt;
   *  corresponding to the key.&lt;br /&gt;
   *  The hashCode method inherited (and possibly overridden)&lt;br /&gt;
   *  from class Object is called to do the hashing, with the returned&lt;br /&gt;
   *  value constrained to the hash table array bounds.&lt;br /&gt;
   *  The distribution of objects in the hash table will depend&lt;br /&gt;
   *  on the quality of the hash function implemented by hashCode.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  reference to object to be hashed&lt;br /&gt;
   *@return      array index of chain corresponding to key&lt;br /&gt;
   */&lt;br /&gt;
  private int getIndex(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    return Math.abs(key.hashCode() % data.length);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Find node given a key and a chain to search.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key    key object reference&lt;br /&gt;
   *@param  ref    node object reference where search will start&lt;br /&gt;
   *@return        node object holding key or null if not found&lt;br /&gt;
   */&lt;br /&gt;
  private Node find(Object key, Node ref)&lt;br /&gt;
  {&lt;br /&gt;
    while (ref != null)&lt;br /&gt;
    {&lt;br /&gt;
      if ((ref.key).equals(key))&lt;br /&gt;
      {&lt;br /&gt;
        return ref;&lt;br /&gt;
      }&lt;br /&gt;
      ref = ref.next;&lt;br /&gt;
    }&lt;br /&gt;
    return null;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
&lt;br /&gt;
The key issue in a hash table in a parallel environment is to make sure any update/insert/delete sequences have been completed properly prior to attempting subsequent operations to make sure the data has been synched appropriately.  However, since access speed is such a critical component of the design of a hash table, it is essential to try and avoid using too many locks for performing synchronization.  Fortunately, a number of lock-free hash designs have been implemented to avoid this bottleneck.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Graphs ==&lt;br /&gt;
=== Graph Intro ===&lt;br /&gt;
&lt;br /&gt;
A graph data structure is another type of linked-list structure that focuses on data that requires linking according to various types of relationships.  For example, in a networking application, one network node may have connections to a variety of other network nodes.  These nodes then also link to a variety of other nodes in the network.  Using this connection of nodes, it would be possible to then find a path from one specific node to another in the chain.  This could be accomplished by having each node contain a linked list of pointers to all other reachable nodes.&lt;br /&gt;
&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Add a new edge to the graph.&lt;br /&gt;
     */&lt;br /&gt;
    public void addEdge( String sourceName, String destName, double cost )&lt;br /&gt;
    {&lt;br /&gt;
        Vertex v = getVertex( sourceName );&lt;br /&gt;
        Vertex w = getVertex( destName );&lt;br /&gt;
        v.adj.add( new Edge( w, cost ) );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Single-source unweighted shortest-path algorithm.&lt;br /&gt;
     */&lt;br /&gt;
    public void unweighted( String startName )&lt;br /&gt;
    {&lt;br /&gt;
        clearAll( ); &lt;br /&gt;
&lt;br /&gt;
        Vertex start = (Vertex) vertexMap.get( startName );&lt;br /&gt;
        if( start == null )&lt;br /&gt;
            throw new NoSuchElementException( &amp;quot;Start vertex not found&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
        LinkedList q = new LinkedList( );&lt;br /&gt;
        q.addLast( start ); start.dist = 0;&lt;br /&gt;
&lt;br /&gt;
        while( !q.isEmpty( ) )&lt;br /&gt;
        {&lt;br /&gt;
            Vertex v = (Vertex) q.removeFirst( );&lt;br /&gt;
&lt;br /&gt;
            for( Iterator itr = v.adj.iterator( ); itr.hasNext( ); )&lt;br /&gt;
            {&lt;br /&gt;
                Edge e = (Edge) itr.next( );&lt;br /&gt;
                Vertex w = e.dest;&lt;br /&gt;
                if( w.dist == INFINITY )&lt;br /&gt;
                {&lt;br /&gt;
                    w.dist = v.dist + 1;&lt;br /&gt;
                    w.prev = v;&lt;br /&gt;
                    q.addLast( w );&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
&lt;br /&gt;
= Quiz =&lt;br /&gt;
= References =&lt;br /&gt;
http://oreilly.com/catalog/masteralgoc/chapter/ch08.pdf&lt;br /&gt;
&lt;br /&gt;
http://www.devjavasoft.org/code/classhashtable.html&lt;br /&gt;
&lt;br /&gt;
http://osr600doc.sco.com/en/SDK_c++/_Intro_graph.html&lt;br /&gt;
&lt;br /&gt;
web.eecs.utk.edu/~berry/cs302s02/src/code/Chap14/Graph.java&lt;br /&gt;
&lt;br /&gt;
http://people.engr.ncsu.edu/efg/506/s01/lectures/notes/lec8.html&lt;br /&gt;
&lt;br /&gt;
http://en.wikipedia.org/wiki/File:Hash_table_3_1_1_0_1_0_0_SP.svg&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/ch5a_ja&amp;diff=59110</id>
		<title>CSC/ECE 506 Spring 2012/ch5a ja</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/ch5a_ja&amp;diff=59110"/>
		<updated>2012-02-27T21:04:43Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: /* Tree Intro */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Chapter 5a CSC/ECE 506 Spring 2012 / ch5a ==&lt;br /&gt;
&lt;br /&gt;
An exploration and summary of concurrency issues as it relates to linked-list based data structures such as hash tables, trees, and graphs.  This topic examines concurrency problems related to each type and possible solutions to allow for parallelization.&lt;br /&gt;
&lt;br /&gt;
= Introduction to Linked-List Parallel Programming =&lt;br /&gt;
&lt;br /&gt;
In determining opportunities for parallel programming during the software design process, many programmers will focus exclusively on loop or array structures, rather than also considering that linked-list pointer-based structures could also provide opportunities to run code in parallel across different processors.&lt;br /&gt;
&lt;br /&gt;
For example, one common parallel technique used in an array processing algorithm is the copy-scan technique.  This technique involves copying rows of data from one processor to another in a log(n) fashion until all processors have their own copy of that row.  From there, you could perform a reduction technique to generate a sum of all the data, all while working in a parallel fashion.  Take the following grid:&lt;br /&gt;
&lt;br /&gt;
The basic process for copy-scan would be to:&lt;br /&gt;
  Step 1) Copy the row 1 array to row 2.&lt;br /&gt;
  Step 2) Copy the row 1 array to row 3, row 2 to row 4, etc on the next run.&lt;br /&gt;
  Step 3) Continue in this manner until all rows have been copied in a log(n) fashion.&lt;br /&gt;
  Step 4) Perform the parallel operations to generate the desired result (reduction for sum, etc.).&lt;br /&gt;
&lt;br /&gt;
[[File:CopyScan.gif]]&lt;br /&gt;
&lt;br /&gt;
But how does this same process work in the linked list world?&lt;br /&gt;
&lt;br /&gt;
With linked lists, there is a concept called pointer doubling, which works in a very similar manner to copy-scan.&lt;br /&gt;
&lt;br /&gt;
  Step 1) Each processor will make a copy of the pointer it holds to it's neighbor.&lt;br /&gt;
  Step 2) Next, each processor will make a pointer to the processor 2 steps away.&lt;br /&gt;
  Step 3) This continues in logarithmic fashion until each processor has a pointer to the end of the chain.&lt;br /&gt;
  Step 4) Perform the parallel operations to generate the desired result.&lt;br /&gt;
&lt;br /&gt;
[[File:linkedlist.gif]]&lt;br /&gt;
&lt;br /&gt;
However, with linked list programming, similar to array-based programming, it becomes imperative to have some sort of locking mechanism on critical sections to avoid race conditions.  To make sure the results are correct, it is important that operations can be serialized appropriately and that data remains current and synchronized.&lt;br /&gt;
&lt;br /&gt;
In this chapter, we will explore 3 linked-list based data structures and the concurrency issues they present: hash tables, trees, and graphs.&lt;br /&gt;
&lt;br /&gt;
= Linked Data Structure algorithms extension =&lt;br /&gt;
== Lock free algorithms ==&lt;br /&gt;
&lt;br /&gt;
In order to overcome the ABA problems (shown in figure blow), we add auxiliary nodes to the data we structure. An auxiliary node is a cell that contains only a next field. We require that every normal cell in the list have an auxiliary node as its predecessor and as its successor. We permit “chains” of auxiliary nodes in the list (i.e., we do not require that every auxiliary node have a normal cell as its predecessor and successor), although such chains are undesirable for performance reasons.&lt;br /&gt;
&lt;br /&gt;
[[File:fig3.PNG]]&lt;br /&gt;
&lt;br /&gt;
The list also contains two dummy cells as the first and last normal cells in the list. These two cells are pointed at by the root pointers First and Last. These dummy cells need not, respectively, be preceded and followed by auxiliary nodes. Thus, m empty list data structure consists of these two dummy cells separated by an auxiliary node.&lt;br /&gt;
&lt;br /&gt;
A cursor is implemented as three pointers into the data structure: target is a pointer to the cell at the position the cursor is visiting. If the cursor is visiting the end-of-list position, then target will be equal to Last. The pointer pre-aux points to an auxiliary node in the data structure. For a cursor c, if c“.pre-aux = c“.target, then the cursor is valid; otherwise it is invalid. The pointer pre.cell points to a regular cell in the data structure. This pointer is used only by the TRYDELETE operation described below. An invalid cursor indicates that the structure of the list in t he vicinity of the cursor has changed (due to a concurrent insert ion or deletion by another process) since the pointers in the cursor were last read. The UPDATE algorithm, given in Figure 5, examines the state of the list and updates the pointers in the cursor so that it becomes valid. Since the list structure contains auxiliary nodes (perhaps more than one in a row), the UPDATE algorithm must skip over them. If two adjacent auxiliary nodes axe found in the list, the UPDATE algorithm will remove one of them. &lt;br /&gt;
&lt;br /&gt;
[[File:fig5.PNG]]&lt;br /&gt;
&lt;br /&gt;
Traversal of the list data structure is accomplished by using the FIRST and NEXT operations, which use the UPDATE operation. Algorithms are given in Figures 6 and 7. The NEXT operation returns FALSE if the cursor is already at the end of the list and cannot be advanced. Adding new cells into the list requires the insertion of both the cell and a new auxiliary node. This insertion is restricted to occur in the following way: The new auxiliary node will follow the new cell in the list, and insertion can only occur between an auxiliary node and a normal cell, as shown in Figure 8. &lt;br /&gt;
&lt;br /&gt;
[[File:fig6.PNG]]&lt;br /&gt;
[[File:fig7.PNG]]&lt;br /&gt;
[[File:fig8.PNG]]&lt;br /&gt;
&lt;br /&gt;
Figure 9 gives an algorithm, which takes as arguments a cursor and pointers to a new cell and auxiliary node. The algorithm will try to insert the new cell and auxiliary node at the position specified by the cursor, returning the value&lt;br /&gt;
TRUE if successful.&lt;br /&gt;
&lt;br /&gt;
[[File:fig9.PNG]]&lt;br /&gt;
&lt;br /&gt;
If the cursor becomes invalid, then the operation returns without inserting the new cell and returns the value FALSE. This allows a higher-level operation to detect that a change to the structure of the list occurred and to take it into account before attempting to insert the new cell again. For example, in the next section we show how the items in the list can be kept sorted using this technique.&lt;br /&gt;
&lt;br /&gt;
Given a valid cursor, the cell that it is visiting can also be deleted from the list. As with the insertion of new cells, if the list structure changes (i.e., the cursor becomes invalid) then the operation fails and must be tried again. Figure 10 gives the TRYDELETE algorithm. The deletion of the cell from the list leaves an “extra” auxiliary node; concurrent processes deleting adjacent cells can result in longer chains. Most of the TRYDELETE algorithm is concerned with removing the extra auxiliary nodes from the list. Normally, removing the extra auxiliary node that results from the deletion of a cell from the list is accomplished by simply swinging the pointer in the cell pointed at by the pre-cell pointer in the cursor. &lt;br /&gt;
&lt;br /&gt;
[[File:fig10.PNG]]&lt;br /&gt;
&lt;br /&gt;
However, this does not always work; in particular, this cell may have itself been deleted from the list, in which case swinging its next pointer will not remove the extra auxiliary node: In order to overcome this problem, we add a back~ink field to the normal cells in the list. When a cell is deleted from the list, the pre.cell field of the cursor is copied into the cell’s backdink field. The TRYDELETE algorithm can then use these pointers to reverse back to a cell that has not been deleted from the list. &lt;br /&gt;
&lt;br /&gt;
With just two processes, it is possible to create a chain of auxiliary nodes (with no intervening normal cells) of any length. However, any such chain can exist in the list only as long as some process is executing the TRYDELETE algorithm.&lt;br /&gt;
&lt;br /&gt;
If all deletions have been completed, then the list will contain no extra auxiliary nodes. To see this, assume that there is a chain of two or more-+ auxiliary nodes in the list. Let z be the normal cell that was deleted from between the first two auxiliary nodes in the chain. Note that this implies that the normal cell that immediately preceded x in the list has not been deleted.&lt;br /&gt;
By assumption, the operation that deleted z has completed. Consider the loop at lines 17–21 of the TRYDELETE algorithm. The only way for the process to exit this 100P, and hence to complete the operation, is for another deletion operation to have extended the chain of auxiliary nodes by deleting the normal cell g immediately following the chain, since the cell z is at the front of the chain.&lt;br /&gt;
Furthermore, the deletion of y must have occurred after the operation deleting x had set its back_link pointer at line 6; otherwise the auxiliary node following y would have been included in the chain found in lines 13–16. Thus, the chain of back_link pointers followed by the process that deleted y will lead to the same normal cell that preceded x. &lt;br /&gt;
&lt;br /&gt;
Now, the only way for the operation that deleted y to have completed is for the same reason as above; i.e., another TRYDELETE operation must extend the chain of auxiliary nodes by deleting a cell z. Since the length of the list must be finite, there must be a last such deletion which, but by the argument above, cannot have completed. Thus this operation must still be in progress, contradicting the assumption that there were no TRYDELETE operations in progress.&lt;br /&gt;
&lt;br /&gt;
[[File:fig11.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Linked Data Structures =&lt;br /&gt;
&lt;br /&gt;
Given this background knowledge, we can begin to explore solutions to some specific data structures that also utilized linked lists in some fashion.&lt;br /&gt;
&lt;br /&gt;
== Trees ==&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
== Hash Tables ==&lt;br /&gt;
=== Hash Table Intro ===&lt;br /&gt;
&lt;br /&gt;
Hash tables are very efficient data structures often used in searching algorithms for fast lookup operations.  Hash tables contain a series of &amp;quot;buckets&amp;quot; that function like indexes into an array, each of which can be accessed directly using their key value.  The bucket for which a piece of data will be placed is determine by a special hashing function.&lt;br /&gt;
&lt;br /&gt;
The major advantage of a hash table is that lookup times are essentially a constant value, much like an array with a known index.  With a proper hashing function in place, it should be fairly rare that any 2 keys would generate the same value.&lt;br /&gt;
&lt;br /&gt;
In the case that 2 keys do map to the same position, there is a conflict that must be dealt with in some fashion to obtain the correct value.  One way that is relevant to linked list structures is to have a chained hash table in which a linked list is created with all values that have been placed in that particular bucket.  The developer would have to not only take into account the proper bucket for the data being searched for, but also must considered the chained linked list.&lt;br /&gt;
&lt;br /&gt;
[[File:315px-Hash table 3 1 1 0 1 0 0 SP.svg.png]]&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
'''  Insert Example: Create new node if hash bucket doesnt exist, else append to the chain.'''&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Put a key/value pair into the table by hashing the key to get the array&lt;br /&gt;
   *  index of the chain that should hold the node containing the pair.&lt;br /&gt;
   *  If an existing node with the same key is present then overwrite its value,&lt;br /&gt;
   *  otherwise add a new node.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   *@param  val  data object reference&lt;br /&gt;
   */&lt;br /&gt;
  public void put(Object key, Object val)&lt;br /&gt;
  {&lt;br /&gt;
    int index = getIndex(key);&lt;br /&gt;
    Node node = find(key, data[index]);&lt;br /&gt;
    // Use helper method to determine if node with same key is already in&lt;br /&gt;
    // chain. If not, add a new node to head of chain.&lt;br /&gt;
    if (node == null)&lt;br /&gt;
    {&lt;br /&gt;
      data[index] = new Node(data[index], key, val);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      // Otherwise update data value of existing node.&lt;br /&gt;
      node.val = val;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Given a key object, return a data object from the table or&lt;br /&gt;
   *  null if it is not found.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   *@return      data object reference or null if no object found&lt;br /&gt;
   */&lt;br /&gt;
  public Object get(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    Node temp = find(key, data[getIndex(key)]);&lt;br /&gt;
    if (temp != null)&lt;br /&gt;
    {&lt;br /&gt;
      return temp.val;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      return null;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''  Delete Example: Delete a node from the chain.'''&lt;br /&gt;
  /**&lt;br /&gt;
   * Remove a key/value pair from table if present, otherwise make no change.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   */&lt;br /&gt;
  public void remove(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    int index = getIndex(key);&lt;br /&gt;
    Node ref = data[index];&lt;br /&gt;
    Node previous = null;&lt;br /&gt;
    while (ref != null)&lt;br /&gt;
    {&lt;br /&gt;
      if ((ref.key).equals(key))&lt;br /&gt;
      {&lt;br /&gt;
        if (previous == null)&lt;br /&gt;
        {&lt;br /&gt;
          data[index] = ref.next;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
          previous.next = ref.next;&lt;br /&gt;
        }&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      previous = ref;&lt;br /&gt;
      ref = ref.next;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Given a key, use a hash function to obtain the array index of the chain&lt;br /&gt;
   *  corresponding to the key.&lt;br /&gt;
   *  The hashCode method inherited (and possibly overridden)&lt;br /&gt;
   *  from class Object is called to do the hashing, with the returned&lt;br /&gt;
   *  value constrained to the hash table array bounds.&lt;br /&gt;
   *  The distribution of objects in the hash table will depend&lt;br /&gt;
   *  on the quality of the hash function implemented by hashCode.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  reference to object to be hashed&lt;br /&gt;
   *@return      array index of chain corresponding to key&lt;br /&gt;
   */&lt;br /&gt;
  private int getIndex(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    return Math.abs(key.hashCode() % data.length);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Find node given a key and a chain to search.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key    key object reference&lt;br /&gt;
   *@param  ref    node object reference where search will start&lt;br /&gt;
   *@return        node object holding key or null if not found&lt;br /&gt;
   */&lt;br /&gt;
  private Node find(Object key, Node ref)&lt;br /&gt;
  {&lt;br /&gt;
    while (ref != null)&lt;br /&gt;
    {&lt;br /&gt;
      if ((ref.key).equals(key))&lt;br /&gt;
      {&lt;br /&gt;
        return ref;&lt;br /&gt;
      }&lt;br /&gt;
      ref = ref.next;&lt;br /&gt;
    }&lt;br /&gt;
    return null;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
&lt;br /&gt;
The key issue in a hash table in a parallel environment is to make sure any update/insert/delete sequences have been completed properly prior to attempting subsequent operations to make sure the data has been synched appropriately.  However, since access speed is such a critical component of the design of a hash table, it is essential to try and avoid using too many locks for performing synchronization.  Fortunately, a number of lock-free hash designs have been implemented to avoid this bottleneck.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Graphs ==&lt;br /&gt;
=== Graph Intro ===&lt;br /&gt;
&lt;br /&gt;
A graph data structure is another type of linked-list structure that focuses on data that requires linking according to various types of relationships.  For example, in a networking application, one network node may have connections to a variety of other network nodes.  These nodes then also link to a variety of other nodes in the network.  Using this connection of nodes, it would be possible to then find a path from one specific node to another in the chain.  This could be accomplished by having each node contain a linked list of pointers to all other reachable nodes.&lt;br /&gt;
&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Add a new edge to the graph.&lt;br /&gt;
     */&lt;br /&gt;
    public void addEdge( String sourceName, String destName, double cost )&lt;br /&gt;
    {&lt;br /&gt;
        Vertex v = getVertex( sourceName );&lt;br /&gt;
        Vertex w = getVertex( destName );&lt;br /&gt;
        v.adj.add( new Edge( w, cost ) );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Single-source unweighted shortest-path algorithm.&lt;br /&gt;
     */&lt;br /&gt;
    public void unweighted( String startName )&lt;br /&gt;
    {&lt;br /&gt;
        clearAll( ); &lt;br /&gt;
&lt;br /&gt;
        Vertex start = (Vertex) vertexMap.get( startName );&lt;br /&gt;
        if( start == null )&lt;br /&gt;
            throw new NoSuchElementException( &amp;quot;Start vertex not found&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
        LinkedList q = new LinkedList( );&lt;br /&gt;
        q.addLast( start ); start.dist = 0;&lt;br /&gt;
&lt;br /&gt;
        while( !q.isEmpty( ) )&lt;br /&gt;
        {&lt;br /&gt;
            Vertex v = (Vertex) q.removeFirst( );&lt;br /&gt;
&lt;br /&gt;
            for( Iterator itr = v.adj.iterator( ); itr.hasNext( ); )&lt;br /&gt;
            {&lt;br /&gt;
                Edge e = (Edge) itr.next( );&lt;br /&gt;
                Vertex w = e.dest;&lt;br /&gt;
                if( w.dist == INFINITY )&lt;br /&gt;
                {&lt;br /&gt;
                    w.dist = v.dist + 1;&lt;br /&gt;
                    w.prev = v;&lt;br /&gt;
                    q.addLast( w );&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
&lt;br /&gt;
= Quiz =&lt;br /&gt;
= References =&lt;br /&gt;
http://oreilly.com/catalog/masteralgoc/chapter/ch08.pdf&lt;br /&gt;
http://www.devjavasoft.org/code/classhashtable.html&lt;br /&gt;
http://osr600doc.sco.com/en/SDK_c++/_Intro_graph.html&lt;br /&gt;
web.eecs.utk.edu/~berry/cs302s02/src/code/Chap14/Graph.java&lt;br /&gt;
http://people.engr.ncsu.edu/efg/506/s01/lectures/notes/lec8.html&lt;br /&gt;
http://en.wikipedia.org/wiki/File:Hash_table_3_1_1_0_1_0_0_SP.svg&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/ch5a_ja&amp;diff=59109</id>
		<title>CSC/ECE 506 Spring 2012/ch5a ja</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2012/ch5a_ja&amp;diff=59109"/>
		<updated>2012-02-27T21:03:51Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Chapter 5a CSC/ECE 506 Spring 2012 / ch5a ==&lt;br /&gt;
&lt;br /&gt;
An exploration and summary of concurrency issues as it relates to linked-list based data structures such as hash tables, trees, and graphs.  This topic examines concurrency problems related to each type and possible solutions to allow for parallelization.&lt;br /&gt;
&lt;br /&gt;
= Introduction to Linked-List Parallel Programming =&lt;br /&gt;
&lt;br /&gt;
In determining opportunities for parallel programming during the software design process, many programmers will focus exclusively on loop or array structures, rather than also considering that linked-list pointer-based structures could also provide opportunities to run code in parallel across different processors.&lt;br /&gt;
&lt;br /&gt;
For example, one common parallel technique used in an array processing algorithm is the copy-scan technique.  This technique involves copying rows of data from one processor to another in a log(n) fashion until all processors have their own copy of that row.  From there, you could perform a reduction technique to generate a sum of all the data, all while working in a parallel fashion.  Take the following grid:&lt;br /&gt;
&lt;br /&gt;
The basic process for copy-scan would be to:&lt;br /&gt;
  Step 1) Copy the row 1 array to row 2.&lt;br /&gt;
  Step 2) Copy the row 1 array to row 3, row 2 to row 4, etc on the next run.&lt;br /&gt;
  Step 3) Continue in this manner until all rows have been copied in a log(n) fashion.&lt;br /&gt;
  Step 4) Perform the parallel operations to generate the desired result (reduction for sum, etc.).&lt;br /&gt;
&lt;br /&gt;
[[File:CopyScan.gif]]&lt;br /&gt;
&lt;br /&gt;
But how does this same process work in the linked list world?&lt;br /&gt;
&lt;br /&gt;
With linked lists, there is a concept called pointer doubling, which works in a very similar manner to copy-scan.&lt;br /&gt;
&lt;br /&gt;
  Step 1) Each processor will make a copy of the pointer it holds to it's neighbor.&lt;br /&gt;
  Step 2) Next, each processor will make a pointer to the processor 2 steps away.&lt;br /&gt;
  Step 3) This continues in logarithmic fashion until each processor has a pointer to the end of the chain.&lt;br /&gt;
  Step 4) Perform the parallel operations to generate the desired result.&lt;br /&gt;
&lt;br /&gt;
[[File:linkedlist.gif]]&lt;br /&gt;
&lt;br /&gt;
However, with linked list programming, similar to array-based programming, it becomes imperative to have some sort of locking mechanism on critical sections to avoid race conditions.  To make sure the results are correct, it is important that operations can be serialized appropriately and that data remains current and synchronized.&lt;br /&gt;
&lt;br /&gt;
In this chapter, we will explore 3 linked-list based data structures and the concurrency issues they present: hash tables, trees, and graphs.&lt;br /&gt;
&lt;br /&gt;
= Linked Data Structure algorithms extension =&lt;br /&gt;
== Lock free algorithms ==&lt;br /&gt;
&lt;br /&gt;
In order to overcome the ABA problems (shown in figure blow), we add auxiliary nodes to the data we structure. An auxiliary node is a cell that contains only a next field. We require that every normal cell in the list have an auxiliary node as its predecessor and as its successor. We permit “chains” of auxiliary nodes in the list (i.e., we do not require that every auxiliary node have a normal cell as its predecessor and successor), although such chains are undesirable for performance reasons.&lt;br /&gt;
&lt;br /&gt;
[[File:fig3.PNG]]&lt;br /&gt;
&lt;br /&gt;
The list also contains two dummy cells as the first and last normal cells in the list. These two cells are pointed at by the root pointers First and Last. These dummy cells need not, respectively, be preceded and followed by auxiliary nodes. Thus, m empty list data structure consists of these two dummy cells separated by an auxiliary node.&lt;br /&gt;
&lt;br /&gt;
A cursor is implemented as three pointers into the data structure: target is a pointer to the cell at the position the cursor is visiting. If the cursor is visiting the end-of-list position, then target will be equal to Last. The pointer pre-aux points to an auxiliary node in the data structure. For a cursor c, if c“.pre-aux = c“.target, then the cursor is valid; otherwise it is invalid. The pointer pre.cell points to a regular cell in the data structure. This pointer is used only by the TRYDELETE operation described below. An invalid cursor indicates that the structure of the list in t he vicinity of the cursor has changed (due to a concurrent insert ion or deletion by another process) since the pointers in the cursor were last read. The UPDATE algorithm, given in Figure 5, examines the state of the list and updates the pointers in the cursor so that it becomes valid. Since the list structure contains auxiliary nodes (perhaps more than one in a row), the UPDATE algorithm must skip over them. If two adjacent auxiliary nodes axe found in the list, the UPDATE algorithm will remove one of them. &lt;br /&gt;
&lt;br /&gt;
[[File:fig5.PNG]]&lt;br /&gt;
&lt;br /&gt;
Traversal of the list data structure is accomplished by using the FIRST and NEXT operations, which use the UPDATE operation. Algorithms are given in Figures 6 and 7. The NEXT operation returns FALSE if the cursor is already at the end of the list and cannot be advanced. Adding new cells into the list requires the insertion of both the cell and a new auxiliary node. This insertion is restricted to occur in the following way: The new auxiliary node will follow the new cell in the list, and insertion can only occur between an auxiliary node and a normal cell, as shown in Figure 8. &lt;br /&gt;
&lt;br /&gt;
[[File:fig6.PNG]]&lt;br /&gt;
[[File:fig7.PNG]]&lt;br /&gt;
[[File:fig8.PNG]]&lt;br /&gt;
&lt;br /&gt;
Figure 9 gives an algorithm, which takes as arguments a cursor and pointers to a new cell and auxiliary node. The algorithm will try to insert the new cell and auxiliary node at the position specified by the cursor, returning the value&lt;br /&gt;
TRUE if successful.&lt;br /&gt;
&lt;br /&gt;
[[File:fig9.PNG]]&lt;br /&gt;
&lt;br /&gt;
If the cursor becomes invalid, then the operation returns without inserting the new cell and returns the value FALSE. This allows a higher-level operation to detect that a change to the structure of the list occurred and to take it into account before attempting to insert the new cell again. For example, in the next section we show how the items in the list can be kept sorted using this technique.&lt;br /&gt;
&lt;br /&gt;
Given a valid cursor, the cell that it is visiting can also be deleted from the list. As with the insertion of new cells, if the list structure changes (i.e., the cursor becomes invalid) then the operation fails and must be tried again. Figure 10 gives the TRYDELETE algorithm. The deletion of the cell from the list leaves an “extra” auxiliary node; concurrent processes deleting adjacent cells can result in longer chains. Most of the TRYDELETE algorithm is concerned with removing the extra auxiliary nodes from the list. Normally, removing the extra auxiliary node that results from the deletion of a cell from the list is accomplished by simply swinging the pointer in the cell pointed at by the pre-cell pointer in the cursor. &lt;br /&gt;
&lt;br /&gt;
[[File:fig10.PNG]]&lt;br /&gt;
&lt;br /&gt;
However, this does not always work; in particular, this cell may have itself been deleted from the list, in which case swinging its next pointer will not remove the extra auxiliary node: In order to overcome this problem, we add a back~ink field to the normal cells in the list. When a cell is deleted from the list, the pre.cell field of the cursor is copied into the cell’s backdink field. The TRYDELETE algorithm can then use these pointers to reverse back to a cell that has not been deleted from the list. &lt;br /&gt;
&lt;br /&gt;
With just two processes, it is possible to create a chain of auxiliary nodes (with no intervening normal cells) of any length. However, any such chain can exist in the list only as long as some process is executing the TRYDELETE algorithm.&lt;br /&gt;
&lt;br /&gt;
If all deletions have been completed, then the list will contain no extra auxiliary nodes. To see this, assume that there is a chain of two or more-+ auxiliary nodes in the list. Let z be the normal cell that was deleted from between the first two auxiliary nodes in the chain. Note that this implies that the normal cell that immediately preceded x in the list has not been deleted.&lt;br /&gt;
By assumption, the operation that deleted z has completed. Consider the loop at lines 17–21 of the TRYDELETE algorithm. The only way for the process to exit this 100P, and hence to complete the operation, is for another deletion operation to have extended the chain of auxiliary nodes by deleting the normal cell g immediately following the chain, since the cell z is at the front of the chain.&lt;br /&gt;
Furthermore, the deletion of y must have occurred after the operation deleting x had set its back_link pointer at line 6; otherwise the auxiliary node following y would have been included in the chain found in lines 13–16. Thus, the chain of back_link pointers followed by the process that deleted y will lead to the same normal cell that preceded x. &lt;br /&gt;
&lt;br /&gt;
Now, the only way for the operation that deleted y to have completed is for the same reason as above; i.e., another TRYDELETE operation must extend the chain of auxiliary nodes by deleting a cell z. Since the length of the list must be finite, there must be a last such deletion which, but by the argument above, cannot have completed. Thus this operation must still be in progress, contradicting the assumption that there were no TRYDELETE operations in progress.&lt;br /&gt;
&lt;br /&gt;
[[File:fig11.PNG]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Linked Data Structures =&lt;br /&gt;
&lt;br /&gt;
Given this background knowledge, we can begin to explore solutions to some specific data structures that also utilized linked lists in some fashion.&lt;br /&gt;
&lt;br /&gt;
== Trees ==&lt;br /&gt;
=== Tree Intro ===&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
== Hash Tables ==&lt;br /&gt;
=== Hash Table Intro ===&lt;br /&gt;
&lt;br /&gt;
Hash tables are very efficient data structures often used in searching algorithms for fast lookup operations.  Hash tables contain a series of &amp;quot;buckets&amp;quot; that function like indexes into an array, each of which can be accessed directly using their key value.  The bucket for which a piece of data will be placed is determine by a special hashing function.&lt;br /&gt;
&lt;br /&gt;
The major advantage of a hash table is that lookup times are essentially a constant value, much like an array with a known index.  With a proper hashing function in place, it should be fairly rare that any 2 keys would generate the same value.&lt;br /&gt;
&lt;br /&gt;
In the case that 2 keys do map to the same position, there is a conflict that must be dealt with in some fashion to obtain the correct value.  One way that is relevant to linked list structures is to have a chained hash table in which a linked list is created with all values that have been placed in that particular bucket.  The developer would have to not only take into account the proper bucket for the data being searched for, but also must considered the chained linked list.&lt;br /&gt;
&lt;br /&gt;
[[File:315px-Hash table 3 1 1 0 1 0 0 SP.svg.png]]&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
'''  Insert Example: Create new node if hash bucket doesnt exist, else append to the chain.'''&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Put a key/value pair into the table by hashing the key to get the array&lt;br /&gt;
   *  index of the chain that should hold the node containing the pair.&lt;br /&gt;
   *  If an existing node with the same key is present then overwrite its value,&lt;br /&gt;
   *  otherwise add a new node.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   *@param  val  data object reference&lt;br /&gt;
   */&lt;br /&gt;
  public void put(Object key, Object val)&lt;br /&gt;
  {&lt;br /&gt;
    int index = getIndex(key);&lt;br /&gt;
    Node node = find(key, data[index]);&lt;br /&gt;
    // Use helper method to determine if node with same key is already in&lt;br /&gt;
    // chain. If not, add a new node to head of chain.&lt;br /&gt;
    if (node == null)&lt;br /&gt;
    {&lt;br /&gt;
      data[index] = new Node(data[index], key, val);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      // Otherwise update data value of existing node.&lt;br /&gt;
      node.val = val;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Given a key object, return a data object from the table or&lt;br /&gt;
   *  null if it is not found.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   *@return      data object reference or null if no object found&lt;br /&gt;
   */&lt;br /&gt;
  public Object get(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    Node temp = find(key, data[getIndex(key)]);&lt;br /&gt;
    if (temp != null)&lt;br /&gt;
    {&lt;br /&gt;
      return temp.val;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      return null;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''  Delete Example: Delete a node from the chain.'''&lt;br /&gt;
  /**&lt;br /&gt;
   * Remove a key/value pair from table if present, otherwise make no change.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  key object reference&lt;br /&gt;
   */&lt;br /&gt;
  public void remove(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    int index = getIndex(key);&lt;br /&gt;
    Node ref = data[index];&lt;br /&gt;
    Node previous = null;&lt;br /&gt;
    while (ref != null)&lt;br /&gt;
    {&lt;br /&gt;
      if ((ref.key).equals(key))&lt;br /&gt;
      {&lt;br /&gt;
        if (previous == null)&lt;br /&gt;
        {&lt;br /&gt;
          data[index] = ref.next;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
          previous.next = ref.next;&lt;br /&gt;
        }&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      previous = ref;&lt;br /&gt;
      ref = ref.next;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Given a key, use a hash function to obtain the array index of the chain&lt;br /&gt;
   *  corresponding to the key.&lt;br /&gt;
   *  The hashCode method inherited (and possibly overridden)&lt;br /&gt;
   *  from class Object is called to do the hashing, with the returned&lt;br /&gt;
   *  value constrained to the hash table array bounds.&lt;br /&gt;
   *  The distribution of objects in the hash table will depend&lt;br /&gt;
   *  on the quality of the hash function implemented by hashCode.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key  reference to object to be hashed&lt;br /&gt;
   *@return      array index of chain corresponding to key&lt;br /&gt;
   */&lt;br /&gt;
  private int getIndex(Object key)&lt;br /&gt;
  {&lt;br /&gt;
    return Math.abs(key.hashCode() % data.length);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   *  Find node given a key and a chain to search.&lt;br /&gt;
   *&lt;br /&gt;
   *@param  key    key object reference&lt;br /&gt;
   *@param  ref    node object reference where search will start&lt;br /&gt;
   *@return        node object holding key or null if not found&lt;br /&gt;
   */&lt;br /&gt;
  private Node find(Object key, Node ref)&lt;br /&gt;
  {&lt;br /&gt;
    while (ref != null)&lt;br /&gt;
    {&lt;br /&gt;
      if ((ref.key).equals(key))&lt;br /&gt;
      {&lt;br /&gt;
        return ref;&lt;br /&gt;
      }&lt;br /&gt;
      ref = ref.next;&lt;br /&gt;
    }&lt;br /&gt;
    return null;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
&lt;br /&gt;
The key issue in a hash table in a parallel environment is to make sure any update/insert/delete sequences have been completed properly prior to attempting subsequent operations to make sure the data has been synched appropriately.  However, since access speed is such a critical component of the design of a hash table, it is essential to try and avoid using too many locks for performing synchronization.  Fortunately, a number of lock-free hash designs have been implemented to avoid this bottleneck.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Graphs ==&lt;br /&gt;
=== Graph Intro ===&lt;br /&gt;
&lt;br /&gt;
A graph data structure is another type of linked-list structure that focuses on data that requires linking according to various types of relationships.  For example, in a networking application, one network node may have connections to a variety of other network nodes.  These nodes then also link to a variety of other nodes in the network.  Using this connection of nodes, it would be possible to then find a path from one specific node to another in the chain.  This could be accomplished by having each node contain a linked list of pointers to all other reachable nodes.&lt;br /&gt;
&lt;br /&gt;
=== Serial Code Example ===&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Add a new edge to the graph.&lt;br /&gt;
     */&lt;br /&gt;
    public void addEdge( String sourceName, String destName, double cost )&lt;br /&gt;
    {&lt;br /&gt;
        Vertex v = getVertex( sourceName );&lt;br /&gt;
        Vertex w = getVertex( destName );&lt;br /&gt;
        v.adj.add( new Edge( w, cost ) );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Single-source unweighted shortest-path algorithm.&lt;br /&gt;
     */&lt;br /&gt;
    public void unweighted( String startName )&lt;br /&gt;
    {&lt;br /&gt;
        clearAll( ); &lt;br /&gt;
&lt;br /&gt;
        Vertex start = (Vertex) vertexMap.get( startName );&lt;br /&gt;
        if( start == null )&lt;br /&gt;
            throw new NoSuchElementException( &amp;quot;Start vertex not found&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
        LinkedList q = new LinkedList( );&lt;br /&gt;
        q.addLast( start ); start.dist = 0;&lt;br /&gt;
&lt;br /&gt;
        while( !q.isEmpty( ) )&lt;br /&gt;
        {&lt;br /&gt;
            Vertex v = (Vertex) q.removeFirst( );&lt;br /&gt;
&lt;br /&gt;
            for( Iterator itr = v.adj.iterator( ); itr.hasNext( ); )&lt;br /&gt;
            {&lt;br /&gt;
                Edge e = (Edge) itr.next( );&lt;br /&gt;
                Vertex w = e.dest;&lt;br /&gt;
                if( w.dist == INFINITY )&lt;br /&gt;
                {&lt;br /&gt;
                    w.dist = v.dist + 1;&lt;br /&gt;
                    w.prev = v;&lt;br /&gt;
                    q.addLast( w );&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Parallel Code Solution ===&lt;br /&gt;
&lt;br /&gt;
= Quiz =&lt;br /&gt;
= References =&lt;br /&gt;
http://oreilly.com/catalog/masteralgoc/chapter/ch08.pdf&lt;br /&gt;
http://www.devjavasoft.org/code/classhashtable.html&lt;br /&gt;
http://osr600doc.sco.com/en/SDK_c++/_Intro_graph.html&lt;br /&gt;
web.eecs.utk.edu/~berry/cs302s02/src/code/Chap14/Graph.java&lt;br /&gt;
http://people.engr.ncsu.edu/efg/506/s01/lectures/notes/lec8.html&lt;br /&gt;
http://en.wikipedia.org/wiki/File:Hash_table_3_1_1_0_1_0_0_SP.svg&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Para3.PNG&amp;diff=59105</id>
		<title>File:Para3.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Para3.PNG&amp;diff=59105"/>
		<updated>2012-02-27T20:53:20Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Para2.PNG&amp;diff=59104</id>
		<title>File:Para2.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Para2.PNG&amp;diff=59104"/>
		<updated>2012-02-27T20:53:00Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Para_tree1.PNG&amp;diff=59103</id>
		<title>File:Para tree1.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Para_tree1.PNG&amp;diff=59103"/>
		<updated>2012-02-27T20:52:37Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Fig11.PNG&amp;diff=59102</id>
		<title>File:Fig11.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Fig11.PNG&amp;diff=59102"/>
		<updated>2012-02-27T20:51:03Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Fig10.PNG&amp;diff=59101</id>
		<title>File:Fig10.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Fig10.PNG&amp;diff=59101"/>
		<updated>2012-02-27T20:50:49Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Fig9.PNG&amp;diff=59100</id>
		<title>File:Fig9.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Fig9.PNG&amp;diff=59100"/>
		<updated>2012-02-27T20:50:39Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Fig8.PNG&amp;diff=59099</id>
		<title>File:Fig8.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Fig8.PNG&amp;diff=59099"/>
		<updated>2012-02-27T20:50:26Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Fig7.PNG&amp;diff=59098</id>
		<title>File:Fig7.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Fig7.PNG&amp;diff=59098"/>
		<updated>2012-02-27T20:50:16Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Fig6.PNG&amp;diff=59097</id>
		<title>File:Fig6.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Fig6.PNG&amp;diff=59097"/>
		<updated>2012-02-27T20:49:18Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Fig5.PNG&amp;diff=59096</id>
		<title>File:Fig5.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Fig5.PNG&amp;diff=59096"/>
		<updated>2012-02-27T20:48:51Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Fig3.PNG&amp;diff=59095</id>
		<title>File:Fig3.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Fig3.PNG&amp;diff=59095"/>
		<updated>2012-02-27T20:48:29Z</updated>

		<summary type="html">&lt;p&gt;Xzhang26: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Xzhang26</name></author>
	</entry>
</feed>