Exploiting On-Chip Data Transfers for Improving Performance of Chip-Scale Multiprocessors

Similar documents
Computer Architecture A Quantitative Approach, Fifth Edition. Chapter 2. Memory Hierarchy Design. Copyright 2012, Elsevier Inc. All rights reserved.

Copyright 2012, Elsevier Inc. All rights reserved.

LECTURE 5: MEMORY HIERARCHY DESIGN

Copyright 2012, Elsevier Inc. All rights reserved.

Computer Architecture. A Quantitative Approach, Fifth Edition. Chapter 2. Memory Hierarchy Design. Copyright 2012, Elsevier Inc. All rights reserved.

Memory Systems and Compiler Support for MPSoC Architectures. Mahmut Kandemir and Nikil Dutt. Cap. 9

EI338: Computer Systems and Engineering (Computer Architecture & Operating Systems)

Locality-Aware Process Scheduling for Embedded MPSoCs*

SPM Management Using Markov Chain Based Data Access Prediction*

Exploiting Shared Scratch Pad Memory Space in Embedded Multiprocessor Systems

Adapted from David Patterson s slides on graduate computer architecture

Chapter-5 Memory Hierarchy Design

Optimizing Inter-Nest Data Locality

2 Improved Direct-Mapped Cache Performance by the Addition of a Small Fully-Associative Cache and Prefetch Buffers [1]

TDT Coarse-Grained Multithreading. Review on ILP. Multi-threaded execution. Contents. Fine-Grained Multithreading

An Experimental Investigation into the Rank Function of the Heterogeneous Earliest Finish Time Scheduling Algorithm

10/16/2017. Miss Rate: ABC. Classifying Misses: 3C Model (Hill) Reducing Conflict Misses: Victim Buffer. Overlapping Misses: Lockup Free Cache

Large and Fast: Exploiting Memory Hierarchy

Behavioral Array Mapping into Multiport Memories Targeting Low Power 3

EITF20: Computer Architecture Part4.1.1: Cache - 2

Performance of Multithreaded Chip Multiprocessors and Implications for Operating System Design

Copyright 2012, Elsevier Inc. All rights reserved.

Objective. We will study software systems that permit applications programs to exploit the power of modern high-performance computers.

Area-Efficient Error Protection for Caches

Memory Hierarchy Computing Systems & Performance MSc Informatics Eng. Memory Hierarchy (most slides are borrowed)

Memory Hierarchy. Caching Chapter 7. Locality. Program Characteristics. What does that mean?!? Exploiting Spatial & Temporal Locality

EITF20: Computer Architecture Part4.1.1: Cache - 2

Memory Hierarchy Computing Systems & Performance MSc Informatics Eng. Memory Hierarchy (most slides are borrowed)

Dynamic Compilation for Reducing Energy Consumption of I/O-Intensive Applications

Profiling-Based L1 Data Cache Bypassing to Improve GPU Performance and Energy Efficiency

Power Protocol: Reducing Power Dissipation on Off-Chip Data Buses

Cache Performance (H&P 5.3; 5.5; 5.6)

The University of Adelaide, School of Computer Science 13 September 2018

CS6303 Computer Architecture Regulation 2013 BE-Computer Science and Engineering III semester 2 MARKS

Characteristics of Mult l ip i ro r ce c ssors r

Chapter 5. Large and Fast: Exploiting Memory Hierarchy

Addendum to Efficiently Enabling Conventional Block Sizes for Very Large Die-stacked DRAM Caches

ELEC 5200/6200 Computer Architecture and Design Spring 2017 Lecture 7: Memory Organization Part II

A Cache Hierarchy in a Computer System

Outline Marquette University

A Hybrid Approach to CAM-Based Longest Prefix Matching for IP Route Lookup

Cache memories are small, fast SRAM-based memories managed automatically in hardware. Hold frequently accessed blocks of main memory

Donn Morrison Department of Computer Science. TDT4255 Memory hierarchies

Unit 9 : Fundamentals of Parallel Processing

Compiler-Directed Array Interleaving for Reducing Energy in Multi-Bank Memories

Optimal Porting of Embedded Software on DSPs

AS the applications ported into System-on-a-Chip (SoC)

Memory Management! How the hardware and OS give application pgms:" The illusion of a large contiguous address space" Protection against each other"

Chapter 2: Memory Hierarchy Design Part 2

DDM-CMP: Data-Driven Multithreading on a Chip Multiprocessor

Multithreaded Architectures and The Sort Benchmark. Phil Garcia Hank Korth Dept. of Computer Science and Engineering Lehigh University

Topics. Digital Systems Architecture EECE EECE Need More Cache?

Memory. From Chapter 3 of High Performance Computing. c R. Leduc

Language and Compiler Support for Out-of-Core Irregular Applications on Distributed-Memory Multiprocessors

Improving Bank-Level Parallelism for Irregular Applications

Cache Memories. From Bryant and O Hallaron, Computer Systems. A Programmer s Perspective. Chapter 6.

Chapter 2: Memory Hierarchy Design Part 2

LECTURE 4: LARGE AND FAST: EXPLOITING MEMORY HIERARCHY

Lecture notes for CS Chapter 2, part 1 10/23/18

LRU. Pseudo LRU A B C D E F G H A B C D E F G H H H C. Copyright 2012, Elsevier Inc. All rights reserved.

Embedded Systems Dr. Santanu Chaudhury Department of Electrical Engineering Indian Institution of Technology, Delhi

Course II Parallel Computer Architecture. Week 2-3 by Dr. Putu Harry Gunawan

To Use or Not to Use: CPUs Cache Optimization Techniques on GPGPUs

Improving Geographical Locality of Data for Shared Memory Implementations of PDE Solvers

Memory. Lecture 22 CS301

Chap. 4 Multiprocessors and Thread-Level Parallelism

,e-pg PATHSHALA- Computer Science Computer Architecture Module 25 Memory Hierarchy Design - Basics

Memories. CPE480/CS480/EE480, Spring Hank Dietz.

Memory Hierarchy Basics. Ten Advanced Optimizations. Small and Simple

Increasing Instruction-Level Parallelism with Instruction Precomputation

Reducing Hit Times. Critical Influence on cycle-time or CPI. small is always faster and can be put on chip

Advanced Memory Organizations

Cache Performance! ! Memory system and processor performance:! ! Improving memory hierarchy performance:! CPU time = IC x CPI x Clock time

An Analysis of the Amount of Global Level Redundant Computation in the SPEC 95 and SPEC 2000 Benchmarks

Reducing Instruction Cache Energy Consumption Using a Compiler-Based Strategy

Load Balancing in the Macro Pipeline Multiprocessor System using Processing Elements Stealing Technique. Olakanmi O. Oladayo

Performance Study of a Compiler/Hardware Approach to Embedded Systems Security

Lecture: Cache Hierarchies. Topics: cache innovations (Sections B.1-B.3, 2.1)

Performance Impact of Resource Conflicts on Chip Multi-processor Servers

Chapter 6 Caches. Computer System. Alpha Chip Photo. Topics. Memory Hierarchy Locality of Reference SRAM Caches Direct Mapped Associative

Cache in a Memory Hierarchy

Chapter 5A. Large and Fast: Exploiting Memory Hierarchy

Chapter 5. Large and Fast: Exploiting Memory Hierarchy

Advanced optimizations of cache performance ( 2.2)

Memory Management! Goals of this Lecture!

LARGE scale parallel scientific applications in general

Cache Performance! ! Memory system and processor performance:! ! Improving memory hierarchy performance:! CPU time = IC x CPI x Clock time

Understanding The Behavior of Simultaneous Multithreaded and Multiprocessor Architectures

15-740/ Computer Architecture Lecture 20: Main Memory II. Prof. Onur Mutlu Carnegie Mellon University

CSC Memory System. A. A Hierarchy and Driving Forces

Memory Hierarchy Basics

CS24: INTRODUCTION TO COMPUTING SYSTEMS. Spring 2014 Lecture 14

Locality-Conscious Process Scheduling in Embedded Systems

Multiprocessing and Scalability. A.R. Hurson Computer Science and Engineering The Pennsylvania State University

Lecture 15: Caches and Optimization Computer Architecture and Systems Programming ( )

Low Power Set-Associative Cache with Single-Cycle Partial Tag Comparison

WHY PARALLEL PROCESSING? (CE-401)

Compiler Algorithms for Optimizing Locality and Parallelism on Shared and Distributed-Memory Machines

Computer Organization and Structure. Bing-Yu Chen National Taiwan University

Agenda Cache memory organization and operation Chapter 6 Performance impact of caches Cache Memories

Transcription:

Exploiting On-Chip Data Transfers for Improving Performance of Chip-Scale Multiprocessors G. Chen 1, M. Kandemir 1, I. Kolcu 2, and A. Choudhary 3 1 Pennsylvania State University, PA 16802, USA 2 UMIST, Manchester M60 1QD, UK 3 Northwestern University, Evanston, IL 60208, USA Abstract. As compared to a complex single processor based system, on-chip multiprocessors are less complex, more power efficient, and easier to test and validate. In this work, we focus on an on-chip multiprocessor where each processor has a local memory (or cache). We demonstrate that, in such an architecture, allowing each processor to do off-chip memory requests on behalf of other processors can improve overall performance over a straightforward strategy, where each processor performs off-chip requests independently. Our experimental results obtained using six benchmark codes indicate large execution cycle savings over a wide range of architectural configurations. 1 Introduction A natural memory architecture for an on-chip multiprocessor is the one in which each processor has a private (on-chip) memory space (in form of either a softwarecontrolled local memory or a hardware-controlled cache). Consequently, assuming the existence of an off-chip (shared) memory, from a given processor s perspective, we have a two-level memory hierarchy: on-chip local memory and offchip global-memory. One of the most critical issues in exploiting this two-level memory hierarchy is to reduce the number of off-chip accesses. Note that reducing off-chip memory accesses is beneficial not only from the performance perspective but also from the energy consumption viewpoint. This is because energy consumption is a function of the effective switching capacitance [2], and large off-chip memory structures have much larger capacitances as compared to relatively smaller on-chip memory structures. In this paper, we focus on such a two-level memory architecture, and propose and evaluate a compiler-directed optimization strategy which reduces the frequency and volume of the off-chip memory traffic. Our approach targets arrayintensive applications, and is based on the observation that, in an on-chip multiprocessor, inter-processor communication is cheaper (both performance and energy wise) than off-chip memory accesses. Consequently, we develop a strategy which reduces off-chip memory accesses at the expense of increased on-chip H. Kosch, L. Böszörményi, H. Hellwagner (Eds.): Euro-Par 2003, LNCS 2790, pp. 271 278, 2003. c Springer-Verlag Berlin Heidelberg 2003

272 G. Chen et al. data traffic. The net result is significant savings in execution cycles. Our approach achieves its objective by not performing off-chip memory accesses based on data requirements of each individual processor but based on the layout of the data in the off-chip memory. In other words, the total data space (array elements) that will be required considering all processors is traversed (accessed) in a layout-efficient manner (instead of allowing each processor access off-chip memory according to its own needs). The consequence of this collective memory access strategy is that each processor gets some data which are, potentially, required by some other processor. In the next step, the processors engage in a many-to-many communication (i.e., they access each others local memories) and, after this on-chip communication step, each processor gets the data it originally wanted. We implemented the necessary compilation techniques for this two-step optimization strategy using an experimental compiler, and collected results from this implementation. Experimental data obtained using six application codes clearly demonstrate the effectiveness of our strategy. In order to measure the robustness of our approach, we also conducted experiments with different architectural parameters (due to the space limitation, the results are omitted in this paper). Based on our experimental data, we believe that the proposed strategy is a much better alternative to a more straightforward strategy, where each processor performs independent off-chip memory accesses. Our experimental results indicate large execution cycle savings over a wide range of architectural configurations. The results also indicate that the proposed approach outperforms an alternate technique that employs classical locality-oriented loop optimizations. 2 Architecture Abstraction In this paper, we focus on an architectural abstraction depicted in Figure 1. In this abstraction, the on-chip multiprocessor contains k CPU-local memory pairs. There is also an off-chip (shared) global memory. There are two buses: an on-chip bus that connects local memories to each other, and an off-chip bus that connects local memories to the off-chip global memory. The other components of the on-chip multiprocessor (e.g., the clock circuitry, ASICs, signal converters, etc.) are omitted as they are not the focus of this work. It should be mentioned that many architectural implementations described by prior research are similar to this abstraction. In this architecture, a data item required by CPU j (1 j k) can be in three different locations: local memory j, local memory j of CPU j (where 1 j k and j j), and the global memory. The performance of a given application executing on such an architecture is significantly influenced by the location of the data requested. Typically, from the viewpoint of a given processor, accessing its local memory is much faster than accessing the global memory (and, in fact, considering current trends, we can expect this gap to be widened in the future). As compared to accessing its own local memory, accessing the local memory of some other processor (called remote local memory, or remote memory for

Exploiting On-Chip Data Transfers for Improving Performance 273 Fig. 1. On-chip multiprocessor abstraction. Fig. 2. Independent memory access vs. optimized memory access and data redistribution. short) is also more costly; however, such remote memory accesses are still much less expensive in comparison to global memory accesses. Therefore, an important issue in compiling applications for running on this chip-scale multiprocessor environment is to ensure that most of data requests of individual processors are satisfied from their local memories or remote memories. The goal of this paper is to present and evaluate a compiler-directed optimization strategy along this direction. It should be emphasized that, in this paper, when we mention on-chip communication, we mean remote memory access. Consequently, when we say processors engage in all-to-all (or many-to-many) communication, we mean that they access each other s local memory. We also use the terms off-chip memory and global memory interchangeably. 3 Our Approach Performance of an application executed on an on-chip multiprocessor is closely tied with the data access pattern. This is because data access pattern is the primary factor that determines how memory is accessed. Therefore, it is critically important that an application exhibits a good access pattern, in which data is accessed with temporal or spatial locality to the highest extent possible. Accesses with locality tend to frequently reuse the data in the same transfer unit (block), and this, in turn, reduces the number of off-chip memory accesses. However, a straightforward coding of many array-intensive applications does not lead to good memory access patterns. As an example, consider the simple loop structure given in Figure 2(a). Assuming that we would like to parallelize the outer loop across four processors (P 0, P 1, P 2, and P 3 ) in our on-chip multiprocessor, Figure 2(b) shows the data access pattern exhibited when each processor performs off-chip accesses independently. It can be seen from this access pattern that, assuming a row-major array layout in memory, each processor touches only a small amount of sequential data. In other words, the spatial locality exhibited

274 G. Chen et al. by each processor is very low. To quantify this, let us conduct a simple calculation to see the memory access cost of this loop nest. Assuming that the granularity of the data transfers between the off-chip memory and on-chip memory is 4 array elements and that the array is stored in a row-major format in the off-chip memory, each processor will make 8 off-chip requests in the access pattern depicted in Figure 2(b). The total volume of the data transferred by each processor is, therefore, 32 (and, note that only 16 of these are really useful). One simple strategy that can be adopted by an optimizing compiler is to interchange the loops. While this may help improve locality in some cases, in many loops, data dependences can prevent loop interchange (or similar loop transformations [4]). In this example, our two step solution operates as follows. We first consider the data layout in memory (which is row-major) and allow each processor access the data using the best possible access pattern (as depicted in Figure 2(c)). Now, each processor has some data which are, originally, required by some other processor. In the next step, the processors engage in an all-to-all (intra-chip) communication (a special case of many-to-many communication), and data is redistributed accordingly. We can calculate the cost of this approach as follows. The number of off-chip memory accesses per processor is only 4 (as all 16 elements that need to be read are consecutive in the off-chip memory). In addition, the total data volume (transferred from the off-chip memory) is 16 (i.e., no unneeded data is transferred). Note that, as compared to the independent memory access scenario, here we reduce the number of off-chip accesses (per processor) by half (which can lead to significant execution cycles savings). However, in this optimized strategy, we also need to perform inter-processor data re-distribution (i.e., the second step) so that each processor receives the data it originally wanted. In our example, each processor needs to send/receive data elements to/from the other three processors. Let us assume that performing an off-chip data transfer takes C 1 cycles and performing an on-chip communication (i.e., local memory-to-local memory transfer) takes C 2 cycles, the independent memory access strategy costs 8C 1 (per processor) and our optimized strategy costs 4C 1 +3C 2 (again, per processor). Assuming C 1 is 50 cycles and C 2 is 10 cycles, our approach improves data access cost by 42.5% (170/400). This small example (with its simplistic cost view) shows that performing off-chip data accesses on behalf of other processors can actually improve the performance of the straightforward (independent) memory access strategy. It should be noted that, depending on whether the local memory space is a software-managed local memory or hardware-managed cache, it might be necessary (in our approach) to interleave off-chip data accesses with on-chip communication. If the local memory is software-managed and is large enough to hold the entire set of elements that will be transferred from the off-chip memory, it is acceptable to first perform all off-chip accesses and, then, perform on-chip communication. On the other hand, if the on-chip local memory is not large enough to hold all the required elements, then we need to tile the computation. What tiling means in this context is that we first transfer (from the off-chip memory) some data elements (called data tile ) to fill the local memory, then perform

Exploiting On-Chip Data Transfers for Improving Performance 275 Benchmark Brief Description Cycles Atr Network IP address translator 11,095,718 SP Computing the all-nodes shortest paths on a given graph 13,892,044 Encr Secure digital signature generator and verifier 30,662,073 Hyper Multiprocessor communication activity simulator 18,023,649 Wood Color-based visual surface inspector 37,021,119 Usonic Feature-based object estimation 46,728,681 Fig. 3. Brief Description of our benchmarks. on-chip communication, and then perform the computation on this data tile (and write back the tile to the global memory if it is modified). After this, we transfer the next set of elements (i.e., the next data tile) and proceed the same way, and so on. It should be observed that if the on-chip memory space is implemented as a conventional cache, tiling the computation might be very important as there is no guarantee that all the data transferred from the off-chip memory will still remain in the cache at the time we move to the on-chip communication phase. Note that, in a straightforward off-chip memory access strategy, each processor accesses its portion of an array without taking into consideration of the storage pattern of the array (i.e., how the array is laid out in memory). In contrast, in our approach, the processors first access the data using an access pattern, which is the same as the storage pattern of the array. This helps reduce the number of off-chip memory references. After that, the data are redistributed across processors so that each array element arrives in its final destination. In general, the proposed strategy will be useful when access pattern and storage pattern are different. 4 Experiments 4.1 Setup We used six applications to test the success of our optimization strategy. The brief descriptions of these benchmarks are presented in Figure 3. While we have also access to pointer-based versions of these applications, in this study, we only used their array-based versions. These applications are coded in such a way that their input sizes can be set by the programmer. In this work, the total data sizes manipulated by these applications range from 661.4KB to 1.14MB. We simulated execution of an on-chip multiprocessor with local and global memories using a custom simulator. Each processor is a simple, single-issue architecture with a pipeline of five stages. Our simulator takes an architectural description and an executable code. The architectural description indicates the number of processors, the capacities of on-chip and off-chip memories, and their relative access latencies. We refer to the relative access latencies of local, remote, and global memories as the access ratio. For example, an access ratio of 1:10:50 indicates that a remote memory access is ten times as costly as a local memory

276 G. Chen et al. Fig. 4. Execution cycle breakdown for the default mode of execution. Fig. 5. Normalized number of off-chip accesses, transfer volume, and overall execution cycles. access, and that a global memory access is five times as costly as a remote memory access. We ran the optimized code on a Sun UltraSparc machine. By default, we assume that the system has 8 processors (runnig at 250MHz) on the chip. Each processor has 4KB local memory. These processors share a 32MB global memory. The access ratio (i.e, the relative access latencies of local, remote and global memories) is 1:10:50. In order to evaluate the effectiveness of our approach, we compare it to a default mode of execution. In this mode, each processor performs independent off-chip memory accesses. However, before going to the off-chip memory, it first checks its local memory, and then checks all remote memories. Consequently, if the requested data item is available in either local memory or remote memories, the off-chip memory access is avoided. As discussed earlier in detail, our approach tries to improve over this default mode of execution by performing off-chip memory accesses in a coordinated fashion. In this strategy, each processor performs off-chip accesses in a way which is most preferable from the data locality viewpoint. After this, processors exchange data so that each data item arrives in its final destination. The last columns of Figure 3 gives the execution cycles obtained under this default mode of execution. Execution cycles reported in the rest of this paper are values normalized with respect to these numbers. In comparing our optimization strategy to the default mode of execution, we used three different metrics. The first metric is the number of off-chip accesses. The second metric is the transfer volume, which is the amount of data transferred from the off-chip memory. As discussed earlier in the paper, our approach is expected to transfer fewer data items (as it exploits spatial locality in off-chip accesses) than the default mode of execution. While reductions in these two metrics indicate the effectiveness of our approach, the ultimate criterion is the reduction in overall execution cycles, which is our third metric. 4.2 Results Figure 4 gives the execution cycle breakdown when each processor accesses the global memory independently (default mode of execution). In this graph, execution cycles are divided into three parts: (1) cycles spent in executing code

Exploiting On-Chip Data Transfers for Improving Performance 277 Fig. 6. Normalized execution cycles of different versions. (including local memory accesses); (2) cycles spent in performing remote memory accesses; and (3) cycles spent in performing global memory accesses (i.e., off-chip accesses). Our first observation is that, on the average, 56.3% of cycles are expended in waiting for off-chip data to arrive. This observation clearly underlines the importance of reducing the number of off-chip data requests. In comparison, the cycles spent in remote memory accesses constitute only 8.75% of total cycles. The graph in Figure 5 shows the number of off-chip memory accesses, transfer volume, and execution cycles resulting from our strategy, each normalized with respect to the corresponding quantity incurred when the default execution mode is used. We see that the average reductions in the number of off-chip memory accesses and transfer volume are 53.66% and 38.18%, respectively. These reductions, in turn, lead to 23.45% savings in overall execution cycles. As a result, we can conclude that our approach is much more successful than the default mode of execution. Execution cycle savings are lower in Encr and Usonic as the original off-chip access patterns exhibited by these applications are relatively good (as compared to the access pattern of the other applications under the default mode of execution). One might argue that classical loop transformations can be used for achieving similar improvement to those provided by our optimization strategy. To check this, we measured performance of the loop optimized versions of our benchmark codes. The loop transformations used here are linear transformations (e.g., loop interchange and scaling), iteration space tiling, and loop fusion. To select the best tile size, we employed the technique proposed by Coleman and McKinley [3]. The first bar of each benchmark in Figure 6 gives the execution cycles of this version, normalized with respect to the original codes (note that both the versions use the default mode of execution). The average improvement brought by this loop-optimized version is 11.52%, which is significantly lower than the average improvement provided by our approach, which is 23.45% (the results of our approach are reproduced as the third bar in Figure 6). The reason that our approach performs better than classical loop transformations is related to data dependences [4]. Specifically, a loop transformation cannot be used if it violates the intrinsic data dependences in the loop being optimized. In many of the loops in our benchmark codes (specifically, in 45% of all loop nests), data dependences

278 G. Chen et al. prevent the best loop transformation from being applied. However, this result does not mean that our optimization strategy cannot take advantage of loop transformations. To evaluate the impact of loop optimizations on the effectiveness of our approach, in our next set of experiments, we measured the execution cycles of a version that combines our approach with loop optimizations. The loop optimizations employed are the ones mentioned earlier. Specifically, we first restructured the code using loop transformations such that spatial locality is improved as much as possible. We then applied our approach in performing off-chip data accesses. The last bar in Figure 6 for each application gives the normalized execution cycles for this version. One can observe that average improvements due to this enhanced version is 26.98% (a 3.53% additional improvement over our base strategy). It is also important to see how close our optimization comes to the optimal in reducing execution cycles. In order to see this, we performed experiments with a hand-optimized version that reduces the off-chip activity to a minimum. It achieves this using a global optimization strategy which considers all nests in the application together and by assuming an infinite amount of on-chip storage. In other words, for each data item, if possible, an off-chip reference is made only once (and since we have unlimited on-chip memory, no data item needs to be written back even if it is modified). The second bar for each application in Figure 6 presents the behavior of this strategy. We see that the average execution cycle improvements is around 31.77%, indicating that our approach still has a large gap to close to reach the optimal. 5 Concluding Remarks On-chip multiprocessing can be aimed at systems that require high performance in either instruction-level parallelism (ILP) or thread-level parallelism, since additional threads can be run simultaneously on other CPU cores within the chip, and therefore, is expected to have a clear advantage over traditional architectures that concentrate on ILP. In this paper, we demonstrate how a compiler can optimize off-chip data accesses in an on-chip multiprocessor based environment by allowing collective off-chip accesses, whereby each processor performs off-chip accesses on behalf of other processors. Our results clearly show the benefits of this approach. References 1. S. P. Amarasinghe et al. Multiprocessors from a Software Perspective. IEEE Micro Magazine, June 1996, pages 52 61. 2. A. Chandrakasan, W. J. Bowhill, and F. Fox. Design of High-Performance Microprocessor Circuits. IEEE Press, 2001. 3. S. Coleman and K. S. McKinley. Tile Size Selection Using Cache Organization and Data Layout. Proceedings of the SIGPLAN 95 Conference on Programming Language Design and Implementation, La Jolla, CA, June 1995. 4. S. S. Muchnick. Advanced Compiler Design and Implementation. Morgan Kaufmann, 1997.