Parallel Patterns Library(PPL) - concurrent_vector - 1

VC++ 10 Concurrency Runtime 2009. 11. 29. 08:30 Posted by 알 수 없는 사용자

Visual Stuido 2010 Beta2가 나오면서 제가 기대하고 있었던 병렬 컨테이너가 드디어 구현되었습니다.

 

Concurrency Runtime(이하 ConRT)에는 총 3개의 병렬 컨테이너를 제공합니다. Beta2에서는 모두 다 구현되지는 못하고 concurrent_vector concurrent_queue 두 개가 구현되었습니다. 아직 구현되지 않은 것은 concurrent_hash_map 입니다.

 

세 개의 컨테이너들은 C++ STL의 컨테이너 중에서 가장 자주 사용하는 것으로 vector, deque, hash_map 컨테이너의 병렬 버전이라는 것을 이름을 보면 쉽게 알 수 있을 것입니다.

 

STL에 있는 컨테이너와 비슷한 이름을 가진 것처럼 사용 방법도 기존의 컨테이너와 비슷합니다. 다만 병렬 컨테이너 답게 스레드 세이프하며, 기존의 컨테이너에서 제공하는 일부 기능을 지원하지 못하는 제한도 있습니다.

 

 

몇 회에 나누어서 concurrent_vector concurrent_queue에 대해서 설명해 나가겠습니다.

이번에는 첫 번째로 concurrent_vector에 대한 것입니다.

 

 

 

concurrent_vector란?

 

STL vector와 같이 임의 접근이 가능한 시퀀스 컨테이너입니다. concurrent_vector는 멀티 스레드에서 요소를 추가하던가 특정 요소에 접근해도 안전합니다. 반복자의 접근과 순회는 언제나 멀티 스레드에서 안전해야 하므로 요소를 추가할 때는 기존의 인덱스와 반복자를 무효화 시키면 안됩니다.

 

 

concurrent_vector vector의 차이점


기능

vctor

Concurrent_vector

추가

스레드에 안전하지 않음

스레드에 안전

요소에 접근

스레드에 안전하지 않음

스레드에 안전

반복자 접근 및 순회

스레드에 안전하지 않음

스레드에 안전

push_back

가능

가능

insert

가능

불가능

clear

모두 삭제

모두 삭제

erase

가능

불가능

pop_back

가능

불가능

배열식 접근 예. &v[0]+2

가능

불가능

 

 

grow_by, grow_to_at_least (vector resize와 비슷)는 스레드에 안전

 

 

추가 또는 resize 때 기존 인덱스나 반복자의 위치가 바뀌지 않음

 

 

bool 형은 정의 되지 않았음

 


concurrent_vector에 대한 설명을 이번에는 소개 정도로 끝내고 다음부터는 본격적으로 Concurrent_vector을 어떻게 사용하면 되는지 상세하게 설명해 나가겠습니다.^^


Visual Studio 2010과 Blend Preview for .NET 4 통합 문제

Visual Studio 2010 2009. 11. 23. 17:40 Posted by 알 수 없는 사용자
Visual Studio 2008과 Expression Blend 3를 사용 할 때 Visual Studio의 프로젝트/솔루션의 xaml 파일에서 마우스 오른쪽 버튼 클릭 후 Open in Expression Blend 메뉴를 클릭하면 Blend 3가 열리면서 디자인 작업 하는 방법을 많이 사용하실겁니다.

이번에 PDC09에서 Silverlight 4가 발표되면서 VS2010과 Blend Preview for .NET 4를 설치 하신 분들이 많을텐데 VS2010에서 Open in Expression Blend 메뉴를 클릭하면 Blend Preview for .NET으로 열리는게 아니고 Blend 3로 열리는것을 경험 할 수 있습니다.

기존에 설치된 Blend 3 때문에 그런 줄 알았는데 VS2010과 Blend Preview for .NET 4만 클린 설치 해도 Blend가 실행 되지 않는다고 합니다. 이 경우에는 Open in Expression Blend 메뉴가 나타나지 않는다고 하네요.


결론적으로 Blend 3가 함께 설치된 경우에만 메뉴가 나타나며 그것도 Blend 3로만 연결되어 실행되는 결과가 나타납니다.
이 문제를 해결하기 위해서는 레지스트리를 수정해서 해결 할 수 있습니다.

레지스트리 편집기에서 HKLM\Software\Microsoft\Expression\Blend 항목에서 VS키에서 String 이름을BlendLaunchPath 로 해주고 Expression Blend의 경로를 입력해주면 됩니다.

 1: [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Expression\Blend\VS]
 2: "BlendLaunchPath"="\"c:\\Program Files\\Microsoft Expression\\
     Blend Preview for .NET 4\\Blend.exe\""

x64 시스템의 경우 경로가 조금 다릅니다.
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Expression\Blend\VS

Wow6432Node 아래에 있으니 주의하시고 수정하시기 바랍니다.

수정하기 번거로우면 첨부 파일을 열어서 시스템에 맞는 파일로 실행시켜주면 됩니다.



※ 원문은 Microsoft의 Tim Heuer 블로그에 있습니다.

Silverlight 4 Beta 공개

RIA 2009. 11. 19. 09:00 Posted by 알 수 없는 사용자

Microsoft PDC09 행사 2일째가 진행중인데 Scott Guthrie의 키노트 발표에서 드디어 Silverlight 4가 공개되었습니다.
올 해 3월달에 MIX09 행사에서 Silverlight 3 베타가 발표되고 7월에 정식 버전이 나왔는데 이후 4개월만에 다시 새로운 버전 베타가 나왔네요.
PDC09 생중계를 보면서 설마설마했는데 발표가 끝나자마자 바로 다운로드가 가능해졌습니다.

아쉽게도 Visual Studio 2010 Beta2에서만 설치가 가능하며 Visual Studio 2008에서는 SL4를 지원하지 않습니다.
그렇지만 VS2010에서 새롭게 향상된 점을 이용한 SL4개발이 기대되지 않나요? ㅎㅎ

키노트에서 SL4의 새로운 점과 데모를 보여줬는데 그 동안 요구사항이 많았던 기능들이 대부분 들어간 것 같습니다.
많은 기능 향상이 이루어졌지만 구글 크롬 브라우저의 정식 지원도 눈에 띄네요.
기존에도 구글 크롬에서 실버라이트가 사용이 가능했지만 공식 지원이 아니라서 그런지 간혹 문제점이 발견되기도 했었는데 SL4에서는 크롬 브라우저를 지원하게 되었습니다.
개인적으로는 웹캠과 마이크 지원, 그리고 HTML 지원 등이 가장 맘에 드네요.
이 외에도 정말 많은 기능과 성능 향상이 이루어졌습니다.
자세한 내용은 Silverlight 4 Beta 공식 사이트에서 확인이 가능합니다.

일단 SL4 발표 소식을 간단하게 전하며 앞으로 차근차근 Silverlight 4와 Visual Studio 2010에서의 개발 방법에 대해 알아보도록 하겠습니다.

[JumpToDX11-7] 간편해진 리소스 처리.

DirectX 11 2009. 11. 18. 15:00 Posted by 알 수 없는 사용자


이번 회의 설명을 위해서 API 를 다음과 같이 크게 나누어 보았습니다.

·        Thread unsafe API

·        Thread safe API

·        Free threaded API


Thread unsafe 한 경우에는 멀티스레드들이 동시에 호출할 수 있지만,
이들에 대한 안정성에 대해서는 전혀 보장하지 않습니다.
결과가 갑자기 이상할 수도 있고, 예측 불가능한 상황을 연출할 수도 있습니다.
주로 즉시즉시 상황을 만들어야 할때 사용될 수 있을 것입니다.

Thread safe 한 API 는 어떤 동기화 모델에 의해서 API 가 보호되어집니다.
여러 스레드에서 API 를 호출하더라도, 그들의 안정적인 동작을 보장한다는 의미입니다.
동기화 작업이 별도로 있기 때문에 느려질 수 있다는 단점이 있습니다.

Free threaded 한 API 는 여러 스레드에서 호출을 하더라도,
어떠한 동기화 모델 없이도 API 가 안정적으로 동작한다는 것을 의미합니다.
그렇기 때문에 아주 높은 성능 향상을 얻을 수 있습니다.

< 기존의 리소스 처리 >

멀티스레드 기반의 렌더링으로 가는 첫번째 길은 리소스 부분입니다.
PC 가 발전하면서 성능적으로나 용량적으로 많은 발전을 거듭했습니다.
더블어 게임에서 사용되는 리소스의 용량도 크게 증가했습니다.

멀티스레드 처리가 어느 정도 자리를 잡으면서,
현재 많은 게임들은 이들 리소스에 대한 처리를 별도의 스레드에서 처리하기도 합니다.




일반적인 텍스쳐 로딩 상황을 한번 가정해 보았습니다.
가장 먼저 로더 스레드가 특정한 파일을 읽습니다.
읽어둔 파일을 바탕으로 실제 메모리를 할당하기 위해서는 결국 Device 인터페이스를 통해야 합니다.
DirectX 에서 리소스 관련 메모리를 할당하는 것은
Device 인터페이스를 통해서만 가능하기 때문입니다.
커맨드(Command) 를 생성하는 권한은 오직 Device 인터페이스만이 가지고 있습니다.
( 지난 회를 참고하시기 바랍니다. )

멀티스레드 기반으로 리소스를 로딩하고 있지만,
실제로는 많은 부분이 메인스레드( 여기서는 Render Thread )에 의존하여 작업이 수행되고 있습니다.
리소스를 생성하기 위해서는 반드시 Create, Lock & Unlock 작업이 필요합니다.

< 여기서 잠깐...>
사실 위의 그림의 경우에는 일반적으로 사용되는 구조로 보기 어렵습니다.
그림은 거의 순차적인 처리 구조이기 때문에,
이런 경우라면 굳이 저렇게 사용할 필요가 없습니다.
실제로 많은 게임들은 텍스쳐가 아직 로딩 중이라면,
Default-Material 을 적용해서 폴리곤을 렌더링하도록 구현하기도 합니다.
즉, Render Thread 가 쉴새 없이 계속 커맨드를 생성하는 구조입니다.^^
그리고 위의 예는 간단한 설명을 위한 것입니다.
개발자분들마다 개성 강한 여러 방법들이 존재하시겠죠? ^^

 

 < 간편해진 리소스 관련 커맨드 생성 >

우리가 DirectX 에서 사용하는 대부분의 리소스 작업은 사실 Free Threaded 합니다.
리소스 처리를 위해서 특별한 동기화 처리가 API 레벨에서는 필요하지 않습니다.
( 개발자의 몫입니다. )
그런데 위의 그림처럼 그 동안은 커맨드를 생성해주는 인터페이스가 오직 하나였기 때문에
메인 스레드에 의존해서 처리할 수 밖에 없었습니다.

두번째 시간에 저는 Device와 DeviceContext 에 대해서 설명을 드렸습니다.
기억이 나지 않으시는 분들은 다시 살펴보시기 바랍니다.^^
요약해드리자면, DirectX11 에서는 Free threaded 한 API 와 그렇지 않은 API 들을 분리했습니다.
Free threaded 한 부분에 바로 리소스 처리가 있습니다.
앞서 우리는 Free threaded 의 이점에 대해서 짧게 언급했었습니다.

위의 그림에서,
이제는 Loader therad 는 굳이 메인 스레드( Render thread ) 에 의존하지 않아도,
순차적으로 리소스 관련 커맨드들을 생성시킬 수 있습니다.
커맨드들이 생성되는 순서는 Free threaded 한 경우에는 중요하지 않기 때문에,
빠른 속도로 처리
할 수 있습니다.
특히나, 메인스레드가 별도로 다른 작업을 수행해서 커맨드를 생성시키는 작업이 있다고 해도,
그것과는 별도로 커맨드 생성 작업을 수행할 수 있습니다.
( 커맨드 생성을 위한 대기 시간이 짧아졌다고 할 수 있습니다. )
이로써, 이제는 조금 더 멀티스레딩 형식에 가까워졌다고 할 수 있습니다.

리소스 처리를 이렇게 분리하는 것은
멀티스레드 기반으로 렌더링으로 가는 중요한 기반을 제공
해 주었습니다.

< 다음 회에서는.... >
다음 회부터는 이제 멀티스레드 기반으로 렌더링 관련 커맨드를 생성하는 것을 살펴볼 것입니다.


task group에서의 병렬 작업 취소 - 1  에 이은 두 번째 글입니다.


3. 작업이 취소되었을 때 해야 할 것


취소는 그것을 호출했을 때 즉시 동작하지 않습니다. task group이 취소되면 런타임은 각 task interruption point를 발동하여 런타임을 throw 시켜서 활동중인 task가 취소될 때 내부 예외 형을 잡을 수 있습니다. Concurrency Runtime은 런타임이 언제 interruption point를 호출할지 정의되어 있지 않습니다. 런타임이 취소를 할 때 던지는 예외를 잡아서 처리할 필요가 있습니다.

그래서 만약 task의 처리 시간이 긴 경우는 정기적으로 취소 여부를 확인할 필요가 있습니다.

 

< 리스트 4. >

auto t5 = make_task([&] {

   // Perform work in a loop.

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

   {

      // To reduce overhead, occasionally check for

      // cancelation.

      if ((i%100) == 0)

      {

         if (tg2.is_canceling())

         {

            wcout << L"The task was canceled." << endl;

            break;

         }

      }

 

      // TODO: Perform work here.

   }

});

 

<리스트 4>의 굵게 표시한 코드는 task5가 정기적으로 task group tg2가 취소 되었는지 조사하고 있는 것입니다.

 

<리스트 4>는 명시적으로 task5가 속한 task group tg2가 취소되었는지 조사하고 있는데 만약 해당 task가 속한 task group을 직접적으로 호출하지 않고 취소 여부를 조사하고 싶을 때는 is_current_task_group_canceling() 을 사용합니다.

 

 

4. 병렬 알고리즘에서의 취소

 

task group에서 사용하는 병렬 알고리즘도 위에서 소개한 방법으로 취소할 수 있습니다.

 

< 리스트 5. Task group에서 병렬 알고리즘 사용 >

structured_task_group tg;

 

task_group_status status = tg.run_and_wait([&] {

   parallel_for(0, 100, [&](int i) {

      // Cancel the task when i is 50.

      if (i == 50)

      {

         tg.cancel();

      }

      else

      {

         // TODO: Perform work here.

      }

   });

});

 

// Print the task group status.

wcout << L"The task group status is: ";

switch (status)

{

case not_complete:

   wcout << L"not complete." << endl;

   break;

case completed:

   wcout << L"completed." << endl;

   break;

case canceled:

   wcout << L"canceled." << endl;

   break;

default:

   wcout << L"unknown." << endl;

   break;

}

 

<리스트 5> task group tg task를 넣을 때 병렬 알고리즘을 넣었습니다. 그리고 이번 beta2에 새로 생긴 run_and_wait 멤버를 사용하여 task의 실행이 끝날 때 까지 대기하도록 했습니다(예전에는 run 이후에 wait를 호출해야 했습니다).


물론 cancel이 아닌 예외를 발생 시켜서 취소 시킬 수도 있습니다.


< 리스트 6. 병렬 알고리즘에서 예외를 발생시켜서 취소 시키기 >

try

{

   parallel_for(0, 100, [&](int i) {

      // Throw an exception to cancel the task when i is 50.

      if (i == 50)

      {

         throw i;

      }

      else

      {

         // TODO: Perform work here.

      }

   });

}

catch (int n)

{

   wcout << L"Caught " << n << endl;

}

 

<리스트 6>은 하나의 task만 예외를 발생시키고 있기 때문에 task group의 모든 task를 취소

시키기 위해서는 모든 task에서 예외를 발생시켜야 합니다.

그래서 아래의 <리스트 7>과 같이 전역 변수 flag를 사용합니다.

 

< 리스트 7. 모든 병렬 알고리즘의 task 취소 시키기 >

bool canceled = false;

 

parallel_for(0, 100, [&](int i) {

   // For illustration, set the flag to cancel the task when i is 50.

   if (i == 50)

   {

      canceled = true;

   }

 

   // Perform work if the task is not canceled.

   if (!canceled)

   {

      // TODO: Perform work here.

   }

});

 

 


5. Parallel 작업을 취소를 사용하지 못하는 경우

 

취소 작업은 모든 상황에서 다 사용할 수 있는 것은 아닙니다. 특정 시나리오에서는 사용하지 못할 수가 있습니다. 예를 들면 어떤 task는 활동중인 다른 task에 의해 block이 풀렸지만 아직 시작하기 전에 task group이 최소되어 버리면 계속 시작하지 못하여 결과적으로 애플리케이션이 dead lock 상황에 빠지게 됩니다.




이것으로 task group에서의 병렬 작업의 취소에 대한 것은 마칩니다. 다음에는 Beta2에 드디어 구현된 Concurrency Container에 대해서 설명하겠숩니다.


참고 url
MSDN : http://msdn.microsoft.com/en-us/library/dd984117(VS.100).aspx

task group을 사용하여 복수의 작업을 병렬적으로 처리할 때 모든 작업이 끝나기 전에 작업을 취소 해야 되는 경우가 있을 것입니다. task group에서 이와 같은 취소 처리를 어떻게 하는지 알아보겠습니다.

 

Concurrency Rumtime에 대한 정보는 아직까지는 MSDN을 통해서 주로 얻을 수 있기 때문에 거의 대부분 MSDN에 있는 것을 제가 좀 더 보기 좋고 쉽게 전달할 수 있도록 각색을 하는 정도이니 이미 MSDN에서 보신 분들은 pass 하셔도 괜찮습니다.^^;

 

 

1. 병렬 작업의 tree

 

PPL task group를 사용하여 병렬 작업을 세분화하여 각 작업을 처리합니다. task group에 다른 task group를 넣으면 이것을 부모와 자식으로 tree 구조로 표현할 수 있습니다.

 

< 리스트 1. >

structured_task_group tg1;

 

auto t1 = make_task([&] {

   structured_task_group tg2;

 

   // Create a child task.

   auto t4 = make_task([&] {

      // TODO: Perform work here.

   });

 

   // Create a child task.

   auto t5 = make_task([&] {

      // TODO: Perform work here.

   });

 

   // Run the child tasks and wait for them to finish.

   tg2.run(t4);

   tg2.run(t5);

   tg2.wait();

});

 

// Create a child task.

auto t2 = make_task([&] {

   // TODO: Perform work here.

});

 

// Create a child task.

auto t3 = make_task([&] {

   // TODO: Perform work here.

});

 

// Run the child tasks and wait for them to finish.

tg1.run(t1);

tg1.run(t2);

tg1.run(t3);

 

<리스트 1>에서는 structured_task_group tg2 tg1에 들어가서 tg2 tg1의 자식이 되었습니다. 이것을 tree 그림으로 표현하면 아래와 같습니다.



< 그림 1. >

 

 

2. 병렬 작업의 취소 방법

 

parallel task를 취소할 때는 task group의 cancel 멤버를 사용하면 됩니다(task_group::cancel, structured_task_group::cancel). 또 다른 방법으로는 task에서 예외를 발생시키는 것입니다. 두 가지 방법 중 cancel 멤버를 사용하는 것이 훨씬 더 효율적입니다.


cancel을 사용하는 것을 top-down 방식으로 task group에 속한 모든 task를 취소시킵니다. 예외를 발생 시켜서 취소하는 방법은 bottom-up 방식으로 task group에 있는 각 task에서 예외를 발생시켜서 위로 전파시킵니다.



2.1. cancel을 사용하여 병렬 작업 취소

 

cancel 멤버는 task group canceled 상태로 설정합니다. cancel 멤버를 호출한 이후부터는 task group task를 처리하지 않습니다. task가 취소되면 task group wait에서는 canceled를 반환합니다.

 

cancel 멤버는 자식 task에서만 영향을 끼칩니다. 예를 들면 <그림 1> t4에서 tg2를 cancel하면 tg2에 속한 t4, t5 task만 취소됩니다. 그러나 tg1을 cancel하면 모든 task가 취소됩니다.

 

structured_task_group은 thread 세이프 하지 않기 때문에 자식 task에서 cancel을 호출하면 어떤 행동을 할지 알 수 없습니다. 자식 task cancel로 부모 task를 취소하던가 is_canceling로 취소 여부를 조사할 수 있습니다.

 

< 리스트 2. cancel을 사용하여 취소 >

auto t4 = make_task([&] {

   // Perform work in a loop.

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

   {

      // Call a function to perform work.

      // If the work function fails, cancel all tasks in the tree.

      bool succeeded = work(i);

      if (!succeeded)

      {

         tg1.cancel();

         break;

      }

   }  

});

 


2.2. 예외를 발생시켜 병렬 작업 취소


앞서 cancel 멤버를 사용하는 것 이외에 예외를 발생시켜서 취소 시킬 수 있다고 했습니다. 그리고 이것은 cancel()을 사용하는 것보다 효율이 좋지 않다고 했습니다.

예외를 발생시켜서 취소하는 방법의 예는 아래의 <리스트 3>의 코드를 보시면 됩니다.

 

< 리스트 3. 예외를 발생시켜서 취소 >

structured_task_group tg2;

 

// Create a child task.     

auto t4 = make_task([&] {

   // Perform work in a loop.

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

   {

      // Call a function to perform work.

      // If the work function fails, throw an exception to

      // cancel the parent task.

      bool succeeded = work(i);

      if (!succeeded)

      {

         throw exception("The task failed");

      }

   }        

});

 

// Create a child task.

auto t5 = make_task([&] {

   // TODO: Perform work here.

});

 

// Run the child tasks.

tg2.run(t4);

tg2.run(t5);

 

// Wait for the tasks to finish. The runtime marshals any exception

// that occurs to the call to wait.

try

{

   tg2.wait();

}

catch (const exception& e)

{

   wcout << e.what() << endl;

}

 

task_group이 structured_task_group wait는 예외가 발생했을 때는 반환 값을 표시하지 못합니다. 그래서 <리스트 3>의 아래 부분에서 try-catch에서 exception을 통해서 상태를 표시하고 있습니다.




아직 이야기가 다 끝난 것이 아닙니다. 나머지는 다음 글을 통해서 설명하겠습니다.^^



참고 url

MSDN : http://msdn.microsoft.com/en-us/library/dd984117(VS.100).aspx


[JumpToDX11-6] 커맨드(Command)...

DirectX 11 2009. 11. 9. 15:00 Posted by 알 수 없는 사용자


앞서 제 개인적인 판단에 DirectX11 의 큰 특징을 3가지 언급했었습니다.
( 테셀레이션, Compute Shader, Multi-threaded-rendering )
저는 이 세가지 중에서 멀티스레드 기반의 렌더링에 대해서
앞으로의 시간동안 글을 전개해 나갈 생각입니다.


< 커맨드를 생성하는 일 >


혹시 '커맨드(Command)' 라는 개념에 대해서 기억이 나시나요?
기억이 나지 않으신다면,
 [JumpToDX11-2]DeviceContext...넌 누구냣!! 편을 다시 읽어보시기 바랍니다.
요약을 해보자면,
API 를 통한 호출은 결국 하드웨어가 인식할 수 있는 커맨드 형태로 전달되어지게 됩니다.



지난 세대의 DirectX 는 이 모든 처리를 하나의 인터페이스를 통해서 처리했었습니다.
즉, 커맨드를 생성할 수 있는 인터페이스가 오직 하나였습니다.
그리고 그렇게 저장된 커맨드들을 그래픽카드는 순차적으로 실행만 합니다.

이를 멀티스레드 기반으로 처리하기 위해서는 사실 굉장한 노력을 해야합니다.
더 어려운 것은 멀티스레드 기반으로 처리 노력을 기울인다고 해도,
성능 향상에 대한 보장은 장담할 수 없습니다.
일반적으로 로직처리는 멀티스레드 기반으로 분산해서 처리하고는 있지만,
렌더링과 관련된 부분은 이러한 처리가 굉장히 어렵습니다.
( 렌더 스레드의 실행 중간에 렌더링 스테이트가 변하면 문제가 크겠죠? )

그래서 지난 세대의 DirectX 는 이러한 커맨드를 생성하는 부분은
단, 하나의 경로를 통해서만 가능했습니다.
그 동안 우리가 사용했던 IDirect3DDevice9 같은 인터페이스가 바로 이러한 역활을 했었습니다.
이 인터페이스는 실제로 API 를 통해서 하드웨어에게 명령 수행을 지시한다는 의미보다는,
API 를 하드웨어가 이해할 수 있는 커맨드로 변환해 주는 것에 더 가깝습니다.
그리고 그 커맨드를 통해서, 실제로 하드웨어가 실행
을 할 것입니다.

그런데 바로 이 커맨드를 생성하는 일, 누가 해주는 것일까요?
하드웨어가 이해할 수 있는 커맨드들은 드라이버( Driver )가 알고 있습니다.
드라이버는 Core API 나 런타임과 통신을 합니다.

"텍스쳐를 로딩해주세요~"
"메모리를 생성해주세요~"
"렌더링 스테이트를 설정해 주세요~"
"비디오 메모리에 리소스를 바인딩 시켜주세요~"

뭐 이런 식으로 API 를 사용하면,
이들과 관련된 커맨드를 생성하기 위해서 누군가 바쁘게 움직여줘야 할 것입니다.
그것은 바로 'CPU'
겠죠?

실제로 우리가 생성하는 커맨드들 이외에도 처리에 필요하면 커맨드가 더 많이 생성될 수도 있습니다.
예를 들면, 비디오 메모리가 가득찬 상태에서 어떤 리소스를 로드한다면
상황에 맞게 특정 리소스를 비디오 메모리에서 제거해야 합니다.
결국 커맨드들의 실행 중간에,
DirectX 의 리소스 매니져에 이를 요구할 수 있는 커맨드들이 생겨져서 더 붙여질 수도 있습니다.
만약 이런 경우라면, 처리 시간이 더 길어지게 되며,
뒤에 있는 커맨드들의 대기시간도 더 길어지게 됩니다.
전체적으로 작업 시간이 지연되는 것이죠.



< 멀티코어의 시대 >

바야흐로 멀티코어시대의 시대입니다.
이제는 CPU 의 성능적인 발전은 정체되었고,
PC 에 탑재되는 CPU 의 갯수가 성능을 좌우하는 시대입니다.

지금까지의 DirectX 는 싱글코어 기반으로 설계되었다고 지난 회에 언급했었습니다.
CPU 의 성능 발전이 지속적으로 상승 곡선을 그렸다면,
아마 렌더링을 멀티스레드로 할 위험(?)은 피할 수 있었을지도 모릅니다.^^

그 동안 DirectX 팀이 최적화 작업을 한다는 것은
API 호출에 대한 오버헤드를 줄이는 것이 가장 큰 일 중에 하나였습니다.
되도록이면 적은 CPU 사이클을 통해서 커맨드를 실행하게 하려고,
정말이지 많은 노력들을 해왔습니다.

그런데 CPU 가 여러개 탑재되고, GPU 가 발전하면서
놀고 있는 CPU 가 생겨나기 시작했고,
GPU 도 많은 시간을 놀면서 지내기 시작했습니다.
그래서 이들에 대한 활용에 대안으로 등장한 것이 바로
멀티 스레드 기반의 렌더링 작업과 Compute Shader 입니다.
멀티스레드 기반의 렌더링은 CPU 에게 렌더링 작업을 분산시키는 것이고,
Compute Shader 는 GPU 를 CPU 처럼 활용하는 것입니다.

제가 앞으로 언급할 것이 바로 멀티스레드 기반으로 렌더링하는 것입니다.
즉, CPU를 활용하는 것으로 볼 수 있습니다.
앞서 렌더링을 멀티스레드로 하는 것은 굉장히 위험한 일이라고 제가 언급했었는데,
이것이 어떻게 가능하냐구요?
네, 맞습니다.
사실 이것은 틀린 말입니다.
정확히는 커맨드를 멀티스레드 기반으로 생성하는 것이 
바로 멀티스레드 기반의 렌더링의 핵심
입니다.


< 다음 회에는... >
이번 시간에 커맨드에 대한 개념을 확실히 잡으셨는지 모르겠습니다.
다음 회 부터는 멀티스레드여서 행복(?)한 부분들을 하나씩 살펴보겠습니다.^^


 

[JumpToDX11-5] 새로운 시대를 여는 DirectX11...

DirectX 11 2009. 11. 2. 15:00 Posted by 알 수 없는 사용자


한주만 쉰다는 것이, 죄송스럽게도 긴 휴식을 가지고 다시 등장습니다.
지난 시간까지 DirectX11 의 기본 API 를 간단히 언급했었습니다.
쉬는 사이에 안승근님께서 DirectX11과 관련된 기본적인 API 에 대한 글을 작성하기 시작하셨기 때문에
앞으로 기본적인 API 위주로 내용을 언급하지 않습니다.


< DirectX9 까지의 특징 >

DirectX는 Windows95 운영체제와 함께 처음 공개된 후에, 
어느덧 현세대까지 발전을 거듭했습니다.( 세월 참 빠르죠? ^^ )

너무 오랜 시간 전은 저도 잘 몰라서 DirectX7 버전부터의 가장 큰 변화를 하나씩 언급해 보겠습니다.
DirectX7 버전부터 변환과 라이팅(T&L) 을 위한 GPU가 활용되기 시작했고,
DirectX8 버전부터는 'Shader' 라는 GPU 를 활용한 프로그래밍이 도입되어서
현재 가장 개발자에게 주목받는 영역이 되었습니다.
개인적인 견해차이가 있겠지만, 저는 DirectX9 까지의 발전 과정 중에
가장 큰 변화로 바로 이 'GPU 의 활용'
이라고 생각하고 있습니다.

그러면 DirectX9 까지의 발전에서 변심(?)하지 않고,
저희를 언제나 반갑게(?) 맞이해 주었던 부분은 어떤 것이 있을까요? ^^
그것은 바로 API 를 설계할 때 항상 싱글 코어를 고려하고 만들었다는 것입니다.

또 다른 부분은 API 자체가 GPU 의 정점 처리 기능을 규정하고 있다는 것입니다.
언제나 '정점입력-->래스터라이즈-->픽셀처리-->디스플레이' 라는 큰 단계를
API 레벨에서 정의하고 있었습니다.
그 동안 우리는 이것은 Fixed pipeline 이라고 불렀습니다.
아래 이미지는 DirectX8 & 9 의 파이프라인입니다.



이미지 출처 : http://pc.watch.impress.co.jp/docs/column/kaigai/20090804_306876.html

사실 DirectX8 & 9 는 크게 차이가 없습니다.
파이프라인상에서 굳이 찾아야 한다면, 텍스쳐 메모리를 버텍스 쉐이더 단계에서도
참조할 수 있다는 정도일 뿐입니다.

간단히 제가 하고 싶은 말을 정리해 보자면,
'싱글코어 기반의 DirectX 의 시대는 이제 역사의 뒤로 사라지게 될 것이며,
GPU 는 더욱 복잡한 기능을 요구하게 될 것이다'
정도로 정리하겠습니다.
( 예언은 아니고, 이미 이렇게 되고 있는 상황이죠..^^ )


< 새로운 시대를 여는 DirectX11 >

아래는 DirectX11 의 파이프라인입니다.
잘 보시라고 그냥 크게 띄웁니다..^^


이미지 출처 : http://pc.watch.impress.co.jp/docs/column/kaigai/20090804_306876.html


DirectX11 의 가장 큰 특징을 저는 크게 3가지로 나누어 보았습니다.
  • GPU Tessellation.
  • Compute Shader.
  • Multi-threaded rendering.

사실 DirectX11 의 많은 부분은 X-Box360 에서 이미 사용되고 있습니다.
X-Box360 의 ComputeShader 지원은 모르겠으나, 나머지 두가지는 지원하고 있습니다.
X-360을 언급한 이유는 이들 기능이 이미 어느 정도 검증을 받은 기능이라는 점을 강조하고 싶어서 입니다.
( 물론 최신 버전이기 때문에 더 빨라지고, 더 좋아진 부분이 많습니다.^^ )

DirectX11 의 큰 패러다임은 '놀지마' 입니다.
이제는 멀티코어(CPU)와 GPU에게 최대한 많은 일을 시킬 수 있는 구조로
하드웨어를 구성했고, 그것을 기반으로 해서 런타임과 API 를 설계
하고 만들었습니다.

DirectX9 까지는 API 가 변화를 주도했다면,
이제는 DirectX API 변화를 하드웨어가 주도하고 있다고 볼 수 있습니다.
그러다보니 자연스럽게 API 도 더욱 하드웨어에 가깝게 설계되었습니다.
대표적으로 OutputMerge 를 지칭하는 OMxxxx 계열과
InputAssembler 를 지칭하는 IAxxxx 계열 등이 있습니다.

혹시 DirectX8-->9 로 포팅 작업을 하셨던 분들이 이 글을 읽으시는지 모르겠습니다만,
8-->9 의 변화는 API 차원에서 변화가 컸기 때문에 매우 단순했습니다.
하지만 이제는 하드웨어가 크게 변했기 때문에,
단순 포팅 작업 정도로 생각하시면 큰 오산입니다.
물론 단순히 API 만 교체해도 성능 향상을 얻을 수 있습니다.
DirectX11 은 하드웨어 오버헤드를 줄이기 위해 많은 최적화 작업을 수행했다고 합니다.

새로운 DirectX 의 시대가 왔다는 느낌이 드시나요? ^^

'DirectX 11' 카테고리의 다른 글

[DX11_#4]텍스트, 버튼 출력  (0) 2009.11.10
[JumpToDX11-6] 커맨드(Command)...  (0) 2009.11.09
[DX11_#3]기본적인 설정  (0) 2009.10.22
[DX11_#2]D3D Buffer( 2 / 2 )  (0) 2009.10.13
[DX11_#1]D3D Buffer( 1 / 2 )  (0) 2009.09.22

Parallel Patterns Library(PPL) - combinable

VC++ 10 Concurrency Runtime 2009. 10. 28. 08:30 Posted by 알 수 없는 사용자

PPL에서 제공하는 알고리즘을 사용하여 병렬로 작업을 실행할 때 각 작업에서 접근하는 공유 리소스는 스레드 세이프 하지 않기 때문에 lock을 걸어서 공유 리소스를 보호해야 합니다.

 

그러나 lock을 건다는 것은 번거롭기도 하며 성능에 좋지 않은 영향을 미칩니다.

가장 좋은 방법은 공유 리소스에 lock을 걸지 않아도 스레드 세이프한 것이 가장 좋습니다.

 

combinable은 바로 위에 언급한 문제를 해결해 주는 것입니다. 모든 상황에 다 사용할 수 있는 것은 아니지만 특정 상황에서는 combinable을 사용하면 lock을 걸지 않아도 공유 리소스를 스레드 세이프하게 접근 할 수 있습니다.

 

 

combinable

combinable은 병렬로 처리하는 작업에서 각 작업마다 계산을 실행한 후 그 계산 결과를 통합할 때 사용하는 재 사용 가능한 스레드 로컬 스트레지를 제공합니다.

 

combinable은 복수의 스레드 또는 태스크 간에 공유 리소스가 있는 경우에 사용하면 편리합니다. combinable는 공유 리소스의 접근을 각 스레드 별로 제공하여 공유 상태를 제거할 수 있습니다.

 


스레드 로컬 스트리지

스레드 프로그래밍을 공부하시면 스레드 고유의 로컬 스트리지를 만들어서 해당 스레드는 자신의 로컬 스트리지에 읽기,쓰기를 하여 다른 스레드와의 경합을 피하는 방법을 배울 수 있습니다.

combinable은 이 스레드 로컬 스트리지와 비슷한 방법입니다.

 

 

combinable의 메소드 설명

combinable::local : 현재 스레드 컨텍스트와 관련된 로컬 변수의 참조를 얻는다.

combinable::clear : 오브젝트로부터 모든 스레드 로컬 변수를 삭제한다.

combinable::combine : 제공하고 있는 있는 조합 함수를 사용하여 모드 스레드 로컬 계산의 set으로부터 최종적인 값을 만든다.

combinable::combinable_each ; 제공하고 있는 조합 함수를 사용하여 모든 스레드 로컬 계산의 set으로부터 최종적인 값을 만든다.

 

 

combinable은 최종 결합 결과 타입의 파라미터를 가지고 있는 템플릿 클래스입니다. 기본 생성자를 호출하면 기본 생성자와 복사 생성자 _Ty 템플릿 파라미터 형이 꼭 있어야합니다. _Ty 템플릿 파라미터 형이 기본 생성자를 가지지 않는 경우 파라미터로 초기화 함수를 사용하는 생성자로 오버로드 되어 있는 것을 호출합니다.

 

combinable을 사용하여 모든 작업에서 처리한 계산 결과 값을 얻을 때는 combine()을 사용하여 합계를 구하던가, combine_each를 사용하여 각 작업에서 계산한 값을 하나씩 호출하여 계산합니다.

 

< 예제 1. Combinable을 사용하지 않고 lock을 사용할 때 >

……

int TotalItemPrice1 = 0;

critical_section rt;

parallel_for( 1, 10000, [&]( int n ) {

                     rt.lock();

                     TotalItemPrice += n;

                     rt.unlock();

                     }         

);

………


<예제 1>critical_section을 사용하여 TotalItemPrice 변수를 보호하고 있습니다.

그럼 <예제 1> combunable을 사용하여 구현해 보겠습니다.

 

< 예제 2. Combinable 사용 >

#include <ppl.h>

#include <iostream>

 

using namespace Concurrency;

using namespace std;

 

 

int main()

{

           combinable<int> ItemPriceSum;

           parallel_for( 1, 10000, [&]( int n ) {

                                ItemPriceSum.local() += n;

                                }         

                     );

 

           int TotalItemPrice = ItemPriceSum.combine( [](int left, int right) {

                                          return left + right;}

                                );

 

           cout << "TotalItemPrice : " << TotalItemPrice << endl;

          

          

           getchar();

           return 0;

}

 

combinable을 사용하면 <예제 1>과 다르게 lock을 걸지 않아도 되기 때문에 훨씬 성능이 더 좋습니다. 다만 모든 곳에서 사용할 수는 없기 때문에 <예제 2>와 같이 어떤 계산의 최종 결과를 구할 때 등 사용할 수 있는 곳을 잘 찾아서 사용해야 합니다.

 

<예제 2>는 각 태스크에서 계산된 결과를 더하기 위해서 conbinablecombine 멤버를 사용했지만 각 태스크의 결과를 하나씩 순회할 때는 conbinablecombine _each 멤버를 사용합니다.

그리고 저는 <예제 2>에서 int combinable에 사용했지만 int 이외에 유저 정의형이나 STL list와 같은 컨테이너도 사용할 수 있습니다.

 


combinable에서 combine_each() 멤버나 combinable에서 STL list 컨테이너를 사용한 MSDN에 있는 예제는 아래와 같습니다.

#include <ppl.h>

#include <vector>

#include <list>

#include <algorithm>

#include <iostream>

 

using namespace std;

using namespace Concurrency;

 

int main()

{

   // Create a vector object that contains the values 1 through 10.

   vector<int> values(10);

  

   int n = 0;

   generate(values.begin(), values.end(), [&] { return ++n; } );

 

   // Generate the list of odd elements of the vector in parallel

   // by using the parallel_for_each algorithm and a combinable object.

   combinable<list<int>> odds;

   parallel_for_each(values.begin(), values.end(), [&](int n) {

         if (n % 2 == 1)

            odds.local().push_back(n);

       });

 

   // Combine all thread-local elements into the final result.

   list<int> result;

   odds.combine_each([&](list<int>& local) {

           // Merge the local list into the result so that the results

           // are in numerical order.

           local.sort(less<int>());

           result.merge(local, less<int>());

        });

 

   // Print the result.

   cout << "The odd elements of the vector are:";

   for_each(result.begin(), result.end(), [](int n) {

          cout << ' ' << n;

        });

}


VS2010 베타2의 WPF & Silverlight 디자이너 성능 향상 팁

Visual Studio 2010 2009. 10. 28. 00:00 Posted by 알 수 없는 사용자
Visual Studio 2010 베타2에서는 WPF와 Silverlight 개발을 위한 디자이너(코드네임 Cider) IDE가 많이 향상되었습니다. VS2010 베타1에서 특히 사용하기 불편 했던 점이 성능에 관한 문제였는데 베타2에서는 불편함 없이 사용이 가능합니다.

Channel 9의 VS2010 베타2의 Cider 디자이너 소개 동영상을 보시면 성능을 더욱 향상 시킬 수 있는 팁이 소개됩니다. VS2010 베타2가 개발 되는 중에 늦게 발견되어 베타2에는 포함되지 못했다고 하는데 최종 릴리즈 때는 따로 수정이 불필요 하도록 포함된다고 합니다.

간단하게 레지스트리에 키를 추가 해주는 방법으로 성능 향상이 이루어 진다고 하는데 방법은 다음과 같습니다.
※ 레지스트리 수정은 시스템에 큰 영향을 줄 수 있으니 주의 바랍니다.

1. 먼저 VS가 실행 중이라면 모두 종료합니다.
2. regedit 명령으로 레지스트리 편집기를 엽니다.
3. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\10.0 키를 선택합니다.
4. 마우스 오른쪽 버튼을 클릭하고 "새로만들기 - 키"를 선택하고 ClrHost라는 이름을 줍니다.
5. 새로 추가한 키에서 다시 마우스 오른쪽 버튼을 눌러 DWORD32 값을 StartupFlags 이름으로 추가합니다.
6. 값은 5로 해줍니다.
7. 레지스트리 편집기를 종료합니다.
8. 이제 모든 수정이 완료되었고 평소처럼 VS를 사용하면 됩니다.

실제로 어느정도 성능이 향상되는지는 알 수 없으나 강력히 추천하고 있으니 꼭 적용시켜서 사용하시길 바랍니다.

Welcome to dynamic C# 외전(1) - Generate From Usage.

C# 2009. 10. 25. 09:00 Posted by 알 수 없는 사용자

- 베타2를 맞이하여.

비주얼스튜디오 2010 베타2가 드디어 나왔습니다. 모양도 초큼더 이뻐진거 같구요, 이제 슬슬 제품이 출시될거 같다는 느낌도 드는 군요. 제가 처음 비주얼 스튜디오를 접한게 비주얼스튜디오2002 베타2 버전이었는데요, 왠지 향수가 느껴지네요.-_-;;; 이번 포스트에서는 TDD의 대세를 따라서 코딩을 좀더 편리하게 해주는 기능하나를 소개해드리려 합니다.


- 이름하여 Generate From Usage!

모 이름은 '사용하는 모냥을 봐서 생성하겠다'정도가 되겠네요. 2008까지는 TDD방식으로 개발을 한다고 해도, 클래스등을 미리 만들어 놓고, 메서드 수준에 가서야 메서드 스텁은 생성하면서 TDD방식을 적용할 수 있었습니다. 물론, 편리한 툴의 지원을 받는 면에서 말이죠. 그런데 2010 베타2 부터는 TDD를 편리하게 할 수 있도록 좀 더 멋진기능이 지원됩니다. 한번 살펴보시져!


예들 들어서, Test123이라는 클래스를 TDD로 만들려고 합니다. 그러면, Test123은 당연히 현재 존재하지 않는 클래스이겠죠? TDD가 일반적으로 시나리오를 기반으로 테스트케이스를 먼저 만들고, 그 테스트를 통과하도록 구체적으로 코드를 작성해나가는 방식이니까요. 약간 귀찮은 문제가 여기서 발생합니다. 실제로 TDD를 해보면, 테스트 코드를 작성할때 대상이 되는 클래스를 열심히 타이핑하는데, 기존에 없는 클래스기 때문에 당연히 인텔리센스의 지원이 안되서 날코딩을 해야 하는거죠. 그래서 귀찮으니깐 없는 클래스를 껍데기만 미리 작성해놓고, 인텔리센스의 지원을 받습니다. 그리고 VS2008에서는 스텁생성이 메서드레벨에서만 지원됐기 때문에, 클래스를 선언해놔야 좀더 편리하기 때문이죠.

근데, 만약에 존재하지 않는 클래스라도 인텔리센스의 지원을 받을 수 있다면? 그리고 그 클래스의 스텁을 생성해줌과 동시에, 클래스 파일까지도 생성을 해준다면? 그리고 드라군이 출동한다면?? ........ 아무튼 *라게 많이 편하겠죠?

<그림1>을 보시면, 이런 멋진 기능이 이제 현실로 다가왔음을 느끼실 수 있습니다. 분명히 Test123은 없는 클래스니깐, 빨간 밑줄이 그어졌는데, new뒤에 나오는 인텔리센스에는 Test123이 버젓이 들어가 있습니다!!!



<그림1>버젓이 들어가 있다!!!!


인텔리센스에 버젓이 들어가 있었지만, 아직 정의안된 클래스니깐 <그림2>처럼 에러메세지가 나오는걸 보실 수 있습니다.


<그림2>클래스정의가 엄서요!!


하지만, 예전버전에서 없는메서드에 마우스 오른쪽 버튼을 눌러서 메서드 스텁을 생성했듯이, Test123위에 마우스를 놓고 오른쪽 버튼을 눌러보면, <그림3>처럼 클래스를 생성하는 옵션이 있습니다.



<그림3>참으로 착한 옵션이로닭!!!


그리고 결과를 보면, <그림4>처럼 Test123.cs라는 파일이 생성되었고, <그림5>처럼 껍데기가 작성된 걸 보실 수 있습니다!



<그림4>조...좋은 생성이다1



<그림5>조...좋은 생성이다2

그리고 이번엔, 없는 프로퍼티를 하나 써볼까요? <그림6>처럼 아직 정의가 안된 프로퍼티를 갖다쓰면, 어쩌구 저쩌구 하고 컴파일러가 불평을 합니다.



<그림6>어쩌구 저쩌구...


그러면, 클래스와 같이 오른쪽 버튼을 지그시 눌러주면, <그림7>처럼 필드나 프로퍼티로 생성을 할 수 있습니다. 프로퍼티를 눌러보면 <그림8>과 같이 프로퍼티가 하나 추가된걸 보실 수 있죠.



<그림7>프로퍼티 하나 추가여.



<그림8>조...좋은 생성이다3


- 마치면서

VS2008에서 TDD를 아주 허접하게 해본 경험으로 미뤄볼때, 확실히 좀더 잔손질을 줄여주는 기능이 될 거 같습니다. 뭐 꼭 TDD가 아니더라도 기능을 활용할 일은 많은 거라는 생각이 드네요. 전 이래서 비주얼 스튜디오가 좋습니다. ㅋㅋㅋ....-_-;;;

VS 2010 Beta 2 설치 과정에서 Silverlight SDK 문제

Visual Studio 2010 2009. 10. 22. 11:00 Posted by 알 수 없는 사용자

기존에 Visual Studio 2008에서 Silverlight 3 SDK를 설치하여 사용 하시던 분들 중에
Visual Studio 2010 Beta 2를 설치 할 때 Silverlight SDK에서 에러가 나는 경우가 있습니다.

Silverlight 3 SDK가 초기에 배포된 이후 마이너 업데이트 되어 GDR 버전이 나왔는데
VS2010 설치를 할 때 같이 설치되는 Silverlight 3 SDK 버전은 최신 버전(GDR)입니다.

VS 2010 Beta 2에서는 최신 버전을 자동으로 설치하지 않고 설치 과정에서 에러를 표시하게 되는데
이 문제는 RTM에서는 해결 될 예정이라고 합니다.

초기 버전의 Silverlight 3 SDK를 사용 하시던 경우에는 먼저 삭제를 하고 Visual Studio 2010 Beta 2를
설치하시면 에러 없이 깔끔하게 설치가 완료 될 것입니다.

그러나 이미 설치 한 경우도 Visual Studio 2010 Beta 2 사용에는 문제가 없고
단지 Silverlight 3 SDK 버전 문제로 에러가 나는 것입니다.

최신 버전의 Silverlight 3 SDK를 사용하기 위해선 Silverlight 3 SDK를 삭제하고
최신 버전인 GDR 버전으로 다시 설치 해 주면 됩니다.

여기에서 Silverlight 3 SDK GDR 버전의 다운로드가 가능합니다.

우선 설치해서 잠깐 둘러본 결과, 가장 우려했던 IDE 의 성능 문제는 의외로 빨랐습니다. 어떤 부분은 Visual Studio 2008 보다 더 빨랐고, 기본적인 대부분의 동작의 실행 속도는 굉장히 만족스럽습니다.

마이크로소프트 Visual Studio 개발팀도 이 점을 인지하고 개선하려고 상당히 노력한 흔적이 엿보입니다. 기존 CTP 와 Beta 1 에서 기어가는 듯한 IDE 가 느렸던 문제는, Beta 2 버전에서는 걱정하지 않으셔도 될 것 같습니다. 체감적으로 Visual Studio 2008 보다 느리지 않네요.  

Visual Studio CTP 와 Beta 버전에 익숙해졌는지 외관상 크게 거부감도 없습니다. 

   

설치된 구성 요소 검색하는 화면

   

라이선스 동의 화면

   

설치 패키지 선택 화면

   

설치 시작 화면

   

설치되는 구성 요소 목록

   

   

   

   

.NET Framework Beta 2 가 설치 된 후 시스템 재시작이 필요합니다.

   

   

Visual Studio 2010 Beta 2 의 Splash 화면

   

   

Visual Studio 시작 페이지 화면

   

Visual Studio 2010 Beta 2 출시

Visual Studio 2010 2009. 10. 20. 10:06 Posted by POWERUMC

미국 시간으로 2009년 10월 19일, Visual Studio 2010 Beta 2 버전이 공개가 되었습니다. MSDN 을 통해 Beta 2 버전을 다운로드 받으실 수 있습니다.

다운로드
http://msdn.microsoft.com/en-us/vstudio/dd582936.aspx

 

그간 Visual Studio 2010 CTP/Beta 버전에서 보여주었던 약간의 성능적인 문제는 이번 Beta 2 버전에서 상당히 많이 개선이 되었다고 합니다.

특히 이번 Beta 2 버전부터는 제품 라인이 전체적으로 변경되었습니다. 기존의 Professional 제품을 제외한 모든 제품의 라인이 변경이 됩니다. 다운로드 받으실 때 혼란이 없으시길 ^_^

더불어 Expression 제품 군도 두 개의 제품으로 나뉘어지게 될 것입니다.

기존 제품

Beta 2 부터 적용되는 제품

Visual Studio Team Suite

Visual Studio Ultimate

Visual Studio Test Edition
Visual Studio Database Edition
Visual Studio Architecture Edition Visual Studio Development Edition

Visual Studio Premium

Visual Studio Professional

Visual Studio Professional

아래는 변경된 MSDN 로고 입니다. ^_^

   

Parallel Patterns Library(PPL) - parallel_invoke

VC++ 10 Concurrency Runtime 2009. 10. 20. 08:30 Posted by 알 수 없는 사용자

parallel_invoke는 일련의 태스크를 병렬로 실행할 때 사용합니다. 그리고 모든 태스크가 끝날 때까지 대기합니다. 이 알고리즘은 복수의 독립된 태스크를 실행할 때 유용합니다.

 

일련의 태스크를 병렬로 실행할 때 사용이라는 것을 들었을 때 생각나는 것이 없는가요? 지금까지 제가 올렸던 글을 보셨던 분이라면 parallel task라는 말이 나와야 합니다. ^^

parallel_invoke parallel task와 비슷합니다.

 

 

parallel_invoke parallel task의 다른 점

복수 개의 태스크를 병렬로 실행한다는 것은 둘 다 같지만 아래와 같은 차이점이 있습니다.


 

parallel_invoke

parallel task

편이성

작업 함수만 정의하면 된다.

작업 함수를 만든 후 task handle로 관리해야 한다.

태스크 개수

10개 이하만 가능

제한 없음

모든 태스크의 종료 시 대기

무조건 모든 태스크가 끝날 때까지 대기

Wait를 사용하지 않으면 대기 하지 않는다.



parallel_invoke를 사용할 때

병렬로 실행할 태스크의 개수가 10개 이하이고, 모든 태스크가 종료 할 때까지 대기해도 상관 없는 경우에는 간단하게 사용할 수 있는 parallel_invoke를 사용하는 것이 좋습니다. 하지만 반대로 병렬로 실행할 태스크가 10개를 넘고 모든 태스크의 종료를 대기하지 않아야 할 때는 parallel task를 사용해야 합니다.

 

 

parallel_invoke 사용 방법

parallel_invoke는 병렬로 태스크를 두 개만 실행하는 것에서 10개까지 실행하는 9개의 버전이 있으며 파라미터를 두 개만 사용하는 것에서 10개의 파라미터를 사용하는 것으로 오버로드 되어 있습니다.

각 오버로드된 버전의 파라미터에는 태스크를 정의한 작업 함수를 넘겨야 합니다.

 

 

parallel_invoke 사용 예

아래 예제는 아주 간단한 것으로 게임 프로그램이 처음 실행할 때 각종 파일을 로딩하는 것을 아주 간략화 하여 parallel_invoke를 사용한 예입니다.

 

#include <iostream>

#include <ctime>

#include <windows.h>

#include <concrt.h>

#include <concrtrm.h>

using namespace std;

 

#include <ppl.h>

using namespace Concurrency;

 

// UI 이미지 로딩

void LoadUIImage()

{

           Sleep(1000);

           cout << "Load Complete UI Image" << endl;

}

 

// 텍스쳐 로딩

void LoadTexture()

{

           Sleep(1000);

           cout << "Load Complete Texture" << endl;

}

 

// 폰트 파일 로딩

void LoadFont()

{

           Sleep(1000);

           cout << "Load Complete Font" << endl;

}

 

int main()

{

           parallel_invoke( [] { LoadUIImage(); },

                      [] { LoadTexture(); },

                      [] { LoadFont(); }

                    );

          

           getchar();

           return 0;

}

 

< 실행 결과 >



위 예제를 parallel_invoke를 사용하지 않고 전통적인 방법으로 순서대로 실행했다면 각 작업 함수에서 1초씩 소비하므로 3초가 걸리지만 parallel_invoke를 사용하여 1초만에 끝납니다.

 

그리고 이전에 parallel_for에서도 이야기 했듯이 병렬로 실행할 때는 순서가 지켜지지 않는다는 것을 꼭 유의하시기 바랍니다. 위의 예의 경우도 LoadUIImage()을 첫 번째 파라미터로 넘겼지만 실행 결과를 보면 LoadFont()가 먼저 완료 되었습니다.

 


마지막으로 위의 예제코드에서 parallel_invoke와 관계 있는 부분만 추려볼 테니 확실하게 사용 방법을 외우시기를 바랍니다.^^

 

#include <ppl.h>

using namespace Concurrency;

 

// 태스크 정의

void LoadUIImage()

{

............

}

 

void LoadTexture()

{

............

}

 

void LoadFont()

{

............

}

 

int main()

{

        parallel_invoke( [] { LoadUIImage(); },

                                 [] { LoadTexture(); },

                                 [] { LoadFont(); }

                          );

 

}


About Visual C++ 10

Visual C++ 10 2009. 10. 15. 08:30 Posted by 알 수 없는 사용자

지난 10 7일에서 9일까지 서울 코엑스에서 ‘KGC 2009’ 라는 게임 개발 컨퍼런스가 열렸습니다.

저는 여기서 ‘Visual C++ 10’에 대해서 강연을 했습니다.

 

이번 버전 10은 이전에 비해서 변화한 부분이 많아서 가장 큰 핵심인 ‘C++0x’‘Parallel’부분만 주제를 잡았는데도 시간 부족상 다 하지는 못했습니다.

 

아직 VSTS 2010 Beta1을 설치하지 않은 분들도 많으실 것 같아서 Demo까지 하려니 도저히 시간이 남지 않더군요.

 

이번에 제대로 하지 못한 ‘Parallel’ 부분은 꼭 다음에 기회가 되는대로 강연을 하도록 하겠습니다.^^





ps : 근래 바빠서 블로그에 포스팅을 하지 못했는데 곧 새로운 글을 올리겠습니다.



이전에 MousePresentationTracker 를 예제로 만들어서 공개한 적이 있습니다. 몇 번 사용해 보면서 Visual Studio 2010 의 새로운 확장 모델인 VSIX 에서는 좀 사소한 버그가 있었습니다. 이 문제 때문에 심히 불편했습니다만, 정식 버전에서는 반드시 고쳐지길 바랄 뿐입니다. ^_^;

문제는 VSIX 의 어셈블리명(DLL) 이 Umc.Core.Tools.MousePresentationTracker.dll 처럼 '.' 이 들어가면 Visual Studio 2010 이 제대로 로드하지 못합니다. 그렇기 때문에 아래와 같이 Assembly Name 은 반드시 "파일명.확장자" 와 같은 이름을 주어야 합니다.

 

기타 확장 기능 참고 

 

안녕하세요. VSTS 2010 공식 팀에서 Twitter 를 시작했습니다. Twitter 를 통해 차마 시간이 없어 정리하지 못한 정보나 알아두면 좋은 팁과 정보 등을 단문 메시지로 여러분들에게 전달해 드릴 예정입니다.

차세대 플랫폼인 Visual Studio / Team System 2010 등 관심 있는 분들의 많은 Following 을 부탁 드립니다.

http://twitter.com/vsts2010

   

 

- 이번엔 웹디자이너와 배포에 대해서

부족한 번역이지만, 이번엔 웹 디자이너와 배포에 대해서 적어볼까 합니다.


- Visual Studio 2010 Web Designer Improvement

 

Visual Studio 2010의 웹페이지 디자이너는 더 뛰어난 CSS 호환성, HTML ASP.NET 마크업의 코드조각에 대한 추가적인 지원과 Jscript를 위해서 다시 디자인된 인텔리센스등으로 더 향상된 기능을 제공합니다.

 

 

- Improved CSS Compatibility

 

Visual Studio 2010 Visual Web Developer 디자이너는 CSS 2.1 표준과 호환되는데요. 이 디자이너는 HTML 소스와의 통합성을 높이면서 기존의 버전의 Visual Studio보다 전체적으로 더 견고한 기능을 제공합니다. 내부적으로는 앞으로 추가될 렌더링, 레이아웃, 사용성 및 유지보수를 위한 설계적인 측면에서의 향상도 있었습니다.

 

 

- HTML and Jscript Snippets

 

HTML에디터는 인텔리센스를 이용해서 태크이름을 자동완성합니다. 그리고 인텔리센스의 코드조각 기능이 전체 태그와 기타 부분을 완성합니다. VisualStudio 2010에서는 인텔리센스의 코드조각 가능이 C# Visual Basic에 적용되었던 것 처럼 Jscript에 대해서도 지원될 것입니다.

 

VisualStudio 2010에는 200개 이상의 코드조각이 ASP.NET HTML의 일반적인 태그와 필요한 속성(runat=”server” 같은)과 특정 태그들에 공통적인 속성들(ID, DataSourceID, ControlToValidate, Text같은)의 자동완성을 도와줍니다.

 

추가적인 코드조각들을 다운받을 수 있으며, 팀의 공동작업이나 개인작업에 공통으로 쓰이는 마크업의 블록을 코드조각으로 뽑아내서 사용할 수도 있습니다.

 

 

- Jscript IntelliSense Enhancements

 

VisualStudio 2010에선 더 풍부한 편집을 위해서 Jscript의 인텔리센스가 다시 디자인 되었습니다. 이젠 인텔리센스가 registerNamespace같은 메서드나 기타 비슷한 자바스크립트 프레임워크의 기술을 이용해서 동적으로 생성되는 객체를 인식할 수 있습니다. 그리고 방대한 스크립트 라이브러리를 분석하고 화면에 인텔리센스를 표시하는데 걸리는 시간을 사용자가 거의 못 느낄 정도로 향상시켰습니다. 호환성 역시 대단히 향상되어서 외부 라이브러리나 다양한 코딩 스타일도 지원할 수 있게 되었습니다. 문서화를 위한 주석은 타이핑하는 즉시 파싱되어서 인텔리센스에서 바로 활용할 수 있습니다.

 

 

- Web Application Deployment with Visual Studio 2010

 

현재 웹 어플리케이션을 배포하는 작업은 우리가 꿈꾸었던 것만큼 쉽지 않았죠. ASP.NET 개발자는 종종 아래와 같은 문제에 직면하곤 합니다.

 

  FTP같은 기술을 사용해야 하는 공동 호스팅 사이트에 배포하는 경우. 게다가 데이터베이스를 세팅하기 위한 SQL스크립트를 직접 실행해야 하거나 가상 디렉토리같은 IIS세팅도 바꿔야 한다.

  엔터프라이즈 환경에서는 웹 어플리케이션을 배포하는 것으로 끝나지 않고, ASP.NET 설정파일이나 IIS세팅도 수정해야 한다. 데이터베이스 관리자는 데이터베이스를 돌리기 위해 필요한 SQL스크립트를 돌려야 한다. 그런 설치작업은 종종 몇 시간을 잡아먹으며 노동에 가까운 일이 되며, 세세하게 문서화 되어야 한다.

 

VisualStudio 2010은 웹 어플리케이션을 중단없이 배포할 수 있게 도와주는 새로운 기술을 통해서 이런문제들을 해결합니다. 이런 기술들중의 하나가 IIS Web Deployment Tool(MsDeploy.exe)이죠.

 

VisualStudio 2010에서 웹배포에 관련된 요소들은 아래와 같이 크게 분류할 수 있습니다.

 

  Web packaging

  Web.config Transformation

  Database deployment

One-Click Publish for Web applications

 

아래의 섹션들에서 하나씩 자세하게 설명을 해보겠습니다.

 

 

Web Packaging

 

VisualStudio 2010에서는 MSDeploy 툴을 사용해서 어플리케이션을 압축해서 압축파일(.zip)을 생성하는데, 그 파일을 웹 패키지라고 부릅니다. 패키지파일은 어플리케이션에 대한 메타데이터와 아래의 내용들을 포함합니다.

 

 어플리케이션 풀 세팅과 에러페이지 세팅, 등등을 포함하는 IIS세팅

  웹페이지와 사용자 정의 컨트롤, 정적인 컨텐츠(이미지와 HTML파일), 등등을 포함하는 실제 웹 컨텐츠

  SQL 서버의 데이터베이스 스카마와 데이터

  보안 인증서, GAC에 설치할 컴포넌트, 레지스트리 세팅, 등등

 

웹 패키지는 아무 서버에나 복사할 수 있고, IIS 매니저를 사용해서 수동으로 설치할 수 있습니다. 또는, 커맨드라인 명령어나 배포API를 사용해서 자동으로 배포할 수도 있습니다.

 

VS2010에서는 웹패키지를 만들기 위해서 사용가능한 MSBuild task target을 제공합니다. 더 많은 정보는 Vishal Joshi의 블로그에 있는 10 + 20 reasons why you should create a Web Package를 참조하시길 바랍니다.

 

 

Web.config Transformation

 

웹 어플리케이션의 배포를 위해서 VisualStudio 2010에서는 XML Document Transform (XDT)가 도입되었는데, 이 요소는 개발설정에서 Web.config를 읽어와서 제품설정(production setting)으로 변환하게 도와줍니다. 변환에 관련된 세팅은 변환파일인 web.debug.config, web.release.config, 그리고 기타파일(이 파일들의 이름은 MSBuild 설정과 매치된다)등에 명시되어 있습니다. 변환파일에는 Web.config파일을 배포하기 위해 필요한 수정사항들만 포함되어 있습니다. 이런 수정사항들을 간단한 문법으로 명시해주면 되는거죠.

 

아래의 예제는 배포의 릴리즈설정에 의해 생성가능한 web.release.config파일의 일부분인데요. 예제의 내용중에서 Replace키워드를 보면, 배포과정에서 Web.config파일의 connectionString 노드의 값이 어떻게 바뀌어야 하는지 명시해주고 있습니다.

 

<connectionStrings xdt:Transform="Replace">

  <add name="BlogDB" connectionString="connection string detail]" />

</connectionStrings>

 

더 자세한 정보는, Vishal Joshi의 블로그의 Web Deployment: Web.Config Transformation를 보시면 됩니다.

 

 

- Database Deployment

 

VisualStudio 2010의 배포 패키지에는 SQL 서버 데이터베이스에 대한 의존성 역시 포함될 수 있습니다. 패키지 정의의 일부분으로 원본 데이터베이스의 연결문자열을 명시해줄 수 있습니다. 웹 패키지를 만들때 VisualStudio2010에 의해서 데이터베이스 스키마와 선택적으로 데이터에 대해서 SQL 스크립트가 만들어지고 패키지에 포함됩니다. 사용자 정의 SQL 스크립트를 만들어서 서버에서 순차적으로 실행되어야 할 순서를 지정해줄 수도 있습니다. 배포할때, 타겟 서버에 대한 연결문자열을 제공하고, 배포 프로세스에서 이 연결문자열을 이용해서 해당 데이터베이스에 SQL 스크립트를 실행해서 데이터베이스 스키마를 만들고 데이터를 추가합니다.

 

추가적으로, One-Click Publish를 이용하면 어플리케이션이 원격의 공용 호스트에 게시된 후에 데이터베이스를 직접적으로 게시할 수 있도록 배포를 설정할 수 있습니다. 자세한 내용은 Vishal Joshi의 블로그의 Database Deployment with VS 2010를 참조하시면 됩니다.

 

 

- One-Click Publish for Web Application

 

VisualStudio 2010에서는 IIS 원격 관리 서비스를 이용해서 원격의 서버에 웹 어플리케이션을 게시할 수 있도록 도와줍니다. 게시를 위해서 호스팅 계정이나 테스트 서버나 스테이징 서버를 위한 게시 프로파일(publish profile)을 생성할 수 있습니다. 각각의 프로파일은 안전하게 계정정보를 저장할 수 있구요. 그러면 Web One Click Publish 툴바를 이용해서 한번의 클릭으로 타겟서버에 배포할 수 있게 됩니다. VisualStudio2010에서는 MSBuild 커맨드 라인을 통해서도 배포할 수 있는데요. 이 기능을 통해서 지속적인 통합 모델을 이용하는 팀 빌드 환경에 게시작업을 포함할 수 있습니다.

 

더 자세한 정보는, Vishal Joshi의 블로그의 Web 1-Click Publish with VS 2010를 보시면 되구요, VisualStudio 2010에서의 웹 어플리케이션 배포에 대한 비디오 영상을 보려면, Vishal Joshi의 블로그의  VS 2010 for Web Developer Previews를 보시면 됩니다.

 

Welcome to Dynamic C#(8) - DLR이 나무를 사랑하는 이유

C# 2009. 9. 21. 09:00 Posted by 알 수 없는 사용자

- 아아... 이거슨 Love Story.

오늘 말씀드릴 내용은 DLR이 왜 Expression Tree(이하 표현나무)를 처음에는 박대하다가 나중에 가서는 "역시 난 니가 아니면 안되나봐 ㅠ_ㅠ"같은 대사를 날리게 되는지 Jim Hugunin의 증언을 통해서 알려드리고자 합니다. 그럼 지금부터 달콤 쌉싸름하고 무슨말인지도 잘 모르겠는 러브스토리를 한번 감상해보시져.


- 누군가가 필요하긴 했어. 하지만 너 아닌 다른 나무라도 괜찮을 거 같았어.

 지난 시간에 말씀드렸듯이 C# 3.0에 표현나무가 추가된 이유는 쿼리가 실행되는 곳이 어디냐에 따라서 최적화를 하기 위해서 컴파일된 IL코드의 형태보다는 자료구조의 형태가 훨씬 수월하기 때문이었습니다. 그리고 DLR은 닷넷 프레임워크에서 실행되는 동적 언어들이 공동으로 사용할 수 있는 기반을 제공해주고, 각 언어들끼리 그리고 정적언어들과도 서로 대화를 주고 받을 수 있도록 해주기 위한 장치인데요. 그렇다면, 언어별로 내부적인 구현의 차이점이 있을 수 있겠고 한 언어에서 작성한 코드를 다른 언어에서도 사용가능하려면, 둘 사이에 변환과정이 있어야 하겠고 그 변환과정을 수월하게 해줄 수 있는 도구가 필요하겠죠. 어떤 가요? DLR과 표현나무의 러브스토리의 윤곽이 좀 잡히시나요?

Jim Hugunin에 따르면 애초에 DLR을 설계할때 코드를 표현할 공통자료구조로 트리형태를 생각하고 있었다고 합니다. 그리고 타입이 없으면서 런타임에 late-bound되는 노드들로 구성된 트리로 구현을 시작했다고 합니다.  그래서 그 당시에 IronPython에 맞게 구현된 트리에는 타입이 있는 노드가 ConstantExpression딱 하나였다고 합니다. 상수 값이면 뭐든지 가지고 있는 노드 말이죠. 그리고 자신들이 생각하고 있는 트리와 표현나무 사이에는 공통점이 없다고 생각했었다고 합니다. 왜냐면 정적언어에서 쓰는 게 동적언어에는 안 맞을거라고 생각했기 때문이라는 군요. 그래서 독립적으로 트리를 구성해 나갔다고 하네요.


- 하지만, 다른 나무들을 만날 수록 니가 그립더라.

하지만, 다른 언어의 구현을 추가하면서, 기존의 DLR트리에 각 언어의 특징을 제대로 표현하기 힘들어졌다고 하는군요. 각 언어의 특징을 지원하기 위한 방법이 필요한데, 그렇다고 해서 직접적으로 그 언어의 특징을 위한 노드를 추가할 수 는 없었다네요. 아마도 DLR트리는 DLR에서 도는 언어들이 공통적으로 공유하게되는 자료구조인데, 특정언어에만 있는 노드를 추가하면, 점점 지저분해 지기 때문이겠죠.

예를 들면, Python의 print문을 보면, 내부적으로 print문은 Python에서 출력에 대한 걸 어떻게 처리할지에 대해 알고 있는 static 메서드를 호출한다고 하는군요. 그래서 DLR트리에 static 메서드 호출노드를 추가했다고 합니다. 그러면 print호출은 static 메서드를 호출하는 걸로 연결할 수 있으니까요.

그리고 이런 작업을 하다보니깐, 그동안 개발팀이 추가해오던 노드들이 정적인 타입이 적용되는 표현나무의 각 노드랑 딱 들어맞는 다는 걸 깨달았다고 합니다. 그래서 처음부터 다시 만드는 대신에 기존에 잘 쓰고 있는 걸 확장하자고 마음을 먹었고, 기존의 표현나무에 동적인 연산이나 변수, 이름 바인딩, 흐름제어등을 위한 노드를 추가했다고 합니다.

그리고 DLR에서 동작하는 언어가 이런 트리형태를 만들어 내게 되면서 각각의 언어에 맞는 최적화를 수행하는게 수월해졌습니다. 지난 포스트에서 설명드렸던 표현나무를 사용하면서 얻는 장점과 매우 동일한 점입니다. 그래서 각 언어의 컴파일러는 코드를 표현나무의 형태로 만들어서 그 표현나무를 DLR에게 전해준다고 하는 군요.


- 그들은 현재 잘 살고 있답니다.

Jim Hugunin의 PDC2008의 "Dynamic Languages In Microsoft .NET"의 슬라이드를 통해서 각 언어별로 나타나는 표현나무의 모양을 보도록 하겠습니다.

C#에서 구현한 팩토리얼을 표현나무로 옮긴다면 아래와 같다고 하는군요.



그리고 이걸 dynamic을 써서 C#에서 작성하면 아래와 같다고 합니다. 붉은 색으로 변화가 있는 부분이 있죠? 이 부분이 동적인 타입을 적용한 부분인데요, 즉 "==", "*", "-"같은 DLR의 표준메세지 객체를 이용해서 모든 언어에서 사용가능하도록 하면서 C#에서 왔다는 걸 표시해서 C# 바인더를 사용할 수 있게 한다고 합니다.



1과 2를 비교해보시면 어떤 노드가 추가됐는지 확일 할 수 있군요. 그리고 동일한 코드로 IronPython에서 만든 표현나무는 아래와 같습니다.



C#대신에 Python바인더를 사용하고 있구요, 메서드 호출부분에서 global field를 참조하는 부분이 있는데요, 이 부분은 닷넷의 프로퍼티를 통한 static field와 거의 완벽하게 들어 맞는다고 하는군요. 그래서 약간의 코드만 추가하면 된다고 합니다. 그리고 아래는 루비의 표현나무입니다.



루비는 함수형언어 개념의 표현식을 기반으로 하는데요 구문이라는게 없고 모든 루비의 코드 한라인 한라인은 값을 리턴하는 구조라고 하는군요. 그래서 return 같은 구문을 안써도 되므로 표현나무와 자연스럽게 어울린다는 군요.

즉, 각 언어에서 나온 트리가 모양이 조금씩 다르긴 한데 전체적으로 비슷한 구조를 유지하고 있습니다. 이런 각 언어에서 나온 표현나무를 분석해서 모든 트리에서 공유하는 폼으로 만들 수 있다는 군요. 아직 어떻게 정확하게 그렇게 할 수 있는지는 명확하게 설명된게 없어서(혹은 제가 못찾아서-_-, 제가 몰라서-_-) 더 설명드리기는 조금 힘들거 같군요.


- 마치면서

확실히 제게는 조금 벅찬 주제일 수도 있지만, 제가 이해한 범위내에서 최대한 명쾌하게 설명드리려고 노력했습니다. 하지만 틀린부분이 있을 수 있겠죠. 그렇다면 여러분의 지식을 공유하시면서 따쓰한 피드백을 주시기 발합니다. 캬캬캬....


- 참고자료

1. http://blogs.msdn.com/hugunin/archive/2007/05/15/dlr-trees-part-1.aspx
2. http://channel9.msdn.com/pdc2008/TL10/