2014-04-26 4 views
3

read()을 사용하여 다른 크기의 파일 (1KB - 1GB)을 읽습니다. 그러나 언제든지 page-faults을 사용하여 perf-stat을 사용할 때마다 항상 거의 동일한 값을 갖습니다.read() 시스템 호출 페이지 오류는 파일 크기에 의존하지 않습니다.

내 기계 :(페도라 18 가상 머신에, RAM - 1GB의 디스크 공간 - 20기가바이트)

uname -a 
Linux localhost.localdomain 3.10.13-101.fc18.x86_64 #1 SMP Fri Sep 27 20:22:12 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux 

mount | grep "^/dev" 
/dev/mapper/fedora-root on/type ext4 (rw,relatime,seclabel,data=ordered) 
/dev/sda1 on /boot type ext4 (rw,relatime,seclabel,data=ordered) 

내 코드 :

10 #define BLOCK_SIZE 1024 
. . . 
19   char text[BLOCK_SIZE]; 
21   int total_bytes_read=0; 
. . . 

81   while((bytes_read=read(d_ifp,text,BLOCK_SIZE))>0) 
82   { 
83     write(d_ofp, text, bytes_read); // writing to /dev/null 
84     total_bytes_read+=bytes_read; 
85     sum+=(int)text[0]; // doing this just to make sure there's 
              // no lazy page loading by read() 
              // I don't care what is in `text[0]` 
86   } 
87   printf("total bytes read=%d\n", total_bytes_read); 
88   if(sum>0) 
89     printf("\n"); 

를 성능 -stat 출력 :(파일 크기, 파일 읽기 시간 및 페이지 오류 수 표시)

[read]: f_size: 1K B, Time: 0.000313 seconds, Page-faults: 150, Total bytes read: 980 
[read]: f_size: 10K B, Time: 0.000434 seconds, Page-faults: 151, Total bytes read: 11172 
[read]: f_size: 100K B, Time: 0.000442 seconds, Page-faults: 150, Total bytes read: 103992 
[read]: f_size: 1M B, Time: 0.00191 seconds, Page-faults: 151, Total bytes read: 1040256 
[read]: f_size: 10M B, Time: 0.050214 seconds, Page-faults: 151, Total bytes read: 10402840 
[read]: f_size: 100M B, Time: 0.2382 seconds, Page-faults: 150, Total bytes read: 104028372 
[read]: f_size: 1G B, Time: 5.7085 seconds, Page-faults: 148, Total bytes read: 1144312092 

질문 :
1.하는 방법 1킬로바이트 & 1기가바이트의 크기의 파일 read()의 페이지 폴트가 동일 할 수 있습니까? 데이터를 읽으므로 (코드 라인 # 84), 데이터가 인 것을 확인하고 실제로는을 읽습니다.
2. 데이터가 이미 메인 메모리에 존재하기 때문에 많은 페이지 폴트가 발생하지 않는다고 생각할 수있는 유일한 이유입니다. 이 경우 코드를 실행하면 실제로 페이지 오류가 표시되도록 플러시 할 수 있습니까? 그렇지 않으면 나는 사실의 성능을 read()으로 측정 할 수 없습니다.

는 EDIT1 :
echo 3 > /proc/sys/vm/drop_caches
도움이되지 않습니다, 출력은 여전히 ​​동일하게 유지됩니다.

Edit2가 : mmap를 들어, perf-stat의 출력은 다음과 같습니다

[mmap]: f_size: 1K B, Time: 0.000103 seconds, Page-faults: 14 
[mmap]: f_size: 10K B, Time: 0.001143 seconds, Page-faults: 151 
[mmap]: f_size: 100K B, Time: 0.002367 seconds, Page-faults: 174 
[mmap]: f_size: 1M B, Time: 0.007634 seconds, Page-faults: 401 
[mmap]: f_size: 10M B, Time: 0.06812 seconds, Page-faults: 2,688 
[mmap]: f_size: 100M B, Time: 0.60386 seconds, Page-faults: 25,545 
[mmap]: f_size: 1G B, Time: 4.9869 seconds, Page-faults: 279,519 
+0

도움이 될지 확실하지 않습니다. 무료 페이지 캐시로 : 에코 1> 변수/proc/sys/vm /는 drop_caches하지 무료 dentries와 아이 노드로 : 에코 2>/proc/sys/vm/drop_caches가 무료 페이지 캐시, dentries와 아이 노드로 : echo 3>/proc/sys/vm/drop_caches – Sasi

+1

@wildplasser : 어떤 차이가 있습니까? 언급해야 할 것은, 나는 그 합계를 사용하지 않고, 나는 그것이 무엇을 계산하는지 상관하지 않는다. – brokenfoot

+2

이러한 페이지 오류는 코드를로드 한 결과 일 가능성이 있습니다 (즉, mmap (2) - 실행 파일 자체). –

답변

5

난 당신이 정확하게 페이지 부재 무엇인지 이해하지 못했다 생각합니다. pagefault, according to Wikipedia은 프로그램이 물리적 메모리에로드되지 않은 프로그램에 액세스하려고 시도 할 때 CPU가 자체적으로 생성하는 인터럽트의 일종 인 "트랩"(예외)입니다 (일반적으로 이미 페이지에 표시된 가상 메모리에 이미 등록되어 있음) "존재하지 않음"P: Present bit = 0).

Pagefault는 CPU가 사용자 프로그램의 실행을 중지하고 커널로 전환하도록하기 때문에 좋지 않습니다. 커널 모드의 페이지 오류는 자주 발생하지 않습니다. 커널이 페이지에 액세스하기 전에 페이지 존재 여부를 확인할 수 있기 때문입니다. 커널 함수가 새 페이지 (귀하의 경우, read 시스템 호출)에 무언가를 쓰고 싶다면, 페이지 할당자를 명시 적으로 호출하여 페이지를 할당합니다. 페이지 할당자를 액세스하려고 시도하거나 페이지 폴트로 폴트하는 것은 아닙니다. 명시 적 메모리 관리로 실행할 인터럽트가 적고 코드가 적습니다.

--- 읽을 경우 ---

귀하의 읽기는 fs/read_write.c에서 sys_read에 의해 처리됩니다.

472 SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) 
479     ret = vfs_read(f.file, buf, count, &pos); 
    vvv 
353 ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) 
368       ret = file->f_op->read(file, buf, count, pos); 
    vvv 

fs/ext4/file.c

626 const struct file_operations ext4_file_operations = { 
628   .read   = do_sync_read, 

... do_sync_read -> generic_file_aio_read -> do_generic_file_read 

mm/filemap.c

1100 static void do_generic_file_read(struct file *filp, loff_t *ppos, 
1119   for (;;) { 
1120     struct page *page; 
1127     page = find_get_page(mapping, index); 
1128     if (!page) { 
1134         goto no_cached_page; 
    // osgx - case when pagecache is empty ^^vv 
1287 no_cached_page: 
1288     /* 
1289     * Ok, it wasn't cached, so we need to create a new 
1290     * page.. 
1291     */ 
1292     page = page_cache_alloc_cold(mapping); 

include/linux/pagemap.h

233 static inline struct page *page_cache_alloc_cold(struct address_space *x) 
235   return __page_cache_alloc(mapping_gfp_mask(x)|__GFP_COLD); 
    vvv 
222 static inline struct page *__page_cache_alloc(gfp_t gfp) 
224   return alloc_pages(gfp, 0); 

그래서 다음은 호출 체인 (아마도 정확하지 않음)입니다 read() syscall이 직접 호출을 통해 페이지 할당 (alloc_pages)으로 끝나는 것을 추적 할 수 있습니다. 페이지를 할당 한 후 read() syscall은 HDD에서 새 페이지로 DMA 전송을 수행 한 다음 파일로 캐시되지 않은 경우를 고려하여 사용자에게 반환합니다. 데이터가 이미 페이지 캐시에있는 경우 read() (do_generic_file_read)은 추가 매핑을 생성하여 실제 HDD 읽기없이 페이지 캐시의 기존 페이지를 재사용합니다.

read()이 반환 된 후에는 모든 데이터가 메모리에 있으며이 메모리에 대한 읽기 액세스로 인해 pagefault가 생성되지 않습니다.

--- mmap를 케이스 ---

당신이 (이 페이지 캐시에 없었다) 테스트 파일의 비 존재하는 페이지 (text[offset]를) mmap() 파일의 ING하고 액세스 할 재 작성하는 경우

, 실제 페이지 오류가 발생합니다.

모든 pagefault 카운터 (perf stat/proc/$pid/stat)는 실제 페이지 오류 트랩이 CPU에 의해 생성 될 때만 업데이트됩니다. vma->vm_ops->fault(vma, &vmf); 끝나는>__do_fault ->handle_pte_fault - 여기

1224 dotraplinkage void __kprobes 
1225 do_page_fault(struct pt_regs *regs, unsigned long error_code) 
1230   __do_page_fault(regs, error_code); 
    vvv 
1001 /* 
1002 * This routine handles page faults. It determines the address, 
1003 * and the problem, and then passes it off to one of the appropriate 
1004 * routines. 
1005 */ 
1007 __do_page_fault(struct pt_regs *regs, unsigned long error_code) 
/// HERE is the perf stat pagefault event generator VVV 
1101   perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); 

를 작동 어딘가에 나중에 페이지 부재 핸들러가 handle_mm_fault 호출 페이지 오류 arch/x86/mm/fault.c의 86 핸들러이다.

fault이 가상 함수는 mmap에 등록되어 있으며 filemap_fault이라고 생각합니다. 이 함수는 실제 페이지 할당 (__alloc_page)을 수행하고 비어있는 페이지 캐시의 경우 디스크 읽기 (외부 I/O가 필요하기 때문에 "주요"페이지 오류로 계산 됨) 또는 페이지 캐시에서 페이지를 다시 매핑합니다 (데이터가 미리 이미 외부 캐시 I/O없이 완료되었고 일반적으로 더 빠르기 때문에 "마이너"페이지 오류로 계산됩니다.


추 신 : 가상 플랫폼에서 실험을 수행하면 변경 될 수 있습니다. 예를 들어 게스트 Fedora에서 디스크 캐시 (pagecache)를 echo 3 > /proc/sys/vm/drop_caches으로 정리 한 후에도 가상 하드 드라이브의 데이터는 호스트 OS에 의해 여전히 캐시 될 수 있습니다.

+0

나는 페이지 결함이 무엇인지 압니다. 내가 이해할 수없는 방법은 페이지가 이미 주 메모리 (이미 디스크에서로드)에 파일 크기가 1KB-1GB에 따라 달라질 수 있습니다 (내 질문에 업데이트 된대로 내 주 메모리 (VIrtual Machine)은 단지 1GB입니다.)는 모든 페이지가 1GB 파일에 대해 주 메모리에 동시에 존재할 수 없음을 의미합니다. – brokenfoot

+0

또는 다른 말로하면, 파일 크기가 1KB와 1GB 인 페이지 폴트 수가 어떻게 같을 수 있습니까? – brokenfoot

+2

읽기 syscalls는 페이지 오류가없는 FAULTing없이 디스크에서 데이터를로드합니다. Pagefault는 매핑되지 않은 페이지에 대한로드/저장 액세스 만 수행합니다. 그러나 인터럽트없이 액세스하기 전에 페이지를 명시 적으로 매핑하십시오. 따라서 이러한 페이지 생성은 페이지 폴트로 간주되지 않습니다 (계산되지 않음). – osgx