Index: storage/browser/blob/blob_memory_controller.cc |
diff --git a/storage/browser/blob/blob_memory_controller.cc b/storage/browser/blob/blob_memory_controller.cc |
index 0153f3bc5f930152123cf306f2705dbe8b641bab..27370be1c3f818c80f34c54177e27bc6ccf0155c 100644 |
--- a/storage/browser/blob/blob_memory_controller.cc |
+++ b/storage/browser/blob/blob_memory_controller.cc |
@@ -16,6 +16,7 @@ |
#include "base/guid.h" |
#include "base/location.h" |
#include "base/memory/ptr_util.h" |
+#include "base/metrics/histogram_functions.h" |
#include "base/metrics/histogram_macros.h" |
#include "base/numerics/safe_conversions.h" |
#include "base/numerics/safe_math.h" |
@@ -41,6 +42,7 @@ namespace storage { |
namespace { |
constexpr int64_t kUnknownDiskAvailability = -1ll; |
constexpr uint64_t kMegabyte = 1024ull * 1024; |
+const int64_t kMinSecondsForPressureEvictions = 30; |
using FileCreationInfo = BlobMemoryController::FileCreationInfo; |
using MemoryAllocation = BlobMemoryController::MemoryAllocation; |
@@ -505,6 +507,9 @@ BlobMemoryController::BlobMemoryController( |
disk_space_function_(&base::SysInfo::AmountOfFreeDiskSpace), |
populated_memory_items_( |
base::MRUCache<uint64_t, ShareableBlobDataItem*>::NO_AUTO_EVICT), |
+ memory_pressure_listener_( |
+ base::Bind(&BlobMemoryController::OnMemoryPressure, |
+ base::Unretained(this))), |
weak_factory_(this) {} |
BlobMemoryController::~BlobMemoryController() {} |
@@ -604,7 +609,8 @@ base::WeakPtr<QuotaAllocationTask> BlobMemoryController::ReserveMemoryQuota( |
if (total_bytes_needed <= GetAvailableMemoryForBlobs()) { |
GrantMemoryAllocations(&unreserved_memory_items, |
static_cast<size_t>(total_bytes_needed)); |
- MaybeScheduleEvictionUntilSystemHealthy(); |
+ MaybeScheduleEvictionUntilSystemHealthy( |
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE); |
done_callback.Run(true); |
return base::WeakPtr<QuotaAllocationTask>(); |
} |
@@ -615,7 +621,8 @@ base::WeakPtr<QuotaAllocationTask> BlobMemoryController::ReserveMemoryQuota( |
auto weak_ptr = AppendMemoryTask( |
total_bytes_needed, std::move(unreserved_memory_items), done_callback); |
- MaybeScheduleEvictionUntilSystemHealthy(); |
+ MaybeScheduleEvictionUntilSystemHealthy( |
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE); |
return weak_ptr; |
} |
@@ -649,7 +656,8 @@ void BlobMemoryController::NotifyMemoryItemsUsed( |
populated_memory_items_.Put(item->item_id(), item.get()); |
} |
} |
- MaybeScheduleEvictionUntilSystemHealthy(); |
+ MaybeScheduleEvictionUntilSystemHealthy( |
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE); |
} |
void BlobMemoryController::CalculateBlobStorageLimits() { |
@@ -771,11 +779,12 @@ void BlobMemoryController::MaybeGrantPendingMemoryRequests() { |
} |
size_t BlobMemoryController::CollectItemsForEviction( |
- std::vector<scoped_refptr<ShareableBlobDataItem>>* output) { |
+ std::vector<scoped_refptr<ShareableBlobDataItem>>* output, |
+ uint64_t min_page_file_size) { |
base::CheckedNumeric<size_t> total_items_size = 0; |
// Process the recent item list and remove items until we have at least a |
// minimum file size or we're at the end of our items to page to disk. |
- while (total_items_size.ValueOrDie() < limits_.min_page_file_size && |
+ while (total_items_size.ValueOrDie() < min_page_file_size && |
!populated_memory_items_.empty()) { |
auto iterator = --populated_memory_items_.end(); |
ShareableBlobDataItem* item = iterator->second; |
@@ -789,7 +798,8 @@ size_t BlobMemoryController::CollectItemsForEviction( |
return total_items_size.ValueOrDie(); |
} |
-void BlobMemoryController::MaybeScheduleEvictionUntilSystemHealthy() { |
+void BlobMemoryController::MaybeScheduleEvictionUntilSystemHealthy( |
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { |
// Don't do eviction when others are happening, as we don't change our |
// pending_memory_quota_total_size_ value until after the paging files have |
// been written. |
@@ -800,20 +810,42 @@ void BlobMemoryController::MaybeScheduleEvictionUntilSystemHealthy() { |
static_cast<uint64_t>(pending_memory_quota_total_size_) + |
blob_memory_used_; |
+ size_t in_memory_limit = limits_.memory_limit_before_paging(); |
+ uint64_t min_page_file_size = limits_.min_page_file_size; |
+ if (memory_pressure_level != |
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) { |
+ in_memory_limit = 0; |
+ // Use lower page file size to reduce using more memory for writing under |
+ // pressure. |
+ min_page_file_size = limits_.max_blob_in_memory_space * |
+ limits_.max_blob_in_memory_space_under_pressure_ratio; |
+ } |
+ |
// We try to page items to disk until our current system size + requested |
// memory is below our size limit. |
// Size limit is a lower |memory_limit_before_paging()| if we have disk space. |
while (total_memory_usage > limits_.effective_max_disk_space || |
(disk_used_ < limits_.effective_max_disk_space && |
- total_memory_usage > limits_.memory_limit_before_paging())) { |
+ total_memory_usage > in_memory_limit)) { |
+ const char* reason = nullptr; |
+ if (memory_pressure_level != |
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) { |
+ reason = "OnMemoryPressure"; |
+ } else if (total_memory_usage > limits_.effective_max_disk_space) { |
+ reason = "SizeExceededMaxDiskSpace"; |
+ } else { |
+ reason = "SizeExceededInMemoryLimit"; |
+ } |
+ |
// We only page when we have enough items to fill a whole page file. |
- if (populated_memory_items_bytes_ < limits_.min_page_file_size) |
+ if (populated_memory_items_bytes_ < min_page_file_size) |
break; |
- DCHECK_LE(limits_.min_page_file_size, |
- static_cast<uint64_t>(blob_memory_used_)); |
+ DCHECK_LE(min_page_file_size, static_cast<uint64_t>(blob_memory_used_)); |
std::vector<scoped_refptr<ShareableBlobDataItem>> items_to_swap; |
- size_t total_items_size = CollectItemsForEviction(&items_to_swap); |
+ |
+ size_t total_items_size = |
+ CollectItemsForEviction(&items_to_swap, min_page_file_size); |
if (total_items_size == 0) |
break; |
@@ -849,7 +881,10 @@ void BlobMemoryController::MaybeScheduleEvictionUntilSystemHealthy() { |
total_items_size), |
base::Bind(&BlobMemoryController::OnEvictionComplete, |
weak_factory_.GetWeakPtr(), base::Passed(&file_reference), |
- base::Passed(&items_to_swap), total_items_size)); |
+ base::Passed(&items_to_swap), total_items_size, reason, |
+ total_memory_usage)); |
+ |
+ last_eviction_time_ = base::TimeTicks::Now(); |
} |
RecordTracingCounters(); |
} |
@@ -858,6 +893,8 @@ void BlobMemoryController::OnEvictionComplete( |
scoped_refptr<ShareableFileReference> file_reference, |
std::vector<scoped_refptr<ShareableBlobDataItem>> items, |
size_t total_items_size, |
+ const char* evict_reason, |
+ size_t memory_usage_before_eviction, |
std::pair<FileCreationInfo, int64_t /* avail_disk */> result) { |
if (!file_paging_enabled_) |
return; |
@@ -893,12 +930,32 @@ void BlobMemoryController::OnEvictionComplete( |
} |
in_flight_memory_used_ -= total_items_size; |
+ // Record change in memory usage at the last eviction reply. |
+ size_t total_usage = blob_memory_used_ + pending_memory_quota_total_size_; |
+ if (!pending_evictions_ && memory_usage_before_eviction >= total_usage) { |
+ std::string full_histogram_name = |
+ std::string("Storage.Blob.SizeEvictedToDiskInKB.") + evict_reason; |
+ base::UmaHistogramCounts100000( |
+ full_histogram_name, |
+ (memory_usage_before_eviction - total_usage) / 1024); |
+ } |
+ |
// We want callback on blobs up to the amount we've freed. |
MaybeGrantPendingMemoryRequests(); |
// If we still have more blobs waiting and we're not waiting on more paging |
// operations, schedule more. |
- MaybeScheduleEvictionUntilSystemHealthy(); |
+ MaybeScheduleEvictionUntilSystemHealthy( |
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE); |
+} |
+ |
+void BlobMemoryController::OnMemoryPressure( |
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { |
+ auto time_from_last_evicion = base::TimeTicks::Now() - last_eviction_time_; |
+ if (time_from_last_evicion.InSeconds() < kMinSecondsForPressureEvictions) |
+ return; |
+ |
+ MaybeScheduleEvictionUntilSystemHealthy(memory_pressure_level); |
} |
FilePath BlobMemoryController::GenerateNextPageFileName() { |