This source file includes following definitions.
- processes_pending_
- RequestContext
- SetReceivedProcessGroupCount
- IncrementProcessesPending
- AddProcessesPending
- DecrementProcessesPending
- DeleteIfAllDone
- Register
- GetRequestContext
- Unregister
- OnShutdown
- FetchProfilerDataAsynchronously
- OnPendingProcesses
- OnProfilerDataCollected
- RegisterAndNotifyAllProcesses
- DecrementPendingProcessesAndSendData
- GetNextAvailableSequenceNumber
#include "chrome/browser/metrics/tracking_synchronizer.h"
#include "base/bind.h"
#include "base/metrics/histogram.h"
#include "base/threading/thread.h"
#include "base/tracked_objects.h"
#include "chrome/browser/metrics/tracking_synchronizer_observer.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/profiler_controller.h"
#include "content/public/common/process_type.h"
using base::TimeTicks;
using content::BrowserThread;
namespace {
const int kNeverUsableSequenceNumber = -2;
static chrome_browser_metrics::TrackingSynchronizer* g_tracking_synchronizer =
NULL;
}
namespace chrome_browser_metrics {
class TrackingSynchronizer::RequestContext {
public:
typedef std::map<int, RequestContext*> RequestContextMap;
RequestContext(
const base::WeakPtr<TrackingSynchronizerObserver>& callback_object,
int sequence_number)
: callback_object_(callback_object),
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 IncrementProcessesPending() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
++processes_pending_;
}
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 RequestContext* Register(
int sequence_number,
const base::WeakPtr<TrackingSynchronizerObserver>& callback_object) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
RequestContext* request = new RequestContext(
callback_object, sequence_number);
outstanding_requests_.Get()[sequence_number] = request;
return 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_;
if (request->callback_object_.get())
request->callback_object_->FinishedReceivingProfilerData();
delete request;
outstanding_requests_.Get().erase(it);
UMA_HISTOGRAM_BOOLEAN("Profiling.ReceivedProcessGroupCount",
received_process_group_count);
UMA_HISTOGRAM_COUNTS("Profiling.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::WeakPtr<TrackingSynchronizerObserver> callback_object_;
int sequence_number_;
bool received_process_group_count_;
int processes_pending_;
static base::LazyInstance<RequestContextMap>::Leaky outstanding_requests_;
};
base::LazyInstance
<TrackingSynchronizer::RequestContext::RequestContextMap>::Leaky
TrackingSynchronizer::RequestContext::outstanding_requests_ =
LAZY_INSTANCE_INITIALIZER;
TrackingSynchronizer::TrackingSynchronizer()
: last_used_sequence_number_(kNeverUsableSequenceNumber) {
DCHECK(!g_tracking_synchronizer);
g_tracking_synchronizer = this;
content::ProfilerController::GetInstance()->Register(this);
}
TrackingSynchronizer::~TrackingSynchronizer() {
content::ProfilerController::GetInstance()->Unregister(this);
RequestContext::OnShutdown();
g_tracking_synchronizer = NULL;
}
void TrackingSynchronizer::FetchProfilerDataAsynchronously(
const base::WeakPtr<TrackingSynchronizerObserver>& callback_object) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!g_tracking_synchronizer) {
return;
}
int sequence_number = g_tracking_synchronizer->RegisterAndNotifyAllProcesses(
callback_object);
BrowserThread::PostDelayedTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&RequestContext::Unregister, sequence_number),
base::TimeDelta::FromMinutes(1));
}
void TrackingSynchronizer::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 TrackingSynchronizer::OnProfilerDataCollected(
int sequence_number,
const tracked_objects::ProcessDataSnapshot& profiler_data,
int process_type) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DecrementPendingProcessesAndSendData(sequence_number, profiler_data,
process_type);
}
int TrackingSynchronizer::RegisterAndNotifyAllProcesses(
const base::WeakPtr<TrackingSynchronizerObserver>& callback_object) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
int sequence_number = GetNextAvailableSequenceNumber();
RequestContext* request =
RequestContext::Register(sequence_number, callback_object);
request->IncrementProcessesPending();
content::ProfilerController::GetInstance()->GetProfilerData(sequence_number);
tracked_objects::ProcessDataSnapshot process_data;
tracked_objects::ThreadData::Snapshot(false, &process_data);
DecrementPendingProcessesAndSendData(sequence_number, process_data,
content::PROCESS_TYPE_BROWSER);
return sequence_number;
}
void TrackingSynchronizer::DecrementPendingProcessesAndSendData(
int sequence_number,
const tracked_objects::ProcessDataSnapshot& profiler_data,
int process_type) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
RequestContext* request = RequestContext::GetRequestContext(sequence_number);
if (!request)
return;
if (request->callback_object_.get()) {
request->callback_object_
->ReceivedProfilerData(profiler_data, process_type);
}
request->DecrementProcessesPending();
request->DeleteIfAllDone();
}
int TrackingSynchronizer::GetNextAvailableSequenceNumber() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
++last_used_sequence_number_;
if (last_used_sequence_number_ < 0)
last_used_sequence_number_ = 1;
return last_used_sequence_number_;
}
}