(*(unsigned log *)&jiffies)++의 의미는 무엇입니까?

정인철의 이미지

jiffies 는 커널에서 타이머에 관련된 변수라고 하는데요..

그것보다..

(*(unsigned long *)&jiffies)++;

이 의미가 무엇이죠?

&jiffies 는 변수의 주소를 말하고..
이것을 (unsigned long *) 시키면... 타입케스팅인가?

헤깔리네요..

이런 류의 어려운 포인터 연산이 종종나오던군요...

해석좀 부탁드릴께요.. [/code]

댓글

cpulpul의 이미지

(*(unsigned long *)&jiffies)++;

&jiffies == > jiffies의 번지를
(unsigned long *)&jiffies ==> unsigned long형으로 casting... 하고
*(unsigned long *)&jiffies ==> casting된 번지에 *를 붙여 값으로 바꾸고
(*(unsigned long *)&jiffies)++ ==> 값에 1을 더합니다.

익명 사용자의 이미지

궁극적인 목적(의도)은 최적화에 의한 jiffies의 외곡을 막을려는 의도가
깊게 사려져 있는게 냄새 나는군요. 아휴 냄새!~!

참고로 jiffies의 원형은

unsigned long volatile jiffies;

이것은 kernel의 /kernel/timer.c 에서 찾아볼수 있고요.

해당 jiffies를 그냥 jiffies++ 해도 값은 증가하지만
그것이 반드시 메모리가 갱신된다는 보장은 시간적으로 볼때
보장할수 없습니다. 때문에 어떻게해서든지
메모리를 직접적으로 접근하도록 컴파일러에게 의사코드를 남겨야 하는데
volatile로는 그것이 전혀 상관 없는 내용이죠.
때문에 보통 의사코드(컴파일러에게 이렇게 해달라는 정책적 결정)를 사용합니다.
그중에 하나가 *((type *)&Value) 입니다.

또 한가지 예를 들면

void a(void)
{
  int NotUsedValue;
  /* Nothing */
}

이런 함수의 경우
NotUsedValue가 나중에 쓰여지지만 지금 쓰여지지 않는다면
컴파일러로부터 경고를 받을겁니다.
이때 NotUsedValue를 컴파일러에게 나중에 사용할수 있다는 의사코드로

void a(void)
{
  int NotUsedValue;
  (void)NotUsedValue;
  /* Nothing */
}

위와 같이 하게 됩니다.
그 밖에도 의미는 같지만 컴파일러에게 명확히 의사전달하는 방법이 많은데
저도 몇개 못찾았습니다.

silasoni의 이미지

배우고 갑니다...

ihavnoid의 이미지

extern unsigned long volatile jiffies;
void func1()
{
    prefunc();
    jiffies++;
    postfunc();
}

void func2()
{
    prefunc();
    *(&jiffies)++;
    postfunc();
}

이 둘의 어셈 코드가 어떻게 다를 지 알 수 있을까요?
아무리 생각해도 대략 psuedo-insturction(??)으로 하면 둘 다

call prefunc
ldr r0, @jiffies
add r0, r0, #1
str r0, @jiffies
call postfunc

이럴 것 같은데요.... 다른 형태의 implementation이 어떤 식으로 가능할까요?

그리고 굳이 최적화 왜곡을 막고자 했다면.... rmb(), wmb() 등을 이용하지 않은 이유는 무엇일까요?

Consider the ravens: for they neither sow nor reap; which neither have storehouse nor barn; and God feedeth them: how much more are ye better than the fowls?
Luke 12:24

익명 사용자의 이미지

ihavnoid wrote:

이 둘의 어셈 코드가 어떻게 다를 지 알 수 있을까요?

jiffies++;

이것은 대부분의 최적화옵션에서는 다음과 같습니다.

movl jiffies, %eax;
incl %eax;
movl %eax jiffies;

하지만

(*((unsigned long *)(&jiffies))++;

이것은 다음과 같이 되죠.

incl jiffies;

잘 생각해보세요.
아무때나 intr이 걸릴수 있는 상황에서
jiffies를 인터럽트를 금지시키지 않고 값을 변경하고자 할때
어떤것이 당연히 만들어져야 하는 코드인지를요.

힌트로 부연설명을 하자면

movl jiffies, %eax;
incl %eax;
movl %eax jiffies;

이렇게 생성된 jiffies++를 사용한다면
incl 바로 앞에서 intr이 발생되고 다른 곳에서 그 값을 수정하였다면
어떻게 될까요?

하지만

incl jiffies;

이렇게 생성되는 (*((unsigned long *)(&jiffies))++;를 사용한다면
intr이 중간에 삐집고 들어갈때가 없죠?

예를 좀 제대로 설명했는지 모르겠지만
이거 말고도 몇가지 이유가 더 있습니다.
잘 생각해보세요.

토발즈는 진짜 커널 개발자로서 이런것을 이미 간과했겠죠.
말로만 커널 개발자로 남는 사람들은 (맨날 커널 공부만 하는 ...)
이런것을 중요시 않할수도 있겠지만
커널 개발을 하시는 분들은 이런거 고려를 반드시 해야 겠죠.
게다가 커널을 개발한다는 사람이 어셈블리를 모르면
이런거 버그 못잡습니다. 그리고 포기하는 방향으로 가겠죠.
커널 공부하실때는 어셈블리는 필수라고 쓰레드 내용과 관계없이 주장합니다.

ihavnoid의 이미지

minzkn wrote:

jiffies++;

이것은 대부분의 최적화옵션에서는 다음과 같습니다.

movl jiffies, %eax;
incl %eax;
movl %eax jiffies;

하지만

(*((unsigned long *)(&jiffies))++;

이것은 다음과 같이 되죠.

incl jiffies;

잘 생각해보세요.
아무때나 intr이 걸릴수 있는 상황에서
jiffies를 인터럽트를 금지시키지 않고 값을 변경하고자 할때
어떤것이 당연히 만들어져야 하는 코드인지를요.

잘 이해가 되지 않아서... 궁금하여 한번 직접 해봤습니다... 역시 님께서 말씀하신대로 되더군요... :)

그렇지만, x86을 제외한 다른 RISC 프로세서에서는 차이를 보이지 않을 것 같은데요... 아니면 뭔가 다른 방식으로...??

.....저는 왜 저렇게 썼는지 사실 잘 모르겠습니다.... -_-;;
단순히 synchronization을 위한 것이라면 사실 저렇게 그냥 쓰는 것보다 뭔가 좀 더 적극적인 수단(interrupt을 끄는 것을 제외한, atomic operation을 보장하는..)을 이용해야 할 것 같아서요...

제가 생각했던 것은, 'jiffies의 용도를 생각해 봤을 때, 어차피 쓰기는 do_timer 한군데에서만 이루어질 것이기 때문에, 그리고 그냥 '대략적으로' 얼만큼의 시간이 흘렀는지 알고자 하는 것이기 때문에 굳이 synchronization을 할 필요가 없다' 였거든요... race condition이 발생한다고 해서 별 문제가 되지 않는다는 것입니다.... :)
(만에 하나라도 do_timer 말고 다른 곳에서 쓰기를 하면 낭패-_-)

한번 ARM에서는 어떻게 되는지 테스트를 해봐야겠습니다... -0-
테스뜨하고 좀 있다 결과 올릴께요.. ^^

Consider the ravens: for they neither sow nor reap; which neither have storehouse nor barn; and God feedeth them: how much more are ye better than the fowls?
Luke 12:24

ihavnoid의 이미지

원래 것과 수정한 것의 컴파일 결과물을 diff 해본 결과 차이가 없습니다.. -0-

do_timer:
        @ args = 0, pretend = 0, frame = 0
        @ frame_needed = 1, current_function_anonymous_args = 0
        mov     ip, sp
        stmfd   sp!, {fp, ip, lr, pc}
        ldr     r3, .L1382
        ldr     r2, [r3, #0]
        add     r2, r2, #1
        str     r2, [r3, #0]
        ldr     r1, [r0, #64]
        sub     fp, ip, #4
        tst     r1, #15
        movne   r0, #0
        moveq   r0, #1
        bl      update_process_times
....이하생략

으음.... 제 생각에는 synchronization때문은 아닌 것 같습니다....
무슨 이유때문에 저런 식으로 구현을 해 놨을 지 고민-0-을 해봐야겠습니다...
끙......
아울러서 왜 x86에서 왜 저렇게 다른 출력이 나오는지도... -0-

Consider the ravens: for they neither sow nor reap; which neither have storehouse nor barn; and God feedeth them: how much more are ye better than the fowls?
Luke 12:24

mushim의 이미지

extern int jiffies1;
extern int volatile jiffies2;

void func1()
{
    jiffies1++;
    jiffies2++;
}

void func2()
{
    (*(int *)(&jiffies1))++;
    (*(int *)(&jiffies2))++;
}

위의 코드를 gcc 를 통해서 어셈블리어로 바꾸어 보면,
아래와 같습니다.

func1:
        pushl   %ebp
        movl    %esp, %ebp
        incl    jiffies1
        movl    jiffies2, %eax
        incl    %eax
        movl    %eax, jiffies2
        leave
        ret

func2:
        pushl   %ebp
        movl    %esp, %ebp
        incl    jiffies1
        incl    jiffies2
        leave
        ret

volatile 로 한정하더래도, incl jiffies 를 보장해주는 군요.

좋은걸 배웠습니다.

익명 사용자의 이미지

같은 질문이 linux-kernel 메일링 리스트에 오래전에 올라와 있네요.

http://web.gnu.walfield.org/mail-archive/linux-kernel/2000-January/0490.html

여기 말고도 찾아 보니 같은 질문이 상당히 많네요.

mastercho의 이미지

최적화 옵션을 줘도 volatile이 저런 코드를 내주나요?

근데 gcc에 보면 -O 한다음 번호로 최적화 수준을 다르게 할수 있다는데

3.2버전에서는 몇까지 최적화 번호를 쓸수 있나요?

음......

위코드를 보면 한마디로 원자적으로 값를 변경할수 있는거 같네요

[근데 저게 다중 프로세서에서도 먹히는거나요?]

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

kuma의 이미지

Visual C/C++ 6.0 Pro에서 컴파일 결과입니다. 쩝....

; 5 : volatile int i;
; 6 :
; 7 : i ++;

mov eax, DWORD PTR _i$[ebp]
add eax, 1
mov DWORD PTR _i$[ebp], eax

; 12 : volatile int i;
; 13 :
; 14 :
; 15 : (*(int*)(&i)) ++;

mov eax, DWORD PTR _i$[ebp]
add eax, 1
mov DWORD PTR _i$[ebp], eax

Visual C/C++ 컴파일러 문제인가요? 똑같은 결과가 나오네요....,
또하나 이상한건 add 를 사용하네요... ㅠㅠ

mastercho의 이미지

결국 컴파일러 의존성 코드라는건데 -_-;

왜 저런 이식성이 없는 저런 코드를 사용했을라나?

역시 표준이 아닌 방법은 .....쩝

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

익명 사용자의 이미지

mastercho wrote:
결국 컴파일러 의존성 코드라는건데 -_-;

왜 저런 이식성이 없는 저런 코드를 사용했을라나?

역시 표준이 아닌 방법은 .....쩝

저의 생각은 좀 다르거든요.
오히려 Visual-C가 추가권고안을 더 안따라서 문제인듯 해요.
Visual-C에서 커널 컴파일 할수 없쟎아요?
MS의 Windows의 커널을 Visual-C에서 컴파일 했을까요? (사실을 알고 싶네요.)

그리고 의사코드는 컴파일러마다 강제적으로 지원해야 한다는 보장이
없기 때문에 사실상 특정 컴파일러의 특성에 따라 코드는 좀더 보강되어져 가야 되는게 맞는거 같고요.

의사코드에 대해서 ANSI-C를 다루는 어느 페이지가 있었는데
기억이 안나네요. 아무튼 의사코드 원래 지원해주는게 맞습니다.
의사코드 지원을 제대로 못해주는 컴파일러에서는 사실상 커널 빌드가
어렵지 않을까 합니다. 아니면 인라인 어셈으로 해야 되던지....

죠커의 이미지

방준영 wrote:
같은 질문이 linux-kernel 메일링 리스트에 오래전에 올라와 있네요.

http://web.gnu.walfield.org/mail-archive/linux-kernel/2000-January/0490.html

여기 말고도 찾아 보니 같은 질문이 상당히 많네요.

위의 주소가 접속이 되는 것인가요?

방금 익스와 파이어버드로 테스트 해보니 들어가지지 않는군요.

ihavnoid의 이미지

http://www.linuxhq.com/lnxlists/linux-kernel/lk_9905_02/msg00309.html

중간에 보면 패치에 주석이 추가되는 것을 볼 수 있습니다.

+	(*(unsigned long *)&jiffies)++; /* Otherwise gcc will generate ugly code */

2.5 언젠가부터 64-bit jiffies로 바뀌고 나서는 위의 코드가 없더군요....

Consider the ravens: for they neither sow nor reap; which neither have storehouse nor barn; and God feedeth them: how much more are ye better than the fowls?
Luke 12:24

정인철의 이미지

정말 알아야 할게 너무 많군요 ㅠㅠ

저가 바로 minzkn님이 말씀하시는 맨날 커널 공부만 하는 사람인거 같습니다.

너무 모르기때문에 ..

어셈블리어는 정말 필요한거 같습니다.
하지만...

시중에 나와있는 책을 보면.. MASM 위주의 그것도 간단한 것만 보이더군요

커널에서 보이는 어셈명령어도 안보이고..
어셈블 강의 제대로 해주실분 없나요 ?

하여간.. 해야할 게 너무 많군요 ^^;
갑자기 하기 싫어지지만... 포기하진 말아야죠

전웅의 이미지

extern unsigned long volatile jiffies;

jiffies++;
(*(unsigned long *)&jiffies)++;

이 둘의 semantic 상에서 중요한 차이는 volatile 형한정을 일종의 type
punning (*& hack) 을 통해 제거해 버렸다는 것입니다 - const 나 volatile
같은 형한정어는 lvalue 문맥에서만 유효하기에 형한정어의 의미를 배제하
고 접근하기 위해서는 유사한 트릭을 사용해야만 합니다. 예를 들어,

(*(unsigned long volatile *)&jiffies)++;

는 언어적 규칙

- 동일한 type 으로의 cast 는 무의미하다.
- 이 경우에, 연속적으로 적용된 &, * 는 무의미하다.

에 의해 jiffies++; 와 완전히 동등한 의미가 됩니다 - 물론 추상적인
semantic 단계에서 동등한 의미라고 해서 항상 동일한 코드가 생성된다는
보장은 없습니다만, 분명 다른 코드가 생성되는 경우는 현실적으로 드문 것
이 사실입니다.

결국, 목적 코드로 incl 이 허용되는 이유는 바로 volatile 이 semantic 단
계에서 제거되었기 때문입니다. 어떠한 경우에도 volatile 이 그대로 유지
된다면 gcc 는 변함없이 incl 의 사용을 막을 것입니다.

minzkn wrote:
해당 jiffies를 그냥 jiffies++ 해도 값은 증가하지만
그것이 반드시 메모리가 갱신된다는 보장은 시간적으로 볼때
보장할수 없습니다. 때문에 어떻게해서든지
메모리를 직접적으로 접근하도록 컴파일러에게 의사코드를 남겨야 하는데
volatile로는 그것이 전혀 상관 없는 내용이죠.

volatile 이 바로 그것 ("반드시 메모리가 갱신되어야 한다") 을 보장해주
는 것입니다. volatile 은 volatile 로 선언된 대상체의 값이 프로그램 외
부의 어떤 영향에 의해 수정될 수 있거나 혹은 해당 대상체에 접근하는 행
위가 어떤 추가적인 side effect 를 낼 수 있다는 것을 implementation 에
게 알리기 위해 사용됩니다. implementation 이 volatile 대상체에 접근함
으로써 생성되는 구체적인 side effect 를 모두 예측할 수 없다면 C 프로그
램의 abstract semantic (위에서는 증감 연산자의 의미 - 메모리에서 해당
대상체의 값을 읽어서, 하나 증가해서, 다시 해당 대상체로 저장하는 것)
을 그대로 따라 actual implementation 을 구성하도록 요구됩니다.

minzkn wrote:
힌트로 부연설명을 하자면

movl jiffies, %eax;
incl %eax;
movl %eax jiffies;

이렇게 생성된 jiffies++를 사용한다면
incl 바로 앞에서 intr이 발생되고 다른 곳에서 그 값을 수정하였다면
어떻게 될까요?

하지만

incl jiffies;

이렇게 생성되는 (*((unsigned long *)(&jiffies))++;를 사용한다면
intr이 중간에 삐집고 들어갈때가 없죠?

(제가 맞게 기억하고 있다면) SMP 상황이 아니라면 일반적으로는 맞는 말씀
입니다. 하지만, 여기서 jiffies 는 ihavnoid 님 말씀대로 do_timer 에 의
해서만 수정되기 때문에 이와 같은 이야기가 그대로 적용되지는 않습니다.

ihavnoid wrote:
단순히 synchronization을 위한 것이라면 사실 저렇게 그냥 쓰는 것보다 뭔가 좀 더 적극적인 수단(interrupt을 끄는 것을 제외한, atomic operation을 보장하는..)을 이용해야 할 것 같아서요...

예, 제 생각에도 보다 그 의도 (과도한 최적화 방지를 억제하여 in-memory
incl 를 쓰는 것) 를 분명히 표현하기 위해서는 인라인 어셈블리어 등으로
대체하는 것이 더 나았을 것 같습니다. 하지만, RISC 를 언급하셨듯이 incl
이 모든 아키텍쳐에서 제공되는 것이 아닌 상황에서, do_timer 가 아키텍쳐
독립적으로 구현되어 있기 때문에 굳이 *& hack 을 사용한 것 같습니다.

결론적으로,

jiffies++;

로 쓰더라도 (x86 아키텍쳐에서 gcc 에 의해 incl 보다 지저분한 코드가 생
성된다는 점 이외에는) 중요한 현실적인 문제는 전혀 없는 것 같습니다.

gcc 가 volatile 에 대해서 과도한 최적화 금지를 한다는 사실과 그 이유에
대해서는

http://gcc.gnu.org/projects/optimize.html

의 "3. Volatile inhibits too many optimizations" 를 보시기 바랍니다.

해당 링크에도 적혀 있듯이 C 표준은 volatile 에 대해서 위에서 말씀드린
semantic 을 제외하고는 상당히 불분명하게 기술하고 있습니다. 이는
volatile 에 대해 기대되는 여러가지 (심지어는 표준화 위원회 조차 예측하
기 어려운) 행동을 감안하여 의도적으로 이루어진 것으로 알고 있습니다.

한가지 중요한 사실은 위에서 *& hack 을 사용해 jiffies 에 접근하는 과정
에서 결론적으로 jiffies 로의 접근이 volatile 한정 없이 이루어지고 있다
는 것입니다. gcc 의 경우에는 "우연히 (혹은 의도적으로?)" 원하는 결과는
얻게 해주었지만, 이를 모르는 컴파일러에서는

volatile int vi;
// ...
(*(int *)&vi)++;

와 같은 구조에서 volatile 의 의미가 없기에 우려하고 있는 register 로의
caching 이 가능합니다 - 이와 같은 구조를 표준은 추상적으로 undefined
behavior 로 명시하고 있습니다. 결국, *& hack 에 의해 얻을 수 있는 위와
같은 행동을 확실한 근거 없이 gcc 가 아닌 컴파일러로 확장하는 것은 예상
하지 못한 현실적인 문제를 일으킬 수도 있습니다.

그럼...

p.s. 최근 C 표준에 대해서만 공부하고 있기 때문에 C 언어 혹은 표준과
관련된 내용을 제외하면 어디까지나 오래된 기억에만 의존한 것들입니다.
틀린 부분 있으면 지적 바랍니다.

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

sliver의 이미지

저도 매우 궁금하여 메일링리스트도 찾아보고 했지만

전웅님 답변이 제일 확실한 것 같군요 :)

mastercho의 이미지

minzkn wrote:

저의 생각은 좀 다르거든요.
오히려 Visual-C가 추가권고안을 더 안따라서 문제인듯 해요.
....

(*(unsigned long *)&jiffies)++; 이렇게 하면 최적화 하지말라는게

표준위원에서의 , "추가 권고안"에 있었던가요?

향후 표준으로 된다든가? :?:

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

전웅의 이미지

mastercho wrote:
minzkn wrote:

저의 생각은 좀 다르거든요.
오히려 Visual-C가 추가권고안을 더 안따라서 문제인듯 해요.
....

(*(unsigned long *)&jiffies)++; 이렇게 하면 최적화 하지말라는게

표준위원에서의 , "추가 권고안"에 있었던가요?

향후 표준으로 된다든가? :?:

없었으며, 앞으로도 없습니다 - 해당 수식은 jiffies 에 volatile 한정을
제거하고 접근한다는 것 (그래서 undefined behavior 를 일으킨다는 것) 외
에는 추상적인 semantic 단계에서는 아무 의미를 갖지 않습니다.

아마도 minzkn 님은 그와 같은 코드를 통해 표현되는 (반드시 강제되지는
않는) 프로그래머의 "의도" 를 (gcc 와는 달리) MSVC 가 제대로 반영하지
않음을 의미하시는 것 같습니다. 하지만, 이 경우에는 MSVC 도 gcc 도 모두
C 표준이 요구하는 volatile 의 semantic 을 충실히 지키고 있습니다.

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

익명 사용자의 이미지

전웅 wrote:
없었으며, 앞으로도 없습니다

어떤 근거로 없었다는 것이죠?
그리고 앞으로도 없다는것은?

저 분명히 어디서 봤습니다.
증거가 없어서 안타깝지만

제 기억이 맞다면 분명 있었습니다.

제가 워낙 위에 글쓰신분들처럼 url을 기억하고 있거나
검색을 잘하는 편이 아니라서 명확한 근거를 제시하지 않아서
죄송스럽지만 어쩔수가 없네요. 제 성격이다 보니까....

익명 사용자의 이미지

위의 링크가 접속이 되질 않는군요. 그러나 구글 캐시로 대신 볼 수 있습니다.

http://www.google.co.kr/search?q=cache:-VACTqAi-V8J:web.gnu.walfield.org/mail-archive/linux-kernel/2000-January/0490.html+jiffies%2B%2B&hl=ko&ie=UTF-8

익명 사용자의 이미지

방준영 wrote:
위의 링크가 접속이 되질 않는군요. 그러나 구글 캐시로 대신 볼 수 있습니다.

http://www.google.co.kr/search?q=cache:-VACTqAi-V8J:web.gnu.walfield.org/mail-archive/linux-kernel/2000-January/0490.html+jiffies%2B%2B&hl=ko&ie=UTF-8

준영님은 이런거 어떻게 검색하시길래 잘 찾으세요?
항상 궁굼하네요.
정말로 검색의 도사가 아닌가 하는 생각이..... 부럽습니다.
비결좀 가르쳐줘요.

mastercho의 이미지

(*(unsigned long *)&jiffies)++; 코드는 무의미하군요

단지 gcc 컴파일러의 버그성 트릭을 이용한거에 불과하네요

특히 incl이 다중 프로세서에서 원자성을 보장 못하고...

단일 CPU 환경하에 , gcc 컴파일러 만든 사람이 커널을 짠건지..

쩝....

unix에서도 원자성으로 값을 증가 시키는 함수가 얼렁 표준화 되서

나와야 겠습니다.....

[개인적으로 표준적인게 아니면 영 그렇네요...
각 컴퓨터마다 OS마다 컴파일러마다 ,제각각인 코드는....]

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

전웅의 이미지

minzkn wrote:
전웅 wrote:
없었으며, 앞으로도 없습니다

어떤 근거로 없었다는 것이죠?
그리고 앞으로도 없다는것은?

C 표준은

extern unsigned long volatile jiffies;

(*(unsigned long *)&jiffies)++;

와 같은 수식에 (volatile 로 한정된 대상체를 형한정을 무시하며 접근함으
로 인해 발생하는) undefined behavior 외에 아무런 의미도 부여하고 있지
않습니다:

Quote:
If an attempt is made to refer to an object defined with a volatile-
qualified type through use of an lvalue with non-volatile-qualified
type, the behavior is undefined. 113)

113) This applies to those objects that behave as if they were defined
with qualified types, even if they are never actually defined as
objects in the program (such as an object at a memory-mapped
input/output address).

그리고, 과거 C 표준이었던 C90, (사실상 이 문제와는 무관한) C90 AMD1,
현재 표준인 C99, 이미 발표된 C99 COR1 을 근거로 "없었으며" 라는 답변을
드린 것이며, 앞으로 C99 COR2 에 포함될 내용들, 아직 발표되지 않은
Embedded C TR 을 근거로 "앞으로도 없습니다" 라고 답변 드렸습니다. 그
이후의 미래는 역술인이 아닌 이상 맞추기 어렵겠지만, 지금까지의 역사를
보았을 때 undefined behavior 는 사실상 "잘못된 프로그램 구조" 로 인식
되고 있기에 해당 수식에 표준 차원에서 어떤 의미가 부여되기는 어렵습니
다. 그리고 최적화를 억제하는 기능은 이미 volatile 을 통해서 잘 명시되
어 있습니다. 이미 말씀드렸듯이 volatile 대상체의 접근에 대해 incl 을
선택하지 않는 gcc 의 행동은 분명 잘못된 것이 아니며, 다만 그와 같은
gcc 의 행동을 kernel 개발자가 맘에 들어하지 않을 뿐입니다.

minzkn wrote:
저 분명히 어디서 봤습니다.
증거가 없어서 안타깝지만

제 기억이 맞다면 분명 있었습니다.

제가 워낙 위에 글쓰신분들처럼 url을 기억하고 있거나
검색을 잘하는 편이 아니라서 명확한 근거를 제시하지 않아서
죄송스럽지만 어쩔수가 없네요. 제 성격이다 보니까....

어디선가 보셨다면 그건 최소한 C 표준은 아닙니다 - 잘못된 정보이거나,
(C 표준이 아닌) 다른 표준이거나 특정 컴파일러에 대한 문서 등등 일 수는
있습니다.

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

mastercho의 이미지

그럼.....

C 표준에서, 원자성으로 증가 시키는 함수가 나올 예정에 없는지요?

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

ihavnoid의 이미지

mastercho wrote:
그럼.....

C 표준에서, 원자성으로 증가 시키는 함수가 나올 예정에 없는지요?

그냥 제 지레짐작이지만 없을 것 같습니다.
백날 single-threaded에서만 작동할 많은 platform에게 원자성을 구현할 것을 강요하는 것은 C의 장점을 많은 양 까먹게 될 듯 합니다.

지금 당장은 8051이 기억나는군요....
아무리 생각해도, 외부 메모리를 이용할 경우에는 인터럽트를 끄는 것 밖에 sync를 보장할 길이 없을텐데, 인터럽트를 컴파일러가 지맘대로 꺼버리고 다시 켠다면, 아주 끔찍한 사태가 일어나겠죠.... -0-

Consider the ravens: for they neither sow nor reap; which neither have storehouse nor barn; and God feedeth them: how much more are ye better than the fowls?
Luke 12:24

mastercho의 이미지

그건 아닌거 같네요

이걸 지원한다고 해서 단일 쓰레드에서 돌아가는 프로그램이

해가될 일은 없죠

어차피 이 코드를 단일 쓰레드 프로그램에서는 쓰이지 않을테니까요

또한 이런게 있으면 다양한 환경에서도 각각의 벤더들마다 알아서 각 컴퓨터에와 OS에 맞는 최적화된 방법으로 그 인터페이스를 구현할테니 문제가 없을테고요

설마 원자적으로 값을 증가 시키질 못할 아키텍쳐를 가진 일반적인 컴퓨터는

존재 하지 않겠죠? [ 임베디드나 기타 안될거 같은 컴퓨터에서는 지원 안하면 되고요 ]

어차피 임베디드쪽에서 C++를 지원하긴 하는데 기능을 전부 지원 못하듯이요

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

ihavnoid의 이미지

mastercho wrote:
그건 아닌거 같네요

이걸 지원한다고 해서 단일 쓰레드에서 돌아가는 프로그램이

해가될 일은 없죠

어차피 이 코드를 단일 쓰레드 프로그램에서는 쓰이지 않을테니까요

또한 이런게 있으면 다양한 환경에서도 각각의 벤더들마다 알아서 각 컴퓨터에와 OS에 맞는 최적화된 방법으로 그 인터페이스를 구현할테니 문제가 없을테고요

설마 원자적으로 값을 증가 시키질 못할 아키텍쳐를 가진 컴퓨터는

존재 하지 않겠죠?

으음... 몇줄 추가해서 수정을 했는데.... 그새 리플을 다셨군요....
오늘 참으로 공부가 많이 될 듯 합니다... :) 덕택에 책과 문서를 많이 찾아보게 되는군요...

일단 원자적으로 증가시키질 못할 아키텍쳐를 위에 '하나'를 제시했습니다.. -0-
그리고 single-threaded임에도 불구하고, 인터럽트 신호에 의한 간섭이 일어날 수 있게 됩니다....

결국은 이런 데에서는 sync을 보장하려면 인터럽트 정지라는 방법밖에 없고, 이 방법을 이용하여 C에서 atomic operation을 구현할 경우 맘대로 인터럽트를 꺼버린다면...... -0-

C는 생각보다 다양한 환경에서 작동을 합니다.... OS가 전혀 없는 8비트 MCU부터 최첨단 기능이 내장된 OS가 작동하는 최신형 프로세서까지....

혹시 다른 아키텍쳐가 존재하는지 좀 찾아보겠습니다...
음.... 근래 나오는 32비트 이상의 프로세서에는..... 존재하지 않을 것 같습니다.

-- 수정하여 첨가 --

제 생각에는, 나오더라도 '확장 표준'으로 나오게 될 것 같습니다.
으음.... 뭔가 그냥 C스럽지 않다는 느낌이 들어서....-_-;;;

나름대로 조금 더 생각을 해 보았습니다......

무엇보다 현재 상황에서 문제제기를 하는 사람이 별로 없는 게 영향을 주는 게 아닐까 하는 생각입니다.... 일단, win32 등의 platform 입장에서 생각을 해 봤을 때, C 자체가 multithread을 standard로 갖고있지 않기 때문에, synchronization을 standard로 갖는다고 해서 큰 도움이 되지 않게 되지 않을까... 하는 생각딥니다..

임베디드 입장에서는 반대로, synchronization을 C에서 지원한다고 해도, 자기 platform과 사용 용도에 적합하게 알아서 인라인 어셈으로 코딩을 하게 될 것이라 생각됩니다. 뭐 아니면 RTOS 등에서 지원하는 sync. method을 이용하겠죠.

Consider the ravens: for they neither sow nor reap; which neither have storehouse nor barn; and God feedeth them: how much more are ye better than the fowls?
Luke 12:24

mastercho의 이미지

근데... 그러한 환경에서는 지원 안하면 되는것일텐데요

특히나 임베디드 같은 환경에서는 원래 지원안되는게 태반이라서

C가 지원된다고 모든게 일반적인 컴퓨터의 C처럼 잘 작동한다고 생각하지

않지 않나요? 따라서 그러한 환경에서는 당연히 지원 여부를 검토할테니

문제가 없을테고요....그리고 pthread 가 표준이긴 하지만 pthread에서

요구하는걸 완벽히 지원 못하는 OS도 있는걸로 압니다

따라서 ifdef로 지원 여부를 검토 할수 있고요

마찬가지가 아닐런지요 , 오히려 pthread보다 구현하기도 용의하거니와

요즘 컴퓨터에선 100% 구현이 될테니 더더욱 표준으로 지정할만 하다고 생각됩니다

단지 귀찬은건 벤더들이죠....

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

익명 사용자의 이미지

Quote:
There was a thread on the egcs list about this a few months
ago. GCC does not guarantee that incrementing a volatile will do it in
a single instruction, even if a single instruction is available.

The value won't be cached (mod. compiler bugs), but it may be loaded,
incremented and then stored. And the store may be deferred past other
non-volatile operations and function calls.

As we all know "incl" is not atomic between competing processors, but it
is atomic w.r.t. interrupts on the same processor as the increment.
Maybe that's why someone thought it was important.

저는 이글에서 컴파일러의 버그라고 부연설명한것에 대해서 부정적인
생각을 가지고 있습니다.

volatile 은 순차적 실행에 대해서만 메모리 접근에 대한 보장을 하면
충분한 지원이라고 생각합니다.
그것이 버그라고 예기할수 없다는 생각입니다.

시간에 의한 비순차적 실행시점(interrrupt)에 대해서 까지 고려한 코드를
생성하는 것에 대해서는 지나친 컴파일러 지원인것 같습니다.
오히려 그때문에 최적화가 방해 받을수 있지 않을까라는 생각을 해봅니다.

보통 "똑똑한 gcc"라고 하는 문구를 여러 사이트에서 자주 찾을수 있었는데요.
맞는 말인거 같습니다. 정말로 그 말에 절대적인 찬사를 안할수가 없습니다.

gcc는 최적화 정책(?) 중에서 메모리 조작(접근이 아님)에 대해서는
되도록 register를 통하여 메모리 버스를 최소화(cache) 한다는 글을 본적이 있습니다.
(아~ 슬프도다 이것또한 증거 제출 못합니다. 정말로 저는 검색 되게 못합니다.)

때문에 jiffies++ 는
movl jiffies, %eax
incl %eax /* 위분이 말씀하신것처럼 VC에서는 add eax, 1 */
movl %eax, jiffies
라는 코드가 생성되는것 같습니다.

그리고 이것은 시간의 흐름에 끼어들기가 없는 한도에서는 정말로
훌륭한 코드임이 맞는것 같습니다.

하지만 이것은 전역변수 (외부에서 읽기 및 쓰기를 시도하는)에 대해서
시간의 흐름제어가 수행되는 경우 약간은 부정적 결과를 얻을수 있겠습니다.

단지 시간의 순차적 흐름에 대한 실행에 대해서는 volatile은 보장되는 것이
반드시 필요하지만 그렇지 않은 경우는 개발자가 신경써야할 몫인것 같습니다.

글 적다보니 이런 생각 드네요.
이거 다른 쓰레드로 글올려야 하는것인가?

sliver의 이미지

mastercho wrote:
(*(unsigned long *)&jiffies)++; 코드는 무의미하군요

단지 gcc 컴파일러의 버그성 트릭을 이용한거에 불과하네요

특히 incl이 다중 프로세서에서 원자성을 보장 못하고...

단일 CPU 환경하에 , gcc 컴파일러 만든 사람이 커널을 짠건지..

쩝....

unix에서도 원자성으로 값을 증가 시키는 함수가 얼렁 표준화 되서

나와야 겠습니다.....

[개인적으로 표준적인게 아니면 영 그렇네요...
각 컴퓨터마다 OS마다 컴파일러마다 ,제각각인 코드는....]


(*(unsigned long *)&jiffies)++;

이 코드가 "원자성"을 위한 트릭이 아닙니다. 원자성과는 아무런 관련이 없습니다.

저렇게 하면 아주 약간 더 빠른 코드가 생성된다는 것 외에는 jiffies++;와 차이점이 없습니다.

mastercho의 이미지

Quote:
Andrea Arcangeli wrote:
> >(*(unsigned long *)&jiffies)++;
> >
> >why not just jiffies++; ? It works fine with jiffies++ but I assume there
> >is a reason...
>
> No reason. It won't make any difference.
>
> You could as well do jiffies++. jiffies is volatile so it can't be
> reodered across other `;' and it won't be cached into registers.

There was a thread on the egcs list about this a few months
ago. GCC does not guarantee that incrementing a volatile will do it in
a single instruction, even if a single instruction is available.

The value won't be cached (mod. compiler bugs), but it may be loaded,
incremented and then stored. And the store may be deferred past other
non-volatile operations and function calls.

As we all know "incl" is not atomic between competing processors, but it
is atomic w.r.t. interrupts on the same processor as the increment.
Maybe that's why someone thought it was important.

But as Andrea says:
> The only "jiffies" writer is the timer irq handler that as an irq handler
> is single threaded by the linux irq design. So there's no point at all to
> even think about atomicity.

So jiffies++ would be fine.

-- Jamie

위글은 토론에 대한 방준영님 달글에서 나온 문서고요
토론을 보면 분명 incl의 원자성에 관 이야기도 나오고
해서 그렇게 쓴겁니다 -_-;

Quote:
이 코드가 "원자성"을 위한 트릭이 아닙니다. 원자성과는 아무런 관련이 없습니다.
저렇게 하면 아주 약간 더 빠른 코드가 생성된다는 것 외에는 jiffies++;와 차이점이 없습니다.

근데 위에 말씀은 여태 나온 내용에 상반되는 말같은데요?
제가 여태 착각한건지??

레지스터에서 케쉬가 되는쪽이 더 빠른거 아닐런지요?
저코드에서 인해 원자성이 논해지고 있었는데... 영 완전 제가 헛다리집은건지....쩝

추가로...-------------------------

생각해보니 좀 어이없는 생각이 듭니다
저코드로 원자성을 논하고 있던 사람들은 전부 바보가 된듯한 느낌이군요

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

익명 사용자의 이미지

자, 이번엔 gcc 메일링 리스트에 무슨 얘기가 오갔는지 살펴 봅시다 8) :
http://www.google.co.kr/search?q=cache:PaenX_ZWIjgJ:web.gnu.walfield.org/mail-archive/linux-kernel/1999-December/0005.html+volatile+gcc+single+instruction&hl=ko&ie=UTF-8

결론적으로 말씀드리면,
(*(unsigned long *)&jiffies)++; /* 1번 */
는 gcc의 코드 생성 특성을 이용한 꽁수입니다. 왜냐하면,
jiffies++; /* 2번 */
가 단일 명령을 생성하리라고 보장할 수 없는 것처럼, 1번 코드 역시 단일 명령을 생성하리라고 보장할 근거는 어디에도 없기 때문입니다. 컴파일러에 따라 1번 코드를 아래와 같이 컴파일할 가능성도 충분히 있습니다:

movl 0xc0ff03a0,%eax	/* jiffies의 주소를 %eax에 대입 */
incl (%eax)		/* 간접 증가 */

따라서 이것은 전적으로 정의되지 않은 동작입니다. 전웅님 말씀이 맞죠.

그런데, 이 코드를 짠 사람이 해봤더니, 1번으로 하면 단일 명령으로 컴파일 안되고, 2번을 쓰면 되더라~한 겁니다. gcc말고 다른 컴파일러를 쓰면? 난 그건 모르겠다, 후다닥~한 겁니다. 8)

sliver의 이미지

그 답글은 volatile이 원자성과는 상관이 없다는 내용입니다.

그리고 당연히 레지스터에 캐쉬되는게 더 빠르죠^^;

volatile unsigned long jiffies;이기 때문에

그냥 jiffies++ 이렇게 하게 되면,

jiffies가 volatile이기 때문에 jiffies에서 한 번 읽고, 또 jiffies에 한번 써야 한다는

조건이 생깁니다.

movl jiffies, %eax
incl %eax
movl %eax, jiffies

따라서 이런 코드나 비슷한 코드로 컴파일 될 수 밖에 없지만,

(*(unsigned long *)&jiffies)++; 이렇게 하면

이제 volatile이 아니기 때문에 컴파일러는

incl jiffies 이렇게 컴파일 "할 수도" 있습니다.

즉, 단지 기대할 뿐이죠..gcc가 jiffies++보다는 빠른 코드(원자성을 보장하는 코드가 아닌)를 생성하기를 말이죠.

익명 사용자의 이미지

mastercho wrote:
생각해보니 좀 어이없는 생각이 듭니다
저코드로 원자성을 논하고 있던 사람들은 전부 바보가 된듯한 느낌이군요

원자성이란 말은 약간 어폐가 있지만, 아무튼 원자성 비스무레하게 구현하려고 한 것(=단일 명령)은 맞습니다. 물론, 코드 최적화와는 정말 아무 상관이 없습니다. 8)
익명 사용자의 이미지

sliver wrote:
(*(unsigned long *)&jiffies)++; 이렇게 하면

이제 volatile이 아니기 때문에 컴파일러는

incl jiffies 이렇게 컴파일 "할 수도" 있습니다.

즉, 단지 기대할 뿐이죠..gcc가 jiffies++보다는 빠른 코드(원자성을 보장하는 코드가 아닌)를 생성하기를 말이죠.


그걸 기대했더라면 처음부터 jiffies를 volatile로 선언 안하면 되죠.

그리고 이게 코드 최적화와 아무 상관이 없는 이유는 sched.c에 보면

1548 void do_timer(struct pt_regs * regs)
1549 {
1550         (*(unsigned long *)&jiffies)++;
1551         lost_ticks++;
1552         mark_bh(TIMER_BH);
1553         if (!user_mode(regs))
1554                 lost_ticks_system++;
1555         if (tq_timer)
1556                 mark_bh(TQUEUE_BH);
1557 }

라고 되어 있는데, 당연히 여기서 명령 한두개 줄인다고 성능이 빨라지는 것과는 상관이 없습니다. 그걸 기대했더라면 아래 lost_ticks++에도 왜 똑같은 꽁수를 안썼을까요?
sliver의 이미지

방준영 wrote:
sliver wrote:
(*(unsigned long *)&jiffies)++; 이렇게 하면

이제 volatile이 아니기 때문에 컴파일러는

incl jiffies 이렇게 컴파일 "할 수도" 있습니다.

즉, 단지 기대할 뿐이죠..gcc가 jiffies++보다는 빠른 코드(원자성을 보장하는 코드가 아닌)를 생성하기를 말이죠.


그걸 기대했더라면 처음부터 jiffies를 volatile로 선언 안하면 되죠.

volatile로 선언해야 합니다.

writer는 timer인터럽트 핸들러 함수인 do_timer밖에 없으므로

원자성을 보장하지 않아도 되지만,

reader입장에서는 언제 do_timer가 jiffies를 수정할지 모르므로

jiffies변수를 접근할때마다 실제로 메모리에서 읽어와야 합니다.

mastercho의 이미지

실제 메모리에서 읽어와야 한다는건

동기화 즉 원자성과도 관련이 있는게 아닌가요?

위에 문서를 토대로 보면 incl이 다중 프로세서에서 동기화를 보장해주지 못하기때문에
저 코드는 잘못된게 아닌지요?

설마 단일 프로세서에서만 돌아가기위한 커널을 만든건 아닐텐데...

헷갈려서 .... 필요없는 말은 줄여야 겠네요 --;

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

sliver의 이미지

mastercho wrote:
실제 메모리에서 읽어와야 한다는건

동기화 즉 원자성과도 관련이 있는게 아닌가요?


원자성은 어떤 작업을 하는데 그 작업을 다른 쓰레드가 끼어들면 안된다는 것을 뜻합니다.

예를 들면, 어떤 메모리 변수의 값을 atomic하게 1 증가시키려면(SMP머신 포함)

lock incl var

이런걸 뜻하는 말입니다.

어떤 변수에 접근할 때마다 실제로 메모리에서 읽어와야 한다는 것은 원자성과는 상관이 없구요..

mastercho wrote:

게다가 incl이 다중 프로세서에서 동기화를 보장해주지 못하기때문에
저 코드는 잘못된게 아닌지요?

설마 단일 프로세서에서만 돌아가기위한 커널을 만든건 아닐텐데...


어떤 irq에 대한 인터럽트 핸들러는 SMP머신의 여러 CPU중 하나에서만

수행됩니다. (여기에서 "하나"란 "특정한"이 아니고 단지 1개를 뜻합니다)

따라서 원자성같은건 필요가 없죠..

만약 (말이 안되긴 하지만) 여러 CPU에서 타이머 인터럽트 핸들러가 동시에

수행된다면 님 말씀대로 원자적으로 해야하죠.. lock incl jiffies 이렇게요.

익명 사용자의 이미지

일단 소스를 좀더 자세히 봤는데요.

음....

일단 jiffies가 증가하기전에 이미 인터럽트는 금지된 상태에서
do_timer가 빠르게 수행되기를 원했던거더군요.

그리고 어차피 jiffies는 매번 갱신되어야 하므로
단일명령으로 수행되는게 보다 빠를수 있는것은 맞는듯 합니다.
어차피 쓰기만을 행하는 유일한 곳이기에 ...

그리고 SMP상황이라도
jiffies에 의해서 각 processor가 동기화를 이뤄야 되기 때문에
구성상 별 문제 없어 보이네요.
어차피 이 jiffies수정영역은 하나의 processor만이 유일한 시간을 가지기 때문일려나?

즉, 단일명령이 여기서는 오히려 좋을거 같습니다.
반드시 그럴거 같지는 않지만 "좀더 좋을지도" 라는 수식어가 붙어야 겠네요.

즉, jiffies++ 이렇게 해도 충분히 시스템은 잘 돌아간다는 것입니다.
그리고 진짜로 나중에는 그렇게 될지도 모르겠군요...
왜냐하면 jiffies로 인하여 476일정도후에 overflow당하기 때문에
분명 수정이 이뤄질 부분일거 같네요.
(아직 2.5.x이후 커널은 제가 소스를 한번도 못봤습니다.)

제 생각의 결론은 그런 코드를 사용한 이유인즉
그냥 "좀거 좋을지도" 라는 또는 "손해볼거 없으면서 뭔가 좋을듯" 이라는
생각에서 개발자가 그런 코드를 만든것으로 생각합니다.

아~ 좀더 머리좀 굴려봐야 겠는데
도저히 제가 납득할수 있는 수준은 여기까지군요.

다덜 잠도 안자고 뭐하시는거예요?
저도 덩달아 잠 안오네요...
자야 되는데...

익명 사용자의 이미지

혹시나 해서 코드를 짜봤더니 흥미로운(?) 결과가 나왔습니다. 코드는 다음과 같습니다:

volatile unsigned long jiffies; 

main() 
{ 
   (*(unsigned long *)&jiffies)++; 
   printf("%d\n", jiffies); 
} 

그런데 이걸 gcc -O로 컴파일했더니 결과가
incl _jiffies
이 되었고, gcc -O2와 -O3으로 컴파일했더니

movl    _jiffies, %edx 
incl    %edx 
movl    %edx, _jiffies 

가 나왔습니다. 두번째 결과는 jiffies++와 똑같네요. 버전은 MinGW 3.2.3 입니다.

결국 같은 컴파일러에서도 최적화 옵션에 따라(그리고 부근에 있는 코드의 모양에 따라서도) 의도한 결과가 나왔다가 안나왔다가 하는 거죠. 따라서 리눅스 커널을 -O2 이상으로 컴파일한다면
(*(unsigned long *)&jiffies)++;
은 하나마나한 일이 될(즉, jiffies++와 코드가 똑같이 생성될) 가능성이 높다고 하겠습니다. 물론 -O로 컴파일해도 버전이나 아키텍쳐별로 무슨 결과가 나올지는 예측 불가능합니다.

최종 결론은 "꽁수를 쓰지 말자!"

mushim의 이미지

kernel 2.2.5 에서 gcc 2.91.66 으로 테스트 해보았습니다.
최적화 옵션은 -O, -O2, -O3 를 주었는데 결과는 같았습니다.

void do_timer(struct pt_regs * regs)
{
        (*(unsigned long *)&jiffies)++;  
        lost_ticks++;
        mark_bh(TIMER_BH);
        if (!user_mode(regs))
                lost_ticks_system++;
        if (tq_timer)
                mark_bh(TQUEUE_BH);
}

jiffies++; 인 경우
        pushl %ebp
        movl %esp,%ebp
        movl jiffies,%eax
        incl %eax
        movl 8(%ebp),%edx
        movl %eax,jiffies
        movl lost_ticks,%eax
        incl %eax
        movl %eax,lost_ticks
        xorl %eax,%eax
        ... 이하 생략

(*(unsigned long *)&jiffies)++; 인 경우,
        pushl %ebp
        movl %esp,%ebp
        movl lost_ticks,%eax
        incl %eax
        movl 8(%ebp),%edx
        incl jiffies
        movl %eax,lost_ticks
        xorl %eax,%eax
        ... 이하 생략

공통적으로 다음과 같은 reordering 이 일어났습니다.
        movl jiffies,%eax
        incl %eax
        movl 8(%ebp),%edx
        movl %eax,jiffies

*) volatile 인 경우는, 이런 경우도 막아주어야 하지 않나요.

(*(unsigned long *)&jiffies)++; 인 경우는 movl lost_ticks,%eax 가 맨위로 올라가버렸군요.
아무래도, silver 님 말처럼 volatile 제한을 없앨테니 힘닿는데까지 한번 최적화를 해봐라, 이런 뜻에서 하지 않았을까 생각되네요.

girneter의 이미지

저같이 무식한 사람은 고수님들의 말씀에
머리가 터질것만 같군요.
용기를 내 정리하면

1.
jiffies 는 volatile 로 선언해야 한다.
writer는 timer인터럽트 핸들러 함수인 do_timer밖에 없으므로
원자성을 보장하지 않아도 되지만,
reader입장에서는 언제 do_timer가 jiffies를 수정할지 모르므로
jiffies변수를 접근할때마다 실제로 메모리에서 읽어와야 합니다.

2.
그냥 jiffies++ 이렇게 하게 되면,
jiffies가 volatile이기 때문에 jiffies에서 한 번 읽고, 또 jiffies에 한번 써야 한다는
조건이 생깁니다.

movl jiffies, %eax
incl %eax
movl %eax, jiffies 

3.
그런데 어차피 jiffies 의 값을 변화시키는 것은
do_timer 밖에 없으므로
단일 명령으로 컴파일 되면 더 좋겠다는 생각이 든다.

incl _jiffies

4.
그러기 위해 jiffies 의 volatile 속성을 잠시 없애기 위해

(*(unsigned long *)&jiffies)++;

와 같이 한다.

5.
그러나 이건 어디까지나 희망사항일 뿐
4번과 같이 하더라도 컴파일 환경에 따라
2번처럼 될 수도 있다.

6.
do_timer 에 들어오기 전에 이미 인터럽트는 금지된 상태이므로
2번이든 3번이든 원자성과는 아무런 상관없다.
SMP 라 하더라도
어떤 irq에 대한 인터럽트 핸들러는 SMP머신의 여러 CPU중 하나에서만
수행됩니다. (여기에서 "하나"란 "특정한"이 아니고 단지 1개를 뜻합니다)
따라서 원자성같은건 필요가 없죠.

======================================

위와 같이 정리한게 맞나요? :oops:

개념없는 초딩들은 좋은 말로 할때 DC나 웃대가서 놀아라. 응?

익명 사용자의 이미지

그런데 왜 갑자기 최적화 얘기가 나왔는지 모르겠습니다. 이 문제는 그냥 volatile 제한을 피해가려는 목적이지 최적화와는 관계없습니다. 함수에 스택 프레임이 살아있고, lost_ticks++가 3명령으로 컴파일된 것으로도 알 수 있죠.

익명 사용자의 이미지

sliver wrote:
volatile로 선언해야 합니다.

writer는 timer인터럽트 핸들러 함수인 do_timer밖에 없으므로

원자성을 보장하지 않아도 되지만,

reader입장에서는 언제 do_timer가 jiffies를 수정할지 모르므로

jiffies변수를 접근할때마다 실제로 메모리에서 읽어와야 합니다.


말씀 자체는 맞지만, volatile을 그런 용도로 사용하는 것은 편법입니다. 정상적으로 프로그램을 짜려면 spl을 조절해 줘야죠. 또는 rwlock을 걸어서 읽는 동안 값이 못바뀌게 제한을 한다든가요.
mushim의 이미지

제 뜻은, do_timer 함수 코드를 최적화 옵션을 주어서 컴파일 할때, (*(unsigned long *)&jiffies)++; 인 경우와 jiffies++; 인 경우가 서로 다른 어셈블리 코드를 만든 다는 뜻이죠.

위의 경우는, 특별히 더 최적화 된것은 아니지만, 의도자체는 그랬을것 같다고 추정된다는 것이죠.

참고로 아래 코드를 -O2 옵션으로 컴파일하게 되면, volatile 을 무시했을 경우 좀 더 최적화 된다는 것을 알수 있습니다.

extern int jiffies1;
extern int volatile jiffies2;

void func1(void)
{
  jiffies1++;
  jiffies2++;

  jiffies1 = jiffies2;
}

void func2(void)
{
  (&(int *)jiffies1))++;
  jiffies2++;

  jiffies1 = jiffies2;

}

func1:
        movl    jiffies2, %eax
        incl    %eax
        pushl   %ebp
        movl    %eax, jiffies2
        movl    jiffies2, %eax
        movl    %esp, %ebp
        movl    %eax, jiffies1

func2:
        pushl   %ebp
        incl    jiffies2
        movl    jiffies2, %eax
        movl    %esp, %ebp
        movl    %eax, jiffies1
girneter의 이미지

머리를 쥐어짜서 겨우 정리했는데
방준영님이 또 아니라 하시네요.
흠~~~

그러믄요, volatile 에 대해 조금만 더 갈쳐 주실래요?

1. 최적화와는 관계없이 volatile 제한을 피한다고 했는데
무슨 제한을 피한다는 거지요?

2. 저는 do_timer 가 언제 jiffies 를 수정할 지 모르니까
memory 로부터 읽어오라는 뜻에서 volatile 을 쓰는걸로
알고 있었는데, 그런 용도가 아니라면
jiffies 를 volatile 로 선언하는 용도가 뭔가요?

3. rwlock 을 건다는건 lock 의 일종으로 알아먹겠는데,
spl 을 조절하는건 또 뭐에요?

개념없는 초딩들은 좋은 말로 할때 DC나 웃대가서 놀아라. 응?

전웅의 이미지

mastercho wrote:
그럼.....

C 표준에서, 원자성으로 증가 시키는 함수가 나올 예정에 없는지요?

signal 과 관련하여 원자적으로 접근할 수 있는 type (sig_atomic_t) 과 구
체적인 방법 (static storage duration + volatile + sig_atomic_t) 은 보
장되어 있습니다. 하지만, sig_atomic_t 는 어디까지나 "(async) signal 과
관련된 접근" 에 대해서만 보장되어 있을 뿐 (물론, 각 implementation 이
확장으로 추가적인 의미를 부여할 수는 있습니다), multi-thread 나 shared
-memory 같은 다른 문맥에서도 안전성이 보장된다고 보기는 어렵습니다 (현
실적으로는 다른 이야기가 가능하지만, C 표준의 엄격한 해석에 따르면 그
렇습니다).

하지만, 어떤 추상적인 단위 (값의 증가, 감소 등등) 의 한 연산이 원자적
으로 수행된다고 보장되는 type 이나, 원자적인 연산을 보장하는 함수 혹은
특수한 연산자 등은 존재하지 않습니다. 그리고 가까운 미래에도 보기 어려
울 것 같습니다. C 표준은 multi-thread 나 shared-memory 는 고려하고 있
지 않습니다 - 아예 고려하고 있지 않은 상황을 부분적으로 배려하는 것 자
체가 모순됩니다. 또한, POSIX 같은 ISO 수준의 다른 표준이 관련된 내용을
기술하기에 그와 같은 시도는 (부분적 지원이든 그렇지 않든 혹은 결핍된
기존 implementation 에게 부담을 주든 그렇지 않든) 다른 표준의 scope 를
침범하는 C 표준의 월권행위가 될 수도 있습니다.

minzkn wrote:
저는 이글에서 컴파일러의 버그라고 부연설명한것에 대해서 부정적인
생각을 가지고 있습니다.

volatile 은 순차적 실행에 대해서만 메모리 접근에 대한 보장을 하면
충분한 지원이라고 생각합니다.
그것이 버그라고 예기할수 없다는 생각입니다.

해당 글은 gcc 의 버그에 대해서 이야기하고 있는 것은 아닙니다.

Quote:
The value won't be cached (mod. compiler bugs), but it may be loaded,
incremented and then stored. And the store may be deferred past other
non-volatile operations and function calls.

이 글은, voaltile 로 선언된 대상체를 ++ 연산할 때 (컴파일러에 버그가
있는 것이 아니라면 - "mod." 는 "modulo" 를 의미하며 "~인 상황을 제외하
면" 정도로 이해할 수 있습니다) register 로 cache 되지 않으며,
(in-memory incl 가 아닌) load/incl/store 의 작업이 이루어질 수 있다고
이야기하고 있습니다. 문제는 마지막 증가된 값을 저장하는 작업이 다른
non-volatile 연산이나 (해당 volatile 연산에 전혀 영향을 주지 않는) 함
수 호출에 의해 미루어질 수 있다는 것입니다. 마지막 문장은 이렇게 이해
할 수 있습니다:

extern volatile int i;
int j, s;

i++;
i--;

for (j=0, s=0; j < 10; j++) s += j;

i 가 volatile 이기에 i 에 발생하는 추가적인 side effect 를 컴파일러가
알 수 없다면 (i 에 대해서) 주어진 연산을 함부로 reordering 하거나 최적
화 (예를 들면, i++; i--; 를 묶어서 제거해 버리는 등) 하지 못하고 C 프
로그램이 명시하는 (i++; i--; 에 대한) 행동을 있는 그대로 따라 번역해야
함을 의미합니다. 하지만, 이러한 사실이 모든 경우에 i++ 에 대해서 다음
과 같이 목적 코드를 생성하는 것을 금지하는 것은 아닙니다.

load i into r1
increment r1
[*]
store r1 into i

load i into r1
decrement r1
store r1 into i

[*] 부분에 상당히 긴 시간의 무의미한 delay 가 주어질 수도 있고, 이 프
로그램의 다른 코드가 우선적으로 실행될 수도 있습니다 (다른 thread 가
실행될 수 있음은 너무도 당연한 이야기입니다). 즉,

load i into r1
increment r1
[아래의 for 문 수행]
store r1 into i

도 가능합니다. 이는 표준이 최소한으로 명시하는 volatile 에 대한 요구를
모두 만족한다는 점에서 적법한 reordering 입니다. 물론, reordering 되어
[*] 부분에서 수행되는 같은 프로그램의 코드가 reordering 되지 않았을 경
우에 얻게 되는 i 에 대한 side effect 에 (결국, 최종적인 프로그램의 결
과에) 영향을 주는 경우, 당연히 해당 reordering 은 허락되지 않을 것입니
다. 다시 말하면, 표준이 명시하는 (따라서 비표준적인 확장을 사용하지 않
는) C 프로그램이 그와 같은 reordering 으로 인한 차이를 보일 수 없다면
앞서 보인 형태의 reordering 이 허락된다는 것입니다. 이는

mushim wrote:
공통적으로 다음과 같은 reordering 이 일어났습니다.
        movl jiffies,%eax 
        incl %eax 
        movl 8(%ebp),%edx 
        movl %eax,jiffies 

*) volatile 인 경우는, 이런 경우도 막아주어야 하지 않나요.

에 대한 답이 됩니다.

하지만,

Quote:
> The only "jiffies" writer is the timer irq handler that as an irq handler
> is single threaded by the linux irq design. So there's no point at all to
> even think about atomicity.

이기 때문에 이 경우에는 jiffies++ 만으로도 충분하다는 뜻입니다. 즉,
jiffies 가 load/incl/store 로 수행되는 경우 위와 같은 reordering 의 가
능성을 고려하더라도 jiffies 가 증가되는 특수한 문맥 (do_timer 에 의해
서만 증가되며 다른 thread 나 processor 에 의한 간섭의 가능성이 없음)
이 jiffies++ 도 의도한대로 충분한 품질의 결과를 보여줄 것이라는 내용이
요점입니다.

minzkn wrote:
gcc는 최적화 정책(?) 중에서 메모리 조작(접근이 아님)에 대해서는
되도록 register를 통하여 메모리 버스를 최소화(cache) 한다는 글을 본적이 있습니다.
(아~ 슬프도다 이것또한 증거 제출 못합니다. 정말로 저는 검색 되게 못합니다.)

때문에 jiffies++ 는
movl jiffies, %eax
incl %eax /* 위분이 말씀하신것처럼 VC에서는 add eax, 1 */
movl %eax, jiffies
라는 코드가 생성되는것 같습니다.

gcc 의 다른 최적화 정책은 모르겠습니다만, 이 문제의 경우 gcc 가
volatile 대상체를 ++ 할 때도 분명 in-memory incl 를 사용할 수 있으면서
도 다음과 같은 걱정 때문에 그러지 못한다는 것입니다.

x86 에서는 우연히 in-memory incl 와 load/incl/store 가 동등한 의미를
갖기에 volatile 로 한정된 대상체의 증가를 in-memory incl 로 다루는 것
이 어떠한 차이도 낳지 않습니다. 하지만, x86 처럼 in-memory incl 명령어
를 가지고 있지만 그 명령의 의미가 load/incl/store 와는 다른 환경의 가
능성을 배제할 수 없기에, volatile 대상체의 증가에 대해 그처럼 안전한
(그야말로 ++ 의 의미 그대로를 보이는) 목적 코드를 선택했다는 뜻입니다.
즉, 단일 in-memory incl 명령을 갖는 x86 이 아닌 아키텍쳐에서
load/incl/store 와 in-memory incl 의 의미가 동등하지 않은 경우, i++ 수
식의 추상적인 의미에 일치하는 load/incl/store 는 욕먹을 일이 없겠지만,
in-memory incl 의 선택은 gcc 가 표준을 따르지 않는다고 비난받을 가능성
이 있다는 것입니다. 제 개인적인 해석으로는 표준은 volatile 대상체에 접
근하는 행위가 구체적으로 어떤 의미를 갖는지는 각 implemenation 이 상세
히 정의한다고 밝히고 있으므로, (implementation 의 일부분을 구성하는)
gcc 의 걱정이 다소 기우라는 생각이 들기는 합니다. 하지만, gcc 로서는
골치 아프지 않게 가장 마음 편안한 방법을 선택한 것으로 보입니다 - 저라
도 그렇게 했을 것입니다. ;-)

이 문제는 방준영님 말씀대로 gcc 가 구체적으로 어떤 코드를 생성해 주느
냐에 의존한 것입니다. load/incl/store 가 왜 그리 못마땅했는지 모르겠지
만, (위의 인용된 글에서 아래와 같은 추측이 있습니다만

Quote:
As we all know "incl" is not atomic between competing processors, but it
is atomic w.r.t. interrupts on the same processor as the increment.
Maybe that's why someone thought it was important.

이 역시 do_timer 가 실행되는 특수한 문맥에서는 쓸모없는 걱정임에 분명
합니다) 분명 해당 부분의 개발자는 jiffies++ 에 대해서 in-memory incl
를 쓰고 싶었나 봅니다. 하지만, gcc 의 위와 같은 정책 때문에 volatile
한정이 유효한 상태에서는 그것이 불가능했고, 이를 아키텍쳐 독립적인 방
법으로 피해가는 방법을 찾다가 *& hack 를 사용하게 된 것입니다.

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

익명 사용자의 이미지

girneter wrote:
1. 최적화와는 관계없이 volatile 제한을 피한다고 했는데
무슨 제한을 피한다는 거지요?

제한을 피한다고 쓰고 보니 어폐가 있군요. gcc가 volatile 변수를 3명령으로 컴파일하는 "문제"를 피해간다는 뜻이었습니다.

Quote:
2. 저는 do_timer 가 언제 jiffies 를 수정할 지 모르니까
memory 로부터 읽어오라는 뜻에서 volatile 을 쓰는걸로
알고 있었는데, 그런 용도가 아니라면
jiffies 를 volatile 로 선언하는 용도가 뭔가요?

위에 썼다시피 그 말씀 자체는 맞는데요, 그렇게 하면 부수 효과(side effect)를 예상할 수 없는 경우가 생기기 때문에 옳은 프로그래밍 방법이 아니라는 겁니다. 저라면 volatile으로 쓰는 것 대신
unsigned long
get_jiffies(void)
{
	return jiffies;
}

void
increment_jiffies(void)
{
	jiffies++;
}

처럼 함수로 만들어 쓰겠습니다. 필요하다면 뒤의 increment_jiffies()는 어셈블리로 고쳐써서 원자 연산으로 바꿀 수도 있겠죠.

Quote:
3. rwlock 을 건다는건 lock 의 일종으로 알아먹겠는데,
spl 을 조절하는건 또 뭐에요?

인터럽트 레벨을 올려서 reader가 jiffies값을 읽을 때 do_timer()가 중간에 끼어들지 못하도록 한다는 의미입니다. 음... 그런데 이렇게 하면 또다른 부수 효과가 여러가지로 발생할 수 있으므로 적절한 방법이 아니군요. 토론을 짧게 유지하기 위해 spl은 없었던 얘기로 해주세요. 8)
전웅의 이미지

girneter wrote:
1.
jiffies 는 volatile 로 선언해야 한다.
writer는 timer인터럽트 핸들러 함수인 do_timer밖에 없으므로
원자성을 보장하지 않아도 되지만,
reader입장에서는 언제 do_timer가 jiffies를 수정할지 모르므로
jiffies변수를 접근할때마다 실제로 메모리에서 읽어와야 합니다.

예, volatile 만으로는 해결할 수 없는 다른 잠재적인 문제를 배제한다면
일단은 그와 같은 이유로 volatile 로 선언된 것으로 볼 수 있습니다.

girneter wrote:
2.
그냥 jiffies++ 이렇게 하게 되면,
jiffies가 volatile이기 때문에 jiffies에서 한 번 읽고, 또 jiffies에 한번 써야 한다는
조건이 생깁니다.

"읽고/연산하고/쓰고" 처럼 매우 구체적으로 명시되어 있지는 않습니다.
volatile 로 선언된 대상체에 대한 접근이 implementation 에 의존하기 때
문에 충분히 달라질 수 있는 이야기지만 (아래 예), 보다 유연한 형태로 동
등한 semantic 을 만족시키는 것도 가능합니다 - 예를 들어, volatile 대상
체의 증가 연산에 대해 x86 에서 load/incl/store 대신 in-memory
operation 을 선택하는 것도 (동등한 의미를 갖기에) 전혀 상관 없습니다.

하지만, 예를 들어 어떤 implementation 에서 특정 volatile 대상체에
load, store 로 접근하는 횟수가 count 되고, in-memory incl 이
load/incl/store 와 다른 count 횟수 (1 이라고 가정) 를 가지며, 그 count
횟수가 다른 volatile 대상체를 통해 프로그램의 결과에 영향을 줄 수 있다
면,

extern volatile int i;

i++;

에 대해 (2회의 count 를 갖는) load/incl/store 대신 (1회의 count 를 갖
는) in-memory incl 를 선택하는 것이 유효한 차이를 보일 수 있습니다.
gcc 가 구체적으로 어떤 상황을 표준의 해석과 문제를 일으킬 수 있는 상황
으로 고민했는지 모르겠지만, 제 개인적인 해석으로는 어느 쪽을 선택하든
지 표준이 요구하는 최소한의 요구 (volatile 로 한정된 대상체와 관련된
수식을 잘못된 결과를 보이도록 최적화하지 않고, 각 sequence point 끝에
서 해당 대상체의 값을 분명히 하고 등등) 를 만족한다면, volatile 대상체
를 접근하는 행위가 구체적으로 어떤 결과를 보이는지를 제대로 document
한다면 둘 다 적법한 선택이라 생각합니다. 하지만, volatile 과 관련된 이
와 같은 문제에 대해서는 조금 더 고민을 해봐야 할 것 같습니다 -
volatile 이 사용된 아주 간단한 프로그램을 놓고도 표준화 위원회 멤버들
사이에서도 서로 다른 소리가 나올 정도로 많은 혼란이 있는 부분입니다.

girneter wrote:
3.
그런데 어차피 jiffies 의 값을 변화시키는 것은
do_timer 밖에 없으므로
단일 명령으로 컴파일 되면 더 좋겠다는 생각이 든다.

do_timer 가 놓인 특수한 상황에 의해 atomicity 는 현재 논의 중인 문제와
아무런 관련이 없습니다. 그리고, 해당 개발자가 왜 load/incl/store 를 그
런 트릭을 사용해가면서까지 피했는지 저로서는 불분명합니다. 아마도 incl
이 SMP 에서는 안전하지 않더라도 최소한 interrupt 에 대해서는 안전하다
는 생각으로 (혹은 습관으로?) incl 을 선택한 것 같지만, 이 역시 해당 문
맥에서 문제가 되는 부분은 아닙니다. 만약, 개발자가 "나로서는 단일 명령
인 in-memory incl 이 더 깔끔해서 좋더라. kernel 은 어차피 gcc 로 컴파
일하고 gcc 가 내가 원하는 바대로 결과를 보이는데 무슨 걱정이 있겠느냐?"
라고 말한다면 할 말은 없습니다. 하지만, 다른 "좋은" 이유를 기대하기는
어렵지 않을까 추측해 봅니다.

girneter wrote:
4.
그러기 위해 jiffies 의 volatile 속성을 잠시 없애기 위해

(*(unsigned long *)&jiffies)++;

와 같이 한다.

이유는 불분명하지만 load/incl/store 가 아닌 in-memory incl 를 생성시키
기 위해 *& hack 을 사용한 것은 틀림없습니다.

girneter wrote:
5.
그러나 이건 어디까지나 희망사항일 뿐
4번과 같이 하더라도 컴파일 환경에 따라
2번처럼 될 수도 있다.

현재 gcc 에 대해서는 맞습니다. 하지만, 만약 논의를 gcc 가 아닌 일반적
인 C 컴파일러로 확장한다면, 정의되지 않은 행동이기에 어떠한 결과도 가
능합니다 - 컴파일이 실패해도 상관 없습니다.

girneter wrote:
6.
do_timer 에 들어오기 전에 이미 인터럽트는 금지된 상태이므로
2번이든 3번이든 원자성과는 아무런 상관없다.
SMP 라 하더라도
어떤 irq에 대한 인터럽트 핸들러는 SMP머신의 여러 CPU중 하나에서만
수행됩니다. (여기에서 "하나"란 "특정한"이 아니고 단지 1개를 뜻합니다)
따라서 원자성같은건 필요가 없죠.

맞습니다.

그리고,

girneter wrote:
머리를 쥐어짜서 겨우 정리했는데
방준영님이 또 아니라 하시네요.

방준영님의 말씀은 volatile 이 jiffies 에 접근할 때 발생하는 모든 문제
를 해결해 주는 방법은 아니라는 뜻입니다.

다시 정리하자면, do_timer 가 있는 문맥은 atomicity 와는 무관한 문맥입
니다. 따라서, 개발자가 어떤 atomicity 를 위해서 in-memory incl 를 고집
했다면 이는 개발자의 실수라 볼 수 있습니다. 물론, 더 나은 성능을 위해
서 in-memory incl 를 고집했다고 생각할 수도 있습니다만, 개인적으로 그
것이 진정한 이유라고 생각하지는 않습니다 - 오히려 개발자의 실수나 습관
에서 비롯된 것이라 보고 있습니다. 저로서도 그 "진정한" 이유가 무엇이었
는지는 궁금합니다.

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

익명 사용자의 이미지

전웅 wrote:
minzkn wrote:
저는 이글에서 컴파일러의 버그라고 부연설명한것에 대해서 부정적인
생각을 가지고 있습니다.

volatile 은 순차적 실행에 대해서만 메모리 접근에 대한 보장을 하면
충분한 지원이라고 생각합니다.
그것이 버그라고 예기할수 없다는 생각입니다.

해당 글은 gcc 의 버그에 대해서 이야기하고 있는 것은 아닙니다.

Quote:
The value won't be cached (mod. compiler bugs), but it may be loaded,
incremented and then stored. And the store may be deferred past other
non-volatile operations and function calls.

이 글은, voaltile 로 선언된 대상체를 ++ 연산할 때 (컴파일러에 버그가
있는 것이 아니라면 - "mod." 는 "modulo" 를 의미하며 "~인 상황을 제외하
면" 정도로 이해할 수 있습니다) register 로 cache 되지 않으며,
(in-memory incl 가 아닌) load/incl/store 의 작업이 이루어질 수 있다고
이야기하고 있습니다. 문제는 마지막 증가된 값을 저장하는 작업이 다른
non-volatile 연산이나 (해당 volatile 연산에 전혀 영향을 주지 않는) 함
수 호출에 의해 미루어질 수 있다는 것입니다. 마지막 문장은 이렇게 이해
할 수 있습니다:

그 나머지 버그에 대한 여부를 말한것인데요.
그것이 버그가 어떤게 있는지요? 없는거 같은데....
그 상황을 저는 나머지 버그라는 것이
시간적인 비순차실행에 대한 제대로된 처리를 못할때 라고 생각했습니다.
그것을 글 쓴사람은 나머지 버그라고 말한거 같던데.. 아닌가요?

전웅 wrote:

minzkn wrote:
gcc는 최적화 정책(?) 중에서 메모리 조작(접근이 아님)에 대해서는
되도록 register를 통하여 메모리 버스를 최소화(cache) 한다는 글을 본적이 있습니다.
(아~ 슬프도다 이것또한 증거 제출 못합니다. 정말로 저는 검색 되게 못합니다.)

때문에 jiffies++ 는
movl jiffies, %eax
incl %eax /* 위분이 말씀하신것처럼 VC에서는 add eax, 1 */
movl %eax, jiffies
라는 코드가 생성되는것 같습니다.

gcc 의 다른 최적화 정책은 모르겠습니다만, 이 문제의 경우 gcc 가
volatile 대상체를 ++ 할 때도 분명 in-memory incl 를 사용할 수 있으면서
도 다음과 같은 걱정 때문에 그러지 못한다는 것입니다.

x86 에서는 우연히 in-memory incl 와 load/incl/store 가 동등한 의미를
갖기에 volatile 로 한정된 대상체의 증가를 in-memory incl 로 다루는 것
이 어떠한 차이도 낳지 않습니다. 하지만, x86 처럼 in-memory incl 명령어
를 가지고 있지만 그 명령의 의미가 load/incl/store 와는 다른 환경의 가
능성을 배제할 수 없기에, volatile 대상체의 증가에 대해 그처럼 안전한
(그야말로 ++ 의 의미 그대로를 보이는) 목적 코드를 선택했다는 뜻입니다.
즉, 단일 in-memory incl 명령을 갖는 x86 이 아닌 아키텍쳐에서
load/incl/store 와 in-memory incl 의 의미가 동등하지 않은 경우, i++ 수
식의 추상적인 의미에 일치하는 load/incl/store 는 욕먹을 일이 없겠지만,
in-memory incl 의 선택은 gcc 가 표준을 따르지 않는다고 비난받을 가능성
이 있다는 것입니다. 제 개인적인 해석으로는 표준은 volatile 대상체에 접
근하는 행위가 구체적으로 어떤 의미를 갖는지는 각 implemenation 이 상세
히 정의한다고 밝히고 있으므로, (implementation 의 일부분을 구성하는)
gcc 의 걱정이 다소 기우라는 생각이 들기는 합니다. 하지만, gcc 로서는
골치 아프지 않게 가장 마음 편안한 방법을 선택한 것으로 보입니다 - 저라
도 그렇게 했을 것입니다. ;-)

맞습니다. GCC의 심려일수도 있지만 사실은 진짜 문제가 있습니다.
분명 inc에 대해서는 조금 꺼림직한 부분이 있죠.
그것이 무엇인지 아세요?
바로 Carry flag를 변화시키지 않는다는 점이죠. 이건 우려의 소지가 있겠죠.
GCC는 똑똑한 놈입니다. 저는 믿습니다.

x86에서 제가 알고 있는 바로는 inc는 변경할수 있는 flag로서는
AF, OF, PF, SF, ZF 뿐이 없는것으로 알고 있습니다.
(이것도 증거 없습니다. 찾아볼려니 못찾겠네요. 제 기억속에서...)

sliver의 이미지

방준영 wrote:
위에 썼다시피 그 말씀 자체는 맞는데요, 그렇게 하면 부수 효과(side effect)를 예상할 수 없는 경우가 생기기 때문에 옳은 프로그래밍 방법이 아니라는 겁니다. 저라면 volatile으로 쓰는 것 대신
unsigned long
get_jiffies(void)
{
	return jiffies;
}

void
increment_jiffies(void)
{
	jiffies++;
}

처럼 함수로 만들어 쓰겠습니다. 필요하다면 뒤의 increment_jiffies()는 어셈블리로 고쳐써서 원자 연산으로 바꿀 수도 있겠죠.

그렇게 함수로 따로 만든다고 해도 inlining과 register caching에 의해 의도대로 안될 수가 있습니다.

unsigned long jiffies;

unsigned long get_jiffies(void)
{
    return jiffies;
}

void test(void)
{
    while(get_jiffies()<10) {}
}

-O2로 컴파일한 결과:

get_jiffies:
    pushl   %ebp
    movl    jiffies, %eax
    movl    %esp, %ebp
    popl    %ebp
    ret
test:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    .p2align 2
.L6:
    call    get_jiffies
    cmpl    $9, %eax
    jbe .L6
    leave
    ret

보시다시피 -O2에서는 의도한대로 비교할 때마다 get_jiffies를 직접 부릅니다.

하지만 -O3로 컴파일하면

test:
    pushl   %ebp
    movl    %esp, %ebp
    movl    jiffies, %eax
    .p2align 2
.L6:
    cmpl    $9, %eax
    jbe .L6
    popl    %ebp
    ret

먼저 한번만 jiffies를 %eax로 읽어온 후에, 계속 %eax에 캐쉬된 것을 사용하는 것을 알 수 있습니다.

unsigned long get_jiffies(void)
{
    asm volatile("" : : :"memory");    
    return jiffies;
}

대신 이렇게 memory clobber를 넣어주게 되면

get_jiffies가 inline되어도 항상 메모리에서 직접 읽어오게 됩니다.
위의 코드로 다시 -O3로 컴파일하면

test:
    pushl   %ebp
    movl    %esp, %ebp
    .p2align 2
.L6:
#APP
#NO_APP
    cmpl    $9, jiffies
    jbe .L6
    popl    %ebp
    ret

정상적인 코드가 생성됩니다.
kyong의 이미지

위에서 이미 나왔듯이 이것은 순전히 최적화와 관련된 문제입니다.
한 아키텍쳐에서라도 인스트럭션 갯수를 줄여서 cpu 사이클 낭비를 막는다면
써야 하는 것이 커널개발자로서 할 일입니다.

익명 사용자의 이미지

kyong wrote:
위에서 이미 나왔듯이 이것은 순전히 최적화와 관련된 문제입니다.
한 아키텍쳐에서라도 인스트럭션 갯수를 줄여서 cpu 사이클 낭비를 막는다면
써야 하는 것이 커널개발자로서 할 일입니다.

대체적으로 그러하지만
아닌 경우도 상당히 많다고 생각합니다.

분명 메모리의 클럭은 CPU에 공급되는것보다 낮습니다.
그러므로 차라리 CPU클럭을 소모하고 조작(접근이 아님)을 하는 것이 낳을수 있지 않을까요?

kyong의 이미지

minzkn wrote:
kyong wrote:
위에서 이미 나왔듯이 이것은 순전히 최적화와 관련된 문제입니다.
한 아키텍쳐에서라도 인스트럭션 갯수를 줄여서 cpu 사이클 낭비를 막는다면
써야 하는 것이 커널개발자로서 할 일입니다.

대체적으로 그러하지만
아닌 경우도 상당히 많다고 생각합니다.

분명 메모리의 클럭은 CPU에 공급되는것보다 낮습니다.
그러므로 차라리 CPU클럭을 소모하고 조작(접근이 아님)을 하는 것이 낳을수 있지 않을까요?

cpu 레지스터를 쓰고 incl 하는 경우와 쓰지 않고 incl 하는 경우입니다.
이미 kernel 코드가 증명하듯 추가적인 레지스터 낭비없이 하는 경우가
당연히 더 빠릅니다.

익명 사용자의 이미지

kyong wrote:
minzkn wrote:
kyong wrote:
위에서 이미 나왔듯이 이것은 순전히 최적화와 관련된 문제입니다.
한 아키텍쳐에서라도 인스트럭션 갯수를 줄여서 cpu 사이클 낭비를 막는다면
써야 하는 것이 커널개발자로서 할 일입니다.

대체적으로 그러하지만
아닌 경우도 상당히 많다고 생각합니다.

분명 메모리의 클럭은 CPU에 공급되는것보다 낮습니다.
그러므로 차라리 CPU클럭을 소모하고 조작(접근이 아님)을 하는 것이 낳을수 있지 않을까요?

cpu 레지스터를 쓰고 incl 하는 경우와 쓰지 않고 incl 하는 경우입니다.
이미 kernel 코드가 증명하듯 추가적인 레지스터 낭비없이 하는 경우가
당연히 더 빠릅니다.

일단 여기서 Kernel에서의 의도는 맞습니다. 보다 빠를수 있겟지요.
왜냐하면 가장 자주 변경되는 메모리를 뽑으라면 jiffies이기 때문이겠죠?

전웅의 이미지

minzkn wrote:
전웅 wrote:
해당 글은 gcc 의 버그에 대해서 이야기하고 있는 것은 아닙니다.

Quote:
The value won't be cached (mod. compiler bugs), but it may be loaded,
incremented and then stored. And the store may be deferred past other
non-volatile operations and function calls.

이 글은, voaltile 로 선언된 대상체를 ++ 연산할 때 (컴파일러에 버그가
있는 것이 아니라면 - "mod." 는 "modulo" 를 의미하며 "~인 상황을 제외하
면" 정도로 이해할 수 있습니다) register 로 cache 되지 않으며,
(in-memory incl 가 아닌) load/incl/store 의 작업이 이루어질 수 있다고
이야기하고 있습니다. 문제는 마지막 증가된 값을 저장하는 작업이 다른
non-volatile 연산이나 (해당 volatile 연산에 전혀 영향을 주지 않는) 함
수 호출에 의해 미루어질 수 있다는 것입니다. 마지막 문장은 이렇게 이해
할 수 있습니다:

그 나머지 버그에 대한 여부를 말한것인데요.
그것이 버그가 어떤게 있는지요? 없는거 같은데....
그 상황을 저는 나머지 버그라는 것이
시간적인 비순차실행에 대한 제대로된 처리를 못할때 라고 생각했습니다.
그것을 글 쓴사람은 나머지 버그라고 말한거 같던데.. 아닌가요?

"(mod. compiler bugs)" 를 오해하신 것 같습니다. 설명드렸듯이, "mod."
는 modulo 의 약자로 "~인 경우를 제외하면" 의 의미로 사용됩니다. 즉, 첫
번째 문장은 "(컴파일러에 버그가 있는 경우가 아니라면) [volatile 대상체
의] 그 값은 cache 되지 않을 것이고..." 로 해석됩니다.

minzkn wrote:
맞습니다. GCC의 심려일수도 있지만 사실은 진짜 문제가 있습니다.
분명 inc에 대해서는 조금 꺼림직한 부분이 있죠.
그것이 무엇인지 아세요?
바로 Carry flag를 변화시키지 않는다는 점이죠. 이건 우려의 소지가 있겠죠.

carry flag 를 조절하지 않는 것이 "조금 꺼림직한" 수준을 넘어서 어떤 현
실적인 문제를 낳을 수 있을지 궁금합니다. 논의가 진행 중인 x86 에서 일
반 대상체에 대해서는 incl 을 사용하는데 아무 문제가 없는 상황에서,
volatile 대상체에 대해서만 "carry flag" 를 걱정한다는 것은 적절하지 않
습니다. 만약, "carry flag" 자체가 문제가 되는 상황이라면 비한정 대상체
에 대해서도 incl 이 사용되어서는 안 됩니다.

minzkn wrote:
GCC는 똑똑한 놈입니다. 저는 믿습니다.

gcc 가 멍청하다는 뜻은 아닙니다. volatile 로 한정된 대상체에 incl 을
적용하지 않는 것은 너무 과한 자기 방어일 수도 있음을 말씀드린 것 뿐입
니다.

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

전웅의 이미지

kyong wrote:
위에서 이미 나왔듯이 이것은 순전히 최적화와 관련된 문제입니다.
한 아키텍쳐에서라도 인스트럭션 갯수를 줄여서 cpu 사이클 낭비를 막는다면
써야 하는 것이 커널개발자로서 할 일입니다.

그와 같은 세심한 최적화가 do_timer 에서 얼마만큼의 성능 향상을 불러올
수 있는지 의심스럽습니다. 만약, jiffies 에 비정상적인 *& hack 을 사용
한 이유가 단지 단일 명령어를 선택해 성능 향상을 도모하는 것이라면 유사
한 다른 부분에 대해서는 왜 동일한 트릭이 사용되지 않았는지요?

*& hack 에 대해서 interrupt 등의 간섭을 막는 것이 그 목적이라면 불필요
한 걱정을 한 셈이고, 성능 향상을 위한 최적화였다면 불완전한 최적화인
셈입니다.

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

익명 사용자의 이미지

kyong wrote:
위에서 이미 나왔듯이 이것은 순전히 최적화와 관련된 문제입니다.
한 아키텍쳐에서라도 인스트럭션 갯수를 줄여서 cpu 사이클 낭비를 막는다면
써야 하는 것이 커널개발자로서 할 일입니다.

으... 이 토론이 제발 volatile 변수를 그렇게 썼더니 속도가 빨라지더라 하는 오해를 사지 않기 바랍니다... 간단히 생각만 해봐도 바로 밑에 lost_ticks++는 왜 그대로 썼는지 설명이 안되지 않습니까.

전웅님이 잘 정리해 주셨으니 그것을 참조하시면 좋겠습니다.

kyong의 이미지

전웅 wrote:
kyong wrote:
위에서 이미 나왔듯이 이것은 순전히 최적화와 관련된 문제입니다.
한 아키텍쳐에서라도 인스트럭션 갯수를 줄여서 cpu 사이클 낭비를 막는다면
써야 하는 것이 커널개발자로서 할 일입니다.

그와 같은 세심한 최적화가 do_timer 에서 얼마만큼의 성능 향상을 불러올
수 있는지 의심스럽습니다. 만약, jiffies 에 비정상적인 *& hack 을 사용
한 이유가 단지 단일 명령어를 선택해 성능 향상을 도모하는 것이라면 유사
한 다른 부분에 대해서는 왜 동일한 트릭이 사용되지 않았는지요?

*& hack 에 대해서 interrupt 등의 간섭을 막는 것이 그 목적이라면 불필요
한 걱정을 한 셈이고, 성능 향상을 위한 최적화였다면 불완전한 최적화인
셈입니다.

아마 그렇게하는 것이 소용없다고 생각해서 일 것입니다. jiffies 같은 경우는
커널의 근간이 돼서 아주 빠르게 관리해야 하는 특수한 경우입니다. 다른 경우에
는 그렇게 빨리 관리할 필요가 없는데 인스트렉션 갯수를 줄인다는 것이 무슨
의미가 있겠어요.

cdpark의 이미지

역사적 흔적일 뿐 아닌가요?

Linux 0.01: kernel/system_call.s (어셈블리어로 짜 있었습니다.)

_timer_interrupt:
        ...
        incl _jiffies

Linux 1.0: kernel/sched.c

static void do_timer(struct pt_regs * regs)
{
        [50 줄 생략]
        jiffies++;

Linux 2.0: kernel/sched.c

void do_timer(struct pt_regs * regs)
{
        (*(unsigned long *)&jiffies)++;

뒤져보니 이 trick은 정확히는 1.3.75 -> 1.3.76 으로 바뀌면서 커널 소스에 도입되었습니다. 이유는 그 당시의 개발자 간에 주고받은 메일 등을 뒤져봐야겠죠? :roll: 어쨌거나 2.6.0에선 이 코드는 사라집니다.

Linux 2.6.0-test : kernel/timer.c

void do_timer(struct pt_regs *regs)
{
        jiffies_64++;
전웅의 이미지

kyong wrote:
전웅 wrote:
그와 같은 세심한 최적화가 do_timer 에서 얼마만큼의 성능 향상을 불러올
수 있는지 의심스럽습니다. 만약, jiffies 에 비정상적인 *& hack 을 사용
한 이유가 단지 단일 명령어를 선택해 성능 향상을 도모하는 것이라면 유사
한 다른 부분에 대해서는 왜 동일한 트릭이 사용되지 않았는지요?

*& hack 에 대해서 interrupt 등의 간섭을 막는 것이 그 목적이라면 불필요
한 걱정을 한 셈이고, 성능 향상을 위한 최적화였다면 불완전한 최적화인
셈입니다.

아마 그렇게하는 것이 소용없다고 생각해서 일 것입니다. jiffies 같은 경우는
커널의 근간이 돼서 아주 빠르게 관리해야 하는 특수한 경우입니다. 다른 경우에
는 그렇게 빨리 관리할 필요가 없는데 인스트렉션 갯수를 줄인다는 것이 무슨
의미가 있겠어요.

do_timer 안에서 jiffies 에게만 이루어지는 최적화가 jiffies 의 어떤 부
분에 어떻게 영향을 주어 "kernel 전체" 에서 "빠르게 관리" 하도록 도와준
다는 것인지 이해하기 어렵습니다.

다음을 보시기 바랍니다. 어떤 implementation 에서 빠른 증감 연산을 위해
(다른 목적은 없습니다) __fast_inc() 라는 특별한 inline 함수를 지원한다
고 가정하겠습니다.

void func(void)
{
    extern int a, b, c;

    __fast_inc(a);    // a++;
    b++;
    c++;
}

이렇게 하면 (동일한 상황에 처해있는 b 와 c 에는 __fast_inc() 가 적용되
지 않았기에 "불완전한 최적화" 라기 보다는) a 가 프로그램 전체에서 근간
이 되어 사용될 경우 더 빠르게 관리할 수 있다고 말할 수 있는지요?

어느 개발자의 습관 (혹은 무지?) 에서 비롯된 "실수", 혹은 특정한 목적
코드에 대한 선호, 혹은 "불완전한 최적화" 라는 추측에서 여전히 벗어나지
못합니다. 제 개인적인 의견은 최소한 "불완전한 최적화" 가 그 목적은 아
닐 것이라는 겁니다.

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

kyong의 이미지

cdpark wrote:
역사적 흔적일 뿐 아닌가요?

Linux 0.01: kernel/system_call.s (어셈블리어로 짜 있었습니다.)

_timer_interrupt:
        ...
        incl _jiffies

Linux 1.0: kernel/sched.c

static void do_timer(struct pt_regs * regs)
{
        [50 줄 생략]
        jiffies++;

Linux 2.0: kernel/sched.c

void do_timer(struct pt_regs * regs)
{
        (*(unsigned long *)&jiffies)++;

뒤져보니 이 trick은 정확히는 1.3.75 -> 1.3.76 으로 바뀌면서 커널 소스에 도입되었습니다. 이유는 그 당시의 개발자 간에 주고받은 메일 등을 뒤져봐야겠죠? :roll: 어쨌거나 2.6.0에선 이 코드는 사라집니다.

Linux 2.6.0-test : kernel/timer.c

void do_timer(struct pt_regs *regs)
{
        jiffies_64++;

jiffies_64는 필요에 의해서 추가됐습니다. jiffies는 없어지지 않았습니다.
역사적인 이유가 아니라 gcc가 더 나은 코드를 생성하는 현실적인 이유가
있기 때문입니다.

kyong의 이미지

Quote:
do_timer 안에서 jiffies 에게만 이루어지는 최적화가 jiffies 의 어떤 부
분에 어떻게 영향을 주어 "kernel 전체" 에서 "빠르게 관리" 하도록 도와준
다는 것인지 이해하기 어렵습니다.

jiffy는 kernel의 기본적인 timer입니다. jiffy accounting은 최대한 신속히
이루어져야 함은 당연합니다. one writer만 있으므로 kernel 전체에서
도와 줄 필요는 없겠네요. 위에서 나왔듯이 gcc가 만든 코드를 다시 확인
하시기 바랍니다.

Quote:

다음을 보시기 바랍니다. 어떤 implementation 에서 빠른 증감 연산을 위해
(다른 목적은 없습니다) __fast_inc() 라는 특별한 inline 함수를 지원한다
고 가정하겠습니다.

void func(void)
{
    extern int a, b, c;

    __fast_inc(a);    // a++;
    b++;
    c++;
}

이렇게 하면 (동일한 상황에 처해있는 b 와 c 에는 __fast_inc() 가 적용되
지 않았기에 "불완전한 최적화" 라기 보다는) a 가 프로그램 전체에서 근간
이 되어 사용될 경우 더 빠르게 관리할 수 있다고 말할 수 있는지요?


a가 kernel에서 처럼 기본 timer로서 광범위하게 사용돼서 process를
schedule하는 것과 같은 함수의 기본값으로 사용된다면 그렇다고 할 수
있겠지요.

Quote:

어느 개발자의 습관 (혹은 무지?) 에서 비롯된 "실수", 혹은 특정한 목적
코드에 대한 선호, 혹은 "불완전한 최적화" 라는 추측에서 여전히 벗어나지
못합니다. 제 개인적인 의견은 최소한 "불완전한 최적화" 가 그 목적은 아
닐 것이라는 겁니다.

linux kernel에서의 최적화는 표준하고 전혀 상관이 없는 gcc에서 최적화
입니다. gcc에서 조금이라도 최적화의 여지가 있다면 trick도 필요한 것
입니다. 이것은 순전히 그렇게 함으로써 gcc가 cpu cycle을 줄이는 코드를
생성한다는 것 왜에는 다른 이유가 없다고 생각됩니다. gcc 한 버젼만이
개발자가 바란대로 최적화 한다고 해도 kernel 개발자는 충분히 선택할 이
유가 있는 것이라고 생각합니다.
eungkyu의 이미지

mastercho wrote:
결국 컴파일러 의존성 코드라는건데 -_-;

왜 저런 이식성이 없는 저런 코드를 사용했을라나?

역시 표준이 아닌 방법은 .....쩝

아시고 계시겠지만, 리눅스 커널은 gcc에서만 컴파일이 됩니다.
최적화를 위해 gcc만의 방법을 사용합니다.
참 이식성 없고 표준이 아닌 방법을 사용 하죠
그래서 리눅스는 gcc가 돌아가는 platform에만 돌아갑니다.

gcc가 안돌면 리눅스도 안된다니... :roll:
gcc가 돌아가는 플랫폼이 많지 않았으면 큰일날 뻔했네요. 8)

전웅의 이미지

kyong wrote:
Quote:
do_timer 안에서 jiffies 에게만 이루어지는 최적화가 jiffies 의 어떤 부
분에 어떻게 영향을 주어 "kernel 전체" 에서 "빠르게 관리" 하도록 도와준
다는 것인지 이해하기 어렵습니다.

jiffy는 kernel의 기본적인 timer입니다. jiffy accounting은 최대한 신속히
이루어져야 함은 당연합니다.

jiffies "만" 신속하게 이루어지고 있습니다. 그래서 "불완전한 최적화" 라
고 부른 것입니다. (만약, 성능 향상이 그 목적이라면) 유사한 트릭을 충분
히 사용해 간단히 do_timer 전체의 성능을 향상시킬 수 있음에도 그렇게 하
고 있지 않다는 것이고, 따라서 "성능 향상" 이 *& hack 을 사용한 주요한
목적은 아닐 것이라는 뜻입니다.

kyong wrote:
one writer만 있으므로 kernel 전체에서
도와 줄 필요는 없겠네요. 위에서 나왔듯이 gcc가 만든 코드를 다시 확인
하시기 바랍니다.

gcc 가 만든 코드에서 jiffies 에만 in-memory operation 이 생성되고 있습
니다. 제가 위에 적은 글을 다시 읽어 보시기 바랍니다.

kyong wrote:
Quote:

다음을 보시기 바랍니다. 어떤 implementation 에서 빠른 증감 연산을 위해
(다른 목적은 없습니다) __fast_inc() 라는 특별한 inline 함수를 지원한다
고 가정하겠습니다.

void func(void)
{
    extern int a, b, c;

    __fast_inc(a);    // a++;
    b++;
    c++;
}

이렇게 하면 (동일한 상황에 처해있는 b 와 c 에는 __fast_inc() 가 적용되
지 않았기에 "불완전한 최적화" 라기 보다는) a 가 프로그램 전체에서 근간
이 되어 사용될 경우 더 빠르게 관리할 수 있다고 말할 수 있는지요?


a가 kernel에서 처럼 기본 timer로서 광범위하게 사용돼서 process를
schedule하는 것과 같은 함수의 기본값으로 사용된다면 그렇다고 할 수
있겠지요.

그렇다면, a, b, c 에 대한 writer 가 func 혼자임에도 불구하고 (따라서,
다른 부분에서는 참조만 일어납니다), 광범위하게 사용되지 않을 때에는 b,
c 는 동일한 트릭으로 최적화될 필요가 없다는 뜻인지요? jiffies 의
writer 가 다른 간섭 없이 do_timer 혼자인 경우, jiffies 에 *& hack 을
사용해 단일 목적 코드를 생성해 내는 것은 다른 부분에서 jiffies 를 사용
(참조) 하는데 아무런 영향을 주지 않습니다. 물론 jiffies 에 단일 목적
코드를 생성하니 do_timer 가 더 빠르게 자신의 일을 수행할 수 있다고 생
각하는 것은 가능합니다. 하지만, do_timer 의 유사한 다른 부분에는 동일
한 트릭을 사용하지 않았다는 사실이 그와 같은 "빠른 실행" 이 해당 트릭
을 사용한 주요한 의도가 아니라는 추측을 뒷받침 한다는 뜻입니다.

kyong wrote:
linux kernel에서의 최적화는 표준하고 전혀 상관이 없는 gcc에서 최적화
입니다.

이 thread 에서 단 한번도 linux kernel 에 사용되는 비표준적인 최적화가
표준에 맞춰 고쳐져야 한다고 주장한 적 없습니다 - "표준" 을 언급한 경우
는, *& hack 이 어떤 의미를 갖는지, gcc 가 왜 volatile 대상체에 대해서
in-memory op 를 선택하지 않는지 등을 설명할 때 뿐입니다.

kyong wrote:
gcc에서 조금이라도 최적화의 여지가 있다면 trick도 필요한 것
입니다. 이것은 순전히 그렇게 함으로써 gcc가 cpu cycle을 줄이는 코드를
생성한다는 것 왜에는 다른 이유가 없다고 생각됩니다.

아직도 제가 "불완전한" 최적화라고 언급하는 이유를 모르고 계신 것 같습
니다. ("빠른 실행"이 당시 개발자의 머릿속에 들어있는 주요한 목적이라면)
do_timer 의 다른 부분에서도 "순전히 그렇게 함으로써" 성능은 더 나아질
수 있습니다. 따라서, "성능 향상을 도모하기 위한 최적화" 가 그 주요한
목적이라고해도 "불완전한 최적화" 에서 벗어나지 못한다는 뜻입니다. 습관
이나 무지에서 비롯된 실수든, 불완전한 최적화든, 특정 목적 코드에 대한
선호든 어느 것 하나 "해당 부분에" *& hack 을 사용한 것에 대해서 합리적
이고 설득력있는 정당성을 제시해주지 못하고 있습니다. 제가 개발자라서
변명을 한다면 (너무 생각이 많은 탓에 비롯될 수 있는) 습관에 의한 실수
나 (괴짜임을 강조하는) 특정 목적 코드에 대한 선호를 선택하겠습니다. ;-)

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

전웅의 이미지

eungkyu wrote:
아시고 계시겠지만, 리눅스 커널은 gcc에서만 컴파일이 됩니다.
최적화를 위해 gcc만의 방법을 사용합니다.

맞는 말씀입니다. 하지만, 현재 논의가 되고 있는 이 경우에, volatile 대
상체에 대해 가능한 in-memory operation 을 목적 코드로 얻는 것이 (다소
불분명할 수 있는) *& hack 을 써서 얻어낼 만큼 중요한 최적화 중 하나라
면, 차라리 gcc 측에 volatile 대상체 접근의 최적화를 어느 정도 요청하거
나, #pragma 를 통한 보다 세련된 확장을 요청해 사용하는 것이 더 아름다
웠을 것 같습니다.

물론, 이는 보다 이해가 쉬운 코드를 지향하는 저의 개인적인 의견일 뿐이
며 (아마도 다른 사람의 코드를 분석하다가 도저히 이해가 안 되는 독특한
부분이 있어 개발자를 수소문 끝에 찾아 물었더니 큰 의미 없다는 답을 자
주 들은 경험이 크게 작용하는 것 같습니다), *& hack 을 사용해 (gcc 에서
만이라도) 그와 같은 목적 코드를 얻는 사실 자체가 중요하다고 생각하시는
분들도 많으리라 생각합니다.

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

kyong의 이미지

eungkyu wrote:
mastercho wrote:
결국 컴파일러 의존성 코드라는건데 -_-;

왜 저런 이식성이 없는 저런 코드를 사용했을라나?

역시 표준이 아닌 방법은 .....쩝

아시고 계시겠지만, 리눅스 커널은 gcc에서만 컴파일이 됩니다.
최적화를 위해 gcc만의 방법을 사용합니다.
참 이식성 없고 표준이 아닌 방법을 사용 하죠
그래서 리눅스는 gcc가 돌아가는 platform에만 돌아갑니다.

gcc가 안돌면 리눅스도 안된다니... :roll:
gcc가 돌아가는 플랫폼이 많지 않았으면 큰일날 뻔했네요. 8)


intel compiler로 컴파일했을 때와 비교한 benchmark까지 나와있습니다.
전웅의 이미지

kyong wrote:
eungkyu wrote:
아시고 계시겠지만, 리눅스 커널은 gcc에서만 컴파일이 됩니다.
최적화를 위해 gcc만의 방법을 사용합니다.
참 이식성 없고 표준이 아닌 방법을 사용 하죠
그래서 리눅스는 gcc가 돌아가는 platform에만 돌아갑니다.

gcc가 안돌면 리눅스도 안된다니... :roll:
gcc가 돌아가는 플랫폼이 많지 않았으면 큰일날 뻔했네요. 8)


intel compiler로 컴파일했을 때와 비교한 benchmark까지 나와있습니다.

http://slashdot.org/article.pl?sid=02/04/24/1214213&mode=thread

Quote:
The 6.0 release of the Intel C++ compiler has improved support for the
GNU C language extensions and is now able to build the Linux kernel
with minor work arounds for both the IA-32 and Itanium architectures.

kernel 이 icc 를 고려한 것이 아니라, icc 가 (gcc-specific extension 을
도입함으로써) kernel 을 (의도적이 아닐지라도) 고려한 것입니다.

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

kyong의 이미지

Quote:

전웅 wrote:
kyong wrote:
Quote:
do_timer 안에서 jiffies 에게만 이루어지는 최적화가 jiffies 의 어떤 부
분에 어떻게 영향을 주어 "kernel 전체" 에서 "빠르게 관리" 하도록 도와준
다는 것인지 이해하기 어렵습니다.

jiffy는 kernel의 기본적인 timer입니다. jiffy accounting은 최대한 신속히
이루어져야 함은 당연합니다.

jiffies "만" 신속하게 이루어지고 있습니다. 그래서 "불완전한 최적화" 라
고 부른 것입니다. (만약, 성능 향상이 그 목적이라면) 유사한 트릭을 충분
히 사용해 간단히 do_timer 전체의 성능을 향상시킬 수 있음에도 그렇게 하
고 있지 않다는 것이고, 따라서 "성능 향상" 이 *& hack 을 사용한 주요한
목적은 아닐 것이라는 뜻입니다.


위에서 예를 든 lost_tick은 2.0.32 대에서는 volatile이 아니였는데 2.2.x에서는
volatile입니다. 아마 volatile이 아니였다고 생각했기 때문에 그렇게 하지 않았
다고 추측할 수 있습니다. 그런 의미에서 불완전하다고 할 수는 있겠지요.
2.4.x 버젼에서는 사용되고 있지 않습니다. 그러므로 이것을 근거로 *& hack
자체의 주요한 목적을 바꿀 수는 없습니다.

Quote:

kyong wrote:
one writer만 있으므로 kernel 전체에서
도와 줄 필요는 없겠네요. 위에서 나왔듯이 gcc가 만든 코드를 다시 확인
하시기 바랍니다.

gcc 가 만든 코드에서 jiffies 에만 in-memory operation 이 생성되고 있습
니다. 제가 위에 적은 글을 다시 읽어 보시기 바랍니다.


gcc가 더 최적화된 코드를 생성한다는 것을(최소한 x86에서) 강조하기 위해서
말한 것입니다.

Quote:

kyong wrote:
Quote:

다음을 보시기 바랍니다. 어떤 implementation 에서 빠른 증감 연산을 위해
(다른 목적은 없습니다) __fast_inc() 라는 특별한 inline 함수를 지원한다
고 가정하겠습니다.

void func(void)
{
    extern int a, b, c;

    __fast_inc(a);    // a++;
    b++;
    c++;
}

이렇게 하면 (동일한 상황에 처해있는 b 와 c 에는 __fast_inc() 가 적용되
지 않았기에 "불완전한 최적화" 라기 보다는) a 가 프로그램 전체에서 근간
이 되어 사용될 경우 더 빠르게 관리할 수 있다고 말할 수 있는지요?


a가 kernel에서 처럼 기본 timer로서 광범위하게 사용돼서 process를
schedule하는 것과 같은 함수의 기본값으로 사용된다면 그렇다고 할 수
있겠지요.

그렇다면, a, b, c 에 대한 writer 가 func 혼자임에도 불구하고 (따라서,
다른 부분에서는 참조만 일어납니다), 광범위하게 사용되지 않을 때에는 b,
c 는 동일한 트릭으로 최적화될 필요가 없다는 뜻인지요? jiffies 의
writer 가 다른 간섭 없이 do_timer 혼자인 경우, jiffies 에 *& hack 을
사용해 단일 목적 코드를 생성해 내는 것은 다른 부분에서 jiffies 를 사용
(참조) 하는데 아무런 영향을 주지 않습니다. 물론 jiffies 에 단일 목적
코드를 생성하니 do_timer 가 더 빠르게 자신의 일을 수행할 수 있다고 생
각하는 것은 가능합니다. 하지만, do_timer 의 유사한 다른 부분에는 동일
한 트릭을 사용하지 않았다는 사실이 그와 같은 "빠른 실행" 이 해당 트릭
을 사용한 주요한 의도가 아니라는 추측을 뒷받침 한다는 뜻입니다.


writer가 func라고 생각하지 않았습니다. 이건 앞서 얘기와 중복되군요.

kyong wrote:
linux kernel에서의 최적화는 표준하고 전혀 상관이 없는 gcc에서 최적화
입니다.

Quote:

이 thread 에서 단 한번도 linux kernel 에 사용되는 비표준적인 최적화가
표준에 맞춰 고쳐져야 한다고 주장한 적 없습니다 - "표준" 을 언급한 경우
는, *& hack 이 어떤 의미를 갖는지, gcc 가 왜 volatile 대상체에 대해서
in-memory op 를 선택하지 않는지 등을 설명할 때 뿐입니다.

동의합니다. 전 단지 kernel에서 가지는 gcc의미를 상기시키려했을 뿐입니다.

Quote:

kyong wrote:
gcc에서 조금이라도 최적화의 여지가 있다면 trick도 필요한 것
입니다. 이것은 순전히 그렇게 함으로써 gcc가 cpu cycle을 줄이는 코드를
생성한다는 것 왜에는 다른 이유가 없다고 생각됩니다.

아직도 제가 "불완전한" 최적화라고 언급하는 이유를 모르고 계신 것 같습
니다. ("빠른 실행"이 당시 개발자의 머릿속에 들어있는 주요한 목적이라면)
do_timer 의 다른 부분에서도 "순전히 그렇게 함으로써" 성능은 더 나아질
수 있습니다. 따라서, "성능 향상을 도모하기 위한 최적화" 가 그 주요한
목적이라고해도 "불완전한 최적화" 에서 벗어나지 못한다는 뜻입니다. 습관
이나 무지에서 비롯된 실수든, 불완전한 최적화든, 특정 목적 코드에 대한
선호든 어느 것 하나 "해당 부분에" *& hack 을 사용한 것에 대해서 합리적
이고 설득력있는 정당성을 제시해주지 못하고 있습니다. 제가 개발자라서
변명을 한다면 (너무 생각이 많은 탓에 비롯될 수 있는) 습관에 의한 실수
나 (괴짜임을 강조하는) 특정 목적 코드에 대한 선호를 선택하겠습니다. ;-)



현재까지 *& hack이 살아남아서 사용되고 있는 이유가 무엇이라고 생각하
세요? 2.2.x 대에서 *& hack이 좀 더 일관성있게 적용 됐더라면 이런 수고를
줄였겠지만, 어쟀든, jiffies 에서만이라도 적용됩으로써 좀 더 최적화 됐다는
사실은 변하지 않습니다. 제가 rdtscl을 사용해서 테스트한 결과는 다른 이유
가 있다고 하더라도 이것이 주요한 목적이란 것을 더욱 확신하게 하네요.
전웅의 이미지

kyong wrote:
전웅 wrote:
jiffies "만" 신속하게 이루어지고 있습니다. 그래서 "불완전한 최적화" 라
고 부른 것입니다. (만약, 성능 향상이 그 목적이라면) 유사한 트릭을 충분
히 사용해 간단히 do_timer 전체의 성능을 향상시킬 수 있음에도 그렇게 하
고 있지 않다는 것이고, 따라서 "성능 향상" 이 *& hack 을 사용한 주요한
목적은 아닐 것이라는 뜻입니다.

위에서 예를 든 lost_tick은 2.0.32 대에서는 volatile이 아니였는데 2.2.x에서는
volatile입니다. 아마 volatile이 아니였다고 생각했기 때문에 그렇게 하지 않았
다고 추측할 수 있습니다. 그런 의미에서 불완전하다고 할 수는 있겠지요.
2.4.x 버젼에서는 사용되고 있지 않습니다. 그러므로 이것을 근거로 *& hack
자체의 주요한 목적을 바꿀 수는 없습니다.

지금은 *& hack 에 대한 일반적인 논의가 이루어지고 있는 것이 아닙니다.
*& hack 이 do_timer 의 문맥에서 volatile 한정을 제거하기 위한 목적으로
jiffies 에 적용된 이유를 찾고 있는 것입니다.

kyong wrote:
현재까지 *& hack이 살아남아서 사용되고 있는 이유가 무엇이라고 생각하
세요?

*& hack 이 사용되는 일반적인 목적이 속도 향상을 위한 최적화라는 말씀이
신지요?

kernel 에서 (jiffies 를 제외하고) volatile 한정을 제거하기 위한 (그래
서 in-memory op 를 얻기 위한) 목적으만으로 *& hack 을 사용한 다른 부분
이 있습니까? 참고로 sys_iopl() 은 적용되지 않습니다 - volatile 한정을
제거하는 목적이 아니라 과거 gcc 의 bug 를 피하기 위한 목적으로 사용된
곳입니다.

kyong wrote:
2.2.x 대에서 *& hack이 좀 더 일관성있게 적용 됐더라면 이런 수고를
줄였겠지만, 어쟀든, jiffies 에서만이라도 적용됩으로써 좀 더 최적화 됐다는
사실은 변하지 않습니다. 제가 rdtscl을 사용해서 테스트한 결과는 다른 이유
가 있다고 하더라도 이것이 주요한 목적이란 것을 더욱 확신하게 하네요.

여전히 do_timer 문맥에서 jiffies 에 *& hack 이 사용된 "주요한 (의도된)"
이유가 성능 향상이라고 생각하지는 않습니다 - 물론, 의도하지 않은 side
effect 로 발생하는 효과일 수는 있습니다.

http://www.ussg.iu.edu/hypermail/linux/kernel/9801.3/0177.html

Alan Cox wrote:
> Hmm... So what is effect of
> (*(unsigned long *)&jiffies)++;
> when jiffies are volatile, anyway? I would expect that jiffies++; is
> just enough...

Nothing.

(제가 틀린 것일 수도 있다는 가능성을 결코 배제하지 않고) 보다 더 확실
한 이유와 신뢰할 만한 근거를 찾기 위해 여러 방법으로 여러 곳을 검색해
보았지만, (검색 능력이 부족한 탓인지) kernel 개발에 관여한 몇몇 사람들
의 위와 같은 답변과 (최소한 성능 향상에 대한 이야기가 아닌) 여러가지
추측들 그리고 (위에서 어느 분께서 보여주신) jiffies++ 에 대해 gcc 가
ugly code 를 생성하다는 주석 외에는 찾지 못하였습니다. 해당 부분에 *&
hack 을 처음 도입한 사람만이 그 답 (진정한 의도가 무엇이었는지) 을 알
고 있겠지만, 저로서는 찾아낼 방법이 없습니다.

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

kyong의 이미지

Quote:

지금은 *& hack 에 대한 일반적인 논의가 이루어지고 있는 것이 아닙니다.
*& hack 이 do_timer 의 문맥에서 volatile 한정을 제거하기 위한 목적으로
jiffies 에 적용된 이유를 찾고 있는 것입니다.

처음부터 일관되게 얘기 했듯이 성능입니다.
반복해서 얘기 하지만, gcc가 더 나은 코드를 만들기 때문입니다.
테스트가 필요하다면 아래 코드를 사용해 보시기 바랍니다.
#include <linux/config.h>
#include <asm/msr.h>
#include <stdio.h>

#define RPT 10000000
unsigned long volatile jiffies;

int main(void)
{
#ifdef CONFIG_X86_TSC
    unsigned long i, time1, time2, diff_time;

    rdtscl(time1);
    for(i=0 ; i<RPT; ++i) {
        jiffies++;
        //(*(unsigned long *)&jiffies)++;
    }
    rdtscl(time2);
    diff_time = time2 - time1;

    printf("elapsed time : %lu\n", diff_time);

#else
#error No TSC
#endif
    return(0);
}

Quote:

kyong wrote:
현재까지 *& hack이 살아남아서 사용되고 있는 이유가 무엇이라고 생각하
세요?

*& hack 이 사용되는 일반적인 목적이 속도 향상을 위한 최적화라는 말씀이
신지요?

kernel 에서 (jiffies 를 제외하고) volatile 한정을 제거하기 위한 (그래
서 in-memory op 를 얻기 위한) 목적으만으로 *& hack 을 사용한 다른 부분
이 있습니까? 참고로 sys_iopl() 은 적용되지 않습니다 - volatile 한정을
제거하는 목적이 아니라 과거 gcc 의 bug 를 피하기 위한 목적으로 사용된
곳입니다.

kyong wrote:
2.2.x 대에서 *& hack이 좀 더 일관성있게 적용 됐더라면 이런 수고를
줄였겠지만, 어쟀든, jiffies 에서만이라도 적용됩으로써 좀 더 최적화 됐다는
사실은 변하지 않습니다. 제가 rdtscl을 사용해서 테스트한 결과는 다른 이유
가 있다고 하더라도 이것이 주요한 목적이란 것을 더욱 확신하게 하네요.

여전히 do_timer 문맥에서 jiffies 에 *& hack 이 사용된 "주요한 (의도된)"
이유가 성능 향상이라고 생각하지는 않습니다 - 물론, 의도하지 않은 side
effect 로 발생하는 효과일 수는 있습니다.

http://www.ussg.iu.edu/hypermail/linux/kernel/9801.3/0177.html

Alan Cox wrote:
> Hmm... So what is effect of
> (*(unsigned long *)&jiffies)++;
> when jiffies are volatile, anyway? I would expect that jiffies++; is
> just enough...

Nothing.

(제가 틀린 것일 수도 있다는 가능성을 결코 배제하지 않고) 보다 더 확실
한 이유와 신뢰할 만한 근거를 찾기 위해 여러 방법으로 여러 곳을 검색해
보았지만, (검색 능력이 부족한 탓인지) kernel 개발에 관여한 몇몇 사람들
의 위와 같은 답변과 (최소한 성능 향상에 대한 이야기가 아닌) 여러가지
추측들 그리고 (위에서 어느 분께서 보여주신) jiffies++ 에 대해 gcc 가
ugly code 를 생성하다는 주석 외에는 찾지 못하였습니다. 해당 부분에 *&
hack 을 처음 도입한 사람만이 그 답 (진정한 의도가 무엇이었는지) 을 알
고 있겠지만, 저로서는 찾아낼 방법이 없습니다.

그럼...


분명히 전 jiffy accounting은 cpu 몇 cycle이 중요할 만큼 최적화 대상이
라고 생각합니다.
제가 오늘 찾은 thread를 알려드리지요.
http://www.ussg.iu.edu/hypermail/linux/kernel/0001.0/0236.html
코드가 만들어낸 결과를 믿는 것이 현명하다고 생각됩니다.
전웅의 이미지

kyong wrote:
처음부터 일관되게 얘기 했듯이 성능입니다.

의견이 아닌 객관적 근거에 기반한 사실을 부탁드립니다. (님의 의견이든
제 의견이든) 의견은 의견일 뿐이며, 지금의 상황에서는 서로 다른 의견이
서로 다른 추측을 근거로 가능합니다. 지금 필요로 하는 것은 객관적 근거
를 갖춘 사실입니다.

kyong wrote:
분명히 전 jiffy accounting은 cpu 몇 cycle이 중요할 만큼 최적화 대상이
라고 생각합니다.

그렇다면 jiffy accounting 이 이루어지는 do_timer 전체에도 동일한 내용
이 적용될 수 있습니다. 그럼에도 lost_ticks 에는 왜 동일한 최적화가 적
용되지 않는지요? 또한, jiffy accounting 의 현재 모습에서는 왜 그러한
트릭을 찾을 수 없는지요? do_timer 에서 이루어지는 jiffy accounting 이
CPU 의 cycle 개수가 문제가 될 만큼 중요한 최적화 대상임에도, 지금의
kernel 개발자들은 그러한 사실을 모르고 있다는 뜻일까요?

kyong wrote:
제가 오늘 찾은 thread를 알려드리지요.
http://www.ussg.iu.edu/hypermail/linux/kernel/0001.0/0236.html

이미 살펴본 thread 입니다. 단일 명령어를 생성해 간섭을 막으려는 의도가
아니었냐는 (잘못된) 추측은 있어도 성능에 대한 이야기는 없던 것으로 기
억하고 있습니다 - 빼먹은 부분이 있다면 인용해 주시기 바랍니다. 결국,
아래 주장하신 내용의 객관적 근거가 될 수는 없습니다.

kyong wrote:
코드가 만들어낸 결과를 믿는 것이 현명하다고 생각됩니다.

이는 아직도 님의 의견일 뿐 분명한 근거 있는 사실은 아닙니다. 조금 더
검색을 해본 결과 mailing list 에서 다음과 같은 가설도 추가로 있었습니
다.

- 역사적인 흔적이다 (이는 현재의 thread 에서도 언급된 바 있습니다)
- gcc 가 더 빠른 코드를 생성할 가능성이 있기 때문이다

하지만, 그 어느 것도 해당 트릭을 도입한 사람의 의도에 대해서는 확신하
고 있지 못합니다.

더 빠른 코드를 생성하기 위함이라는 가능성 자체를 덮어 놓고 있는 것은
아니지만, 그것이 진짜 의도였다고 해도 지금 이 시점에서는 불완전한 적용
으로 인해 그 의미가 퇴색된 셈입니다.

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

kyong의 이미지

Quote:

전웅 wrote:
kyong wrote:
처음부터 일관되게 얘기 했듯이 성능입니다.

의견이 아닌 객관적 근거에 기반한 사실을 부탁드립니다. (님의 의견이든
제 의견이든) 의견은 의견일 뿐이며, 지금의 상황에서는 서로 다른 의견이
서로 다른 추측을 근거로 가능합니다. 지금 필요로 하는 것은 객관적 근거
를 갖춘 사실입니다.


객관적인 사실은 더 나은 코드가 생성됐다는 것입니다.(최소한 제가 테스트한
x86에서) 무엇이 객관적인 근거가 아니란 말씀이세요?

Quote:

kyong wrote:
분명히 전 jiffy accounting은 cpu 몇 cycle이 중요할 만큼 최적화 대상이
라고 생각합니다.

그렇다면 jiffy accounting 이 이루어지는 do_timer 전체에도 동일한 내용
이 적용될 수 있습니다. 그럼에도 lost_ticks 에는 왜 동일한 최적화가 적
용되지 않는지요? 또한, jiffy accounting 의 현재 모습에서는 왜 그러한
트릭을 찾을 수 없는지요? do_timer 에서 이루어지는 jiffy accounting 이
CPU 의 cycle 개수가 문제가 될 만큼 중요한 최적화 대상임에도, 지금의
kernel 개발자들은 그러한 사실을 모르고 있다는 뜻일까요?


lost_tick에 관한 것은 앞서 얘기도 했으며 인용한 kernel thread에서도 나옵
니다. 최적화 대상 후보라고 생각합니다. 지금 개발자들은 잘 알고 있기
때문에 *& hack을 계속 쓰고 있으며 lost_tick은 2.4.x 이후 없습니다.
모조리 최적화하지 못했다고 최적화한 코드의 정당성이 살아지는 것은
아닙니다.

Quote:

kyong wrote:
제가 오늘 찾은 thread를 알려드리지요.
http://www.ussg.iu.edu/hypermail/linux/kernel/0001.0/0236.html

이미 살펴본 thread 입니다. 단일 명령어를 생성해 간섭을 막으려는 의도가
아니었냐는 (잘못된) 추측은 있어도 성능에 대한 이야기는 없던 것으로 기
억하고 있습니다 - 빼먹은 부분이 있다면 인용해 주시기 바랍니다. 결국,
아래 주장하신 내용의 객관적 근거가 될 수는 없습니다.


제가 이해하기론, *& hack 이 계속 쓰이는 것이 왜 더 좋은지 분명히 얘기하고
있었습니다.
http://www.ussg.iu.edu/hypermail/linux/kernel/0001.0/0456.html
http://www.ussg.iu.edu/hypermail/linux/kernel/0001.0/0275.html

Quote:

kyong wrote:
코드가 만들어낸 결과를 믿는 것이 현명하다고 생각됩니다.

이는 아직도 님의 의견일 뿐 분명한 근거 있는 사실은 아닙니다. 조금 더
검색을 해본 결과 mailing list 에서 다음과 같은 가설도 추가로 있었습니
다.

- 역사적인 흔적이다 (이는 현재의 thread 에서도 언급된 바 있습니다)
- gcc 가 더 빠른 코드를 생성할 가능성이 있기 때문이다

하지만, 그 어느 것도 해당 트릭을 도입한 사람의 의도에 대해서는 확신하
고 있지 못합니다.


제 근거는 앞서 얘기한 대로 입니다.
역사적인 흔적이란 말은 어울리지 않습니다. 현실적으로 나은 코드를 생성
하기 때문입니다. 더구나 깨끗한 코드를 선호하는 경향을 생각할 때 더욱
그렇습니다. 그래서 lkml에서 그런 토론이 있었덧 것이라고 생각됩니다.
Quote:

더 빠른 코드를 생성하기 위함이라는 가능성 자체를 덮어 놓고 있는 것은
아니지만, 그것이 진짜 의도였다고 해도 지금 이 시점에서는 불완전한 적용
으로 인해 그 의미가 퇴색된 셈입니다.

그 의미는 여전히 유효합니다. lost_tick은 사라졌고 *& hack은 살아남았으니
까요. irc, lkml 에서 접한 여러 의견을 볼 때 전웅님이 주요한 목적이라고 생각하
는 경우는 너무 특수해서 드러나지 않았는지도 모릅니다. 그렇지만 코드는 어떤
주석보다도 분명히 말하고 있습니다. 이렇게 하니까 더 빠르더라고. 그것 이상의
효과는 저로서는 불필요합니다.
전웅의 이미지

kyong wrote:
객관적인 사실은 더 나은 코드가 생성됐다는 것입니다.(최소한 제가 테스트한
x86에서) 무엇이 객관적인 근거가 아니란 말씀이세요?

그 객관적 코드를 선택하게 된 원래 개발자의 의도는 다양할 수 있습니다.
이 문제와 관련된 mailing list 의 각종 논의를 보시면 아시겠지만,
load/inc/store 대신 in-memory inc 가 생성되도록 하기 위해서 그와 같은
트릭을 사용했다는 사실은 대부분의 사람이 잘 알고 있습니다. 하지만, 왜
in-memory inc 를 고집했냐는 사실에는 서로 다른 의견이 제시되고 있으며
반대로 in-memory inc 와 (jiffies++ 를 사용해) load/inc/store 를 선택하
는 것의 차이를 묻는 질문에 (kernel 개발자 중 한명인) Alan Cox 도
"Nothing" 이라고 답하고 있습니다 - 만약, 그 성능 차이가 뚜렷이 중요했
다면 "Nothing except for low efficiency" 정도의 답변이 나왔으리라 기대
할 수 있는 대목입니다. in-memory inc 를 생성하기 위한 것이 그 트릭의
목적이라는 것은 객관적인 사실이며 저 역시 다르게 생각하지 않습니다. 하
지만, 과연 지금까지 언급된 이유 중에 당시 그 트릭을 도입해 in-memory
inc 를 고집한 사람의 머릿속에 들어있는 이유는 무엇이었을까요? 이것을
묻고 있는 것이며 이는 확실한 근거 (당시 개발자의 증언이 가장 확실하겠
지요) 가 필요한 부분이지 추측이 필요한 부분이 아닙니다. 말씀드렸듯이
in-memory inc 가 더 나은 성능을 제공한다는 side effect 는 가질 수 있습
니다. 과연, 그것이 비의도적인 side effect 인지, 아니면 목적 그 자체이
고 (저를 포함한) 다른 사람들의 추측이 side effect 였는지는 여전히 불분
명합니다. (또한, "개인적으로는" 해당 do_timer 문맥이 in-memory inc 를
강제로 선택하는 것이 필수적일만큼 중요한 상황인지도 의심스럽습니다)

kyong wrote:
제가 이해하기론, *& hack 이 계속 쓰이는 것이 왜 더 좋은지 분명히 얘기하고
있었습니다.
http://www.ussg.iu.edu/hypermail/linux/kernel/0001.0/0456.html
http://www.ussg.iu.edu/hypermail/linux/kernel/0001.0/0275.html

위에서 말씀드린 이야기가 여전히 적용됩니다. 오히려 인용하신 글 중에는
in-memory inc 를 선택했다는 이야기만 있을 뿐, 그 선택에 대한 이유에 대
해서는 언급되어 있지 않습니다 - mailing list 내용 중에서 "빠른 성능"
의 가능성이 언급되었다는 사실을 밝힌 사람은 오히려 저였습니다. 만약,
님께서 "해당 트릭을 사용한 이유는 load/inc/stroe 대신 in-memory inc 를
선택하기 위함이다" 라고 주장하고 계신 것이라면 전적으로 동의합니다. 하
지만, 이는 제가 묻고 있는 것과는 다른 내용입니다.

kyong wrote:
제 근거는 앞서 얘기한 대로 입니다.
역사적인 흔적이란 말은 어울리지 않습니다. 현실적으로 나은 코드를 생성
하기 때문입니다. 더구나 깨끗한 코드를 선호하는 경향을 생각할 때 더욱
그렇습니다. 그래서 lkml에서 그런 토론이 있었덧 것이라고 생각됩니다.

"깨끗한 코드" 와 "빠른 코드" 는 다른 개념입니다. 그리고 님이 제시한 근
거 (in-memory inc 의 선택) 에는 님의 추측 이외에도 다른 추측도 가능하
다는 사실을 잊지 마시기 바랍니다.

kyong wrote:
그 의미는 여전히 유효합니다. lost_tick은 사라졌고 *& hack은 살아남았으니
까요. irc, lkml 에서 접한 여러 의견을 볼 때 전웅님이 주요한 목적이라고 생각하
는 경우는 너무 특수해서 드러나지 않았는지도 모릅니다. 그렇지만 코드는 어떤
주석보다도 분명히 말하고 있습니다.

님이나 저나, 논의에 참여한 대부분의 사람들 역시 "해당 문맥에서 *& hack
의 목적은 in-memory inc 를 사용하는 것이다" 라는 사실에는 동의합니다.

하지만, 님은 "또한 in-memory inc 를 사용한 의도된 목적은 빠른 성능이
다" 라고 단언하고 계신데 반해, 저는 "in-memory inc 를 사용한 의도된 목
적은 확신할 수 없다, 여러 가능한 이유가 있지만 빠른 성능을 필수적으로
생각한 것 같지는 않다" 라고 말했던 것입니다.

제 입장에 처음과 달라진 부분이 있다면 여러 버전의 kernel 코드를 살펴보
는 과정에서 "조금이라도 빠른 성능의 가능성" 을 주요한 목적으로 (혹은
주요한 목적 중 하나로) 고려했을 가능성도 완전히 배제할 수는 없겠다는
생각이 보다 더 커졌다는 것입니다 - "빠른 성능" 이 아닌 "빠른 성능의 가
능성" 이 더 바람직한 표현입니다, *& hack 으로 volatile 한정을 제거하는
것이 항상 "빠른 성능" 을 보장해 주지는 않습니다.

누군가가 mailing list 나 뉴스그룹을 통해 이 문제에 대한 확답을 찾아주
셨으면 좋겠습니다.

kyong wrote:
이렇게 하니까 더 빠르더라고. 그것 이상의 효과는 저로서는 불필요합니다.

계속해서 오해를 하고 계십니다. 저는,

*& hack 의 일반적인 목적을 묻고 있는 것이 아닙니다, 이미 말씀드렸듯이
과거 kernel 의 다른 부분에서는 *& hack 을 성능이 아닌 gcc 의 버그를 피
하기 위한 목적으로 (이는 분명히 밝혀진 사실입니다) 사용된 적도 있습니
다.

*& hack 의 "님이 생각하는" 혹은 "님이 필요로하는" 목적을 묻고 있는 것
이 아닙니다. "내 생각은 이렇다" 를 주장하고 계신 것이라면, 님이 논의에
참여하시기 이전과 상황이 달라진 부분은 없습니다.

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

kyong의 이미지

전웅 wrote:
kyong wrote:
객관적인 사실은 더 나은 코드가 생성됐다는 것입니다.(최소한 제가 테스트한
x86에서) 무엇이 객관적인 근거가 아니란 말씀이세요?

그 객관적 코드를 선택하게 된 원래 개발자의 의도는 다양할 수 있습니다.
이 문제와 관련된 mailing list 의 각종 논의를 보시면 아시겠지만,
load/inc/store 대신 in-memory inc 가 생성되도록 하기 위해서 그와 같은
트릭을 사용했다는 사실은 대부분의 사람이 잘 알고 있습니다.


제가 이 thread에 뛰어든 이유는 잘 정리가 되는 듯 하다가 흐름의 일관성이 결
여된 부분을 봤기 때문입니다.

다른 의미로 생각해 볼 수 있는 것은 이미 나왔습니다.

Quote:

이 글은, voaltile 로 선언된 대상체를 ++ 연산할 때 (컴파일러에 버그가
있는 것이 아니라면 - "mod." 는 "modulo" 를 의미하며 "~인 상황을 제외하
면" 정도로 이해할 수 있습니다) register 로 cache 되지 않으며,
(in-memory incl 가 아닌) load/incl/store 의 작업이 이루어질 수 있다고
이야기하고 있습니다.

말씀하셨는데, 처음 글쓴이의 의도는 volatile이기 때문에 값이 cache 되지
않는다는 말이며 다른 operation에 의해 값이 수정될 수 있다는 것을 말하고 있
는 것입니다. volatile ++에 대해서 register로 cache되지 않는다는 뜻과는 차이
가 있습니다.
그래서 atomic한 특성이 요구되어 지는데, incl은 atomic 하지 않지만 같은
processor에서 인터럽트가 걸린 상황에서는 incl이 atomic하게 이루어 지기 때
문에 중요하다고 생각한 것일 수도 있겠지요.

결국 남는 것은 timer irq는 고려 못하고 atomic한 것을 추구했다는 것인데 전
그보다는 최적화에 더 무게를 두는 것입니다. ugly code를 만든다고 주석을
단 것을 봐도 그렇고요.(누군지 알고 있지만 저자인지는 분명치 않지만)

Quote:

제 입장에 처음과 달라진 부분이 있다면 여러 버전의 kernel 코드를 살펴보
는 과정에서 "조금이라도 빠른 성능의 가능성" 을 주요한 목적으로 (혹은
주요한 목적 중 하나로) 고려했을 가능성도 완전히 배제할 수는 없겠다는
생각이 보다 더 커졌다는 것입니다 - "빠른 성능" 이 아닌 "빠른 성능의 가
능성" 이 더 바람직한 표현입니다, *& hack 으로 volatile 한정을 제거하는
것이 항상 "빠른 성능" 을 보장해 주지는 않습니다.

제가 의도한 것입니다. gcc가 보장해 주기를 기대하고 kernel개발이 이루어
지는 것은 아니니까요.

Quote:

kyong wrote:
이렇게 하니까 더 빠르더라고. 그것 이상의 효과는 저로서는 불필요합니다.

계속해서 오해를 하고 계십니다. 저는,

*& hack 의 일반적인 목적을 묻고 있는 것이 아닙니다, 이미 말씀드렸듯이
과거 kernel 의 다른 부분에서는 *& hack 을 성능이 아닌 gcc 의 버그를 피
하기 위한 목적으로 (이는 분명히 밝혀진 사실입니다) 사용된 적도 있습니
다.


*& hack의 일반적인 목적이 아니라 단지 이 code가 무엇을 말하는 지 분명히
하고 싶었을 뿐입니다.

Quote:

*& hack 의 "님이 생각하는" 혹은 "님이 필요로하는" 목적을 묻고 있는 것
이 아닙니다. "내 생각은 이렇다" 를 주장하고 계신 것이라면, 님이 논의에
참여하시기 이전과 상황이 달라진 부분은 없습니다.

다른 목적이 더 주요한 이유일 것이라고 말했기 때문에 thread가 길어진 것
입니다.
전웅의 이미지

kyong wrote:
Quote:

이 글은, voaltile 로 선언된 대상체를 ++ 연산할 때 (컴파일러에 버그가
있는 것이 아니라면 - "mod." 는 "modulo" 를 의미하며 "~인 상황을 제외하
면" 정도로 이해할 수 있습니다) register 로 cache 되지 않으며,
(in-memory incl 가 아닌) load/incl/store 의 작업이 이루어질 수 있다고
이야기하고 있습니다.

말씀하셨는데, 처음 글쓴이의 의도는 volatile이기 때문에 값이 cache 되지
않는다는 말이며 다른 operation에 의해 값이 수정될 수 있다는 것을 말하고 있
는 것입니다.

뭔가를 단단히 오해하고 계십니다. 해당 글을 쓴 사람은 이미 atomicity 가
보장될 필요가 없음을 알고 있는 상태였습니다 - 글 전체나 그 글이 속해
있는 thread 전체를 읽어 보시기 바랍니다.

Quote:
And the store may be deferred past other non-volatile operations and
function calls.

이 문장이 "다른 operation 의 간섭에 의해 값이 수정될 수 있음" 을 의미
하는 것이 아님을 이미 위에서 설명드렸고, 다른 분께서 보여주신 예와 질
문에도 답하였습니다 - 해당 부분을 다시 읽어보시기 바랍니다. 그리고 그
글쓴이는

Quote:
As we all know "incl" is not atomic between competing processors, but it
is atomic w.r.t. interrupts on the same processor as the increment.
Maybe that's why someone thought it was important.

라고 말하고 있습니다. 즉, "incl" 역시 어차피 SMP 에서는 atomic 하지 않
고, 또 do_timer 는 atomicity 을 신경 쓸 필요가 없는 상황인데도, 과거에
누군가가 그것이 중요하다 판단하여 in-memory inc 를 쓰도록 *& hack 을
사용한 것 같다고 말하고 있는 부분입니다.

kyong wrote:
volatile ++에 대해서 register로 cache되지 않는다는 뜻과는 차이
가 있습니다.

대체 무슨 말씀을 하고 계신 것인지 알 길이 없습니다. 왜 이미 멀쩡히 잘
설명되어 있는 글에 문맥에서 벗어난 잘못된 해석을 달고 계신 것인지요?

kyong wrote:
그래서 atomic한 특성이 요구되어 지는데, incl은 atomic 하지 않지만 같은
processor에서 인터럽트가 걸린 상황에서는 incl이 atomic하게 이루어 지기 때
문에 중요하다고 생각한 것일 수도 있겠지요.

이미 인용된 글의 글쓴이가 지적한 내용입니다 - 위를 보시기 바랍니다.

kyong wrote:
결국 남는 것은 timer irq는 고려 못하고 atomic한 것을 추구했다는 것인데 전
그보다는 최적화에 더 무게를 두는 것입니다. ugly code를 만든다고 주석을
단 것을 봐도 그렇고요.(누군지 알고 있지만 저자인지는 분명치 않지만)

님이 지금까지 보여주신 내용은 이미 다 설명된 내용이고, 번호를 붙여가며
질문주신 분에게 답변한 내용에도 정리되어 있습니다. 그리고, 저는 제 의
견을 충분히 밝혔고, 님도 님의 의견을 충분히 밝힌 상태이며, 제가 원하는
것은 더 이상의 "의견" 이 아닌 해당 트릭을 처음 도입한 사람이 마음 속에
품은 의도라고 반복하여 말씀드리고 있습니다. 이런 말씀 드리게 되어 죄송
하지만, 이미 진행된 논의를 무의미하게 반복하는 것이 님에게는 어떤 의미
가 있을지 모르겠지만, 저나 이 thread 를 읽는 다른 분들에게는 시간 낭비
입니다.

kyong wrote:
*& hack의 일반적인 목적이 아니라 단지 이 code가 무엇을 말하는 지 분명히
하고 싶었을 뿐입니다.

그 code 가 무엇을 말하는지는 님이 이 논의에 참여하기 이전부터 분명했습
니다. 여기서 분명하지 않은 것은 과연 그 code 를 고집한 원래 개발자의
생각이 무엇이냐는 것이었습니다. 이에 대해 저는 제 의견을 제시했고, 님
은 님의 의견을 제시한 것 뿐입니다. 또 다른 분은 또 다른 의견을 제시할
수 있는 상황입니다 (실제로 위에서 그러했습니다).

kyong wrote:
Quote:
*& hack 의 "님이 생각하는" 혹은 "님이 필요로하는" 목적을 묻고 있는 것
이 아닙니다. "내 생각은 이렇다" 를 주장하고 계신 것이라면, 님이 논의에
참여하시기 이전과 상황이 달라진 부분은 없습니다.

다른 목적이 더 주요한 이유일 것이라고 말했기 때문에 thread가 길어진 것
입니다.

반복하여 말씀드리지만, 님이 제시하신 근거만으로 (오히려 제가 님의 의견
에 힘을 더하는 근거를 보였지만) 님의 의견이 진실임을 확신할 수 있는 상
황이 아닙니다. 지금까지 제시된 다양한 추측 모두가 가능성이 있고 그럴싸
한 이야기지만, 당시 개발자 사이에 오고간 메일 내용이나 *& hack 을 도입
한 것에 대한 당시의 document 등이 밝혀지지 않는 이상 어떠한 추측이 맞
는지는 알 수 없다는 것이 제가 드리고 싶은 말씀입니다. 더 이상 추가적인
새로운 근거 없이 "내 생각은 이렇다" 라는 이야기는 아무런 발전을 가져오
지 않습니다.

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

kyong의 이미지

Quote:

전웅 wrote:
kyong wrote:
Quote:

이 글은, voaltile 로 선언된 대상체를 ++ 연산할 때 (컴파일러에 버그가
있는 것이 아니라면 - "mod." 는 "modulo" 를 의미하며 "~인 상황을 제외하
면" 정도로 이해할 수 있습니다) register 로 cache 되지 않으며,
(in-memory incl 가 아닌) load/incl/store 의 작업이 이루어질 수 있다고
이야기하고 있습니다.

말씀하셨는데, 처음 글쓴이의 의도는 volatile이기 때문에 값이 cache 되지
않는다는 말이며 다른 operation에 의해 값이 수정될 수 있다는 것을 말하고 있
는 것입니다.

뭔가를 단단히 오해하고 계십니다. 해당 글을 쓴 사람은 이미 atomicity 가
보장될 필요가 없음을 알고 있는 상태였습니다 - 글 전체나 그 글이 속해
있는 thread 전체를 읽어 보시기 바랍니다.


네 알고 있습니다. 원래 저자의 글을 잘 못 번역하셨다는 것을 전 지적하고 있습
니다. volatile때문에 register cache되지 않는다는 말이 맞다고 생각하세요?

Quote:

Quote:

Quote:
And the store may be deferred past other non-volatile operations and
function calls.

이 문장이 "다른 operation 의 간섭에 의해 값이 수정될 수 있음" 을 의미
하는 것이 아님을 이미 위에서 설명드렸고, 다른 분께서 보여주신 예와 질
문에도 답하였습니다 - 해당 부분을 다시 읽어보시기 바랍니다. 그리고 그
글쓴이는



찾을 수 없고 동의할 수 없습니다. 원저자의 문맥상도 그러하거니와,
수정될 수 있음이 atomicity를 거론한 이유였습니다.

Quote:

Quote:
As we all know "incl" is not atomic between competing processors, but it
is atomic w.r.t. interrupts on the same processor as the increment.
Maybe that's why someone thought it was important.

라고 말하고 있습니다. 즉, "incl" 역시 어차피 SMP 에서는 atomic 하지 않
고, 또 do_timer 는 atomicity 을 신경 쓸 필요가 없는 상황인데도, 과거에
누군가가 그것이 중요하다 판단하여 in-memory inc 를 쓰도록 *& hack 을
사용한 것 같다고 말하고 있는 부분입니다.

kyong wrote:
volatile ++에 대해서 register로 cache되지 않는다는 뜻과는 차이
가 있습니다.

대체 무슨 말씀을 하고 계신 것인지 알 길이 없습니다. 왜 이미 멀쩡히 잘
설명되어 있는 글에 문맥에서 벗어난 잘못된 해석을 달고 계신 것인지요?


원문을 인용하실 때 서로 대응되는 문장을 인용하시기 바랍니다.
문맥에 벗어난 해석을 한 사람은 제가 아닙니다.

Quote:

kyong wrote:
그래서 atomic한 특성이 요구되어 지는데, incl은 atomic 하지 않지만 같은
processor에서 인터럽트가 걸린 상황에서는 incl이 atomic하게 이루어 지기 때
문에 중요하다고 생각한 것일 수도 있겠지요.

이미 인용된 글의 글쓴이가 지적한 내용입니다 - 위를 보시기 바랍니다.


다른 주요한 이유로서 상기시키기 위해 다시 말한 것입니다.

kyong wrote:
결국 남는 것은 timer irq는 고려 못하고 atomic한 것을 추구했다는 것인데 전
그보다는 최적화에 더 무게를 두는 것입니다. ugly code를 만든다고 주석을
단 것을 봐도 그렇고요.(누군지 알고 있지만 저자인지는 분명치 않지만)

Quote:

님이 지금까지 보여주신 내용은 이미 다 설명된 내용이고, 번호를 붙여가며
질문주신 분에게 답변한 내용에도 정리되어 있습니다. 그리고, 저는 제 의
견을 충분히 밝혔고, 님도 님의 의견을 충분히 밝힌 상태이며, 제가 원하는
것은 더 이상의 "의견" 이 아닌 해당 트릭을 처음 도입한 사람이 마음 속에
품은 의도라고 반복하여 말씀드리고 있습니다. 이런 말씀 드리게 되어 죄송
하지만, 이미 진행된 논의를 무의미하게 반복하는 것이 님에게는 어떤 의미
가 있을지 모르겠지만, 저나 이 thread 를 읽는 다른 분들에게는 시간 낭비
입니다.

다른 사람의 시간까지 관리하실 필요는 없습니다. 원 저자의 마음을 확인한 후에
코드를 읽지는 않습니다.

Quote:

kyong wrote:
*& hack의 일반적인 목적이 아니라 단지 이 code가 무엇을 말하는 지 분명히
하고 싶었을 뿐입니다.

그 code 가 무엇을 말하는지는 님이 이 논의에 참여하기 이전부터 분명했습
니다. 여기서 분명하지 않은 것은 과연 그 code 를 고집한 원래 개발자의
생각이 무엇이냐는 것이었습니다. 이에 대해 저는 제 의견을 제시했고, 님
은 님의 의견을 제시한 것 뿐입니다. 또 다른 분은 또 다른 의견을 제시할
수 있는 상황입니다 (실제로 위에서 그러했습니다).


분명한 분도 있었고 아닌 분도 있었습니다. 전 제 결론에 충실해서 이 thread에
참여한 것 뿐입니다. 제가 원 저자가 아니어서 제 결론에 충실한 것이 문제가
됩니까? 전웅님이 이 thread에 참여하기 이전에 이미 그런 내용들은 있었습니다.
단지 전 최적화로 굳히기를 시도했을 뿐입니다.

Quote:

kyong wrote:
Quote:
*& hack 의 "님이 생각하는" 혹은 "님이 필요로하는" 목적을 묻고 있는 것
이 아닙니다. "내 생각은 이렇다" 를 주장하고 계신 것이라면, 님이 논의에
참여하시기 이전과 상황이 달라진 부분은 없습니다.

다른 목적이 더 주요한 이유일 것이라고 말했기 때문에 thread가 길어진 것
입니다.

반복하여 말씀드리지만, 님이 제시하신 근거만으로 (오히려 제가 님의 의견
에 힘을 더하는 근거를 보였지만) 님의 의견이 진실임을 확신할 수 있는 상
황이 아닙니다. 지금까지 제시된 다양한 추측 모두가 가능성이 있고 그럴싸
한 이야기지만, 당시 개발자 사이에 오고간 메일 내용이나 *& hack 을 도입
한 것에 대한 당시의 document 등이 밝혀지지 않는 이상 어떠한 추측이 맞
는지는 알 수 없다는 것이 제가 드리고 싶은 말씀입니다. 더 이상 추가적인
새로운 근거 없이 "내 생각은 이렇다" 라는 이야기는 아무런 발전을 가져오
지 않습니다.


*& hack을 도입한 배경은 lkml에서 이미 밝혀졌고 반대하는 기고는
없었습니다. 누가 발전을 가져오는지 판단할 입장은 아니라고 생각됩니다.
최적화가 주요 이유임을 부정하신 분이 정확한 논거를 가지고 이 thread에
다시 나타나셔야 할 것으로 생각됩니다.
전 제가 테스트한 결과를 정확한 근거로 이미 제시했으니까요.
전웅의 이미지

kyong wrote:
전웅 wrote:
뭔가를 단단히 오해하고 계십니다. 해당 글을 쓴 사람은 이미 atomicity 가
보장될 필요가 없음을 알고 있는 상태였습니다 - 글 전체나 그 글이 속해
있는 thread 전체를 읽어 보시기 바랍니다.

네 알고 있습니다. 원래 저자의 글을 잘 못 번역하셨다는 것을 전 지적하고 있습
니다. volatile때문에 register cache되지 않는다는 말이 맞다고 생각하세요?

이제야 님이 무엇을 오해하고 계신지 알겠습니다. 님은 volatile 과 해당
글의 글쓴이가 이야기한 "register cache" 를 잘못 이해하고 계십니다. 아
마도 해당 글쓴이가 "volatile 가 register cache 를 막아준다" 라고 이야
기한 것을 "CPU register 에 전혀 올리지 않고 메모리 상에서 (in-memory)
바로 연산된다" 를 의미하는 것으로 오해하신 것 같습니다. volatile 에 대
해 이야기할 때 사용되는 "register cache 금지" 라는 표현은 그런 뜻이 아
닙니다. volatile 은 프로그램의 특정 부분에서 (이를 sequence point 라고
부릅니다) 실제 대상체에 저장되어 있는 값이 프로그램이 보여주는 추상적
인 semantic 과 일치함을 보장하는 것이며, 두 sequence point 사이에서의
register caching 까지 막지는 않습니다. 즉, 그 글쓴이가 말한 것은 다음
과 같은 문장을 (i 에 이루어지는 side effect 를 implementation 이 예측
할 수 없다면),

volatile int i;

for (i = 0; i < 100; i++) func(i);

아래와 같이 번역할 수 없음의 의미하는 것 뿐이며,

register int r;    // "register" obeyed
for (r = 0; r < 100; r++) func(r);
i = r;

in-memory operation 이 이루어져야 한다고 주장한 것은 아닙니다.
이제 오해가 해결되었는지요?

kyong wrote:
전웅 wrote:
이 문장이 "다른 operation 의 간섭에 의해 값이 수정될 수 있음" 을 의미
하는 것이 아님을 이미 위에서 설명드렸고, 다른 분께서 보여주신 예와 질
문에도 답하였습니다 - 해당 부분을 다시 읽어보시기 바랍니다. 그리고 그
글쓴이는

찾을 수 없고 동의할 수 없습니다. 원저자의 문맥상도 그러하거니와,
수정될 수 있음이 atomicity를 거론한 이유였습니다.

흠... volatile 에 대해서 뭔가를 많이 오해하고 계신 것 같습니다. 만약,
해당 문장이 "다른 operation 의 간섭에 의해 값이 수정될 수 있음" 을 의
미하는 것이었다면 왜 간섭할 수 있는 operation 을 non-volatile 로 한정
했을까요? 해당 글쓴이는 다른 thread 나 processor 의 간섭이 없음을 (따
라서 atomicity 에 대한 걱정이 불필요함을) 알고 있는 상태에서 "같은" 프
로그램의 다른 (non-volatile) operation 에 의해 volatile 연산의 일부가
지연될 수 있음을 말하고 있는 것입니다. 그리고 이미 다른 분이 예를 보여
주셨듯이 이는 실제 일어나는 일이고, 표준이 허락하고 있는 것이며, 대다
수의 실제적인 impelemtation 에서 그와 같은 지연이 일어나지 않았을 때와
차이를 만들지 않습니다 - 즉, 아직까지 그렇게까지 똑똑하거나 무모한 컴
파일러는 개발되지 않았습니다.

kyong wrote:
원문을 인용하실 때 서로 대응되는 문장을 인용하시기 바랍니다.
문맥에 벗어난 해석을 한 사람은 제가 아닙니다.

이 부분 역시 위에서 있었던 volatile 에 대한 오해를 푸신다면 자연스레
이해되실 부분이라 생각합니다.

제가 원문을 보이지 않은 상태에서 여러 문장으로 찢어 제 입맛에 맞도록
해석했다면 오해의 가능성이 있을 수 있지만, 원문이 고스란히 미리 제공된
상태에서 제가 제 글의 흐름에 맞춰 인용해가며 설명드린 것입니다. 제가
원문의 흐름을 따르지 않으며 해석했을지 모르겠지만, 제 해석은 기술적으
로 틀린 부분이 없습니다. 제 해석이 틀리다는 것을 증명하고자 하신다면
정확한 근거를 보여주시기 바랍니다.

kyong wrote:
다른 사람의 시간까지 관리하실 필요는 없습니다. 원 저자의 마음을 확인한 후에
코드를 읽지는 않습니다.

처음부터 제가 궁금했던 것은 원 개발자의 의도였습니다. 대체 무엇을 위해
서 이 논의를 이어가고 계신 것인지 알 수 없군요.

kyong wrote:
분명한 분도 있었고 아닌 분도 있었습니다.

분명하지 않은 부분은 반복하여 말씀드리듯이 원 개발자의 의도 였으며, 이
는 제 능력으로는 추측만 가능할 뿐 확신할 수는 없는 부분입니다 - 님의
의견 역시 가능한 한 가지 추측에 불과합니다. 나머지 부분은 모두 기술적
으로 분명했으며, 다만 님께서 내용을 잘못 이해하신 후에 불분명하다고 판
단하신 것 뿐입니다. 원 개발자의 의도를 추측하는 부분을 제외하고 기술적
으로 틀린 부분이 있다면 지적 바랍니다.

kyong wrote:
전 제 결론에 충실해서 이 thread에
참여한 것 뿐입니다. 제가 원 저자가 아니어서 제 결론에 충실한 것이 문제가
됩니까?

그러면, "제 생각에는 조금이라도 빠른 성능을 얻고자 한 것 같습니다" 라
는 문장이 적절했습니다. 확실한 근거를 가지고 있는 듯한 느낌의 단언적인
태도는 오해를 낳을 수 있습니다 - 또한, 실제 오해를 낳았습니다.

그리고, 님이 개인적인 의견을 제시하는 것에는 아무런 문제가 없지만, 틀
리지 않은 기술적 내용을 틀린 것처럼 (잘못되게) 해석하고 판단하는 것에
는 분명 문제가 있습니다.

kyong wrote:
전웅님이 이 thread에 참여하기 이전에 이미 그런 내용들은 있었습니다.
단지 전 최적화로 굳히기를 시도했을 뿐입니다.

기술적 토론은 힘이 주가 되는 레슬링이 아닙니다. 님께서 근거 없이 단언
적인 태도를 취하며 "굳히기" 를 시도한다고 해서 굳혀지는 것도 아닙니다.
저 역시 원 개발자의 의도에 대해서 근거가 부족한 추측을 제시하고 있는
마당에 다른 분들이 추측을 제시했다고 해서 그것이 잘못이라고 탓하지는
않습니다. 하지만, 님의 다음과 같은 문장은

kyong wrote:
위에서 이미 나왔듯이 이것은 순전히 최적화와 관련된 문제입니다.

추측을 보이는 것이라 생각하기 어렵습니다. 진정한 "굳히기" 를 원하신다
면 원 개발자의 의도를 보여주는 근거를 제시해 주시기 바랍니다. 이는 오
래전부터 제가 바라던 것이기도 합니다.

kyong wrote:
*& hack을 도입한 배경은 lkml에서 이미 밝혀졌고 반대하는 기고는
없었습니다.

어디서 밝혀졌죠? in-memory incl 를 쓰는 것이 그 배경인가요? 이는 이미
확실한 사실입니다. 그러면, in-memory incl 를 쓰는 배경은 무엇인가요?
lkml 에서 어떤 사람은 "없다" 고 답하고, 어떤 사람은 "역사적 이유" 라고
답하고, 또 어떤 사람은 "불필요한 atomicity 에 대한 걱정" 이라고 답하고
있으며, 이들 모두에 반대하는 기고는 없었습니다.

kyong wrote:
누가 발전을 가져오는지 판단할 입장은 아니라고 생각됩니다.
최적화가 주요 이유임을 부정하신 분이 정확한 논거를 가지고 이 thread에
다시 나타나셔야 할 것으로 생각됩니다.

안타깝게도 방준영님은 더 이상 KLDP BBS 에서 활동하시지 않습니다.

kyong wrote:
전 제가 테스트한 결과를 정확한 근거로 이미 제시했으니까요.

님이 이 논의에 참여하기 이전에 논의에 참여하고 있던 사람들은 해당 부분
을 도입한 원 개발자의 의도에 대해서 고민하고 있었습니다. 그리고, 방준
영님은 그 의도는 최적화가 아닐 것이라는 다소 단정적인 태도를 취하셨고
(그렇더라도 추측에서는 벗어나지 않습니다), 저 역시 다른 부분을 보았을
때 그럴 가능성은 적다는 의견을 보인 것입니다. 이 논의에 참여하던 대부
분의 사람들도 in-memory incl 이 더 나은 성능을 보일 것이라는 사실에 대
해서는 (님이 테스트 결과를 제시하기 이전부터) 인지하고 있었으며, 다만
그것이 진정 원 개발자의 의도인지를 의심하고 있던 상황이었습니다. 따라
서, 님이 제시한 테스트 결과는 "해당 코드는 더 나은 성능을 보인다" 라는
(이미 동의되어 있는) 주장을 뒷받침하기에는 적절하지만 "원 개발자의 의
도는 성능 향상이었다" 라는 주장을 뒷받침하기에는 부족합니다.

토론 중에 부적절한 말씀을 드리는 느낌이지만, 더 이상 새로운 기술적 사
실이나 객관적 증거가 없다면 더 이상의 논의는 시간 낭비라 생각합니다.
님이 개인적인 의견을 사견임을 분명히 하며 밝히는 것은 (다른 것이 진실
임을 누구도 알지 못하는 상태에서) 그 누구도 막지 않습니다. 다만, 더 이
상 올바른 기술적 내용에 대한 왜곡이 없기를 바랍니다.

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

mastercho의 이미지

관리자님의 쓰레드 닫기가 이루어져야 하겠네요 ㅎㅎ

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

kyong의 이미지

전웅 wrote:
kyong wrote:
전웅 wrote:
뭔가를 단단히 오해하고 계십니다. 해당 글을 쓴 사람은 이미 atomicity 가
보장될 필요가 없음을 알고 있는 상태였습니다 - 글 전체나 그 글이 속해
있는 thread 전체를 읽어 보시기 바랍니다.

네 알고 있습니다. 원래 저자의 글을 잘 못 번역하셨다는 것을 전 지적하고 있습
니다. volatile때문에 register cache되지 않는다는 말이 맞다고 생각하세요?

이제야 님이 무엇을 오해하고 계신지 알겠습니다. 님은 volatile 과 해당
글의 글쓴이가 이야기한 "register cache" 를 잘못 이해하고 계십니다.


아닙니다. 제가 정확히 이해하고 있다고 생각합니다.

Quote:

아마도 해당 글쓴이가 "volatile 가 register cache 를 막아준다" 라고 이야
기한 것을 "CPU register 에 전혀 올리지 않고 메모리 상에서 (in-memory)
바로 연산된다" 를 의미하는 것으로 오해하신 것 같습니다. volatile 에 대
해 이야기할 때 사용되는 "register cache 금지" 라는 표현은 그런 뜻이 아
닙니다.

해당 글쓴이가 한 말을 다음과 같았습니다.
원문 wrote:

Andrea Arcangeli wrote:
> >(*(unsigned long *)&jiffies)++;
> >
> >why not just jiffies++; ? It works fine with jiffies++ but I assume there
> >is a reason...
>
> No reason. It won't make any difference.
>
> You could as well do jiffies++. jiffies is volatile so it can't be
> reodered across other `;' and it won't be cached into registers.

There was a thread on the egcs list about this a few months
ago. GCC does not guarantee that incrementing a volatile will do it in
a single instruction, even if a single instruction is available.

The value won't be cached (mod. compiler bugs), but it may be loaded,
incremented and then stored. And the store may be deferred past other
non-volatile operations and function calls.

As we all know "incl" is not atomic between competing processors, but it
is atomic w.r.t. interrupts on the same processor as the increment.
Maybe that's why someone thought it was important.

But as Andrea says:
> The only "jiffies" writer is the timer irq handler that as an irq handler
> is single threaded by the linux irq design. So there's no point at all to
> even think about atomicity.

So jiffies++ would be fine.

-- Jamie


문맥상 의미를 얘기 하기 전에,
volatile 이 register cache를 막아준다는 말은 맞습니다. register에 copy한다면
그 사이 원래 메모리에서 수정이 이루어 졌을 경우에 문제가 있는 것입니다.
in memory incl 같은 경우는 최소한 x86에서 지원하는 연산인 것입니다. 그리고
volatile은 compiler에게 physical memory외에 어떤 가정도 하지 말도록 하는
것입니다.

제가 저번에 그와 같이 질문을 드린 것은 원문 2번째 단락의 정확한 의미는
메모리에서 값의 수정이 이루어 질 수 있기 때문에 volatile이 atomicity를
오히려 방해한다는 것인데 이 의미를 제대로 번역하지 못했고 그래서 인지
모르지만, 다른 이유의 가장 유력한 후보가 무시 됐기 때문에 상기 시킨 것
입니다.
원문을 보면 알겠지만 인용하면서 Andrea Arcangeli가 한 말을 또 한 것이
아니라, 뒤에 나오는 atomictiy의 근거로서 값에 초점을 뒀다는 것을 다시
말씀드립니다.

Quote:

volatile 은 프로그램의 특정 부분에서 (이를 sequence point 라고
부릅니다) 실제 대상체에 저장되어 있는 값이 프로그램이 보여주는 추상적
인 semantic 과 일치함을 보장하는 것이며, 두 sequence point 사이에서의
register caching 까지 막지는 않습니다.

틀렸다고 생각됩니다. squence point사이의 최적화는 허용하지만 register
caching은 막으며, 즉 volatile object의 reference는 최적화 되지 말아야 한다는
것이 표준입니다. 단, 같은 volatile object가 two squence point 사이에 여러번
쓰일 때는 compiler가 optimize 할 수 있습니다.

Quote:

즉, 그 글쓴이가 말한 것은 다음
과 같은 문장을 (i 에 이루어지는 side effect 를 implementation 이 예측
할 수 없다면),

volatile int i;

for (i = 0; i < 100; i++) func(i);

아래와 같이 번역할 수 없음의 의미하는 것 뿐이며,

register int r;    // "register" obeyed
for (r = 0; r < 100; r++) func(r);
i = r;

in-memory operation 이 이루어져야 한다고 주장한 것은 아닙니다.
이제 오해가 해결되었는지요?


글쓴이가 한 말과 상관없는 예제 입니다.
register는 더구나 compiler에게 advice하는 것이지 register를 쓴다는
보장도 없습니다. 물론 요즘 compiler는 알아서 쓰지만요.
그러나 squence point를 볼 때 register caching이 가능한 경우라고 생각됩니다.
원문에 당연히 im-memory operation 주장한적 없습니다.

Quote:

kyong wrote:
전웅 wrote:
이 문장이 "다른 operation 의 간섭에 의해 값이 수정될 수 있음" 을 의미
하는 것이 아님을 이미 위에서 설명드렸고, 다른 분께서 보여주신 예와 질
문에도 답하였습니다 - 해당 부분을 다시 읽어보시기 바랍니다. 그리고 그
글쓴이는

찾을 수 없고 동의할 수 없습니다. 원저자의 문맥상도 그러하거니와,
수정될 수 있음이 atomicity를 거론한 이유였습니다.

흠... volatile 에 대해서 뭔가를 많이 오해하고 계신 것 같습니다. 만약,
해당 문장이 "다른 operation 의 간섭에 의해 값이 수정될 수 있음" 을 의
미하는 것이었다면 왜 간섭할 수 있는 operation 을 non-volatile 로 한정
했을까요? 해당 글쓴이는 다른 thread 나 processor 의 간섭이 없음을 (따
라서 atomicity 에 대한 걱정이 불필요함을) 알고 있는 상태에서 "같은" 프
로그램의 다른 (non-volatile) operation 에 의해 volatile 연산의 일부가
지연될 수 있음을 말하고 있는 것입니다. 그리고 이미 다른 분이 예를 보여
주셨듯이 이는 실제 일어나는 일이고, 표준이 허락하고 있는 것이며, 대다
수의 실제적인 impelemtation 에서 그와 같은 지연이 일어나지 않았을 때와
차이를 만들지 않습니다 - 즉, 아직까지 그렇게까지 똑똑하거나 무모한 컴
파일러는 개발되지 않았습니다.


위에서 얘기 했듯이 연산의 지연에 관한 문제가 아니라 값(value)의 atomicity
에 관한 문제입니다. 그리고 연산중에 일어날 수도 있고 아닐 수도 있습니다.
왜냐면 register에서 일어나는 것이 아니라 memory에서 일어나기 때문입니다.
non-volatile으로 한정한 것이 아니라 memory에 있기 때문에 memory를 접근
하는 모든 operation에 의해서 값이 수정될 수 있다는 것을 뜻한다고 생각합
니다. 결과적으로 차이를 만들지 않는다는 것은 표준과 동떨어진 말이며
차이는 날 수도 있고 안 날 수도 있습니다.

Quote:

제가 원문을 보이지 않은 상태에서 여러 문장으로 찢어 제 입맛에 맞도록
해석했다면 오해의 가능성이 있을 수 있지만, 원문이 고스란히 미리 제공된
상태에서 제가 제 글의 흐름에 맞춰 인용해가며 설명드린 것입니다. 제가
원문의 흐름을 따르지 않으며 해석했을지 모르겠지만, 제 해석은 기술적으
로 틀린 부분이 없습니다. 제 해석이 틀리다는 것을 증명하고자 하신다면
정확한 근거를 보여주시기 바랍니다.

최초 원문 번역은 문맥상 차이가 있기 때문에 번역 기술상 틀렸다고 생각됩니다.
operation의 간섭의 문제가 아니라 지연의 문제라고 주장하신 것은 의미상
동일 할 수 있지만 대다수 implementation에서 차이가 없다고 말하신 것으로
봐서 기술적으로 잘 못 이해하신 것이라고 생각됩니다. 그러나 미묘하지만
경우에 따라 굉장한 차이라고 생각됩니다. 오늘 나온 다른 문제는 위에서
얘기를 했고요.

Quote:

kyong wrote:
다른 사람의 시간까지 관리하실 필요는 없습니다. 원 저자의 마음을 확인한 후에
코드를 읽지는 않습니다.

처음부터 제가 궁금했던 것은 원 개발자의 의도였습니다. 대체 무엇을 위해
서 이 논의를 이어가고 계신 것인지 알 수 없군요.


제가 주장한 이유를 능가하는 합당한 이유가 나타나지 않으면서 계속 thread가
길어지는 것에 대해서는 저도 궁굼합니다.

kyong wrote:
분명한 분도 있었고 아닌 분도 있었습니다.

Quote:

분명하지 않은 부분은 반복하여 말씀드리듯이 원 개발자의 의도 였으며, 이
는 제 능력으로는 추측만 가능할 뿐 확신할 수는 없는 부분입니다 - 님의
의견 역시 가능한 한 가지 추측에 불과합니다. 나머지 부분은 모두 기술적
으로 분명했으며, 다만 님께서 내용을 잘못 이해하신 후에 불분명하다고 판
단하신 것 뿐입니다. 원 개발자의 의도를 추측하는 부분을 제외하고 기술적
으로 틀린 부분이 있다면 지적 바랍니다.

이미 나온 것이지만 제 의견을 하나의 가설이라고 하죠.
다른 유력한 가설이 나오지 못했고 기존 가설을 뒤집을 만한 조그만 증거도
나오지 못했다면 한 가지 추측 뿐이라고 말할 수 있겠습니까?
역사 과목이라고 해도 인정해야 할 것입니다.
제가 잘 못 이해한 부분을 말씀해 주시기 바랍니다.

Quote:

kyong wrote:
전 제 결론에 충실해서 이 thread에
참여한 것 뿐입니다. 제가 원 저자가 아니어서 제 결론에 충실한 것이 문제가
됩니까?

그러면, "제 생각에는 조금이라도 빠른 성능을 얻고자 한 것 같습니다" 라
는 문장이 적절했습니다. 확실한 근거를 가지고 있는 듯한 느낌의 단언적인
태도는 오해를 낳을 수 있습니다 - 또한, 실제 오해를 낳았습니다.


제 단언을 반박할 만한 증거도 없이 어떤 오해가 나왔다는 것이죠?
그럼 님이 하실 일은 분명합니다. 또 다른 추측으로 기존 사실을 흐리지
말고 정확한 근거로 답하시는 것입니다.
Quote:

없었으며, 앞으로도 없습니다

전 현재 존재하는 코드를 두고 확신했지만 님은 미래를 두고 확신 하셨더군요.

Quote:

kernel 에서 (jiffies 를 제외하고) volatile 한정을 제거하기 위한 (그래
서 in-memory op 를 얻기 위한) 목적으만으로 *& hack 을 사용한 다른 부분
이 있습니까? 참고로 sys_iopl() 은 적용되지 않습니다 - volatile 한정을
제거하는 목적이 아니라 과거 gcc 의 bug 를 피하기 위한 목적으로 사용된
곳입니다.

애초에 님이 가졌던 생각을 짐작할 수 있으며 역시 근거도 없이 단정하고 있습
니다.

Quote:

그리고, 님이 개인적인 의견을 제시하는 것에는 아무런 문제가 없지만, 틀
리지 않은 기술적 내용을 틀린 것처럼 (잘못되게) 해석하고 판단하는 것에
는 분명 문제가 있습니다.

역시 기술적으로 틀린 부분을 밝혀 주시기 바랍니다.

Quote:

kyong wrote:
전웅님이 이 thread에 참여하기 이전에 이미 그런 내용들은 있었습니다.
단지 전 최적화로 굳히기를 시도했을 뿐입니다.

기술적 토론은 힘이 주가 되는 레슬링이 아닙니다. 님께서 근거 없이 단언
적인 태도를 취하며 "굳히기" 를 시도한다고 해서 굳혀지는 것도 아닙니다.
저 역시 원 개발자의 의도에 대해서 근거가 부족한 추측을 제시하고 있는
마당에 다른 분들이 추측을 제시했다고 해서 그것이 잘못이라고 탓하지는
않습니다. 하지만, 님의 다음과 같은 문장은

kyong wrote:
위에서 이미 나왔듯이 이것은 순전히 최적화와 관련된 문제입니다.

추측을 보이는 것이라 생각하기 어렵습니다. 진정한 "굳히기" 를 원하신다
면 원 개발자의 의도를 보여주는 근거를 제시해 주시기 바랍니다. 이는 오
래전부터 제가 바라던 것이기도 합니다.


네 레슬링이 아님을 동의합니다. 그리고 전 추측하지 않고 당당히 근거에 기초해
말했습니다. 누군가 원 개발자의 의도를 말한다고 해도 역시 code와 tool로 확인
한 후 검증하는 것이 순서일 것입니다. 지금 code가 있는 상황에서 필수가 아님
을 말씀드립니다.

kyong wrote:
*& hack을 도입한 배경은 lkml에서 이미 밝혀졌고 반대하는 기고는 없었습니다.

Quote:

어디서 밝혀졌죠? in-memory incl 를 쓰는 것이 그 배경인가요? 이는 이미
확실한 사실입니다.

정확히 volatile을 피해 compiler에게 최적화를 유도하는 것입니다.
결과적으로 x86에서 in-memory incl로 나타난 것입니다.
명확한 사실이라고 얘기하시는 것은 의견의 변화라고 생각됩니다.

Quote:

그러면, in-memory incl 를 쓰는 배경은 무엇인가요?
lkml 에서 어떤 사람은 "없다" 고 답하고, 어떤 사람은 "역사적 이유" 라고
답하고, 또 어떤 사람은 "불필요한 atomicity 에 대한 걱정" 이라고 답하고
있으며, 이들 모두에 반대하는 기고는 없었습니다.

in-memory incl에 대해서 세번째로 든 이유말고 첫번째, 두번째 이유라는
기고가 있었던 가요? 알고있었는지 모르지만 in-memory incl이 밝혀지기
전에 alan cox가 없다고 한 것은 기억나지만요. thread가 길어지다 보니
가물한데, 절절한 이유를 들어 performance라고 생각한 분이 더 많았다고
기억됩니다.

Quote:

kyong wrote:
누가 발전을 가져오는지 판단할 입장은 아니라고 생각됩니다.
최적화가 주요 이유임을 부정하신 분이 정확한 논거를 가지고 이 thread에
다시 나타나셔야 할 것으로 생각됩니다.

안타깝게도 방준영님은 더 이상 KLDP BBS 에서 활동하시지 않습니다.


그러면 지금까지 이 thread에 계속 답글을 다신 이유가 무엇입니까?

Quote:

kyong wrote:
전 제가 테스트한 결과를 정확한 근거로 이미 제시했으니까요.

님이 이 논의에 참여하기 이전에 논의에 참여하고 있던 사람들은 해당 부분
을 도입한 원 개발자의 의도에 대해서 고민하고 있었습니다. 그리고, 방준
영님은 그 의도는 최적화가 아닐 것이라는 다소 단정적인 태도를 취하셨고
(그렇더라도 추측에서는 벗어나지 않습니다), 저 역시 다른 부분을 보았을
때 그럴 가능성은 적다는 의견을 보인 것입니다. 이 논의에 참여하던 대부
분의 사람들도 in-memory incl 이 더 나은 성능을 보일 것이라는 사실에 대
해서는 (님이 테스트 결과를 제시하기 이전부터) 인지하고 있었으며, 다만
그것이 진정 원 개발자의 의도인지를 의심하고 있던 상황이었습니다. 따라
서, 님이 제시한 테스트 결과는 "해당 코드는 더 나은 성능을 보인다" 라는
(이미 동의되어 있는) 주장을 뒷받침하기에는 적절하지만 "원 개발자의 의
도는 성능 향상이었다" 라는 주장을 뒷받침하기에는 부족합니다.


님의 생각은 일관적이였는지 모르지만 글을 봤을 때 그렇지 않았고,
원 개발자의 의도가 어떠했든 간에 지금 maintainer가 그 코드를 유지하고
있는 주요한 이유는 performance라는 것을 저는 얘기하고 있는 것입니다.

Quote:

토론 중에 부적절한 말씀을 드리는 느낌이지만, 더 이상 새로운 기술적 사
실이나 객관적 증거가 없다면 더 이상의 논의는 시간 낭비라 생각합니다.
님이 개인적인 의견을 사견임을 분명히 하며 밝히는 것은 (다른 것이 진실
임을 누구도 알지 못하는 상태에서) 그 누구도 막지 않습니다. 다만, 더 이
상 올바른 기술적 내용에 대한 왜곡이 없기를 바랍니다.

topic에 집중해 주시기 바랍니다.
kslee80의 이미지

전웅님과 kyong님 두분다 이쯤에서 그만 두시는게 어떨지요.
두분의 토론이 계속해서 쳇바퀴 돌듯 도는거 같습니다.

전웅님은 현재 해당 코드의 명확한 이유..즉, lkml 이건 어디서건 간에
해당 코드의 개발자의 말이나 혹은 다른 개발자들의 의견등 명확한 이유를
찾으시려고 하는 것이며..
kyong 님은 가장 가능성 있는 가설을 제시하셨고,
그 가설의 가능성에 대한 증명까지 하셨습니다.
그리고 그 가설이 이 코드의 이유이다..라는 주장을 하시고 있습니다.

즉, 두분이 궁극적으로 찾고자 하는 것은 같지만..
그 과정이 서로 틀리기 때문에 계속해서 헛도는 듯한 토론이 되어 가고 있는거
같습니다.

이쯤에서 kyong님과 전웅님께서
자신의 의견을 정리하는 글을 한개씩 추가하시고 토론을 끝내는게 어떨지요?
(필요없다고 생각하신다면, 그렇게 하지 않아도 될듯 싶습니다만;;)

Necromancer의 이미지

x86 어셈블리는 인텔이나 AMD에서 공개하는 프로세서 메뉴얼이 가장 좋습니다.
(인텔이 더 좋더군요.)
시중 책들은 대부분 초보 강좌 수준입니다. 처음 공부할 때 빼고는
별도 도움 안됩니다.

특히 모르는 명령어가 나왔을 경우에는 이들 매뉴얼보면 다 찾을 수 있습니다.

또 nasm 문서 보면 뒤에 지원 x86명령어 리스트가 나와 있습니다.
그것도 보시고요.

컴퓨터구조는 필수입니다.

Written By the Black Knight of Destruction

전웅의 이미지

kyong wrote:
문맥상 의미를 얘기 하기 전에,
volatile 이 register cache를 막아준다는 말은 맞습니다. register에 copy한다면
그 사이 원래 메모리에서 수정이 이루어 졌을 경우에 문제가 있는 것입니다.

님의 글 전체를 읽었을 때, 대체 님이 무엇을 이해하고 계신지, 어느 부분
을 오해하고 계신지 알기 어렵습니다. 지금까지는 논의를 가능한 빨리 마무
리하고자 직접 서술형의 답을 드렸지만 지금부터는 간단히 질문으로 답을
이어가겠습니다. 이 질문은 님의 귀찮게 혹은 불쾌하게 하려는 의도가 아니
라 구체적으로 님과 저 사이에 어떤 오해가 있는지 확인하기 위한 것입니다.

- volatile 이 register cache 를 막아준다는 말이 맞다는 뜻은, volatile
대상체 i 에 대한 ++ 연산에 대해서 다음과 같은 코드를 생성하는 것이 잘
못되었다는 뜻으로 하시는 말씀인지요?

load i into r1
add 1 to r1
store r1 into i

아니면 제가 아래에서 보였던 예와 같이 프로그램의 특정 시점에서 프로그
램이 명시하는 abstract semantic 과 actual implementation 이 일치함을
의미하시는 것인지요?

kyong wrote:
in memory incl 같은 경우는 최소한 x86에서 지원하는 연산인 것입니다. 그리고
volatile은 compiler에게 physical memory외에 어떤 가정도 하지 말도록 하는
것입니다.

- "님이 알고 계시는" volatile 의 공통된 의미에 대해서 설명 부탁드립니
다. 특히, "physical memory 외에 어떠한 가정도 하지 말라" 는 말의 뜻은
어떠한 구체적인 행위가 금지된다는 뜻으로 하신 말씀인지요?

kyong wrote:
제가 저번에 그와 같이 질문을 드린 것은 원문 2번째 단락의 정확한 의미는
메모리에서 값의 수정이 이루어 질 수 있기 때문에 volatile이 atomicity를
오히려 방해한다는 것인데 이 의미를 제대로 번역하지 못했고

- 그렇다면 반대로 volatile 을 사용하지 않아 in-memory operation 을 얻
어냈을 때는 atomicity 가 보장되는지요?

load/inc/store 가 생성되든 in-memory incl 이 생성되든 어차피 근본적인
atomicity 는 보장되지 않습니다. 해당 글쓴이는 이러한 사실을 알고 있었
고, do_timer 가 기본적으로 atomicity 가 보장되는 특수한 상황에 있다는
것도 알고 있었습니다. do_timer 의 특수한 상황에서, 단일 명령어와 여러
개의 명령어로 생성된 것에는, "같은" 프로그램의 다른 "non-volatile" 연
산이 jiffies 를 증가시키는 행동에 끼어들 수 있느냐 없느냐의 차이를 낳
는다는 것이 해당 문장의 의미입니다 - 하지만, 그러한 끼어듬이 jiffies
의 값의 품질에 영향을 주지는 않습니다. do_timer 가 아닌 일반적인 문맥
에서 volatile 이 없어서 incl 이 선택된다고 해도 어차피 atomicity 는 보
장되지 않습니다. 그런데 do_timer 의 특수한 문맥에서 volatile 과
atomicity 의 관계 (volatile 이 atomicity 를 방해한다?) 를 기술하는 것
이 어떤 의미를 갖는다고 생각하십니까? (volatile 이 없었다면 생성되었을)
in-memory operation 에 atomicity 가 보장된다는 생각은 오해입니다. 또한
volatile 이 반드시 in-memory operation 을 생성하지 않는다는 것 역시 오
해입니다. 이미 방준영님과 다른 분이 보여주신 예에서 확인할 수 있듯이
volatile 과 atomicity 는 아무런 관련이 없습니다.

kyong wrote:
그래서 인지
모르지만, 다른 이유의 가장 유력한 후보가 무시 됐기 때문에 상기 시킨 것
입니다.

- 여기서 무시되었다고 생각하시는 다른 이유의 강력한 후보는 구체적으로
무엇인지요?

kyong wrote:
Quote:

volatile 은 프로그램의 특정 부분에서 (이를 sequence point 라고
부릅니다) 실제 대상체에 저장되어 있는 값이 프로그램이 보여주는 추상적
인 semantic 과 일치함을 보장하는 것이며, 두 sequence point 사이에서의
register caching 까지 막지는 않습니다.

틀렸다고 생각됩니다. squence point사이의 최적화는 허용하지만 register
caching은 막으며,

- 제가 말씀드린 "두 sequence point 사이에서의 register caching" 과 님
이 말씀하신 "sequence point 사이의 최적화" 사이의 차이는 무엇인지요?

참고로, 제가 말씀드린 "register caching" 은 CPU 가 연산을 위해
volatile 대상체의 값을 CPU register 로 올릴 수 있음을 의미하기 위해서
사용한 용어입니다 - 즉, in-memory operation 과 대조되는 의미로 사용한
것입니다. 두 sequence point 사이라 해도 volatile 의 semantic 에 영향을
주는 register caching 까지 허락하는 것은 아닙니다 - 님의 두 sequence
point 사이에서의 최적화는 허용된다" 는 말씀은 사실이 아닙니다. 일부 잘
못된 C 언어 서적 (예를 들면, H&S 시리즈) 에서 이를 잘못 설명하고 있지
만, 이미 C 표준화 위원회 멤버와의 논의에서 이것이 표준이 의도한
volatile 의 의미가 아님을 확인했습니다.

kyong wrote:
즉 volatile object의 reference는 최적화 되지 말아야 한다는
것이 표준입니다.

- 제가 언제 volatile 대상체의 참조가 최적화 되어야 한다고 말씀드린 적
이 있는지요?

kyong wrote:
단, 같은 volatile object가 two squence point 사이에 여러번
쓰일 때는 compiler가 optimize 할 수 있습니다.

extern volatile int a;

i = a + a;

- 여기서 두 sequence point 가 어디인지요?

- 또, 그 사이에서 최적화가 허락된다는 것은 a 라는 대상체 (실제 메모리)
에 최소한 몇 번의 참조가 있어야 함을 의미하는 것인지요?

kyong wrote:

Quote:

즉, 그 글쓴이가 말한 것은 다음
과 같은 문장을 (i 에 이루어지는 side effect 를 implementation 이 예측
할 수 없다면),

volatile int i;

for (i = 0; i < 100; i++) func(i);

아래와 같이 번역할 수 없음의 의미하는 것 뿐이며,

register int r;    // "register" obeyed
for (r = 0; r < 100; r++) func(r);
i = r;

in-memory operation 이 이루어져야 한다고 주장한 것은 아닙니다.
이제 오해가 해결되었는지요?


글쓴이가 한 말과 상관없는 예제 입니다.

- 주장만 있고 근거가 없습니다. 근거 부탁드립니다.

Quote:
register는 더구나 compiler에게 advice하는 것이지 register를 쓴다는
보장도 없습니다. 물론 요즘 compiler는 알아서 쓰지만요.

위에서 보인 두번째 코드는 어셈블리어 코드를 쓰지 않기 위해 사용한 일종
의 pseudo code 입니다. 주석을 보시면 "register" 가 지켜진다는 가정을
하고 있음을 확인할 수 있습니다.

kyong wrote:
그러나 squence point를 볼 때 register caching이 가능한 경우라고 생각됩니다.

- 이번에는 정확히 sequence point 가 어디에 있는지요?

- register caching 이 가능하다는 뜻은 첫번째 프로그램을 두번째와 같이
행동하도록 만들 수 있다는 뜻인지요? 아니라면 구체적으로 무슨 의미인지
요?

kyong wrote:
전웅 wrote:
흠... volatile 에 대해서 뭔가를 많이 오해하고 계신 것 같습니다. 만약,
해당 문장이 "다른 operation 의 간섭에 의해 값이 수정될 수 있음" 을 의
미하는 것이었다면 왜 간섭할 수 있는 operation 을 non-volatile 로 한정
했을까요? 해당 글쓴이는 다른 thread 나 processor 의 간섭이 없음을 (따
라서 atomicity 에 대한 걱정이 불필요함을) 알고 있는 상태에서 "같은" 프
로그램의 다른 (non-volatile) operation 에 의해 volatile 연산의 일부가
지연될 수 있음을 말하고 있는 것입니다. 그리고 이미 다른 분이 예를 보여
주셨듯이 이는 실제 일어나는 일이고, 표준이 허락하고 있는 것이며, 대다
수의 실제적인 impelemtation 에서 그와 같은 지연이 일어나지 않았을 때와
차이를 만들지 않습니다 - 즉, 아직까지 그렇게까지 똑똑하거나 무모한 컴
파일러는 개발되지 않았습니다.

위에서 얘기 했듯이 연산의 지연에 관한 문제가 아니라 값(value)의 atomicity
에 관한 문제입니다.

- 그렇다면, "do_timer 의 문맥에서" in-memory operation 인 incl 이 생성
되면 값의 atomicity 가 보장되고, volatile 에 의해 load/incl/store 가
생성되면 값의 atomicity 가 보장되지 않는다는 뜻인지요?

- 어차피 atomicity 에 대한 이야기라면 왜 간섭할 수 있는 연산을
"non-volatile" 로 한정하고 있을까요?

kyong wrote:
왜냐면 register에서 일어나는 것이 아니라 memory에서 일어나기 때문입니다.

- 무엇이 register 가 아닌 memory 에서 일어난다고 말씀하고 계신
것인지요?

kyong wrote:
non-volatile으로 한정한 것이 아니라 memory에 있기 때문에 memory를 접근
하는 모든 operation에 의해서 값이 수정될 수 있다는 것을 뜻한다고 생각합
니다.

원 글쓴이가 non-volatile 이라는 표현을 분명 사용하고 있음에도 님이 예
상하는 의미와 다르다고 판단되니 무시해 버리시는군요. :(

- memory 에 접근하는 모든 operation 에 의해서 값이 수정될 수 있다는 것
이 do_timer 가 처한 특수한 상황에서도 가능한지요?

kyong wrote:
결과적으로 차이를 만들지 않는다는 것은 표준과 동떨어진 말이며
차이는 날 수도 있고 안 날 수도 있습니다.

- 무엇에 의한 차이를 말씀하시는 것인지요? 참고로 표준에 의해 차이가 발
생하지 않는다는 것은 do_timer 가 사실상 single-thread 문맥에 있다는 특
수한 상황이 보장해 주는 것입니다. 그럼에도 차이를 만들 수 있다는 뜻인
지요?

kyong wrote:
최초 원문 번역은 문맥상 차이가 있기 때문에 번역 기술상 틀렸다고 생각됩니다.
operation의 간섭의 문제가 아니라 지연의 문제라고 주장하신 것은 의미상
동일 할 수 있지만 대다수 implementation에서 차이가 없다고 말하신 것으로
봐서 기술적으로 잘 못 이해하신 것이라고 생각됩니다.

- do_timer 문맥에서 차이가 있을 수 있는 가상의 implementation 을 예시
해 주시기 바랍니다.

kyong wrote:
제가 주장한 이유를 능가하는 합당한 이유가 나타나지 않으면서 계속 thread가
길어지는 것에 대해서는 저도 궁굼합니다.

- 님이 주장하시는 것 외의 다른 이유 중에는 합당한 이유가 없다는 뜻인지
요? 그럼 님이 주장하시는 것 외의 다른 이유를 주장한 사람들 (lkml 의 다
수의 사람들과 이곳에 계신 분들) 은 왜 그런 주장을 했다고 생각하시는지
요?

kyong wrote:
이미 나온 것이지만 제 의견을 하나의 가설이라고 하죠.
다른 유력한 가설이 나오지 못했고 기존 가설을 뒤집을 만한 조그만 증거도
나오지 못했다면 한 가지 추측 뿐이라고 말할 수 있겠습니까?

이미 상반되는 여러가지 증거를 보였습니다. do_timer 자체가 "불완전한 최
적화" 라는 사실에는 동의하신 것으로 알고 있습니다. 특정 시점에서 "불완
전한 최적화" 인 적이 있었고, 또 몇몇 kernel 개발자의 입에서 여러 명령
어로 풀어지는 것과 "아무런" 차이가 없다는 답변이 있을 때, 과연 원 개발
자가 단지 성능 향상을 위해서 그와 같은 선택을 했다는 사실을 단 하나의
의심도 없이 받아드릴 수 있을까요? 님의 주장이 전혀 가능성이 없다고 생
각하지는 않습니다. 다만 아직도 불분명한 부분이 남아 있고 개인적으로는
100% 확신할 수 없음을 말씀드리고 있는 것입니다. 저는 님의 "믿음" 에 변
화를 주기 위해서 이 곳에 있는 것이 아니라, 그 개인적인 "믿음" 을 다른
분들에게 "진실" 인 것처럼 강요해서는 안 된다고 말씀드리기 위해 이 논의
를 이끌고 있는 것입니다.

kyong wrote:
제 단언을 반박할 만한 증거도 없이 어떤 오해가 나왔다는 것이죠?
그럼 님이 하실 일은 분명합니다. 또 다른 추측으로 기존 사실을 흐리지
말고 정확한 근거로 답하시는 것입니다.

이 문제 ("진정한 의도는 무엇인가?") 에 대해서 더 이상 같은 근거와 같은
주장을 되풀이하는 것이 진정 무의미하다고 생각하지만, 제가 님의 주장에
대해 단 하나의 반대되는 근거도 제시하지 않았다는 사실은 거짓입니다 -
지금까지 진행된 논의를 살펴보시기 바랍니다. 님께서는

- atomicity 를 보장해 보겠다는 불필요한 고민

- 최초 어셈블리어로 incl 이 사용된 것에서 시작된 역사적 이유

등등의 이유에 대한 반대 증거를 제시해 보시기 바랍니다. 이를 제시하기
위해서는 결국 "원래 개발자의 의도는 무엇이었는가?" 하는 문제로 돌아가
게 됩니다. 만약, 위와 같은 주장에 대한 반론이 확실한 상태에서 님의 주
장에 대한 반론이 불가능하다면 상당히 신뢰할만한 주장이 되지만, 그렇지
않은 상황에서는 크기의 차이는 있어도 모두 의심의 대상이 된다고 생각합
니다. 저는 님의 주장이 전혀 가능성이 없음을 주장하기 위해 이 논의를 이
끌고 있는 것이 아닙니다 - 이 점에 대해서는 오해 없기를 바랍니다.

kyong wrote:
Quote:

없었으며, 앞으로도 없습니다

전 현재 존재하는 코드를 두고 확신했지만 님은 미래를 두고 확신 하셨더군요.

- 제가 드린 확신에 구체적인 문제가 있다면 지적 바랍니다. 저는 C 언어의
표준화 과정에 참여하고 있으며, 제가 그렇게 미래에 대해서 확신할 수 있
는 근거를 이미 충분히 밝혔습니다. 제 확신에 어떠한 거짓의 가능성이 있
을 수 있는지 근거를 부탁드립니다.

kyong wrote:
Quote:

kernel 에서 (jiffies 를 제외하고) volatile 한정을 제거하기 위한 (그래
서 in-memory op 를 얻기 위한) 목적으만으로 *& hack 을 사용한 다른 부분
이 있습니까? 참고로 sys_iopl() 은 적용되지 않습니다 - volatile 한정을
제거하는 목적이 아니라 과거 gcc 의 bug 를 피하기 위한 목적으로 사용된
곳입니다.

애초에 님이 가졌던 생각을 짐작할 수 있으며 역시 근거도 없이 단정하고 있습
니다.

- ??? 제가 위의 글에서 무엇을 단정하고 있다고 생각하십니까? sys_iopl()
에 사용된 *& hack 이 과거 gcc 의 bug 때문에 사용되었다는 것은 원 개발
자의 증언을 근거로 삼고 있는 것이며, kernel 의 다른 부분에서 jiffies
와 동일한 목적 (volatile 한정을 제거해 in-memory op 를 얻는 것) 으로
*& hack 을 사용한 부분이 또 있는지 묻고 있는 것입니다. 제가 무엇을 단
정하고 있다는 것인지 이해하기 어렵습니다.

kyong wrote:
그리고 전 추측하지 않고 당당히 근거에 기초해
말했습니다. 누군가 원 개발자의 의도를 말한다고 해도 역시 code와 tool로 확인
한 후 검증하는 것이 순서일 것입니다. 지금 code가 있는 상황에서 필수가 아님
을 말씀드립니다.

code 와 tool 로 확인한 내용이 다른 의도의 가능성을 내포하고 있을 때에
는 이야기가 달라질 수 있습니다.

- 그리고 무엇인 "필수" 가 아니라고 말씀하고 계신 것인지요?

kyong wrote:
정확히 volatile을 피해 compiler에게 최적화를 유도하는 것입니다.
결과적으로 x86에서 in-memory incl로 나타난 것입니다.
명확한 사실이라고 얘기하시는 것은 의견의 변화라고 생각됩니다.

저는 "in-memory incl 를 사용하는 것이 *& hack 의 목적이다" 라는 사실에
대해서는 님이 이 논의에 참여하기 이전부터 이야기하고 있었으며:

Quote:
분명 해당 부분의 개발자는 jiffies++ 에 대해서 in-memory incl
를 쓰고 싶었나 봅니다.

그 이유가 "최적화" 인지는 의심스럽다고 말씀드리고 있는 것입니다. 논의
가 진행되면서 제 의견의 변화가 생긴 부분은 (이미 말씀드렸듯이) 최적화
일 가능성에 대한 생각이 이전보다 커졌다는 것 뿐입니다.

kyong wrote:
Quote:

그러면, in-memory incl 를 쓰는 배경은 무엇인가요?
lkml 에서 어떤 사람은 "없다" 고 답하고, 어떤 사람은 "역사적 이유" 라고
답하고, 또 어떤 사람은 "불필요한 atomicity 에 대한 걱정" 이라고 답하고
있으며, 이들 모두에 반대하는 기고는 없었습니다.

in-memory incl에 대해서 세번째로 든 이유말고 첫번째, 두번째 이유라는
기고가 있었던 가요? 알고있었는지 모르지만 in-memory incl이 밝혀지기
전에 alan cox가 없다고 한 것은 기억나지만요.

님이 논의에 참여하는 자세를 볼 때 더 이상의 논의가 무의미해 보입니다.
님의 생각과 다른 의견과 그 근거는 간단히 무시해버리거나 기억에서 지워
버리는 것이 님이 논의에 참여하는 자세인지요? 지금까지 근거를 제시한 제
행동이 무의미한 짓으로 평가절하되는 순간이군요.

kyong wrote:
thread가 길어지다 보니
가물한데, 절절한 이유를 들어 performance라고 생각한 분이 더 많았다고
기억됩니다.

직접 세어 보시기 바랍니다. 그리고 님은 lkml 에서 "성능 향상" 이 그 이
유라고 생각하는 사람을 단 한 사람도 찾지 못했고, 오히려 제가 한 사람
찾아냈습니다. 다수는 "atomicity 에 대한 오해에서 비롯된 것일 가능성이
있다" 라는 의견이었습니다. 님이 인용해 놓으신 논의는 모두 읽어보셨는지
요?

kyong wrote:
전웅 wrote:
kyong wrote:
누가 발전을 가져오는지 판단할 입장은 아니라고 생각됩니다.
최적화가 주요 이유임을 부정하신 분이 정확한 논거를 가지고 이 thread에
다시 나타나셔야 할 것으로 생각됩니다.

안타깝게도 방준영님은 더 이상 KLDP BBS 에서 활동하시지 않습니다.


그러면 지금까지 이 thread에 계속 답글을 다신 이유가 무엇입니까?

혹시 매번 다른 분이 "kyong" 라는 ID 로 논의에 참여하고 계신 것인지 의
심스럽습니다. 바로 이전 글에서 그 이유를 밝혔습니다. 님이 님의 개인적
인 의견임을 분명히 하지 않고, 의심이 가능한 사실을 단정적으로 말씀하신
것이 최초의 이유였습니다.

kyong wrote:
전웅 wrote:
님이 이 논의에 참여하기 이전에 논의에 참여하고 있던 사람들은 해당 부분
을 도입한 원 개발자의 의도에 대해서 고민하고 있었습니다. 그리고, 방준
영님은 그 의도는 최적화가 아닐 것이라는 다소 단정적인 태도를 취하셨고
(그렇더라도 추측에서는 벗어나지 않습니다), 저 역시 다른 부분을 보았을
때 그럴 가능성은 적다는 의견을 보인 것입니다. 이 논의에 참여하던 대부
분의 사람들도 in-memory incl 이 더 나은 성능을 보일 것이라는 사실에 대
해서는 (님이 테스트 결과를 제시하기 이전부터) 인지하고 있었으며, 다만
그것이 진정 원 개발자의 의도인지를 의심하고 있던 상황이었습니다. 따라
서, 님이 제시한 테스트 결과는 "해당 코드는 더 나은 성능을 보인다" 라는
(이미 동의되어 있는) 주장을 뒷받침하기에는 적절하지만 "원 개발자의 의
도는 성능 향상이었다" 라는 주장을 뒷받침하기에는 부족합니다.

님의 생각은 일관적이였는지 모르지만 글을 봤을 때 그렇지 않았고,

- 구체적으로 어떤 부분에 문제가 있는지요? 전부는 아닐지라도 단 하나라
도 구체적으로 근거와 함께 지적 바랍니다.

kyong wrote:
원 개발자의 의도가 어떠했든 간에 지금 maintainer가 그 코드를 유지하고
있는 주요한 이유는 performance라는 것을 저는 얘기하고 있는 것입니다.

지금 "유지보수자" 가 그 코드를 유지하고 있는 주요한 이유는 다행스럽게
도 직접 물을 수 있기에 확실히 알 수 있는 부분입니다 - 이 부분 역시 확
인이 필요합니다.

하지만, 제가 시종일관 확신할 수 없다고 이야기한 부분은 "유지보수자" 가
아닌 "원 개발자" 의 의도가 무엇이냐는 것이었습니다 - 저 역시 "topic 에
집중해 주시기를" 부탁드립니다.

kyong wrote:
topic에 집중해 주시기 바랍니다.

님이 지적하시는 내용에 대해서 제가 갖는 느낌은 특별히 기술적으로 잘못
된 부분이 없음에도 "지적하고 싶다" 는 마음 하나로 이미 논의가 끝난 내
용을 끄집어내어 지적하고 계신다는 것입니다. 기술적으로 제가 이야기한
부분에서 잘못된 내용이 있다면 근거와 함께 구체적으로 지적해 주시기 바
랍니다. 이는 저를 위해서도 중요한 일이며, 이 글을 읽는 다른 분들을 위
해서도 중요한 일입니다. 분명 기술적으로 잘못된 내용이 있다면 사과드리
고 정정할 것입니다. 하지만, 충분한 근거도 제시 못하는 상황에서 님이 잘
못 알고 있는 내용과 다르다는 이유만으로 "틀립니다" 등의 표현을 사용하
는 것은 올바른 내용에 대한 왜곡 시도에 불과합니다.

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

전웅의 이미지

kslee80 wrote:
전웅님과 kyong님 두분다 이쯤에서 그만 두시는게 어떨지요.
두분의 토론이 계속해서 쳇바퀴 돌듯 도는거 같습니다.

kyong 님께서 "내 개인적인 생각에는 in-memory operation 을 고집한 이유
는 성능을 위해서인 것 같다" 라는 내용만을 주장하신다면 제가 반론의 제
기할 정당성이 전혀 없습니다 - 실제 그와 같은 "개인적인" 생각에 반론을
제기한 적도 없습니다.

하지만, kyong 님은 시종일관 이미 올바르게 설명과 논의가 끝난 내용을 다
시 끄집어내어 뚜렷한 근거가 부족한 상태에서 불분명한 어투로 트집을 잡
고 계시며, 제가 근거로 인용했던 여러가지 내용을 이해가 부족한 상태에서
무시하거나 왜곡하고 있습니다. 더구나 제가 그에 대한 반론을 제기하면 또
다른 멀쩡한 내용을 인용하며 트집을 잡는 행동을 계속하고 계십니다.

kyong 님과의 논의에서 불쾌한 부분이 있다면, 논의가 길어지거나 개인적인
주장을 바꾸지 않는다는 사실이 아니라 (이미 말씀드렸듯이, 개인적인 주장
이 개인적인 주장임을 분명히 하며 이루어진다면, 다른 사실이 분명치 않은
상황에서 반대할 이유가 없습니다), 기술적으로 잘못되지 않은 내용을 구체
적인 근거 없이 틀린 것으로 가정하고 애매모호한 표현으로 지적하고 계신
다신 사실입니다. "in-memory op 에 대한 원 개발자의 의도는 무엇인가" 에
대한 문제는 차치하고라도 지금까지 kyong 님께서 지적하신 (근거가 충분한)
기술적인 내용에 대해서는 확실히 하고 넘어갈 필요가 있다고 생각합니다.

이 논의는 감정 싸움이나 주관적 가치 판단에 대한 논쟁이 아닌 분명한 사
실에 대한 기술적인 논의입니다. 단지, 논의가 길어진다는 이유만으로
thread 가 닫히거나 하는 불상사가 없기를 바랍니다.

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

kyong의 이미지

Quote:

전웅 wrote:
kyong wrote:
문맥상 의미를 얘기 하기 전에,
volatile 이 register cache를 막아준다는 말은 맞습니다. register에 copy한다면
그 사이 원래 메모리에서 수정이 이루어 졌을 경우에 문제가 있는 것입니다.

님의 글 전체를 읽었을 때, 대체 님이 무엇을 이해하고 계신지, 어느 부분
을 오해하고 계신지 알기 어렵습니다. 지금까지는 논의를 가능한 빨리 마무
리하고자 직접 서술형의 답을 드렸지만 지금부터는 간단히 질문으로 답을
이어가겠습니다. 이 질문은 님의 귀찮게 혹은 불쾌하게 하려는 의도가 아니
라 구체적으로 님과 저 사이에 어떤 오해가 있는지 확인하기 위한 것입니다.


이런식의 쓰레드는 낯설군요.
제가 기존에 했던 말은 최소한 가능한 기술적으로 기술하려고 했다는 사실을
주지했으면 합니다. 틀렸으면 분명히 틀린 부분을 지적해 주시면 고맙겠습니다.
그리고 저도 생각이 조금 바뀐 부분이 있으므로 이번 쓰레드에서 기술하는 것을
기준으로 말씀해 주시기 바랍니다.

Quote:

- volatile 이 register cache 를 막아준다는 말이 맞다는 뜻은, volatile
대상체 i 에 대한 ++ 연산에 대해서 다음과 같은 코드를 생성하는 것이 잘
못되었다는 뜻으로 하시는 말씀인지요?

load i into r1
add 1 to r1
store r1 into i


표준은 register operation에 대한 것까지 정의하고 있지 않다는 것이 제
해석입니다. 결국 그럴 수도 있고 아닐 수도 있다입니다. 그러나 main memory
외에는 값에 대해서 어떤 가정도 하지 않는다는 것은 분명합니다.
++ 경우 main memory의 constant주소에 2번 access 하는 경우 입니다.
각각의 access에서 implementaion-defined 된 부분이지만 일치된 값을 보장한
다는 것이 제 해석입니다. x86 manual에 따르면 최소한 x86에서 맞다고 생각됩
니다. 그러니까 gcc가 보장할 필요가 없다는 해석이 가능합니다.
그러나 결합된 intruction에 대해서는 보장하고 있지 않습니다.

Quote:

아니면 제가 아래에서 보였던 예와 같이 프로그램의 특정 시점에서 프로그
램이 명시하는 abstract semantic 과 actual implementation 이 일치함을
의미하시는 것인지요?

용어 자체는 표준에서 말하고 있는 것입니다. 그러나 예제는 다시 검토할 것
입니다.

Quote:

kyong wrote:
in memory incl 같은 경우는 최소한 x86에서 지원하는 연산인 것입니다. 그리고
volatile은 compiler에게 physical memory외에 어떤 가정도 하지 말도록 하는
것입니다.

- "님이 알고 계시는" volatile 의 공통된 의미에 대해서 설명 부탁드립니
다. 특히, "physical memory 외에 어떠한 가정도 하지 말라" 는 말의 뜻은
어떠한 구체적인 행위가 금지된다는 뜻으로 하신 말씀인지요?


volatile의 의미를 정확히 이해하고 있다면 해서는 안 될 질문이라고 생각됩니다.
object가 volatile일 때는 반드시 main memory의 주소에서 값을 읽어오란 뜻
입니다. 즉, pointer를 사용하게 되면 register에 copy해서 최적화 대상이 될 수
있고 결국 register에서만 값을 읽어 오고 main memory에서 변경됐을 수도 있는
값을 못 가져온다는 말입니다. 쓰레드로 얘기 하자면 첫번째 쓰레드에서 변경된
값이 cache되고 두번째 쓰레드부터는 원래 값을 못 가져 오게 될 수 있음을
얘기합니다.

Quote:

kyong wrote:
제가 저번에 그와 같이 질문을 드린 것은 원문 2번째 단락의 정확한 의미는
메모리에서 값의 수정이 이루어 질 수 있기 때문에 volatile이 atomicity를
오히려 방해한다는 것인데 이 의미를 제대로 번역하지 못했고

- 그렇다면 반대로 volatile 을 사용하지 않아 in-memory operation 을 얻
어냈을 때는 atomicity 가 보장되는지요?


x86에서 single instruction으로서 인터럽트가 걸린 상황에서 incl을 얘기 하시는 것이라면 여러 프로세서에서도 보장된다는 것이 제 해석입니다.
이것은 저 번에 인용한 원문에 인용된 글에서 single processor에서 보장된다는
것 보다 나아간 해석입니다.(intel manual)

Quote:

load/inc/store 가 생성되든 in-memory incl 이 생성되든 어차피 근본적인
atomicity 는 보장되지 않습니다. 해당 글쓴이는 이러한 사실을 알고 있었
고, do_timer 가 기본적으로 atomicity 가 보장되는 특수한 상황에 있다는
것도 알고 있었습니다.

원문 2번째 단락상 의미 때문에 안되는데 *& hack으로 single instruction을
유도해서인터럽트가 걸린 상황에서 되는 상황이 되었지만 다른 사람이
얘기한 do_timer의 design으로 볼 때 고려할 필요도 없는 것이므로 jiffies++
도 좋다고 예기한 것입니다.

Quote:

do_timer 의 특수한 상황에서, 단일 명령어와 여러
개의 명령어로 생성된 것에는, "같은" 프로그램의 다른 "non-volatile" 연
산이 jiffies 를 증가시키는 행동에 끼어들 수 있느냐 없느냐의 차이를 낳
는다는 것이 해당 문장의 의미입니다

do_timer의 상황에서는 인터럽트가 걸렸기 때문에 다른 어느 것도 값에
영향을 줄 수 없습니다. do_timer 상황은 빼고 얘기하셔야 합니다.
x86에서 물리적 메모리에 쓰는 것이 느리기 때문에 store buffer를 둬서 성능
을 관리하는데 이 때 이루어지는 delay를 갖고 얘기할 수있겠다는 생각이
들었습니다. 그렇지만 delay됐기 때문에 program oder가 안 지켜지는 것은
아닙니다. 그러나 read, write 할 때 access 시점이 다르고(incl이더라도)
interrupt나 lock이 걸린 상황이 아니므로 값의 차이를 낳는다입니다.
즉, access 시점이 다른 두 intruction을 결합해서는 예측할 수 없는 것이
volatile인 것입니다.

Quote:

- 하지만, 그러한 끼어듬이 jiffies
의 값의 품질에 영향을 주지는 않습니다. do_timer 가 아닌 일반적인 문맥
에서 volatile 이 없어서 incl 이 선택된다고 해도 어차피 atomicity 는 보
장되지 않습니다. 그런데 do_timer 의 특수한 문맥에서 volatile 과
atomicity 의 관계 (volatile 이 atomicity 를 방해한다?) 를 기술하는 것
이 어떤 의미를 갖는다고 생각하십니까? (volatile 이 없었다면 생성되었을)
in-memory operation 에 atomicity 가 보장된다는 생각은 오해입니다. 또한
volatile 이 반드시 in-memory operation 을 생성하지 않는다는 것 역시 오
해입니다. 이미 방준영님과 다른 분이 보여주신 예에서 확인할 수 있듯이
volatile 과 atomicity 는 아무런 관련이 없습니다.

do_timer상황에서는 맞습니다. 그러나 volatile과 atomicity와 아무 관련이
없다는 말은 틀렸습니다. in-memory operation에 대해 한 말은 제가 한 것과
는 다릅니다. volatile의 의미를 제거한 최적화의결과로서 의미를 가진다고
얘기로 한 줄로 압니다. volatile이 in-memory operation을 생성하는 것은 제가
기대하는 행동입니다.
volatile은 main memory에서의 여러 방법으로 값이 변경될 수 있음을 규정하기
때문에 atomicity를 위해서 별도의 design을 강요하는 것입니다.

Quote:

kyong wrote:
그래서 인지
모르지만, 다른 이유의 가장 유력한 후보가 무시 됐기 때문에 상기 시킨 것
입니다.

- 여기서 무시되었다고 생각하시는 다른 이유의 강력한 후보는 구체적으로
무엇인지요?


volatile 의미를 제거해 single instruction이 생성되도록 최적화를 유도해
atomicity를 보장받으려 시도했다는 것입니다. 그러나 전 이것이 후보라고
얘기 했지만 여러 글들을 보면서 더욱 아니란 생각을 하게 됐습니다.
gcc mailling list를 봤을 때 특히, *& hack은 거기 개발자도 권하는 기법이고
(volatile <-> non-volatile 변환) linus같은 경우엔 특히 volatile이 제대로 된
코드를 못 만든다고 불평하는 것을 봤습니다. 그 당시 개발자가 timer irq
design을 이해 못했다고 생각되지 않습니다.

Quote:

kyong wrote:
Quote:

volatile 은 프로그램의 특정 부분에서 (이를 sequence point 라고
부릅니다) 실제 대상체에 저장되어 있는 값이 프로그램이 보여주는 추상적
인 semantic 과 일치함을 보장하는 것이며, 두 sequence point 사이에서의
register caching 까지 막지는 않습니다.

틀렸다고 생각됩니다. squence point사이의 최적화는 허용하지만 register
caching은 막으며,

- 제가 말씀드린 "두 sequence point 사이에서의 register caching" 과 님
이 말씀하신 "sequence point 사이의 최적화" 사이의 차이는 무엇인지요?

참고로, 제가 말씀드린 "register caching" 은 CPU 가 연산을 위해
volatile 대상체의 값을 CPU register 로 올릴 수 있음을 의미하기 위해서
사용한 용어입니다 - 즉, in-memory operation 과 대조되는 의미로 사용한
것입니다. 두 sequence point 사이라 해도 volatile 의 semantic 에 영향을
주는 register caching 까지 허락하는 것은 아닙니다 - 님의 두 sequence
point 사이에서의 최적화는 허용된다" 는 말씀은 사실이 아닙니다. 일부 잘
못된 C 언어 서적 (예를 들면, H&S 시리즈) 에서 이를 잘못 설명하고 있지
만, 이미 C 표준화 위원회 멤버와의 논의에서 이것이 표준이 의도한
volatile 의 의미가 아님을 확인했습니다.


제가 저번에 조건을 둔 즉, 두 sequence point 사이에 같은 값이 여러번 사용된
경우를 애기한 것입니다. 즉 다음과 같은 경우입니다.
if (f(j*j)) => register int temp = j; if (f(temp*temp))
이 예제는 C reference manual 에서 인용했습니다.

Quote:

kyong wrote:
즉 volatile object의 reference는 최적화 되지 말아야 한다는
것이 표준입니다.

- 제가 언제 volatile 대상체의 참조가 최적화 되어야 한다고 말씀드린 적
이 있는지요?


알겠습니다.

Quote:

kyong wrote:
단, 같은 volatile object가 two squence point 사이에 여러번
쓰일 때는 compiler가 optimize 할 수 있습니다.

extern volatile int a;

i = a + a;

- 여기서 두 sequence point 가 어디인지요?

- 또, 그 사이에서 최적화가 허락된다는 것은 a 라는 대상체 (실제 메모리)
에 최소한 몇 번의 참조가 있어야 함을 의미하는 것인지요?


위 예제는 적절하지 않다고 생각됩니다.
위의 경우 side effect가 없는 경우입니다. 그러므로 기본적인 ; 이 적용됩니다.

다음 질문에서 이 부분은 제가 표준화관련 문서를 정확히 본 것이 아니고 irc에서
들은 것이여서 정확한지는 모르겠으나 여러번이라고 했으니 2번 이상이라고 짐
작할 뿐입니다.

Quote:

kyong wrote:

Quote:

즉, 그 글쓴이가 말한 것은 다음
과 같은 문장을 (i 에 이루어지는 side effect 를 implementation 이 예측
할 수 없다면),

volatile int i;

for (i = 0; i < 100; i++) func(i);

아래와 같이 번역할 수 없음의 의미하는 것 뿐이며,

register int r;    // "register" obeyed
for (r = 0; r < 100; r++) func(r);
i = r;

in-memory operation 이 이루어져야 한다고 주장한 것은 아닙니다.
이제 오해가 해결되었는지요?


글쓴이가 한 말과 상관없는 예제 입니다.

- 주장만 있고 근거가 없습니다. 근거 부탁드립니다.


님이 애초에 semantic을 보장하는 register caching까지 막지 않는다는 것을 말
하면서 든 예제인데 여기 예제는 register로 copy하지 말고 main memory를 읽어야한다는 volatile의 의미를 얘기한 예제일 뿐입니다.
그러니까 적절한 예제는 semantic을 보장하면서 register cacing하는
경우입니다.

Quote:

Quote:
register는 더구나 compiler에게 advice하는 것이지 register를 쓴다는
보장도 없습니다. 물론 요즘 compiler는 알아서 쓰지만요.

위에서 보인 두번째 코드는 어셈블리어 코드를 쓰지 않기 위해 사용한 일종
의 pseudo code 입니다. 주석을 보시면 "register" 가 지켜진다는 가정을
하고 있음을 확인할 수 있습니다.


이것은 제가 주석을 못 본 불찰입니다. 무시하시기 바랍니다.

Quote:

kyong wrote:
그러나 squence point를 볼 때 register caching이 가능한 경우라고 생각됩니다.

- 이번에는 정확히 sequence point 가 어디에 있는지요?


위에서 얘기했고요, 그러나 값이 바뀌므로 해당되지 않는다로 정정합니다.
for문에서 sequence point는 4개 입니다. 틀렸다면 정정해 주시기 바랍니다.

Quote:

kyong wrote:
전웅 wrote:
흠... volatile 에 대해서 뭔가를 많이 오해하고 계신 것 같습니다. 만약,
해당 문장이 "다른 operation 의 간섭에 의해 값이 수정될 수 있음" 을 의
미하는 것이었다면 왜 간섭할 수 있는 operation 을 non-volatile 로 한정
했을까요? 해당 글쓴이는 다른 thread 나 processor 의 간섭이 없음을 (따
라서 atomicity 에 대한 걱정이 불필요함을) 알고 있는 상태에서 "같은" 프
로그램의 다른 (non-volatile) operation 에 의해 volatile 연산의 일부가
지연될 수 있음을 말하고 있는 것입니다. 그리고 이미 다른 분이 예를 보여
주셨듯이 이는 실제 일어나는 일이고, 표준이 허락하고 있는 것이며, 대다
수의 실제적인 impelemtation 에서 그와 같은 지연이 일어나지 않았을 때와
차이를 만들지 않습니다 - 즉, 아직까지 그렇게까지 똑똑하거나 무모한 컴
파일러는 개발되지 않았습니다.

위에서 얘기 했듯이 연산의 지연에 관한 문제가 아니라 값(value)의 atomicity
에 관한 문제입니다.

- 그렇다면, "do_timer 의 문맥에서" in-memory operation 인 incl 이 생성
되면 값의 atomicity 가 보장되고, volatile 에 의해 load/incl/store 가
생성되면 값의 atomicity 가 보장되지 않는다는 뜻인지요?

- 어차피 atomicity 에 대한 이야기라면 왜 간섭할 수 있는 연산을
"non-volatile" 로 한정하고 있을까요?


제가 번역 기술상 맞다고 생각하는 번역은 다음과 같습니다.
Quote:

그 값은 캐쉬되지 않을 것이다.(컴파일러 버그인 경우를 뺀다면), 그러나 값이
읽어져서 증가된 다음 저장 될 수 있다. 그리고 저장은 volatile이 아닌 연산이
나 함수호출 이후로 연기될 수 있다.


즉, 지금 volatile 연산에 의해 변경된 값이 메모리에 반영되기 전에 volatile이
아닌 연산(즉 volatile 연산은 최적화 되지 않기 때문에 또 실행 된다고 해도 program order가 보장되므로)이나 함수로 인해 값이 또 읽혀 질 수 있고
저장된 후에는 다른 값이 되어서 atomicity가 홰손되는 것입니다.
결국 atomicity가 홰손된다는 것은 맞지만 다른 연산에 의해 지연되서 생긴 결과
라는 해석과는 다분히 차이가 있는 것입니다.

Quote:

kyong wrote:
왜냐면 register에서 일어나는 것이 아니라 memory에서 일어나기 때문입니다.

- 무엇이 register 가 아닌 memory 에서 일어난다고 말씀하고 계신
것인지요?

kyong wrote:
non-volatile으로 한정한 것이 아니라 memory에 있기 때문에 memory를 접근
하는 모든 operation에 의해서 값이 수정될 수 있다는 것을 뜻한다고 생각합
니다.

원 글쓴이가 non-volatile 이라는 표현을 분명 사용하고 있음에도 님이 예
상하는 의미와 다르다고 판단되니 무시해 버리시는군요. :(


의미상 좀 차이가 있음을 인정합니다. 위에서 번역한 것을 기준으로 말씀해 주시
기 바랍니다.

Quote:

- memory 에 접근하는 모든 operation 에 의해서 값이 수정될 수 있다는 것
이 do_timer 가 처한 특수한 상황에서도 가능한지요?

인터럽트 상황에는 기존 operation을 끝내고 system bus를 독점하기 때문에
그럴 수 없다는 것이 제 해석입니다.

Quote:

kyong wrote:
결과적으로 차이를 만들지 않는다는 것은 표준과 동떨어진 말이며
차이는 날 수도 있고 안 날 수도 있습니다.

- 무엇에 의한 차이를 말씀하시는 것인지요? 참고로 표준에 의해 차이가 발
생하지 않는다는 것은 do_timer 가 사실상 single-thread 문맥에 있다는 특
수한 상황이 보장해 주는 것입니다. 그럼에도 차이를 만들 수 있다는 뜻인
지요?


표준은 위애서 얘기 했듯이 read, write가 결합된 연산에 대해서 side effect가
없음을 얘기하고 있지 않습니다. do_timer는 atomicity를 고려된 경우이고요.
분명히 위해서 애기하신 것은 do_timer 상황에서 얘기한 경우가 아니라고
생각됩니다.

Quote:

kyong wrote:
최초 원문 번역은 문맥상 차이가 있기 때문에 번역 기술상 틀렸다고 생각됩니다.
operation의 간섭의 문제가 아니라 지연의 문제라고 주장하신 것은 의미상
동일 할 수 있지만 대다수 implementation에서 차이가 없다고 말하신 것으로
봐서 기술적으로 잘 못 이해하신 것이라고 생각됩니다.

- do_timer 문맥에서 차이가 있을 수 있는 가상의 implementation 을 예시
해 주시기 바랍니다.


위에서 애기했듯이 do_timer는 인터럽트가 걸린 상황이므로 전혀 다른 경우입
니다. 제가 do_timer 상황에서 문제가 된다고 한 적이 없다는 것을 분명히
아시기 바랍니다.

Quote:

kyong wrote:
제가 주장한 이유를 능가하는 합당한 이유가 나타나지 않으면서 계속 thread가
길어지는 것에 대해서는 저도 궁굼합니다.

- 님이 주장하시는 것 외의 다른 이유 중에는 합당한 이유가 없다는 뜻인지
요? 그럼 님이 주장하시는 것 외의 다른 이유를 주장한 사람들 (lkml 의 다
수의 사람들과 이곳에 계신 분들) 은 왜 그런 주장을 했다고 생각하시는지
요?


네 그렇다고 생각합니다. 왜냐면 그렇게 code를 씀으로 해서 cpu cycle을 줄이
는 직접적인 효과가 바로 보이는 반면 다른 주장에는 그런 효과 같은 뚜렷한
징후를 볼 수 없다는 것입니다.

Quote:

kyong wrote:
이미 나온 것이지만 제 의견을 하나의 가설이라고 하죠.
다른 유력한 가설이 나오지 못했고 기존 가설을 뒤집을 만한 조그만 증거도
나오지 못했다면 한 가지 추측 뿐이라고 말할 수 있겠습니까?

이미 상반되는 여러가지 증거를 보였습니다. do_timer 자체가 "불완전한 최
적화" 라는 사실에는 동의하신 것으로 알고 있습니다. 특정 시점에서 "불완
전한 최적화" 인 적이 있었고, 또 몇몇 kernel 개발자의 입에서 여러 명령
어로 풀어지는 것과 "아무런" 차이가 없다는 답변이 있을 때, 과연 원 개발
자가 단지 성능 향상을 위해서 그와 같은 선택을 했다는 사실을 단 하나의
의심도 없이 받아드릴 수 있을까요? 님의 주장이 전혀 가능성이 없다고 생
각하지는 않습니다. 다만 아직도 불분명한 부분이 남아 있고 개인적으로는
100% 확신할 수 없음을 말씀드리고 있는 것입니다. 저는 님의 "믿음" 에 변
화를 주기 위해서 이 곳에 있는 것이 아니라, 그 개인적인 "믿음" 을 다른
분들에게 "진실" 인 것처럼 강요해서는 안 된다고 말씀드리기 위해 이 논의
를 이끌고 있는 것입니다.


제가 진실인양 강요한 것이 아니라 뚜렷한 근거를 들어 제 주장을 펼친 것 뿐
입니다. 진실로 믿고 말고는 각자가 판단할 일입니다.

kyong wrote:
제 단언을 반박할 만한 증거도 없이 어떤 오해가 나왔다는 것이죠?
그럼 님이 하실 일은 분명합니다. 또 다른 추측으로 기존 사실을 흐리지
말고 정확한 근거로 답하시는 것입니다.

Quote:

이 문제 ("진정한 의도는 무엇인가?") 에 대해서 더 이상 같은 근거와 같은
주장을 되풀이하는 것이 진정 무의미하다고 생각하지만, 제가 님의 주장에
대해 단 하나의 반대되는 근거도 제시하지 않았다는 사실은 거짓입니다 -
지금까지 진행된 논의를 살펴보시기 바랍니다. 님께서는

- atomicity 를 보장해 보겠다는 불필요한 고민

- 최초 어셈블리어로 incl 이 사용된 것에서 시작된 역사적 이유

등등의 이유에 대한 반대 증거를 제시해 보시기 바랍니다. 이를 제시하기
위해서는 결국 "원래 개발자의 의도는 무엇이었는가?" 하는 문제로 돌아가
게 됩니다. 만약, 위와 같은 주장에 대한 반론이 확실한 상태에서 님의 주
장에 대한 반론이 불가능하다면 상당히 신뢰할만한 주장이 되지만, 그렇지
않은 상황에서는 크기의 차이는 있어도 모두 의심의 대상이 된다고 생각합
니다. 저는 님의 주장이 전혀 가능성이 없음을 주장하기 위해 이 논의를 이
끌고 있는 것이 아닙니다 - 이 점에 대해서는 오해 없기를 바랍니다.


이 thread에서 제가 atomicity에 대한 가능성을 유력한 후보로 가장 많은
말을 하지않았나 생각됩니다. 그래서 원문을 계속 얘기 한 것이고요.
timer_irq design을 몰랐음이 아니라는 가정하에 그것은 아니다입니다.
역사적인 이유에 대해서는 구체적으로 읽어 보지 못했습니다. 단 최근에
volatile을 busy-waiting과 관련해서 역사적인 이유에서 남겨 둔다는 말은
본 적이 있습니다. 최초 incl이 사용됐다면 중간에 jiffies++가 생겼다가
없어지는 일이 일어나지 말았어야 한다고 전 생각합니다.
이것은 atomicity에 대한 것도 해당되는것입니다.
전 가능성을 얘기하는 것이 아니라 가장 신뢰할 만한 가능성을 얘기하는
것입니다.

Quote:

kyong wrote:
Quote:

없었으며, 앞으로도 없습니다

전 현재 존재하는 코드를 두고 확신했지만 님은 미래를 두고 확신 하셨더군요.

- 제가 드린 확신에 구체적인 문제가 있다면 지적 바랍니다. 저는 C 언어의
표준화 과정에 참여하고 있으며, 제가 그렇게 미래에 대해서 확신할 수 있
는 근거를 이미 충분히 밝혔습니다. 제 확신에 어떠한 거짓의 가능성이 있
을 수 있는지 근거를 부탁드립니다.


c 표준화 과정을 정확히 모르지만, draft를 거쳐 rfc가 만들어 지는 과정을 봐도
그렇고(rfc가 표준은 아니지만) 규정은 계속 진화하는 것입니다. C89, C99로
진화했듯이 변화하기 마련인데 그런 단정을 하시니 이해가 되지 않을 뿐입니다.
특히 volatile에 대한 rvalue에 대한 의미는 표준에서 정확하지 않다는 글을 본적
이 있습니다. 거짓에 가능성이 아니라 변화의 가능성을 부정한 사실에 대한
일상적인 거부감이란 사실을 이해하시기 바랍니다.

Quote:

kyong wrote:
Quote:

kernel 에서 (jiffies 를 제외하고) volatile 한정을 제거하기 위한 (그래
서 in-memory op 를 얻기 위한) 목적으만으로 *& hack 을 사용한 다른 부분
이 있습니까? 참고로 sys_iopl() 은 적용되지 않습니다 - volatile 한정을
제거하는 목적이 아니라 과거 gcc 의 bug 를 피하기 위한 목적으로 사용된
곳입니다.

애초에 님이 가졌던 생각을 짐작할 수 있으며 역시 근거도 없이 단정하고 있습
니다.

- ??? 제가 위의 글에서 무엇을 단정하고 있다고 생각하십니까? sys_iopl()
에 사용된 *& hack 이 과거 gcc 의 bug 때문에 사용되었다는 것은 원 개발
자의 증언을 근거로 삼고 있는 것이며, kernel 의 다른 부분에서 jiffies
와 동일한 목적 (volatile 한정을 제거해 in-memory op 를 얻는 것) 으로
*& hack 을 사용한 부분이 또 있는지 묻고 있는 것입니다. 제가 무엇을 단
정하고 있다는 것인지 이해하기 어렵습니다.


gcc bug를 피하기 위한 목적이란 문장이 앞 글에서 나왔다는 사실을 모르고
한 얘기니 무시하시기 바랍니다.
sys_iopl에서 문제는 결국 다른 방법으로 해결됐습니다. 2.7.x 버젼에서 문제가
있어서 그런 *& hack으로 linus가 풀었지만 결국 2.8.x 에서 다시 불거져 나와서
다른 patch가 적용된 것입니다. 결국 bug를 피하기 위한 임시 방편은 오래 가지
못한다는 것이 제 생각입니다. 그리고 그것은 volatile 의미를 제거하는 hack
이 아니기 때문에 다른 문제라고 생각됩니다.

Quote:

kyong wrote:
그리고 전 추측하지 않고 당당히 근거에 기초해
말했습니다. 누군가 원 개발자의 의도를 말한다고 해도 역시 code와 tool로 확인
한 후 검증하는 것이 순서일 것입니다. 지금 code가 있는 상황에서 필수가 아님
을 말씀드립니다.

code 와 tool 로 확인한 내용이 다른 의도의 가능성을 내포하고 있을 때에
는 이야기가 달라질 수 있습니다.

- 그리고 무엇인 "필수" 가 아니라고 말씀하고 계신 것인지요?


kernel 개발자들은 주석을 안 달기로 유명합니다. david miller는 문서가 오히려
방해되므로 필요없다고까지 얘기 한 사람입니다. 물론 전적으로 동의하지 않지만
적어도 지금 networking layer를 볼 때 분명 동작하는 system입니다. code 가
가장 많은 것을 말해 준다는 사실을 부정하시진 않겠지요?

Quote:

kyong wrote:
정확히 volatile을 피해 compiler에게 최적화를 유도하는 것입니다.
결과적으로 x86에서 in-memory incl로 나타난 것입니다.
명확한 사실이라고 얘기하시는 것은 의견의 변화라고 생각됩니다.

저는 "in-memory incl 를 사용하는 것이 *& hack 의 목적이다" 라는 사실에
대해서는 님이 이 논의에 참여하기 이전부터 이야기하고 있었으며:

Quote:
분명 해당 부분의 개발자는 jiffies++ 에 대해서 in-memory incl
를 쓰고 싶었나 봅니다.

그 이유가 "최적화" 인지는 의심스럽다고 말씀드리고 있는 것입니다. 논의
가 진행되면서 제 의견의 변화가 생긴 부분은 (이미 말씀드렸듯이) 최적화
일 가능성에 대한 생각이 이전보다 커졌다는 것 뿐입니다.


알겠습니다. *& hack은 platform independent 하기 때문에 incl 이 목적이
다라고 얘기할 수 없고 volatile 의미를 제거한 최적화 유도가 목적이다가 더 정확할 것 같습니다.

Quote:

kyong wrote:
Quote:

그러면, in-memory incl 를 쓰는 배경은 무엇인가요?
lkml 에서 어떤 사람은 "없다" 고 답하고, 어떤 사람은 "역사적 이유" 라고
답하고, 또 어떤 사람은 "불필요한 atomicity 에 대한 걱정" 이라고 답하고
있으며, 이들 모두에 반대하는 기고는 없었습니다.

in-memory incl에 대해서 세번째로 든 이유말고 첫번째, 두번째 이유라는
기고가 있었던 가요? 알고있었는지 모르지만 in-memory incl이 밝혀지기
전에 alan cox가 없다고 한 것은 기억나지만요.

님이 논의에 참여하는 자세를 볼 때 더 이상의 논의가 무의미해 보입니다.
님의 생각과 다른 의견과 그 근거는 간단히 무시해버리거나 기억에서 지워
버리는 것이 님이 논의에 참여하는 자세인지요? 지금까지 근거를 제시한 제
행동이 무의미한 짓으로 평가절하되는 순간이군요.


무시한 것이 아닙니다. thread가 길어져서 또 다시 읽기가 귀찮아서 그런 것
뿐입니다. 이미 밝혀진 것들이고 code로 설명 되지 않는 불명확한 근거임은
잘 알고 있습니다.

Quote:

kyong wrote:
thread가 길어지다 보니
가물한데, 절절한 이유를 들어 performance라고 생각한 분이 더 많았다고
기억됩니다.

직접 세어 보시기 바랍니다. 그리고 님은 lkml 에서 "성능 향상" 이 그 이
유라고 생각하는 사람을 단 한 사람도 찾지 못했고, 오히려 제가 한 사람
찾아냈습니다. 다수는 "atomicity 에 대한 오해에서 비롯된 것일 가능성이
있다" 라는 의견이었습니다. 님이 인용해 놓으신 논의는 모두 읽어보셨는지
요?


전 lkml을 거의 매일 읽는 사람입니다.
위에서 애기 했듯이 code로 설명되지 않는다면 무의미 합니다.
역사적인 이유도 그렇고요. asm version을 제안한 사람이 누군지도 기억합니다.

Quote:

kyong wrote:
전웅 wrote:
kyong wrote:
누가 발전을 가져오는지 판단할 입장은 아니라고 생각됩니다.
최적화가 주요 이유임을 부정하신 분이 정확한 논거를 가지고 이 thread에
다시 나타나셔야 할 것으로 생각됩니다.

안타깝게도 방준영님은 더 이상 KLDP BBS 에서 활동하시지 않습니다.


그러면 지금까지 이 thread에 계속 답글을 다신 이유가 무엇입니까?

혹시 매번 다른 분이 "kyong" 라는 ID 로 논의에 참여하고 계신 것인지 의
심스럽습니다. 바로 이전 글에서 그 이유를 밝혔습니다. 님이 님의 개인적
인 의견임을 분명히 하지 않고, 의심이 가능한 사실을 단정적으로 말씀하신
것이 최초의 이유였습니다.


이것은 극히 저보다 위험한 발상입니다. 의심을 구체적으로 밝혀가는 것이
순서입니다. 여기 누가 오고 가는지 알려고 오는 것이 아닙니다.
비슷한 부류의 사람들끼리 정보를 교환하면서 함께 커 가자고 오는 것입니다.
제가 누군지는 로그가 말해 주고 주변 정황을 속일 수는 없습니다.

Quote:

kyong wrote:
전웅 wrote:
님이 이 논의에 참여하기 이전에 논의에 참여하고 있던 사람들은 해당 부분
을 도입한 원 개발자의 의도에 대해서 고민하고 있었습니다. 그리고, 방준
영님은 그 의도는 최적화가 아닐 것이라는 다소 단정적인 태도를 취하셨고
(그렇더라도 추측에서는 벗어나지 않습니다), 저 역시 다른 부분을 보았을
때 그럴 가능성은 적다는 의견을 보인 것입니다. 이 논의에 참여하던 대부
분의 사람들도 in-memory incl 이 더 나은 성능을 보일 것이라는 사실에 대
해서는 (님이 테스트 결과를 제시하기 이전부터) 인지하고 있었으며, 다만
그것이 진정 원 개발자의 의도인지를 의심하고 있던 상황이었습니다. 따라
서, 님이 제시한 테스트 결과는 "해당 코드는 더 나은 성능을 보인다" 라는
(이미 동의되어 있는) 주장을 뒷받침하기에는 적절하지만 "원 개발자의 의
도는 성능 향상이었다" 라는 주장을 뒷받침하기에는 부족합니다.

님의 생각은 일관적이였는지 모르지만 글을 봤을 때 그렇지 않았고,

- 구체적으로 어떤 부분에 문제가 있는지요? 전부는 아닐지라도 단 하나라
도 구체적으로 근거와 함께 지적 바랍니다.


위에서 얘기 했습니다.

Quote:

kyong wrote:
원 개발자의 의도가 어떠했든 간에 지금 maintainer가 그 코드를 유지하고
있는 주요한 이유는 performance라는 것을 저는 얘기하고 있는 것입니다.

지금 "유지보수자" 가 그 코드를 유지하고 있는 주요한 이유는 다행스럽게
도 직접 물을 수 있기에 확실히 알 수 있는 부분입니다 - 이 부분 역시 확
인이 필요합니다.

님의 문제는 소프트웨어에 대한 생각이 극히 제한 돼 있다는 것입니다.
저자가 bug없는 perfect한 코드를 만들고 자기한 만든 code를 모두 기억하고 있
다면 맞습니다. 물어보면 되죠. 그러나 현실은 그렇지 않습니다. code는 저자가
없어도 살아서 증명해 보이는 것입니다.

Quote:

하지만, 제가 시종일관 확신할 수 없다고 이야기한 부분은 "유지보수자" 가
아닌 "원 개발자" 의 의도가 무엇이냐는 것이었습니다 - 저 역시 "topic 에
집중해 주시기를" 부탁드립니다.

topic은 (*(unsigned long *)&jiffies)++ 의 의미였습니다. 원 개발자의 마음을
알아보는 것이 아니였음을 말씀드립니다.

Quote:

님이 지적하시는 내용에 대해서 제가 갖는 느낌은 특별히 기술적으로 잘못
된 부분이 없음에도 "지적하고 싶다" 는 마음 하나로 이미 논의가 끝난 내
용을 끄집어내어 지적하고 계신다는 것입니다. 기술적으로 제가 이야기한
부분에서 잘못된 내용이 있다면 근거와 함께 구체적으로 지적해 주시기 바
랍니다. 이는 저를 위해서도 중요한 일이며, 이 글을 읽는 다른 분들을 위
해서도 중요한 일입니다. 분명 기술적으로 잘못된 내용이 있다면 사과드리
고 정정할 것입니다. 하지만, 충분한 근거도 제시 못하는 상황에서 님이 잘
못 알고 있는 내용과 다르다는 이유만으로 "틀립니다" 등의 표현을 사용하
는 것은 올바른 내용에 대한 왜곡 시도에 불과합니다.

틀릴 수 있고 맞을 수 있습니다. 사과할 일은 아닙니다. 지적하고 고쳐주면 될
일입니다. 제가 분명히 느낀점은 code를 해석하는 방법이 현실과는 거리가 먼
저자와의 접촉이 우선이란 것을 막무가네로 가르치려 한다는 것입니다. 제가
code에 의해 제시한 근거는 추측에 지나지 않고 나름대로 지식을 바탕으로
기술한 것을 왜곡에 대한 불순한 시도인양 치부하고 있습니다. 최소한 그런
자세는 사실을 기술하는데 도움이 되지 않는다고 생각됩니다.
kyong의 이미지

원저자의 의도도 그렇다는 것이 제 생각입니다.

ftp://ftp.kernel.org/pub/linux/kernel/v1.3/linux-1.3.76.tar.bz2
ftp://ftp.kernel.org/pub/linux/kernel/v1.3/patch-1.3.76.gz
interrupt latency reasons로 패치된 곳을 보면 직접적으로 jiffies를 언급하지는
않았지만 같은 문제 인식아래 *& 으로 바꾸었다고 짐작할 수 있습니다.
patch는 잘 못 되어서 나오지 않는데 1.3.76 소스에 처음 적용된 것은 분명합니다.
그리고 시간상으로 봤을 때 저자는 linus라고 짐작됩니다.

전웅의 이미지

kyong wrote:
Quote:

- volatile 이 register cache 를 막아준다는 말이 맞다는 뜻은, volatile
대상체 i 에 대한 ++ 연산에 대해서 다음과 같은 코드를 생성하는 것이 잘
못되었다는 뜻으로 하시는 말씀인지요?

load i into r1
add 1 to r1
store r1 into i

표준은 register operation에 대한 것까지 정의하고 있지 않다는 것이 제
해석입니다.

맞습니다.

kyong wrote:
결국 그럴 수도 있고 아닐 수도 있다입니다. 그러나 main memory
외에는 값에 대해서 어떤 가정도 하지 않는다는 것은 분명합니다.

사실, 표준에는 CPU register 나 main memory 에 대해 이야기하는 부분이
아예 없습니다 - 다른 추상화된 모델을 통해 volatile 을 기술할 뿐입니다.
하지만, 그 의도를 보았을 때 적용할 수 있는 해석입니다.

kyong wrote:
++ 경우 main memory의 constant주소에 2번 access 하는 경우 입니다.

read/write 각각 한번씩 총 2번 (이는 해당 연산을 위한 최소한의 필요한
횟수이기도 합니다) 맞습니다. 하지만, 이미 보여드린 예에서처럼 access
횟수가 가시적인 side effect 를 생성하지 않을 경우 (volatile 대상체에
대한 접근의 detail 은 implementation 에게 맡겨져 있습니다), 그 횟수는
더 늘어나도 상관 없습니다 - "access 횟수가 side effect 를 생성하지 않
는다" 라는 가정에 유의하시기 바랍니다. 또한, 매우 제한적인 경우
implementation 이 volatile 대상체에 이루어지는 side effect 를 모두 예
측할 수 있다면, volatile 대상체에 대한 접근 역시 최적화 대상이 될 수
있습니다.

kyong wrote:
x86 manual에 따르면 최소한 x86에서 맞다고 생각됩
니다. 그러니까 gcc가 보장할 필요가 없다는 해석이 가능합니다.

맞습니다. 이미 gcc 의 과도한 최적화 방지가 표준을 위배하지 않는 것이라
고 명백히 한 바 있습니다.

kyong wrote:
그러나 결합된 intruction에 대해서는 보장하고 있지 않습니다.

어떠한 연산의 경우에도, 표준이 volatile 대상체에 대한 접근에 대해서 이
야기하고 있는 것은 (접근에 대한 추가적인 implementation 의 정의를 고려
하지 않았을 때) C 프로그램이 가정하는 abstract machine 과 actual
machine 사이에 1:1 관계가 성립하도록 프로그램이 행동해야 한다는 것입니
다. 따라서 volatile 의 의미는 volatile 이 허락되는 모든 경우에 동일한
최소한의 보장을 갖습니다.

kyong wrote:
전웅 wrote:
- "님이 알고 계시는" volatile 의 공통된 의미에 대해서 설명 부탁드립니
다. 특히, "physical memory 외에 어떠한 가정도 하지 말라" 는 말의 뜻은
어떠한 구체적인 행위가 금지된다는 뜻으로 하신 말씀인지요?

volatile의 의미를 정확히 이해하고 있다면 해서는 안 될 질문이라고 생각됩니다.

volatile 의 의미를 정확히 이해하고 있지 않기 때문이 아니라, 님이 표현
이 불분명하기 때문에 드린 질문입니다.

kyong wrote:
object가 volatile일 때는 반드시 main memory의 주소에서 값을 읽어오란 뜻
입니다.

완벽하지는 않지만 부분적으로는 맞습니다. 더 정확히는 implementation 에
의해 구성되는 actual implementation 과 프로그램이 명시하는 abstract
semantic 이 최소한 1:1 로 대응되어야 함을 의미하는 것입니다. 그 보장을
만족시키는 과정에서 main memory 에 저장되어 있는 "실제 값" 에 대한 보
장이 이루어지는 것입니다.

kyong wrote:
전웅 wrote:
- 그렇다면 반대로 volatile 을 사용하지 않아 in-memory operation 을 얻
어냈을 때는 atomicity 가 보장되는지요?

x86에서 single instruction으로서 인터럽트가 걸린 상황에서 incl을 얘기 하시는 것이라면 여러 프로세서에서도 보장된다는 것이 제 해석입니다.
이것은 저 번에 인용한 원문에 인용된 글에서 single processor에서 보장된다는
것 보다 나아간 해석입니다.(intel manual)

manual 을 다시 한번 확인해 보시기 바랍니다. SMP 에서는 어차피
atomicity 가 보장되지 않습니다.

kyong wrote:
원문 2번째 단락상 의미 때문에 안되는데 *& hack으로 single instruction을
유도해서인터럽트가 걸린 상황에서 되는 상황이 되었지만 다른 사람이
얘기한 do_timer의 design으로 볼 때 고려할 필요도 없는 것이므로 jiffies++
도 좋다고 예기한 것입니다.

해당 부분에 대한 해석에 대해서는 아래에서 다시 나오므로 그때 언급하도
록 하겠습니다.

kyong wrote:
x86에서 물리적 메모리에 쓰는 것이 느리기 때문에 store buffer를 둬서 성능
을 관리하는데 이 때 이루어지는 delay를 갖고 얘기할 수있겠다는 생각이
들었습니다. 그렇지만 delay됐기 때문에 program oder가 안 지켜지는 것은
아닙니다.

이제 님과 제가 가장 의견일치를 보지 못하는 부분에 대한 내용입니다.
(non-volatile) operation 에 의한 delay 는 같은 프로그램의 실행 순서가
최적화로 인해 바뀌는 경우를 이야기하는 것입니다. 이는 아마도 님이 C 표
준이 C 프로그램의 실행에 대해 이야기하는 바를 제대로 알고 계시지 못한
탓이라 생각합니다.

for (i=0; i < 10; i++);
for (j=0; j < 10; j++);
printf("%d, %d\n", i, j);

이와 같은 문장이 있을 때 implementation 은 임의로 j 에 대한 loop 를 먼
저 실행시킬 수도, 혹은 i, j 에 대한 loop 를 한 주기씩 엇갈려가며 실행
시킬 수도 있습니다. C 프로그램은 actual machine 의 행동을 기술하는 것
이 아닌, C 프로그램이 최적화 없이 그대로 실행된다고 가정되는 abstract
machine 의 행동을 기술하는 것입니다. 그리고, 그 actual/abstract
machine 사이에는 완전히 동일한 행동이 보장되지는 않으며, 다만 abstract
machine 에서 얻은 최종적인 결과가 actual machine 에서 얻은 최종 결과와
같다는 것만 보장됩니다 - 이를 "as if 규칙" 이라고 부릅니다. 이와 같은
사실을 근거로 implementation 은 동일한 결과를 보장한다는 전제 아래 최
적화를 도입할 수 있는 것이며, 다만 그와 같은 최적화가 일으킬 수 있는
현실적인 문제를 막을 수 있도록 C 언어에서 volatile 을 제공하고 있는 것
입니다. 일례로, 어떤 implementation 이 actual/abstract machine 이 동일
하게 행동하도록 (따라서, 완전히 최적화가 배제되도록) 구성되어 있다면,
volatile 은 아예 무시될 수도 있습니다.

따라서, 님이 생각하시는 것과는 달리, 동일한 결과를 보인다면 "같은" 프
로그램의 다른 부분을 미리 실행하는 것이 가능하며, 실제로 그와 같은 일
이 일어남을 위의 다른 분이 보여주신 예에서 확인할 수 있습니다 - "code
가 가장 많은 것을 설명해준다" 고 믿는 분이 아니었는지요?

kyong wrote:
그러나 read, write 할 때 access 시점이 다르고(incl이더라도)
interrupt나 lock이 걸린 상황이 아니므로 값의 차이를 낳는다입니다.
즉, access 시점이 다른 두 intruction을 결합해서는 예측할 수 없는 것이
volatile인 것입니다.

일단, 한 가지를 분명히 하겠습니다. 아래에서 다시 자세히 말씀드리겠지만
volatile 은 atomicity 와 아무런 관련이 없습니다. implementation 이 추
가적으로 atomicity 에 대한 보장을 줄 수는 있지만, 이는 표준이 volatile
에 대해 최소한으로 요구하는 것이 아닙니다. 따라서, volatile 은
atomicity 와 관련된 문제를 그대로 안고 있습니다. 하지만, 논의의 중심에
있는 do_timer 는 다른 이유로 atomicity 가 보장되는 문맥입니다.

kyong wrote:
do_timer상황에서는 맞습니다. 그러나 volatile과 atomicity와 아무 관련이
없다는 말은 틀렸습니다. in-memory operation에 대해 한 말은 제가 한 것과
는 다릅니다. volatile의 의미를 제거한 최적화의결과로서 의미를 가진다고
얘기로 한 줄로 압니다. volatile이 in-memory operation을 생성하는 것은 제가
기대하는 행동입니다.

앞으로 그런 기대를 버리시기 바랍니다. volatile 이 어떻게든 atomicity
와 관련되어 있다면, async signal 에 대해서 표준이 sig_atomic_t 를 도입
할 이유가 없습니다. signal 만 관련되어도 volatile 은 "접근" 에 대한
atomicity 를 보장해 주지 못합니다.

kyong wrote:
volatile은 main memory에서의 여러 방법으로 값이 변경될 수 있음을 규정하기
때문에 atomicity를 위해서 별도의 design을 강요하는 것입니다.

절대로 그렇지 않습니다. 표준을 가지고 계신다면 "volatile" 로 본문을
검색해 보시기 바랍니다. 어떠한 경로를 통해 그와 같은 정보를 얻으셨는지
모르겠지만 틀린 이야기입니다.

kyong wrote:
volatile 의미를 제거해 single instruction이 생성되도록 최적화를 유도해
atomicity를 보장받으려 시도했다는 것입니다. 그러나 전 이것이 후보라고
얘기 했지만 여러 글들을 보면서 더욱 아니란 생각을 하게 됐습니다.
gcc mailling list를 봤을 때 특히, *& hack은 거기 개발자도 권하는 기법이고
(volatile <-> non-volatile 변환) linus같은 경우엔 특히 volatile이 제대로 된
코드를 못 만든다고 불평하는 것을 봤습니다. 그 당시 개발자가 timer irq
design을 이해 못했다고 생각되지 않습니다.

"그 당시 개발자가 timer IRQ desing 을 이해 못했을리 없다" 는 것은 님이
말씀하고 계시듯이 님의 "생각" 입니다. 그리고, 여러가지 다른 생각이 있
을 수 있는 것이 현재의 상황입니다. 저는 지금 "성능 향상이 그 목적" 이
라는 님의 생각이 틀렸음을 주장하고 있는 것이 아니라, 의심의 여지 없이
확신할 수는 없음을 이야기하고 있는 것입니다. 단 하나의 객관적 진실이
불분명한 상태에서, 님에게 님의 생각이 중요하듯이 다른 사람들에게는 그
들의 생각이 중요한 것입니다.

kyong wrote:
제가 저번에 조건을 둔 즉, 두 sequence point 사이에 같은 값이 여러번 사용된
경우를 애기한 것입니다. 즉 다음과 같은 경우입니다.
if (f(j*j)) => register int temp = j; if (f(temp*temp))
이 예제는 C reference manual 에서 인용했습니다.

해당 예제는 잘못된 것입니다. H&S4 에 대해서는 오래 전에 해당 저자에게
지적하는 메일을 보냈으며
(http://c-expert.uos.ac.kr/program/c_etcdoc/carmerror.pdf),
다만 그 시점이 H&S5 가 나온 이후 이기에 제대로 H&S5 에 제대로 반영되지
않았습니다. 제가 표준화 위원회의 멤버와 그와 같은 최적화에 대해 논의를
한 이유도 바로 그 예제에 대한 의심 때문이었고, 그와 같은 두 sequence
point 사이에서의 최적화는 올바르지 않다는 것이 결론이었습니다.

kyong wrote:
전웅 wrote:
extern volatile int a;

i = a + a;

- 여기서 두 sequence point 가 어디인지요?

- 또, 그 사이에서 최적화가 허락된다는 것은 a 라는 대상체 (실제 메모리)
에 최소한 몇 번의 참조가 있어야 함을 의미하는 것인지요?


위 예제는 적절하지 않다고 생각됩니다.
위의 경우 side effect가 없는 경우입니다.

님께서 어떠한 경로를 통해 volatile 에 대한 지식을 얻으셨는지 모르겠지
만, 개인적으로 표준을 직접 보시거나 표준을 올바르게 기술한 책을 다시
보시기를 추천해 드립니다. volatile 대상체를 읽는 행동은 그 자체로 side
effect 입니다.

kyong wrote:
다음 질문에서 이 부분은 제가 표준화관련 문서를 정확히 본 것이 아니고 irc에서
들은 것이여서 정확한지는 모르겠으나 여러번이라고 했으니 2번 이상이라고 짐
작할 뿐입니다.

님께서 sequence point 사이에서의 최적화에 대한 이야기를 H&S 에서 얻으
셨을 것이라 예상했기에 일부러 유사한 예를 보여드린 것입니다. H&S 에 따
르면, 위의 예는

register r = a;    // "register" obeyed
i = r + r;

와 같이 최적화가 가능합니다. 하지만, 말씀드렸듯이 이것은 사실이 아닙니
다. H&S 에서 유사한 예를 통해 seqeunce point 사이에서의 최적화가 가능
하다고 생각하시는 분이 이 상황에서는 최소한 2번의 접근이 필요하다고 추
측하시는 것은 모순됩니다.

kyong wrote:
volatile int i;

for (i = 0; i < 100; i++) func(i);

아래와 같이 번역할 수 없음의 의미하는 것 뿐이며,

register int r;    // "register" obeyed
for (r = 0; r < 100; r++) func(r);
i = r;

님이 애초에 semantic을 보장하는 register caching까지 막지 않는다는 것을 말
하면서 든 예제인데 여기 예제는 register로 copy하지 말고 main memory를 읽어야한다는 volatile의 의미를 얘기한 예제일 뿐입니다.
그러니까 적절한 예제는 semantic을 보장하면서 register cacing하는
경우입니다.

"첫번째 보인 코드가 두번째 코드처럼 행동할 수 없다" 는 것을 보이는 위
의 예는 "volatile 의 semantic 을 보장하면서 register caching 을 막음을
보여주는" 예입니다 - C 표준의 Rationale 에 나온 것과 사실한 동일한 예
입니다. 다르게 생각하신다면 이는 님께서 volatile 에 대해서 오해하는 부
분이 있기 때문입니다.

kyong wrote:
제가 번역 기술상 맞다고 생각하는 번역은 다음과 같습니다.
Quote:

그 값은 캐쉬되지 않을 것이다.(컴파일러 버그인 경우를 뺀다면), 그러나 값이
읽어져서 증가된 다음 저장 될 수 있다. 그리고 저장은 volatile이 아닌 연산이
나 함수호출 이후로 연기될 수 있다.


즉, 지금 volatile 연산에 의해 변경된 값이 메모리에 반영되기 전에 volatile이
아닌 연산(즉 volatile 연산은 최적화 되지 않기 때문에 또 실행 된다고 해도 program order가 보장되므로)이나 함수로 인해 값이 또 읽혀 질 수 있고
저장된 후에는 다른 값이 되어서 atomicity가 회손되는 것입니다.
결국 atomicity가 회손된다는 것은 맞지만 다른 연산에 의해 지연되서 생긴 결과
라는 해석과는 다분히 차이가 있는 것입니다.

이 부분이 바로 님께서 오해하고 계신 부분입니다. 원하신다면 해당 글을
쓴 사람에게 그 의미를 직접 물어보시기 바랍니다. 이미 말씀드렸듯이 프로
그램의 실행 순서는 동일한 결과를 보인다는 전제 아래에서 뒤바뀔 수 있습
니다. 프로그램의 실행 순서가 보장된다는 님의 생각이 옳다면 gcc 는 어떠
한 옵션을 사용해도 표준을 따르지 않는 implementation 이 되어 버립니다.
그리고, 다시 한번 말씀드리지만, 해당 문단은 do_timer 가 처한 atomicity
가 보장되는 특수한 문맥에 대해서 이야기하고 있는 것이며, 만약 님의 생
각처럼 atomicity 문제를 이야기하는 것이라면 간섭이 가능한 연산을
non-volatile 로 한정할 이유가 없습니다. 같은 프로그램 안에서
implementation 이 side effect 를 예측할 수 없는 두 volailte 대상체에
대한 연산의 순서를 바꾸는 것은 결과에 영향을 줄 수 있기 때문에 거의 일
어나지 않는 일입니다. 하지만, 어떤 volatile 연산과 non-volatile 연산의
순서는 결과에 영향을 주지 않기에 (이론적으로는 큰 scale 도 가능하지만,
현실적인 이유로 보통은 작은 scale 에서) 순서가 뒤섞일 수 있습니다. 해
당 글이 말하는 "delay" 는 이로 인한 delay 입니다.

kyong wrote:
non-volatile으로 한정한 것이 아니라 memory에 있기 때문에 memory를 접근
하는 모든 operation에 의해서 값이 수정될 수 있다는 것을 뜻한다고 생각합
니다.

kyong wrote:
인터럽트 상황에는 기존 operation을 끝내고 system bus를 독점하기 때문에
그럴 수 없다는 것이 제 해석입니다.

맞습니다. 따라서, do_timer 에 대한 논의에서는 atomicity 는 배제되어야
합니다. 그럼에도 님께서는 위에서 계속 해당 연산의 atomicity 에 대해
이야기하고 계십니다. 아직도 무엇이 문제인지 보이지 않으시는지요?

kyong wrote:
표준은 위애서 얘기 했듯이 read, write가 결합된 연산에 대해서 side effect가
없음을 얘기하고 있지 않습니다. do_timer는 atomicity를 고려된 경우이고요.
분명히 위해서 애기하신 것은 do_timer 상황에서 얘기한 경우가 아니라고
생각됩니다.

2번째 문단을 do_timer 문맥이 아닌 일반적인 문맥에 대한 이야기라고 믿고
계신 것 같습니다. 이 역시 해당 글쓴이에게 직접 메일을 보내 물어보시기
바랍니다. 만약, 해당 문맥이 do_timer 문맥이 아닌 일반적인 이야기로 쓴
것이라면 ++ 연산에 간섭을 줄 수 있는 연산을 non-volatile 로 한정할 필
요가 전혀 없습니다.

kyong wrote:
네 그렇다고 생각합니다. 왜냐면 그렇게 code를 씀으로 해서 cpu cycle을 줄이
는 직접적인 효과가 바로 보이는 반면 다른 주장에는 그런 효과 같은 뚜렷한
징후를 볼 수 없다는 것입니다.

이 부분은 "저의 생각", "님의 생각" 이므로 더 이상 논의하지 않겠습니다.
진실이 불투명한 상태에서 님이나 저나 서로의 "생각의 자유" 를 빼앗을 권
리는 없습니다. 만약, 진실이 불투명하지 않다고 생각하신다면, 계속 추가
적인 근거를 찾아서 설득해주시기 바랍니다.

Quote:
제가 진실인양 강요한 것이 아니라 뚜렷한 근거를 들어 제 주장을 펼친 것 뿐
입니다. 진실로 믿고 말고는 각자가 판단할 일입니다.

그 주장을 보다 "주장" 인 것처럼 표현해 달라고 말씀드린 것입니다.

kyong wrote:
timer_irq design을 몰랐음이 아니라는 가정하에 그것은 아니다입니다.

"가정하" 에 그렇습니다. 그럼 이제 그 가정을 증명할 차례입니다. 문제는
"원 개발자는 timer IRQ design 을 알았을까?" 가 됩니다. 이제 그 가정을
어떻게 증명하실 것인지요? 제가 왜 계속해서 "원 개발자의 마음 속에 들
어있는 생각" 을 찾고 계신지 그 이유를 모르시겠습니까?

kyong wrote:
역사적인 이유에 대해서는 구체적으로 읽어 보지 못했습니다. 단 최근에
volatile을 busy-waiting과 관련해서 역사적인 이유에서 남겨 둔다는 말은
본 적이 있습니다. 최초 incl이 사용됐다면 중간에 jiffies++가 생겼다가
없어지는 일이 일어나지 말았어야 한다고 전 생각합니다.
이것은 atomicity에 대한 것도 해당되는것입니다.

유사한 이야기는 *& hack 에도 적용됩니다. "성능 향상" 이 그 주요한 목적
이었다면, 꾸준하게 "완전한" 성능 향상을 위한 최적화가 사용되었어야 합
니다. 단 한 시점에서라도 불완전한 형태를 보였다는 사실은 그에 대한 의
심을 남깁니다.

kyong wrote:
전 가능성을 얘기하는 것이 아니라 가장 신뢰할 만한 가능성을 얘기하는
것입니다.

"신뢰할만한" 은 주관적인 가치 판단입니다.

kyong wrote:
c 표준화 과정을 정확히 모르지만, draft를 거쳐 rfc가 만들어 지는 과정을 봐도
그렇고(rfc가 표준은 아니지만) 규정은 계속 진화하는 것입니다. C89, C99로
진화했듯이 변화하기 마련인데 그런 단정을 하시니 이해가 되지 않을 뿐입니다.

앞으로 발표될 예정인 C99 TC2 와 Embedded C TR 에는 그와 같은 보장이 추
가로 존재하지 않는다고 말씀드렸습니다. 그리고, 그 이후의 미래는 저도
확신할 수 없지만 ("역술가" 이야기를 언급했던 것으로 기억합니다), C 표
준화 위원회가 생각하고 있는 C 언어의 정의를 고려한다면 그럴 가능성이
적다고 말씀 드렸습니다. 즉, Embedded C TR 과 C99 TC2 가 발표되는 시점
까지는 제 예상이 맞을 수 밖에 없는 것이며, 그 이후에는 틀릴 가능성이
있음을 이미 인정하고 있습니다. 엉뚱한 부분을 인용하며 반박의 근거로 사
용하시지 않으셨으면 좋겠습니다.

kyong wrote:
특히 volatile에 대한 rvalue에 대한 의미는 표준에서 정확하지 않다는 글을 본적
이 있습니다.

잘못된 이야기입니다. "rvalue 에 대한 의미" 로 무엇을 말씀하고 계신지
불분명하지만,

- rvalue (값의) 문맥에서 형한정어는 무의미하다.

- volatile 대상체를 "읽는 행위" 는 side effect 이다.

임은 분명한 사실입니다. volatile 에 대한 불분명한 부분은 전혀 다른 곳
에 있습니다.

kyong wrote:
거짓에 가능성이 아니라 변화의 가능성을 부정한 사실에 대한
일상적인 거부감이란 사실을 이해하시기 바랍니다.

가까운 미래에 대해서는 확실한 근거를 기반으로 한 단정적인 부정이었으며
먼 미래에 대해서는 기본적인 철학에 기반한 약한 부정이었습니다. 님이 말
씀하신 것과 유사하게, 님의 단정적인 표현을 빌린 "개인적 의견 혹은 추측"
에 대한 다른 사람들의 일상적인 거부감도 생각해 보시기 바랍니다.

kyong wrote:
sys_iopl에서 문제는 결국 다른 방법으로 해결됐습니다. 2.7.x 버젼에서 문제가
있어서 그런 *& hack으로 linus가 풀었지만 결국 2.8.x 에서 다시 불거져 나와서
다른 patch가 적용된 것입니다. 결국 bug를 피하기 위한 임시 방편은 오래 가지
못한다는 것이 제 생각입니다. 그리고 그것은 volatile 의미를 제거하는 hack
이 아니기 때문에 다른 문제라고 생각됩니다.

예, 그렇기 때문에 sys_iopl 을 "제외한" kernel 의 다른 부분에서
volatile 의 의미를 제거하기 위한 목적으로 *& hack 이 사용된 경우가 있
는지 묻고 있는 것입니다.

kyong wrote:
kernel 개발자들은 주석을 안 달기로 유명합니다. david miller는 문서가 오히려
방해되므로 필요없다고까지 얘기 한 사람입니다. 물론 전적으로 동의하지 않지만
적어도 지금 networking layer를 볼 때 분명 동작하는 system입니다. code 가
가장 많은 것을 말해 준다는 사실을 부정하시진 않겠지요?

그동안의 개인적인 경험에 따르면 비표준적이고 document 되지 않은 비정상
적인 code 에 대해서는 원 개발자의 의도를 정확히 아는 것이 가장 중요하
다는 것입니다 - 물론, 이 역시 가치 판단이 개입되어 있으므로, 서로 다른
사람이 다른 생각을 할 수 있습니다. "code 가 가장 많은 것을 말해줄 수는
있어도" (원 개발자의 의도까지를 포함한) 모든 것을 말해줄 수는 없습니다.

kyong wrote:
전웅 wrote:
저는 "in-memory incl 를 사용하는 것이 *& hack 의 목적이다" 라는 사실에
대해서는 님이 이 논의에 참여하기 이전부터 이야기하고 있었으며

...

그 이유가 "최적화" 인지는 의심스럽다고 말씀드리고 있는 것입니다. 논의
가 진행되면서 제 의견의 변화가 생긴 부분은 (이미 말씀드렸듯이) 최적화
일 가능성에 대한 생각이 이전보다 커졌다는 것 뿐입니다.


알겠습니다. *& hack은 platform independent 하기 때문에 incl 이 목적이
다라고 얘기할 수 없고 volatile 의미를 제거한 최적화 유도가 목적이다가 더 정확할 것 같습니다.

제가 말씀드린 바를 제대로 이해하고 계시지 못합니다. 상황을 어떻게 설명
드려야 의사소통이 가능할지 답답합니다. *& hack 은 결코 platform
independent 하지 않으며, *& hack 의 목적은 incl 이 분명합니다.
volatile 의 의미를 제거하는 것의 "일반적인" 의미는 최적화와 무관합니다.

kyong wrote:
전 lkml을 거의 매일 읽는 사람입니다.
위에서 애기 했듯이 code로 설명되지 않는다면 무의미 합니다.
역사적인 이유도 그렇고요. asm version을 제안한 사람이 누군지도 기억합니다.

님이 lkml 을 거의 매일 읽는 것과 code 로 설명되지 않으면 무의미하다는
주장 사이에는 연관 관계가 없습니다. asm version 을 제안한 사람이 누구
인지 기억하는 것 역시 님의 개인적인 생각이 진실임을 보장하는 근거가 되
지 않습니다.

kyong wrote:
전웅 wrote:
혹시 매번 다른 분이 "kyong" 라는 ID 로 논의에 참여하고 계신 것인지 의
심스럽습니다. 바로 이전 글에서 그 이유를 밝혔습니다. 님이 님의 개인적
인 의견임을 분명히 하지 않고, 의심이 가능한 사실을 단정적으로 말씀하신
것이 최초의 이유였습니다.

이것은 극히 저보다 위험한 발상입니다. 의심을 구체적으로 밝혀가는 것이
순서입니다. 여기 누가 오고 가는지 알려고 오는 것이 아닙니다.
비슷한 부류의 사람들끼리 정보를 교환하면서 함께 커 가자고 오는 것입니다.
제가 누군지는 로그가 말해 주고 주변 정황을 속일 수는 없습니다.

제가 드린 말씀은 비유적인 표현입니다. 님이 전체 논의의 흐름을 제대로
인식하고 계시지 못한 상태에서 님의 개인적인 의견만을 반복하여 주장하고
계시기에 전체 논의를 완전히 인식하신 후에 진정 문제가 되는 부분만을 말
씀해 주시기를 바라며 쓴 비유입니다.

kyong wrote:
전웅 wrote:
지금 "유지보수자" 가 그 코드를 유지하고 있는 주요한 이유는 다행스럽게
도 직접 물을 수 있기에 확실히 알 수 있는 부분입니다 - 이 부분 역시 확
인이 필요합니다.

님의 문제는 소프트웨어에 대한 생각이 극히 제한 돼 있다는 것입니다.
저자가 bug없는 perfect한 코드를 만들고 자기한 만든 code를 모두 기억하고 있
다면 맞습니다. 물어보면 되죠. 그러나 현실은 그렇지 않습니다. code는 저자가
없어도 살아서 증명해 보이는 것입니다.

님이 유일하게 근거로 언급하고 계시는 것은 "생성된 code 가 더 나은 성능
을 보인다 (혹은 보일 수 있다)" 입니다. 그리고 이와 같은 사실에 대해서
는 이미 제 의견을 제시한 바 있습니다. 제가 이 상황에서 또 그 의견을 반
복하고, 님은 또 "code 가 보여준다" 라는 의견을 제시하고, 저는 또 반복
하고, ... 오죽하면 서로 다른 사람이 "kyong" 라는 ID 로 논의에 참여하고
있지는 않냐는 비유를 사용했겠습니까?

kyong wrote:
topic은 (*(unsigned long *)&jiffies)++ 의 의미였습니다.
원 개발자의 마음을 알아보는 것이 아니였음을 말씀드립니다.

원 개발자의 마음이 *& hack 을 사용한 jiffies++ 의 의미입니다.
"jiffies++ 에 *& hack 을 사용해 더 나은 성능을 얻을 수도 있다" 라는 사
실은 분명합니다. "jiffies++ 에 *& hack 을 사용한 근본적인 이유가 성능
향상일까?" 는 또 다른 문제이며, OP 께서 묻고자 했던 것입니다.

kyong wrote:
틀릴 수 있고 맞을 수 있습니다. 사과할 일은 아닙니다.

저는 제가 말씀드린 기술적인 내용 중에 오류가 있다면 분명 사과드립니다.
이는 일정 시간동안 제 말을 믿고 잘못된 내용을 진실로 알고 계신 분들에
대한 사과입니다. 이는 제 글의 신뢰성을 높이기 위한 방법이며, 그 신뢰성
을 위해 글을 쓰기 전에 관련된 내용을 재확인해보도록 해주는 장치이기도
합니다.

kyong wrote:
제가 분명히 느낀점은 code를 해석하는 방법이 현실과는 거리가 먼
저자와의 접촉이 우선이란 것을 막무가네로 가르치려 한다는 것입니다.

지금까지의 논의에서 (분명히 확신하고 있는 부분을 제외하고) 제가 "막무
가내" 의 태도를 보인 적이 있다면 인용바랍니다. 저는 "불확실함" 을 표현
한 적은 있어도 "내 말이 진실이니 믿어라" 라는 식의 태도를 취한 적은 없
습니다. 오히려 님의 단정적인 형태의 주장은 "막무가내" 에 가까운 태도였
습니다.

kyong wrote:
제가
code에 의해 제시한 근거는 추측에 지나지 않고 나름대로 지식을 바탕으로
기술한 것을 왜곡에 대한 불순한 시도인양 치부하고 있습니다. 최소한 그런
자세는 사실을 기술하는데 도움이 되지 않는다고 생각됩니다.

code 에 대해 제시한 근거는 (님은 중요하다고 생각하실지 모르겠지만) 의
심많은 제가 보기엔 여전히 가능한 의견 중 하나일 뿐이며, 그렇지 않다는
것을 증명하는 것은 제가 아닌 님의 몫입니다. 그리고, 이미 말씀드렸듯이
님의 volatile 에 대한 이해는 불완전한 상태이며, C 언어와 volatile 에
대한 불완전한 지식으로 문제의 lkml 의 글을 부분적으로 이해하시는 과정
에서 오해가 발생한 것입니다. 정리하면,

- 지금까지 진행된 논의에서 제 기술적인 설명에는 틀린 부분이 없으며, 님
께서 틀렸다고 지적하신 부분은 님이 해당 부분을 오해하고 계신 탓입니다
(구체적으로 어떤 부분을 어떻게 잘못 알고 계신 것인지 제가 알 길이 없기
에 지난번에 질문 형태의 글을 포스팅한 것입니다. 이점 이해해 주시길 바
랍니다).

- jiffies++ 에 *& hack 을 적용한 근본적인 이유 중 하나로 "가능한 성능
향상" 을 배제해서는 안 되는 것이었습니다 - 이는 님이 이 논의에 참여하
신 이후에 처음과 달라진 제 생각입니다.

- load/incl/store 대신 in-memory operation 을 사용하면 분명 성능 향상
이 있습니다. 하지만, 이것이 원 개발자의 주요한 의도였는지는 아직 의심
의 여지가 남아 있습니다. 이부분에 대해서 님은 다르게 생각하실 수 있습
니다. 저는 님의 개인적인 생각까지 잘못된 것이라 주장하는 것은 아닙니다.

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

전웅의 이미지

kyong wrote:
원저자의 의도도 그렇다는 것이 제 생각입니다.

ftp://ftp.kernel.org/pub/linux/kernel/v1.3/linux-1.3.76.tar.bz2
ftp://ftp.kernel.org/pub/linux/kernel/v1.3/patch-1.3.76.gz
interrupt latency reasons로 패치된 곳을 보면 직접적으로 jiffies를 언급하지는
않았지만 같은 문제 인식아래 *& 으로 바꾸었다고 짐작할 수 있습니다.
patch는 잘 못 되어서 나오지 않는데 1.3.76 소스에 처음 적용된 것은 분명합니다.

드디어 추가적인 근거가 나왔군요 - 매우 반갑습니다. 이 근거에 대해서는
추후에 (제가 현재 개인적인 일로 너무 바쁩니다) 확인해본 후 말씀드리겠
습니다 - 님께서 이 글을 포스팅하신 이후에 님의 이전 글에 대한 제 답글
이 포스팅되었기에, 포스팅 순서에 따른 가능한 오해를 막기 위해 미리 말
씀드립니다.

kyong wrote:
그리고 시간상으로 봤을 때 저자는 linus라고 짐작됩니다.

저 역시 그렇게 생각합니다. 64비트 jiffies 문제를 다룰 때 jiffies++ 에
*& hack 가 적용된 형태를 여러 곳에서 반복하여 언급하는 사람 역시 Linus
였습니다. 가능하다면 lkml 등을 통해 보다 분명한 목적을 확인해 주셨으면
하는 바램입니다.

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

페이지

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.