Android New Runtime


The ART Manifesto

Developers should not work around the runtime

Code should be fast

garbage collection should help, not hinder

The runtime should scale


Performance (Better living through compilation)






ART garbage collection


Faster overall gc

single, short pause

less fragmentation

less memory usage



64-bit support (Supporting the future)


Advantages

Increased address space as Android usage diversifies

Increased performance from 64-bit instruction sets and cores

Full support for existing 32-bit apps




ART의 소개




Process VM


Interpretation- it involves a cycle of fetching a source instruction, analyzing it, performing the required operation, and then fetching the next source instruction all in software

Binary translation - it attempts to amortize the fetch and analysis costs by translating a block of source instructions to a block of target instructions and saving the translated code for repeated use.



guest state를 host state로 맵핑 시키는 것.

memory addressing architecture를 emulation 시키는 것.

instruction emulation

exception을 emulation

operating system call을 에뮬레이션


추가로 성능 향상을 위해서, code cache management 기술이 있다.


VM의 개발


loader는 게스트 코드 데이터를 게스트에 할당된 메모리 이미지에다가 쓰기를 한다. 또한 런타임 코드들도 기록 한다.
이것은 게스트 코드와 데이터이지만, 결국 이것 자체는 실행되어질수 없기 대문에 런타임을 포함하는 것이라고 할 수 있다.

이러한 코드들은 결국 interpretation 또는 binary translation의 루틴에서의 인풋이라고 볼 수 있다.


Loader는 initialization block을 한다. 이것은 Code cache를 위한 메모리 공간을 할당하며 process 에뮬레이션을 위한 테이블 공간을 위한 메모리 공간도 할당하게 된다.

추가로, initialization 과정에서는 해당 시스템에서 발생할수 있는 모든 signal에 대한 handler를 생성하기위해서 Host OS를 호출하게 된다. initialization 다음에 에뮬레이션 과정이 시작되게 된다.

Emulation Engine은 Binary Translator 또는 intepreter에 의해서 동작 하게 된다. 


Code cache manager는 Code cache를 관리함.


Profile Data는 최적화를 위해서 사용됨.


OS call Emulator는 시스템 콜을 에뮬레이션 해준다.


Runtime은 반드시 Guest에서 발생할 수 있는 인터럽트에 대해서 핸들을 해줘야한다. 번역된 코드에 있는 Trap을 유발하는 코드에대해서 반드시 처리를 해줘야한다. Runtime은 이것을 처리하기 위해서 exception emulator를 가지게 된다. 이것을 처리해줄때 반드시 Guest의 state를 보장해줘야한다. program counter 또는 register value, trap condition 같은 것들을 말이다.


Side table은 translation 절차에 의해서 만들어 지는 것이다. 이것의 중요한 사용처중 하나는 exception model을 정확하게 동작시키기 위함이다. 즉 source ISA를 정확하게 매칭 시킨다. 









보충 자료




 JIT의 정의 : JIT는 일반적인 뜻으로 'Just-in-time'의 약어로 ‘즉시’라는 뜻입니다.

 JIT 컴파일은 Java, C#등에서 제공하는 ‘실시간’ 컴파일 방식입니다. 자바 가상 머신 실현 방법의 하나입니다. 가상 머신의 실현 방법으로는 현재 3종류가 있습니다. 이 JIT 컴파일러는 자바의 중간 코드인 바이트코드를 실행하는 컴퓨터 운영 체계(OS)와 중앙 처리 장치(CPU)에 맞춘 2진 코드로 일괄 변환한 후에 실행합니다. 자바 해석기 방식의 10~20배의 성능을 얻을 수 있습니다. 다시말해 JIT는 JIT Compiler라 하고 자바 프로그램의 실행 속도를 향상 시키기 위해서 개발된 기술입니다. 일반적인 자바 프로그램 실행은 byte code 가 native code(JVM이 실행중일 OS가 이해할 수 있는 code)로 변환 후 실행 되게 합니다. 이때 JIT는 byte code loading시 변환된 native code의 주소를 v-table에 표기하고 이후 실행시에는 곧바로 native code를 실행 하는 방식으로 속도를 향상 시킵니다. 이것은 기존의 interpreter방식의 단점을 보완한 방법으로 특정 메쏘드를 지속적으로 호출할 때 더 빠른 성능을 보입니다. 하지만 이로 인해 일부 프로그램의 경우 오히려 성능 저하를 가져 올 수 있습니다. (반복 적인 메소드 호출이 없는 경우에는 지속적인 bytecode->machine code 로의 컴파일이 발생 하기 때문에 성능 저하가 발생 합니다.) 이를 보완 하기 위한 compile 방식으로 AOT(ahead-of-time)방식이 있습니다. 이 AOT방식은 실행 전에 미리 컴파일 하는 방식으로 성능 향상에 도움이 됩니다.


좀 더 쉽게 요약


AOT(Ahead of Time) - 실행 시간 이전에 이루어지는 컴파일 방식이며 (실행시점이 아닌 설치시점에 미리 이루어진다는 뜻),

컴파일 타임에 중간언어로 번역한 다음 가상 머신 코드(중간 언어)를 최종 기계어로 번역한다.


JIT(Just In Time) - 실행 시간 이전에 컴파일 한 내용을 미리 가상 머신 코드(중간 언어)로 저장해놓고

                        컴포넌트 사용시 (매번 실행시 마다)에 가상 머신 코드를 최종 기계어로 바꾸어 명령어가 실행되도록 한다.




JIT 컴파일러의 경우 바이트코드를 재실행하는 경우 네이티브 코드를 다시 사용한다.

이 NativeCode의 단위는 class단위가 아니고 method단위이다.

JIT 컴파일러는 byte코드를 최적화한다.


AOT 컴파일러의 경우

- JIT와 동일하게 ByteCode->NativeCode로 컴파일한다. 

- 다른점은, 하나의 JVM에서만 사용할 수 있는게 아니라,여러 JVM에서 사용할 수 있다는 것이다.

- AOT Compiler는 생성한 AOT code를 Shared Cache에 저장한다. 그러면 이 Shared cache를 사용하는 JVM은 기동 시 AOT Code를 바로 사용할 수 있게 되어 기동시간이 줄어드는 이점이 있다




Wikipedia


Ahead of time compilation (AOT)


AOT는 컴파일을 하는 작업의 하나의 종류로 고수준의 언어인 java와 .net 같은 것들의 중간코드 IR 들 즉, 머신에 독립적인 코드들을 native 코드로 변경 하는 작업을 말한다.


보통 중간코드들은 실행되는 순간에 머신 코드로 변경이되는 Just in time(JIT)방식을 취하게 된다. 하지만 이러한 방법들은 응용프로그램의 성능 저하에 원인이 될 수 있다.

AOT는 이러한 수행중 컴파일되어야하는 필요성 자체를 제거하는 기법으로, 실행전에 모든것을 컴파일 하는 방법이다. 하지만 이것은 제한적인 수행 범위를 같는 것이 일반적이다.


AOT 컴파일 방식이 효과적인 상황에 대해서 이야기 하겠다.

1) interpreter가 너무 느린 경우

2) JIT 가 너무 복잡한 경우

3) 지연이 너무 큰경우


AOT는 표준 네이티브 컴파일러와 같은 최적화된 머신 코드를 만들어 낸다. 

즉, compiler 기술이라고 볼 수 있다.



Just in time compilation (JIT) - compiler라는게 정설이다 -

JIT는 dynamic translation기술로 알려져 있으며, 실행중에 중간코드를 머신코드로 변경하는 작업을 한다.

JIT compliation은 2개의 전통적인 기술을 조합한 방법이다. 즉, AOT 기술과 interpretation 기술의 각각의 장점과 단점들을 융합한것이다. 

중간 언어까지는 AOT로 컴파일을 하니, 그 장점을 취함.

Interpretation에서 제공하는 타겟에 덜 의존성적이며 이로인해서 컴파일러 개발 보다는 덜 보작하다는 장점을 취함. 또한 따로 최적화를 하지 않기 때문에 실행에 지연을 발생 시키지 않는다. 


- Applications

현대의 대부분의 runtime 환경들은 JIT compilation 기술에 의존한다. 높은 실행 속도를 제공하기 위해서

bytecode로 AOT를 이용해서 모두 변경 한다음에,

이러한 bytecode를 runtime시점에 machine code로 변경하게된다. 똑같은 코드가 다시 실행된다면, 그것을 재활용 하게 된다.

이것은 결국 interpreter 기능을 향상 시킨 기법이다.


이 JIT Compilation의 궁극적인 목표는 bytecode interpretation의 장점을 유지한체로, static compilation의 성능을 뛰어 넘는 것이다.

기본적으로, JIT은 interpreter 보다는 빠르다. 하지만 당연히 profiling을 하닌까 손실은 발생 할 수 있다.

그리고 몇몇 케이스에 대해서 static compiler 보다도 빠를 수 있다. 왜냐하면, 많은 최적화 기술들은 run time에만 실현 가능한 기술들이 있기 때문이다.


1) 실행중에 타켓 CPU나 운영체제에 맞추어서 최적화를 시킬 수 있다. 

2) 특정 영역이 얼마나 빈번히 실행 되는지에대한 통계값을 이용해서 최적화를 시도할 수 있다.

3) Inlining을 통해서 global code optimization들을 수행 할 수 있다. 이게 static에서는 어려운 이유가 virtual call 때문이다. 다형성으로 인해서 override 된 함수는 실행 해봐야 뭐가 콜 될지를 알 수 있다.

4) GC를 최적의 조건에 맞춰서 부를수 있다. 스태틱하게도 되지만, 어렵다. 실행해봐야 최적의 GC 시점을 알 수 있다.


- Startup delay and optimizations

bytecode를 Load하고 Compile하는 시간 때문에, JIT는 실행의 처음 단계에서 약간의 지연을 발생 시킨다.

이것을 startup time delay 라고 종종 부른다. 

JIT compiler는 최적화가 잘된 Machine Code를 만들어 낼 수 있다. 하지만, 지연은 더더욱 증가하게 되는  trade-off 관계를 가진다.

JVM에서의 전략은 다음과 같다.

일단 bytecode는 interpretation 된다. 그다음 JVM은 bytecode의 실행 빈도를 모니터링 하게 된다. 이렇게해서 가끔 실행 되는 코드들은 최적화를 위한 컴파일 시간을 대폭 줄이게 된다. 하지만 자주 실행 되는 코드라면, 최적화 기능을 모두 적용해서 interpretation 하게 된다. 이렇게하면 초기 지연은 좀 발생하지만, 자주실행되는 bytecode 이기 때문에 다음번 부터는 최적화된 machine code로 실행 할 수 있게 된다. 





Interpreter (이것은 compiler와 대립되는 기술이다.)

컴퓨터 프로그램을 직접적으로 실행하는 방식을 말한다. 즉, 프로그래밍 언어나 스크립트로 짜여진 명령어들을 머신 코드로 실행전에 변경하지 않고 그것을 실행 하는 것을 말한다. 그때 그때 머신 코드로 변경해서 실행하는 것이다.


interpreter는 다음의 전략들중 하나를 프로그램 실행을 위해서 사용 한다.

1) 소스코드를 파스하고 그것을 실행한다.

Lisp programing language and Dartmouth BASIC


2) 소스코드를 중간 코드 몇몇으로 변경한다음 그것을 실행 한다.

Perl, Python, MATLAB, Ruby


3) 인터 프리터 시스템의 한부분인 컴파일러에 의해서 만들어진 precompiled code를 실행하게 된다. (중간코드를 사용)

UCSD Pascal


소스코드는 ahead of time에 컴파일 되어지며, 이것은 머신에 독립적인 코드로 저장되어져 있다.

그다음 이것은 런타임에 인터프리터나, JIT 컴파일러 같은것들에 의해서 runtime에 실행 되어 진다.


java 같은 시스템들은 위 기술들중 몇개를 혼용해서 사용 한다.



Interpreter, static (ahead-of-time) compilation, and Just-in-time (JIT) 3개 구분

전통적으로 컴퓨터 프로그램을 실행하는 방법은 3가지 방법이 존재한다.


1) 인터프리터는 고수준 언어를 저수준언어로 실행할때 번역하게 된다.

2) AOT는 실행 이전에 모두 저수준언어로 번역하여 실행 한다.

3) JIT는 사실 위 두 기술의 hybrid 형태이다. 실행할때 고수준언오를 저수준언어로 번역하게 되고, 이것은 캐쉬에 저장된다. 따라서 매번 번역 과정을 수행하지 않는다. 하지만 분명히 AOT에 비해서 실행중에 번역을 하므로 오버해드는 존재한다.






+ Recent posts