Commit 4f3f095f authored by zijiehe's avatar zijiehe Committed by Commit bot

[Chromoting] Retrieve process resource usage (ProcessStats) and its tests

ProcessStatsStub is an interface to receive process resource usage information
from a ProcessStats.

ProcessResourceUsage is a structure to store the resource usage of one process.
AggregatedProcessResourceUsage is a structure to store the resource usgaes of
several processes.

ProcessStatsAgent is an interface to retrieve resource usage of one process.
CurrentProcessStatsAgent is a ProcessStatsAgent implementation to retrieve
resource usage from current process.
ForwardProcessStatsAgent receives resource usage from a third-party and forwards
the latest usage as a ProcessStatsAgent.

ProcessStatsSender is a class to regularly report resource usages from various
ProcessStatsAgent implementations to a ProcessStatsStub. It merges several
non-empty ProcessResourceUsage into one AggregatedProcessResourceUsage.
This is typical useful on Windows: we need to calculate the resource usages from
both network process and desktop process.

R=sergeyu@chromium.org, jamiewalch@chromium.org
BUG=650926

Review-Url: https://codereview.chromium.org/2775983003
Cr-Original-Commit-Position: refs/heads/master@{#467753}
Committed: https://chromium.googlesource.com/chromium/src/+/5928f440f84065ab45f848dcd135e3c2f52ca5bb
Review-Url: https://codereview.chromium.org/2775983003
Cr-Commit-Position: refs/heads/master@{#467844}
parent 4df7199f
...@@ -96,6 +96,8 @@ static_library("host") { ...@@ -96,6 +96,8 @@ static_library("host") {
"continue_window_linux.cc", "continue_window_linux.cc",
"continue_window_mac.mm", "continue_window_mac.mm",
"continue_window_win.cc", "continue_window_win.cc",
"current_process_stats_agent.cc",
"current_process_stats_agent.h",
"curtain_mode.h", "curtain_mode.h",
"curtain_mode_linux.cc", "curtain_mode_linux.cc",
"curtain_mode_mac.cc", "curtain_mode_mac.cc",
...@@ -131,6 +133,8 @@ static_library("host") { ...@@ -131,6 +133,8 @@ static_library("host") {
"disconnect_window_win.cc", "disconnect_window_win.cc",
"dns_blackhole_checker.cc", "dns_blackhole_checker.cc",
"dns_blackhole_checker.h", "dns_blackhole_checker.h",
"forward_process_stats_agent.cc",
"forward_process_stats_agent.h",
"gcd_rest_client.cc", "gcd_rest_client.cc",
"gcd_rest_client.h", "gcd_rest_client.h",
"gcd_state_updater.cc", "gcd_state_updater.cc",
...@@ -223,6 +227,11 @@ static_library("host") { ...@@ -223,6 +227,11 @@ static_library("host") {
"policy_watcher.h", "policy_watcher.h",
"posix/signal_handler.cc", "posix/signal_handler.cc",
"posix/signal_handler.h", "posix/signal_handler.h",
"process_stats_agent.h",
"process_stats_sender.cc",
"process_stats_sender.h",
"process_stats_util.cc",
"process_stats_util.h",
"register_support_host_request.cc", "register_support_host_request.cc",
"register_support_host_request.h", "register_support_host_request.h",
"remote_input_filter.cc", "remote_input_filter.cc",
...@@ -460,6 +469,7 @@ source_set("unit_tests") { ...@@ -460,6 +469,7 @@ source_set("unit_tests") {
"pairing_registry_delegate_win_unittest.cc", "pairing_registry_delegate_win_unittest.cc",
"pin_hash_unittest.cc", "pin_hash_unittest.cc",
"policy_watcher_unittest.cc", "policy_watcher_unittest.cc",
"process_stats_sender_unittest.cc",
"register_support_host_request_unittest.cc", "register_support_host_request_unittest.cc",
"remote_input_filter_unittest.cc", "remote_input_filter_unittest.cc",
"resizing_host_observer_unittest.cc", "resizing_host_observer_unittest.cc",
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/host/current_process_stats_agent.h"
#include "base/process/process_metrics.h"
namespace remoting {
CurrentProcessStatsAgent::CurrentProcessStatsAgent(
const std::string& process_name)
: process_name_(process_name),
metrics_(base::ProcessMetrics::CreateCurrentProcessMetrics()) {}
CurrentProcessStatsAgent::~CurrentProcessStatsAgent() = default;
protocol::ProcessResourceUsage CurrentProcessStatsAgent::GetResourceUsage() {
protocol::ProcessResourceUsage current;
current.set_process_name(process_name_);
current.set_processor_usage(metrics_->GetPlatformIndependentCPUUsage());
current.set_working_set_size(metrics_->GetWorkingSetSize());
current.set_pagefile_size(metrics_->GetPagefileUsage());
return current;
}
} // namespace remoting
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_HOST_CURRENT_PROCESS_STATS_AGENT_H_
#define REMOTING_HOST_CURRENT_PROCESS_STATS_AGENT_H_
#include <memory>
#include <string>
#include "remoting/host/process_stats_agent.h"
#include "remoting/proto/process_stats.pb.h"
namespace base {
class ProcessMetrics;
} // namespace base
namespace remoting {
// A component to report statistic data of the current process.
class CurrentProcessStatsAgent final : public ProcessStatsAgent {
public:
explicit CurrentProcessStatsAgent(const std::string& process_name);
~CurrentProcessStatsAgent() override;
// ProcessStatsAgent implementation.
protocol::ProcessResourceUsage GetResourceUsage() override;
private:
const std::string process_name_;
const std::unique_ptr<base::ProcessMetrics> metrics_;
};
} // namespace remoting
#endif // REMOTING_HOST_CURRENT_PROCESS_STATS_AGENT_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/host/forward_process_stats_agent.h"
#include "base/logging.h"
namespace remoting {
ForwardProcessStatsAgent::ForwardProcessStatsAgent() = default;
ForwardProcessStatsAgent::~ForwardProcessStatsAgent() = default;
protocol::ProcessResourceUsage ForwardProcessStatsAgent::GetResourceUsage() {
DCHECK(thread_checker_.CalledOnValidThread());
return usage_;
}
void ForwardProcessStatsAgent::OnProcessStats(
const protocol::ProcessResourceUsage& usage) {
DCHECK(thread_checker_.CalledOnValidThread());
usage_ = usage;
}
} // namespace remoting
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_HOST_FORWARD_PROCESS_STATS_AGENT_H_
#define REMOTING_HOST_FORWARD_PROCESS_STATS_AGENT_H_
#include "base/threading/thread_checker.h"
#include "remoting/host/process_stats_agent.h"
#include "remoting/proto/process_stats.pb.h"
namespace remoting {
// ProcessStatsAgent implementation that returns stats passed to
// OnProcessStats(). Used to collect stats from processes other than the current
// one. All public functions, not including constructor and destructor, of the
// object of ForwardProcessStatsAgent are expected to be called in a same
// thread.
class ForwardProcessStatsAgent final : public ProcessStatsAgent {
public:
ForwardProcessStatsAgent();
~ForwardProcessStatsAgent() override;
void OnProcessStats(const protocol::ProcessResourceUsage& usage);
// ProcessStatsAgent implementation.
protocol::ProcessResourceUsage GetResourceUsage() override;
private:
base::ThreadChecker thread_checker_;
protocol::ProcessResourceUsage usage_;
};
} // namespace remoting
#endif // REMOTING_HOST_FORWARD_PROCESS_STATS_AGENT_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_HOST_PROCESS_STATS_AGENT_H_
#define REMOTING_HOST_PROCESS_STATS_AGENT_H_
#include "remoting/proto/process_stats.pb.h"
namespace remoting {
// An interface to report the process statistic data.
class ProcessStatsAgent {
public:
ProcessStatsAgent() = default;
virtual ~ProcessStatsAgent() = default;
// This function is expected to be executed in an IO-disallowed thread: if the
// implementation requires IO access or may cost a significant amount of time,
// using a background thread is preferred.
virtual protocol::ProcessResourceUsage GetResourceUsage() = 0;
};
} // namespace remoting
#endif // REMOTING_HOST_PROCESS_STATS_AGENT_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/host/process_stats_sender.h"
#include <utility>
#include "base/location.h"
#include "base/logging.h"
#include "remoting/host/process_stats_agent.h"
#include "remoting/host/process_stats_util.h"
namespace remoting {
ProcessStatsSender::ProcessStatsSender(
protocol::ProcessStatsStub* host_stats_stub,
base::TimeDelta interval,
std::initializer_list<ProcessStatsAgent*> agents)
: host_stats_stub_(host_stats_stub),
agents_(agents),
thread_checker_() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(host_stats_stub_);
DCHECK(!interval.is_zero());
DCHECK(!agents_.empty());
timer_.Start(FROM_HERE, interval, this, &ProcessStatsSender::ReportUsage);
}
ProcessStatsSender::~ProcessStatsSender() {
DCHECK(thread_checker_.CalledOnValidThread());
timer_.Stop();
}
void ProcessStatsSender::ReportUsage() {
DCHECK(thread_checker_.CalledOnValidThread());
std::vector<protocol::ProcessResourceUsage> usages;
for (auto* const agent : agents_) {
DCHECK(agent);
protocol::ProcessResourceUsage usage = agent->GetResourceUsage();
if (!IsEmptyProcessResourceUsage(usage)) {
usages.push_back(std::move(usage));
}
}
host_stats_stub_->OnProcessStats(AggregateProcessResourceUsage(usages));
}
} // namespace remoting
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_HOST_PROCESS_STATS_SENDER_H_
#define REMOTING_HOST_PROCESS_STATS_SENDER_H_
#include <initializer_list>
#include <vector>
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "remoting/proto/process_stats.pb.h"
#include "remoting/protocol/process_stats_stub.h"
namespace remoting {
class ProcessStatsAgent;
// A component to report process statistic data regularly, it starts immediately
// after construction, and stops after destruction.
// All public functions, including constructor and destructor of the object of
// ProcessStatsSender need to be executed in a same thread.
class ProcessStatsSender final {
public:
// ProcessStatsSender reports statistic data to |host_stats_stub| once per
// |interval|.
// ProcessStatsSender does not take the ownership of both |host_stats_stub|
// and |agents|. They must outlive the ProcessStatsSender object.
ProcessStatsSender(protocol::ProcessStatsStub* host_stats_stub,
base::TimeDelta interval,
std::initializer_list<ProcessStatsAgent*> agents);
~ProcessStatsSender();
private:
void ReportUsage();
protocol::ProcessStatsStub* const host_stats_stub_;
std::vector<ProcessStatsAgent*> agents_;
base::RepeatingTimer timer_;
const base::ThreadChecker thread_checker_;
};
} // namespace remoting
#endif // REMOTING_HOST_PROCESS_STATS_SENDER_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/host/process_stats_sender.h"
#include <stdint.h>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/location.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/time/time.h"
#include "remoting/host/process_stats_agent.h"
#include "remoting/proto/process_stats.pb.h"
#include "remoting/protocol/process_stats_stub.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace remoting {
namespace {
class FakeProcessStatsStub : public protocol::ProcessStatsStub {
public:
FakeProcessStatsStub() = default;
~FakeProcessStatsStub() override = default;
void OnProcessStats(
const protocol::AggregatedProcessResourceUsage& usage) override {
received_.push_back(usage);
DCHECK_LE(received_.size(), expected_usage_count_);
DCHECK(!quit_closure_.is_null());
if (received_.size() == expected_usage_count_) {
quit_closure_.Run();
}
}
const std::vector<protocol::AggregatedProcessResourceUsage>& received()
const {
return received_;
}
void set_quit_closure(base::Closure quit_closure) {
quit_closure_ = quit_closure;
}
void set_expected_usage_count(size_t expected_usage_count) {
expected_usage_count_ = expected_usage_count;
}
private:
std::vector<protocol::AggregatedProcessResourceUsage> received_;
size_t expected_usage_count_ = 0;
base::Closure quit_closure_;
};
class FakeProcessStatsAgent : public ProcessStatsAgent {
public:
FakeProcessStatsAgent() = default;
~FakeProcessStatsAgent() override = default;
protocol::ProcessResourceUsage GetResourceUsage() override {
protocol::ProcessResourceUsage usage;
usage.set_process_name("FakeProcessStatsAgent");
usage.set_processor_usage(index_);
usage.set_working_set_size(index_);
usage.set_pagefile_size(index_);
index_++;
return usage;
}
// Checks the expected usage based on index.
static void AssertExpected(
const protocol::AggregatedProcessResourceUsage& usage,
size_t index) {
ASSERT_EQ(usage.processor_usage(), index);
ASSERT_EQ(usage.working_set_size(), index);
ASSERT_EQ(usage.pagefile_size(), index);
}
static void AssertExpected(const protocol::ProcessResourceUsage& usage,
size_t index) {
ASSERT_EQ(usage.processor_usage(), index);
ASSERT_EQ(usage.working_set_size(), index);
ASSERT_EQ(usage.pagefile_size(), index);
}
size_t issued_times() const { return index_; }
private:
size_t index_ = 0;
};
} // namespace
TEST(ProcessStatsSenderTest, ReportUsage) {
base::MessageLoop message_loop;
base::RunLoop run_loop;
FakeProcessStatsStub stub;
std::unique_ptr<ProcessStatsSender> stats;
FakeProcessStatsAgent agent;
stub.set_expected_usage_count(10);
stub.set_quit_closure(base::Bind(
[](std::unique_ptr<ProcessStatsSender>* stats,
const FakeProcessStatsStub& stub, const FakeProcessStatsAgent& agent,
base::RunLoop* run_loop) -> void {
ASSERT_EQ(stub.received().size(), agent.issued_times());
stats->reset();
run_loop->Quit();
},
base::Unretained(&stats), base::ConstRef(stub), base::ConstRef(agent),
base::Unretained(&run_loop)));
message_loop.task_runner()->PostTask(
FROM_HERE,
base::Bind(
[](std::unique_ptr<ProcessStatsSender>* stats,
FakeProcessStatsStub* stub, FakeProcessStatsAgent* agent) -> void {
stats->reset(new ProcessStatsSender(
stub, base::TimeDelta::FromMilliseconds(1), { agent }));
},
base::Unretained(&stats), base::Unretained(&stub),
base::Unretained(&agent)));
run_loop.Run();
ASSERT_EQ(stub.received().size(), 10U);
for (size_t i = 0; i < stub.received().size(); i++) {
FakeProcessStatsAgent::AssertExpected(stub.received()[i], i);
}
}
TEST(ProcessStatsSenderTest, MergeUsage) {
base::MessageLoop message_loop;
base::RunLoop run_loop;
FakeProcessStatsStub stub;
std::unique_ptr<ProcessStatsSender> stats;
// Owned by |stats|.
FakeProcessStatsAgent agent1;
FakeProcessStatsAgent agent2;
stub.set_expected_usage_count(10);
stub.set_quit_closure(base::Bind(
[](std::unique_ptr<ProcessStatsSender>* stats,
const FakeProcessStatsStub& stub, const FakeProcessStatsAgent& agent1,
const FakeProcessStatsAgent& agent2, base::RunLoop* run_loop) -> void {
ASSERT_EQ(stub.received().size(), agent1.issued_times());
ASSERT_EQ(stub.received().size(), agent2.issued_times());
stats->reset();
run_loop->Quit();
},
base::Unretained(&stats), base::ConstRef(stub), base::ConstRef(agent1),
base::ConstRef(agent2), base::Unretained(&run_loop)));
message_loop.task_runner()->PostTask(
FROM_HERE,
base::Bind(
[](std::unique_ptr<ProcessStatsSender>* stats,
FakeProcessStatsStub* stub, FakeProcessStatsAgent* agent1,
FakeProcessStatsAgent* agent2) -> void {
stats->reset(new ProcessStatsSender(
stub, base::TimeDelta::FromMilliseconds(1),
{ agent1, agent2 } ));
},
base::Unretained(&stats), base::Unretained(&stub),
base::Unretained(&agent1), base::Unretained(&agent2)));
run_loop.Run();
ASSERT_EQ(stub.received().size(), 10U);
for (size_t i = 0; i < stub.received().size(); i++) {
FakeProcessStatsAgent::AssertExpected(stub.received()[i], i * 2);
for (int j = 0; j < stub.received()[i].usages_size(); j++) {
FakeProcessStatsAgent::AssertExpected(
stub.received()[i].usages().Get(j), i);
}
}
}
} // namespace remoting
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/host/process_stats_util.h"
#include <stdint.h>
#include <string>
#include <utility>
namespace remoting {
bool IsEmptyProcessResourceUsage(const protocol::ProcessResourceUsage& usage) {
return !usage.has_process_name() && !usage.has_processor_usage() &&
!usage.has_working_set_size() && !usage.has_pagefile_size();
}
protocol::AggregatedProcessResourceUsage AggregateProcessResourceUsage(
const std::vector<protocol::ProcessResourceUsage>& usages) {
if (usages.empty()) {
return protocol::AggregatedProcessResourceUsage();
}
if (usages.size() == 1) {
const protocol::ProcessResourceUsage& usage = usages[0];
protocol::AggregatedProcessResourceUsage aggregated;
aggregated.set_name(usage.process_name());
aggregated.set_processor_usage(usage.processor_usage());
aggregated.set_working_set_size(usage.working_set_size());
aggregated.set_pagefile_size(usage.pagefile_size());
return aggregated;
}
std::string name = "aggregate { ";
double processor_usage = 0;
uint64_t working_set_size = 0;
uint64_t pagefile_size = 0;
protocol::AggregatedProcessResourceUsage aggregated;
for (const auto& usage : usages) {
name.append(usage.process_name()).append(", ");
processor_usage += usage.processor_usage();
working_set_size += usage.working_set_size();
pagefile_size += usage.pagefile_size();
*aggregated.add_usages() = usage;
}
name += " }";
aggregated.set_name(std::move(name));
aggregated.set_processor_usage(processor_usage);
aggregated.set_working_set_size(working_set_size);
aggregated.set_pagefile_size(pagefile_size);
return aggregated;
}
} // namespace remoting
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_HOST_PROCESS_STATS_UTIL_H_
#define REMOTING_HOST_PROCESS_STATS_UTIL_H_
#include <vector>
#include "remoting/proto/process_stats.pb.h"
namespace remoting {
// Whether the |usage| is empty, i.e. all fields hold initial values.
bool IsEmptyProcessResourceUsage(const protocol::ProcessResourceUsage& usage);
// Merges several ProcessResourceUsage instances into one
// AggregatedProcessResourceUsage.
protocol::AggregatedProcessResourceUsage AggregateProcessResourceUsage(
const std::vector<protocol::ProcessResourceUsage>& usages);
} // namespace remoting
#endif // REMOTING_HOST_PROCESS_STATS_UTIL_H_
...@@ -18,6 +18,7 @@ proto_library("proto") { ...@@ -18,6 +18,7 @@ proto_library("proto") {
"event.proto", "event.proto",
"internal.proto", "internal.proto",
"mux.proto", "mux.proto",
"process_stats.proto",
"video.proto", "video.proto",
"video_stats.proto", "video_stats.proto",
] ]
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Protocol for process resource usage.
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
package remoting.protocol;
// The resource usage of a single process.
// Next Id: 5
message ProcessResourceUsage {
// The name or friendly name of the process.
optional string process_name = 1;
// The processor usage. It should be a consistent value on all platforms in
// range of 0 to (100 * NumCPUCores).
optional double processor_usage = 2;
// Memory usage of working set.
optional uint64 working_set_size = 3;
// Memory usage of page file.
optional uint64 pagefile_size = 4;
}
// The resource usage of several processes.
// Next Id: 6
message AggregatedProcessResourceUsage {
// A friendly name of the processes current instance aggregated from.
optional string name = 1;
// The total processor usage.
optional double processor_usage = 2;
// The total memory usage of working set.
optional uint64 working_set_size = 3;
// The total memory usage of page file.
optional uint64 pagefile_size = 4;
// The process resource usage of each individual process.
repeated ProcessResourceUsage usages = 5;
}
...@@ -128,6 +128,7 @@ static_library("protocol") { ...@@ -128,6 +128,7 @@ static_library("protocol") {
"port_allocator_factory.h", "port_allocator_factory.h",
"port_range.cc", "port_range.cc",
"port_range.h", "port_range.h",
"process_stats_stub.h",
"pseudotcp_adapter.cc", "pseudotcp_adapter.cc",
"pseudotcp_adapter.h", "pseudotcp_adapter.h",
"pseudotcp_channel_factory.cc", "pseudotcp_channel_factory.cc",
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_PROTOCOL_PROCESS_STATS_STUB_H_
#define REMOTING_PROTOCOL_PROCESS_STATS_STUB_H_
#include "remoting/proto/process_stats.pb.h"
namespace remoting {
namespace protocol {
// An interface to receive process statistic data.
class ProcessStatsStub {
public:
ProcessStatsStub() = default;
virtual ~ProcessStatsStub() = default;
virtual void OnProcessStats(
const protocol::AggregatedProcessResourceUsage& usage) = 0;
};
} // namespace protocol
} // namespace remoting
#endif // REMOTING_PROTOCOL_PROCESS_STATS_STUB_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment