Q: 질문
A: 답변
=>: 구체적으로 궁금한 부분 / 정확하지 않은 답변
* [리눅스 커널 내부구조 中]: 관련 내용 정리부분
질문에 대해 같이 공유했으면 좋겠습니다.
아시는 내용이 있으시면 " [Q1] 답변: " 의 형식으로 댓글을 달아 주셨으면 좋겠습니다.
Q1. hyperthreed에 대하여??
Q2. smp (symmetric multi processor)?에 대한 개념 - 물리적 / 논리적 구조에 따른 작업역할
http://myfreechild.tistory.com/92
http://electronicdesign.com/digital-ics/symmetric-multiprocessing-vs-asymmetric-processing
Q3. 스케줄러는 언제 호출될까?? (1. 2. 번의 경우가 같은상황인가? 다른상황인가?)
1. 주기적으로 타이머 인터럽트가 발생하는데 이 인터럽트의 서비스 루틴이 종료되는 시점에 현재 수행되고 있는 태스크의 need_resched 필드를 살펴보고 스케줄링 할 필요가 있다면 스케줄러를 호출한다.
A. 1번 상황은 인터럽터 핸들러에서 태스크의 상태를 변경하거나 했을 경우 인터럽트 핸들러에서는 IRQ stack이라 context switch를 발생 시킬수 없기에 need_resched 플래그를 셋팅해서 핸들러 종료 시점에 stack을 tack의 스택으로 변경하고 스케줄러를 호출하는 상황입니다.
2. 현재 수행되고 있는 task가 자신의 타임 슬라이스를 모두 사용했거나, 이벤트를 대기하는 경우이다.
A. 2번은 H/W Timer에서 발생한 Tick Handler에서 매 tick마다 task의 time slice를 감소 시키다 0이된 순간 need_resched 플래그를 셋팅해서 인터럽트 핸들러 종료 시점에 스케줄링 시키는 케이스 입니다.
2번은 1번의 서브 셋에 가까운 상황이죠.
Q4. 1번상황에서 주기적인 타이머 인터럽트가 발생할때 이 타이머 인터럽트는 OS가 호출한거냐? 아니면 태스크가 호출한 타이머 인터럽트인가?
A. H/W Timer에서 발생한 인터럽트 입니다.
Q5. 인터럽트는 os가 핸들링 할수 있나???
Q6. p89 task A, task B 문맥 교환이 일어날 경우 정보가 저장되는 순서는??
* [리눅스 커널 내부구조 中]
커널 스택에 CPU 정보가 저장된다. (Save 1)
그런 뒤 커널이 스케줄링 코드를 수행하고 다음번 수행 대상으로 Task B를 선정하여
문맥교환을 하게 되면 여태껏 사용하던 CPU정보를 Task A의 task_struct.thread에 저장한다(Save 2)
Task B의 task_struct.thread의 정보를 복원한다(Restore1)
그런 뒤 Task B의 커널 스택에서 CPU 정보를 복원한다. (Restore 2)
Q7. #save 1, #save 2가 같은 값 같은데 두번 저장해서 비효율 적으로 작업을 할 필요가 있을까?(왜 두번 Save를 하는지? Save 1만 하고 커널 코드를 수행한 뒤 Restore2만 하면 되는게 아닌지.) / 문맥저장을 할 때 저장을 두번 하는 이유는?
=> 검색으로 나온 의견은 Save1에서는 EIP와 ESP등만 저장을 해서 문맥교환이 일어나지 않는 경우 불필요하게 모든 CPU 레지스터를 저장하는 오버헤드를 없앤다는 것.
즉 실제로 문맥교환이 일어나는 경우에만 모든 레지스터는 Save2에서 저장한다는 의견.
사실여부 확인이 필요하고, 맞다면 구체적으로 어떤 정보를 저장하는지 알아야 함
Q8. bank / node / zone의 차이점?
뱅크(bank) 접근 속도가 같은 메모리의 집합
* [리눅스 커널 내부구조 中]
UMA구조에서는 뱅크는 시피유 갯수와 관계없이 한개 존재 BUT NUMA구조에서는 뱅크의 개수가 CPU의 개수만큼 존재
노드(node) 뱅크를 표현하는 구조 - 리눅스의 전역 변수인 contig_page_data를 통해 접근 가능 / 복수개의 node는 리스트를 통해 관리되며 pgdat_list라는 이름의 배열을 통해 접근
즉. 리눅스는 뱅크/노드 관계를 통해서 하드웨어와 상관없이 전체 메모리를 접근,제어 할 수 있다.
존(ZONE) 노드 안에 존재하고 있는 메모리는 모두 어떠한 용도로도 사용될 수 있어야 한다.
리눅스 개발자는 리눅스가 원활하게 수행할 수 있도록 node의 일부분을 따로 관리할 수 있도록 하였다.
node에 존재하는 물리메모리 중 16mb이 하부분을 특별히 관리하기위해 자료구조를 만들어 놓았으며 이 자료구조를 zone이라 부른다.
http://codecat.tistory.com/entry/Virtual-Linux-Manager-%EC%A0%95%EB%A6%AC-1
* [리눅스 커널 내부구조 中]
커널도 페이징 단계를 거쳐야 가상주소를 물리주소로 변환할 수 있다. 그러나 커널에게는 mm_struct, pgd가 없다.
따라서 리눅스 커널은 자신을 위한 페이지 테이블을 시스템의 부팅시점에 미리 작성해놓고 이 위치를 swapper_pg_dir이라는 전역변수에 저장해 놓고 사용한다.
Q9. 3GB~4GB에 해당하는 커널 영역도 페이징이 되는 것인지?
=> 만약 그렇다면 ZONE_NORMAL의 896MB는 direct mapping으로 연결되어 있어서 페이지테이블이 필요 없을텐데 3~4GB 영역중 정확히 어느 부분이 페이징이 되는지. 혹시 1GB - 896MB = 128MB 부분만 페이징이 되는것인지.
댓글 5
-
woos
2016.05.08 21:53
-
단보
2016.05.09 00:46
정확한 설명 해주셔서 감사합니다.ㅎㅎ
-
chic
2016.05.09 23:45
Q3 답변부분에
핸들러 종료 시점에 stack을 tack의 스택으로 변경하고 - 이 부분에서 tack이 무엇인가요?
그리고 plat mapping도 무엇인지 궁금합니다.
-
단보
2016.05.10 11:53
tack은 task 오타신거 같습니다.
-
woos
2016.05.10 13:34
인터럽트가 발생할때 수행중이였던 task를 말합니다.
plat-mapping을 다른말로 direct-mapping라 말합니다. 일반적으로 os하는 사람들은 plat-mapping라는 용어를 주로 씁니다.
.
Q1. hyperthreed에 대하여??
-> cpu에는 콘트롤 유닛과 컴퓨테이션 유닛, 아키텍쳐 스테이트가 있습니다.
-> 콘트롤 유닛과 컴퓨테이션 유닛은 데이터 메모리큐, 다바이더, TLB, BP, 기타 각종유닛 등등 종류가 아주 많습니다.
-> 아키텍쳐 스테이트는 context에 해당하는 부분이고요.
-> 그럼 예를들어 single-core cpu에서 하나의 thread만 동작한다면 놀게 되는 콘트롤 유닛과 컴퓨테이션 유닛이 많겠죠.
-> 이렇게 노는 유닛을 최대한 사용해보고자 아키텍쳐 스테이트를 single-core에서 두개를 두고 두 thread가 번갈아가며 수행하게끔 하는게 하이퍼 스레딩입니다.
-> 한 thread만 돌때와 비교하면 자원을 혼자 독점하지 못해 느려지겠죠.
-> 하지만 두 thread가 동시에 돌아 cpu 유틸라이제이션이 높아지기 때문에 전체적으로 스루풋이 증가해 성능이 좋아집니다.
-> 멀티 코어에서도 동일하게 적용됩니다.
Q2. smp (symmetric multi processor)?에 대한 개념 - 물리적 / 논리적 구조에 따른 작업역할
http://myfreechild.tistory.com/92
http://electronicdesign.com/digital-ics/symmetric-multiprocessing-vs-asymmetric-processing
-> 작업 역활??
-> 작업 역활의 정의가 모호하네요.
-> SMP는 각 코어가 메인 메모리와 버스, 장치를 공유하는 형태입니다.
Q3. 스케줄러는 언제 호출될까?? (1. 2. 번의 경우가 같은상황인가? 다른상황인가?)
1. 주기적으로 타이머 인터럽트가 발생하는데 이 인터럽트의 서비스 루틴이 종료되는 시점에 현재 수행되고 있는 태스크의 need_resched 필드를 살펴보고 스케줄링 할 필요가 있다면 스케줄러를 호출한다.
A. 1번 상황은 인터럽터 핸들러에서 태스크의 상태를 변경하거나 했을 경우 인터럽트 핸들러에서는 IRQ stack이라 context switch를 발생 시킬수 없기에 need_resched 플래그를 셋팅해서 핸들러 종료 시점에 stack을 tack의 스택으로 변경하고 스케줄러를 호출하는 상황입니다.
2. 현재 수행되고 있는 task가 자신의 타임 슬라이스를 모두 사용했거나, 이벤트를 대기하는 경우이다.
A. 2번은 H/W Timer에서 발생한 Tick Handler에서 매 tick마다 task의 time slice를 감소 시키다 0이된 순간 need_resched 플래그를 셋팅해서 인터럽트 핸들러 종료 시점에 스케줄링 시키는 케이스 입니다.
2번은 1번의 서브 셋에 가까운 상황이죠.
Q4. 1번상황에서 주기적인 타이머 인터럽트가 발생할때 이 타이머 인터럽트는 OS가 호출한거냐? 아니면 태스크가 호출한 타이머 인터럽트인가?
A. H/W Timer에서 발생한 인터럽트 입니다.
Q5. 인터럽트는 os가 핸들링 할수 있나???
-> 네.
Q6. p89 task A, task B 문맥 교환이 일어날 경우 정보가 저장되는 순서는??
* [리눅스 커널 내부구조 中]
커널 스택에 CPU 정보가 저장된다. (Save 1)
그런 뒤 커널이 스케줄링 코드를 수행하고 다음번 수행 대상으로 Task B를 선정하여
문맥교환을 하게 되면 여태껏 사용하던 CPU정보를 Task A의 task_struct.thread에 저장한다(Save 2)
Task B의 task_struct.thread의 정보를 복원한다(Restore1)
그런 뒤 Task B의 커널 스택에서 CPU 정보를 복원한다. (Restore 2)
-> 이건 해석의 차이가 있을수 있는 문장이네요.
-> caller saved register를 필요하면 stack에 save하는 건데 명시적으로 해주지 않아도 compiler가 liveness analysis를 통해 stack에 save해야 될 필요가 있는 register는 알아서 stack에 save해줍니다.
-> 아마 이걸 의도하고 말한것 같은데, 잘못 해석하면 오해의 소지가 있을것 같네요.
Q7. #save 1, #save 2가 같은 값 같은데 두번 저장해서 비효율 적으로 작업을 할 필요가 있을까?(왜 두번 Save를 하는지? Save 1만 하고 커널 코드를 수행한 뒤 Restore2만 하면 되는게 아닌지.) / 문맥저장을 할 때 저장을 두번 하는 이유는?
=> 검색으로 나온 의견은 Save1에서는 EIP와 ESP등만 저장을 해서 문맥교환이 일어나지 않는 경우 불필요하게 모든 CPU 레지스터를 저장하는 오버헤드를 없앤다는 것.
즉 실제로 문맥교환이 일어나는 경우에만 모든 레지스터는 Save2에서 저장한다는 의견.
사실여부 확인이 필요하고, 맞다면 구체적으로 어떤 정보를 저장하는지 알아야 함
-> 위에 설명했습니다.
Q8. bank / node / zone의 차이점?
뱅크(bank) 접근 속도가 같은 메모리의 집합
-> bank : H/W적으로는 memory controller에서 관리하는 주소의 기본 단위. 일반적으로 UMA에서는 각 bank에 엑세스하는 속도가 동일하죠. NUMA에서는 엑세스 속도가 각 코어별로 주소 영역마다 다릅니다. 리눅스에서는 이걸 같은 엑세스 속도를 가지는 메모리를 하나의 bank로 표현하고, 다른 속도를 가지는 메모리들을 각기 다른 bank로 표현합니다.
-> node : bank를 표현하는 구조
-> zone : 다시 node를 나누어서 DMA, NORMAL, HIGHMEM zone으로 나누는데 DMA zone은 하위 16MB이고 이는 오래된 ISA 기반의 DMA 장치는 16MB 이상을 접근 못해서 호환성을 위해 남겨둔 부분입니다. 하지만 요즘 DMA 장치들은 물리적으로 선형 되어야만 한다는 제약만 있고 16MB 제약은 존제하지 않죠.
x86에서 NORMAL zone은 커널 영역 1024MB(1GB)에서 1G 이상의 3G 영역을 맵핑할 페이지 테이블 사이즈인 128MB를 뺀 896MB 영역입니다.
이 영역은 plat mapping 할수 있는 영역이라 가상주소를 가지고 물리주소를 구할때 오프셋만 제거하면 되기 때문에 물리주소와 가상주소를 구하는게 쉽습니다. ex) VA 0xC0001000 -> PA 0x00001000
커널 내부에서는 이렇게 가상 주소의 물리 주소를 구하는 일은 매우 빈번하게 발생하기 때문에 성능에 큰 영향을 줍니다.
또한 이 영역은 커널이 내부 자료구조나 버퍼를 위해 사용할 경우 task간 context switch시 TLB flash가 적게 일어나기 때문에(커널 영역은 task가 각각 공유하기 때문) task간 전환시도 성능에 장점을 가져옵니다.
HIGHMEM은 896MB 이후의 영역이고 이 영역은 plat mapping한다 하더라도 커널의 영역으로 사용할수가 없습니다. 그래서 이 영역을 사용하게 될경우 커널 내부에서 필요에 의해 주소를 변환해야될 경우 오버헤더가 발생하기에 커널은 이 영역을 되도록 잘 사용하지 않습니다. 커널이 못사용하는 영역은 없습니다. DMA, NORMAL, HIGHMEM 모두 사용 가능하지만 성능과 필요에 의해 메모리를 달리 사용하고자 구분해놓은 것입니다. x86은 이렇게 ARM은 HIGHMEM이 없고 DMA와 NORMAL만 있습니다.
* [리눅스 커널 내부구조 中]
UMA구조에서는 뱅크는 시피유 갯수와 관계없이 한개 존재 BUT NUMA구조에서는 뱅크의 개수가 CPU의 개수만큼 존재
-> 아. 이건 잘못 기술된 내용이네요. NUMA에서 bank는 CPU 갯수만큼 있는게 아니라 node 갯수만큼 있습니다. node는 엑세스 속도가 동일한 메모리의 집합.
노드(node) 뱅크를 표현하는 구조 - 리눅스의 전역 변수인 contig_page_data를 통해 접근 가능 / 복수개의 node는 리스트를 통해 관리되며 pgdat_list라는 이름의 배열을 통해 접근
즉. 리눅스는 뱅크/노드 관계를 통해서 하드웨어와 상관없이 전체 메모리를 접근,제어 할 수 있다.
존(ZONE) 노드 안에 존재하고 있는 메모리는 모두 어떠한 용도로도 사용될 수 있어야 한다.
리눅스 개발자는 리눅스가 원활하게 수행할 수 있도록 node의 일부분을 따로 관리할 수 있도록 하였다.
node에 존재하는 물리메모리 중 16mb이 하부분을 특별히 관리하기위해 자료구조를 만들어 놓았으며 이 자료구조를 zone이라 부른다.
http://codecat.tistory.com/entry/Virtual-Linux-Manager-%EC%A0%95%EB%A6%AC-1
* [리눅스 커널 내부구조 中]
커널도 페이징 단계를 거쳐야 가상주소를 물리주소로 변환할 수 있다. 그러나 커널에게는 mm_struct, pgd가 없다.
따라서 리눅스 커널은 자신을 위한 페이지 테이블을 시스템의 부팅시점에 미리 작성해놓고 이 위치를 swapper_pg_dir이라는 전역변수에 저장해 놓고 사용한다.
-> 첨언하면 swapper가 리눅스에서 최초로 만들어지는 task이며 idle task로 사용됩니다.
Q9. 3GB~4GB에 해당하는 커널 영역도 페이징이 되는 것인지?
=> 만약 그렇다면 ZONE_NORMAL의 896MB는 direct mapping으로 연결되어 있어서 페이지테이블이 필요 없을텐데 3~4GB 영역중 정확히 어느 부분이 페이징이 되는지. 혹시 1GB - 896MB = 128MB 부분만 페이징이 되는것인지.
-> 엥엥?? paging을 사용하면 당연히 plat-mapping되어 있다 할지라도 MMU에 의해 주소 변환이 일어나죠. ㅎㅎ
-> 단지 프로그램 내에서 VA->RA 계산이 오프셋만 구하면 되기 때문에 쉽다는 것과 task switch시 TLB flash 영역이 줄어들어 오버헤더가 감소한다는 장점이 있는거죠.