blob: 229b4162cf5970c2eeeeb942419fa31f022954b7 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ios/chrome/browser/memory/memory_metrics.h"
#include <mach/mach.h>
#include <mach/task.h>
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include "base/logging.h"
#include "base/mac/scoped_mach_port.h"
#include "base/process/process_handle.h"
#include "base/process/process_metrics.h"
#include "build/build_config.h"
#ifdef ARCH_CPU_64_BITS
#define cr_vm_region vm_region_64
#else
#define cr_vm_region vm_region
#endif
namespace {
// The number of pages returned by host_statistics and vm_region are a count
// of pages of 4096 bytes even when running on arm64 but the constants that
// are exposed (vm_page_size, VM_PAGE_SIZE, host_page_size) are all equals to
// 16384 bytes. So we define our own constant here to convert from page count
// to bytes.
const uint64_t kVMPageSize = 4096;
}
namespace memory_util {
uint64_t GetFreePhysicalBytes() {
vm_statistics_data_t vmstat;
mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
base::mac::ScopedMachSendRight host(mach_host_self());
kern_return_t result = host_statistics(
host.get(), HOST_VM_INFO, reinterpret_cast<host_info_t>(&vmstat), &count);
if (result != KERN_SUCCESS) {
LOG(ERROR) << "Calling host_statistics failed.";
return 0;
}
return vmstat.free_count * kVMPageSize;
}
uint64_t GetRealMemoryUsedInBytes() {
task_vm_info task_info_data;
mach_msg_type_number_t count = sizeof(task_vm_info) / sizeof(natural_t);
kern_return_t kr =
task_info(mach_task_self(), TASK_VM_INFO,
reinterpret_cast<task_info_t>(&task_info_data), &count);
if (kr != KERN_SUCCESS)
return 0;
return task_info_data.resident_size - task_info_data.reusable;
}
uint64_t GetDirtyVMBytes() {
// Iterate over all VM regions and sum their dirty pages.
unsigned int total_dirty_pages = 0;
vm_size_t vm_size = 0;
kern_return_t result;
for (vm_address_t address = MACH_VM_MIN_ADDRESS;; address += vm_size) {
vm_region_extended_info_data_t info;
mach_msg_type_number_t info_count = VM_REGION_EXTENDED_INFO_COUNT;
mach_port_t object_name;
result = cr_vm_region(
mach_task_self(), &address, &vm_size, VM_REGION_EXTENDED_INFO,
reinterpret_cast<vm_region_info_t>(&info), &info_count, &object_name);
if (result == KERN_INVALID_ADDRESS) {
// The end of the address space has been reached.
break;
} else if (result != KERN_SUCCESS) {
LOG(ERROR) << "Calling vm_region failed with code: " << result;
break;
} else {
total_dirty_pages += info.pages_dirtied;
}
}
return total_dirty_pages * kVMPageSize;
}
uint64_t GetInternalVMBytes() {
task_vm_info_data_t task_vm_info;
mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
kern_return_t result =
task_info(mach_task_self(), TASK_VM_INFO,
reinterpret_cast<task_info_t>(&task_vm_info), &count);
if (result != KERN_SUCCESS) {
LOG(ERROR) << "Calling task_info failed.";
return 0;
}
return static_cast<uint64_t>(task_vm_info.internal);
}
} // namespace memory_util