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 |