2017년 4월 20일 목요일

Coarse-grained vs Fine-grained Multithreading

Scheduling 관련 문서나 논문을 읽다보면, Coarse-grained 와 Fine-grained 용어가 나오는 경우가 있다. 사전적 의미만 가지고는 그 의미 유추가 힘들어서, 한번 정리를 해보았다. Multithreading 에서의 Coarse-grained 와 Fine-grained 개념에 대해 알아본다.

Multithreaded processors 개념은 여러개의 thread를 동시에 실행시키는 것이다. 이렇게 하면, latency를 숨길 수 있다. latency를 숨기다는 것이 어떤 의미인지, 예를 들어살펴보자.

Thread A의 동작을 상상해보자. Thread A는 정해진 동작을 수행, 어느 순간 cache miss가 발생할 것이다. 이때, 메모리에 데이터를 로드하는 동작을 수행하게 된다. core level 에서는 DRAM으로 data를 요청하고, 대기하게 된다. DRAM에 data를 로드하는 데까지, 상당 시간이 흘러갈 것이다. 이렇게 long-latency가 포함된 동작이 실행된 경우, 그 latency 동안에 다른 thread를 실행할 수 있다. DRAM에는 data 로드를 요청해두고, processor는 해당 작업이 완료될때까지, Thread B를 실행하는 것이다. Thread B를 수행하다가 다시 Thread A로 돌아가면 DRAM 로드가 완료되고 작업을 이어서 할 수 있을 것이다. 이렇게 Thread A->B를 이동하면, latency가 발생해도, processor 입장에서는 동작을 계속 할 수 있다.

thread의 실행을 교체하는 것을(Thread A 실행 -> Thread B 실행) context switching 이라고 한다. 이 context switching 자체도 다소 큰 overhead 가 발생하므로, context swtiching을 언제/어떻게 수행할 것인지도 큰 설계 고려사항이다.

Multithread Models 는 크게 2가지 방법으로 분류한다.

1. Coarse-grained Multithreading (block interleaving)
사전적 의미로 coarse는 "(피부나 천이) 거친, (알갱이?올 등이) 굵은"의 뜻을 가지고 있다. Multithread Models 에서의 coarse 의 의미는 촘촘하지 못한 것을 의미하며, Multithreading 동작이 큰 단위로 발생한다는 것을 암시한다. Coarse-grained Multithreading은 위에서 언급했던 memory stall 등과 같은 long latency 동작이 발생할때까지, 동작 중인 thread를 계속 동작시키는 것이다. long latency 이벤트가 발생하면, context switching 이 수행한다. 따라서, Coarse-grained Multithreading은 context switching이 상대적으로 적게 발생한다.

2. Fine-grained Multithreading (cycle-by-cycle interleaving)
사전적 의미로 fine은 "(알갱이가) 고운"으로 사용되었다. Multithreading 동작이 촘촘하게(작은 단위)로 발생한다는 것을 암시한다. Fine-grained Multithreading은 thread switching이 cycle 단위로 발생한다. cycle 단위로, 동작할 thread를 변경하는 것이다. cycle 단위로 switching이 수행되면 매우 큰 switching overhead가 당연해보인다. 따라서, Fine-grained Multithreading 방식은 thread swithching 동작을 수행할 hardware logic 이 포함된다. 이 logic으로 switching overhead를 매우 작게 만들어 수행한다. processor 내에 충분한 수의 레지스터를 설계하여, context switching이 수행될때, 레지스터에 대한 save/restore 동작이 필요없게 만드는 식이다.

Navigation of this blog:이 블로그 한눈에 보기

2017년 4월 8일 토요일

안드로이드에서 프로세스와 스레드 생성 과정

Linux프로세스 생성과 관련한 코드를 살펴보았으니, 이번에는 실제로 안드로이드(Android) 플랫폼에서의 프로세스 생성이 어떻게 이뤄지는지, 그 과정을 살펴보도록 하자. 안드로이드에서의 프로세스(Process) 생성과 스레드(Thread) 생성에 관련한 각각의 예를 살펴보자.

안드로이드에서의 프로세스(Process) 생성 안드로이드에서의 프로세스 생성에 자주 사용되는 함수는 Java의 표준 라이브러리인 Runtime을 이용한 실행이다. Runtime.exec() 를 통해서 Process 를 생성하고 Process는 stdout로 Process가 실행된 결과를 전달한다. 이미 이전 글에서 Linux 는 프로세스 생성에 fork-and-exec 모델에 대해 알아보았다. 시스템 콜 함수인 fork() 함수와 exec() 함수를 호출해서 외부 프로세스를 실행한다.

안드로이드에서는 아직 vfork() 함수를 사용하고 있다.(이전 글에서 vfork() 함수는 서서히 없어질 것처럼 기재했었지만..) vfork() 함수는 부모 프로세스와 같은 자식 프로세스를 생성하고, 메모리 공간은 공유하기 때문에, 부모 프로세스는 exec() 함수가 호출될때까지 잠시 대기(sleep)한다. exec() 함수는 하위 프로세스가 실행할 파일을 읽어 메모리 이미지를 변경하고 새로운 프로그램을 실행한다. 아래에서 보이는 예제에서는 ping 명령어 실행이 이뤄졌다. vfork() 함수 호출 후에, exec() 함수를 호출하면 프로세스를 생성했던 부모 프로세스는 sleep에서 깨어나 이전에 실행했던 프로세스를 계속 실행하며, 새로이 fork된 자식 프로세스(이경우는 ping 명령어)는 새로운 메모리 공간에서 실행을 시작한다.

Runtime.exec() 호출 시, JAVA library 단에서 native 단 호출까지 함수 콜을 아래 모두 표시해두었다. UNIXProcess_md.c 파일에서 UNIXProcess_forkAndExec 함수를 보면 실제 프로세스 생성에 사용되는 vfork 와 exec 함수 system call 호출을 확인할 수 있다.

fork process on android

안드로이드에서의 스레드(Thread) 생성 안드로이드에서의 스레드 생성에 대해 살펴보자. 아래 예는 Thread를 생성하고 start로 Thread를 실행했을 때의 함수 호출을 표시해두었다. Thread start 호출 시, 안드로이드 art 의 thread.cc 파일에서 pthread_create 함수를 이용하여 thread를 생성한다. pthread는 POSIX 스레드(POSIX Threads)의 약자로, 모든 유닉스 계열 POSIX 시스템에서, 일반적으로 이용되는 표준 라이브러리이다. 실제로 thread를 생성하는 부분은 pthread_create 함수 안에 clone 호출로 이뤄져있다. Clone 함수 호출 시, 사용되는 flags들도 눈여겨보자. 안드로이드에서의 thread 생성 시, 아래 flag가 설정되어 clone system call로 전달되는 것이다.

fork thread on android

안드로이드 프로세스(Process) 생성과 스레드(Thread) 생성에 관련한 각각의 예를 살펴보았다. 실제로 함수 콜을 따라가면서, 함수들을 살펴보면, 좀 더 깊은 이해를 할 수 있다.

Navigation of this blog:이 블로그 한눈에 보기