Transactional Memory #2

무려 2013년 11월에 Transactional Memory에 대한 포스팅을 한 적이 있다. 이 때는, Parallel Computing에서 일반적으로 사용되는 Lock 방식의 메모리 관리기법의 단점에 대해 알아보았다. 대표적으로 3가지를 들 수 있다.

  • Dead Lock: 같은 자원에 접근하는 Thread가 서로 멈추는 문제
  • Priority Inversion: Thread의 Priority가 지켜지지 않는 문제
  • Convoying: Lock 중인 Thread가 System call을 받으면 기다리는 모든 Thread가 멈추는 문제
  • 위 3가지의 구조적 문제점 이 외에도, Shared resource에 대한 Lock을 위해 Kernel Instruction이 수시로 호출되면서 속도가 저하되는 문제

정작 Transactional Memory에 대해서는 다음에 알아보자고 어물쩍 넘어갔는데, 이번 포스팅에서 Transactional Memory가 어떻게 동작하는지 알아보자.

Implementation Instructions

Transactional Memory가 어떻게 일을 하는지는 앞선 포스팅에서 간략히 소개한 적이 있다. 다른 사람이 공유자원을 쓰는지 안쓰는지 확인하기 복잡하니, 일단 내가 쓰고싶은 만큼 불러와서 데이터를 사용하고 기록한다. 이러한 과정을 메모리에 그때 그때 업데이트하는게 아니라, 따로 기록해둔다. 그리고 내가 사용해서 변경된 내역들은 나중에 한꺼번에 반영(commit)한다. 이러한 Commit과정에서 내가 사용한 메모리를 다른 곳에서 사용했는지 검사(validate)를 해본다. 만약 다른 곳에서 접근해서 사용했다면 내가 가지고 있는 메모리 데이터가 올바르지 않을 수 있으니 현재 까지의 변경 사항은 그냥 버린다(abort). 그리고 Transaction의 처음부터 다시 하는 것이다. 이렇게 Transactional Memory의 동작은 크게 3가지(commit, abort, validate)로 나눌 수 있으며, 이를 구현하기 위해서 필요한 Instruction은 아래와 같다.

  • Load-transactional (LT): 공유 메모리에서 값을 읽어올 때 사용하는 명령어. 이 때 읽어오는 값은 바뀌지 않는다.
  • Load-transactional-exclusive (LTX): 공유 메모리에서 값을 읽어오는데, 이 값이 변경될 때 사용하는 명령어.
  • Store-transactional (ST): 메모리에 값을 쓰는 명령어. 이 때, 쓰는 값은 즉시 메모리에 업데이트 되는게 아니다. 최종적으로 Transactional Thread가 성공적으로 완료되었을 때 (commit) 업데이트된다.

Transactional Memory의 동작을 다시 정리하면 아래와 같다.

  • Commit: 현재 Transaction을 종료하고, 변경 사항을 모두 메모리에 반영할지 버릴지 결정한다. 공유 메모리에 다른 Transaction이 접근한 적이 없다면 변경 사항이 모두 메모리에 반영되어, 다음부터 다른 Transaction 이 해당 메모리에 접근할 때 변경된 값을 사용할 수 있을 것이다.
  • Abort: 현재 Transaction에서 있었던 변경 사항을 모두 버린다. 메모리에 반영하지 않음.
  • Validate: Transaction 중 현재 메모리 상황을 파악한다. 현재 내가 가지고 있는 자료의 본 메모리에 다른 Transaction이 접근했다면, 자료가 변경되었을 수 있다. 이럴 경우에는 Validate False다.

Transactional Memory의 동작은 간단하게 아래와 같을 것이다.

  1. LT, LTX: 메모리에서 값을 Register로 가져온다.
  2. Validate: 가져온 값이 유효한가? 최신 정보인지 확인한다.
  3. ST: 계산한 결과들을 저장한다.
  4. Commit: 일련의 과정이 모두 끝나고, 내가 변경한 데이터들을 다른 Transaction 들도 사용할 수 있게, 메모리에 반영한다. 이 때, Validate False라면 1번으로 돌아가 다시 반복한다.

다음 포스팅에서는 (언제가 될지 장담할 수 없지만) Snoopy Cache와 Directory Cache에서 각각 어떤 방식으로 적용했는지 알아보자.