Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(593)

Side by Side Diff: net/sdch/sdch_owner.cc

Issue 1051353003: SDCH: add TimeWeightedMemoryUse (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Don't reset clock Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/sdch/sdch_owner.h ('k') | net/sdch/sdch_owner_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "net/sdch/sdch_owner.h" 5 #include "net/sdch/sdch_owner.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/debug/alias.h" 8 #include "base/debug/alias.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/metrics/histogram_macros.h" 10 #include "base/metrics/histogram_macros.h"
11 #include "base/prefs/persistent_pref_store.h" 11 #include "base/prefs/persistent_pref_store.h"
12 #include "base/prefs/value_map_pref_store.h" 12 #include "base/prefs/value_map_pref_store.h"
13 #include "base/strings/string_util.h" 13 #include "base/strings/string_util.h"
14 #include "base/time/default_clock.h" 14 #include "base/time/default_clock.h"
15 #include "base/values.h" 15 #include "base/values.h"
16 #include "net/base/sdch_manager.h" 16 #include "net/base/sdch_manager.h"
17 #include "net/base/sdch_net_log_params.h" 17 #include "net/base/sdch_net_log_params.h"
18 18
19 namespace net { 19 namespace net {
20 20
21 namespace { 21 namespace {
22 22
23 enum DictionaryFate {
24 // A Get-Dictionary header wasn't acted on.
25 DICTIONARY_FATE_GET_IGNORED = 1,
26
27 // A fetch was attempted, but failed.
28 // TODO(rdsmith): Actually record this case.
29 DICTIONARY_FATE_FETCH_FAILED = 2,
30
31 // A successful fetch was dropped on the floor, no space.
32 DICTIONARY_FATE_FETCH_IGNORED_NO_SPACE = 3,
33
34 // A successful fetch was refused by the SdchManager.
35 DICTIONARY_FATE_FETCH_MANAGER_REFUSED = 4,
36
37 // A dictionary was successfully added based on
38 // a Get-Dictionary header in a response.
39 DICTIONARY_FATE_ADD_RESPONSE_TRIGGERED = 5,
40
41 // A dictionary was evicted by an incoming dict.
42 DICTIONARY_FATE_EVICT_FOR_DICT = 6,
43
44 // A dictionary was evicted by memory pressure.
45 DICTIONARY_FATE_EVICT_FOR_MEMORY = 7,
46
47 // A dictionary was evicted on destruction.
48 DICTIONARY_FATE_EVICT_FOR_DESTRUCTION = 8,
49
50 // A dictionary was successfully added based on
51 // persistence from a previous browser revision.
52 DICTIONARY_FATE_ADD_PERSISTENCE_TRIGGERED = 9,
53
54 // A dictionary was unloaded on destruction, but is still present on disk.
55 DICTIONARY_FATE_UNLOAD_FOR_DESTRUCTION = 10,
56
57 DICTIONARY_FATE_MAX = 11
58 };
59
60 enum PersistenceFailureReason { 23 enum PersistenceFailureReason {
61 // File didn't exist; is being created. 24 // File didn't exist; is being created.
62 PERSISTENCE_FAILURE_REASON_NO_FILE = 1, 25 PERSISTENCE_FAILURE_REASON_NO_FILE = 1,
63 26
64 // Error reading in information, but should be able to write. 27 // Error reading in information, but should be able to write.
65 PERSISTENCE_FAILURE_REASON_READ_FAILED = 2, 28 PERSISTENCE_FAILURE_REASON_READ_FAILED = 2,
66 29
67 // Error leading to abort on attempted persistence. 30 // Error leading to abort on attempted persistence.
68 PERSISTENCE_FAILURE_REASON_WRITE_FAILED = 3, 31 PERSISTENCE_FAILURE_REASON_WRITE_FAILED = 3,
69 32
70 PERSISTENCE_FAILURE_REASON_MAX = 4 33 PERSISTENCE_FAILURE_REASON_MAX = 4
71 }; 34 };
72 35
73 // Dictionaries that haven't been touched in 24 hours may be evicted 36 // Dictionaries that haven't been touched in 24 hours may be evicted
74 // to make room for new dictionaries. 37 // to make room for new dictionaries.
75 const int kFreshnessLifetimeHours = 24; 38 const int kFreshnessLifetimeHours = 24;
76 39
77 // Dictionaries that have never been used only stay fresh for one hour. 40 // Dictionaries that have never been used only stay fresh for one hour.
78 const int kNeverUsedFreshnessLifetimeHours = 1; 41 const int kNeverUsedFreshnessLifetimeHours = 1;
79 42
80 void RecordDictionaryFate(enum DictionaryFate fate) {
81 UMA_HISTOGRAM_ENUMERATION("Sdch3.DictionaryFate", fate, DICTIONARY_FATE_MAX);
82 }
83
84 void RecordPersistenceFailure(PersistenceFailureReason failure_reason) { 43 void RecordPersistenceFailure(PersistenceFailureReason failure_reason) {
85 UMA_HISTOGRAM_ENUMERATION("Sdch3.PersistenceFailureReason", failure_reason, 44 UMA_HISTOGRAM_ENUMERATION("Sdch3.PersistenceFailureReason", failure_reason,
86 PERSISTENCE_FAILURE_REASON_MAX); 45 PERSISTENCE_FAILURE_REASON_MAX);
87 } 46 }
88 47
89 void RecordDictionaryEvictionOrUnload(int use_count, DictionaryFate fate) {
90 DCHECK(fate == DICTIONARY_FATE_EVICT_FOR_DICT ||
91 fate == DICTIONARY_FATE_EVICT_FOR_MEMORY ||
92 fate == DICTIONARY_FATE_EVICT_FOR_DESTRUCTION ||
93 fate == DICTIONARY_FATE_UNLOAD_FOR_DESTRUCTION);
94
95 UMA_HISTOGRAM_COUNTS_100("Sdch3.DictionaryUseCount", use_count);
96 RecordDictionaryFate(fate);
97 }
98
99 // Schema specifications and access routines. 48 // Schema specifications and access routines.
100 49
101 // The persistent prefs store is conceptually shared with any other network 50 // The persistent prefs store is conceptually shared with any other network
102 // stack systems that want to persist data over browser restarts, and so 51 // stack systems that want to persist data over browser restarts, and so
103 // use of it must be namespace restricted. 52 // use of it must be namespace restricted.
104 // Schema: 53 // Schema:
105 // pref_store_->GetValue(kPreferenceName) -> Dictionary { 54 // pref_store_->GetValue(kPreferenceName) -> Dictionary {
106 // 'version' -> 1 [int] 55 // 'version' -> 1 [int]
107 // 'dictionaries' -> Dictionary { 56 // 'dictionaries' -> Dictionary {
108 // server_hash -> { 57 // server_hash -> {
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 // static 208 // static
260 const size_t SdchOwner::kMaxTotalDictionarySize = 20 * 1000 * 1000; 209 const size_t SdchOwner::kMaxTotalDictionarySize = 20 * 1000 * 1000;
261 #endif 210 #endif
262 211
263 // Somewhat arbitrary, but we assume a dictionary smaller than 212 // Somewhat arbitrary, but we assume a dictionary smaller than
264 // 50K isn't going to do anyone any good. Note that this still doesn't 213 // 50K isn't going to do anyone any good. Note that this still doesn't
265 // prevent download and addition unless there is less than this 214 // prevent download and addition unless there is less than this
266 // amount of space available in storage. 215 // amount of space available in storage.
267 const size_t SdchOwner::kMinSpaceForDictionaryFetch = 50 * 1000; 216 const size_t SdchOwner::kMinSpaceForDictionaryFetch = 50 * 1000;
268 217
218 void SdchOwner::RecordDictionaryFate(enum DictionaryFate fate) {
219 UMA_HISTOGRAM_ENUMERATION("Sdch3.DictionaryFate", fate, DICTIONARY_FATE_MAX);
220 }
221
222 void SdchOwner::RecordDictionaryEvictionOrUnload(const std::string& server_hash,
223 size_t size,
224 int use_count,
225 DictionaryFate fate) {
226 DCHECK(fate == DICTIONARY_FATE_EVICT_FOR_DICT ||
227 fate == DICTIONARY_FATE_EVICT_FOR_MEMORY ||
228 fate == DICTIONARY_FATE_EVICT_FOR_DESTRUCTION ||
229 fate == DICTIONARY_FATE_UNLOAD_FOR_DESTRUCTION);
230
231 UMA_HISTOGRAM_COUNTS_100("Sdch3.DictionaryUseCount", use_count);
232 RecordDictionaryFate(fate);
233
234 DCHECK(load_times_.count(server_hash) == 1);
235 base::Time now = clock_->Now();
236 base::TimeDelta dict_lifetime = now - load_times_[server_hash];
237 consumed_byte_seconds_.push_back(size * dict_lifetime.InMilliseconds());
238 load_times_.erase(server_hash);
239 }
240
269 SdchOwner::SdchOwner(SdchManager* sdch_manager, URLRequestContext* context) 241 SdchOwner::SdchOwner(SdchManager* sdch_manager, URLRequestContext* context)
270 : manager_(sdch_manager->GetWeakPtr()), 242 : manager_(sdch_manager->GetWeakPtr()),
271 fetcher_(new SdchDictionaryFetcher(context)), 243 fetcher_(new SdchDictionaryFetcher(context)),
272 total_dictionary_bytes_(0), 244 total_dictionary_bytes_(0),
273 clock_(new base::DefaultClock), 245 clock_(new base::DefaultClock),
274 max_total_dictionary_size_(kMaxTotalDictionarySize), 246 max_total_dictionary_size_(kMaxTotalDictionarySize),
275 min_space_for_dictionary_fetch_(kMinSpaceForDictionaryFetch), 247 min_space_for_dictionary_fetch_(kMinSpaceForDictionaryFetch),
276 #if defined(OS_CHROMEOS) 248 #if defined(OS_CHROMEOS)
277 // For debugging http://crbug.com/454198; remove when resolved. 249 // For debugging http://crbug.com/454198; remove when resolved.
278 destroyed_(0), 250 destroyed_(0),
279 #endif 251 #endif
280 memory_pressure_listener_( 252 memory_pressure_listener_(
281 base::Bind(&SdchOwner::OnMemoryPressure, 253 base::Bind(&SdchOwner::OnMemoryPressure,
282 // Because |memory_pressure_listener_| is owned by 254 // Because |memory_pressure_listener_| is owned by
283 // SdchOwner, the SdchOwner object will be available 255 // SdchOwner, the SdchOwner object will be available
284 // for the lifetime of |memory_pressure_listener_|. 256 // for the lifetime of |memory_pressure_listener_|.
285 base::Unretained(this))), 257 base::Unretained(this))),
286 in_memory_pref_store_(new ValueMapPrefStore()), 258 in_memory_pref_store_(new ValueMapPrefStore()),
287 external_pref_store_(nullptr), 259 external_pref_store_(nullptr),
288 pref_store_(in_memory_pref_store_.get()) { 260 pref_store_(in_memory_pref_store_.get()),
261 creation_time_(clock_->Now()) {
289 #if defined(OS_CHROMEOS) 262 #if defined(OS_CHROMEOS)
290 // For debugging http://crbug.com/454198; remove when resolved. 263 // For debugging http://crbug.com/454198; remove when resolved.
291 CHECK(clock_.get()); 264 CHECK(clock_.get());
292 #endif 265 #endif
293 manager_->AddObserver(this); 266 manager_->AddObserver(this);
294 InitializePrefStore(pref_store_); 267 InitializePrefStore(pref_store_);
295 } 268 }
296 269
297 SdchOwner::~SdchOwner() { 270 SdchOwner::~SdchOwner() {
298 #if defined(OS_CHROMEOS) 271 #if defined(OS_CHROMEOS)
299 // For debugging http://crbug.com/454198; remove when resolved. 272 // For debugging http://crbug.com/454198; remove when resolved.
300 CHECK_EQ(0u, destroyed_); 273 CHECK_EQ(0u, destroyed_);
301 CHECK(clock_.get()); 274 CHECK(clock_.get());
302 clock_.reset();
303 CHECK(manager_.get()); 275 CHECK(manager_.get());
304 #endif 276 #endif
305 277
306 for (DictionaryPreferenceIterator it(pref_store_); !it.IsAtEnd(); 278 for (DictionaryPreferenceIterator it(pref_store_); !it.IsAtEnd();
307 it.Advance()) { 279 it.Advance()) {
308 int new_uses = it.use_count() - use_counts_at_load_[it.server_hash()]; 280 int new_uses = it.use_count() - use_counts_at_load_[it.server_hash()];
309 DictionaryFate fate = IsPersistingDictionaries() ? 281 DictionaryFate fate = IsPersistingDictionaries() ?
310 DICTIONARY_FATE_UNLOAD_FOR_DESTRUCTION : 282 DICTIONARY_FATE_UNLOAD_FOR_DESTRUCTION :
311 DICTIONARY_FATE_EVICT_FOR_DESTRUCTION; 283 DICTIONARY_FATE_EVICT_FOR_DESTRUCTION;
312 RecordDictionaryEvictionOrUnload(new_uses, fate); 284 RecordDictionaryEvictionOrUnload(it.server_hash(), it.size(), new_uses,
285 fate);
313 } 286 }
314 manager_->RemoveObserver(this); 287 manager_->RemoveObserver(this);
315 288
316 // This object only observes the external store during loading, 289 // This object only observes the external store during loading,
317 // i.e. before it's made the default preferences store. 290 // i.e. before it's made the default preferences store.
318 if (external_pref_store_) 291 if (external_pref_store_)
319 external_pref_store_->RemoveObserver(this); 292 external_pref_store_->RemoveObserver(this);
320 293
294 int64 object_lifetime =
295 (clock_->Now() - creation_time_).InMilliseconds();
296 for (const auto& val : consumed_byte_seconds_) {
297 if (object_lifetime > 0) {
298 // Objects that are created and immediately destroyed don't add any memory
299 // pressure over time (and also cause a crash here).
300 UMA_HISTOGRAM_MEMORY_KB("Sdch3.TimeWeightedMemoryUse",
301 val / object_lifetime);
302 }
303 }
304
321 #if defined(OS_CHROMEOS) 305 #if defined(OS_CHROMEOS)
322 destroyed_ = 0xdeadbeef; 306 destroyed_ = 0xdeadbeef;
323 #endif 307 #endif
324 } 308 }
325 309
326 void SdchOwner::EnablePersistentStorage(PersistentPrefStore* pref_store) { 310 void SdchOwner::EnablePersistentStorage(PersistentPrefStore* pref_store) {
327 DCHECK(!external_pref_store_); 311 DCHECK(!external_pref_store_);
328 external_pref_store_ = pref_store; 312 external_pref_store_ = pref_store;
329 external_pref_store_->AddObserver(this); 313 external_pref_store_->AddObserver(this);
330 314
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
443 427
444 DCHECK(pref_dictionary_map->HasKey(stale_it->server_hash)); 428 DCHECK(pref_dictionary_map->HasKey(stale_it->server_hash));
445 bool success = pref_dictionary_map->RemoveWithoutPathExpansion( 429 bool success = pref_dictionary_map->RemoveWithoutPathExpansion(
446 stale_it->server_hash, nullptr); 430 stale_it->server_hash, nullptr);
447 DCHECK(success); 431 DCHECK(success);
448 432
449 avail_bytes += stale_it->dictionary_size; 433 avail_bytes += stale_it->dictionary_size;
450 434
451 int new_uses = stale_it->use_count - 435 int new_uses = stale_it->use_count -
452 use_counts_at_load_[stale_it->server_hash]; 436 use_counts_at_load_[stale_it->server_hash];
453 RecordDictionaryEvictionOrUnload(new_uses, 437 RecordDictionaryEvictionOrUnload(stale_it->server_hash,
438 stale_it->dictionary_size,
439 new_uses,
454 DICTIONARY_FATE_EVICT_FOR_DICT); 440 DICTIONARY_FATE_EVICT_FOR_DICT);
455 441
456 ++stale_it; 442 ++stale_it;
457 } 443 }
458 DCHECK_GE(avail_bytes, dictionary_text.size()); 444 DCHECK_GE(avail_bytes, dictionary_text.size());
459 445
460 RecordDictionaryFate( 446 RecordDictionaryFate(
461 // Distinguish between loads triggered by network responses and 447 // Distinguish between loads triggered by network responses and
462 // loads triggered by persistence. 448 // loads triggered by persistence.
463 last_used.is_null() ? DICTIONARY_FATE_ADD_RESPONSE_TRIGGERED 449 last_used.is_null() ? DICTIONARY_FATE_ADD_RESPONSE_TRIGGERED
(...skipping 16 matching lines...) Expand all
480 // Record the addition in the pref store. 466 // Record the addition in the pref store.
481 scoped_ptr<base::DictionaryValue> dictionary_description( 467 scoped_ptr<base::DictionaryValue> dictionary_description(
482 new base::DictionaryValue()); 468 new base::DictionaryValue());
483 dictionary_description->SetString(kDictionaryUrlKey, dictionary_url.spec()); 469 dictionary_description->SetString(kDictionaryUrlKey, dictionary_url.spec());
484 dictionary_description->SetDouble(kDictionaryLastUsedKey, 470 dictionary_description->SetDouble(kDictionaryLastUsedKey,
485 last_used.ToDoubleT()); 471 last_used.ToDoubleT());
486 dictionary_description->SetInteger(kDictionaryUseCountKey, use_count); 472 dictionary_description->SetInteger(kDictionaryUseCountKey, use_count);
487 dictionary_description->SetInteger(kDictionarySizeKey, 473 dictionary_description->SetInteger(kDictionarySizeKey,
488 dictionary_text.size()); 474 dictionary_text.size());
489 pref_dictionary_map->Set(server_hash, dictionary_description.Pass()); 475 pref_dictionary_map->Set(server_hash, dictionary_description.Pass());
476 load_times_[server_hash] = clock_->Now();
490 } 477 }
491 478
492 void SdchOwner::OnDictionaryUsed(SdchManager* manager, 479 void SdchOwner::OnDictionaryUsed(SdchManager* manager,
493 const std::string& server_hash) { 480 const std::string& server_hash) {
494 base::Time now(clock_->Now()); 481 base::Time now(clock_->Now());
495 base::DictionaryValue* pref_dictionary_map = 482 base::DictionaryValue* pref_dictionary_map =
496 GetPersistentStoreDictionaryMap(pref_store_); 483 GetPersistentStoreDictionaryMap(pref_store_);
497 ScopedPrefNotifier scoped_pref_notifier(pref_store_); 484 ScopedPrefNotifier scoped_pref_notifier(pref_store_);
498 485
499 base::Value* value = nullptr; 486 base::Value* value = nullptr;
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
712 fetcher_.reset(fetcher.release()); 699 fetcher_.reset(fetcher.release());
713 } 700 }
714 701
715 void SdchOwner::OnMemoryPressure( 702 void SdchOwner::OnMemoryPressure(
716 base::MemoryPressureListener::MemoryPressureLevel level) { 703 base::MemoryPressureListener::MemoryPressureLevel level) {
717 DCHECK_NE(base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, level); 704 DCHECK_NE(base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, level);
718 705
719 for (DictionaryPreferenceIterator it(pref_store_); !it.IsAtEnd(); 706 for (DictionaryPreferenceIterator it(pref_store_); !it.IsAtEnd();
720 it.Advance()) { 707 it.Advance()) {
721 int new_uses = it.use_count() - use_counts_at_load_[it.server_hash()]; 708 int new_uses = it.use_count() - use_counts_at_load_[it.server_hash()];
722 RecordDictionaryEvictionOrUnload(new_uses, 709 RecordDictionaryEvictionOrUnload(it.server_hash(),
710 it.size(),
711 new_uses,
723 DICTIONARY_FATE_EVICT_FOR_MEMORY); 712 DICTIONARY_FATE_EVICT_FOR_MEMORY);
724 } 713 }
725 714
726 // TODO(rdsmith): Make a distinction between moderate and critical 715 // TODO(rdsmith): Make a distinction between moderate and critical
727 // memory pressure. 716 // memory pressure.
728 manager_->ClearData(); 717 manager_->ClearData();
729 } 718 }
730 719
731 bool SdchOwner::SchedulePersistedDictionaryLoads( 720 bool SdchOwner::SchedulePersistedDictionaryLoads(
732 const base::DictionaryValue& persisted_info) { 721 const base::DictionaryValue& persisted_info) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
774 } 763 }
775 764
776 return true; 765 return true;
777 } 766 }
778 767
779 bool SdchOwner::IsPersistingDictionaries() const { 768 bool SdchOwner::IsPersistingDictionaries() const {
780 return in_memory_pref_store_.get() != nullptr; 769 return in_memory_pref_store_.get() != nullptr;
781 } 770 }
782 771
783 } // namespace net 772 } // namespace net
OLDNEW
« no previous file with comments | « net/sdch/sdch_owner.h ('k') | net/sdch/sdch_owner_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698