| #include <errno.h> |
| #include <fcntl.h> |
| #include <stdbool.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/mman.h> |
| #include <sys/time.h> |
| |
| #include "pagingtest.h" |
| |
| int pageinout_test(int test_runs, bool cache, unsigned long long file_size) { |
| int fd; |
| char tmpname[] = "pageinoutXXXXXX"; |
| unsigned char *vec; |
| int i; |
| unsigned long long j; |
| volatile char *buf; |
| int ret = -1; |
| int rc; |
| struct timeval begin_time, end_time, elapsed_time, total_time_in, total_time_out; |
| long pagesize = sysconf(_SC_PAGE_SIZE); |
| |
| timerclear(&total_time_in); |
| timerclear(&total_time_out); |
| |
| fd = create_tmp_file(tmpname, file_size); |
| if (fd < 0) { |
| return -1; |
| } |
| |
| vec = alloc_mincore_vec(file_size); |
| if (vec == NULL) { |
| goto err_alloc; |
| } |
| |
| buf = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0); |
| if (buf == ((void *)-1)) { |
| fprintf(stderr, "Failed to mmap file: %s\n", strerror(errno)); |
| goto err_mmap; |
| } |
| |
| if (!check_caching((void *)buf, vec, file_size, false)) { |
| goto err; |
| } |
| |
| if (!cache) { |
| //madvise and fadvise as random to prevent prefetching |
| rc = madvise((void *)buf, file_size, MADV_RANDOM) || |
| posix_fadvise(fd, 0, file_size, POSIX_FADV_RANDOM); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| for (i = 0; i < test_runs; i++) { |
| gettimeofday(&begin_time, NULL); |
| //read every page into the page cache |
| for (j = 0; j < file_size; j += pagesize) { |
| buf[j]; |
| } |
| gettimeofday(&end_time, NULL); |
| |
| timersub(&end_time, &begin_time, &elapsed_time); |
| timeradd(&total_time_in, &elapsed_time, &total_time_in); |
| |
| if (!check_caching((void *)buf, vec, file_size, true)) { |
| goto err; |
| } |
| |
| gettimeofday(&begin_time, NULL); |
| rc = madvise((void *)buf, file_size, MADV_DONTNEED) || |
| posix_fadvise(fd, 0, file_size, POSIX_FADV_DONTNEED); |
| gettimeofday(&end_time, NULL); |
| if (rc) { |
| fprintf(stderr, "posix_fadvise/madvise DONTNEED failed\n"); |
| goto err; |
| } |
| |
| timersub(&end_time, &begin_time, &elapsed_time); |
| timeradd(&total_time_out, &elapsed_time, &total_time_out); |
| |
| if (!check_caching((void *)buf, vec, file_size, false)) { |
| goto err; |
| } |
| } |
| |
| printf("%scached page-in: %llu MB/s\n", cache ? "" : "un", |
| (file_size * test_runs * USEC_PER_SEC) / |
| (1024 * 1024 * (total_time_in.tv_sec * USEC_PER_SEC + total_time_in.tv_usec))); |
| printf("%scached page-out (clean): %llu MB/s\n", cache ? "" : "un", |
| (file_size * test_runs * USEC_PER_SEC) / |
| (1024 * 1024 * (total_time_out.tv_sec * USEC_PER_SEC + total_time_out.tv_usec))); |
| |
| ret = 0; |
| |
| err: |
| munmap((void *)buf, file_size); |
| err_mmap: |
| free(vec); |
| err_alloc: |
| close(fd); |
| return ret; |
| } |