This source file includes following definitions.
- processes_pending_
- RequestContext
- SetReceivedProcessGroupCount
- AddProcessesPending
- DecrementProcessesPending
- DeleteIfAllDone
- Register
- GetRequestContext
- Unregister
- OnShutdown
- async_sequence_number_
- GetInstance
- FetchHistograms
- FetchHistogramsAsynchronously
- FetchHistogramsAsynchronously
- RegisterAndNotifyAllProcesses
- OnPendingProcesses
- OnHistogramDataCollected
- SetCallbackTaskAndThread
- ForceHistogramSynchronizationDoneCallback
- InternalPostTask
- GetNextAvailableSequenceNumber
#include "content/browser/histogram_synchronizer.h"
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_delta_serialization.h"
#include "base/pickle.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "content/browser/histogram_controller.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/histogram_fetcher.h"
#include "content/public/common/content_constants.h"
using base::Time;
using base::TimeDelta;
using base::TimeTicks;
namespace {
static const int kNeverUsableSequenceNumber = -2;
}
namespace content {
class HistogramSynchronizer::RequestContext {
public:
typedef std::map<int, RequestContext*> RequestContextMap;
RequestContext(const base::Closure& callback, int sequence_number)
: callback_(callback),
sequence_number_(sequence_number),
received_process_group_count_(0),
processes_pending_(0) {
}
~RequestContext() {}
void SetReceivedProcessGroupCount(bool done) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
received_process_group_count_ = done;
}
void AddProcessesPending(int processes_pending) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
processes_pending_ += processes_pending;
}
void DecrementProcessesPending() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
--processes_pending_;
}
void DeleteIfAllDone() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (processes_pending_ <= 0 && received_process_group_count_)
RequestContext::Unregister(sequence_number_);
}
static void Register(const base::Closure& callback, int sequence_number) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
RequestContext* request = new RequestContext(callback, sequence_number);
outstanding_requests_.Get()[sequence_number] = request;
}
static RequestContext* GetRequestContext(int sequence_number) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
RequestContextMap::iterator it =
outstanding_requests_.Get().find(sequence_number);
if (it == outstanding_requests_.Get().end())
return NULL;
RequestContext* request = it->second;
DCHECK_EQ(sequence_number, request->sequence_number_);
return request;
}
static void Unregister(int sequence_number) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
RequestContextMap::iterator it =
outstanding_requests_.Get().find(sequence_number);
if (it == outstanding_requests_.Get().end())
return;
RequestContext* request = it->second;
DCHECK_EQ(sequence_number, request->sequence_number_);
bool received_process_group_count = request->received_process_group_count_;
int unresponsive_processes = request->processes_pending_;
request->callback_.Run();
delete request;
outstanding_requests_.Get().erase(it);
UMA_HISTOGRAM_BOOLEAN("Histogram.ReceivedProcessGroupCount",
received_process_group_count);
UMA_HISTOGRAM_COUNTS("Histogram.PendingProcessNotResponding",
unresponsive_processes);
}
static void OnShutdown() {
while (!outstanding_requests_.Get().empty()) {
RequestContextMap::iterator it = outstanding_requests_.Get().begin();
delete it->second;
outstanding_requests_.Get().erase(it);
}
}
base::Closure callback_;
int sequence_number_;
bool received_process_group_count_;
int processes_pending_;
static base::LazyInstance<RequestContextMap>::Leaky outstanding_requests_;
};
base::LazyInstance
<HistogramSynchronizer::RequestContext::RequestContextMap>::Leaky
HistogramSynchronizer::RequestContext::outstanding_requests_ =
LAZY_INSTANCE_INITIALIZER;
HistogramSynchronizer::HistogramSynchronizer()
: lock_(),
callback_thread_(NULL),
last_used_sequence_number_(kNeverUsableSequenceNumber),
async_sequence_number_(kNeverUsableSequenceNumber) {
HistogramController::GetInstance()->Register(this);
}
HistogramSynchronizer::~HistogramSynchronizer() {
RequestContext::OnShutdown();
SetCallbackTaskAndThread(NULL, base::Closure());
}
HistogramSynchronizer* HistogramSynchronizer::GetInstance() {
return Singleton<HistogramSynchronizer,
LeakySingletonTraits<HistogramSynchronizer> >::get();
}
void HistogramSynchronizer::FetchHistograms() {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&HistogramSynchronizer::FetchHistograms));
return;
}
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
HistogramSynchronizer* current_synchronizer =
HistogramSynchronizer::GetInstance();
if (current_synchronizer == NULL)
return;
current_synchronizer->RegisterAndNotifyAllProcesses(
HistogramSynchronizer::UNKNOWN,
base::TimeDelta::FromMinutes(1));
}
void FetchHistogramsAsynchronously(base::MessageLoop* callback_thread,
const base::Closure& callback,
base::TimeDelta wait_time) {
HistogramSynchronizer::FetchHistogramsAsynchronously(
callback_thread, callback, wait_time);
}
void HistogramSynchronizer::FetchHistogramsAsynchronously(
base::MessageLoop* callback_thread,
const base::Closure& callback,
base::TimeDelta wait_time) {
DCHECK(callback_thread != NULL);
DCHECK(!callback.is_null());
HistogramSynchronizer* current_synchronizer =
HistogramSynchronizer::GetInstance();
current_synchronizer->SetCallbackTaskAndThread(
callback_thread, callback);
current_synchronizer->RegisterAndNotifyAllProcesses(
HistogramSynchronizer::ASYNC_HISTOGRAMS, wait_time);
}
void HistogramSynchronizer::RegisterAndNotifyAllProcesses(
ProcessHistogramRequester requester,
base::TimeDelta wait_time) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
int sequence_number = GetNextAvailableSequenceNumber(requester);
base::Closure callback = base::Bind(
&HistogramSynchronizer::ForceHistogramSynchronizationDoneCallback,
base::Unretained(this),
sequence_number);
RequestContext::Register(callback, sequence_number);
HistogramController::GetInstance()->GetHistogramData(sequence_number);
BrowserThread::PostDelayedTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&RequestContext::Unregister, sequence_number),
wait_time);
}
void HistogramSynchronizer::OnPendingProcesses(int sequence_number,
int pending_processes,
bool end) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
RequestContext* request = RequestContext::GetRequestContext(sequence_number);
if (!request)
return;
request->AddProcessesPending(pending_processes);
request->SetReceivedProcessGroupCount(end);
request->DeleteIfAllDone();
}
void HistogramSynchronizer::OnHistogramDataCollected(
int sequence_number,
const std::vector<std::string>& pickled_histograms) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
base::HistogramDeltaSerialization::DeserializeAndAddSamples(
pickled_histograms);
RequestContext* request = RequestContext::GetRequestContext(sequence_number);
if (!request)
return;
request->DecrementProcessesPending();
request->DeleteIfAllDone();
}
void HistogramSynchronizer::SetCallbackTaskAndThread(
base::MessageLoop* callback_thread,
const base::Closure& callback) {
base::Closure old_callback;
base::MessageLoop* old_thread = NULL;
{
base::AutoLock auto_lock(lock_);
old_callback = callback_;
callback_ = callback;
old_thread = callback_thread_;
callback_thread_ = callback_thread;
async_sequence_number_ = kNeverUsableSequenceNumber;
}
InternalPostTask(old_thread, old_callback);
}
void HistogramSynchronizer::ForceHistogramSynchronizationDoneCallback(
int sequence_number) {
base::Closure callback;
base::MessageLoop* thread = NULL;
{
base::AutoLock lock(lock_);
if (sequence_number != async_sequence_number_)
return;
callback = callback_;
thread = callback_thread_;
callback_.Reset();
callback_thread_ = NULL;
}
InternalPostTask(thread, callback);
}
void HistogramSynchronizer::InternalPostTask(base::MessageLoop* thread,
const base::Closure& callback) {
if (callback.is_null() || !thread)
return;
thread->PostTask(FROM_HERE, callback);
}
int HistogramSynchronizer::GetNextAvailableSequenceNumber(
ProcessHistogramRequester requester) {
base::AutoLock auto_lock(lock_);
++last_used_sequence_number_;
if (last_used_sequence_number_ < 0) {
last_used_sequence_number_ =
kHistogramSynchronizerReservedSequenceNumber + 1;
}
DCHECK_NE(last_used_sequence_number_,
kHistogramSynchronizerReservedSequenceNumber);
if (requester == ASYNC_HISTOGRAMS)
async_sequence_number_ = last_used_sequence_number_;
return last_used_sequence_number_;
}
}