kokr/memory-barriers/txt: Replace uses of "transitive"
This commit applies two upstream change, commitf1ab25a30c
("memory-barriers: Replace uses of "transitive"") and commit0902b1f44a
("memory-barriers: Rework multicopy-atomicity section") to the Korean translation. Those two changes are applied with this signle commit because the second change is improvement of the first one. Signed-off-by: SeongJae Park <sj38.park@gmail.com> Signed-off-by: Jonathan Corbet <corbet@lwn.net>
This commit is contained in:
parent
8ee25f6fcf
commit
578152da87
|
@ -82,7 +82,7 @@ Documentation/memory-barriers.txt
|
|||
- SMP 배리어 짝맞추기.
|
||||
- 메모리 배리어 시퀀스의 예.
|
||||
- 읽기 메모리 배리어 vs 로드 예측.
|
||||
- 이행성
|
||||
- Multicopy 원자성.
|
||||
|
||||
(*) 명시적 커널 배리어.
|
||||
|
||||
|
@ -656,6 +656,11 @@ Documentation/RCU/rcu_dereference.txt 파일을 주의 깊게 읽어 주시기
|
|||
해줍니다.
|
||||
|
||||
|
||||
데이터 의존성에 의해 제공되는 이 순서규칙은 이를 포함하고 있는 CPU 에
|
||||
지역적임을 알아두시기 바랍니다. 더 많은 정보를 위해선 "Multicopy 원자성"
|
||||
섹션을 참고하세요.
|
||||
|
||||
|
||||
데이터 의존성 배리어는 매우 중요한데, 예를 들어 RCU 시스템에서 그렇습니다.
|
||||
include/linux/rcupdate.h 의 rcu_assign_pointer() 와 rcu_dereference() 를
|
||||
참고하세요. 여기서 데이터 의존성 배리어는 RCU 로 관리되는 포인터의 타겟을 현재
|
||||
|
@ -864,38 +869,10 @@ CPU 는 b 로부터의 로드 오퍼레이션이 a 로부터의 로드 오퍼레
|
|||
주어진 if 문의 then 절과 else 절에게만 (그리고 이 두 절 내에서 호출되는
|
||||
함수들에게까지) 적용되지, 이 if 문을 뒤따르는 코드에는 적용되지 않습니다.
|
||||
|
||||
마지막으로, 컨트롤 의존성은 이행성 (transitivity) 을 제공하지 -않습니다-. 이건
|
||||
'x' 와 'y' 가 둘 다 0 이라는 초기값을 가졌다는 가정 하의 두개의 예제로
|
||||
보이겠습니다:
|
||||
|
||||
CPU 0 CPU 1
|
||||
======================= =======================
|
||||
r1 = READ_ONCE(x); r2 = READ_ONCE(y);
|
||||
if (r1 > 0) if (r2 > 0)
|
||||
WRITE_ONCE(y, 1); WRITE_ONCE(x, 1);
|
||||
컨트롤 의존성에 의해 제공되는 이 순서규칙은 이를 포함하고 있는 CPU 에
|
||||
지역적입니다. 더 많은 정보를 위해선 "Multicopy 원자성" 섹션을 참고하세요.
|
||||
|
||||
assert(!(r1 == 1 && r2 == 1));
|
||||
|
||||
이 두 CPU 예제에서 assert() 의 조건은 항상 참일 것입니다. 그리고, 만약 컨트롤
|
||||
의존성이 이행성을 (실제로는 그러지 않지만) 보장한다면, 다음의 CPU 가 추가되어도
|
||||
아래의 assert() 조건은 참이 될것입니다:
|
||||
|
||||
CPU 2
|
||||
=====================
|
||||
WRITE_ONCE(x, 2);
|
||||
|
||||
assert(!(r1 == 2 && r2 == 1 && x == 2)); /* FAILS!!! */
|
||||
|
||||
하지만 컨트롤 의존성은 이행성을 제공하지 -않기- 때문에, 세개의 CPU 예제가 실행
|
||||
완료된 후에 위의 assert() 의 조건은 거짓으로 평가될 수 있습니다. 세개의 CPU
|
||||
예제가 순서를 지키길 원한다면, CPU 0 와 CPU 1 코드의 로드와 스토어 사이, "if"
|
||||
문 바로 다음에 smp_mb()를 넣어야 합니다. 더 나아가서, 최초의 두 CPU 예제는
|
||||
매우 위험하므로 사용되지 않아야 합니다.
|
||||
|
||||
이 두개의 예제는 다음 논문:
|
||||
http://www.cl.cam.ac.uk/users/pes20/ppc-supplemental/test6.pdf 와
|
||||
이 사이트: https://www.cl.cam.ac.uk/~pes20/ppcmem/index.html 에 나온 LB 와 WWC
|
||||
리트머스 테스트입니다.
|
||||
|
||||
요약하자면:
|
||||
|
||||
|
@ -930,8 +907,8 @@ http://www.cl.cam.ac.uk/users/pes20/ppc-supplemental/test6.pdf 와
|
|||
|
||||
(*) 컨트롤 의존성은 보통 다른 타입의 배리어들과 짝을 맞춰 사용됩니다.
|
||||
|
||||
(*) 컨트롤 의존성은 이행성을 제공하지 -않습니다-. 이행성이 필요하다면,
|
||||
smp_mb() 를 사용하세요.
|
||||
(*) 컨트롤 의존성은 multicopy 원자성을 제공하지 -않습니다-. 모든 CPU 들이
|
||||
특정 스토어를 동시에 보길 원한다면, smp_mb() 를 사용하세요.
|
||||
|
||||
(*) 컴파일러는 컨트롤 의존성을 이해하고 있지 않습니다. 따라서 컴파일러가
|
||||
여러분의 코드를 망가뜨리지 않도록 하는건 여러분이 해야 하는 일입니다.
|
||||
|
@ -943,13 +920,14 @@ SMP 배리어 짝맞추기
|
|||
CPU 간 상호작용을 다룰 때에 일부 타입의 메모리 배리어는 항상 짝을 맞춰
|
||||
사용되어야 합니다. 적절하게 짝을 맞추지 않은 코드는 사실상 에러에 가깝습니다.
|
||||
|
||||
범용 배리어들은 범용 배리어끼리도 짝을 맞추지만 이행성이 없는 대부분의 다른
|
||||
타입의 배리어들과도 짝을 맞춥니다. ACQUIRE 배리어는 RELEASE 배리어와 짝을
|
||||
맞춥니다만, 둘 다 범용 배리어를 포함해 다른 배리어들과도 짝을 맞출 수 있습니다.
|
||||
쓰기 배리어는 데이터 의존성 배리어나 컨트롤 의존성, ACQUIRE 배리어, RELEASE
|
||||
배리어, 읽기 배리어, 또는 범용 배리어와 짝을 맞춥니다. 비슷하게 읽기 배리어나
|
||||
컨트롤 의존성, 또는 데이터 의존성 배리어는 쓰기 배리어나 ACQUIRE 배리어,
|
||||
RELEASE 배리어, 또는 범용 배리어와 짝을 맞추는데, 다음과 같습니다:
|
||||
범용 배리어들은 범용 배리어끼리도 짝을 맞추지만 multicopy 원자성이 없는
|
||||
대부분의 다른 타입의 배리어들과도 짝을 맞춥니다. ACQUIRE 배리어는 RELEASE
|
||||
배리어와 짝을 맞춥니다만, 둘 다 범용 배리어를 포함해 다른 배리어들과도 짝을
|
||||
맞출 수 있습니다. 쓰기 배리어는 데이터 의존성 배리어나 컨트롤 의존성, ACQUIRE
|
||||
배리어, RELEASE 배리어, 읽기 배리어, 또는 범용 배리어와 짝을 맞춥니다.
|
||||
비슷하게 읽기 배리어나 컨트롤 의존성, 또는 데이터 의존성 배리어는 쓰기 배리어나
|
||||
ACQUIRE 배리어, RELEASE 배리어, 또는 범용 배리어와 짝을 맞추는데, 다음과
|
||||
같습니다:
|
||||
|
||||
CPU 1 CPU 2
|
||||
=============== ===============
|
||||
|
@ -1361,57 +1339,74 @@ A 의 로드 두개가 모두 B 의 로드 뒤에 있지만, 서로 다른 값
|
|||
: : +-------+
|
||||
|
||||
|
||||
이행성
|
||||
------
|
||||
MULTICOPY 원자성
|
||||
----------------
|
||||
|
||||
이행성(transitivity)은 실제의 컴퓨터 시스템에서 항상 제공되지는 않는, 순서
|
||||
맞추기에 대한 상당히 직관적인 개념입니다. 다음의 예가 이행성을 보여줍니다:
|
||||
Multicopy 원자성은 실제의 컴퓨터 시스템에서 항상 제공되지는 않는, 순서 맞추기에
|
||||
대한 상당히 직관적인 개념으로, 특정 스토어가 모든 CPU 들에게 동시에 보여지게
|
||||
됨을, 달리 말하자면 모든 CPU 들이 모든 스토어들이 보여지는 순서를 동의하게 되는
|
||||
것입니다. 하지만, 완전한 multicopy 원자성의 사용은 가치있는 하드웨어
|
||||
최적화들을 무능하게 만들어버릴 수 있어서, 보다 완화된 형태의 ``다른 multicopy
|
||||
원자성'' 라는 이름의, 특정 스토어가 모든 -다른- CPU 들에게는 동시에 보여지게
|
||||
하는 보장을 대신 제공합니다. 이 문서의 뒷부분들은 이 완화된 형태에 대해 논하게
|
||||
됩니다만, 단순히 ``multicopy 원자성'' 이라고 부르겠습니다.
|
||||
|
||||
다음의 예가 multicopy 원자성을 보입니다:
|
||||
|
||||
CPU 1 CPU 2 CPU 3
|
||||
======================= ======================= =======================
|
||||
{ X = 0, Y = 0 }
|
||||
STORE X=1 LOAD X STORE Y=1
|
||||
<범용 배리어> <범용 배리어>
|
||||
LOAD Y LOAD X
|
||||
STORE X=1 r1=LOAD X (reads 1) LOAD Y (reads 1)
|
||||
<범용 배리어> <읽기 배리어>
|
||||
STORE Y=r1 LOAD X
|
||||
|
||||
CPU 2 의 X 로드가 1을 리턴했고 Y 로드가 0을 리턴했다고 해봅시다. 이는 CPU 2 의
|
||||
X 로드가 CPU 1 의 X 스토어 뒤에 이루어졌고 CPU 2 의 Y 로드는 CPU 3 의 Y 스토어
|
||||
전에 이루어졌음을 의미합니다. 그럼 "CPU 3 의 X 로드는 0을 리턴할 수 있나요?"
|
||||
CPU 2 의 Y 로의 스토어에 사용되는 X 로드의 결과가 1 이었고 CPU 3 의 Y 로드가
|
||||
1을 리턴했다고 해봅시다. 이는 CPU 1 의 X 로의 스토어가 CPU 2 의 X 로부터의
|
||||
로드를 앞서고 CPU 2 의 Y 로의 스토어가 CPU 3 의 Y 로부터의 로드를 앞섬을
|
||||
의미합니다. 또한, 여기서의 메모리 배리어들은 CPU 2 가 자신의 로드를 자신의
|
||||
스토어 전에 수행하고, CPU 3 가 Y 로부터의 로드를 X 로부터의 로드 전에 수행함을
|
||||
보장합니다. 그럼 "CPU 3 의 X 로부터의 로드는 0 을 리턴할 수 있을까요?"
|
||||
|
||||
CPU 2 의 X 로드는 CPU 1 의 스토어 후에 이루어졌으니, CPU 3 의 X 로드는 1을
|
||||
리턴하는게 자연스럽습니다. 이런 생각이 이행성의 한 예입니다: CPU A 에서 실행된
|
||||
로드가 CPU B 에서의 같은 변수에 대한 로드를 뒤따른다면, CPU A 의 로드는 CPU B
|
||||
의 로드가 내놓은 값과 같거나 그 후의 값을 내놓아야 합니다.
|
||||
CPU 3 의 X 로드가 CPU 2 의 로드보다 뒤에 이루어졌으므로, CPU 3 의 X 로부터의
|
||||
로드는 1 을 리턴한다고 예상하는게 당연합니다. 이런 예상은 multicopy
|
||||
원자성으로부터 나옵니다: CPU B 에서 수행된 로드가 CPU A 의 같은 변수로부터의
|
||||
로드를 뒤따른다면 (그리고 CPU A 가 자신이 읽은 값으로 먼저 해당 변수에 스토어
|
||||
하지 않았다면) multicopy 원자성을 제공하는 시스템에서는, CPU B 의 로드가 CPU A
|
||||
의 로드와 같은 값 또는 그 나중 값을 리턴해야만 합니다. 하지만, 리눅스 커널은
|
||||
시스템들이 multicopy 원자성을 제공할 것을 요구하지 않습니다.
|
||||
|
||||
리눅스 커널에서 범용 배리어의 사용은 이행성을 보장합니다. 따라서, 앞의 예에서
|
||||
CPU 2 의 X 로드가 1을, Y 로드는 0을 리턴했다면, CPU 3 의 X 로드는 반드시 1을
|
||||
리턴합니다.
|
||||
앞의 범용 메모리 배리어의 사용은 모든 multicopy 원자성의 부족을 보상해줍니다.
|
||||
앞의 예에서, CPU 2 의 X 로부터의 로드가 1 을 리턴했고 CPU 3 의 Y 로부터의
|
||||
로드가 1 을 리턴했다면, CPU 3 의 X 로부터의 로드는 1을 리턴해야만 합니다.
|
||||
|
||||
하지만, 읽기나 쓰기 배리어에 대해서는 이행성이 보장되지 -않습니다-. 예를 들어,
|
||||
앞의 예에서 CPU 2 의 범용 배리어가 아래처럼 읽기 배리어로 바뀐 경우를 생각해
|
||||
봅시다:
|
||||
하지만, 의존성, 읽기 배리어, 쓰기 배리어는 항상 non-multicopy 원자성을 보상해
|
||||
주지는 않습니다. 예를 들어, CPU 2 의 범용 배리어가 앞의 예에서 사라져서
|
||||
아래처럼 데이터 의존성만 남게 되었다고 해봅시다:
|
||||
|
||||
CPU 1 CPU 2 CPU 3
|
||||
======================= ======================= =======================
|
||||
{ X = 0, Y = 0 }
|
||||
STORE X=1 LOAD X STORE Y=1
|
||||
<읽기 배리어> <범용 배리어>
|
||||
LOAD Y LOAD X
|
||||
STORE X=1 r1=LOAD X (reads 1) LOAD Y (reads 1)
|
||||
<데이터 의존성> <읽기 배리어>
|
||||
STORE Y=r1 LOAD X (reads 0)
|
||||
|
||||
이 코드는 이행성을 갖지 않습니다: 이 예에서는, CPU 2 의 X 로드가 1을
|
||||
리턴하고, Y 로드는 0을 리턴하지만 CPU 3 의 X 로드가 0을 리턴하는 것도 완전히
|
||||
합법적입니다.
|
||||
이 변화는 non-multicopy 원자성이 만연하게 합니다: 이 예에서, CPU 2 의 X
|
||||
로부터의 로드가 1을 리턴하고, CPU 3 의 Y 로부터의 로드가 1 을 리턴하는데, CPU 3
|
||||
의 X 로부터의 로드가 0 을 리턴하는게 완전히 합법적입니다.
|
||||
|
||||
CPU 2 의 읽기 배리어가 자신의 읽기는 순서를 맞춰줘도, CPU 1 의 스토어와의
|
||||
순서를 맞춰준다고는 보장할 수 없다는게 핵심입니다. 따라서, CPU 1 과 CPU 2 가
|
||||
버퍼나 캐시를 공유하는 시스템에서 이 예제 코드가 실행된다면, CPU 2 는 CPU 1 이
|
||||
쓴 값에 좀 빨리 접근할 수 있을 것입니다. 따라서 CPU 1 과 CPU 2 의 접근으로
|
||||
조합된 순서를 모든 CPU 가 동의할 수 있도록 하기 위해 범용 배리어가 필요합니다.
|
||||
핵심은, CPU 2 의 데이터 의존성이 자신의 로드와 스토어를 순서짓지만, CPU 1 의
|
||||
스토어에 대한 순서는 보장하지 않는다는 것입니다. 따라서, 이 예제가 CPU 1 과
|
||||
CPU 2 가 스토어 버퍼나 한 수준의 캐시를 공유하는, multicopy 원자성을 제공하지
|
||||
않는 시스템에서 수행된다면 CPU 2 는 CPU 1 의 쓰기에 이른 접근을 할 수도
|
||||
있습니다. 따라서, 모든 CPU 들이 여러 접근들의 조합된 순서에 대해서 동의하게
|
||||
하기 위해서는 범용 배리어가 필요합니다.
|
||||
|
||||
범용 배리어는 "글로벌 이행성"을 제공해서, 모든 CPU 들이 오퍼레이션들의 순서에
|
||||
동의하게 할 것입니다. 반면, release-acquire 조합은 "로컬 이행성" 만을
|
||||
제공해서, 해당 조합이 사용된 CPU 들만이 해당 액세스들의 조합된 순서에 동의함이
|
||||
보장됩니다. 예를 들어, 존경스런 Herman Hollerith 의 C 코드로 보면:
|
||||
범용 배리어는 non-multicopy 원자성만 보상할 수 있는게 아니라, -모든- CPU 들이
|
||||
-모든- 오퍼레이션들의 순서를 동일하게 인식하게 하는 추가적인 순서 보장을
|
||||
만들어냅니다. 반대로, release-acquire 짝의 연결은 이런 추가적인 순서는
|
||||
제공하지 않는데, 해당 연결에 들어있는 CPU 들만이 메모리 접근의 조합된 순서에
|
||||
대해 동의할 것으로 보장됨을 의미합니다. 예를 들어, 존경스런 Herman Hollerith
|
||||
의 코드를 C 코드로 변환하면:
|
||||
|
||||
int u, v, x, y, z;
|
||||
|
||||
|
@ -1444,8 +1439,7 @@ CPU 2 의 읽기 배리어가 자신의 읽기는 순서를 맞춰줘도, CPU 1
|
|||
}
|
||||
|
||||
cpu0(), cpu1(), 그리고 cpu2() 는 smp_store_release()/smp_load_acquire() 쌍의
|
||||
연결을 통한 로컬 이행성에 동참하고 있으므로, 다음과 같은 결과는 나오지 않을
|
||||
겁니다:
|
||||
연결에 참여되어 있으므로, 다음과 같은 결과는 나오지 않을 겁니다:
|
||||
|
||||
r0 == 1 && r1 == 1 && r2 == 1
|
||||
|
||||
|
@ -1454,8 +1448,9 @@ cpu0() 의 쓰기를 봐야만 하므로, 다음과 같은 결과도 없을 겁
|
|||
|
||||
r1 == 1 && r5 == 0
|
||||
|
||||
하지만, release-acquire 타동성은 동참한 CPU 들에만 적용되므로 cpu3() 에는
|
||||
적용되지 않습니다. 따라서, 다음과 같은 결과가 가능합니다:
|
||||
하지만, release-acquire 에 의해 제공되는 순서는 해당 연결에 동참한 CPU 들에만
|
||||
적용되므로 cpu3() 에, 적어도 스토어들 외에는 적용되지 않습니다. 따라서, 다음과
|
||||
같은 결과가 가능합니다:
|
||||
|
||||
r0 == 0 && r1 == 1 && r2 == 1 && r3 == 0 && r4 == 0
|
||||
|
||||
|
@ -1482,8 +1477,8 @@ u 로의 스토어를 cpu1() 의 v 로부터의 로드 뒤에 일어난 것으
|
|||
이런 결과는 어떤 것도 재배치 되지 않는, 순차적 일관성을 가진 가상의
|
||||
시스템에서도 일어날 수 있음을 기억해 두시기 바랍니다.
|
||||
|
||||
다시 말하지만, 당신의 코드가 글로벌 이행성을 필요로 한다면, 범용 배리어를
|
||||
사용하십시오.
|
||||
다시 말하지만, 당신의 코드가 모든 오퍼레이션들의 완전한 순서를 필요로 한다면,
|
||||
범용 배리어를 사용하십시오.
|
||||
|
||||
|
||||
==================
|
||||
|
@ -3058,6 +3053,9 @@ AMD64 Architecture Programmer's Manual Volume 2: System Programming
|
|||
Chapter 7.1: Memory-Access Ordering
|
||||
Chapter 7.4: Buffering and Combining Memory Writes
|
||||
|
||||
ARM Architecture Reference Manual (ARMv8, for ARMv8-A architecture profile)
|
||||
Chapter B2: The AArch64 Application Level Memory Model
|
||||
|
||||
IA-32 Intel Architecture Software Developer's Manual, Volume 3:
|
||||
System Programming Guide
|
||||
Chapter 7.1: Locked Atomic Operations
|
||||
|
@ -3069,6 +3067,8 @@ The SPARC Architecture Manual, Version 9
|
|||
Appendix D: Formal Specification of the Memory Models
|
||||
Appendix J: Programming with the Memory Models
|
||||
|
||||
Storage in the PowerPC (Stone and Fitzgerald)
|
||||
|
||||
UltraSPARC Programmer Reference Manual
|
||||
Chapter 5: Memory Accesses and Cacheability
|
||||
Chapter 15: Sparc-V9 Memory Models
|
||||
|
|
Loading…
Reference in New Issue