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