Chromium Code Reviews| Index: chrome/browser/extensions/api/system_info_cpu/cpu_info_provider.cc |
| diff --git a/chrome/browser/extensions/api/system_info_cpu/cpu_info_provider.cc b/chrome/browser/extensions/api/system_info_cpu/cpu_info_provider.cc |
| index c7c9cca42ebc1c2ee54fa2f87b3096fa459b3617..ba39afb6ac8ba6488197d211f4cd55c96f01959c 100644 |
| --- a/chrome/browser/extensions/api/system_info_cpu/cpu_info_provider.cc |
| +++ b/chrome/browser/extensions/api/system_info_cpu/cpu_info_provider.cc |
| @@ -5,10 +5,27 @@ |
| #include "chrome/browser/extensions/api/system_info_cpu/cpu_info_provider.h" |
| #include "base/sys_info.h" |
| +#include "content/public/browser/browser_thread.h" |
| namespace extensions { |
| using api::experimental_system_info_cpu::CpuInfo; |
| +using api::experimental_system_info_cpu::CpuUpdateInfo; |
| +using content::BrowserThread; |
| + |
| +// Default sampling interval is 1000ms. |
| +const unsigned int kDefaultSamplingIntervalMs = 1000; |
| + |
| +CpuInfoProvider::CpuInfoProvider() |
| + : is_sampling_started_(false), |
| + sampling_timer_(NULL), |
| + sampling_interval_(kDefaultSamplingIntervalMs) { |
| +} |
| + |
| +CpuInfoProvider::~CpuInfoProvider() { |
| + if (sampling_timer_) |
| + BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, sampling_timer_); |
|
benwells
2012/09/21 08:19:50
This feels racy. Can the timer fire before it is d
Hongbo Min
2012/09/21 09:00:23
Your concern is valid, but if the CpuInfoProvider
benwells
2012/09/25 17:32:13
Lazy instances are destroyed at program exit. I do
|
| +} |
| bool CpuInfoProvider::QueryInfo(CpuInfo* info) { |
| if (info == NULL) |
| @@ -20,14 +37,22 @@ bool CpuInfoProvider::QueryInfo(CpuInfo* info) { |
| return true; |
| } |
| -bool CpuInfoProvider::StartSampling(const QueryCpuTimeCallback& callback) { |
| - // TODO(hongbo): Implement sampling functionality for event router. |
| - return false; |
| +void CpuInfoProvider::StartSampling(const SamplingCallback& callback) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + BrowserThread::PostTask( |
| + BrowserThread::FILE, |
| + FROM_HERE, |
| + base::Bind(&CpuInfoProvider::StartSamplingOnFileThread, |
| + base::Unretained(this), callback)); |
| } |
| -bool CpuInfoProvider::StopSampling() { |
| - // TODO(hongbo): Implement sampling functionality for event router. |
| - return false; |
| +void CpuInfoProvider::StopSampling() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + BrowserThread::PostTask( |
| + BrowserThread::FILE, |
| + FROM_HERE, |
| + base::Bind(&CpuInfoProvider::StopSamplingOnFileThread, |
| + base::Unretained(this))); |
|
benwells
2012/09/21 08:19:50
Why use unretained here? If you descend from RefCo
Hongbo Min
2012/09/21 09:00:23
The CpuInfoProvider is a global lazy instance and
benwells
2012/09/25 17:32:13
OK, again if you ensure the timer is stopped when
|
| } |
| // static |
| @@ -35,4 +60,65 @@ CpuInfoProvider* CpuInfoProvider::Get() { |
| return CpuInfoProvider::GetInstance<CpuInfoProvider>(); |
| } |
| +void CpuInfoProvider::StartSamplingOnFileThread( |
| + const SamplingCallback& callback) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| + if (is_sampling_started_) |
| + return; |
| + |
| + if (!QueryCpuTimePerProcessor(&baseline_cpu_time_)) |
| + return; |
| + |
| + is_sampling_started_ = true; |
| + callback_ = callback; |
| + DCHECK(!sampling_timer_) << "The sampling timer is leaked. Did you forgot " |
| + "calling StopSampling?"; |
| + // Should be deleted on FILE thread. |
| + sampling_timer_ = new base::RepeatingTimer<CpuInfoProvider>(); |
| + sampling_timer_->Start(FROM_HERE, |
| + base::TimeDelta::FromMilliseconds(sampling_interval_), |
| + this, &CpuInfoProvider::DoSample); |
| +} |
| + |
| +void CpuInfoProvider::StopSamplingOnFileThread() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| + if (!is_sampling_started_) return; |
| + delete sampling_timer_; |
| + sampling_timer_ = NULL; |
| + baseline_cpu_time_.clear(); |
| + is_sampling_started_ = false; |
| +} |
| + |
| +void CpuInfoProvider::DoSample() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| + |
| + std::vector<CpuTime> next_cpu_time; |
| + if (!QueryCpuTimePerProcessor(&next_cpu_time)) |
| + return; |
| + |
| + // Calculate the CPU usage information from the next_cpu_time and |
| + // |baseline_cpu_time_|. |
| + double total_usage = 0; |
| + scoped_ptr<CpuUpdateInfo> info(new CpuUpdateInfo()); |
| + for (size_t i = 0; i < next_cpu_time.size(); ++i) { |
| + double total_time = |
| + (next_cpu_time[i].user - baseline_cpu_time_[i].user) + |
| + (next_cpu_time[i].kernel - baseline_cpu_time_[i].kernel) + |
| + (next_cpu_time[i].idle - baseline_cpu_time_[i].idle); |
| + double idle_time = next_cpu_time[i].idle - baseline_cpu_time_[i].idle; |
| + |
| + double usage = 0; |
| + if (total_time != 0) |
| + usage = (100 - idle_time * 100 / total_time); |
| + info->usage_per_processor.push_back(usage); |
| + total_usage += usage; |
| + } |
| + |
| + info->average_usage = total_usage / next_cpu_time.size(); |
| + if (!callback_.is_null()) |
| + callback_.Run(info.Pass()); |
| + // Use next_cpu_time as baseline_cpu_time_ for the next sampling cycle. |
| + baseline_cpu_time_.swap(next_cpu_time); |
| +} |
| + |
| } // namespace extensions |