chromium/tools/android/fincore/fincore.cc

// 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;
}