병렬화는 어느 단위에나 일어난다.

하다 못해 모바일도 GPU 가속을 받는 세상이니까.

걍 썰이 풀고파서 끄적임.


1. Single Core Parallelism


이건 superpipeline 과 superscalar 를 이용한 기술을 말한다.

그러기 위해서 data hazard, branch hazard, structural hazard 를 제거 해야한다.

structural hazard 는 사실 개인이 손댈 여지가 그닥 없다고 본다. 컴파일러가 알아서 해 줘야 할 문제.


data hazard 의 경우, 종속성을 없애거나 줄이면된다. branch hazard 의 경우, 분기를 없애거나 줄이면 된다.

가령, 1 ~ 100 까지의 누적합을 (누가 가우스의 등차수열의 합산공식을 안쓰겠냐만은) 구하는데 있어


int sum = 0;

for(int i = 1; i <= 100; ++i) sum += i;


하는것 보다,

int sum = 0;

for(int i = 1; i <= 100;)

{

sum += i++;

sum += i++;

sum += i++;

....

sum += i++;

}


하는게 cmp(비교)와 jmp(분기) 가 줄겠지?

하지만 저 코드는 루프의 확장이라 불리는 전통적인 기법으로 아주 미미한 최적화 효과만 있다.

왜냐하면 sum 과 i 값의 write back 에 data dependency 가 걸려 있기 때문이다.


그렇다면,

int sum = 0;

for(int i = 1; i <= 100; i+=10)

{

sum += i;

sum += i + 1;

sum += i + 2;

....

}


이건 어떤가? i, i + 1, i + 2 가 write back 없이 병렬화 될 수 있다. 하지만 sum 에 대한 dependency는 해결되지 못했다.


int sum[10] = {0, };

for(int i = 1; i <= 100; i += 10)

{

sum[0] += i;

sum[1] += i + 1;

....

}


이건 어떤가? sum 자체에 대한 dependency는 줄었다. 그렇지만 배열 태그 연산비용이 생겼다.

그럼,

int sum0, sum1, sum2.... sum9;

sum0 sum1 = ... sum9 = 0;

for(int i = 1; i <= 100; i += 10)

{

sum0 += i;

sum1 += i + 1;

....

}

int sum = sum0 + sum1 + ... sum9;


이건 어떤가? 스택에 생성된 변수들을 기억해야할 갯수가 늘긴 했다. 이 말은 레지스터 활용도가 조금 떨어진단 이야기다.

하지만 그 위의 코드와 이 코드는 코어별로 확실히 성능차이를 보인다. (어눌한 코어일수록 아랫것이 유리)


이것이 data hazard 를 다루는 기본 기법중 하나다. 지금 당장 필요하지 않은 코드를 컴파일러가 알아서 삽입해주기도 하지만,

연속한 데이타를 다루는데 있어서는 스크램블링을 해주지 않는다. 코드가 늘어난다는건, 또 다른 비용발생이 있긴하다. (캐시)

이러한 병렬화의 의존제거를 위한 작업분리와, 연산후의 mux 개념은 싱글 코어의 범주를 넘어서,

쓰레드 베이스 멀티프로세싱, 분산 처리에 그대로 적용된다.


하지만 누가 손으로 짜 걍 OpenMP 나 C++AMP, OpenCL 등등 여러 도구들 많은데 =_=


더 떠들면 글 짤리겠지? 요까이.