Computer Architecture,  Study

[Computer Arch.] False Sharing

멀티 코어 CPU에서 발생할 수 있는 문제다. 멀티 코어 CPU에서는 데이터를 word 단위로 읽어오는 대신 메모리 I/O 효율성을 위해서 cache line로 읽어오는데, 이때 문제가 생길 수 있다. 두개의 메모리 연산이 동일한 cache line에서 실행될 경우, CPU<->Memory 버스 사이에서 하드웨어적인 락이 걸리는데, 이때 하드웨어적인 병목현상이 발생한다.

  False-sharing 은 현대의 멀티코어 CPU가 메모리에서 데이터를 읽어올 때 Word 단위 (=native int 의 크기) 로 읽어오는게 아니라, 메모리 I/O의 효율성을 위해 cache에 저장하는 단위[1] 로 읽어오면서 생기는 문제다.즉,

  1. Core 0가 메모리 1000 번지에 write 연산
  2. Core 1가 메모리 1008 번지에 write 연산

  이런 두 개의 흐름이 동시에 진행될 때, 1, 2가 독립적으로 실행되지 못하고((다만 1000번지와 1008번지는 같은 cache line 위에 있다고 생각해야 한다)), CPU – Memory 버스사이에서 하드웨어적인 lock 을 잡게 되서 생기는 문제다. (각각 실행되는게 아니라 둘 중 하나가 먼저, 나머지 하나가 나중에 실행된다) 즉, 1이 실행되면 CPU의 cache-coherency protocol로 인해서 2가 실행되기전에 업데이트가 이루어지고, 이로 인해 HW 병목이 생긴다.

  core 1은 이 값을 읽을 때, 최신 값이 아닌 예전 값을 읽게 되는 문제가 발생한다. 이 경우가 배로 cache coherency, cache 일치성에 문제가 생긴 것이다. 이런 것을 막고자 자기가 쓰고 있는 cache가 다른 코어도 들고 있다면 그 값을 바꾸라는 메세지를 보내야 한다. 이런 일련의 과정을 Cache Coherence Protocol이라는 규칙으로 해결하고 있다. 대표적으로 MOESI가 있다. MOESI는 각 cache 라인이 가질 수 있는 5가지 상태 (Invalid, Owned, Shared, Exclusive, Modified)의 첫머리를 따서 만든 것이다.

  간략하게 이 경우에 해당하는 상황만 설명하면, 처음 이 두 코어가 이 데이터를 cache에 가지고 있을 때는 모두 shared 상태로 되어있다. 두 코어로부터 공유되고 있다는 뜻이다. 여기서 Core 0이 데이터를 고치면 먼저 이 cache를 자기 것으로 만들기 위해 다른 공유자들에게 모두 무효 시키라는 메세지를 보내야만 한다. 그러면 Core 1은 shared 상태였던 cache를 invalid로 고친다. 그런 뒤, Core 0는 이제 이 cache 사본에 수정을 가하고 modified 상태로 바뀐다. 여기서 만약 core 1이 데이터를 읽으려면 cache가 invalid 상태이므로 L2 cache 혹은 Core 0의 cache로부터 가져와야 하기 때문에 더 많은 시간이 걸린다.

  그렇다면 false sharing은 정확히 어떤 것을 말하는가? 위에서 설명한 모든 cache 작동에 있어서 그 단위는 바이트 혹은 4바이트 단위로 작동하는 것이 아니다. 보다 큰 단위인 cache line 이라고 불리는 대략 64바이트, 128바이트 단위로 모든 작업이 이루어진다. 이건 spatial locality (공간 지역성)을 이용하기 위해서이다. 한번에 cache로 데이터를 가져오는데 4바이트만 가져오는 것 보다 그 보다 큰 양을 가지고 오는 것이 당연히 좋을 것이다. 당연히 위에서 설명한 cache coherency도 모두 바이트 단위가 아닌 64바이트 정도의 캐시 라인 단위로 이루어 진다. 즉, cache의 각종 상태들이 모두 cache-line 단위로 관리된다.

  문제는 cache 라인이 공유가 되고는 있는데, 실제 Core 0이 쓰는 데이터는 이 라인 중 첫 번째 4바이트뿐이다. 또, Core 1은 쓰는 것은 마지막 4바이트뿐이다. 즉, 서로 둘은 실제로 공유하고 있는 데이터가 전혀 없다. 그러나 이 데이터가 같은 cache line에 있다. 그래서 어느 한 코어가 각각의 데이터에 접근할 때 마다, CPU는 cache 공유가 이루어지는 것으로 착각하고 만다. 그래서 서로 서로를 invalid 시키는 등의 신호를 보내는 삽질을 하게 된다. 위에서 설명하였듯이 invalid 시켜버리면 다른 쪽은 데이터 읽을 때 마다 cache miss를 겪게 된다. 따라서 false sharing의 결과는 대단한 성능 하락으로 이어질 수 있다.

Reference

  1. http://smallake.kr/?p=2271

Leave a Reply

Your email address will not be published. Required fields are marked *