Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 16 Jul 2015 18:42:26 +0300
From:      Dmitry Sivachenko <trtrmitya@gmail.com>
To:        hackers@freebsd.org
Subject:   Strange memory management with mmap()
Message-ID:  <FDB6E0F9-A3FF-4194-83C1-A3121CBAE407@gmail.com>

next in thread | raw e-mail | index | archive | help

--Apple-Mail=_F134DC1F-8226-4CB0-B2E6-3B8F9A79A1BA
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
	charset=us-ascii

Hello!

I am using FreeBSD-10-stable and writing a program that uses large data =
file via mmap() in read only mode.
To be specific, I have 256GB RAM machine and typical size of data file =
is ~160GB (more than 1/2 of RAM and less that the whole RAM).
There is no other programs running during the test.

Consider the following use case: I have two files on disk.  I mmap() the =
first one and prefetch data to RAM (touch every page of the file).
After that I expect all data to be cached in RAM and subsequent access =
will be fast.

Next I do munmap() on the first file, mmap() the second one and do the =
same test: prefetch data and expect it to be cached in RAM (and some of =
the pages belonging to the first file to be purged out, because =
size_of(file1)+size_of(file2) > size_of(RAM).

Please find my test program attached.

I run the program with 2 files provided via command line (both about =
160GB).
What I observe in real is:
-- before I run the program all RAM is in FREE state as reported by =
top(1).
-- after first prefetch() of the first file, all it's data goes to =
"Cache" state, RES column of the process remains the same (small)
-- second prefetch() works fast as expected, memory goes from Cache to =
Active state, RES column of the process grows up to match file size =
(SIZE=3D=3DRES now)
-- now first prefetch() for second file starts: the remaining Free =
memory goes to Cache state, Active size still equals to first file size.
-- second prefetch() for second file works as slow as first one, like if =
nothing was cached in memory during the first prefetch() run, RES column =
does not change.


Here is the output:
% /tmp/a.out file1.dat file2.dat
file1.dat... First prefault time: 1235.747351 seconds
Second prefault time: 74.893323 seconds
Ok.
file2.dat... First prefault time: 1316.405527 seconds
Second prefault time: 1311.491842 seconds
Ok.

I treat this like the bug somewhere in virtual memory management.  Am I =
right or my expectations about how that test program should work are =
false?

Thanks in advance.



--Apple-Mail=_F134DC1F-8226-4CB0-B2E6-3B8F9A79A1BA
Content-Disposition: attachment;
	filename=mmap_test.c
Content-Type: application/octet-stream;
	name="mmap_test.c"
Content-Transfer-Encoding: 7bit

#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>


static void prefault(const char *buf, size_t s) {
    volatile const char *p;
    size_t page_size;
    
    if (s == 0)
        return;
    page_size = sysconf(_SC_PAGESIZE);
    for (p = buf; p < buf + s; p += page_size)
        *p;

    *(volatile const char *)(buf + s - 1);
}


int main(int argc, char* argv[]) {
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <file> ...\n", argv[0]);
        exit(0);
    }
    int i, fd;
    struct stat st;
    void *p;
    struct timeval tv1, tv2;
    for (i=1; i < argc; i++) {
        printf("%s... ", argv[i]);
        if ((fd = open(argv[i], O_RDONLY)) < 0)
            err(1, "open");
        if (fstat(fd, &st) != 0)
            err(1, "fstat");
        if (st.st_size > 0) {
            if ((p = mmap(NULL, st.st_size, PROT_READ, MAP_NOCORE, fd, 0)) == MAP_FAILED)
                err(1, "mmap");
            gettimeofday(&tv1, NULL);
            prefault(p, st.st_size);
            gettimeofday(&tv2, NULL);
            printf("First prefault time: %f seconds\n",
                   (double) (tv2.tv_usec - tv1.tv_usec) / 1000000 +
                   (double) (tv2.tv_sec - tv1.tv_sec));
            gettimeofday(&tv1, NULL);
            prefault(p, st.st_size);
            gettimeofday(&tv2, NULL);
            printf("Second prefault time: %f seconds\n",
                   (double) (tv2.tv_usec - tv1.tv_usec) / 1000000 +
                   (double) (tv2.tv_sec - tv1.tv_sec));
            if (munmap(p, st.st_size) != 0)
                err(1, "munmap");
        }
        close(fd);
        printf("Ok.\n");
    }
    return 0;
}

--Apple-Mail=_F134DC1F-8226-4CB0-B2E6-3B8F9A79A1BA--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?FDB6E0F9-A3FF-4194-83C1-A3121CBAE407>