I have a C program that computes the page fault service time in C. For this program I have 2 large files (of less than 3GB each - almost the size of the RAM)
#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;
}
I get the following compiler warnings:
lmelvix@Melvix:~/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);
^
When I run it with the command I get the error
./a.out file1.txt file2.txt
mmap: Cannot allocate memory
What does the code do? We map both the files using flags
MAP_PRIVATE (so that no other process should access this file) and MAP_POPULATE (so that
when we call mmap() complete file is mapped in memory) along with PROT_READ protection flag.
First we map file1 and since we use MAP_POPULATE complete RAM is filled by data corresponding to this file. After this we map file2 using same flags and thus now we have file2 completely mapped in RAM. Thus accessing data of file1 will cause page faults since file2 occupies all the available RAM. We also call madvise() syscall with MADV_RANDOM flag set, to advise kernel not to do read ahead reading of pages, for both files. So now once this initial setup is done with file2 occupying all the available RAM, we access data corresponding to file1 randomly (to avoid any effect of read ahead reading optimization performed by kernel and also avoid reading from L3 cache) Since, RAM is filled with data corresponding to file2, every access to data corresponding to file will cause a page fault. We perform 10 random readings across the mapped region in loop and measure the mean time required for this operation.
take a look at the compiler warning you get. You've got an integer overflow here: #define SIZE_OF_MEMORY 2 * GB
. That equals 2^31
== 0b1000 ... 0
which for signed int equals INT_MIN. That's why mmap
fails.
You should use unsigned literals in your defines:
#define KB (1024u)
#define MB (1024u * KB)
#define GB (1024u * MB)
#define SIZE_OF_MEMORY (2u * GB)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With