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> | 11 #include <cmath> |
12 | 12 |
13 #include "base/bind.h" | 13 #include "base/bind.h" |
14 #include "base/logging.h" | 14 #include "base/logging.h" |
15 #include "base/mac/mac_util.h" | 15 #include "base/mac/mac_util.h" |
16 | 16 |
17 // Redeclare for partial 10.9 availability. | 17 // Redeclare for partial 10.9 availability. |
18 DISPATCH_EXPORT const struct dispatch_source_type_s | 18 DISPATCH_EXPORT const struct dispatch_source_type_s |
19 _dispatch_source_type_memorypressure; | 19 _dispatch_source_type_memorypressure; |
20 | 20 |
| 21 namespace { |
| 22 static const int kUMATickSize = 5; |
| 23 } // namespace |
| 24 |
21 namespace base { | 25 namespace base { |
22 namespace mac { | 26 namespace mac { |
23 | 27 |
24 MemoryPressureListener::MemoryPressureLevel | 28 MemoryPressureListener::MemoryPressureLevel |
25 MemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressure( | 29 MemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressure( |
26 int mac_memory_pressure) { | 30 int mac_memory_pressure) { |
27 switch (mac_memory_pressure) { | 31 switch (mac_memory_pressure) { |
28 case DISPATCH_MEMORYPRESSURE_NORMAL: | 32 case DISPATCH_MEMORYPRESSURE_NORMAL: |
29 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; | 33 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; |
30 case DISPATCH_MEMORYPRESSURE_WARN: | 34 case DISPATCH_MEMORYPRESSURE_WARN: |
31 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE; | 35 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE; |
32 case DISPATCH_MEMORYPRESSURE_CRITICAL: | 36 case DISPATCH_MEMORYPRESSURE_CRITICAL: |
33 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL; | 37 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL; |
34 } | 38 } |
35 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; | 39 return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; |
36 } | 40 } |
37 | 41 |
38 MemoryPressureMonitor::MemoryPressureMonitor() | 42 MemoryPressureMonitor::MemoryPressureMonitor() |
39 : memory_level_event_source_(dispatch_source_create( | 43 : memory_level_event_source_(dispatch_source_create( |
40 DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, | 44 DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, |
41 0, | 45 0, |
42 DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL | | 46 DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL | |
43 DISPATCH_MEMORYPRESSURE_NORMAL, | 47 DISPATCH_MEMORYPRESSURE_NORMAL, |
44 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0))), | 48 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0))), |
45 dispatch_callback_( | 49 dispatch_callback_( |
46 base::Bind(&MemoryPressureListener::NotifyMemoryPressure)), | 50 base::Bind(&MemoryPressureListener::NotifyMemoryPressure)), |
47 last_pressure_change_(CFAbsoluteTimeGetCurrent()), | 51 last_statistic_report_(CFAbsoluteTimeGetCurrent()), |
| 52 last_pressure_level_(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE), |
48 reporting_error_(0) { | 53 reporting_error_(0) { |
49 last_pressure_level_ = GetCurrentPressureLevel(); | |
50 dispatch_source_set_event_handler(memory_level_event_source_, ^{ | 54 dispatch_source_set_event_handler(memory_level_event_source_, ^{ |
51 OnMemoryPressureChanged(memory_level_event_source_.get(), | 55 OnMemoryPressureChanged(memory_level_event_source_.get(), |
52 dispatch_callback_); | 56 dispatch_callback_); |
53 }); | 57 }); |
54 dispatch_resume(memory_level_event_source_); | 58 dispatch_resume(memory_level_event_source_); |
55 } | 59 } |
56 | 60 |
57 MemoryPressureMonitor::~MemoryPressureMonitor() { | 61 MemoryPressureMonitor::~MemoryPressureMonitor() { |
58 dispatch_source_cancel(memory_level_event_source_); | 62 dispatch_source_cancel(memory_level_event_source_); |
59 } | 63 } |
60 | 64 |
61 MemoryPressureListener::MemoryPressureLevel | 65 MemoryPressureListener::MemoryPressureLevel |
62 MemoryPressureMonitor::GetCurrentPressureLevel() const { | 66 MemoryPressureMonitor::GetCurrentPressureLevel() { |
63 int mac_memory_pressure; | 67 int mac_memory_pressure; |
64 size_t length = sizeof(int); | 68 size_t length = sizeof(int); |
65 sysctlbyname("kern.memorystatus_vm_pressure_level", &mac_memory_pressure, | 69 sysctlbyname("kern.memorystatus_vm_pressure_level", &mac_memory_pressure, |
66 &length, nullptr, 0); | 70 &length, nullptr, 0); |
67 return MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure); | 71 MemoryPressureListener::MemoryPressureLevel memory_pressure_level = |
| 72 MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure); |
| 73 bool pressure_level_changed = false; |
| 74 if (last_pressure_level_ != memory_pressure_level) { |
| 75 pressure_level_changed = true; |
| 76 } |
| 77 SendStatisticsIfNecessary(pressure_level_changed); |
| 78 last_pressure_level_ = memory_pressure_level; |
| 79 return memory_pressure_level; |
68 } | 80 } |
| 81 |
69 void MemoryPressureMonitor::OnMemoryPressureChanged( | 82 void MemoryPressureMonitor::OnMemoryPressureChanged( |
70 dispatch_source_s* event_source, | 83 dispatch_source_s* event_source, |
71 const MemoryPressureMonitor::DispatchCallback& dispatch_callback) { | 84 const MemoryPressureMonitor::DispatchCallback& dispatch_callback) { |
72 int mac_memory_pressure = dispatch_source_get_data(event_source); | 85 int mac_memory_pressure = dispatch_source_get_data(event_source); |
73 MemoryPressureListener::MemoryPressureLevel memory_pressure_level = | 86 MemoryPressureListener::MemoryPressureLevel memory_pressure_level = |
74 MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure); | 87 MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure); |
75 CFTimeInterval now = CFAbsoluteTimeGetCurrent(); | 88 bool pressure_level_changed = false; |
76 CFTimeInterval since_last_change = now - last_pressure_change_; | 89 if (last_pressure_level_ != memory_pressure_level) { |
77 last_pressure_change_ = now; | 90 pressure_level_changed = true; |
78 | 91 } |
79 double ticks_to_report; | 92 SendStatisticsIfNecessary(pressure_level_changed); |
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; | 93 last_pressure_level_ = memory_pressure_level; |
94 if (memory_pressure_level != | 94 if (memory_pressure_level != |
95 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) | 95 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) |
96 dispatch_callback.Run(memory_pressure_level); | 96 dispatch_callback.Run(memory_pressure_level); |
97 } | 97 } |
98 | 98 |
| 99 void MemoryPressureMonitor::SendStatisticsIfNecessary( |
| 100 bool pressure_level_changed) { |
| 101 CFTimeInterval now = CFAbsoluteTimeGetCurrent(); |
| 102 CFTimeInterval since_last_report = now - last_statistic_report_; |
| 103 last_statistic_report_ = now; |
| 104 |
| 105 double accumulated_time = since_last_report + reporting_error_; |
| 106 int ticks_to_report = static_cast<int>(accumulated_time / kUMATickSize); |
| 107 reporting_error_ = std::fmod(accumulated_time, kUMATickSize); |
| 108 |
| 109 // Round up on change to ensure we capture it |
| 110 if (pressure_level_changed && ticks_to_report < 1) { |
| 111 ticks_to_report = 1; |
| 112 reporting_error_ = 0; |
| 113 } |
| 114 |
| 115 if (ticks_to_report >= 1) |
| 116 RecordMemoryPressure(last_pressure_level_, ticks_to_report); |
| 117 } |
| 118 |
99 void MemoryPressureMonitor::SetDispatchCallback( | 119 void MemoryPressureMonitor::SetDispatchCallback( |
100 const DispatchCallback& callback) { | 120 const DispatchCallback& callback) { |
101 dispatch_callback_ = callback; | 121 dispatch_callback_ = callback; |
102 } | 122 } |
103 | 123 |
104 } // namespace mac | 124 } // namespace mac |
105 } // namespace base | 125 } // namespace base |
OLD | NEW |