2016-02-22 42 views
7

Ho un programma C che calcola la pagina di tempo di servizio guasto C. Per questo programma ho 2 file di grandi dimensioni (inferiore a 3 GB ciascuno - quasi la dimensione della RAM)mmap: Impossibile allocare memoria

#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <sys/mman.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include "rdstc.h" 
#include "config.h" 

#define KB 1024 
#define MB 1024 * KB 
#define GB 1024 * MB 
#define SIZE_OF_MEMORY 1 * GB // Main memory size 

#define handle_error(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0) 

int main(int argc, char *argv[]){ 

    int fd1, fd2; 
    char *addr1, *addr2, c; 
    int i, j; 
    long long unsigned int s_t, e_t, t=0; 

    if (argc != 3){ 
     printf("usage: a.out <file1> <file2> \n"); 
     exit(EXIT_FAILURE); 
    } 

    if ((fd1 = open(argv[1], O_RDONLY)) == -1){ 
     handle_error("open"); 
    } 

    if ((fd2 = open(argv[2], O_RDONLY)) == -1){ 
     handle_error("open"); 
    } 

    posix_fadvise(fd1, 0, 0, POSIX_FADV_RANDOM); 
    posix_fadvise(fd2, 0, 0, POSIX_FADV_RANDOM); 

    addr1 = (char *) mmap(0, SIZE_OF_MEMORY, PROT_READ, MAP_PRIVATE | MAP_POPULATE, fd1, 0); 
    if (addr1 == MAP_FAILED){ 
     handle_error("mmap"); 
    } 
    addr2 = (char *) mmap(0, SIZE_OF_MEMORY, PROT_READ, MAP_PRIVATE | MAP_POPULATE, fd2, 0); 
    if (addr2 == MAP_FAILED){ 
     handle_error("mmap"); 
    } 

    madvise(addr1, 0, MADV_RANDOM); 
    madvise(addr2, 0, MADV_RANDOM); 

    j = 32;  // default read ahead size if 256 blocks (assuming each block is of 512 bytes) 
    for(i = 0; i < ITERATIONS; i++){ 
     s_t = rdtsc(); 
      c = addr1[i + j*4*KB];  // read at multiple of page size, so every read causes a page fault 
      j *= 2; 
     e_t = rdtsc(); 
     t += (e_t - s_t); 
    } 
    printf("Time required to service a page faut is %f \n", (t/ITERATIONS)/CPU_FREQ); 

    munmap(addr1, SIZE_OF_MEMORY); 
    munmap(addr2, SIZE_OF_MEMORY); 

    return 0; 
} 

io ottenere i seguenti avvisi del compilatore:

[email protected]:~/projects/mem$ gcc mem1_4.c -lm 
mem1_4.c: In function ‘main’: 
mem1_4.c:11:17: warning: integer overflow in expression [-Woverflow] 
#define MB 1024 * KB 
       ^
mem1_4.c:12:19: note: in expansion of macro ‘MB’ 
#define GB 1024 * MB 
       ^
mem1_4.c:13:28: note: in expansion of macro ‘GB’ 
#define SIZE_OF_MEMORY 2 * GB // Main memory size 
          ^
mem1_4.c:40:30: note: in expansion of macro ‘SIZE_OF_MEMORY’ 
    addr1 = (char *) mmap(0, SIZE_OF_MEMORY, PROT_READ, MAP_PRIVATE | MAP_POPULATE, fd1, 0); 
          ^
mem1_4.c:11:17: warning: integer overflow in expression [-Woverflow] 
#define MB 1024 * KB 
       ^
mem1_4.c:12:19: note: in expansion of macro ‘MB’ 
#define GB 1024 * MB 
       ^
mem1_4.c:13:28: note: in expansion of macro ‘GB’ 
#define SIZE_OF_MEMORY 2 * GB // Main memory size 
          ^
mem1_4.c:44:30: note: in expansion of macro ‘SIZE_OF_MEMORY’ 
    addr2 = (char *) mmap(0, SIZE_OF_MEMORY, PROT_READ, MAP_PRIVATE | MAP_POPULATE, fd2, 0); 
          ^
mem1_4.c:11:17: warning: integer overflow in expression [-Woverflow] 
#define MB 1024 * KB 
       ^
mem1_4.c:12:19: note: in expansion of macro ‘MB’ 
#define GB 1024 * MB 
       ^
mem1_4.c:13:28: note: in expansion of macro ‘GB’ 
#define SIZE_OF_MEMORY 2 * GB // Main memory size 
          ^
mem1_4.c:62:19: note: in expansion of macro ‘SIZE_OF_MEMORY’ 
    munmap(addr1, SIZE_OF_MEMORY); 
       ^
mem1_4.c:11:17: warning: integer overflow in expression [-Woverflow] 
#define MB 1024 * KB 
       ^
mem1_4.c:12:19: note: in expansion of macro ‘MB’ 
#define GB 1024 * MB 
       ^
mem1_4.c:13:28: note: in expansion of macro ‘GB’ 
#define SIZE_OF_MEMORY 2 * GB // Main memory size 
          ^
mem1_4.c:63:19: note: in expansion of macro ‘SIZE_OF_MEMORY’ 
    munmap(addr2, SIZE_OF_MEMORY); 
       ^

Quando eseguo con il comando ho l'errore

./a.out file1.txt file2.txt 
mmap: Cannot allocate memory 

Cosa fa il codice? Mappiamo entrambi i file utilizzando bandiere

MAP_PRIVATE (in modo che nessun altro processo deve accedere a questo file) e MAP_POPULATE (in modo che

quando chiamiamo mmap() file completo è mappato in memoria) con la protezione PROT_READ bandiera.

Prima mappiamo il file1 e poiché utilizziamo MAP_POPULATE la RAM completa viene riempita dai dati corrispondenti a questo file. Dopo di ciò mappiamo file2 usando gli stessi flag e quindi ora abbiamo file2 completamente mappato nella RAM. Pertanto l'accesso ai dati di file1 causerà errori di pagina poiché il file2 occupa tutta la RAM disponibile. Chiamiamo anche il syscall di madvise() con il set di flag MADV_RANDOM, per consigliare al kernel di non leggere le pagine in lettura, per entrambi i file. Così ora, una volta che questa configurazione iniziale viene eseguita con file2 che occupa tutta la RAM disponibile, accediamo ai dati corrispondenti a file1 in modo casuale (per evitare qualsiasi effetto dell'ottimizzazione della lettura in lettura eseguita dal kernel ed evitare anche la lettura dalla cache L3) Poiché, la RAM è piena di dati corrispondenti a file2, ogni accesso ai dati corrispondenti al file causerà un errore di pagina. Eseguiamo 10 letture casuali attraverso la regione mappata in loop e misuriamo il tempo medio richiesto per questa operazione.

+0

Le avvertenze del compilatore dovrebbe dare un suggerimento - 2 * 1024 * 1024 * 1024 overflow ad un numero negativo. – immibis

risposta

6

dai un'occhiata all'avvertimento del compilatore. Hai un overflow intero qui: #define SIZE_OF_MEMORY 2 * GB. Quello equivale a 2^31 == 0b1000 ... 0 che per l'int firmato è uguale a INT_MIN. Ecco perché mmap fallisce.

Si dovrebbe usare unsigned literals nei tuoi definisce:

#define KB (1024u) 
#define MB (1024u * KB) 
#define GB (1024u * MB) 
#define SIZE_OF_MEMORY (2u * GB) 
+2

... e aggiungi parentesi! – wildplasser