Home | History | Annotate | Download | only in memory
      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