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