Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(271)

Side by Side Diff: base/process/process_metrics_mac.cc

Issue 2826123004: Use faster, but less information methods to calculate memory dumps on macOS. (Closed)
Patch Set: comments form mark, primiano. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/process/process_metrics.h" 5 #include "base/process/process_metrics.h"
6 6
7 #include <mach/mach.h> 7 #include <mach/mach.h>
8 #include <mach/mach_vm.h> 8 #include <mach/mach_vm.h>
9 #include <mach/shared_region.h> 9 #include <mach/shared_region.h>
10 #include <stddef.h> 10 #include <stddef.h>
11 #include <stdint.h> 11 #include <stdint.h>
12 #include <sys/sysctl.h> 12 #include <sys/sysctl.h>
13 13
14 #include "base/containers/hash_tables.h" 14 #include "base/containers/hash_tables.h"
15 #include "base/logging.h" 15 #include "base/logging.h"
16 #include "base/mac/mach_logging.h" 16 #include "base/mac/mach_logging.h"
17 #include "base/mac/scoped_mach_port.h" 17 #include "base/mac/scoped_mach_port.h"
18 #include "base/memory/ptr_util.h" 18 #include "base/memory/ptr_util.h"
19 #include "base/numerics/safe_conversions.h" 19 #include "base/numerics/safe_conversions.h"
20 #include "base/numerics/safe_math.h"
20 #include "base/sys_info.h" 21 #include "base/sys_info.h"
21 22
22 namespace base { 23 namespace base {
23 24
24 namespace { 25 namespace {
25 26
26 bool GetTaskInfo(mach_port_t task, task_basic_info_64* task_info_data) { 27 bool GetTaskInfo(mach_port_t task, task_basic_info_64* task_info_data) {
27 if (task == MACH_PORT_NULL) 28 if (task == MACH_PORT_NULL)
28 return false; 29 return false;
29 mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT; 30 mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
(...skipping 25 matching lines...) Expand all
55 return addr >= SHARED_REGION_BASE_I386 && 56 return addr >= SHARED_REGION_BASE_I386 &&
56 addr < (SHARED_REGION_BASE_I386 + SHARED_REGION_SIZE_I386); 57 addr < (SHARED_REGION_BASE_I386 + SHARED_REGION_SIZE_I386);
57 } else if (type == CPU_TYPE_X86_64) { 58 } else if (type == CPU_TYPE_X86_64) {
58 return addr >= SHARED_REGION_BASE_X86_64 && 59 return addr >= SHARED_REGION_BASE_X86_64 &&
59 addr < (SHARED_REGION_BASE_X86_64 + SHARED_REGION_SIZE_X86_64); 60 addr < (SHARED_REGION_BASE_X86_64 + SHARED_REGION_SIZE_X86_64);
60 } else { 61 } else {
61 return false; 62 return false;
62 } 63 }
63 } 64 }
64 65
65 enum MachVMRegionResult { Finished, Error, Success }; 66 MachVMRegionResult ParseOutputFromMachVMRegion(kern_return_t kr) {
66
67 // Both |size| and |address| are in-out parameters.
68 // |info| is an output parameter, only valid on Success.
69 MachVMRegionResult GetTopInfo(mach_port_t task,
70 mach_vm_size_t* size,
71 mach_vm_address_t* address,
72 vm_region_top_info_data_t* info) {
73 mach_msg_type_number_t info_count = VM_REGION_TOP_INFO_COUNT;
74 mach_port_t object_name;
75 kern_return_t kr = mach_vm_region(task, address, size, VM_REGION_TOP_INFO,
76 reinterpret_cast<vm_region_info_t>(info),
77 &info_count, &object_name);
78 // We're at the end of the address space.
79 if (kr == KERN_INVALID_ADDRESS)
80 return Finished;
81
82 if (kr != KERN_SUCCESS)
83 return Error;
84
85 // The kernel always returns a null object for VM_REGION_TOP_INFO, but
86 // balance it with a deallocate in case this ever changes. See 10.9.2
87 // xnu-2422.90.20/osfmk/vm/vm_map.c vm_map_region.
88 mach_port_deallocate(task, object_name);
89 return Success;
90 }
91
92 MachVMRegionResult GetBasicInfo(mach_port_t task,
93 mach_vm_size_t* size,
94 mach_vm_address_t* address,
95 vm_region_basic_info_64* info) {
96 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
97 mach_port_t object_name;
98 kern_return_t kr = mach_vm_region(
99 task, address, size, VM_REGION_BASIC_INFO_64,
100 reinterpret_cast<vm_region_info_t>(info), &info_count, &object_name);
101 if (kr == KERN_INVALID_ADDRESS) { 67 if (kr == KERN_INVALID_ADDRESS) {
102 // We're at the end of the address space. 68 // We're at the end of the address space.
103 return Finished; 69 return MachVMRegionResult::Finished;
104 } else if (kr != KERN_SUCCESS) { 70 } else if (kr != KERN_SUCCESS) {
105 return Error; 71 return MachVMRegionResult::Error;
106 } 72 }
107 73 return MachVMRegionResult::Success;
108 // The kernel always returns a null object for VM_REGION_BASIC_INFO_64, but
109 // balance it with a deallocate in case this ever changes. See 10.9.2
110 // xnu-2422.90.20/osfmk/vm/vm_map.c vm_map_region.
111 mach_port_deallocate(task, object_name);
112 return Success;
113 } 74 }
114 75
115 } // namespace 76 } // namespace
116 77
117 // Getting a mach task from a pid for another process requires permissions in 78 // Getting a mach task from a pid for another process requires permissions in
118 // general, so there doesn't really seem to be a way to do these (and spinning 79 // general, so there doesn't really seem to be a way to do these (and spinning
119 // up ps to fetch each stats seems dangerous to put in a base api for anyone to 80 // up ps to fetch each stats seems dangerous to put in a base api for anyone to
120 // call). Child processes ipc their port, so return something if available, 81 // call). Child processes ipc their port, so return something if available,
121 // otherwise return 0. 82 // otherwise return 0.
122 83
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 // try to avoid counting pages that are also referenced by other tasks. Since 145 // try to avoid counting pages that are also referenced by other tasks. Since
185 // we don't have access to the VM regions of other tasks the only hint we have 146 // we don't have access to the VM regions of other tasks the only hint we have
186 // is if the address is in the shared region area. 147 // is if the address is in the shared region area.
187 // 148 //
188 // Private memory is much simpler. We simply count the pages that are marked 149 // Private memory is much simpler. We simply count the pages that are marked
189 // as private or copy on write (COW). 150 // as private or copy on write (COW).
190 // 151 //
191 // See libtop_update_vm_regions in 152 // See libtop_update_vm_regions in
192 // http://www.opensource.apple.com/source/top/top-67/libtop.c 153 // http://www.opensource.apple.com/source/top/top-67/libtop.c
193 mach_vm_size_t size = 0; 154 mach_vm_size_t size = 0;
194 for (mach_vm_address_t address = MACH_VM_MIN_ADDRESS;; address += size) { 155 mach_vm_address_t address = MACH_VM_MIN_ADDRESS;
195 mach_vm_size_t size_copy = size; 156 while (true) {
157 base::CheckedNumeric<mach_vm_address_t> next_address(address);
158 next_address += size;
159 if (!next_address.IsValid())
160 return false;
161 address = next_address.ValueOrDie();
162
196 mach_vm_address_t address_copy = address; 163 mach_vm_address_t address_copy = address;
197
198 vm_region_top_info_data_t info; 164 vm_region_top_info_data_t info;
199 MachVMRegionResult result = GetTopInfo(task, &size, &address, &info); 165 MachVMRegionResult result = GetTopInfo(task, &size, &address, &info);
200 if (result == Error) 166 if (result == MachVMRegionResult::Error)
201 return false; 167 return false;
202 if (result == Finished) 168 if (result == MachVMRegionResult::Finished)
203 break; 169 break;
204 170
205 vm_region_basic_info_64 basic_info; 171 vm_region_basic_info_64 basic_info;
206 result = GetBasicInfo(task, &size_copy, &address_copy, &basic_info); 172 mach_vm_size_t dummy_size = 0;
207 switch (result) { 173 result = GetBasicInfo(task, &dummy_size, &address_copy, &basic_info);
208 case Finished: 174 if (result == MachVMRegionResult::Error)
209 case Error: 175 return false;
210 return false; 176 if (result == MachVMRegionResult::Finished)
211 case Success: 177 break;
212 break; 178
213 }
214 bool is_wired = basic_info.user_wired_count > 0; 179 bool is_wired = basic_info.user_wired_count > 0;
215 180
216 if (IsAddressInSharedRegion(address, cpu_type) && 181 if (IsAddressInSharedRegion(address, cpu_type) &&
217 info.share_mode != SM_PRIVATE) 182 info.share_mode != SM_PRIVATE)
218 continue; 183 continue;
219 184
220 if (info.share_mode == SM_COW && info.ref_count == 1) 185 if (info.share_mode == SM_COW && info.ref_count == 1)
221 info.share_mode = SM_PRIVATE; 186 info.share_mode = SM_PRIVATE;
222 187
223 switch (info.share_mode) { 188 switch (info.share_mode) {
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 meminfo->speculative = 414 meminfo->speculative =
450 saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.speculative_count); 415 saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.speculative_count);
451 meminfo->file_backed = 416 meminfo->file_backed =
452 saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.external_page_count); 417 saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.external_page_count);
453 meminfo->purgeable = 418 meminfo->purgeable =
454 saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.purgeable_count); 419 saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.purgeable_count);
455 420
456 return true; 421 return true;
457 } 422 }
458 423
424 // Both |size| and |address| are in-out parameters.
425 // |info| is an output parameter, only valid on Success.
426 MachVMRegionResult GetTopInfo(mach_port_t task,
427 mach_vm_size_t* size,
428 mach_vm_address_t* address,
429 vm_region_top_info_data_t* info) {
430 mach_msg_type_number_t info_count = VM_REGION_TOP_INFO_COUNT;
431 mach_port_t object_name;
432 kern_return_t kr = mach_vm_region(task, address, size, VM_REGION_TOP_INFO,
433 reinterpret_cast<vm_region_info_t>(info),
434 &info_count, &object_name);
435 // The kernel always returns a null object for VM_REGION_TOP_INFO, but
436 // balance it with a deallocate in case this ever changes. See 10.9.2
437 // xnu-2422.90.20/osfmk/vm/vm_map.c vm_map_region.
438 mach_port_deallocate(task, object_name);
439 return ParseOutputFromMachVMRegion(kr);
440 }
441
442 MachVMRegionResult GetBasicInfo(mach_port_t task,
443 mach_vm_size_t* size,
444 mach_vm_address_t* address,
445 vm_region_basic_info_64* info) {
446 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
447 mach_port_t object_name;
448 kern_return_t kr = mach_vm_region(
449 task, address, size, VM_REGION_BASIC_INFO_64,
450 reinterpret_cast<vm_region_info_t>(info), &info_count, &object_name);
451 // The kernel always returns a null object for VM_REGION_BASIC_INFO_64, but
452 // balance it with a deallocate in case this ever changes. See 10.9.2
453 // xnu-2422.90.20/osfmk/vm/vm_map.c vm_map_region.
454 mach_port_deallocate(task, object_name);
455 return ParseOutputFromMachVMRegion(kr);
456 }
457
459 } // namespace base 458 } // namespace base
OLDNEW
« no previous file with comments | « base/process/process_metrics.h ('k') | components/tracing/common/process_metrics_memory_dump_provider.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698