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

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: fix ios compile error. 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
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) {
102 // We're at the end of the address space.
103 return Finished;
104 } else if (kr != KERN_SUCCESS) {
105 return Error;
106 }
107
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 }
114
115 } // namespace 66 } // namespace
116 67
117 // Getting a mach task from a pid for another process requires permissions in 68 // 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 69 // 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 70 // 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, 71 // call). Child processes ipc their port, so return something if available,
121 // otherwise return 0. 72 // otherwise return 0.
122 73
123 // static 74 // static
124 std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics( 75 std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics(
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 // try to avoid counting pages that are also referenced by other tasks. Since 135 // 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 136 // 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. 137 // is if the address is in the shared region area.
187 // 138 //
188 // Private memory is much simpler. We simply count the pages that are marked 139 // Private memory is much simpler. We simply count the pages that are marked
189 // as private or copy on write (COW). 140 // as private or copy on write (COW).
190 // 141 //
191 // See libtop_update_vm_regions in 142 // See libtop_update_vm_regions in
192 // http://www.opensource.apple.com/source/top/top-67/libtop.c 143 // http://www.opensource.apple.com/source/top/top-67/libtop.c
193 mach_vm_size_t size = 0; 144 mach_vm_size_t size = 0;
194 for (mach_vm_address_t address = MACH_VM_MIN_ADDRESS;; address += size) { 145 mach_vm_address_t address = MACH_VM_MIN_ADDRESS;
195 mach_vm_size_t size_copy = size; 146 while (true) {
147 base::CheckedNumeric<mach_vm_address_t> numeric(address);
Mark Mentovai 2017/04/21 12:33:51 “numeric” isn’t a great name for an address. The i
erikchen 2017/04/21 18:20:24 Done.
148 numeric += size;
149 if (!numeric.IsValid())
150 return false;
151 address = numeric.ValueOrDie();
152
196 mach_vm_address_t address_copy = address; 153 mach_vm_address_t address_copy = address;
197
198 vm_region_top_info_data_t info; 154 vm_region_top_info_data_t info;
199 MachVMRegionResult result = GetTopInfo(task, &size, &address, &info); 155 MachVMRegionResult result = GetTopInfo(task, &size, &address, &info);
200 if (result == Error) 156 if (result == MachVMRegionResult::Error)
201 return false; 157 return false;
202 if (result == Finished) 158 if (result == MachVMRegionResult::Finished)
203 break; 159 break;
204 160
205 vm_region_basic_info_64 basic_info; 161 vm_region_basic_info_64 basic_info;
206 result = GetBasicInfo(task, &size_copy, &address_copy, &basic_info); 162 mach_vm_size_t dummy_size = 0;
207 switch (result) { 163 result = GetBasicInfo(task, &dummy_size, &address_copy, &basic_info);
208 case Finished: 164 if (result == MachVMRegionResult::Error)
209 case Error: 165 return false;
210 return false; 166 if (result == MachVMRegionResult::Finished)
211 case Success: 167 break;
212 break; 168
213 }
214 bool is_wired = basic_info.user_wired_count > 0; 169 bool is_wired = basic_info.user_wired_count > 0;
215 170
216 if (IsAddressInSharedRegion(address, cpu_type) && 171 if (IsAddressInSharedRegion(address, cpu_type) &&
217 info.share_mode != SM_PRIVATE) 172 info.share_mode != SM_PRIVATE)
218 continue; 173 continue;
219 174
220 if (info.share_mode == SM_COW && info.ref_count == 1) 175 if (info.share_mode == SM_COW && info.ref_count == 1)
221 info.share_mode = SM_PRIVATE; 176 info.share_mode = SM_PRIVATE;
222 177
223 switch (info.share_mode) { 178 switch (info.share_mode) {
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 meminfo->speculative = 404 meminfo->speculative =
450 saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.speculative_count); 405 saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.speculative_count);
451 meminfo->file_backed = 406 meminfo->file_backed =
452 saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.external_page_count); 407 saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.external_page_count);
453 meminfo->purgeable = 408 meminfo->purgeable =
454 saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.purgeable_count); 409 saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.purgeable_count);
455 410
456 return true; 411 return true;
457 } 412 }
458 413
414 // Both |size| and |address| are in-out parameters.
415 // |info| is an output parameter, only valid on Success.
416 MachVMRegionResult GetTopInfo(mach_port_t task,
417 mach_vm_size_t* size,
418 mach_vm_address_t* address,
419 vm_region_top_info_data_t* info) {
420 mach_msg_type_number_t info_count = VM_REGION_TOP_INFO_COUNT;
421 mach_port_t object_name;
422 kern_return_t kr = mach_vm_region(task, address, size, VM_REGION_TOP_INFO,
423 reinterpret_cast<vm_region_info_t>(info),
424 &info_count, &object_name);
425 // We're at the end of the address space.
426 if (kr == KERN_INVALID_ADDRESS)
427 return MachVMRegionResult::Finished;
428
429 if (kr != KERN_SUCCESS)
430 return MachVMRegionResult::Error;
431
432 // The kernel always returns a null object for VM_REGION_TOP_INFO, but
433 // balance it with a deallocate in case this ever changes. See 10.9.2
434 // xnu-2422.90.20/osfmk/vm/vm_map.c vm_map_region.
435 mach_port_deallocate(task, object_name);
436 return MachVMRegionResult::Success;
437 }
438
439 MachVMRegionResult GetBasicInfo(mach_port_t task,
440 mach_vm_size_t* size,
441 mach_vm_address_t* address,
442 vm_region_basic_info_64* info) {
443 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
444 mach_port_t object_name;
445 kern_return_t kr = mach_vm_region(
446 task, address, size, VM_REGION_BASIC_INFO_64,
447 reinterpret_cast<vm_region_info_t>(info), &info_count, &object_name);
448 if (kr == KERN_INVALID_ADDRESS) {
Mark Mentovai 2017/04/21 12:33:52 No reason for this section to deviate from 425-430
erikchen 2017/04/21 18:20:25 Done.
449 // We're at the end of the address space.
450 return MachVMRegionResult::Finished;
451 } else if (kr != KERN_SUCCESS) {
452 return MachVMRegionResult::Error;
453 }
454
455 // The kernel always returns a null object for VM_REGION_BASIC_INFO_64, but
456 // balance it with a deallocate in case this ever changes. See 10.9.2
457 // xnu-2422.90.20/osfmk/vm/vm_map.c vm_map_region.
458 mach_port_deallocate(task, object_name);
459 return MachVMRegionResult::Success;
460 }
461
459 } // namespace base 462 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698