// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fcntl.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <iomanip>
#include <iostream>
#include <vector>
void PrintUsage(char* prog) {
std::cout << "Usage: " << prog << " FILE" << std::endl
<< "Determine what portion of the FILE is resident in memory."
<< std::endl;
}
int main(int argc, char* argv[]) {
if (argc != 2) {
PrintUsage(argv[0]);
return 1;
}
char* file_name = argv[1];
if (!std::string("--help").compare(file_name)) {
PrintUsage(argv[0]);
return 0;
}
int fd = open(file_name, O_RDONLY);
if (fd == -1) {
perror(file_name);
return 1;
}
struct stat st;
if (fstat(fd, &st)) {
perror("fstat");
return 1;
}
size_t len = static_cast<size_t>(st.st_size);
if (len > SIZE_MAX) {
std::cerr << "File too large" << std::endl;
return 1;
}
void* start_address = mmap(nullptr, len, PROT_READ, MAP_SHARED, fd, 0);
if (start_address == MAP_FAILED) {
perror("mmap");
return 1;
}
size_t total_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE;
std::vector<uint8_t> page_residencies(total_pages);
if (mincore(start_address, len, page_residencies.data())) {
perror("mincore");
return 1;
}
size_t resident_pages = 0;
for (auto page_residency : page_residencies) {
if (page_residency != 0) {
resident_pages++;
}
}
std::cout << "File size: " << len << ", resident pages: " << resident_pages
<< ", which is " << std::setprecision(4)
<< 100.0 * resident_pages / total_pages << "\% of all pages ("
<< resident_pages / 256 << "MiB)." << std::endl;
return 0;
}