Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/oom_priority_manager.h" | 5 #include "chrome/browser/oom_priority_manager.h" |
| 6 | 6 |
| 7 #include <list> | 7 #include <list> |
| 8 | 8 |
| 9 #include "base/process.h" | 9 #include "base/process.h" |
| 10 #include "base/process_util.h" | 10 #include "base/process_util.h" |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 22 #error This file only meant to be compiled on ChromeOS | 22 #error This file only meant to be compiled on ChromeOS |
| 23 #endif | 23 #endif |
| 24 | 24 |
| 25 using base::TimeDelta; | 25 using base::TimeDelta; |
| 26 using base::TimeTicks; | 26 using base::TimeTicks; |
| 27 using base::ProcessHandle; | 27 using base::ProcessHandle; |
| 28 using base::ProcessMetrics; | 28 using base::ProcessMetrics; |
| 29 | 29 |
| 30 namespace browser { | 30 namespace browser { |
| 31 | 31 |
| 32 // The default interval in seconds after which to adjust the oom_adj | 32 // The default interval in seconds after which to adjust the oom_score_adj |
| 33 // value. | 33 // value. |
| 34 #define ADJUSTMENT_INTERVAL_SECONDS 10 | 34 #define ADJUSTMENT_INTERVAL_SECONDS 10 |
| 35 | 35 |
| 36 // The default interval in minutes for considering activation times | 36 // The default interval in minutes for considering activation times |
| 37 // "equal". | 37 // "equal". |
| 38 #define BUCKET_INTERVAL_MINUTES 10 | 38 #define BUCKET_INTERVAL_MINUTES 10 |
| 39 | 39 |
| 40 OomPriorityManager::OomPriorityManager() { | 40 OomPriorityManager::OomPriorityManager() { |
| 41 StartTimer(); | 41 StartTimer(); |
| 42 } | 42 } |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 59 | 59 |
| 60 // Returns true if |first| is considered less desirable to be killed | 60 // Returns true if |first| is considered less desirable to be killed |
| 61 // than |second|. | 61 // than |second|. |
| 62 bool OomPriorityManager::CompareRendererStats(RendererStats first, | 62 bool OomPriorityManager::CompareRendererStats(RendererStats first, |
| 63 RendererStats second) { | 63 RendererStats second) { |
| 64 // The size of the slop in comparing activation times. [This is | 64 // The size of the slop in comparing activation times. [This is |
| 65 // allocated here to avoid static initialization at startup time.] | 65 // allocated here to avoid static initialization at startup time.] |
| 66 static const int64 kTimeBucketInterval = | 66 static const int64 kTimeBucketInterval = |
| 67 TimeDelta::FromMinutes(BUCKET_INTERVAL_MINUTES).ToInternalValue(); | 67 TimeDelta::FromMinutes(BUCKET_INTERVAL_MINUTES).ToInternalValue(); |
| 68 | 68 |
| 69 // Being pinned is most important. | 69 // Being currently selected is most important. |
| 70 if (first.is_selected != second.is_selected) | |
| 71 return first.is_selected == true; | |
| 72 | |
| 73 // Being pinned is second most important. | |
| 70 if (first.is_pinned != second.is_pinned) | 74 if (first.is_pinned != second.is_pinned) |
| 71 return first.is_pinned == true; | 75 return first.is_pinned == true; |
| 72 | 76 |
| 73 // We want to be a little "fuzzy" when we compare these, because | 77 // We want to be a little "fuzzy" when we compare these, because |
| 74 // it's not really possible for the times to be identical, but if | 78 // it's not really possible for the times to be identical, but if |
| 75 // the user selected two tabs at about the same time, we still want | 79 // the user selected two tabs at about the same time, we still want |
| 76 // to take the one that uses more memory. | 80 // to take the one that uses more memory. |
| 77 if (abs((first.last_selected - second.last_selected).ToInternalValue()) < | 81 if (abs((first.last_selected - second.last_selected).ToInternalValue()) < |
| 78 kTimeBucketInterval) | 82 kTimeBucketInterval) |
| 79 return first.last_selected < second.last_selected; | 83 return first.last_selected < second.last_selected; |
| 80 | 84 |
| 81 return first.memory_used < second.memory_used; | 85 return first.memory_used < second.memory_used; |
| 82 } | 86 } |
| 83 | 87 |
| 84 // Here we collect most of the information we need to sort the | 88 // Here we collect most of the information we need to sort the |
| 85 // existing renderers in priority order, and hand out oom_adj scores | 89 // existing renderers in priority order, and hand out oom_score_adj |
| 86 // based on that sort order. | 90 // scores based on that sort order. |
| 87 // | 91 // |
| 88 // Things we need to collect on the browser thread (because | 92 // Things we need to collect on the browser thread (because |
| 89 // TabStripModel isn't thread safe): | 93 // TabStripModel isn't thread safe): |
| 90 // 1) whether or not a tab is pinned | 94 // 1) whether or not a tab is pinned |
| 91 // 2) last time a tab was selected | 95 // 2) last time a tab was selected |
| 96 // 3) is the tab currently selected | |
| 92 // | 97 // |
| 93 // We also need to collect: | 98 // We also need to collect: |
| 94 // 3) size in memory of a tab | 99 // 4) size in memory of a tab |
| 95 // But we do that in DoAdjustOomPriorities on the FILE thread so that | 100 // But we do that in DoAdjustOomPriorities on the FILE thread so that |
| 96 // we avoid jank, because it accesses /proc. | 101 // we avoid jank, because it accesses /proc. |
| 97 void OomPriorityManager::AdjustOomPriorities() { | 102 void OomPriorityManager::AdjustOomPriorities() { |
| 98 if (BrowserList::size() == 0) | 103 if (BrowserList::size() == 0) |
| 99 return; | 104 return; |
| 100 | 105 |
| 101 StatsList renderer_stats; | 106 StatsList renderer_stats; |
| 102 for (BrowserList::const_iterator browser_iterator = BrowserList::begin(); | 107 for (BrowserList::const_iterator browser_iterator = BrowserList::begin(); |
| 103 browser_iterator != BrowserList::end(); ++browser_iterator) { | 108 browser_iterator != BrowserList::end(); ++browser_iterator) { |
| 104 Browser* browser = *browser_iterator; | 109 Browser* browser = *browser_iterator; |
| 105 const TabStripModel* model = browser->tabstrip_model(); | 110 const TabStripModel* model = browser->tabstrip_model(); |
| 106 for (int i = 0; i < model->count(); i++) { | 111 for (int i = 0; i < model->count(); i++) { |
| 107 TabContents* contents = model->GetTabContentsAt(i)->tab_contents(); | 112 TabContents* contents = model->GetTabContentsAt(i)->tab_contents(); |
| 108 RendererStats stats; | 113 RendererStats stats; |
| 109 stats.last_selected = contents->last_selected_time(); | 114 stats.last_selected = contents->last_selected_time(); |
| 110 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle(); | 115 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle(); |
| 111 stats.is_pinned = model->IsTabPinned(i); | 116 stats.is_pinned = model->IsTabPinned(i); |
| 112 stats.memory_used = 0; // This gets calculated in DoAdjustOomPriorities. | 117 stats.memory_used = 0; // This gets calculated in DoAdjustOomPriorities. |
| 118 stats.is_selected = model->IsTabSelected(i); | |
| 113 renderer_stats.push_back(stats); | 119 renderer_stats.push_back(stats); |
| 114 } | 120 } |
| 115 } | 121 } |
| 116 | 122 |
| 117 BrowserThread::PostTask( | 123 BrowserThread::PostTask( |
| 118 BrowserThread::FILE, FROM_HERE, | 124 BrowserThread::FILE, FROM_HERE, |
| 119 NewRunnableMethod(this, &OomPriorityManager::DoAdjustOomPriorities, | 125 NewRunnableMethod(this, &OomPriorityManager::DoAdjustOomPriorities, |
| 120 renderer_stats)); | 126 renderer_stats)); |
| 121 } | 127 } |
| 122 | 128 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 138 // process is gone anyhow. | 144 // process is gone anyhow. |
| 139 stats_iter->memory_used = metrics->GetWorkingSetSize(); | 145 stats_iter->memory_used = metrics->GetWorkingSetSize(); |
| 140 } | 146 } |
| 141 } | 147 } |
| 142 | 148 |
| 143 // Now we sort the data we collected so that least desirable to be | 149 // Now we sort the data we collected so that least desirable to be |
| 144 // killed is first, most desirable is last. | 150 // killed is first, most desirable is last. |
| 145 renderer_stats.sort(OomPriorityManager::CompareRendererStats); | 151 renderer_stats.sort(OomPriorityManager::CompareRendererStats); |
| 146 | 152 |
| 147 // Now we assign priorities based on the sorted list. We're | 153 // Now we assign priorities based on the sorted list. We're |
| 148 // assigning priorities in the range of 5 to 10. oom_adj takes | 154 // assigning priorities in the range of 300 to 1000. oom_score_adj |
| 149 // values from -17 to 15. Negative values are reserved for system | 155 // takes values from -1000 to 1000. Negative values are reserved |
| 150 // processes, and we want to give some room on either side of the | 156 // for system processes, and we want to give some room below the |
| 151 // range we're using to allow for things that want to be above or | 157 // range we're using to allow for things that want to be above the |
| 152 // below the renderers in priority, so 5 to 10 gives us some | 158 // renderers in priority, so 300 to 1000 gives us some variation in |
| 153 // variation in priority without taking up the whole range. In the | 159 // priority without taking up the whole range. In the end, however, |
| 154 // end, however, it's a pretty arbitrary range to use. Higher | 160 // it's a pretty arbitrary range to use. Higher values are more |
| 155 // values are more likely to be killed by the OOM killer. We also | 161 // likely to be killed by the OOM killer. |
| 156 // remove any duplicate PIDs, leaving the most important of the | 162 // |
| 157 // duplicates. | 163 // We also remove any duplicate PIDs, leaving the most important |
| 158 const int kMinPriority = 5; | 164 // (least likely to be killed) of the duplicates, so that a |
| 159 const int kMaxPriority = 10; | 165 // particular renderer process takes on the oom_score_adj of the |
| 166 // least likely tab to be killed. | |
| 167 const int kMinPriority = 300; | |
| 168 const int kMaxPriority = 1000; | |
|
stevenjb
2011/08/18 00:20:07
It would be good to avoid having these constants d
Greg Spencer (Chromium)
2011/08/18 23:10:50
OK, I added two constants to chrome/common/chrome_
| |
| 160 const int kPriorityRange = kMaxPriority - kMinPriority; | 169 const int kPriorityRange = kMaxPriority - kMinPriority; |
| 161 float priority_increment = | 170 float priority_increment = |
| 162 static_cast<float>(kPriorityRange) / renderer_stats.size(); | 171 static_cast<float>(kPriorityRange) / renderer_stats.size(); |
| 163 float priority = kMinPriority; | 172 float priority = kMinPriority; |
| 164 std::set<base::ProcessHandle> already_seen; | 173 std::set<base::ProcessHandle> already_seen; |
| 165 for (StatsList::iterator iterator = renderer_stats.begin(); | 174 for (StatsList::iterator iterator = renderer_stats.begin(); |
| 166 iterator != renderer_stats.end(); ++iterator) { | 175 iterator != renderer_stats.end(); ++iterator) { |
| 167 if (already_seen.find(iterator->renderer_handle) == already_seen.end()) { | 176 if (already_seen.find(iterator->renderer_handle) == already_seen.end()) { |
| 168 already_seen.insert(iterator->renderer_handle); | 177 already_seen.insert(iterator->renderer_handle); |
| 169 ZygoteHost::GetInstance()->AdjustRendererOOMScore( | 178 ZygoteHost::GetInstance()->AdjustRendererOOMScore( |
| 170 iterator->renderer_handle, | 179 iterator->renderer_handle, |
| 171 static_cast<int>(priority + 0.5f)); | 180 static_cast<int>(priority + 0.5f)); |
| 172 priority += priority_increment; | 181 priority += priority_increment; |
| 173 } | 182 } |
| 174 } | 183 } |
| 175 } | 184 } |
| 176 | 185 |
| 177 } // namespace browser | 186 } // namespace browser |
| OLD | NEW |