Files
document-haness/docs/virtualization/final/.techviz/guest-memory-address-translation-path/spec.json
T

285 lines
9.6 KiB
JSON

{
"version": "1.1",
"id": "guest-memory-address-translation-path",
"title": "Guest 의 메모리 접근 한 번은 이름이 두 번 바뀌며 네 계층을 지난다",
"question": "Guest 프로세스가 읽은 주소는 어느 계층을 차례로 지나 어떤 물리 메모리에 닿는가",
"type": "data-flow",
"direction": "TB",
"audience": [
"가상 머신에 준 RAM 이 Host RAM 에서 무엇을 뜻하는지 가르려는 사람",
"KVM/QEMU 메모리 경로를 처음 읽는 사람"
],
"summary": "Guest 구역 안에서 GVA 가 Guest TLB 와 Guest Page Table 을 지나 GPA 가 되고, VM Boundary 를 넘은 뒤 EPT 가 GPA 를 HPA 로 바꾸며, 그 HPA 가 Host RAM 의 physical page 와 그 page 가 속한 NUMA node 로 이어진다.",
"alt": "Guest 구역 안에서 Keycloak · PostgreSQL 의 GVA 가 Guest TLB 와 Guest Page Table 을 지나 GPA 가 되고, VM Boundary 를 넘어 EPT 에서 HPA 가 된 뒤 Host RAM 구역의 Host Physical Memory 를 지나 NUMA Node 0 과 NUMA Node 1 로 갈라지는 주소 변환 경로도.",
"long_description": "위에서 아래로 읽는다. 맨 위 Guest 구역 안에 Keycloak · PostgreSQL 이 있고 그 접근은 GVA 로 Guest TLB 에 들어간다. TLB 에 변환이 없으면 TLB Miss 로 Guest Page Table 을 조회하고 거기서 GVA 가 GPA 가 된다. 그 GPA 는 VM Boundary 를 넘어 Guest 구역 밖의 EPT 로 가고 EPT 가 GPA 를 HPA 로 바꾼다. HPA 는 Host RAM 구역의 Host Physical Memory 에 닿고, 그 physical page 는 맨 아래에서 NUMA Node 0 또는 NUMA Node 1 가운데 한쪽에 놓인다. 상자 안 작은 글씨는 그 단계가 어느 계층인지와 무엇을 무엇으로 바꾸는지를 적은 것이다. 어느 단계에서 접근이 완료되지 못할 때 무엇이 일어나는지와 QEMU 가 이 경로를 어떻게 준비하는지는 본문의 문단과 표가 맡는다.",
"source_context": {
"document": "docs/virtualization/final/document.md",
"document_sha256": "181e2b3cc8a45bae81e7e8193d026937c4d586ae4495d3b2c323eb7e6abcfadd",
"anchor": {
"kind": "heading",
"value": "87. 최종 기준 그림",
"line": 4029
}
},
"composition": {
"profile": "component-flow",
"diagram_only": true,
"reference_ids": [
"payment-event-flow"
],
"rationale": "이 절이 세우는 것은 한 번의 메모리 접근이 한 방향으로 지나가는 경로와 그 경로가 네 계층으로 나뉜다는 것이다. sequence 는 참여자마다 생명선을 세우고 메시지에 시각 순서를 매기는데 여기서는 참여자끼리 주고받는 메시지가 아니라 주소 하나가 계층을 지나며 이름이 바뀌는 변환 사슬이라 순서를 매길 메시지가 없다. two-zone-pipeline 은 구역이 둘일 때의 문법인데 이 경로는 Guest Userspace · Guest Kernel · KVM/CPU · Host RAM 넷으로 갈리고 Guest Kernel 안쪽에도 TLB Miss 엣지가 있어 구역 안 엣지 라벨이 캔버스 위쪽에 고정된다.",
"focus_node": "ept"
},
"groups": [
{
"id": "guest",
"label": "Guest",
"kind": "boundary",
"description": "VM Boundary 안쪽. Guest Userspace 와 Guest Kernel 이 여기 있고 GVA 가 GPA 가 되는 첫 번째 변환이 여기서 끝난다.",
"evidence": [
{
"start_line": 4034,
"end_line": 4053
}
],
"assumption": false
},
{
"id": "host-ram",
"label": "Host RAM",
"kind": "boundary",
"description": "변환이 끝난 주소가 닿는 실제 서버 메모리.",
"evidence": [
{
"start_line": 4069,
"end_line": 4079
}
],
"assumption": false
}
],
"nodes": [
{
"id": "guest-process",
"label": "Keycloak · PostgreSQL",
"kind": "actor",
"role": "source",
"shape": "box",
"group": "guest",
"description": "Guest 안에서 메모리를 읽는 프로세스. 여기서 GVA 가 출발한다.",
"evidence": [
{
"start_line": 4034,
"end_line": 4038
}
],
"assumption": false,
"details": [
"Guest Userspace"
]
},
{
"id": "guest-tlb",
"label": "Guest TLB",
"kind": "component",
"role": "store",
"shape": "box",
"group": "guest",
"description": "최근 변환 결과를 담아 두는 CPU 안의 캐시.",
"evidence": [
{
"start_line": 4043,
"end_line": 4045
}
],
"assumption": false,
"details": [
"Guest Kernel"
]
},
{
"id": "guest-page-table",
"label": "Guest Page Table",
"kind": "component",
"role": "service",
"shape": "box",
"group": "guest",
"description": "GVA 를 GPA 로 바꾸는 첫 번째 변환 표.",
"evidence": [
{
"start_line": 4048,
"end_line": 4053
}
],
"assumption": false,
"details": [
"Guest Kernel",
"GVA → GPA"
]
},
{
"id": "ept",
"label": "EPT",
"kind": "component",
"role": "service",
"shape": "box",
"emphasis": "primary",
"description": "VM Boundary 바깥에서 GPA 를 HPA 로 바꾸는 두 번째 변환 표. KVM 과 CPU 가 맡는다.",
"evidence": [
{
"start_line": 4055,
"end_line": 4067
}
],
"assumption": false,
"details": [
"KVM / CPU",
"GPA → HPA"
]
},
{
"id": "host-physical-memory",
"label": "Host Physical Memory",
"kind": "store",
"role": "store",
"shape": "box",
"group": "host-ram",
"description": "HPA 가 가리키는 실제 서버 메모리.",
"evidence": [
{
"start_line": 4069,
"end_line": 4072
}
],
"assumption": false
},
{
"id": "numa-node-0",
"label": "NUMA Node 0",
"kind": "store",
"role": "sink",
"shape": "box",
"group": "host-ram",
"description": "physical page 가 놓일 수 있는 한쪽 NUMA node.",
"evidence": [
{
"start_line": 4073,
"end_line": 4075
}
],
"assumption": false
},
{
"id": "numa-node-1",
"label": "NUMA Node 1",
"kind": "store",
"role": "sink",
"shape": "box",
"group": "host-ram",
"description": "physical page 가 놓일 수 있는 다른 쪽 NUMA node.",
"evidence": [
{
"start_line": 4073,
"end_line": 4075
}
],
"assumption": false
}
],
"edges": [
{
"id": "process-to-tlb",
"from": "guest-process",
"to": "guest-tlb",
"label": "GVA",
"kind": "data",
"style": "solid",
"evidence": [
{
"start_line": 4036,
"end_line": 4043
}
],
"assumption": false
},
{
"id": "tlb-to-page-table",
"from": "guest-tlb",
"to": "guest-page-table",
"label": "TLB Miss",
"kind": "control",
"style": "solid",
"evidence": [
{
"start_line": 4043,
"end_line": 4048
}
],
"assumption": false
},
{
"id": "page-table-to-ept",
"from": "guest-page-table",
"to": "ept",
"label": "VM Boundary",
"kind": "control",
"style": "solid",
"evidence": [
{
"start_line": 4053,
"end_line": 4062
}
],
"assumption": false
},
{
"id": "ept-to-host-memory",
"from": "ept",
"to": "host-physical-memory",
"label": "HPA",
"kind": "data",
"style": "solid",
"evidence": [
{
"start_line": 4062,
"end_line": 4071
}
],
"assumption": false
},
{
"id": "host-memory-to-node-0",
"from": "host-physical-memory",
"to": "numa-node-0",
"label": "Physical Page",
"kind": "data",
"style": "solid",
"evidence": [
{
"start_line": 4071,
"end_line": 4075
}
],
"assumption": false
},
{
"id": "host-memory-to-node-1",
"from": "host-physical-memory",
"to": "numa-node-1",
"label": "Physical Page",
"kind": "data",
"style": "solid",
"evidence": [
{
"start_line": 4071,
"end_line": 4075
}
],
"assumption": false
}
],
"legend": [],
"metadata": {
"rationale": "data-flow 로 고른 이유는 이 절이 답하는 물음이 「주소 하나가 어디를 지나 어디에 닿는가」이기 때문이다. LR 로 세우면 캔버스가 1889px 에 종횡비 5.37 이라 문서 폭에서 글자가 읽히지 않아 TB 로 세웠다. Guest Userspace · Guest Kernel · KVM / CPU · Host RAM 넷을 모두 group 으로 두면 group 이름이 그 경계를 넘는 엣지 라벨에 먹혀 「Guest Kerne」·「KVM / CP」로 잘렸다. 그래서 경계는 VM Boundary 를 사이에 둔 Guest 와 Host RAM 둘만 상자로 두고, 나머지 두 계층 이름은 그 자리 노드의 details 로 내렸다. SSOT 가 같은 절에 그린 관리 경로(virsh · libvirt · QEMU · KVM)와 자원 압박 경로는 다른 물음이라 이 그림에 넣지 않았다. §87 이 EPT 옆에 적어 둔 「EPT Violation 가능」과 Guest Page Table 옆의 「Guest #PF 가능」도 뺐다 — 이 기록의 본문은 정상 경로를 세우고, 세 계층의 fault 는 짝이 되는 기록이 맡는다. 마지막 Physical RAM 상자는 Host Physical Memory 와 뜻이 겹쳐 빼고 NUMA node 둘을 끝으로 두었다."
}
}