// test the write throughput of a sliding mmap window vs simple FILE* #include #include #include #include #include #include #include #include #include #include #include #include #include int total_bytes = 0; int last_bytes = 0; struct timeval last_time; void timeout(int) { struct timeval now; gettimeofday(&now, 0); double time_diff = (now.tv_sec - last_time.tv_sec) + ((now.tv_usec - last_time.tv_usec) / 1000000.); last_time = now; int new_bytes = total_bytes; int diff = new_bytes - last_bytes; printf("wrote %dk %dM bytes in %f seconds -> %fM/sec\n", diff / 1024, diff / (1024 * 1024), time_diff, (diff / (time_diff * 1000000.))); last_bytes = new_bytes; } // tests O_DIRECT + pwrite = fail // O_DIRECT + truncate = happy // truncate = happy // pwrite = happy // O_DIRECT + truncate = happy // truncate = happy // O_DIRECT + pwrite = fail void do_mapwrite(int fd) { // lets write as fast as we can.... int const window_size = 2 * 1024 * 1024; // 2 * 1024 * 1024; // 16k int const window_pages = window_size / 4096; int file_page_offset = 0; long long file_size = window_size; // fast-forward... by 2046 windows file_size += 2046u * (2 * 1024 * 1024); file_page_offset += 2046; //ftruncate64(fd, file_size); printf("pwrite to %llx %llu\n", file_size, file_size); pwrite64(fd, "", 1, file_size); char* mapping_start = static_cast(mmap64(0, window_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, file_size - window_size)); // scribble into buffer and walk the window for (;;) { memset(mapping_start, 0, window_size); // grow file file_size += window_size; //ftruncate64(fd, file_size); pwrite64(fd, "", 1, file_size); file_page_offset += window_pages; //munmap(mapping_start, window_size); //mapping_start = static_cast(mmap64(mapping_start, window_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, file_size - window_size)); while (remap_file_pages(mapping_start, window_size, 0, file_page_offset, MAP_SHARED /*| MAP_NONBLOCK*/) <0) perror("remap_file_pages"); total_bytes += window_size; } } void do_filewrite(int fd) { FILE* ptr = fdopen(fd, "w+"); int line_len = 80; char* buf = (char*)malloc(line_len); memset(buf, 0, line_len); for (;;) { fwrite(buf, line_len, 1, ptr); total_bytes += line_len; } } void do_syswrite(int fd) { int line_len = 64 * 1024; char* buf = (char*)malloc(line_len); memset(buf, 0, line_len); for (;;) { write(fd, buf, line_len); total_bytes += line_len; } } int main(int argc, char* argv[]) { if (argc != 3) { printf("usage: %s -[mfw] \n", argv[0]); return 0; } if ((argv[1][0] != '-') || ((argv[1][1] != 'm') && (argv[1][1] != 'w') && (argv[1][1] != 'f'))) { printf("usage: %s -[mfw] \n", argv[0]); return 0; } int fd = open(argv[2], O_RDWR | O_CREAT | O_LARGEFILE | O_DIRECT, 0644); if (fd < 0) { perror("open"); return 0; } // start the clock... signal(SIGALRM, timeout); { struct itimerval itv; itv.it_interval.tv_sec = 1; itv.it_interval.tv_usec = 0; itv.it_value = itv.it_interval; setitimer(ITIMER_REAL, &itv, 0); } switch (argv[1][1]) { case 'm': do_mapwrite(fd); break; case 'f': do_filewrite(fd); break; case 'w': do_syswrite(fd); break; } return 0; }