2014-12-24 5 views
5

리눅스 시스템에서 페이지 오류 시간을 계산하는 프로그램을 작성했습니다. 보다 정확하게, 커널이 함수 __do_page_fault을 실행합니다.
그리고 어쨌든 pfcount_at_begpfcount_at_end이라는 두 개의 전역 변수를 작성했습니다.이 변수는 함수의 다른 위치에서 __do_page_fault 함수가 실행될 때 한 번 증가합니다. I는 pfcount_at_end의 값 pfcount_at_beg 값보다 작을 것으로 예상리눅스에서 페이지 오류를 계산하는 데 혼란스러운 결과가 있습니다.

unsigned long pfcount_at_beg = 0; 
unsigned long pfcount_at_end = 0; 
static void __kprobes 
__do_page_fault(...) 
{ 
    struct vm_area_sruct *vma; 
    ... // VARIABLES DEFINITION 
    unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; 
    pfcount_at_beg++;  // I add THIS 
    ... 
    ... 
    // ORIGINAL CODE OF THE FUNCTION 
    ... 
    pfcount_at_end++;  // I add THIS 
} 

:으로 설명하기

는 수정 기능 간다.

커널이 코드 pfcount_at_end++의 명령을 실행할 때마다 pfcount_at_beg++ (모든 기능이 코드의 맨 처음부터 시작됨)을 실행해야합니다.
한편,이 두 줄의 코드 사이에는 많은 조건부 return이 있습니다.

그러나 결과는 반대로 나타납니다. pfcount_at_end 값은 pfcount_at_beg 값보다 큽니다.
printk을 사용하여이 커널 변수를 자체 정의 된 syscall을 통해 인쇄합니다. 그리고 system call으로 전화를 걸기 위해 사용자 레벨 프로그램을 작성했습니다. 정확히이 기간 동안 무슨 일이 있었는지 아는 사람이

// syscall 
asmlinkage int sys_mysyscall(void) 
{ 
    printk(KERN_INFO "total pf_at_beg%lu\ntotal pf_at_end%lu\n", pfcount_at_beg, pfcount_at_end) 
    return 0; 
} 

// user-level program 
#include<linux/unistd.h> 
#include<sys/syscall.h> 
#define __NR_mysyscall 223 
int main() 
{ 
    syscall(__NR_mysyscall); 
    return 0; 
} 

있습니까 : 여기

내 간단한 syscall 및 사용자 수준의 프로그램입니다?

이제 코드를 수정하여 pfcount_at_begpfcount_at_endstatic으로 만들었습니다. 그러나 결과는 변하지 않았고, 즉 pfcount_at_end의 값은 pfcount_at_beg의 값보다 큽니다. 아마도 원자 단위 증가 연산에 의해 발생할 수 있습니다. 읽기 - 쓰기 잠금을 사용하면 더 좋을까요?

+0

내가 생각하기에 가장 가능성있는 것은 당신이'syscall' 또는 사용자 레벨 프로그램에 버그가 있고 거기에 변수가 섞여 있다는 것입니다. 고려해야 할 또 하나의 사항은 두 변수를 원자 적으로 액세스하는지 여부와 그렇지 않은 경우 중간에 페이지 오류가 발생할 가능성이 있는지 여부입니다. – Graeme

+0

@Graeme 질문에'syscall' 프로그램과 사용자 레벨 프로그램을 추가했습니다. 그것들은'syscall'이 어떻게 구현되는지를 경험하기위한 연습 이었기 때문에 상대적으로 간단합니다. –

+0

이것이 실제 시스템 코드입니까? 인쇄물에 실제 값이 누락되었습니다. –

답변

0

++ 연산자가 원자 단위가 아니므로 카운터에 동시 액세스가 발생하고 잘못된 값이있을 수 있습니다. 증분을 중요한 섹션으로 보호하거나 <asm/atomic.h>에 정의 된 atomic_t 유형 및 관련 atomic_set()atomic_add() 기능 (더 많은 기능)을 사용해야합니다.

문제가 직접적으로 연결되어 있지 않지만 특정 syscall을 사용하면 잔인합니다 (하지만 운동 일 수 있음). 더 가벼운 솔루션은 /proc 항목을 사용할 수도 있습니다 (흥미로운 연습 문제).