OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/memory/memory_pressure_monitor_mac.h" | 5 #include "base/memory/memory_pressure_monitor_mac.h" |
6 | 6 |
7 #include <dlfcn.h> | 7 #include <dlfcn.h> |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 #include <sys/sysctl.h> | 9 #include <sys/sysctl.h> |
10 | 10 |
| 11 #include <cmath> |
| 12 |
11 #include "base/bind.h" | 13 #include "base/bind.h" |
12 #include "base/logging.h" | 14 #include "base/logging.h" |
13 #include "base/mac/mac_util.h" | 15 #include "base/mac/mac_util.h" |
14 | 16 |
15 // Redeclare for partial 10.9 availability. | 17 // Redeclare for partial 10.9 availability. |
16 DISPATCH_EXPORT const struct dispatch_source_type_s | 18 DISPATCH_EXPORT const struct dispatch_source_type_s |
17 _dispatch_source_type_memorypressure; | 19 _dispatch_source_type_memorypressure; |
18 | 20 |
19 namespace base { | 21 namespace base { |
20 namespace mac { | 22 namespace mac { |
21 | 23 |
22 MemoryPressureListener::MemoryPressureLevel | 24 MemoryPressureListener::MemoryPressureLevel |
23 MemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressure( | 25 MemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressure( |
24 int mac_memory_pressure) { | 26 int mac_memory_pressure) { |
25 switch (mac_memory_pressure) { | 27 switch (mac_memory_pressure) { |
26 case DISPATCH_MEMORYPRESSURE_NORMAL: | 28 case DISPATCH_MEMORYPRESSURE_NORMAL: |
27 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; | 29 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; |
28 case DISPATCH_MEMORYPRESSURE_WARN: | 30 case DISPATCH_MEMORYPRESSURE_WARN: |
29 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE; | 31 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE; |
30 case DISPATCH_MEMORYPRESSURE_CRITICAL: | 32 case DISPATCH_MEMORYPRESSURE_CRITICAL: |
31 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL; | 33 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL; |
32 } | 34 } |
33 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; | 35 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; |
34 } | 36 } |
35 | 37 |
36 void MemoryPressureMonitor::NotifyMemoryPressureChanged( | |
37 dispatch_source_s* event_source, | |
38 const MemoryPressureMonitor::DispatchCallback& dispatch_callback) { | |
39 int mac_memory_pressure = dispatch_source_get_data(event_source); | |
40 MemoryPressureListener::MemoryPressureLevel memory_pressure_level = | |
41 MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure); | |
42 dispatch_callback.Run(memory_pressure_level); | |
43 } | |
44 | |
45 MemoryPressureMonitor::MemoryPressureMonitor() | 38 MemoryPressureMonitor::MemoryPressureMonitor() |
46 // The MemoryPressureListener doesn't want to know about transitions to | |
47 // MEMORY_PRESSURE_LEVEL_NONE so don't watch for | |
48 // DISPATCH_MEMORYPRESSURE_NORMAL notifications. | |
49 : memory_level_event_source_(dispatch_source_create( | 39 : memory_level_event_source_(dispatch_source_create( |
50 DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, | 40 DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, |
51 0, | 41 0, |
52 DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL, | 42 DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL | |
| 43 DISPATCH_MEMORYPRESSURE_NORMAL, |
53 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0))), | 44 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0))), |
54 dispatch_callback_( | 45 dispatch_callback_( |
55 base::Bind(&MemoryPressureListener::NotifyMemoryPressure)) { | 46 base::Bind(&MemoryPressureListener::NotifyMemoryPressure)), |
| 47 last_pressure_change_(CFAbsoluteTimeGetCurrent()), |
| 48 reporting_error_(0) { |
| 49 last_pressure_level_ = GetCurrentPressureLevel(); |
56 dispatch_source_set_event_handler(memory_level_event_source_, ^{ | 50 dispatch_source_set_event_handler(memory_level_event_source_, ^{ |
57 NotifyMemoryPressureChanged(memory_level_event_source_.get(), | 51 OnMemoryPressureChanged(memory_level_event_source_.get(), |
58 dispatch_callback_); | 52 dispatch_callback_); |
59 }); | 53 }); |
60 dispatch_resume(memory_level_event_source_); | 54 dispatch_resume(memory_level_event_source_); |
61 } | 55 } |
62 | 56 |
63 MemoryPressureMonitor::~MemoryPressureMonitor() { | 57 MemoryPressureMonitor::~MemoryPressureMonitor() { |
64 dispatch_source_cancel(memory_level_event_source_); | 58 dispatch_source_cancel(memory_level_event_source_); |
65 } | 59 } |
66 | 60 |
67 MemoryPressureListener::MemoryPressureLevel | 61 MemoryPressureListener::MemoryPressureLevel |
68 MemoryPressureMonitor::GetCurrentPressureLevel() const { | 62 MemoryPressureMonitor::GetCurrentPressureLevel() const { |
69 int mac_memory_pressure; | 63 int mac_memory_pressure; |
70 size_t length = sizeof(int); | 64 size_t length = sizeof(int); |
71 sysctlbyname("kern.memorystatus_vm_pressure_level", &mac_memory_pressure, | 65 sysctlbyname("kern.memorystatus_vm_pressure_level", &mac_memory_pressure, |
72 &length, nullptr, 0); | 66 &length, nullptr, 0); |
73 return MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure); | 67 return MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure); |
74 } | 68 } |
| 69 void MemoryPressureMonitor::OnMemoryPressureChanged( |
| 70 dispatch_source_s* event_source, |
| 71 const MemoryPressureMonitor::DispatchCallback& dispatch_callback) { |
| 72 int mac_memory_pressure = dispatch_source_get_data(event_source); |
| 73 MemoryPressureListener::MemoryPressureLevel memory_pressure_level = |
| 74 MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure); |
| 75 CFTimeInterval now = CFAbsoluteTimeGetCurrent(); |
| 76 CFTimeInterval since_last_change = now - last_pressure_change_; |
| 77 last_pressure_change_ = now; |
| 78 |
| 79 double ticks_to_report; |
| 80 reporting_error_ = |
| 81 modf(since_last_change + reporting_error_, &ticks_to_report); |
| 82 |
| 83 // Sierra fails to call the handler when pressure returns to normal, |
| 84 // which would skew our data. For example, if pressure went to 'warn' |
| 85 // at T0, back to 'normal' at T1, then to 'critical' at T10, we would |
| 86 // report 10 ticks of 'warn' instead of 1 tick of 'warn' and 9 ticks |
| 87 // of 'normal'. |
| 88 // This is rdar://29114314 |
| 89 if (mac::IsAtMostOS10_11()) |
| 90 RecordMemoryPressure(last_pressure_level_, |
| 91 static_cast<int>(ticks_to_report)); |
| 92 |
| 93 last_pressure_level_ = memory_pressure_level; |
| 94 if (memory_pressure_level != |
| 95 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) |
| 96 dispatch_callback.Run(memory_pressure_level); |
| 97 } |
75 | 98 |
76 void MemoryPressureMonitor::SetDispatchCallback( | 99 void MemoryPressureMonitor::SetDispatchCallback( |
77 const DispatchCallback& callback) { | 100 const DispatchCallback& callback) { |
78 dispatch_callback_ = callback; | 101 dispatch_callback_ = callback; |
79 } | 102 } |
80 | 103 |
81 } // namespace mac | 104 } // namespace mac |
82 } // namespace base | 105 } // namespace base |
OLD | NEW |