멀티쓰레드가 싱글쓰레드보다 더 느리다?

 

cpu의 코어들은 각각의 쓰레드 작업을 할때 코어마다 있는 캐시(L1, L2)에 변수를 저장하여 빠르게 작업을 처리하려 한다.

[L3는 각 코어가 공유하는 데이터를 저장함]

*참고로 각 코어마다 register도 있고 제일 빠름

그런데 캐시에 변수를 기록할때 딱 그 변수크기만 읽어서 기록하지 않는다. 캐시라인 단위로 읽어 온다.

보통 cpu는 64byte씩 통째로 읽어들인다.

따라서 쓰레드가 int 변수 하나만 가져와 쓴다 하더라도 그 변수 위치부터 64byte 만큼 한꺼번에 읽어서 가져온다.

 

여기서 어떤 상황에서 false sharing 이라는 것이 발생하고 성능저하를 일으킨다. 즉 하드웨어로 인한 성능저하다.

그 어떤 상황의 예)

int a=0;
int b=0;

void thread_1()
{
	for(int i=0; i<1000; ++i)
    	++a;
}

void thread_2()
{
	for(int i=0; i<1000; ++i)
    	++b;
}

core1 에서 thread_1을 실행, core2 에서 thread_2를 실행한다고 했을때, 각 코어의 캐시에는 변수가 다음과 같이 기록될 수 있다. (아닐 수도 있음)

a와 b가 붙어 있기 때문에 이럴 확률이 높다

여기서 변수 b가 각 코어의 캐시에 동일하게 공유되어있다.  cpu는 cpu끼리 공유되고 있는 변수가 있을 시 동기화를 위한 작업을 수행한다. (MOESI 프로토콜)

 

간단히 설명하면 공유되고있는 데이터의 변화를 각자의 캐시에 적용하면 서로 변화를 모른다. 그래서 어떤 한 코어에서 데이터 변경 시 공유 데이터가 있으면 다른 코어의 캐시를 invalid시킨다.

즉, Core1에서 데이터를 업데이트 시, b라는 변수가 Core2와 공유되고있기 때문에  Core2의 캐시라인을 invalid한다. ( Core1은 b를 고치지 않지만 어쨋든 캐시라인에 공유되고 있기때문에 착각하여 동기화를 진행한다.)

 

그러면 후에 Core2에서 작업하려할 시, 캐시라인이 invalid되었기 때문에  Core1의 캐시로부터 데이터를 다시 가져와야 해서 더 많은 시간이 걸린다.

 

이렇게 서로 다른 데이터를 사용하지만 캐시라인 공유로 인해 하드웨어상 동기화 작업으로 성능저하가 나타난다.

 

이를 해결하기위해 있는 것이 alignas

alignas(64) 키워드를 사용하여 변수 사이의 주소를 물리적으로 떨어뜨린다.

 

alignas(64) int a=0;
alignas(64) int b=0;

void thread_1()
{
	for(int i=0; i<1000; ++i)
    	++a;
}

void thread_2()
{
	for(int i=0; i<1000; ++i)
    	++b;
}

 

+cpu캐시의 크기를 얻어오는 매크로

std::hardware_destructive_interference_size

 

 

*공부한 블로그 b

[05. 멀티쓰레드] 멀티쓰레드 2 (Lock 의 사용과 문제점 - 성능저하) (tistory.com) 

false sharing이란? in 멀티 쓰레드(About Memory alignment) (tistory.com)

'멀티 쓰레드' 카테고리의 다른 글

데드락 (deadlock, 교착상태)  (0) 2023.09.06
프로세스와 스레드  (0) 2023.08.23
[cpu의 사기 2] atomic  (0) 2023.03.02
[컴파일러의 사기] volatile 키워드  (0) 2023.03.01

+ Recent posts