NOTE: At the and of the article there is a link to the archive containing all the source code and scripts necessary to reproduce the experiments. Also, note that the code has only been tested on Linux/PC.
Assuming you have compute_checksum.cpp (containing the above code) in your current directory, running the following set of commands in succession
$ dd if=/dev/zero of=./input.txt count=1024 bs=1048576 $ g++ -o compute_checksum compute_checksum.cpp -std=c++0x -O3 -march=native $ ./compute_checksum ./input.txt
checksum = 0, time = 0.52s checksum = 0, time = 0.45s checksum = 0, time = 0.46s
(a) What if you are using a third-party cluster (rebooting requires sudo)?
(b) Even if you have the privileges necessary for rebooting, you would still need to reboot every time you modify your program and rebooting can take a minute or so. This solution is thus not very practical.
After reading a sufficient amount of data, this will indeed overwrite the cache and is slightly better, though still a bit "dirty", solution. This solution has the advantage that it does not require sudo privileges.
echo 3 | sudo tee /proc/sys/vm/drop_caches
- The algorithm is only allocating and using a small amount of RAM (few GiB), and
- We successfully empty the page cache at the beginning of the program,
posix_fadvise - predeclare an access pattern for file data
#include <fcntl.h> int posix_fadvise(int fd, off_t offset, off_t len, int advice);
Programs can use posix_fadvise() to announce an intention to access file data in a specific pattern in the future, thus allowing the kernel to perform appropriate optimizations. The advice applies to a (not necessarily existent) region starting at offset and extending for len bytes (or until the end of the file if len is 0) within the file referred to by fd. The advice is not binding; it merely constitutes an expectation on behalf of the application. Permissible values for advice include: (...) POSIX_FADV_DONTNEED The specified data will not be accessed in the near future. POSIX_FAVD_DONNEED attempts to free cached pages associated with the specified region. This is useful, for example, while streaming large files. A program may periodically request the kernel to free cached data that has already been used, so that more useful cached pages are not discarded instead. (...)
$ g++ -o empty_page_cache empty_page_cache.cpp -std=c++0x -O3 -march=native $ ./empty_page_cache ./input.txt $ ./compute_checksum ./input.txt
checksum = 0, time = 5.14s checksum = 0, time = 0.50s checksum = 0, time = 0.45s
$ g++ -o checksum_uncached checksum_uncached.cpp -std=c++0x -O3 -march=native $ ./checksum_uncached ./input.txt
checksum = 0, time = 4.98s checksum = 0, time = 4.86s checksum = 0, time = 4.92s
My preferred solution is Solution 4, at it does not have the restrictions that come with using O_DIRECT, can be easily embedded in the code, does not require sudo access. It is also faster than other solutions, as it only drops the cached pages of the files we specify.