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_MEMORY_DETAILS_H_
6#define CHROME_BROWSER_MEMORY_DETAILS_H_
7
8#include <map>
9#include <vector>
10
11#include "base/memory/ref_counted.h"
12#include "base/process/process_handle.h"
13#include "base/process/process_metrics.h"
14#include "base/strings/string16.h"
15#include "base/time/time.h"
16#include "chrome/browser/site_details.h"
17#include "content/public/common/process_type.h"
18
19// We collect data about each browser process.  A browser may
20// have multiple processes (of course!).  Even IE has multiple
21// processes these days.
22struct ProcessMemoryInformation {
23  // NOTE: Do not remove or reorder the elements in this enum, and only add new
24  // items at the end. We depend on these specific values in a histogram.
25  enum RendererProcessType {
26    RENDERER_UNKNOWN = 0,
27    RENDERER_NORMAL,
28    RENDERER_CHROME,        // WebUI (chrome:// URL)
29    RENDERER_EXTENSION,     // chrome-extension://
30    RENDERER_DEVTOOLS,      // Web inspector
31    RENDERER_INTERSTITIAL,  // malware/phishing interstitial
32    RENDERER_BACKGROUND_APP // hosted app background page
33  };
34
35  static std::string GetRendererTypeNameInEnglish(RendererProcessType type);
36  static std::string GetFullTypeNameInEnglish(
37      int process_type,
38      RendererProcessType rtype);
39
40  ProcessMemoryInformation();
41  ~ProcessMemoryInformation();
42
43  // Default ordering is by private memory consumption.
44  bool operator<(const ProcessMemoryInformation& rhs) const;
45
46  // The process id.
47  base::ProcessId pid;
48  // The working set information.
49  base::WorkingSetKBytes working_set;
50  // The committed bytes.
51  base::CommittedKBytes committed;
52  // The process version
53  base::string16 version;
54  // The process product name.
55  base::string16 product_name;
56  // The number of processes which this memory represents.
57  int num_processes;
58  // A process is a diagnostics process if it is rendering about:memory.
59  // Mark this specially so that it can avoid counting it in its own
60  // results.
61  bool is_diagnostics;
62  // If this is a child process of Chrome, what type (i.e. plugin) it is.
63  int process_type;
64  // If this is a renderer process, what type it is.
65  RendererProcessType renderer_type;
66  // A collection of titles used, i.e. for a tab it'll show all the page titles.
67  std::vector<base::string16> titles;
68};
69
70typedef std::vector<ProcessMemoryInformation> ProcessMemoryInformationList;
71
72// Browser Process Information.
73struct ProcessData {
74  ProcessData();
75  ProcessData(const ProcessData& rhs);
76  ~ProcessData();
77  ProcessData& operator=(const ProcessData& rhs);
78
79  base::string16 name;
80  base::string16 process_name;
81  ProcessMemoryInformationList processes;
82
83  // Track site data for predicting process counts with out-of-process iframes.
84  // See site_details.h.
85  BrowserContextSiteDataMap site_data;
86};
87
88// MemoryGrowthTracker tracks latest metrics about record time and memory usage
89// at that time per process.
90class MemoryGrowthTracker {
91 public:
92  MemoryGrowthTracker();
93  ~MemoryGrowthTracker();
94
95  // If 30 minutes have passed since last UMA record, UpdateSample() computes
96  // a difference between current memory usage |sample| of process |pid| and
97  // stored memory usage at the time of last UMA record. Then, it updates the
98  // stored memory usage to |sample|, stores the difference in |diff| and
99  // returns true.
100  // If no memory usage of |pid| has not been recorded so far or 30 minutes
101  // have not passed since last record, it just returns false.
102  // |sample| is memory usage in kB.
103  bool UpdateSample(base::ProcessId pid, int sample, int* diff);
104
105 private:
106  // Latest metrics about record time and memory usage at that time per process.
107  // The second values of |memory_sizes_| are in kB.
108  std::map<base::ProcessId, base::TimeTicks> times_;
109  std::map<base::ProcessId, int> memory_sizes_;
110
111  DISALLOW_COPY_AND_ASSIGN(MemoryGrowthTracker);
112};
113
114#if defined(OS_MACOSX)
115class ProcessInfoSnapshot;
116#endif
117
118// MemoryDetails fetches memory details about current running browsers.
119// Because this data can only be fetched asynchronously, callers use
120// this class via a callback.
121//
122// Example usage:
123//
124//    class MyMemoryDetailConsumer : public MemoryDetails {
125//
126//      MyMemoryDetailConsumer() {
127//        // Anything but |StartFetch()|.
128//      }
129//
130//      // (Or just call |StartFetch()| explicitly if there's nothing else to
131//      // do.)
132//      void StartDoingStuff() {
133//        StartFetch();  // Starts fetching details.
134//        // Etc.
135//      }
136//
137//      // Your other class stuff here
138//
139//      virtual void OnDetailsAvailable() {
140//        // do work with memory info here
141//      }
142//    }
143class MemoryDetails : public base::RefCountedThreadSafe<MemoryDetails> {
144 public:
145  enum UserMetricsMode {
146    UPDATE_USER_METRICS,  // Update UMA memory histograms with results.
147    SKIP_USER_METRICS
148  };
149
150  // Constructor.
151  MemoryDetails();
152
153  // Access to the process detail information.  This data is only available
154  // after OnDetailsAvailable() has been called.
155  const std::vector<ProcessData>& processes() { return process_data_; }
156
157  // Initiate updating the current memory details.  These are fetched
158  // asynchronously because data must be collected from multiple threads.
159  // Updates UMA memory histograms if |mode| is UPDATE_USER_METRICS.
160  // OnDetailsAvailable will be called when this process is complete.
161  void StartFetch(UserMetricsMode user_metrics_mode);
162
163  virtual void OnDetailsAvailable() = 0;
164
165  // Returns a string summarizing memory usage of the Chrome browser process
166  // and all sub-processes, suitable for logging.
167  std::string ToLogString();
168
169 protected:
170  friend class base::RefCountedThreadSafe<MemoryDetails>;
171
172  virtual ~MemoryDetails();
173
174  // Set MemoryGrowthTracker into MemoryDetails.
175  void SetMemoryGrowthTracker(MemoryGrowthTracker* memory_growth_tracker);
176
177 private:
178  // Collect child process information on the IO thread.  This is needed because
179  // information about some child process types (i.e. plugins) can only be taken
180  // on that thread.  The data will be used by about:memory.  When finished,
181  // invokes back to the file thread to run the rest of the about:memory
182  // functionality.
183  void CollectChildInfoOnIOThread();
184
185  // Collect current process information from the OS and store it
186  // for processing.  If data has already been collected, clears old
187  // data and re-collects the data.
188  // Note - this function enumerates memory details from many processes
189  // and is fairly expensive to run, hence it's run on the file thread.
190  // The parameter holds information about processes from the IO thread.
191  void CollectProcessData(const std::vector<ProcessMemoryInformation>&);
192
193#if defined(OS_MACOSX)
194  // A helper for |CollectProcessData()|, collecting data on the Chrome/Chromium
195  // process with PID |pid|. The collected data is added to the state of the
196  // object (in |process_data_|).
197  void CollectProcessDataChrome(
198      const std::vector<ProcessMemoryInformation>& child_info,
199      base::ProcessId pid,
200      const ProcessInfoSnapshot& process_info);
201#endif
202
203  // Collect child process information on the UI thread.  Information about
204  // renderer processes is only available there.
205  void CollectChildInfoOnUIThread();
206
207  // Updates the global histograms for tracking memory usage.
208  void UpdateHistograms();
209
210#if defined(OS_CHROMEOS)
211  void UpdateSwapHistograms();
212#endif
213
214  // Returns a pointer to the ProcessData structure for Chrome.
215  ProcessData* ChromeBrowser();
216
217  std::vector<ProcessData> process_data_;
218
219  UserMetricsMode user_metrics_mode_;
220
221  // A pointer to MemoryGrowthTracker which is contained in a longer-lived
222  // owner of MemoryDetails, for example, ChromeMetricsServiceClient.
223  // The pointer is NULL by default and set by SetMemoryGrowthTracker().
224  // If it is NULL, nothing is tracked.
225  MemoryGrowthTracker* memory_growth_tracker_;
226
227#if defined(OS_CHROMEOS)
228  base::SwapInfo swap_info_;
229#endif
230
231  DISALLOW_COPY_AND_ASSIGN(MemoryDetails);
232};
233
234#endif  // CHROME_BROWSER_MEMORY_DETAILS_H_
235