Caching¶
Core Idea¶
Caching is the technique of maintaining a fast, local, usually-smaller copy of information whose original is slow to produce or fetch, so that repeated or nearby accesses are served from the copy rather than from the source — exploiting locality of reference (the empirical observation that accesses exhibit temporal and spatial clustering) to reduce average latency, bandwidth consumption, computational cost, or coordination overhead[1]. The essential commitment is that a multi-tier storage or computation architecture with a small-fast tier and a large-slow tier can dramatically outperform either alone, given workloads with sufficient reuse, and that the cache's effectiveness depends jointly on the workload's locality, the cache's size and organization, the replacement policy[2], and the coherence (correctness) guarantees.
How would you explain it like I'm…
Keep a Snack Close
Fast Copy Nearby
Local Copy for Repeated Access
Structural Signature¶
- The two-level storage hierarchy (small-fast C with large-slow S, with locality exploitation as the enabling property) [3]
- The cache population mechanism (on-demand miss-driven fetch, prefetch/speculative load, or write-through) [4]
- The replacement policy (LRU, LFU, FIFO, clock, or application-specific) governing eviction on capacity pressure [2]
- The coherence / consistency model (strong, eventual, or weak) determining when cached copies are invalidated or updated [5]
- The hit-ratio metric as the performance predictor (τ_avg = h × τ_f + (1−h) × τ_s) relating locality to cost [4]
- The cost structure being optimized (latency, bandwidth, energy, computation, or contention) contextualizing cache design [4]
What It Is Not¶
-
Not identical to the principle of locality. Locality of reference is the empirical property of access patterns that makes caching effective; caching is the architectural / algorithmic response to that property. One could in principle exploit locality without caching (e.g., access-reordering optimizations) or cache without locality (rarely effective, since the cache gets frequent misses).
-
Not equivalent to mere storage or buffering. A buffer is a temporary holding area without reuse intent; a cache is specifically for accelerating repeated access by storing copies. Persistent storage is a cache of computation only if the stored result is reused; otherwise it is just storage.
-
Not always beneficial. Caching imposes overhead (lookup, management, coherence) that must be offset by hit-rate savings. In workloads with poor locality (random access over a large dataset) or high coherence costs, caching can slow the system. "Cache-oblivious" or "cache-aware" algorithm design addresses when and how to cache.
-
Not the same as memoization, though closely related. Memoization specifically stores results of pure function calls keyed by arguments. It is caching applied to deterministic computation. Caching in general includes non-functional applications (I/O results, mutable state).
-
Not a substitute for fundamental speed. A cache amortizes access but does not change worst-case performance. Systems designed for predictable latency (real-time, hard-deadline) often eschew caching for deterministic memory access patterns.
-
Common misclassification: Treating caching as a panacea for performance problems without analyzing locality structure, working-set size, or coherence costs — leading to cache misses worse than no cache, or stale-data bugs.
Broad Use¶
Caching appears in hardware (CPU L1/L2/L3 caches, TLBs, branch predictors, GPU texture caches), in operating systems (page cache, buffer cache, inode cache), in databases (buffer pool, query-result cache, materialized views), in web applications (HTTP caching, CDNs, Memcached, Redis, browser caches), in networking (DNS caches, ARP caches, route caches), in compilers and runtimes (compiled-code caches, method caches, JIT), in algorithms (memoization, dynamic programming), in distributed systems (local replicas, read-through / write-through / write-back patterns), in content delivery (Akamai, CloudFlare, Fastly), in AI systems (KV cache in LLM inference), in logistics (forward-deployed inventory), and in human cognition (working memory, frequently-used skills).
Clarity¶
Caching clarifies that systems with non-uniform access costs and non-uniform access frequencies can be optimized by tiered storage, that locality of reference is a pervasive workload property, that the hit/miss distinction is central to performance analysis[4], that cache size vs locality determines effectiveness, that coherence (when to invalidate) is a separate and often difficult problem, and that many seemingly disparate optimizations (CDNs, memoization, branch prediction) share a single structural pattern.
Manages Complexity¶
The construct manages complexity by factoring performance into a simple model (hit ratio × fast latency + miss ratio × slow latency + overhead), by reusing the same pattern across storage, networking, computation, and content delivery, and by supporting systematic analysis of workload performance via locality measurements (working-set size, reuse distance)[1]. The replacement-policy literature systematizes the choices for managing the cache itself. Belady's optimal algorithm (evict the item whose next reference is furthest in the future) provides a theoretical upper bound for comparison, even though it is impractical.
Abstract Reasoning¶
Caching reasoning proceeds by identifying the access pattern and its locality structure, sizing the cache relative to the working set, choosing a replacement policy consistent with the workload's temporal / frequency structure, specifying the coherence protocol, and analyzing expected hit rates and their performance implications[4]. It supports architectural decisions (where to place caches, how many layers, how large each), algorithmic design (cache-oblivious algorithms, working-set aware data structures), and operational troubleshooting (stale-cache bugs, thundering herd, cache-stampede mitigation).
Knowledge Transfer¶
A systems engineer's caching reasoning (access pattern, working set, replacement policy, coherence) transfers across hardware, networking, databases, and algorithms. The structural core is small-fast store in front of large-slow store + replacement policy + coherence; what varies is the substrate and the coherence requirements. The same diagnostic framework — is there locality, what is the hit ratio, what invalidation mechanism is appropriate — applies to CPU caches, DNS caches, CDNs, and memoization.
Examples¶
Formal/abstract¶
Wilkes' "slave memory" concept (1965) pioneered the two-level memory hierarchy: a fast register file backed by slower main memory. The canonical analysis comes from Denning and others: given a cache of size M and a working set of size W, if W ≤ M, the hit ratio approaches 1 and average access time approaches τ_f (the fast tier). If W ≫ M, the working set thrashes the cache, and performance approaches τ_s (the slow tier). Belady's optimal algorithm (1966) evicts the item whose next reference is furthest in the future — an upper bound for any replacement policy[6]. Practical policies (LRU, LFU, clock) approximate this bound. Patterson and Hennessy (2016) formalize the performance model in computer architecture: τ_avg = h × τ_f + (1 − h) × τ_s, where h is hit ratio, and this drives the analysis of multi-level memory hierarchies.
Mapped back: This instantiates the structural signature directly — two-level hierarchy, hit-ratio metric, replacement policy trade-offs, and performance model guiding cache design.
Applied/industry¶
A video-streaming service places popular video segments at edge servers geographically near users. When a user in Seoul requests a popular show, the request is served from a Seoul edge cache rather than from the U.S. origin server. For highly popular content with strong temporal locality (new episode releases), edge caches achieve hit rates exceeding 95%, dramatically reducing bandwidth costs and latency. Cache invalidation (content updates, geo-restrictions, licensing changes) is handled through explicit purges and TTLs. The structural match is real: small-fast store (edge) in front of large-slow store (origin), high locality (popular content is repeatedly requested), replacement by LRU or TTL, and coherence via invalidation[5]. This pattern recurs in virtually all large-scale web services.
Mapped back: This shows the same two-level hierarchy, locality exploitation, replacement mechanism, and coherence protocol applied to geographic content distribution at massive scale.
Structural Tensions¶
-
T1: Coherence / Staleness Tradeoff. Strong coherence (cache always reflects source) requires invalidation or write-through, imposing overhead. Weak coherence (eventual consistency, TTL-based freshness) is faster but risks serving stale data. The right choice depends on the semantic requirements and the cost of staleness[5]. Mismatched coherence model — strong where weak would suffice (slow), or weak where strong is needed (incorrect results, security bugs, financial errors) — is a failure mode.
-
T2: Cache Stampede / Thundering Herd on Miss. When a hot cached item expires or is invalidated, many concurrent requests may simultaneously attempt to regenerate or fetch it, overwhelming the source. Naive cache-aside patterns without locking or request coalescing can cause cascading failures under load when popular items expire; mitigation via probabilistic early refresh, request coalescing, or background refresh.
-
T3: Working Set Larger Than Cache. When the working set exceeds cache capacity, hit rates drop precipitously (cliff behavior), and performance may be worse than with no cache (overhead without benefit)[7]. Caches are deployed without measuring or estimating the working set size; performance degrades as data grows past the cliff; scaling cache capacity is reactive rather than proactive.
-
T4: Correctness Bugs From Cache Invalidation Errors. "There are only two hard things in computer science: cache invalidation and naming things" (Phil Karlton). Cache-invalidation bugs are a persistent source of correctness failures (users see stale permissions, stale prices, stale auth tokens). Invalidation logic is scattered, incomplete, or incorrect; debugging is hampered by the intermittent and stateful nature of cache bugs; systems drift into consistency violations that are difficult to detect and reproduce.
-
T5: Cache Size vs Lookup Overhead. Larger caches offer better hit rates but slower lookup (hash table growth, memory contention). Smaller caches are faster to search but miss more often. The optimal size depends on workload and hardware; exceeding CPU cache size can negate hit-rate gains through increased memory latency.
-
T6: Multi-Level Cache Coherence Across Tiers. Systems with L1, L2, L3, and main memory caches (or client/intermediate/origin caches in distributed systems) must coordinate coherence across tiers. Write-back vs write-through, invalidation vs update, snoop-based vs directory-based — each choice has cost implications and can create consistency bugs.
Structural–Framed Character¶
Caching sits at the structural end of the structural–framed spectrum: it is a pure relational pattern, the same in any domain where it appears, and nothing about its meaning depends on a particular field's vocabulary or assumptions.
Its content is a two-level hierarchy — a fast, smaller local copy standing in front of a slow, larger source — that exploits clustering in access patterns so repeated or nearby requests are served from the copy. The pieces are formal: the storage tiers, the population rule, and the locality property that makes the scheme pay off, with no evaluative weight or human institution required. The same pattern appears as a processor's memory cache, a browser storing fetched pages, or an organization keeping frequently needed reference data close at hand, and using it is recognizing a hierarchy already structuring the system. On every diagnostic, it reads structural.
Substrate Independence¶
Caching is a highly substrate-independent prime — composite 4 / 5 on the substrate-independence scale. Its signature — a small-fast tier fronting a large-slow one, exploiting locality and governed by a replacement policy — is largely substrate-agnostic. It travels across computing (memory hierarchies, CPU caches), cognitive science (working memory, chunking), operations (buffering and staging), and systems engineering, with examples ranging from Wilkes' slave memory to video-streaming edge caches to cognitive chunking. What keeps it from a 5 is that, although near-universal within caching-relevant domains, some of its instances straddle the computational and cognitive rather than reaching cleanly into every substrate.
- Composite substrate independence — 4 / 5
- Domain breadth — 4 / 5
- Structural abstraction — 4 / 5
- Transfer evidence — 4 / 5
Relationships to Other Abstractions¶
Current abstraction Caching Prime
Parents (3) — more general patterns this builds on
-
Caching presupposes Locality Of Reference Prime
Caching presupposes locality of reference because exploiting a fast-local copy only pays off when accesses cluster temporally or spatially.Caching presupposes locality of reference because the economic case for maintaining a small fast tier alongside a large slow tier depends entirely on workloads in which accesses cluster: recently-used items are likely to be reused soon, and items near a used one are likely to be touched next. Locality supplies the empirical distribution-of-access regularity that makes a cache pay off; without it, every access is equally likely to miss and the cache provides no average-case advantage over going straight to the source.
-
Caching presupposes Optimization Prime
Caching presupposes Optimization: keeping a fast local copy minimizes expected access cost under locality and capacity constraints.Caching maintains a small, fast tier holding likely-to-be-reused items so that average access latency or bandwidth cost is minimized given finite cache capacity. The eviction policy, sizing, and placement decisions are all instances of choosing values to minimize an expected-cost objective subject to capacity constraints. That is the optimization triplet — variables, objective, constraints — and caching presupposes optimization because every nontrivial cache design is implicitly or explicitly the solution to such a problem.
-
Caching presupposes Reserve Prime
Caching presupposes reserve because the fast local copy is a deliberately maintained surplus held against repeated access demand.Caching maintains a fast, local copy of information whose original is slow to fetch, so repeated accesses are served from the copy rather than the source. The cache is meaningful only as a deliberately held surplus — extra storage allocated beyond strict need, valuable precisely because available when demand patterns reuse it. Reserve supplies that structural object: a maintained surplus beyond expected need, absorbing variation without failure. Caching specializes reserve to information access, with locality of reference as the demand pattern the surplus exploits and latency reduction as the value delivered.
Children (1) — more specific cases that build on this
-
Two-Store Architecture Prime presupposes, typical Caching
Shares the fast-store/slow-store substrate pair with caching but REVERSES the origination flow (born-fast-migrates-slow vs born-slow-mirrored-fast); contrast-sibling rather than is a specialization of.Caching supplies the prerequisite condition: Store for faster retrieval. Two-Store Architecture operates against that background: A fast interference-prone store and a slow integrated store coupled by a periodic transfer mechanism, paying for both speed and integration by maintaining two oppositely-optimised substrates. If the parent condition is removed, the child relation becomes undefined or loses the mechanism asserted by this edge; the parent can obtain independently, so the relation is presupposition rather than subsumption. The typical qualifier limits the claim to the characteristic route, not a constitutive requirement of every instance; exceptions must retain the child's identity through another mechanism.
Hierarchy paths (9) — routes to 7 parentless roots
- Caching → Locality Of Reference → Recurrence
- Caching → Optimization
- Caching → Locality Of Reference → Heavy-Tailed Distributions
- Caching → Reserve → Mobilization → Latent Realizable Capacity
- Caching → Locality Of Reference → Spatial Indexing → Search and Retrieval → Trade-offs → Constraint
- Caching → Reserve → Economy Of Force → Allocation → Scarcity → Constraint
- Caching → Locality Of Reference → Spatial Indexing → Search and Retrieval → Problem Space → Representation → Abstraction
- Caching → Locality Of Reference → Spatial Indexing → Search and Retrieval → Problem Space → State and State Transition → Phase Space
- Caching → Locality Of Reference → Spatial Indexing → Search and Retrieval → Problem Space → Problem Representation → Representation → Abstraction
Neighborhood in Abstraction Space¶
Caching sits in a sparse region of abstraction space (87th percentile for distinctiveness): few abstractions share its structure, so a faithful description tends to retrieve it precisely rather than landing on a neighbor.
Family — Unclustered & Miscellaneous (429 primes)
Nearest neighbors
- Scalability — 0.70
- Two-Store Architecture — 0.70
- Pipeline — 0.69
- Encoding Specificity — 0.69
- Sharding — 0.69
Computed from structural-signature embeddings · 2026-07-26
Not to Be Confused With¶
Caching must be distinguished from Buffering, though both involve temporary storage. Buffering is a transient holding area that absorbs mismatches between the rate at which data is produced and the rate at which it is consumed — a buffer smooths demand-supply imbalances, allowing a fast producer to deposit data into the buffer while a slower consumer retrieves it at a sustainable rate. A network buffer absorbs bursts of incoming packets so the router does not drop them; an audio buffer in a media player absorbs jitter in network delivery so playback remains smooth. The motivation for buffering is flow management — maintaining throughput despite asynchronous rates. Caching, by contrast, stores items because they will be reused; the motivation is reuse avoidance. A cache stores frequently-accessed items near the point of use to reduce latency on repeated access. The critical difference: buffering is designed to be emptied (the buffer is transient, and items flow through it); caching is designed to retain popular items indefinitely (the cache persists as long as the system runs, and items stay in the cache as long as they are frequently used). A buffer with no throughput mismatch is wasted capacity; a cache with no reuse is also wasted, but a cache serving repeated requests saves cost each time an item is reused. The operational implications differ: buffer sizing is based on burst tolerance and throughput rates; cache sizing is based on working-set size and locality structure. A practical system might use both — a network buffer to smooth bursts, and a cache to avoid repeated fetches — but the structural mechanisms are distinct.
Caching is also not Chunking, despite both involving aggregation and memory-hierarchy reasoning. Chunking is the cognitive process (or data-organization principle) by which a learner groups individual items into meaningful units that can be manipulated as a single entity, reducing the number of items that must be held in working memory at once. A chess player chunks board positions into meaningful patterns (attack, defense, pawn structures), rather than remembering individual piece locations; a programmer chunks repeated code sequences into functions, rather than holding each sequence as separate lines. Chunking's primary benefit is reducing cognitive or operational load — fewer items to track, each richer in meaning. Caching's primary benefit is avoiding latency and computation — reusing a previously-computed or retrieved item rather than recomputing or refetching it. The two are orthogonal: caching can be applied to chunks (cache the function result rather than recompute it) or to non-chunked items (cache individual integers in a CPU L1 cache); chunking can organize cached or non-cached data. A system might use both strategically — chunk operations into larger units to improve cache locality, so the same cache lines stay resident longer — but the core mechanisms are separate. Chunking is about cognitive or logical grouping; caching is about reuse acceleration through proximity and duplication.
Finally, caching is distinct from Search and Retrieval, though they are closely related in practice. Search and retrieval is the process of finding and accessing a desired item from a large corpus — the mechanism by which a query is matched to data and the data is delivered. A database query engine retrieves rows matching a WHERE clause; an information retrieval system searches a corpus for documents matching keywords; a cache lookup searches the cache for a desired item. The search-and-retrieval mechanism is the underlying operation that caching optimizes. Caching avoids needing to search by keeping frequently-searched-for items in a fast, small store where they can be found immediately without searching the larger, slower store. A system with no cache must search the origin (main memory, disk, remote server) every time; a system with a cache searches the cache first (usually succeeding because of locality), and only searches the origin on a cache miss. The distinction is that caching assumes a search mechanism exists (and caches its results) while search-and-retrieval is the mechanism itself. A practical system uses both: a search engine is the retrieval mechanism; caching the top-100 queries is the performance optimization around that mechanism. Understanding the distinction prevents the confusion of substituting a cache for proper indexing — a cache accelerates retrieval but does not replace the need for efficient search structures if the dataset grows beyond cache capacity.
Solution Archetypes¶
Solution archetypes in the catalog that build on this prime — directly (this prime is a source ingredient) or as a related prime.
Built directly on this prime (4)
- Dynamic Subproblem Reuse: Reuse solutions to recurring subproblems so repeated decision work does not have to be recomputed.▸ Mechanisms (8)
- Cache Invalidation Review
- Dynamic Programming Method
- Dynamic Programming Table
- Memoization Cache
- Modular Planning Template
- Precedent Index
- Recurrence Equation
- Reusable Playbook Library
- Fast–Slow Store Coupling: Keep a volatile fast store and a durable integrated store coupled by governed transfer so the system gets immediate access without losing long-term coherence.▸ Mechanisms (10)
- Commit Log and Compaction Cycle
- Edge Cache with Origin Synchronization
- Hot/Warm/Cold Storage Tiering
- Inbox-to-Archive Processing Workflow
- Incident Timeline to Permanent Runbook Update
- Local Inventory Cache with System-of-Record Refresh
- Scratchpad-to-Knowledge-Base Curation
- Short-Term to Long-Term Memory Consolidation Routine
- Staging Table to Canonical Warehouse Pipeline
- Write-Back Cache with Durable Backing Store
- Precomputation / Prefetching: Do likely future work in advance so response is faster when demand arrives.▸ Mechanisms (10)
- Advance Staffing Roster
- Cache Warming
- Materialized View — Stores the precomputed result of a query as a physical table so an expensive join or aggregation is paid once at refresh time instead of on every read.
- Preapproved Template Packet
- Precomputed Report
- Predictive Prefetch
- Prepositioned Supply Kit
- Read-Ahead Loading
- Scenario Playbook
- Scheduled Batch Preparation
- Strategic Caching: Store high-value reusable results near where they are needed so repeated retrieval or computation becomes faster and less costly.▸ Mechanisms (8)
- Cached Approval
- Knowledge-Base FAQ
- Local Inventory Cache
- Memoization — Stores the result of a computation keyed by its inputs, so a repeat call with the same inputs returns the saved value instead of recomputing it.
- Precomputed Report
- Prepared Template Library
- Reusable Decision Precedent
- Web Cache
Also a related prime in 8 archetypes
- Access-Optimized Redundant Representation: Create a governed redundant representation around a proven access path, keep one authority and an explicit derivation, bound divergence, verify the benefit, and make refresh, repair, schema change, privacy, and retirement part of the design.
- Buffering: Insert bounded temporary holding capacity between producer and consumer to preserve continuity across mismatched rates, bursts, or timing gaps.
- Deferred Fulfillment Placeholder: Create a first-class placeholder for a committed future value so dependent work can proceed, compose, wait, cancel, or fail explicitly before the value exists.
- Demand-Triggered Deferred Evaluation: Represent optional or path-dependent work as a suspended unit, realize only the dependency closure demanded now, and make result sharing, side effects, failure timing, cancellation, lifetime, and first-use latency explicit.
- Index-Based Retrieval: Create an index or retrieval structure so relevant information can be found without scanning the whole space.
- Operation-Weighted Data Structure Design: Choose the information structure around the real operation mix, making lookup, update, traversal, storage, consistency, and maintenance tradeoffs explicit instead of accidental.
- Request–Response Capability Provisioning: Make a scarce or specialized capability addressable as a service that many independent clients can request and receive responses from under explicit capacity and failure rules.
- Task-Relevant Compression: Compress information by preserving what matters for the task and discarding or encoding the rest.
Notes¶
Caching is held at High confidence. Ubiquitous CS / systems-engineering construct with many applied substrates. The construct has deep roots: Wilkes' 1965 slave-memory concept, Denning's working-set theory, Belady's optimal algorithm, and Patterson-Hennessy's architectural formalization all provide foundational theory. The entry emphasizes the locality-exploitation mechanism, the coherence / staleness tradeoff, the failure modes (stampede, stale data, working-set cliffs), and the broad reach of the pattern beyond computing (biology, logistics, education, cognitive science). The performance model (h × τ_f + (1−h) × τ_s) recurs across all instances.
References¶
[1] Denning, P. J. (1968). "The working set model for program behavior". Communications of the ACM, 11(5), 323–333. Introduces the working-set model: a running program references only a small, slowly-drifting subset of its address space at any instant, so the working set rather than the whole address space is the unit of locality reasoning and management. Supports markers 016 and 024. ↩
[2] Podlipnig, S., & Böszörmenyi, L. (2003). "A survey of web cache replacement strategies". ACM Computing Surveys, 35(4), 374–398. Surveys and classifies cache replacement policies (LRU, LFU, FIFO, clock, and application-specific strategies) that govern eviction under capacity pressure. Supports markers 019 and 030. ↩
[3] Wilkes, M. V. (1965). "Slave memories and dynamic storage allocation". IEEE Transactions on Electronic Computers, EC-14(2), 270–271. Introduces the 'slave memory' — a small fast store fronting a large slow store so effective access time approaches that of the fast tier — the origin of the two-level cache hierarchy. Supports marker 017. ↩
[4] Hennessy, J. L., & Patterson, D. A. (2017). Computer Architecture: A Quantitative Approach (6th ed.). Morgan Kaufmann/Elsevier. Formalizes the memory-hierarchy performance model τ_avg = h × τ_f + (1 − h) × τ_s and the cache population mechanisms (miss-driven fetch, prefetch, write-through), the cost structures optimized, and the hit/miss analysis driving cache design. Supports markers 018, 021, 022, 023, 025. ↩
[5] Brewer, E. A. (2000). "Towards robust distributed systems". Proceedings of the 19th Annual ACM Symposium on Principles of Distributed Computing (PODC), 7. Keynote introducing the consistency-availability-partition (CAP) trade-off: strong consistency requires synchronous invalidation/update at a cost, while availability favors weaker (eventual/TTL-bounded) consistency that risks serving stale copies — the coherence-vs-staleness trade-off a cache must choose on. Supports markers 020, 027, 028. ↩
[6] Bélády, L. A. (1966). "A study of replacement algorithms for a virtual-storage computer". IBM Systems Journal, 5(2), 78–101. Introduces the optimal (MIN) replacement algorithm — evict the item whose next reference is furthest in the future — giving the theoretical upper bound against which practical replacement policies are measured. Supports marker 026. ↩
[7] Denning, P. J. (1968). "Thrashing: Its causes and prevention". Proceedings of the AFIPS Fall Joint Computer Conference, 33, 915–922. Shows that when the combined working sets exceed available fast storage the system thrashes — hit rate collapses and performance falls toward the slow tier — the working-set-larger-than-cache cliff behavior. Re-sources marker 029 (replaces a non-supporting, mis-dated Agarwal Alewife citation). ↩
[8] Karlton, P. (attributed). "There are only two hard things in computer science: cache invalidation and naming things." Widely attributed aphorism (no formal publication); popularized in systems-engineering literature and via XKCD #1722. Cited in support of the claim that cache invalidation is a persistent source of correctness bugs. Bibliography-only (tier C); no authoritative formal source exists, left link-less.
[9] Agarwal, A., et al. (1989). "The MIT alewife machine: Architecture and performance." Proceedings of the 16th Annual International Symposium on Computer Architecture, 2–13.