You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by tn...@apache.org on 2015/07/15 02:58:18 UTC
[1/2] mesos git commit: Added cpuacct subsystem to cgroups.
Repository: mesos
Updated Branches:
refs/heads/master 1b70debfd -> 867ff24ba
Added cpuacct subsystem to cgroups.
Review: https://reviews.apache.org/r/36106
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/9a5eaca9
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/9a5eaca9
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/9a5eaca9
Branch: refs/heads/master
Commit: 9a5eaca9e3ab7ac01ae5f884b32e8c570da4f799
Parents: 1b70deb
Author: Jojy Varghese <jo...@mesosphere.io>
Authored: Tue Jul 14 17:10:03 2015 -0700
Committer: Timothy Chen <tn...@apache.org>
Committed: Tue Jul 14 17:57:50 2015 -0700
----------------------------------------------------------------------
src/linux/cgroups.cpp | 51 ++++++++++++++++++++++++++++++++++++++++
src/linux/cgroups.hpp | 35 +++++++++++++++++++++++++++
src/tests/cgroups_tests.cpp | 14 +++++++++++
3 files changed, 100 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/9a5eaca9/src/linux/cgroups.cpp
----------------------------------------------------------------------
diff --git a/src/linux/cgroups.cpp b/src/linux/cgroups.cpp
index 4c006d0..b7d11ac 100644
--- a/src/linux/cgroups.cpp
+++ b/src/linux/cgroups.cpp
@@ -1991,6 +1991,57 @@ Try<Nothing> cfs_quota_us(
} // namespace cpu {
+namespace cpuacct {
+
+Result<string> cgroup(pid_t pid)
+{
+ return internal::cgroup(pid, "cpuacct");
+}
+
+
+Try<Stats> stat(
+ const string& hierarchy,
+ const string& cgroup)
+{
+ const Try<hashmap<string, uint64_t>> stats =
+ cgroups::stat(hierarchy, cgroup, "cpuacct.stat");
+
+ if (!stats.isSome()) {
+ return Error(stats.error());
+ }
+
+ if (!stats.get().contains("user") || !stats.get().contains("system")) {
+ return Error("Failed to get user/system value from cpuacct.stat");
+ }
+
+ // Get user ticks per second. This value is constant for the lifetime of a
+ // process.
+ // TODO(Jojy): Move system constants to a separate compilation unit.
+ static long userTicks = sysconf(_SC_CLK_TCK);
+ if (userTicks <= 0) {
+ return ErrnoError("Failed to get _SC_CLK_TCK");
+ }
+
+ Try<Duration> user =
+ Duration::create((double) stats.get().at("user") / userTicks);
+
+ if (user.isError()) {
+ return Error(
+ "Failed to convert user ticks to Duration: " + user.error());
+ }
+
+ Try<Duration> system =
+ Duration::create((double) stats.get().at("system") / userTicks);
+
+ if (system.isError()) {
+ return Error(
+ "Failed to convert system ticks to Duration: " + system.error());
+ }
+
+ return Stats({user.get(), system.get()});
+}
+
+} // namespace cpuacct {
namespace memory {
http://git-wip-us.apache.org/repos/asf/mesos/blob/9a5eaca9/src/linux/cgroups.hpp
----------------------------------------------------------------------
diff --git a/src/linux/cgroups.hpp b/src/linux/cgroups.hpp
index 73b9831..a47f9a2 100644
--- a/src/linux/cgroups.hpp
+++ b/src/linux/cgroups.hpp
@@ -432,6 +432,41 @@ Try<Nothing> cfs_quota_us(
} // namespace cpu {
+// Cpuacct subsystem.
+namespace cpuacct {
+
+// Returns the cgroup that the specified pid is a member of within the
+// hierarchy that the 'cpuacct' subsytem is mounted or None if the
+// subsystem is not mounted or the pid is not a member of a cgroup.
+//
+// @param pid process id for which cgroup is queried within the cpuacct
+// subsytem.
+// @return Some cgroup in case there was a valid cgroup found for the pid.
+// Error if there was any error in processing.
+Result<std::string> cgroup(pid_t pid);
+
+
+// Encapsulates the 'stat' information exposed by the cpuacct subsystem.
+struct Stats
+{
+ const Duration user;
+ const Duration system;
+};
+
+
+// Returns 'Stats' for a given hierarchy and cgroup.
+//
+// @param hierarchy hierarchy for the 'cpuacct' subsystem.
+// @param cgroup cgroup for a given process.
+// @return Some<Stats> if sucessful.
+// Error in case of any error during processing.
+Try<Stats> stat(
+ const std::string& hierarchy,
+ const std::string& cgroup);
+
+} // namespace cpuacct {
+
+
// Memory controls.
namespace memory {
http://git-wip-us.apache.org/repos/asf/mesos/blob/9a5eaca9/src/tests/cgroups_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/cgroups_tests.cpp b/src/tests/cgroups_tests.cpp
index 475f48a..af4b37b 100644
--- a/src/tests/cgroups_tests.cpp
+++ b/src/tests/cgroups_tests.cpp
@@ -1186,6 +1186,20 @@ TEST_F(CgroupsAnyHierarchyMemoryPressureTest, ROOT_IncreasePageCache)
EXPECT_LT(0u, low);
}
+// Tests the cpuacct::stat API. This test just tests for ANY value returned by
+// the API.
+TEST_F(CgroupsAnyHierarchyWithCpuAcctMemoryTest, ROOT_CGROUPS_CpuAcctsStats)
+{
+ const std::string hierarchy = path::join(baseHierarchy, "cpuacct");
+ ASSERT_SOME(cgroups::create(hierarchy, TEST_CGROUPS_ROOT));
+
+ CHECK_SOME(cgroups::assign(hierarchy, TEST_CGROUPS_ROOT, ::getpid()));
+
+ ASSERT_SOME(cgroups::cpuacct::stat(hierarchy, TEST_CGROUPS_ROOT));
+
+ AWAIT_READY(cgroups::destroy(hierarchy, TEST_CGROUPS_ROOT));
+}
+
} // namespace tests {
} // namespace internal {
} // namespace mesos {
[2/2] mesos git commit: Added cgroups based statistics to Docker
containerizer.
Posted by tn...@apache.org.
Added cgroups based statistics to Docker containerizer.
Review: https://reviews.apache.org/r/36326
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/867ff24b
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/867ff24b
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/867ff24b
Branch: refs/heads/master
Commit: 867ff24ba91de54a50fe6b0bcf006152c017791a
Parents: 9a5eaca
Author: Jojy Varghese <jo...@mesosphere.io>
Authored: Tue Jul 14 17:10:25 2015 -0700
Committer: Timothy Chen <tn...@apache.org>
Committed: Tue Jul 14 17:57:55 2015 -0700
----------------------------------------------------------------------
src/slave/containerizer/docker.cpp | 142 +++++++++++++++++++-------
src/slave/containerizer/docker.hpp | 8 +-
src/tests/docker_containerizer_tests.cpp | 1 +
3 files changed, 105 insertions(+), 46 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/867ff24b/src/slave/containerizer/docker.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/docker.cpp b/src/slave/containerizer/docker.cpp
index cfb6017..e710876 100644
--- a/src/slave/containerizer/docker.cpp
+++ b/src/slave/containerizer/docker.cpp
@@ -1202,71 +1202,135 @@ Future<ResourceStatistics> DockerContainerizerProcess::usage(
return Failure("Container is being removed: " + stringify(containerId));
}
+ auto collectUsage = [this, containerId](
+ pid_t pid) -> Future<ResourceStatistics> {
+ // First make sure container is still there.
+ if (!containers_.contains(containerId)) {
+ return Failure("Container has been destroyed: " + stringify(containerId));
+ }
+
+ Container* container = containers_[containerId];
+
+ if (container->state == Container::DESTROYING) {
+ return Failure("Container is being removed: " + stringify(containerId));
+ }
+
+ const Try<ResourceStatistics> cgroupStats = cgroupsStatistics(pid);
+ if (cgroupStats.isError()) {
+ return Failure("Failed to collect cgroup stats: " + cgroupStats.error());
+ }
+
+ ResourceStatistics result = cgroupStats.get();
+
+ // Set the resource allocations.
+ const Resources& resource = container->resources;
+ const Option<Bytes> mem = resource.mem();
+ if (mem.isSome()) {
+ result.set_mem_limit_bytes(mem.get().bytes());
+ }
+
+ const Option<double> cpus = resource.cpus();
+ if (cpus.isSome()) {
+ result.set_cpus_limit(cpus.get());
+ }
+
+ return result;
+ };
+
// Skip inspecting the docker container if we already have the pid.
if (container->pid.isSome()) {
- return __usage(containerId, container->pid.get());
+ return collectUsage(container->pid.get());
}
return docker->inspect(container->name())
- .then(defer(self(), &Self::_usage, containerId, lambda::_1));
+ .then(defer(
+ self(),
+ [this, containerId, collectUsage]
+ (const Docker::Container& _container) -> Future<ResourceStatistics> {
+ const Option<pid_t> pid = _container.pid;
+ if (pid.isNone()) {
+ return Failure("Container is not running");
+ }
+
+ if (!containers_.contains(containerId)) {
+ return Failure(
+ "Container has been destroyed:" + stringify(containerId));
+ }
+
+ Container* container = containers_[containerId];
+
+ // Update the container's pid now. We ran inspect because we didn't have
+ // a pid for the container.
+ container->pid = pid;
+
+ return collectUsage(pid.get());
+ }));
#endif // __linux__
}
-Future<ResourceStatistics> DockerContainerizerProcess::_usage(
- const ContainerID& containerId,
- const Docker::Container& _container)
+Try<ResourceStatistics> DockerContainerizerProcess::cgroupsStatistics(
+ pid_t pid) const
{
- if (!containers_.contains(containerId)) {
- return Failure("Container has been destroyed:" + stringify(containerId));
- }
-
- Container* container = containers_[containerId];
+#ifndef __linux__
+ return Error("Does not support cgroups on non-linux platform");
+#else
+ const Result<string> cpuHierarchy = cgroups::hierarchy("cpuacct");
+ const Result<string> memHierarchy = cgroups::hierarchy("memory");
- if (container->state == Container::DESTROYING) {
- return Failure("Container is being removed: " + stringify(containerId));
+ if (cpuHierarchy.isError()) {
+ return Error(
+ "Failed to determine the cgroup 'cpu' subsystem hierarchy: " +
+ cpuHierarchy.error());
}
- Option<pid_t> pid = _container.pid;
- if (pid.isNone()) {
- return Failure("Container is not running");
+ if (memHierarchy.isError()) {
+ return Error(
+ "Failed to determine the cgroup 'memory' subsystem hierarchy: " +
+ memHierarchy.error());
}
- container->pid = pid;
-
- return __usage(containerId, pid.get());
-}
+ const Result<string> cpuCgroup = cgroups::cpuacct::cgroup(pid);
+ if (cpuCgroup.isError()) {
+ return Error(
+ "Failed to determine cgroup for the 'cpu' subsystem: " +
+ cpuCgroup.error());
+ }
+ const Result<string> memCgroup = cgroups::memory::cgroup(pid);
+ if (memCgroup.isError()) {
+ return Error(
+ "Failed to determine cgroup for the 'memory' subsystem: " +
+ memCgroup.error());
+ }
-Future<ResourceStatistics> DockerContainerizerProcess::__usage(
- const ContainerID& containerId,
- pid_t pid)
-{
- Container* container = containers_[containerId];
+ const Try<cgroups::cpuacct::Stats> cpuAcctStat =
+ cgroups::cpuacct::stat(cpuHierarchy.get(), cpuCgroup.get());
- // Note that here getting the root pid is enough because
- // the root process acts as an 'init' process in the docker
- // container, so no other child processes will escape it.
- Try<ResourceStatistics> statistics = mesos::internal::usage(pid, true, true);
- if (statistics.isError()) {
- return Failure(statistics.error());
+ if (cpuAcctStat.isError()) {
+ return Error("Failed to get cpu.stat: " + cpuAcctStat.error());
}
- ResourceStatistics result = statistics.get();
+ const Try<hashmap<string, uint64_t>> memStats =
+ cgroups::stat(memHierarchy.get(), memCgroup.get(), "memory.stat");
- // Set the resource allocations.
- const Resources& resource = container->resources;
- Option<Bytes> mem = resource.mem();
- if (mem.isSome()) {
- result.set_mem_limit_bytes(mem.get().bytes());
+ if (memStats.isError()) {
+ return Error(
+ "Error getting memory statistics from cgroups memory subsystem: " +
+ memStats.error());
}
- Option<double> cpus = resource.cpus();
- if (cpus.isSome()) {
- result.set_cpus_limit(cpus.get());
+ if (!memStats.get().contains("rss")) {
+ return Error("cgroups memory stats does not contain 'rss' data");
}
+ ResourceStatistics result;
+ result.set_cpus_system_time_secs(cpuAcctStat.get().system.secs());
+ result.set_cpus_user_time_secs(cpuAcctStat.get().user.secs());
+ result.set_mem_rss_bytes(memStats.get().at("rss"));
+
return result;
+#endif // __linux__
}
http://git-wip-us.apache.org/repos/asf/mesos/blob/867ff24b/src/slave/containerizer/docker.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/docker.hpp b/src/slave/containerizer/docker.hpp
index 9a7a951..e43d300 100644
--- a/src/slave/containerizer/docker.hpp
+++ b/src/slave/containerizer/docker.hpp
@@ -219,13 +219,7 @@ private:
const Resources& resources,
pid_t pid);
- Future<ResourceStatistics> _usage(
- const ContainerID& containerId,
- const Docker::Container& container);
-
- Future<ResourceStatistics> __usage(
- const ContainerID& containerId,
- pid_t pid);
+ Try<ResourceStatistics> cgroupsStatistics(pid_t pid) const;
// Call back for when the executor exits. This will trigger
// container destroy.
http://git-wip-us.apache.org/repos/asf/mesos/blob/867ff24b/src/tests/docker_containerizer_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/docker_containerizer_tests.cpp b/src/tests/docker_containerizer_tests.cpp
index a3da786..77dbeaa 100644
--- a/src/tests/docker_containerizer_tests.cpp
+++ b/src/tests/docker_containerizer_tests.cpp
@@ -961,6 +961,7 @@ TEST_F(DockerContainerizerTest, ROOT_DOCKER_Usage)
statistics.mem_limit_bytes());
EXPECT_LT(0, statistics.cpus_user_time_secs());
EXPECT_LT(0, statistics.cpus_system_time_secs());
+ EXPECT_GT(statistics.mem_rss_bytes(), 0);
Future<containerizer::Termination> termination =
dockerContainerizer.wait(containerId.get());