| 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() {
|
|
|