/* alloctest.c - create files which demonstrate internal fragmentation on * modern Linux kernels and filesystems. Tested on 2.6.23, .28, .29 * with ext2, ext3; filefrag(8) reports 10,000 to 20,000 frags for * a 1GB file. Less fragmentation is observed on RHEL4 2.6.9-55.ELsmp, * with filefrag reporting up to a dozen extents. Less fragmentation is * also observed on ext4, with around 30-40 extents reported. * * Written by Andrew Isaacson for VMware. * Copyright 2009 VMware, Inc. All rights reserved. * Parts of this program are derived from work * Copyright 2002-2009 Andrew Isaacson * This program is free software, licensed under the GNU GPL v2. */ #include #include #include #include #include #include #include #include #include #include void die(char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); exit(1); } double rtc(void) { struct timeval t; static struct timeval t0; if(t0.tv_sec == 0) { gettimeofday(&t0, 0); return 0; } gettimeofday(&t, 0); return t.tv_sec - t0.tv_sec + 1e-6 * (t.tv_usec - t0.tv_usec); } long long rnd(long long x, long long period) { return ((x + 23) * 1000000007 % period); } int o_touch = 0, o_write = 0, o_touchdown = 0; void usage(char *prog) { fprintf(stderr, "usage: %s [-t] file len\n", prog); fprintf(stderr, " -t: touch pages (read) sequentially before writing\n"); exit(1); } int main(int argc, char **argv) { int i, fd, c; int pgsz = getpagesize(), npg; char *map; size_t sz; double t01, t0, t1, t2, t3, t4, t5; while((c = getopt(argc, argv, "dtw")) != EOF) { switch(c) { case 'd': o_touchdown++; break; case 't': o_touch++; break; case 'w': o_write++; break; default: usage(argv[0]); } } if(argc < optind+2) usage(argv[0]); if((fd = open(argv[optind], O_RDWR|O_CREAT, 0666)) == -1) die("%s: %s\n", argv[optind]); sz = strtoll(argv[optind+1], 0, 0); npg = sz / pgsz; if(ftruncate(fd, sz) == -1) die("ftruncate(%d, %lld): %s\n", fd, (long long)sz); if((map = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) die("mmap: %s\n", strerror(errno)); t01 = rtc(); if(o_touch || o_write || o_touchdown) { char t = 0; for(i = 0; i < npg; i++) { int idx = o_touchdown ? (npg - i - 1) : i; if(o_write) map[pgsz * idx] ^= t; else t ^= map[pgsz * idx]; } map[0] = t; } t0 = rtc(); for(i = 0; i < npg; i++) { int pgno = (rnd(i, npg) % npg); int *p = (void *)(map + (long long)pgsz * pgno); if(*p) printf("i=%d pgno=%d npg=%d p=%p hit %d\n", i, pgno, npg, p, *p); *p = i; } t1 = rtc(); if(o_touch) { printf("streaming %s %d pages in %f seconds (%.2f usec/page, %.2f MB/s)\n", o_write ? "dirtied" : "touched", npg, t0-t01, 1e6 * (t0-t01) / npg, sz / (1024.*1024) / (t0-t01)); } printf("touched %d pages in %f seconds (%.2f usec/page, %.2f MB/s)\n", npg, t1-t0, 1e6 * (t1-t0) / npg, sz / (1024.*1024) / (t1-t0)); t2 = rtc(); if(msync(map, sz, MS_SYNC) == -1) die("msync: %s\n", strerror(errno)); t3 = rtc(); if(munmap(map, sz) == -1) die("munmap: %s\n", strerror(errno)); t4 = rtc(); close(fd); t5 = rtc(); printf("msync took %f seconds\n", t3 - t2); printf("munmap took %f seconds\n", t4 - t3); printf("close took %f seconds\n", t5 - t4); printf("total throughput %f MB/sec\n", sz / (1024.*1024) / (t5 - t01)); return 0; }