Linux mmap Based File Write
Breif on mmap:
mmap() creates a new mapping in the virtual address space of the calling process. The starting address for the new mapping is specified in addr. The length argument specifies the length ofthe mapping.
You can find more info about mmap [1]
There are lots of examples on web which do a entire file copy and its quite easy.
One of my colleague wanted a faster file writes, he tried fwrite/write but it was too slow for him and I suggested to use mmaping the file and writing the contents to the file. Unfortunately google didn’t help him out, so just pasting the code so that someone else might get benefit from it.
OK here goes the code:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <errno.h>
struct buffer {
#define MAX_BUFFER_SIZE 1000
char ptr[MAX_BUFFER_SIZE]; /* array */
int size; /* size of data in buffer */
};
void buffer_generator(struct buffer *buf, int size)
{
int i;
buf->size = 0;
/* just make sure we dont exceed max size */
if (size > MAX_BUFFER_SIZE)
return;
buf->size = size;
for (i = 0; i < size; i++)
buf->ptr[i] = 'A' + rand() % 26;
}
int main(int argc, char *argv[]) {
unsigned int loop = 1000, i; /* defaulting */
void *target;
clock_t begin, end;
off_t map_skip = 0;
long pagemask = 0;
int outfd;
off_t offset;
int ret;
if(argc != 2) {
printf("Usage ./mmap filename.txt\n");
return -1;
}
outfd = open(argv[1], O_RDWR | O_CREAT | O_APPEND, 0666);
if (outfd <= 0) {
printf("Error: opening file: %s\n", argv[2]);
return -1;
}
pagemask = ~(sysconf(_SC_PAGESIZE) - 1);
for (i = 0; i < loop; i++) {
struct buffer buf;
/* get a random buffer of random size but within
* out max range limit
*/
buffer_generator(&buf, rand() % (MAX_BUFFER_SIZE - 1) + 1);
if (!buf.size)
continue;
/* get the current file size of output file */
offset = lseek(outfd, 0, SEEK_END);
map_skip = offset - (offset & pagemask);
/* Increase file size */
ret = ftruncate(outfd, (off_t)offset + (off_t)buf.size);
if (ret) {
printf("Failed to increase file size\n");
goto fail;
}
/* mmap the file of required offset
* and align it to pagesize
*/
if((target = mmap(0, buf.size + map_skip, PROT_WRITE, MAP_SHARED, outfd, offset - map_skip)) == (void *) -1) {
printf("MMAP Failed: %d\n", errno);
goto fail;
}
/* copy buffer */
memcpy(target + map_skip, buf.ptr, buf.size);
/* umap the region */
munmap(target, buf.size + map_skip);
}
fail:
close(outfd);
return 0;
}
The code is quite explanatory, a random buffer is generated with random characters in it of random size and this buffer is written to the file.
Off course you can also increase the priority of the process to achieve more faster rates!
[1] http://goo.gl/zMLHuJ
mmap() creates a new mapping in the virtual address space of the calling process. The starting address for the new mapping is specified in addr. The length argument specifies the length ofthe mapping.
You can find more info about mmap [1]
There are lots of examples on web which do a entire file copy and its quite easy.
One of my colleague wanted a faster file writes, he tried fwrite/write but it was too slow for him and I suggested to use mmaping the file and writing the contents to the file. Unfortunately google didn’t help him out, so just pasting the code so that someone else might get benefit from it.
OK here goes the code:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <errno.h>
struct buffer {
#define MAX_BUFFER_SIZE 1000
char ptr[MAX_BUFFER_SIZE]; /* array */
int size; /* size of data in buffer */
};
void buffer_generator(struct buffer *buf, int size)
{
int i;
buf->size = 0;
/* just make sure we dont exceed max size */
if (size > MAX_BUFFER_SIZE)
return;
buf->size = size;
for (i = 0; i < size; i++)
buf->ptr[i] = 'A' + rand() % 26;
}
int main(int argc, char *argv[]) {
unsigned int loop = 1000, i; /* defaulting */
void *target;
clock_t begin, end;
off_t map_skip = 0;
long pagemask = 0;
int outfd;
off_t offset;
int ret;
if(argc != 2) {
printf("Usage ./mmap filename.txt\n");
return -1;
}
outfd = open(argv[1], O_RDWR | O_CREAT | O_APPEND, 0666);
if (outfd <= 0) {
printf("Error: opening file: %s\n", argv[2]);
return -1;
}
pagemask = ~(sysconf(_SC_PAGESIZE) - 1);
for (i = 0; i < loop; i++) {
struct buffer buf;
/* get a random buffer of random size but within
* out max range limit
*/
buffer_generator(&buf, rand() % (MAX_BUFFER_SIZE - 1) + 1);
if (!buf.size)
continue;
/* get the current file size of output file */
offset = lseek(outfd, 0, SEEK_END);
map_skip = offset - (offset & pagemask);
/* Increase file size */
ret = ftruncate(outfd, (off_t)offset + (off_t)buf.size);
if (ret) {
printf("Failed to increase file size\n");
goto fail;
}
/* mmap the file of required offset
* and align it to pagesize
*/
if((target = mmap(0, buf.size + map_skip, PROT_WRITE, MAP_SHARED, outfd, offset - map_skip)) == (void *) -1) {
printf("MMAP Failed: %d\n", errno);
goto fail;
}
/* copy buffer */
memcpy(target + map_skip, buf.ptr, buf.size);
/* umap the region */
munmap(target, buf.size + map_skip);
}
fail:
close(outfd);
return 0;
}
The code is quite explanatory, a random buffer is generated with random characters in it of random size and this buffer is written to the file.
Off course you can also increase the priority of the process to achieve more faster rates!
[1] http://goo.gl/zMLHuJ
Comments
Post a Comment