Support manipulating scheduler policy on Linux. Review: https://reviews.apache.org/r/34309
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/6de149e4 Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/6de149e4 Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/6de149e4 Branch: refs/heads/master Commit: 6de149e4715743345add600ade967a79351555f9 Parents: d7c0873 Author: Ian Downes <[email protected]> Authored: Fri May 15 17:58:28 2015 -0700 Committer: Ian Downes <[email protected]> Committed: Fri May 29 14:33:21 2015 -0700 ---------------------------------------------------------------------- src/Makefile.am | 2 + src/linux/sched.hpp | 93 ++++++++++++++++++++++++++++++++++++++++ src/tests/sched_tests.cpp | 96 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/6de149e4/src/Makefile.am ---------------------------------------------------------------------- diff --git a/src/Makefile.am b/src/Makefile.am index e7281ac..9d1f0d5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -550,6 +550,7 @@ libmesos_no_3rdparty_la_SOURCES += \ linux/fs.hpp \ linux/ns.hpp \ linux/perf.hpp \ + linux/sched.hpp \ local/flags.hpp \ local/local.hpp \ logging/flags.hpp \ @@ -1480,6 +1481,7 @@ if OS_LINUX mesos_tests_SOURCES += tests/memory_pressure_tests.cpp mesos_tests_SOURCES += tests/ns_tests.cpp mesos_tests_SOURCES += tests/perf_tests.cpp + mesos_tests_SOURCES += tests/sched_tests.cpp mesos_tests_SOURCES += tests/setns_test_helper.cpp endif http://git-wip-us.apache.org/repos/asf/mesos/blob/6de149e4/src/linux/sched.hpp ---------------------------------------------------------------------- diff --git a/src/linux/sched.hpp b/src/linux/sched.hpp new file mode 100644 index 0000000..2ae80be --- /dev/null +++ b/src/linux/sched.hpp @@ -0,0 +1,93 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LINUX_SCHED_HPP__ +#define __LINUX_SCHED_HPP__ + +// This file contains Linux-only OS utilities. +#ifndef __linux__ +#error "linux/sched.hpp is only available on Linux systems." +#endif + +#include <sched.h> + +#include <sys/types.h> + +#include <stout/error.hpp> +#include <stout/none.hpp> +#include <stout/nothing.hpp> +#include <stout/option.hpp> +#include <stout/try.hpp> + +namespace sched { + +enum Policy +{ + OTHER = SCHED_OTHER, // Default policy. + BATCH = SCHED_BATCH, // Non-interactive, CPU intensive. + IDLE = SCHED_IDLE, // Very low priority. + FIFO = SCHED_FIFO, // Realtime. + RR = SCHED_RR // Realtime, round-robin. +}; + + +namespace policy { + +// Return the current scheduling policy for the specified pid, or for +// the caller if pid is None() or zero. +inline Try<Policy> get(const Option<pid_t>& pid = None()) +{ + int status = sched_getscheduler(pid.isSome() ? pid.get() : 0); + + if (status == -1) { + return ErrnoError("Failed to get scheduler policy"); + } + + return static_cast<Policy>(status); +} + + +// Set the scheduling policy for the specified pid, or for the caller +// if pid is None() or zero. Only realtime scheduling policies (FIFO +// and RR) accept a priority (within a range, see +// sched_setscheduler(2)). +// TODO(idownes): Add wrappers around sched_get_priority_{min,max}. +inline Try<Nothing> set( + Policy policy, + const Option<pid_t>& pid = None(), + int priority = 0) +{ + if ((policy == OTHER || policy == BATCH || policy == IDLE) && + priority != 0) { + return Error("Non-real-time scheduling policies only support priority = 0"); + } + + sched_param param; + param.sched_priority = priority; + + if (sched_setscheduler(pid.isSome() ? pid.get() : 0, policy, ¶m) == -1) { + return ErrnoError("Failed to set scheduler policy"); + } + + return Nothing(); +} + +} // namespace policy { +} // namespace sched { + +#endif // __LINUX_SCHED_HPP__ http://git-wip-us.apache.org/repos/asf/mesos/blob/6de149e4/src/tests/sched_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/sched_tests.cpp b/src/tests/sched_tests.cpp new file mode 100644 index 0000000..00723d0 --- /dev/null +++ b/src/tests/sched_tests.cpp @@ -0,0 +1,96 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "linux/sched.hpp" + +#include <process/gtest.hpp> +#include <process/reap.hpp> + +#include <gtest/gtest.h> + +#include <stout/gtest.hpp> + +using sched::Policy; + +namespace mesos { +namespace internal { +namespace tests { + +// TODO(idownes): Test the priority and preemption behavior for +// running competing SCHED_OTHER and SCHED_IDLE tasks. + +TEST(SchedTest, ROOT_PolicySelf) +{ + Try<Policy> original = sched::policy::get(); + ASSERT_SOME(original); + + Policy different = (original.get() == Policy::OTHER ? Policy::IDLE + : Policy::OTHER); + + // Change our own scheduling policy. + EXPECT_SOME(sched::policy::set(different)); + EXPECT_SOME_EQ(different, sched::policy::get()); + + // Change it back. + EXPECT_SOME(sched::policy::set(original.get())); + EXPECT_SOME_EQ(original.get(), sched::policy::get()); +} + + +// Change the scheduling policy of a different process (our child). +TEST(SchedTest, ROOT_PolicyChild) +{ + Try<Policy> original = sched::policy::get(); + ASSERT_SOME(original); + + Policy different = (original.get() == Policy::OTHER ? Policy::IDLE + : Policy::OTHER); + + pid_t pid = ::fork(); + ASSERT_NE(-1, pid); + + if (pid == 0) { + // Child. + sleep(10); + + ABORT("Child process should not reach here"); + } + + // Continue in parent. + // Check the child has inherited our policy. + EXPECT_SOME_EQ(original.get(), sched::policy::get(pid)); + + // Check we can change the child's policy. + EXPECT_SOME(sched::policy::set(different, pid)); + EXPECT_SOME_EQ(different, sched::policy::get(pid)); + + process::Future<Option<int>> status = process::reap(pid); + + // Kill the child process. + ASSERT_NE(-1, ::kill(pid, SIGKILL)); + + // Wait for the child process. + AWAIT_READY(status); + ASSERT_SOME(status.get()); + EXPECT_TRUE(WIFSIGNALED(status.get().get())); + EXPECT_EQ(SIGKILL, WTERMSIG(status.get().get())); +} + +} // namespace tests { +} // namespace internal { +} // namespace mesos {
