MSDN에 있는 글을 옮겨와 봤습니다^^

 

다른 프로세서에서 사용되고 있는 복수의 동시실행 태스크가 같은 캐시라인에 배치되어 있는 변수에 쓰기를 하면 거짓 공유가 발생한다. 하나의 태스크가 어떤 변수에 쓰기를 하면 양쪽 변수의 캐시라인이 무효화된다. 캐시라인이 무효화 될 때마다 재 로딩이 필요하게 된다. 즉 거짓 공유가 발생하면 애플리케이션의 성능이 저하할 위험이 크다.

 

long count1 = 0L;

long count2 = 0L;

concurrency::parallel_invoke(

   [&count1] {

      for(int i = 0; i < 100000000; ++i)

         ++count1;

   },

   [&count2] {

      for(int i = 0; i < 100000000; ++i)

         ++count2;

   }

);

long count = count1 + count2;

위의 코드는 태스크에 공유 변수를 사용하지 않기 위해 count1, count2로 변수를 나누어서 사용하고 있다. 그래서 일견 보기에는 서로 독립적으로 실행될 것이라고 생각할 수 있다. 그러나 위에 설명했듯이 count1 count2는 서로 같은 캐시라인에 배치될 확률이 높아서 결과적으로 거짓 공유가 발생한다.

 

이 문제를 해결하기 위해서는 아래처럼 메모리 정렬에 의해 서로 다른 캐시라인에 배치되도록 한다.

__declspec(align(64)) long count1 = 0L;     

__declspec(align(64)) long count2 = 0L;     

concurrency::parallel_invoke(

   [&count1] {

      for(int i = 0; i < 100000000; ++i)

         ++count1;

   },

   [&count2] {

      for(int i = 0; i < 100000000; ++i)

         ++count2;

   }

);

long count = count1 + count2;

핵심은 __declspec(align(64))으로 메모리 캐시 사이즈가 64바이트 이하인 경우 같은 캐시라인을 사용하지 않도록 해준다.

 

 

__declspec 설명

http://blog.naver.com/riverrun27/40126498899

 

 

저작자 표시
신고
by 흥배 2014.02.03 08:00

병렬 프로그래밍의 하나의 스타일로 간단하면서 범용적이므로 널리 사용되고 있다. SPMD Single Program Multiple Data의 약어이다. 이것의 의미는 복수의 프로세서 상에서 각각의 데이터를 이동하고 그것을 처리하는 프로그램은 동일하다 이다.

 

SPMD 언어로는 OpenMP, Co-array Fortran, UPC, Titanium 이 있다.

저작자 표시
신고
by 흥배 2009.12.23 00:18

[CEDEC 2009]MS의 카와니시 히로유키씨가 차기 개발툴 「Visual Studio 10」의 병렬화 지원 기능을 소개


이미, 멀티 코어 프로세서는 가격적으로도 특별한 것은 아니다. 사진은 Phenom II X4 965 Black Edition/3.4GHz」

PC의 세계에서도 또 컨슈머(consumer) 게임기의 세계에서도 멀티 코어 프로세서가 급속히 퍼지고 있다. 싱글 코어로의 성능이 향상하던 시대라면 프로그래머가 가만히 있어도 하드웨어가 새로워지면 프로그램의 고속화를 기대할 수 있었지만 멀티 코어 시대는 그렇지 않다.
 

프로세서 전체의 퍼포먼스는 오르고 있어도 코어 하나 정도의 성능이 오르고 있다고는 할 수 없기 때문에 아무것도 생각하지 않은 프로그램은 전혀 성능이 오르지 않는 상황이 되고 있어 프로그래머 측에도 노력이 요구되고 있는 것이다. 많이 알려진 “프로그램의 병렬화”(자주 말하는 multi-thread 화와 거의 동의)이다.
 

게임은 비교적 multi-thread화가 어려운 소프트웨어로 4Gamer에 게재되는 각종 benchmark test 결과에서도 멀티 코어로의 성장이 적은 현실에 그것이 잘 나타나고 있다고 말할 수 있을 것이다.
 

그렇다고는 해도 멀티 코어화의 흐름 거술러 수는 없는 것으로 게임도 CPU 코어 수에 따라 확정성 높게 퍼포먼스를 늘릴 수 있는 병렬화의 궁리가 필수가 되고 있는 것도 확실하다.
 

CEDEC 2009의 2일 째에 행해졌던「측정할 수 있는 병렬화」라고 제목이 된 세션은 차기 개발툴「Microsoft Visual Studio 2010」(이하 Visual Studio 2010)가 지원 하는 병렬화 지원의 소개를 중심으로 병렬화의 포인트를 설명 하는 내용이었다. 게임에 특화한 이야기는 적고 또 프로그래머 전용의 세션인 만큼 게이머에게 직접 관계가 있는 이야기는 아니지만 툴의 지원이 충실하는 것으로써 게임의 병렬화도 진행되지 않을까라고 기대하면서 내용을 소개해 본다.



프로그램의 병렬화에 가로막는 다양한 곤란

 

마이크로소프트 디벨로퍼&플랫폼 통괄 본부 플랫폼 선교자 카와니시 히로유키씨

본세션을 담당한 것은 Microsoft의 일본 법인인 마이크로소프트에서 플랫폼 선교자를 맡은 카와니시 히로유키씨다. 마이크로소프트가 담당하는 기술 세션에서는 친숙한 「얼굴」이다. 아시는 분도 많다고 생각하지만 카와니시씨가 자랑으로 여기는 것은 그래픽스. 그 때문에 이 세션도 「뒤의 타이틀은「Larrabee」(라라비, 개발 코드네임)의 준비를 하자, 차세대 준비를 하려는 김」으로 할까라고 생각하고 있었다고 한다.
 

카와니시씨는 우선 CEDEC 2009에서 행해졌던 CrytekCarl Jones씨에 의한 세션에서 다루어지고 있었다고 하는 예측을 소개. 그것은 2013년 이후 CPU, GPU 함께 고도로 병렬화 해 경합 하게 될 것이다 라고 하는 내용이다.
 

카와니시씨는 여기서 고도로 병렬화한 CPU나 GPU에 대응하는 「새로운 렌더링 알고리즘이 요구된다」라고 말한다. 그것이 어떤 것이 될까는 모른다고 하면서 「Direct3D 패러렐과 같은 것이 나올지도 모른다」라고 예측하고 있었다.또 그렇게 멀지 않은 장래 등장할 Larrabee에 대해서도 「범용적인 알고리즘이 예를 들면 32기의 CPU로 움직이는 것이 실현된다」라고도 말하고 있었다.


Crytek의 Carl Jones씨가 말하고 있었다고 하는 병렬화의 예측. 2013년 이후 CPU와 GPU는 고도로 병렬화해 새로운 패러다임(paradigm)가 요구되게 된다고 한다

 

카와니시씨는 Larrabee 대단히 기대하고 있는 것 같다. Larrabee는 범용적인 Pentium 클래스의 CPU 코어를 다수 집적한 프로세서로 GPU과는 달리 범용적인 알고리즘을 메니 코어로 처리할 수 있다

 

병렬화에 가로막는 다양한 장매물. 섬세하게 설명은 하지 않지만 무엇을 병렬로 하는가 하는 설계 상의 난관에 더해 스렛드 간의 동기, 데드 락이라고 하는 기술상의 문제나 에러로부터의 회복이나 디버그가 어려운 점 등 처음부터 마지막까지 병렬화에는 다양한 난관이 기다리고 있다

 

장래적으로는 32 CPU, 64 CPU……라고 하는 메니 코어로 프로그램을 동작시킬 필요가 있어 프로그램의 측정할 수 있는 병렬화는 급무가 되고 있는 것이다. 하지만 병렬화는 그렇게 간단한 물건은 아니다.
 

현재 유감스럽지만 자동적으로 프로그램을 병렬로 해 주는 「자동 병렬화 컴파일러는 없다」(카와니시씨). 따라서 병렬화는 프로그래머가 스스로 실시하지 않을 수 없지만 거기에는 다양한 곤란이 있다고 하며 나타난 것이 오른쪽의 슬라이드다.이러한 곤란을 어느 정도 클리어로 해 주는(≒해결해 준다)  “영리한 개발툴”이 요구된다고 지적한다.



Visual Studio 2010에 들어간 병렬화를 지원하는 기능

 

Visual Studio 2010에 구현되고 있는 태스크 스케쥴러. 여기서 말하는 태스크는 「병렬로 실행시키고 싶은 일」이라고 이해해 주었으면 한다. 프로그램측이 태스크 스케쥴러에 태스크를 건네주면 그것을 적절한 타이밍에 스레드로서 Windows에 실행시킨다고 하는 이미지다

 

베타인 Windows프 로그래밍에서는 병렬화할 수 있는 처리를 스레드로 구현하고 Windows API를 사용해 스레드를 기동시킨다라고 하는 일을 실시한다.
 

기동된 스레드는 Windows 커널의 스케쥴러가 적당한 CPU에 할당해 주지만 스레드를 처리시키는 차례 등은 프로그래머 스스로가 결정할 필요가 있다. 차례의 사정으로 놀고 있던 CPU가 나와 버리는 것은 바람직하지 않지만--CPU 수에 따라 성능을 올리고 싶으면 놀고 있는 CPU는 가능한 한 줄이고 싶다--, CPU를 효율적으로 일하게 하는 것은 꽤 어렵다고 하는 문제가 있다.
 

거기서 Visual Studio 10의 런타임에는「유저 모드 스케쥴러」라는 것이 구현되어 있다고 한다.
 

유저 모드 스케쥴러는 프로그램측에서 건네받은 태스크를 적절한 타이밍(=CPU가 보다 효율 좋게 일하는 타이밍)으로 태스크를 Windows의 스레드로서 실행시키는 기능을 가지고 있다.
 

예를 들면 「가능한 한 캐쉬가 두꺼운 태스크를 스케줄 한다」(카와니시씨)라고 한 것까지 자동적으로 해 준다라는 것.  「캐쉬가 두꺼운 태스크」라고 하는 것은 「캐쉬가 히트 하고 있을 태스크」라고 하는 의미이지만 유저 모드 스케쥴러의 자원 매니저는 PC에 탑재되고 있는 CPU 코어 수등을 파악하고 있어 기동하는 스레드의 수를 CPU 코어 수에 따라 조절한다고 하는 것도 자동적으로 행해진다라는 것이다.
 

여기서 데먼스트레이션을 했다. 그 내용은 아래에 게재한 사진으로 확인해 주었으면 한다.



 

바이너리 트리의 탐색을 재귀적으로 실시하는 C#의 데모 프로그램. 단순하게 스레드화 하면 ,500 이상의 스레드가 일어선다

 

메모장에 쓰여진 「17670」은 싱글스 레드로의 실행 시간(17.670초)로 「16866」은 multi-thread화 했을 때의 실행 시간(16.866초). 거의 변하지 않는 것은 4 코어의 플랫폼에서 500 이상의  스레드를 동시에 기동시켰기 때문이다.스레드 수가 너무 많아서 콘텍스트 스위칭이나 메모리 확보 등의 오버헤드가 커져 멀티 코어의 메리트를 살릴 수 없다

 

스레드 대신에 Visual Studio 10의 태스크로서 기동시키도록 고쳐 쓴다

 

그러면 불과 6초만으로 같은 처리가 종료했다.유저 모드 스케쥴러가 CPU 코어 수에 응한 태스크를 기동시켰기 때문이다

 



parallel_for 이용 예이지만 실제로는 정상적으로 동작하지 않는다. 병렬화 된 for문장 중에서 변수 u,v가 변화하기 때문이다. 이와 같이 스레드간에 공용되는 데이터가 있는 케이스에서는 단순하게 for 문장을 parallel_for로 옮겨놓을 수 없다

 

이 바이너리 트리의 데모는 약간 극단적이기는 하지만 유저 모드 스케쥴러의 효과를 매우 잘 아는 예다. 프로그래머는 플랫폼에 탑재되고 있는 CPU 코어 수를 의식할 필요는 없이 병렬화 할 수 있는 부분을 태스크로서 건네주는 것만으로 적당한 스레드로서 실행해 주는 모습을 알 수 있다.
 

또, Visual Studio 2010에는 병렬화를 지원하는 라이브러리 세트가 들어가 있어 루프를 병렬화한 parallel_for(for 문장을 병렬에 열린다), parallel_foreach(foreach를 병렬에 열린다)라고 하는 구조를 이용할 수 있는 것 같다.

....... 이하는 생략합니다.


 

 

출처 : http://www.4gamer.net/games/032/G003263/20090903008/

 

이 글은 스프링노트에서 작성되었습니다.

신고
by 흥배 2009.09.17 01:06
| 1 |

티스토리 툴바