I got some huge files I need to parse, and people have been recommending mmap because this should avoid having to allocate the entire file in-memory.
But looking at 'top' it does look like I'm opening the entire file into the memory, so I think I must be doing something wrong. 'top shows >2.1 gig'
This is a code snippet that shows what I'm doing.
Thanks
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <fcntl.h>
#include <sysexits.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <cstring>
int main (int argc, char *argv[] ) {
struct stat sb;
char *p,*q;
//open filedescriptor
int fd = open (argv[1], O_RDONLY);
//initialize a stat for getting the filesize
if (fstat (fd, &sb) == -1) {
perror ("fstat");
return 1;
}
//do the actual mmap, and keep pointer to the first element
p =(char *) mmap (0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
q=p;
//something went wrong
if (p == MAP_FAILED) {
perror ("mmap");
return 1;
}
//lets just count the number of lines
size_t numlines=0;
while(*p++!='\0')
if(*p=='\n')
numlines++;
fprintf(stderr,"numlines:%lu\n",numlines);
//unmap it
if (munmap (q, sb.st_size) == -1) {
perror ("munmap");
return 1;
}
if (close (fd) == -1) {
perror ("close");
return 1;
}
return 0;
}
No, what you're doing is mapping the file into memory. This is different to actually reading the file into memory.
Were you to read it in, you would have to transfer the entire contents into memory. By mapping it, you let the operating system handle it. If you attempt to read or write to a location in that memory area, the OS will load the relevant section for you first. It will not load the entire file unless the entire file is needed.
That is where you get your performance gain. If you map the entire file but only change one byte then unmap it, you'll find that there's not much disk I/O at all.
Of course, if you touch every byte in the file, then yes, it will all be loaded at some point but not necessarily in physical RAM all at once. But that's the case even if you load the entire file up front. The OS will swap out parts of your data if there's not enough physical memory to contain it all, along with that of the other processes in the system.
The main advantages of memory mapping are:
Keep in mind that there is most likely a disconnect between your address space usage and your physical memory usage. You can allocate an address space of 4G (ideally, though there may be OS, BIOS or hardware limitations) in a 32-bit machine with only 1G of RAM. The OS handles the paging to and from disk.
And to answer your further request for clarification:
Just to clarify. So If I need the entire file, mmap will actually load the entire file?
Yes, but it may not be in physical memory all at once. The OS will swap out bits back to the filesystem in order to bring in new bits.
But it will also do that if you've read the entire file in manually. The difference between those two situations is as follows.
With the file read into memory manually, the OS will swap parts of your address space (may include the data or may not) out to the swap file. And you will need to manually rewrite the file when your finished with it.
With memory mapping, you have effectively told it to use the original file as an extra swap area for that file/memory only. And, when data is written to that swap area, it affects the actual file immediately. So no having to manually rewrite anything when you're done and no affecting the normal swap (usually).
It really is just a window to the file:
You can also use fadvise(2) (and madvise(2), see also posix_fadvise & posix_madvise ) to mark mmaped file (or its parts) as read-once.
#include <sys/mman.h>
int madvise(void *start, size_t length, int advice);
The advice is indicated in the advice parameter which can be
MADV_SEQUENTIAL
Expect page references in sequential order. (Hence, pages in the given range can be aggressively read ahead, and may be freed soon after they are accessed.)
Portability: posix_madvise and posix_fadvise is part of ADVANCED REALTIME option of IEEE Std 1003.1, 2004. And constants will be POSIX_MADV_SEQUENTIAL and POSIX_FADV_SEQUENTIAL.
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