Created
September 29, 2023 10:42
-
-
Save saagarjha/1a82fddb67f5870525e104cb2f5454e9 to your computer and use it in GitHub Desktop.
Test whether mmap or read is faster on your computer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// As seen on: | |
// https://federated.saagarjha.com/notice/AaEMQpJBSbxhLyxYzg | |
// https://twitter.com/_saagarjha/status/1707423903969341949 | |
// Compiling: gcc mmap_vs_read.c -O3 -o mmap_vs_read | |
// Usage: ./mmap_vs_read <bigfile> <mmap|read> | |
#include <fcntl.h> | |
#include <stddef.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/fcntl.h> | |
#include <sys/mman.h> | |
#include <unistd.h> | |
unsigned char hash_buffer(unsigned char *buffer, size_t size) { | |
unsigned char hash = 0; | |
while (size--) { | |
hash ^= *buffer++; | |
} | |
return hash; | |
} | |
unsigned char test_read(int fd) { | |
unsigned char hash = 0; | |
size_t buffer_size = sysconf(_SC_PAGESIZE) * 16; | |
unsigned char *buffer = malloc(buffer_size); | |
ssize_t size = 0; | |
while (size = read(fd, buffer, buffer_size), size > 0) { | |
hash ^= hash_buffer(buffer, size); | |
} | |
return hash; | |
} | |
unsigned char test_mmap(int fd) { | |
off_t size = lseek(fd, 0, SEEK_END); | |
unsigned char *buffer = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); | |
return hash_buffer(buffer, size); | |
} | |
int main(int argc, char **argv) { | |
int fd = open(*++argv, O_RDONLY); | |
char *choice = *++argv; | |
if (!choice) { | |
return EXIT_FAILURE; | |
} else if (!strcmp(choice, "read")) { | |
return test_read(fd); | |
} else if (!strcmp(choice, "mmap")) { | |
return test_mmap(fd); | |
} else { | |
return EXIT_FAILURE; | |
} | |
} |
And on the big FreeBSD system:
% repeat 5 time ./tperf ./freenas-boot.zfs.gz read
4.899u 1.149s 0:06.04 99.8% 5+168k 0+0io 0pf+0w
4.913u 1.275s 0:06.18 100.0% 5+167k 0+0io 0pf+0w
4.721u 1.416s 0:06.13 100.0% 5+167k 0+0io 0pf+0w
4.940u 1.189s 0:06.13 99.8% 5+167k 0+0io 0pf+0w
4.950u 1.188s 0:06.13 100.0% 5+167k 0+0io 0pf+0w
% repeat 5 time ./tperf ./freenas-boot.zfs.gz mmap
5.526u 1.637s 0:07.16 99.8% 5+168k 0+0io 0pf+0w
5.647u 1.535s 0:07.18 99.8% 5+167k 0+0io 0pf+0w
5.576u 1.575s 0:07.15 99.8% 5+167k 0+0io 0pf+0w
5.593u 1.551s 0:07.14 100.0% 5+167k 0+0io 0pf+0w
5.397u 1.762s 0:07.15 100.0% 5+168k 0+0io 0pf+0w
The big Mac and FreeBSD systems each have hundreds of gigabytes of RAM, and all three systems are SSD-only. (However: on the big FreeSBD system, I used /tmp
which is tmpfs
; on the smaller one, which doesn't have as much RAM, the test file was on a ZFS dataset.)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
With some slight changes, on a wimpy FreeBSD machine:
However, in a beefy Mac Pro, with those same changes:
The changes were to use
madvise
and break it up into smaller chunks:My big FreeBSD system isn't booting, and I'm 5000 miles away, so I'll have to spend effort into figuring why.