Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/browser/chromeos/memory/oom_priority_manager.h" | 5 #include "chrome/browser/chromeos/memory/oom_priority_manager.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 24 #include "base/utf_string_conversions.h" | 24 #include "base/utf_string_conversions.h" |
| 25 #include "build/build_config.h" | 25 #include "build/build_config.h" |
| 26 #include "chrome/browser/browser_process.h" | 26 #include "chrome/browser/browser_process.h" |
| 27 #include "chrome/browser/chromeos/memory/low_memory_observer.h" | 27 #include "chrome/browser/chromeos/memory/low_memory_observer.h" |
| 28 #include "chrome/browser/memory_details.h" | 28 #include "chrome/browser/memory_details.h" |
| 29 #include "chrome/browser/ui/browser.h" | 29 #include "chrome/browser/ui/browser.h" |
| 30 #include "chrome/browser/ui/browser_list.h" | 30 #include "chrome/browser/ui/browser_list.h" |
| 31 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 31 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 32 #include "chrome/common/chrome_constants.h" | 32 #include "chrome/common/chrome_constants.h" |
| 33 #include "chrome/common/chrome_switches.h" | 33 #include "chrome/common/chrome_switches.h" |
| 34 #include "chrome/common/url_constants.h" | |
| 34 #include "content/public/browser/browser_thread.h" | 35 #include "content/public/browser/browser_thread.h" |
| 35 #include "content/public/browser/notification_service.h" | 36 #include "content/public/browser/notification_service.h" |
| 36 #include "content/public/browser/notification_types.h" | 37 #include "content/public/browser/notification_types.h" |
| 37 #include "content/public/browser/render_process_host.h" | 38 #include "content/public/browser/render_process_host.h" |
| 38 #include "content/public/browser/render_widget_host.h" | 39 #include "content/public/browser/render_widget_host.h" |
| 39 #include "content/public/browser/web_contents.h" | 40 #include "content/public/browser/web_contents.h" |
| 40 #include "content/public/browser/zygote_host_linux.h" | 41 #include "content/public/browser/zygote_host_linux.h" |
| 41 #include "ui/base/text/bytes_formatting.h" | 42 #include "ui/base/text/bytes_formatting.h" |
| 42 | 43 |
| 43 using base::TimeDelta; | 44 using base::TimeDelta; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 69 // value. | 70 // value. |
| 70 const int kAdjustmentIntervalSeconds = 10; | 71 const int kAdjustmentIntervalSeconds = 10; |
| 71 | 72 |
| 72 // If there has been no priority adjustment in this interval, we assume the | 73 // If there has been no priority adjustment in this interval, we assume the |
| 73 // machine was suspended and correct our timing statistics. | 74 // machine was suspended and correct our timing statistics. |
| 74 const int kSuspendThresholdSeconds = kAdjustmentIntervalSeconds * 4; | 75 const int kSuspendThresholdSeconds = kAdjustmentIntervalSeconds * 4; |
| 75 | 76 |
| 76 // The default interval in milliseconds to wait before setting the score of | 77 // The default interval in milliseconds to wait before setting the score of |
| 77 // currently focused tab. Must be be long enough that a user who is flipping | 78 // currently focused tab. Must be be long enough that a user who is flipping |
| 78 // through tabs with Ctrl-Tab does not mark each every tab as "focused". | 79 // through tabs with Ctrl-Tab does not mark each every tab as "focused". |
| 79 const int kFocusedTabScoreAdjustIntervalMs = 2000; | 80 const int kFocusedTabScoreAdjustIntervalMs = 1500; |
| 80 | 81 |
| 81 // Returns a unique ID for a WebContents. Do not cast back to a pointer, as | 82 // Returns a unique ID for a WebContents. Do not cast back to a pointer, as |
| 82 // the WebContents could be deleted if the user closed the tab. | 83 // the WebContents could be deleted if the user closed the tab. |
| 83 int64 IdFromWebContents(WebContents* web_contents) { | 84 int64 IdFromWebContents(WebContents* web_contents) { |
| 84 return reinterpret_cast<int64>(web_contents); | 85 return reinterpret_cast<int64>(web_contents); |
| 85 } | 86 } |
| 86 | 87 |
| 87 //////////////////////////////////////////////////////////////////////////////// | 88 //////////////////////////////////////////////////////////////////////////////// |
| 88 // OomMemoryDetails logs details about all Chrome processes during an out-of- | 89 // OomMemoryDetails logs details about all Chrome processes during an out-of- |
| 89 // memory event in an attempt to identify the culprit, then discards a tab and | 90 // memory event in an attempt to identify the culprit, then discards a tab and |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 127 Release(); | 128 Release(); |
| 128 } | 129 } |
| 129 | 130 |
| 130 } // namespace | 131 } // namespace |
| 131 | 132 |
| 132 //////////////////////////////////////////////////////////////////////////////// | 133 //////////////////////////////////////////////////////////////////////////////// |
| 133 // OomPriorityManager | 134 // OomPriorityManager |
| 134 | 135 |
| 135 OomPriorityManager::TabStats::TabStats() | 136 OomPriorityManager::TabStats::TabStats() |
| 136 : is_app(false), | 137 : is_app(false), |
| 138 is_reloadable_ui(false), | |
| 137 is_pinned(false), | 139 is_pinned(false), |
| 138 is_selected(false), | 140 is_selected(false), |
| 139 is_discarded(false), | 141 is_discarded(false), |
| 140 renderer_handle(0), | 142 renderer_handle(0), |
| 141 tab_contents_id(0) { | 143 tab_contents_id(0) { |
| 142 } | 144 } |
| 143 | 145 |
| 144 OomPriorityManager::TabStats::~TabStats() { | 146 OomPriorityManager::TabStats::~TabStats() { |
| 145 } | 147 } |
| 146 | 148 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 192 TabStatsList::iterator it = stats.begin(); | 194 TabStatsList::iterator it = stats.begin(); |
| 193 for ( ; it != stats.end(); ++it) { | 195 for ( ; it != stats.end(); ++it) { |
| 194 string16 str; | 196 string16 str; |
| 195 str.reserve(4096); | 197 str.reserve(4096); |
| 196 str += it->title; | 198 str += it->title; |
| 197 str += ASCIIToUTF16(" ("); | 199 str += ASCIIToUTF16(" ("); |
| 198 int score = pid_to_oom_score_[it->renderer_handle]; | 200 int score = pid_to_oom_score_[it->renderer_handle]; |
| 199 str += base::IntToString16(score); | 201 str += base::IntToString16(score); |
| 200 str += ASCIIToUTF16(")"); | 202 str += ASCIIToUTF16(")"); |
| 201 str += ASCIIToUTF16(it->is_app ? " app" : ""); | 203 str += ASCIIToUTF16(it->is_app ? " app" : ""); |
| 204 str += ASCIIToUTF16(it->is_reloadable_ui ? " reloadable_ui" : ""); | |
| 202 str += ASCIIToUTF16(it->is_pinned ? " pinned" : ""); | 205 str += ASCIIToUTF16(it->is_pinned ? " pinned" : ""); |
| 203 str += ASCIIToUTF16(it->is_discarded ? " discarded" : ""); | 206 str += ASCIIToUTF16(it->is_discarded ? " discarded" : ""); |
| 204 titles.push_back(str); | 207 titles.push_back(str); |
| 205 } | 208 } |
| 206 return titles; | 209 return titles; |
| 207 } | 210 } |
| 208 | 211 |
| 209 // TODO(jamescook): This should consider tabs with references to other tabs, | 212 // TODO(jamescook): This should consider tabs with references to other tabs, |
| 210 // such as tabs created with JavaScript window.open(). We might want to | 213 // such as tabs created with JavaScript window.open(). We might want to |
| 211 // discard the entire set together, or use that in the priority computation. | 214 // discard the entire set together, or use that in the priority computation. |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 225 return false; | 228 return false; |
| 226 } | 229 } |
| 227 | 230 |
| 228 void OomPriorityManager::LogMemoryAndDiscardTab() { | 231 void OomPriorityManager::LogMemoryAndDiscardTab() { |
| 229 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 230 // Deletes itself upon completion. | 233 // Deletes itself upon completion. |
| 231 OomMemoryDetails* details = new OomMemoryDetails(); | 234 OomMemoryDetails* details = new OomMemoryDetails(); |
| 232 details->StartFetch(MemoryDetails::SKIP_USER_METRICS); | 235 details->StartFetch(MemoryDetails::SKIP_USER_METRICS); |
| 233 } | 236 } |
| 234 | 237 |
| 238 /////////////////////////////////////////////////////////////////////////////// | |
| 239 // OomPriorityManager, private: | |
| 240 | |
| 241 // static | |
| 242 bool OomPriorityManager::IsReloadableUI(const GURL& url) { | |
| 243 // There are many chrome:// UI URLs, but only look for the ones that users | |
| 244 // are likely to have open. Most of the benefit is the from NTP URL. | |
| 245 const char* kReloadableUrlPrefixes[] = { | |
| 246 chrome::kChromeUIDownloadsURL, | |
| 247 chrome::kChromeUIHistoryURL, | |
| 248 chrome::kChromeUINewTabURL, | |
| 249 chrome::kChromeUISettingsURL, | |
|
Dan Beam
2016/06/01 17:30:36
why wouldn't we use WebUIControllerFactoryRegistry
| |
| 250 }; | |
| 251 // Prefix-match against the table above. Use strncmp to avoid allocating | |
| 252 // memory to convert the URL prefix constants into std::strings. | |
| 253 for (size_t i = 0; i < arraysize(kReloadableUrlPrefixes); ++i) { | |
| 254 if (!strncmp(url.spec().c_str(), | |
| 255 kReloadableUrlPrefixes[i], | |
| 256 strlen(kReloadableUrlPrefixes[i]))) | |
| 257 return true; | |
| 258 } | |
| 259 return false; | |
| 260 } | |
| 261 | |
| 235 bool OomPriorityManager::DiscardTabById(int64 target_web_contents_id) { | 262 bool OomPriorityManager::DiscardTabById(int64 target_web_contents_id) { |
| 236 for (BrowserList::const_iterator browser_iterator = BrowserList::begin(); | 263 for (BrowserList::const_iterator browser_iterator = BrowserList::begin(); |
| 237 browser_iterator != BrowserList::end(); ++browser_iterator) { | 264 browser_iterator != BrowserList::end(); ++browser_iterator) { |
| 238 Browser* browser = *browser_iterator; | 265 Browser* browser = *browser_iterator; |
| 239 TabStripModel* model = browser->tab_strip_model(); | 266 TabStripModel* model = browser->tab_strip_model(); |
| 240 for (int idx = 0; idx < model->count(); idx++) { | 267 for (int idx = 0; idx < model->count(); idx++) { |
| 241 // Can't discard tabs that are already discarded or active. | 268 // Can't discard tabs that are already discarded or active. |
| 242 if (model->IsTabDiscarded(idx) || (model->active_index() == idx)) | 269 if (model->IsTabDiscarded(idx) || (model->active_index() == idx)) |
| 243 continue; | 270 continue; |
| 244 WebContents* web_contents = model->GetWebContentsAt(idx); | 271 WebContents* web_contents = model->GetWebContentsAt(idx); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 325 } | 352 } |
| 326 | 353 |
| 327 // Returns true if |first| is considered less desirable to be killed | 354 // Returns true if |first| is considered less desirable to be killed |
| 328 // than |second|. | 355 // than |second|. |
| 329 bool OomPriorityManager::CompareTabStats(TabStats first, | 356 bool OomPriorityManager::CompareTabStats(TabStats first, |
| 330 TabStats second) { | 357 TabStats second) { |
| 331 // Being currently selected is most important to protect. | 358 // Being currently selected is most important to protect. |
| 332 if (first.is_selected != second.is_selected) | 359 if (first.is_selected != second.is_selected) |
| 333 return first.is_selected; | 360 return first.is_selected; |
| 334 | 361 |
| 362 // Tab with internal web UI like NTP or Settings are good choices to discard, | |
| 363 // so protect non-Web UI and let the other conditionals finish the sort. | |
| 364 if (first.is_reloadable_ui != second.is_reloadable_ui) | |
| 365 return !first.is_reloadable_ui; | |
| 366 | |
| 335 // Being pinned is important to protect. | 367 // Being pinned is important to protect. |
| 336 if (first.is_pinned != second.is_pinned) | 368 if (first.is_pinned != second.is_pinned) |
| 337 return first.is_pinned; | 369 return first.is_pinned; |
| 338 | 370 |
| 339 // Being an app is important too, as you're the only visible surface in the | 371 // Being an app is important too, as you're the only visible surface in the |
| 340 // window and we don't want to discard that. | 372 // window and we don't want to discard that. |
| 341 if (first.is_app != second.is_app) | 373 if (first.is_app != second.is_app) |
| 342 return first.is_app; | 374 return first.is_app; |
| 343 | 375 |
| 344 // TODO(jamescook): Incorporate sudden_termination_allowed into the sort | 376 // TODO(jamescook): Incorporate sudden_termination_allowed into the sort |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 462 browser_iterator != BrowserList::end_last_active(); | 494 browser_iterator != BrowserList::end_last_active(); |
| 463 ++browser_iterator) { | 495 ++browser_iterator) { |
| 464 Browser* browser = *browser_iterator; | 496 Browser* browser = *browser_iterator; |
| 465 bool is_browser_for_app = browser->is_app(); | 497 bool is_browser_for_app = browser->is_app(); |
| 466 const TabStripModel* model = browser->tab_strip_model(); | 498 const TabStripModel* model = browser->tab_strip_model(); |
| 467 for (int i = 0; i < model->count(); i++) { | 499 for (int i = 0; i < model->count(); i++) { |
| 468 WebContents* contents = model->GetWebContentsAt(i); | 500 WebContents* contents = model->GetWebContentsAt(i); |
| 469 if (!contents->IsCrashed()) { | 501 if (!contents->IsCrashed()) { |
| 470 TabStats stats; | 502 TabStats stats; |
| 471 stats.is_app = is_browser_for_app; | 503 stats.is_app = is_browser_for_app; |
| 504 stats.is_reloadable_ui = IsReloadableUI(contents->GetURL()); | |
| 472 stats.is_pinned = model->IsTabPinned(i); | 505 stats.is_pinned = model->IsTabPinned(i); |
| 473 stats.is_selected = browser_active && model->IsTabSelected(i); | 506 stats.is_selected = browser_active && model->IsTabSelected(i); |
| 474 stats.is_discarded = model->IsTabDiscarded(i); | 507 stats.is_discarded = model->IsTabDiscarded(i); |
| 475 stats.last_selected = contents->GetLastSelectedTime(); | 508 stats.last_selected = contents->GetLastSelectedTime(); |
| 476 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle(); | 509 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle(); |
| 477 stats.title = contents->GetTitle(); | 510 stats.title = contents->GetTitle(); |
| 478 stats.tab_contents_id = IdFromWebContents(contents); | 511 stats.tab_contents_id = IdFromWebContents(contents); |
| 479 stats_list.push_back(stats); | 512 stats_list.push_back(stats); |
| 480 } | 513 } |
| 481 } | 514 } |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 532 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore( | 565 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore( |
| 533 iterator->renderer_handle, score); | 566 iterator->renderer_handle, score); |
| 534 pid_to_oom_score_[iterator->renderer_handle] = score; | 567 pid_to_oom_score_[iterator->renderer_handle] = score; |
| 535 } | 568 } |
| 536 priority += priority_increment; | 569 priority += priority_increment; |
| 537 } | 570 } |
| 538 } | 571 } |
| 539 } | 572 } |
| 540 | 573 |
| 541 } // namespace chromeos | 574 } // namespace chromeos |
| OLD | NEW |