Files
test-repo/docs/.vitepress/theme/components/appendix/computer-fundamentals/CacheDemo.vue
T
sanbuphy f44c842fe7 feat(docs): update computer fundamentals content and demos
- Refactor frontend framework demo descriptions for clarity
- Remove interactive features from triad and field map demos
- Add new computer organization and DSL documentation links
- Split type systems and compilers into separate pages
- Enhance power-on-to-web article with relay race analogy
- Add new interactive demos for type systems and compilation
- Improve visual presentation of boot process and hardware flow
- Introduce new Vibe Coding flow demo component
2026-02-25 01:38:27 +08:00

545 lines
12 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="cache-demo">
<div class="demo-header">
<span class="title">缓存 (Cache) 原理</span>
<span class="subtitle">CPU 与内存之间的"桥梁"</span>
</div>
<div class="cache-visualization">
<div class="cache-levels">
<div class="level cpu-level">
<div class="level-label">CPU 核心</div>
<div class="level-icon"></div>
</div>
<div class="arrow-right"></div>
<div class="level l1-cache" :class="{ active: activeLevel === 'L1' }">
<div class="level-label">L1 缓存</div>
<div class="level-info">
<span class="size">64 KB</span>
<span class="speed">~1ns</span>
</div>
</div>
<div class="arrow-right"></div>
<div class="level l2-cache" :class="{ active: activeLevel === 'L2' }">
<div class="level-label">L2 缓存</div>
<div class="level-info">
<span class="size">256 KB</span>
<span class="speed">~5ns</span>
</div>
</div>
<div class="arrow-right"></div>
<div class="level l3-cache" :class="{ active: activeLevel === 'L3' }">
<div class="level-label">L3 缓存</div>
<div class="level-info">
<span class="size">8 MB</span>
<span class="speed">~15ns</span>
</div>
</div>
<div class="arrow-right"></div>
<div class="level memory" :class="{ active: activeLevel === 'MEM' }">
<div class="level-label">主存</div>
<div class="level-info">
<span class="size">16 GB</span>
<span class="speed">~100ns</span>
</div>
</div>
</div>
</div>
<div class="cache-operation">
<div class="control-panel">
<div class="panel-title">缓存操作演示</div>
<div class="btn-group">
<button class="btn" @click="simulateRead(100)">读取地址 100</button>
<button class="btn" @click="simulateRead(104)">读取地址 104</button>
<button class="btn" @click="simulateRead(200)">读取地址 200</button>
<button class="btn" @click="simulateRead(108)">读取地址 108</button>
</div>
</div>
<div class="operation-log">
<div class="log-title">操作记录</div>
<div class="log-content">
<div v-for="(log, i) in logs" :key="i" :class="['log-item', log.type]">
<span class="log-time">T+{{ log.time }}ns</span>
<span class="log-text">{{ log.text }}</span>
</div>
</div>
</div>
</div>
<div class="locality-explanation">
<div class="exp-title">为什么缓存有效 局部性原理</div>
<div class="locality-grid">
<div class="locality-card">
<div class="locality-icon"></div>
<div class="locality-name">时间局部性</div>
<div class="locality-desc">刚访问的数据很可能再次被访问</div>
<div class="locality-example">循环中的变量</div>
</div>
<div class="locality-card">
<div class="locality-icon">📦</div>
<div class="locality-name">空间局部性</div>
<div class="locality-desc">访问某个数据后附近的数据也可能被访问</div>
<div class="locality-example">数组遍历顺序执行</div>
</div>
</div>
</div>
<div class="cache-mapping">
<div class="mapping-title">缓存映射方式</div>
<div class="mapping-tabs">
<button
v-for="map in mappings"
:key="map.type"
:class="['map-btn', { active: selectedMapping === map.type }]"
@click="selectedMapping = map.type"
>
{{ map.type }}
</button>
</div>
<div class="mapping-details" v-if="selectedMappingData">
<div class="mapping-desc">{{ selectedMappingData.desc }}</div>
<div class="mapping-compare">
<div class="compare-item">
<span class="compare-label">速度</span>
<span class="compare-value fast">{{ selectedMappingData.speed }}</span>
</div>
<div class="compare-item">
<span class="compare-label">命中率</span>
<span class="compare-value">{{ selectedMappingData.hitRate }}</span>
</div>
<div class="compare-item">
<span class="compare-label">实现复杂度</span>
<span class="compare-value">{{ selectedMappingData.complexity }}</span>
</div>
</div>
</div>
</div>
<div class="hit-rate-calc">
<div class="calc-title">命中率计算</div>
<div class="calc-formula">
<span class="formula">平均访问时间 = H × T<sub>c</sub> + (1-H) × T<sub>m</sub></span>
</div>
<div class="calc-example">
<div class="calc-row">
<label>缓存访问时间 (Tc):</label>
<input type="range" v-model="tc" min="1" max="10" />
<span>{{ tc }} ns</span>
</div>
<div class="calc-row">
<label>内存访问时间 (Tm):</label>
<input type="range" v-model="tm" min="50" max="200" />
<span>{{ tm }} ns</span>
</div>
<div class="calc-row">
<label>命中率 (H):</label>
<input type="range" v-model="hitRate" min="0" max="100" />
<span>{{ hitRate }}%</span>
</div>
<div class="calc-result">
平均访问时间 = {{ avgTime }} ns
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeLevel = ref('')
const logs = ref([])
const tc = ref(2)
const tm = ref(100)
const hitRate = ref(90)
const selectedMapping = ref('直接映射')
const mappings = ref([
{
type: '直接映射',
desc: '每个主存块只能映射到唯一的缓存行',
speed: '最快',
hitRate: '较低',
complexity: '最低'
},
{
type: '组相联',
desc: '每个主存块可以映射到 N 个缓存行(N路组相联)',
speed: '较快',
hitRate: '较高',
complexity: '中等'
},
{
type: '全相联',
desc: '主存块可以放到任意缓存行中',
speed: '最慢',
hitRate: '最高',
complexity: '最高'
}
])
const selectedMappingData = computed(() => {
return mappings.value.find(m => m.type === selectedMapping.value)
})
const avgTime = computed(() => {
const h = hitRate.value / 100
return Math.round(h * tc.value + (1 - h) * tm.value)
})
const simulateRead = async (addr) => {
logs.value = []
if (addr >= 100 && addr < 110) {
logs.value.push({ time: 0, text: `读取地址 ${addr}`, type: 'read' })
activeLevel.value = 'L1'
logs.value.push({ time: tc.value, text: '✓ L1 缓存命中!', type: 'hit' })
} else if (addr >= 200 && addr < 210) {
logs.value.push({ time: 0, text: `读取地址 ${addr}`, type: 'read' })
activeLevel.value = 'L1'
logs.value.push({ time: tc.value, text: '✗ L1 缓存未命中', type: 'miss' })
activeLevel.value = 'L2'
logs.value.push({ time: tc.value + 5, text: '✗ L2 缓存未命中', type: 'miss' })
activeLevel.value = 'MEM'
logs.value.push({ time: tc.value + 5 + 100, text: '从主存加载数据', type: 'load' })
logs.value.push({ time: tc.value + 5 + 100, text: '数据存入缓存', type: 'store' })
}
}
</script>
<style scoped>
.cache-demo {
background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
border-radius: 12px;
padding: 20px;
margin: 16px 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 20px;
}
.title {
font-size: 18px;
font-weight: 700;
color: #1e293b;
}
.subtitle {
font-size: 13px;
color: #64748b;
margin-left: auto;
}
.cache-visualization {
background: white;
border-radius: 8px;
padding: 16px;
margin-bottom: 16px;
}
.cache-levels {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.level {
display: flex;
flex-direction: column;
align-items: center;
padding: 12px;
border-radius: 8px;
background: #f1f5f9;
transition: all 0.3s;
}
.level.active {
transform: scale(1.05);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
}
.cpu-level {
background: #fef3c7;
}
.l1-cache.active { background: #dbeafe; border: 2px solid #3b82f6; }
.l2-cache.active { background: #dbeafe; border: 2px solid #2563eb; }
.l3-cache.active { background: #dbeafe; border: 2px solid #1d4ed8; }
.memory.active { background: #dcfce7; border: 2px solid #16a34a; }
.level-label {
font-size: 11px;
font-weight: 600;
color: #1e293b;
margin-bottom: 4px;
}
.level-icon {
font-size: 24px;
}
.level-info {
display: flex;
flex-direction: column;
align-items: center;
font-size: 10px;
}
.size { color: #0369a1; font-weight: 600; }
.speed { color: #64748b; }
.arrow-right {
font-size: 18px;
color: #94a3b8;
}
.cache-operation {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
margin-bottom: 16px;
}
.control-panel, .operation-log {
background: white;
border-radius: 8px;
padding: 12px;
}
.panel-title, .log-title {
font-size: 14px;
font-weight: 600;
color: #1e293b;
margin-bottom: 12px;
}
.btn-group {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.btn {
padding: 8px 12px;
background: #3b82f6;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 12px;
}
.btn:hover {
background: #2563eb;
}
.log-content {
max-height: 120px;
overflow-y: auto;
}
.log-item {
display: flex;
gap: 8px;
padding: 4px 0;
font-size: 11px;
}
.log-time {
color: #64748b;
min-width: 50px;
}
.log-item.hit .log-text { color: #16a34a; }
.log-item.miss .log-text { color: #ea580c; }
.log-item.load .log-text { color: #0369a1; }
.locality-explanation {
background: white;
border-radius: 8px;
padding: 16px;
margin-bottom: 16px;
}
.exp-title {
font-size: 14px;
font-weight: 600;
color: #1e293b;
margin-bottom: 12px;
}
.locality-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.locality-card {
padding: 12px;
background: #f8fafc;
border-radius: 8px;
text-align: center;
}
.locality-icon {
font-size: 24px;
margin-bottom: 8px;
}
.locality-name {
font-size: 14px;
font-weight: 600;
color: #1e293b;
}
.locality-desc {
font-size: 11px;
color: #64748b;
margin: 8px 0;
}
.locality-example {
font-size: 10px;
padding: 4px 8px;
background: #e0f2fe;
border-radius: 4px;
color: #0369a1;
}
.cache-mapping {
background: white;
border-radius: 8px;
padding: 16px;
margin-bottom: 16px;
}
.mapping-title {
font-size: 14px;
font-weight: 600;
color: #1e293b;
margin-bottom: 12px;
}
.mapping-tabs {
display: flex;
gap: 8px;
margin-bottom: 12px;
}
.map-btn {
padding: 8px 16px;
border: 2px solid #e2e8f0;
border-radius: 6px;
background: white;
cursor: pointer;
font-size: 13px;
}
.map-btn.active {
border-color: #3b82f6;
background: #eff6ff;
}
.mapping-desc {
font-size: 12px;
color: #475569;
margin-bottom: 12px;
}
.mapping-compare {
display: flex;
gap: 16px;
}
.compare-item {
display: flex;
flex-direction: column;
}
.compare-label {
font-size: 10px;
color: #64748b;
}
.compare-value {
font-size: 13px;
font-weight: 600;
color: #1e293b;
}
.compare-value.fast { color: #16a34a; }
.hit-rate-calc {
background: white;
border-radius: 8px;
padding: 16px;
}
.calc-title {
font-size: 14px;
font-weight: 600;
color: #1e293b;
margin-bottom: 12px;
}
.calc-formula {
text-align: center;
margin-bottom: 16px;
}
.formula {
font-family: monospace;
font-size: 14px;
color: #0369a1;
}
.calc-example {
display: flex;
flex-direction: column;
gap: 8px;
}
.calc-row {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
}
.calc-row label {
min-width: 120px;
color: #475569;
}
.calc-row input {
flex: 1;
}
.calc-result {
margin-top: 12px;
padding: 12px;
background: #dcfce7;
border-radius: 6px;
text-align: center;
font-size: 16px;
font-weight: 700;
color: #166534;
}
</style>