| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_CHROMEOS_MEMORY_OOM_PRIORITY_MANAGER_H_ |
| #define CHROME_BROWSER_CHROMEOS_MEMORY_OOM_PRIORITY_MANAGER_H_ |
| |
| #include <vector> |
| |
| #include "base/compiler_specific.h" |
| #include "base/containers/hash_tables.h" |
| #include "base/gtest_prod_util.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/process/process.h" |
| #include "base/strings/string16.h" |
| #include "base/synchronization/lock.h" |
| #include "base/time/time.h" |
| #include "base/timer/timer.h" |
| #include "chromeos/memory/low_memory_listener_delegate.h" |
| #include "content/public/browser/notification_observer.h" |
| #include "content/public/browser/notification_registrar.h" |
| |
| class GURL; |
| |
| namespace chromeos { |
| |
| class LowMemoryListener; |
| |
| // The OomPriorityManager periodically checks (see |
| // ADJUSTMENT_INTERVAL_SECONDS in the source) the status of renderers |
| // and adjusts the out of memory (OOM) adjustment value (in |
| // /proc/<pid>/oom_score_adj) of the renderers so that they match the |
| // algorithm embedded here for priority in being killed upon OOM |
| // conditions. |
| // |
| // The algorithm used favors killing tabs that are not selected, not pinned, |
| // and have been idle for longest, in that order of priority. |
| class OomPriorityManager : public content::NotificationObserver, |
| public LowMemoryListenerDelegate { |
| public: |
| OomPriorityManager(); |
| virtual ~OomPriorityManager(); |
| |
| // Number of discard events since Chrome started. |
| int discard_count() const { return discard_count_; } |
| |
| // See member comment. |
| bool recent_tab_discard() const { return recent_tab_discard_; } |
| |
| void Start(); |
| void Stop(); |
| |
| // Returns list of tab titles sorted from most interesting (don't kill) |
| // to least interesting (OK to kill). |
| std::vector<string16> GetTabTitles(); |
| |
| // Discards a tab to free the memory occupied by its renderer. |
| // Tab still exists in the tab-strip; clicking on it will reload it. |
| // Returns true if it successfully found a tab and discarded it. |
| bool DiscardTab(); |
| |
| // Log memory statistics for the running processes, then discards a tab. |
| // Tab discard happens sometime later, as collecting the statistics touches |
| // multiple threads and takes time. |
| void LogMemoryAndDiscardTab(); |
| |
| private: |
| friend class OomMemoryDetails; |
| FRIEND_TEST_ALL_PREFIXES(OomPriorityManagerTest, Comparator); |
| FRIEND_TEST_ALL_PREFIXES(OomPriorityManagerTest, IsReloadableUI); |
| |
| struct TabStats { |
| TabStats(); |
| ~TabStats(); |
| bool is_app; // browser window is an app |
| bool is_reloadable_ui; // Reloadable web UI page, like NTP or Settings. |
| bool is_playing_audio; |
| bool is_pinned; |
| bool is_selected; // selected in the currently active browser window |
| bool is_discarded; |
| base::TimeTicks last_selected; |
| base::ProcessHandle renderer_handle; |
| string16 title; |
| int64 tab_contents_id; // unique ID per WebContents |
| }; |
| typedef std::vector<TabStats> TabStatsList; |
| |
| // Returns true if the |url| represents an internal Chrome web UI page that |
| // can be easily reloaded and hence makes a good choice to discard. |
| static bool IsReloadableUI(const GURL& url); |
| |
| // Discards a tab with the given unique ID. Returns true if discard occurred. |
| bool DiscardTabById(int64 target_web_contents_id); |
| |
| // Records UMA histogram statistics for a tab discard. We record statistics |
| // for user triggered discards via chrome://discards/ because that allows us |
| // to manually test the system. |
| void RecordDiscardStatistics(); |
| |
| // Record whether we ran out of memory during a recent time interval. |
| // This allows us to normalize low memory statistics versus usage. |
| void RecordRecentTabDiscard(); |
| |
| // Purges data structures in the browser that can be easily recomputed. |
| void PurgeBrowserMemory(); |
| |
| // Returns the number of tabs open in all browser instances. |
| int GetTabCount() const; |
| |
| TabStatsList GetTabStatsOnUIThread(); |
| |
| // Called when the timer fires, sets oom_adjust_score for all renderers. |
| void AdjustOomPriorities(); |
| |
| // Called by AdjustOomPriorities. |
| void AdjustOomPrioritiesOnFileThread(TabStatsList stats_list); |
| |
| // Posts AdjustFocusedTabScore task to the file thread. |
| void OnFocusTabScoreAdjustmentTimeout(); |
| |
| // Sets the score of the focused tab to the least value. |
| void AdjustFocusedTabScoreOnFileThread(); |
| |
| static bool CompareTabStats(TabStats first, TabStats second); |
| |
| // NotificationObserver overrides: |
| virtual void Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) OVERRIDE; |
| |
| // LowMemoryListenerDelegate overrides: |
| virtual void OnMemoryLow() OVERRIDE; |
| |
| base::RepeatingTimer<OomPriorityManager> timer_; |
| base::OneShotTimer<OomPriorityManager> focus_tab_score_adjust_timer_; |
| base::RepeatingTimer<OomPriorityManager> recent_tab_discard_timer_; |
| content::NotificationRegistrar registrar_; |
| |
| // This lock is for pid_to_oom_score_ and focus_tab_pid_. |
| base::Lock pid_to_oom_score_lock_; |
| // map maintaining the process - oom_score mapping. |
| typedef base::hash_map<base::ProcessHandle, int> ProcessScoreMap; |
| ProcessScoreMap pid_to_oom_score_; |
| base::ProcessHandle focused_tab_pid_; |
| |
| // Observer for the kernel low memory signal. |
| scoped_ptr<LowMemoryListener> low_memory_listener_; |
| |
| // Wall-clock time when the priority manager started running. |
| base::TimeTicks start_time_; |
| |
| // Wall-clock time of last tab discard during this browsing session, or 0 if |
| // no discard has happened yet. |
| base::TimeTicks last_discard_time_; |
| |
| // Wall-clock time of last priority adjustment, used to correct the above |
| // times for discontinuities caused by suspend/resume. |
| base::TimeTicks last_adjust_time_; |
| |
| // Number of times we have discarded a tab, for statistics. |
| int discard_count_; |
| |
| // Whether a tab discard event has occurred during the last time interval, |
| // used for statistics normalized by usage. |
| bool recent_tab_discard_; |
| |
| DISALLOW_COPY_AND_ASSIGN(OomPriorityManager); |
| }; |
| |
| } // namespace chromeos |
| |
| #endif // CHROME_BROWSER_CHROMEOS_MEMORY_OOM_PRIORITY_MANAGER_H_ |