• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 CONTENT_BROWSER_HISTOGRAM_SYNCHRONIZER_H_
6 #define CONTENT_BROWSER_HISTOGRAM_SYNCHRONIZER_H_
7 
8 #include <string>
9 #include <vector>
10 
11 #include "base/basictypes.h"
12 #include "base/callback.h"
13 #include "base/memory/singleton.h"
14 #include "base/synchronization/lock.h"
15 #include "base/time/time.h"
16 #include "content/browser/histogram_subscriber.h"
17 
18 namespace base {
19 class MessageLoop;
20 }
21 
22 namespace content {
23 
24 // This class maintains state that is used to upload histogram data from the
25 // various child processes, into the browser process. Such transactions are
26 // usually instigated by the browser. In general, a child process will respond
27 // by gathering snapshots of all internal histograms, calculating what has
28 // changed since its last upload, and transmitting a pickled collection of
29 // deltas.
30 //
31 // There are actually two modes of update request.  One is synchronous (and
32 // blocks the UI thread, waiting to populate an about:histograms tab) and the
33 // other is asynchronous, and used by the metrics services in preparation for a
34 // log upload.
35 //
36 // To assure that all the processes have responded, a counter is maintained to
37 // indicate the number of pending (not yet responsive) processes. To avoid
38 // confusion about a response (i.e., is the process responding to a current
39 // request for an update, or to an old request for an update) we tag each group
40 // of requests with a sequence number. When an update arrives we can ignore it
41 // (relative to the counter) if it does not relate to a current outstanding
42 // sequence number.
43 //
44 // There is one final mode of use, where a renderer spontaneously decides to
45 // transmit a collection of histogram data.  This is designed for use when the
46 // renderer is terminating.  Unfortunately, renders may be terminated without
47 // warning, and the best we can do is periodically acquire data from a tab, such
48 // as when a page load has completed.  In this mode, the renderer uses a
49 // reserved sequence number, different from any sequence number that might be
50 // specified by a browser request.  Since this sequence number can't match an
51 // outstanding sequence number, the pickled data is accepted into the browser,
52 // but there is no impact on the counters.
53 
54 class HistogramSynchronizer : public HistogramSubscriber {
55  public:
56   enum ProcessHistogramRequester {
57     UNKNOWN,
58     ASYNC_HISTOGRAMS,
59   };
60 
61   // Return pointer to the singleton instance for the current process, or NULL
62   // if none.
63   static HistogramSynchronizer* GetInstance();
64 
65   // Contact all processes, and get them to upload to the browser any/all
66   // changes to histograms. This method is called from about:histograms.
67   static void FetchHistograms();
68 
69   // Contact all child processes, and get them to upload to the browser any/all
70   // changes to histograms.  When all changes have been acquired, or when the
71   // wait time expires (whichever is sooner), post the callback to the
72   // specified message loop. Note the callback is posted exactly once.
73   static void FetchHistogramsAsynchronously(base::MessageLoop* callback_thread,
74                                             const base::Closure& callback,
75                                             base::TimeDelta wait_time);
76 
77  private:
78   friend struct DefaultSingletonTraits<HistogramSynchronizer>;
79 
80   class RequestContext;
81 
82   HistogramSynchronizer();
83   virtual ~HistogramSynchronizer();
84 
85   // Establish a new sequence number, and use it to notify all processes
86   // (renderers, plugins, GPU, etc) of the need to supply, to the browser,
87   // any/all changes to their histograms. |wait_time| specifies the amount of
88   // time to wait before cancelling the requests for non-responsive processes.
89   void RegisterAndNotifyAllProcesses(ProcessHistogramRequester requester,
90                                      base::TimeDelta wait_time);
91 
92   // -------------------------------------------------------
93   // HistogramSubscriber methods for browser child processes
94   // -------------------------------------------------------
95 
96   // Update the number of pending processes for the given |sequence_number|.
97   // This is called on UI thread.
98   virtual void OnPendingProcesses(int sequence_number,
99                                   int pending_processes,
100                                   bool end) OVERRIDE;
101 
102   // Send histogram_data back to caller and also record that we are waiting
103   // for one less histogram data from child process for the given sequence
104   // number. This method is accessible on UI thread.
105   virtual void OnHistogramDataCollected(
106       int sequence_number,
107       const std::vector<std::string>& pickled_histograms) OVERRIDE;
108 
109   // Set the callback_thread_ and callback_ members. If these members already
110   // had values, then as a side effect, post the old callback_ to the old
111   // callaback_thread_.  This side effect should not generally happen, but is in
112   // place to assure correctness (that any tasks that were set, are eventually
113   // called, and never merely discarded).
114   void SetCallbackTaskAndThread(base::MessageLoop* callback_thread,
115                                 const base::Closure& callback);
116 
117   void ForceHistogramSynchronizationDoneCallback(int sequence_number);
118 
119   // Internal helper function, to post task, and record callback stats.
120   void InternalPostTask(base::MessageLoop* thread,
121                         const base::Closure& callback);
122 
123   // Gets a new sequence number to be sent to processes from browser process.
124   int GetNextAvailableSequenceNumber(ProcessHistogramRequester requester);
125 
126   // This lock_ protects access to all members.
127   base::Lock lock_;
128 
129   // When a request is made to asynchronously update the histograms, we store
130   // the task and thread we use to post a completion notification in
131   // callback_ and callback_thread_.
132   base::Closure callback_;
133   base::MessageLoop* callback_thread_;
134 
135   // We don't track the actual processes that are contacted for an update, only
136   // the count of the number of processes, and we can sometimes time-out and
137   // give up on a "slow to respond" process.  We use a sequence_number to be
138   // sure a response from a process is associated with the current round of
139   // requests (and not merely a VERY belated prior response).
140   // All sequence numbers used are non-negative.
141   // last_used_sequence_number_ is the most recently used number (used to avoid
142   // reuse for a long time).
143   int last_used_sequence_number_;
144 
145   // The sequence number used by the most recent asynchronous update request to
146   // contact all processes.
147   int async_sequence_number_;
148 
149   DISALLOW_COPY_AND_ASSIGN(HistogramSynchronizer);
150 };
151 
152 }  // namespace content
153 
154 #endif  // CONTENT_BROWSER_HISTOGRAM_SYNCHRONIZER_H_
155