일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 인공지능
- 삼성전자 소프트웨어멤버십 SSM
- 고려대학교
- 멤버십
- Neural Network
- 갤럭시탭S8울트라
- 증강현실
- Python
- NarwalFreo
- 삼성
- 빅데이터
- 신경회로망
- 물걸레자동세척로봇청소기
- 패턴인식
- 구글 앱 엔진
- 물걸레로봇청소기추천
- 파이썬
- Google App Engine
- BAM
- 삼성소프트웨어멤버십
- 신경망
- Friendship
- Bidirectional Associative Memory
- 하이퍼바이저
- SSM
- 동아리
- 가상화
- 나르왈프레오
- hopfield network
- 패턴 인식
- Today
- Total
정보공간_1
[2기 수원 이동열] Memory hierachy 본문
일반적으로 C언어를 배우는 과정에서 register키워드를 사용한 변수가 빠르다는 것을 여러 서적을 통해서 학습을 하게 됩니다. 본 포스트에서는 실제로 register 변수와 일반 변수에 대해 실험을 진행하여, 메모리 구조를 통해 왜 register 변수의 속도가 더 빠른지 그 이유를 살펴보고자 합니다. 또한 그에 따른 컴퓨터의 cache 메모리에 대해 다뤄 보고자 합니다. 일단 컴퓨터의 입장에서는 C언어로 작성된 코드는 인식을 할 수가 없습니다. 따라서 C언어로 제작된 프로그램들을 컴파일을 통해서 컴퓨터가 인식하는 binary들로 변환을 하게 됩니다.
실험을 위한 간단하게 C언어로 프로그램을 제작 해보았습니다. 하나는 register 변수를 사용한 루프이고, 다른 하나는 일반 변수를 사용한 루프입니다. 그리고 두 개의 루프를 사용하였을 때, 루프를 실행한 시간을 출력하는 프로그램입니다. 위 실험은 linux환경에서 진행을 하였으며, GCC 4.4.4를 사용하였습니다. 실험은 Xeon 2.53GHz, Cache size 8MB에서 실험을 실시해 보았습니다.
프로그램은 각 변수에 대해 1,000,000,000번의 루프를 돌렸을 때의 성능을 측정하는 프로그램입니다. 컴파일된 코드 분석을 위해 인라인 어셈블리를 사용하여, 디스어셈블을 실행하면 해당 루프에 대한 코드가 어느 부분에 위치하는지 알 수 있도록 하였습니다.
총 5번 프로그램을 실행해보았으며, 모든 경우에 대해서 레지스터 변수가 약 3배 이상 더 좋은 성능을 낼 수 있다는 것을 확인할 수 있었습니다. 실험결과는 일반적인 서적에 나와 있듯이 레지스터 변수가 더 빠르다는 결론에 도달을 할 수 있었는데요. 해당 프로그램이 컴파일 이후 생성된 코드를 분석하기 위해 objdump를 활용하여 디스어셈블을 시켜 보았습니다.
위 그림은 프로그램의 여러 부분 중 실험과 관련된 루프가 있는 코드 부분입니다. 일단 루프 사이에는 총 5개의 명령어로 이뤄져 있다는 것을 확인할 수 있었으며 컴파일러는 register 변수, 일반변수를 구분하지 않고 비슷한 코드를 생성한다는 것을 확인할 수 있었는데요. 디스어셈블 된 소스코드를 분석을 해보면, 두 가지 모두 mov, add, cmp, jbe, jmp 이렇게 5개의 명령어로 구성이 됩니다. 여기서 가장 눈 여겨 봐야 할 차이점이 있는데, mov, add cmp 명령어에 일반 변수를 사용한 루프는 모두 메모리 접근을 위한 offset이 들어간다는 것을 확인할 수가 있습니다. 결국 이 부분이 루프의 성능 차이를 만들어 내는 부분입니다.
레지스터 키워드로 선언한 변수들은 컴파일러에 의해 범용 레지스터에 할당이 됩니다. 그리고 일반 변수들은 스택이나 힙에 할당이 됩니다. 그리고 스택이나 힙은 레지스터가 아닌 컴퓨터 메모리에 위치해 있게 되는데, 여기서 말하는 메모리는 CPU내에 있는 메모리가 아니라 DRAM이 됩니다.
이것은 현재 일반적인 컴퓨터의 메모리 계층을 나타내주는 그림입니다. 컴퓨터의 메모리는 위와 같은 계층을 가지게 되는데, 컴퓨터의 탑재된 CPU의 입장에서는 상단에 위치해 있을수록 더 빠르게 데이터를 처리할 수 있습니다. 상단에 위치해 있다는 것은 core의 입장에서 물리적으로 더 가까운 거리에 있다는 것을 의미하고, 물리적인 거리에 가깝다는 것은 더 빠르게 데이터를 가져올 수 있다는 것을 의미하게 됩니다. 따라서 register 키워드로 사용하여 정의된 변수들이 일반 변수들보다 더 빠르게 동작을 할 수 있는 것은 컴파일 타임시 해당 변수를 범용 레지스터로 사용하도록 할당해주기 때문이며, 이렇게 할당된 범용 레지스터가 하드웨어적으로 더 빠르기 때문입니다.
메모리는 계층은 크게 2가지로 나눌 수 있습니다. 나누는 경계가 CPU가 될 수 있는데, CPU 입장에서 cache 계층까지는 CPU 내부에 포함이 되게 됩니다. Cache 계층의 하위에 있는 메모리는 CPU 밖에 위치하게 됩니다. 따라서 CPU입장에서 메모리를 사용하는 명령어인 load/store가 다른 명령어들에 비해서 많은 시간이 걸리는 이유는 이 부분 때문입니다. 다른 명령어들은 모두 CPU내부에서 처리할 수 있지만, 메모리 관련된 명령어는 CPU 외부에 의해 영향을 받는 부분이 다수 존재하게 됩니다. 이러한 영향은 결국 CPU가 가지고 있는 최고의 성능을 제대로 활용하지 못하는 상황이 발생할 수 있는데, 이러한 문제를 해결하기 위해서 CPU내부에 cache 메모리가 존재하게 되는 겁니다.
위의 그림은 컴퓨터의 각 메모리들에 대한 동작 속도를 나타내주는 그림입니다. 만약 캐쉬가 없는 상태를 가정을 하고 위의 코드를 실행하게 된다면, 약 25ns의 시간이 걸리게 됩니다. 하지만 캐쉬가 존재하게 된다면, 17ns의 시간이 걸리게 됩니다. 1초에 억 단위의 명령어를 수행하는 CPU입장에서는 메모리와 관련된 명령어로 인해 좋은 성능을 발휘하지 못하는 문제가 발생할 수 있지만, cache 메모리로 인해 메모리 관련 명령어의 오버헤드를 줄일 수 있다는 것을 확인할 수 있습니다.
최근에 나오는 프로그램들은 많은 리소스를 요구하며, 그에 따라 많은 메모리를 할당하고 동작하게 됩니다. 따라서 CPU내부에 있는 cache 메모리가 하는 역할이 그만큼 중요해지고 있으며, 여러 방향으로 cache 메모리의 최적화 연구가 활발히 진행되고 있습니다. 특히 최근에 나오는 multi core processor 나 heterogeneous architecture 같은 경우에서는 cache가 복잡하게 구현이 되어 있으며, 단순히 데이터들을 임시로 저장하는 것에서 벗어나 여러 개의 core가 동시에 동작할 때 상호간의 데이터 공유에 대한 동기화 부분과 이에 관련된 최적화 등도 지속적으로 연구가 진행되고 있는 분야입니다.
'IT 놀이터 > Elite Member Tech & Talk' 카테고리의 다른 글
[2기 대구 김길종] Unity3D 기초 (1) (0) | 2012.09.23 |
---|---|
[2기 대구 이현복] Data Structure - List (0) | 2012.09.23 |
[2기 대전 김호원] Concerto MCU 2. 프로젝트 생성 (0) | 2012.09.20 |
[2기 강북 송석호] OSGi FrameWork에서 Bundle 만들기 (0) | 2012.09.20 |
[2기 대구 최진원] C++ Class & Basic OOP (0) | 2012.09.19 |