oom_priority_manager.h revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_CHROMEOS_MEMORY_OOM_PRIORITY_MANAGER_H_
6#define CHROME_BROWSER_CHROMEOS_MEMORY_OOM_PRIORITY_MANAGER_H_
7
8#include <vector>
9
10#include "base/compiler_specific.h"
11#include "base/containers/hash_tables.h"
12#include "base/gtest_prod_util.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/process/process.h"
15#include "base/strings/string16.h"
16#include "base/synchronization/lock.h"
17#include "base/time/time.h"
18#include "base/timer/timer.h"
19#include "chromeos/memory/low_memory_listener_delegate.h"
20#include "content/public/browser/notification_observer.h"
21#include "content/public/browser/notification_registrar.h"
22
23class GURL;
24
25namespace chromeos {
26
27class LowMemoryListener;
28
29// The OomPriorityManager periodically checks (see
30// ADJUSTMENT_INTERVAL_SECONDS in the source) the status of renderers
31// and adjusts the out of memory (OOM) adjustment value (in
32// /proc/<pid>/oom_score_adj) of the renderers so that they match the
33// algorithm embedded here for priority in being killed upon OOM
34// conditions.
35//
36// The algorithm used favors killing tabs that are not selected, not pinned,
37// and have been idle for longest, in that order of priority.
38class OomPriorityManager : public content::NotificationObserver,
39                           public LowMemoryListenerDelegate {
40 public:
41  OomPriorityManager();
42  virtual ~OomPriorityManager();
43
44  // Number of discard events since Chrome started.
45  int discard_count() const { return discard_count_; }
46
47  // See member comment.
48  bool recent_tab_discard() const { return recent_tab_discard_; }
49
50  void Start();
51  void Stop();
52
53  // Returns list of tab titles sorted from most interesting (don't kill)
54  // to least interesting (OK to kill).
55  std::vector<string16> GetTabTitles();
56
57  // Discards a tab to free the memory occupied by its renderer.
58  // Tab still exists in the tab-strip; clicking on it will reload it.
59  // Returns true if it successfully found a tab and discarded it.
60  bool DiscardTab();
61
62  // Log memory statistics for the running processes, then discards a tab.
63  // Tab discard happens sometime later, as collecting the statistics touches
64  // multiple threads and takes time.
65  void LogMemoryAndDiscardTab();
66
67 private:
68  friend class OomMemoryDetails;
69  FRIEND_TEST_ALL_PREFIXES(OomPriorityManagerTest, Comparator);
70  FRIEND_TEST_ALL_PREFIXES(OomPriorityManagerTest, IsReloadableUI);
71
72  struct TabStats {
73    TabStats();
74    ~TabStats();
75    bool is_app;  // browser window is an app
76    bool is_reloadable_ui;  // Reloadable web UI page, like NTP or Settings.
77    bool is_playing_audio;
78    bool is_pinned;
79    bool is_selected;  // selected in the currently active browser window
80    bool is_discarded;
81    base::TimeTicks last_selected;
82    base::ProcessHandle renderer_handle;
83    string16 title;
84    int64 tab_contents_id;  // unique ID per WebContents
85  };
86  typedef std::vector<TabStats> TabStatsList;
87
88  // Returns true if the |url| represents an internal Chrome web UI page that
89  // can be easily reloaded and hence makes a good choice to discard.
90  static bool IsReloadableUI(const GURL& url);
91
92  // Discards a tab with the given unique ID.  Returns true if discard occurred.
93  bool DiscardTabById(int64 target_web_contents_id);
94
95  // Records UMA histogram statistics for a tab discard. We record statistics
96  // for user triggered discards via chrome://discards/ because that allows us
97  // to manually test the system.
98  void RecordDiscardStatistics();
99
100  // Record whether we ran out of memory during a recent time interval.
101  // This allows us to normalize low memory statistics versus usage.
102  void RecordRecentTabDiscard();
103
104  // Purges data structures in the browser that can be easily recomputed.
105  void PurgeBrowserMemory();
106
107  // Returns the number of tabs open in all browser instances.
108  int GetTabCount() const;
109
110  TabStatsList GetTabStatsOnUIThread();
111
112  // Called when the timer fires, sets oom_adjust_score for all renderers.
113  void AdjustOomPriorities();
114
115  // Called by AdjustOomPriorities.
116  void AdjustOomPrioritiesOnFileThread(TabStatsList stats_list);
117
118  // Posts AdjustFocusedTabScore task to the file thread.
119  void OnFocusTabScoreAdjustmentTimeout();
120
121  // Sets the score of the focused tab to the least value.
122  void AdjustFocusedTabScoreOnFileThread();
123
124  static bool CompareTabStats(TabStats first, TabStats second);
125
126  // NotificationObserver overrides:
127  virtual void Observe(int type,
128                       const content::NotificationSource& source,
129                       const content::NotificationDetails& details) OVERRIDE;
130
131  // LowMemoryListenerDelegate overrides:
132  virtual void OnMemoryLow() OVERRIDE;
133
134  base::RepeatingTimer<OomPriorityManager> timer_;
135  base::OneShotTimer<OomPriorityManager> focus_tab_score_adjust_timer_;
136  base::RepeatingTimer<OomPriorityManager> recent_tab_discard_timer_;
137  content::NotificationRegistrar registrar_;
138
139  // This lock is for pid_to_oom_score_ and focus_tab_pid_.
140  base::Lock pid_to_oom_score_lock_;
141  // map maintaining the process - oom_score mapping.
142  typedef base::hash_map<base::ProcessHandle, int> ProcessScoreMap;
143  ProcessScoreMap pid_to_oom_score_;
144  base::ProcessHandle focused_tab_pid_;
145
146  // Observer for the kernel low memory signal.
147  scoped_ptr<LowMemoryListener> low_memory_listener_;
148
149  // Wall-clock time when the priority manager started running.
150  base::TimeTicks start_time_;
151
152  // Wall-clock time of last tab discard during this browsing session, or 0 if
153  // no discard has happened yet.
154  base::TimeTicks last_discard_time_;
155
156  // Wall-clock time of last priority adjustment, used to correct the above
157  // times for discontinuities caused by suspend/resume.
158  base::TimeTicks last_adjust_time_;
159
160  // Number of times we have discarded a tab, for statistics.
161  int discard_count_;
162
163  // Whether a tab discard event has occurred during the last time interval,
164  // used for statistics normalized by usage.
165  bool recent_tab_discard_;
166
167  DISALLOW_COPY_AND_ASSIGN(OomPriorityManager);
168};
169
170}  // namespace chromeos
171
172#endif  // CHROME_BROWSER_CHROMEOS_MEMORY_OOM_PRIORITY_MANAGER_H_
173