percpu_read 와 __attribute__(__section__)

조회 수 1123 추천 수 0 2010.03.08 09:00:43

 

여기저기 뒤져봤는데, 좀 내용이 난해하네요 ㅡ_ㅡ;;;

 

#define DEFINE_PER_CPU(type, name)                     \
        DEFINE_PER_CPU_SECTION(type, name, "")

 

#define PER_CPU_BASE_SECTION    ".data.percpu"

#define PER_CPU_ATTRIBUTES

 

#define __stringify_1(x...)     #x
#define __stringify(x...)       __stringify_1(x)

#define __percpu_seg            fs

#define __percpu_arg(x)         "%%"__stringify(__percpu_seg)":%P" #x

 

#define DEFINE_PER_CPU_SECTION(type, name, section)                   \
        __attribute__((__section__(PER_CPU_BASE_SECTION section))) \
        PER_CPU_ATTRIBUTES __typeof__(type) per_cpu_##name

 

#define percpu_from_op(op, var)                         \
({                                                                            \
        typeof(var) ret__;                                          \
        switch (sizeof(var)) {                                    \
        case 1:                                                            \
                asm(op "b "__percpu_arg(1)",%0"       \
                    : "=q" (ret__)                                     \
                    : "m" (var));                                       \
                break;                                                     \
        case 2:                                                            \
                asm(op "w "__percpu_arg(1)",%0"      \
                    : "=r" (ret__)                                      \
                    : "m" (var));                                       \
                break;                                                     \
        case 4:                                                            \
                asm(op "l "__percpu_arg(1)",%0"        \
                    : "=r" (ret__)                                     \
                    : "m" (var));                                       \
                break;                                                    \
        case 8:                                                           \
                asm(op "q "__percpu_arg(1)",%0"      \
                    : "=r" (ret__)                                    \
                    : "m" (var));                                      \
                break;                                                   \
        default: __bad_percpu_size();                     \
        }                                                                   \
        ret__;                                                            \
})

 

#define percpu_read(var)        percpu_from_op("mov", per_cpu__##var)

 

DEFINE_PER_CPU(int, cpu_number);


 

제가 이것들을 해석한바에 의하면 ㅡㅡ;;;

cpu_number라는 녀석이 어떻게 된 구조인지 전혀 모르겠네요 ...

 

그래도 일단, 제 나름대로의 해석을 ...

먼저 어제 도움을 주신분의 말씀대로 DEFINE_PER_CPU(int, cpu_number)를 살펴봤습니다.

 

위에 보이는 구조대로 DEFINE_PER_CPU_SECTION(type, name, "") 로 되어있어

DEFINE_PER_CPU_SECTION을 추적해봤습니다.

그러니까 또 엄청난 테러가 ... ;;;

 

#define DEFINE_PER_CPU_SECTION(type, name, section)                   \
        __attribute__((__section__(PER_CPU_BASE_SECTION section))) \
        PER_CPU_ATTRIBUTES __typeof__(type) per_cpu_##name

 

위와 같은 엽기적인 녀석이 튀어나오는 겁니다 ... OTL ...

아무튼 PER_CPU_BASE_SECTION을 알아보니 ".data.percpu" 더군요

그리고 PER_CPU_ATTRIBUTES는 아무것도 없었습니다.

__typeof__ 녀석도 GCC 확장으로 int가 들어갔으니 ... 타입을 가져올테구

per_cpu_##name은 치환되어 int per_cpu_cpu_number 로 된다는 것인데,

도대체 이게 뭔말인가요 ㅡㅡ;;; 해석하고도 뭔말인지 정신이 없습니다.

 

그다음으로 더 충격적인 것은

 

#define percpu_read(var)        percpu_from_op("mov", per_cpu__##var)

이번에는 per_cpu__cpu_number가 되겠죠 ?

그래서 percpu_from_op를 추적해봤습니다.

 

#define percpu_from_op(op, var)                         \
({                                                                            \
        typeof(var) ret__;                                          \
        switch (sizeof(var)) {                                    \
        case 1:                                                            \
                asm(op "b "__percpu_arg(1)",%0"       \
                    : "=q" (ret__)                                     \
                    : "m" (var));                                       \
                break;                                                     \
        case 2:                                                            \
                asm(op "w "__percpu_arg(1)",%0"      \
                    : "=r" (ret__)                                      \
                    : "m" (var));                                       \
                break;                                                     \
        case 4:                                                            \
                asm(op "l "__percpu_arg(1)",%0"        \
                    : "=r" (ret__)                                     \
                    : "m" (var));                                       \
                break;                                                    \
        case 8:                                                           \
                asm(op "q "__percpu_arg(1)",%0"      \
                    : "=r" (ret__)                                    \
                    : "m" (var));                                      \
                break;                                                   \
        default: __bad_percpu_size();                     \
        }                                                                   \
        ret__;                                                            \
})

 

opcode로 들어온 mov와 var(per_cpu__cpu_number)가 있습니다.

그리고 typeof로 var의 타입인 int __ret을 설정합니다.

그리고 int형이니 case 4에 걸릴테고(32 bit Architecture)

__percpu_arg(1)을 다시 조사해보면, 아래와 같습니다.

 

#define __stringify_1(x...)     #x
#define __stringify(x...)       __stringify_1(x)

#define __percpu_seg            fs

#define __percpu_arg(x)         "%%"__stringify(__percpu_seg)":%P" #x

 

여기서부터 다 꼬이기 시작하네요 ㅡㅡ;;;

누군가 절 구제해주십시오 ...

 

도대체 저 엽기적인 문법들은 뭔가요 .... ?

문법을 알아서 해석을해도 ㅡ_ㅡ;;; 정리가 안됩니다.

 

 

 

 

 

 


이상훈

2010.03.08 10:36:50
*.36.40.20

그리고 ".data.precpu" 라는 Section은 도대체 뭐하는 섹션일까요 ㅡ_ㅡ; ㅎ

김남형

2010.03.08 10:52:14
*.176.76.114

percpu 변수들은 각 cpu마다 각자 사용하는 데이터를 의미하는데

cache coherency로 인해 발생할 수 있는 성능 저하를 최소화하기 위해

cpu 별로 따로 할당되는 percpu 영역(segment)에 저장됩니다.


따라서 이러한 변수들을 별도로 관리하기 위해 .data.percpu라는 섹션을 만들어 둔 뒤

DEFINE_PER_CPU()로 선언된 변수들은 해당 섹션에 저장하도록 합니다.

그리고 커널 부팅 시에 percpu 영역을 읽어들여서

각 cpu 마다 메모리를 할당하여 percpu 영역의 내용을 복사하고

해당 영역을 가리키는 segment descriptor를 설정하여 GDT에  저장하고

fs 레지스터가 해당 segment descriptor를 가리키도록 합니다.

이상훈

2010.03.08 11:19:36
*.36.40.20

감사합니다 ^^;ㅎ

그런데 __attribute__(__section__) 이녀석이 하는 역할이 정확히 뭔가요 ?

특정 섹션에다가 배치하겠다고 하는것 같은데, 실제로 그 섹션이 위치하는것이 무엇이고,

저렇게 특정한 섹션을 만들어서 배치시키는 이유가 무엇인지 궁금합니다.

백창우

2010.03.08 11:54:27
*.101.136.91

section을 설정하는 compiler directive입니다. __attribute__(".data")하게 되면 해당하는 코드 및 데이터는 .data 섹션에 넣게 됩니다.

섹션에 대해서는 제가 보내드린 문서를 참고하십시요.

 

.data.percpu 섹션은 컴파일러에서 기본적으로 잡는 섹션이 아닙니다.

그래서 임의로 지정해주어야 합니다.

 

마지막으로 percpu는 SMP 시스템에서 특정 전역 자료 구조 접근시 해당 CPU만 사용하는 자료임으로 lock 없이 접근할 수 있어 lock overhead를 줄이는 역할도 담당합니다.

이상훈

2010.03.08 14:51:31
*.36.40.20

오 ... 감사합니다 ㅎㅎ

List of Articles
번호 제목 글쓴이 날짜 조회 수
102 Linker Script부분과 종합된 질문 [4] 이상훈 2010-03-17 1038
101 sbrk() 의 정확한 역할 ... [3] 이상훈 2010-03-17 1072
100 엄청난 오개념 [4] 이상훈 2010-03-16 987
99 커널 스터디 관련 질문입니다. [1] 이준명 2010-03-16 965
98 용어적인 질문 [2] 이상훈 2010-03-16 939
97 spin_lock , zone, cgroup 에 관한질문.. [4] 강진성 2010-03-13 1088
96 환경 변수 설정관련 질문 ... [3] 이상훈 2010-03-11 969
95 네트워크 인터페이스 할당 변경에 관련하여 문의드립니다. [3] 송인재 2010-03-10 1025
» percpu_read 와 __attribute__(__section__) [5] 이상훈 2010-03-08 1123
93 cpu_number 정의가 어디있는건가요 ? [2] 이상훈 2010-03-07 1002
92 add_preempt_count() 에 대해서 ... [3] 이상훈 2010-03-07 1044
91 기계어 질문 [7] 이상훈 2010-03-06 1072
90 스터디 시간 좀 늦춰주실 수 없나요 ? [3] 이상훈 2010-03-06 957
89 백창우님 질문입니다 [4] 이상훈 2010-03-06 1104
88 __ASSEMBLY__ 의 의미는 무엇인가요 ? [2] 이상훈 2010-03-05 1122
87 신기한 것 발견 ... [2] 이상훈 2010-03-03 1231
86 제일 궁금한부분입니다 ㅡ_ㅡ;;; [2] 이상훈 2010-03-03 1000
85 질문입니다 [2] 이상훈 2010-03-02 1019
84 $(TOPDIR)/Makefile 질문 [4] 이상훈 2010-03-02 1045
83 모듈 단위로 분석하는 것의 한계점 [5] Linux 2010-02-28 1053



XE Login