mmap MAP_NOSYNC regression in 10.x
Pieter de Goeje
pieter at degoeje.nl
Fri Sep 5 00:38:16 UTC 2014
After upgrading my month old 10-stable installation today (to r271093) ,
I've noticed a that the kernel no longer honors the MAP_NOSYNC flag.
Attached is a demonstration program that highlights the issue (also
available here: http://pastebin.com/y0kvdn0r ).
The program creates and mmap()s a 200MiB file and repeatedly writes
zeros to it. The expected behavior is that under normal circumstances
(no memory pressure), the dirtied pages are not flushed to disk.
Observed is however that every ~30 seconds the syncer kicks in and
basically halts the program while it does its job. The program prints a
line everytime the throughput drops below 500MBps, well below memory
bandwidth.
mmap() is called like this:
void *p = mmap(NULL, len, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_NOSYNC | MAP_ALIGNED_SUPER, fd, 0);
Sample output:
write...
zeroing: 209.6 MB
...write: 5.839s
mmap...
...mmap: 0.000s
20.1s: memset #259: 34.7MBps - stalled
55.7s: memset #810: 34.7MBps - stalled
91.3s: memset #1359: 34.6MBps - stalled
100.0s: memset #1522: 3938.5MBps
overall bandwidth: 3190.6MBps
munmap...
...munmap: 5.796s
done
(this is a rather old system)
If necessary I'm willing to find out the exact commit that caused the
problem.
-
Pieter
-------------- next part --------------
#include <sys/mman.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#define CLEAREOL "\e[0K"
#define CLOCK_START(a) double _clk_##a = now(); printf("%s... \n", #a)
#define CLOCK_STOP(a) printf(" ...%s: %.3fs\n", #a, now() - _clk_##a)
static double now() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec + ts.tv_nsec * 1E-9;
}
int main() {
setvbuf(stdout, NULL, _IONBF, 0);
int fd = open("backing-file", O_RDWR | O_CREAT | O_TRUNC, 0666);
if(fd == -1)
err(1, "open");
size_t len = 200 * 1024 * 1024;
size_t blen = 128 * 1024;
CLOCK_START(write);
char *buf = calloc(1, blen);
for(size_t i = 0; i < len; i += blen) {
printf("\rzeroing: %.1f MB" CLEAREOL, i * 1E-6);
if(write(fd, buf, blen) != blen)
err(1, "write\n");
}
free(buf);
printf("\n");
CLOCK_STOP(write);
CLOCK_START(mmap);
void *p = mmap(NULL, len, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_NOSYNC | MAP_ALIGNED_SUPER, fd, 0);
if(p == MAP_FAILED)
err(1, "mmap");
CLOCK_STOP(mmap);
if(close(fd) == -1)
err(1, "close");
double start, stop, last;
stop = start = now();
int n = 0;
do {
memset(p, 0, len);
last = stop; stop = now();
double bw = 1E-6 * len / (stop - last);
printf("\r%.1fs: memset #%d: %.1fMBps" CLEAREOL, stop - start, ++n, bw);
if(bw < 500.0)
printf(" - stalled\n");
} while(stop - start < 100.0);
printf("\noverall bandwidth: %.1fMBps\n", n * (double)len / (stop - start) * 1E-6);
CLOCK_START(munmap);
if(munmap(p, len) == -1)
err(1, "munmap");
CLOCK_STOP(munmap);
printf("done\n");
return 0;
}
More information about the freebsd-hackers
mailing list