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