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