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

Side by Side Diff: chrome/browser/oom_priority_manager.cc

Issue 3235007: This adds periodic OOM score adjustment, based on the last access time (Closed)
Patch Set: Final review changes Created 10 years, 3 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 | « chrome/browser/oom_priority_manager.h ('k') | chrome/browser/tab_contents/tab_contents.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/oom_priority_manager.h"
6
7 #include <list>
8
9 #include "base/process.h"
10 #include "base/process_util.h"
11 #include "base/thread.h"
12 #include "build/build_config.h"
13 #include "chrome/browser/browser_list.h"
14 #include "chrome/browser/chrome_thread.h"
15 #include "chrome/browser/renderer_host/render_process_host.h"
16 #include "chrome/browser/tab_contents/tab_contents.h"
17 #include "chrome/browser/tabs/tab_strip_model.h"
18 #include "chrome/browser/zygote_host_linux.h"
19
20 #if !defined(OS_CHROMEOS)
21 #error This file only meant to be compiled on ChromeOS
22 #endif
23
24 using base::TimeDelta;
25 using base::TimeTicks;
26 using base::ProcessHandle;
27 using base::ProcessMetrics;
28
29 namespace browser {
30
31 // The default interval in seconds after which to adjust the oom_adj
32 // value.
33 #define ADJUSTMENT_INTERVAL_SECONDS 10
34
35 // The default interval in minutes for considering activation times
36 // "equal".
37 #define BUCKET_INTERVAL_MINUTES 10
38
39 OomPriorityManager::OomPriorityManager() {
40 StartTimer();
41 }
42
43 OomPriorityManager::~OomPriorityManager() {
44 StopTimer();
45 }
46
47 void OomPriorityManager::StartTimer() {
48 if (!timer_.IsRunning()) {
49 timer_.Start(TimeDelta::FromSeconds(ADJUSTMENT_INTERVAL_SECONDS),
50 this,
51 &OomPriorityManager::AdjustOomPriorities);
52 }
53 }
54
55 void OomPriorityManager::StopTimer() {
56 timer_.Stop();
57 }
58
59
60 namespace {
61 struct RendererStats {
62 bool is_pinned;
63 TimeTicks last_selected;
64 size_t memory_used;
65 ProcessHandle renderer_handle;
66 };
67
68 // Returns true if |first| is considered less desirable to be killed
69 // than |second|.
70 bool SortRendererStats(RendererStats first, RendererStats second) {
71 // The size of the slop in comparing activation times. [This is
72 // allocated here to avoid static initialization at startup time.]
73 static const int64 kTimeBucketInterval =
74 TimeDelta::FromMinutes(BUCKET_INTERVAL_MINUTES).ToInternalValue();
75
76 // Being pinned is most important.
77 if (first.is_pinned != second.is_pinned)
78 return first.is_pinned == true;
79
80 // We want to be a little "fuzzy" when we compare these, because
81 // it's not really possible for the times to be identical, but if
82 // the user selected two tabs at about the same time, we still want
83 // to take the one that uses more memory.
84 if (abs((first.last_selected - second.last_selected).ToInternalValue()) <
85 kTimeBucketInterval)
86 return first.last_selected < second.last_selected;
87
88 return first.memory_used < second.memory_used;
89 }
90 } // anonymous namespace
91
92 // Post a new task for the file thread to actually adjust the priorities.
93 void OomPriorityManager::AdjustOomPriorities() {
94 ChromeThread::PostTask(
95 ChromeThread::FILE, FROM_HERE,
96 NewRunnableMethod(this, &OomPriorityManager::DoAdjustOomPriorities));
97 }
98
99 // Here we collect all the information we need to sort the existing
100 // renderers in priority order, and hand out oom_adj scores based on
101 // that sort order.
102 //
103 // Things we need to collect:
104 // 1) whether or not a tab is pinned
105 // 2) last time a tab was selected
106 // 3) size in memory of a tab
107 void OomPriorityManager::DoAdjustOomPriorities() {
108 std::list<RendererStats> renderer_stats;
109
110 if (BrowserList::size() == 0)
111 return;
112
113 for (BrowserList::const_iterator browser_iterator = BrowserList::begin();
114 browser_iterator != BrowserList::end(); ++browser_iterator) {
115 Browser* browser = *browser_iterator;
116 const TabStripModel* model = browser->tabstrip_model();
117 for (int i = 0; i < model->count(); i++) {
118 TabContents* contents = model->GetTabContentsAt(i);
119 RendererStats stats;
120 stats.last_selected = contents->last_selected_time();
121 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle();
122 scoped_ptr<ProcessMetrics> metrics(
123 ProcessMetrics::CreateProcessMetrics(stats.renderer_handle));
124
125 base::WorkingSetKBytes working_set_kbytes;
126 if (metrics->GetWorkingSetKBytes(&working_set_kbytes)) {
127 // We use the proportional set size (PSS) to calculate memory
128 // usage "badness" on Linux.
129 stats.memory_used = working_set_kbytes.shared * 1024;
130 } else {
131 // and if for some reason we can't get PSS, we revert to using
132 // resident set size (RSS).
133 stats.memory_used = metrics->GetWorkingSetSize();
134 }
135
136 stats.is_pinned = model->IsTabPinned(i);
137 renderer_stats.push_back(stats);
138 }
139 }
140
141 // Now we sort the data we collected so that least desirable to be
142 // killed is first, most desirable is last.
143 renderer_stats.sort(SortRendererStats);
144
145 // Now we assign priorities based on the sorted list. We're
146 // assigning priorities in the range of 5 to 10. oom_adj takes
147 // values from -17 to 15. Negative values are reserved for system
148 // processes, and we want to give some room on either side of the
149 // range we're using to allow for things that want to be above or
150 // below the renderers in priority, so 5 to 10 gives us some
151 // variation in priority without taking up the whole range. In the
152 // end, however, it's a pretty arbitrary range to use. Higher
153 // values are more likely to be killed by the OOM killer.
154 const int kMinPriority = 5;
155 const int kMaxPriority = 10;
156 const int kPriorityRange = kMaxPriority - kMinPriority;
157 float priority_increment =
158 static_cast<float>(kPriorityRange) / renderer_stats.size();
159 float priority = kMinPriority;
160 for (std::list<RendererStats>::iterator iterator = renderer_stats.begin();
161 iterator != renderer_stats.end(); ++iterator) {
162 Singleton<ZygoteHost>()->AdjustRendererOOMScore(
163 iterator->renderer_handle,
164 static_cast<int>(priority + 0.5f));
165 priority += priority_increment;
166 }
167 }
168
169 } // namespace browser
OLDNEW
« no previous file with comments | « chrome/browser/oom_priority_manager.h ('k') | chrome/browser/tab_contents/tab_contents.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698