TLB (Translation Lookaside Buffer)
요놈을 알기 위해선 page table이라는 개념을 알고 있어야 한다. 알아보자
Page Table
page table이란 간단히 말해 가상 주소와 실제 주소를 mapping 하는 table이다.
CPU가 가상 주소를 생성하면 이 가상 주소가 실제 주소로 어떻게 변환되어야 하는지 정보를 가지고 있는 것이다. 다른 말로 하면 실제 주소를 가지고 있다.
메인 메모리에 존재하며 프로세스마다 고유의 page table을 가진다. context switching 할 때마다 page table도 변경돼야 한다. 즉, CPU가 어느 page table을 사용할지 알아야 한다.
어떻게 알까?
CPU안에는 특별한 레지스터가 존재하는데 ARM에서는 TTBR (Translation Table Base location Register)이라는 시스템 레지스터를 통해 알 수 있다. 변역 그대로 page table의 시작 주소를 저장한다. 그래서 context switching이 일어날 때마다 TTBR의 값도 바뀐다. (+ x86에서는, CR3라고 한다. RISC-V에서는, SATTR라고 한다. )
아래는 TTBR의 포맷이다.
page tabel의 변환은 아래와 같다.
Virtual page number는 2^20 크기의 page table 중에 어느 위치의 page인지 가리키는 부분이고,
Page offset은 실제 page에서의 정확한 위치를 의미한다. 12bit인 이유는 page size가 4KB이기 때문이다.
12bit는 0x000 ~ 0xfff로 page size이기 때문에 이 중에 어떤 곳의 위치인지 page offest이 지정한다.
즉, page number는 page table에서의 위치를 의미하고 page offset은 그 page에서의 정확한 위치를 의미한다.
아래 그림을 보면 조금 더 이해가 쉬울 것이다.
이렇게 지정된 table에서 물리 주소의 page를 뽑는데 page정보와 page offset이 합쳐져서 실제 물리 메모리와 mapping 된다.
메모리 size에 대해서 알고 가자,
Zedboard에서 32bit Arm 코어를 사용한다.
32bit CPU란, CPU안에 레지스터도 각각 32bit로 이루어져 있고, Data path도 32bit로 이동한다는 소리다.
정리하면 basic unit of data가 32bit라는 의미다. 그러니 2^32만큼의 가상 주소 공간을 사용한다.
그렇다면 64bit 컴퓨터를 기준으로 본다면 어떨까? 똑같이 basic unit of data가 64bit로 이루어져 있다는 의미인데 주소를 가리키는 PC레지스터도 64bit일까? 아니다!! 홀리 쓋! 48bit의 가상 주소를 사용한다.
왜일까?
한 번 확인해 보자.
int i;
printf("%p\n", &i);
위 코드를 실행시키면 지역변수 i의 주소가 출력될 것이다. 즉, 변수 i가 할당받은 주소가 출력될 것이다.
예를 들면 64bit에서는 0x7ffd_3abd_bbc4와 같이 48bit로 출력된다.
이렇게 48bit만 사용하는 이유는 64bit는 엄청 큰 공간을 만들 수 있는데 이게 너무 크기 때문에 줄인 것이다.
32bit라면 2^32 = 4GB라는 큰 공간을 만들 수 있다. ( G = 10^9 )
64bit는 2^64 = 16EB라는 너무나도 큰 공간을 만들 수 있다. 여기서 포인트는 너무나도 큰 공간이다. ( E = 10 ^18 )
그래서 48bit로 줄인 것이다 이것도 256TB의 크기다. 보통 우리가 노트북에서 사용하는 메인 메모리의 크기는 8GB, 16GB 정도고 hard disk도 512GB라고 하더라도 충분히 큰 공간이다.( T = 10 ^ 12 )
그렇게 48bit의 가상 주소를 이용하고, 실제 메인 메모리의 물리 주소는 39bit ( = 512GB )를 사용하여 만든다.
뭔가 이상한데 메인 메모리의 물리 주소가 39bit라고?? 뭔 소린가 싶다. 메인 메모리는 16GB라고 하지 않았나? 이게 좀 헷갈릴 수 있다.
512GB의 "빈 공간"을 만들 수 있다는 의미다. 이 512GB 중에서 16GB의 메인 메모리를 할당하고 다른 I/O 장비들도 memory mapping을 이용하여 실제 주소와 연결하는 것이다. 즉, 만들 "수" 있는 건 512GB이지만 실제로 만드는 건 다른 의미라는 걸 알아야 한다.
이렇게 가상 주소를 실제 주소와 연결하는 것이 매우 중요한 작업이 됐다. 이게 TLB가 필요한 이유다.
TLB (Translation Lookaside Buffer)
page table는 메인 메모리에 존재하는데 그렇다면 CPU는 명령어를 수행하기 위해서 메인 메모리에 최소 2번은 접근해야 원하는 데이터를 얻을 수 있다.
1. page table에 한번 접근 (Fetch)
2. page table을 기반으로 실제 메모리로 접근 (Memory access)
이렇게 되면 명령어 하나하나 실행할 때마다 같은 table이지만 메인 메모리에 접근해야 하는 불필요한 일이 발생한다.
그러니 이런 메모리의 접근을 줄이고자 나온 게 TLB ( Translation Look-aside Buffer )다. 하드웨어적으로 지원하여 page table의 임시저장 cache 역할을 한다. 메모리에 접근하는 건 너무 느리기 때문이다.
TLB는 최근에 읽었던 page table entry(변환될 물리 주소)를 매핑하여 저장하는데 굉장히 작다. 64 ~ 1024 entry정도다. 왜냐면 TLB에 있으면 메모리에 접근하기 전에 막아야 하기 때문에 크기를 작게 하여 속도를 높였다.
결론적으로는 TLB는 page tabel의 캐시 역할을 해준다.
전체 흐름을 보자.
CPU가 가장 주소를 MMU 넘겨주면 TLB를 hit 하거나 miss 해서 page table을 통해 물리 주소를 얻어낸다.
그리곤 cache에 주소를 넘겨준다. 하지만 항상 캐시가 물리 주소를 받는 건 아니다 가상 주소를 받기도 한다.
TLB도 캐시라고 했으니 구조를 한 번 보자.
사실상 캐시 구조와 거의 똑같다. Valid가 있고 tag가 있는데 캐시는 Data나 Instruction이 저장되지만, TLB는 physical page number가 들어가 있다.
page offset은 제외하고 나머지 bit에서 TLB의 구조에 따라 index를 지정하고 나머지로 tag를 찾아서 HIT인지 MISS인지 결정한다. HIT라면 page offset를 결합해서 cache에 보낸다.
그런데 page table은 각각 task마다 고유로 가지고 있는데 context switching을 하면 TLB는 어떻게 될까? 대혼란이다. 다 쓸모가 없는 정보가 된다. 그러니 모두 flush 시켜야 한다. 이런 비효율적인 짓을 하지 않기 위해 task의 table정보를 같이 저장해야 한다.
그게 ASID (Address Space ID)라는 공간이다. 각각의 task마다 ID를 고유로 부여하는데 그 ID를 ASID에 표시하여 저장한다.
TLB의 전체 흐름은 위 그림과 같다.
TLB에 page table entry의 정보가 없을 땐 TLB miss라고 하는데 2가지 종류가 있다.
1. TLB miss
2. Page Fault
기본 TLB miss는 TLB엔 없지만 main memory에는 올라가 있는 상태를 의미한다. 그러니 page table을 가져와서 TLB에 저장하면 간단히 해결된다. 10 cycle정도면 TLB에 정보를 저장할 수 있다. 하드웨어나 소프트웨어의 통제를 받는데 하나의 exception이라고 보면 된다.
하지만 Page Fault는 다르다. 요청한 page가 main memory에 없는 상태를 의미한다.
그러니 hard disk에서부터 불러와야 한다. 그러니 약 1,000,000 cycle정도 소요해야 TLB에 정보를 저장할 수 있다. 엄청난 차이가 있는데 이러니 page Fault를 최대한 발생시키지 않아야 한다.
Page Fault흐름을 보면
1. Page Fault가 발생한다.
2. 운영체제에 page fault trap을 발생시킨다.
2-1. 동작하고 있던 프로세스의 PCB를 메모리에 저장한다.
3. 그러면 운영체제는 다른 page table을 확인한다. 그리고 뭔가 이상하다면 프로세스를 중지시키고 그냥 메모리에 없는 것이라면 backing store에서 찾는다.
4. 필요한 page를 찾아서 물리 메모리에서 빈 frame을 찾는다. 빈 frame이 없다면 교체 알고리즘으로 page in, page out을 수행해야 한다. 이때 프로그램은 wait queue에 들어가서 대기한다.
4-1. free frame을 찾고 있을 때 CPU는 다른 프로그램에게 할당된다.
4-2. 찾았다면 CPU를 사용하고 있던 프로그램의 PCB를 저장하고 page fault를 발생시킨 프로그램의 PCB를 가져온다.
교체 알고리즘은 아래 정리해 놨다.
5. 그리고 물리 메모리에 올리면, page table을 update 한다. 즉, valid bit를 수정한다
6. page fault를 발생시킨 코드를 다시 시작한다.
너무 많은 overhead가 발생하니 page fault는 최대한 발생하지 않게 해야 한다.
이렇게 TLB의 개요에 대해 알아봤다. TLB는 중요하니 잘 알아두자
'시스템 반도체 > Arm' 카테고리의 다른 글
Vitis 사용법 ( vivado 연결 ) (1) | 2022.09.22 |
---|---|
VIVADO 사용법 ( board 연결, zynq 7000, Vits 연결 ) (2) | 2022.09.20 |
Arm Private Timer ( zynq 7000 board, Load 레지스터, counter 레지스터, status 레지스터, control 레지스터 ) (0) | 2022.08.10 |
Arm calling convention ( 레지스터 사용, caller, callee, AAPCS ) (0) | 2022.08.02 |
Arm TrustZone ( 신뢰공간, TEE, monitor, banked register, memory ) (0) | 2022.06.24 |
댓글