Repository: mesos Updated Branches: refs/heads/master 0d4548cb6 -> 0802b3c79
Added a benchmark test for Registrar which is enabled by 'make bench'. Review: https://reviews.apache.org/r/19761 Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/0802b3c7 Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/0802b3c7 Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/0802b3c7 Branch: refs/heads/master Commit: 0802b3c797a04d9bbd339777accbc77c3b7e39a0 Parents: 0d4548c Author: Jiang Yan Xu <[email protected]> Authored: Thu Mar 27 11:22:08 2014 -0700 Committer: Jiang Yan Xu <[email protected]> Committed: Mon Apr 14 15:42:54 2014 -0700 ---------------------------------------------------------------------- src/tests/registrar_tests.cpp | 146 ++++++++++++++++++++++++++++++++++--- 1 file changed, 136 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/0802b3c7/src/tests/registrar_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/registrar_tests.cpp b/src/tests/registrar_tests.cpp index 67c26aa..c0ef0ca 100644 --- a/src/tests/registrar_tests.cpp +++ b/src/tests/registrar_tests.cpp @@ -16,14 +16,19 @@ * limitations under the License. */ +#include <algorithm> #include <map> #include <string> +#include <vector> #include <process/gmock.hpp> #include <process/gtest.hpp> #include <process/pid.hpp> #include <process/process.hpp> +#include <stout/bytes.hpp> +#include <stout/stopwatch.hpp> + #include "common/protobuf_utils.hpp" #include "common/type_utils.hpp" @@ -31,6 +36,7 @@ #include "master/master.hpp" #include "master/registrar.hpp" +#include "state/in_memory.hpp" #include "state/leveldb.hpp" #include "state/protobuf.hpp" #include "state/storage.hpp" @@ -42,6 +48,7 @@ using namespace process; using std::map; using std::string; +using std::vector; using testing::_; using testing::Eq; @@ -55,16 +62,16 @@ class RegistrarTest : public ::testing::TestWithParam<bool> public: RegistrarTest() : storage(NULL), - state(NULL), - path(os::getcwd() + "/.state") {} + state(NULL) {} protected: virtual void SetUp() { - os::rmdir(path); - // TODO(bmahler): Only use LevelDBStorage or LogStorage for - // performance testing, otherwise just use InMemoryStorage. - storage = new state::LevelDBStorage(path); + // We use InMemoryStorage to test Registrar correctness and + // LevelDBStorage to test performance. + // TODO(xujyan): Use LogStorage to exercise what we're using in + // production. + storage = new state::InMemoryStorage(); state = new state::protobuf::State(storage); master.CopyFrom(protobuf::createMasterInfo(UPID("[email protected]:5050"))); flags.registry_strict = GetParam(); @@ -74,16 +81,12 @@ protected: { delete state; delete storage; - os::rmdir(path); } state::Storage* storage; state::protobuf::State* state; MasterInfo master; Flags flags; - -private: - const std::string path; }; @@ -281,6 +284,129 @@ TEST_P(RegistrarTest, bootstrap) } } + +// We are not inheriting from RegistrarTest because this test fixture +// derives from a different instantiation of the TestWithParam template. +class Registrar_BENCHMARK_Test : public ::testing::TestWithParam<size_t> +{ +public: + Registrar_BENCHMARK_Test() + : storage(NULL), + state(NULL), + path(os::getcwd() + "/.state") {} + +protected: + virtual void SetUp() + { + os::rmdir(path); + + // We use InMemoryStorage to test Registrar correctness and + // LevelDBStorage to test performance. + storage = new state::LevelDBStorage(path); + state = new state::protobuf::State(storage); + master.CopyFrom(protobuf::createMasterInfo(UPID("[email protected]:5050"))); + + // Strictness is not important in our benchmark tests so it's + // just set to false here. + flags.registry_strict = false; + } + + virtual void TearDown() + { + delete state; + delete storage; + os::rmdir(path); + } + + state::Storage* storage; + state::protobuf::State* state; + MasterInfo master; + Flags flags; + +private: + const std::string path; +}; + + +// The Registrar benchmark tests are parameterized by the number of slaves. +INSTANTIATE_TEST_CASE_P( + SlaveCount, + Registrar_BENCHMARK_Test, + ::testing::Values(10000U, 20000U, 30000U, 50000U)); + + +TEST_P(Registrar_BENCHMARK_Test, performance) +{ + Registrar registrar(flags, state); + AWAIT_READY(registrar.recover(master)); + + vector<SlaveInfo> infos; + + Attributes attributes = Attributes::parse("foo:bar;baz:quux"); + Resources resources = + Resources::parse("cpus(*):1.0;mem(*):512;disk(*):2048").get(); + + size_t slaveCount = GetParam(); + + // Create slaves. + for (size_t i = 0; i < slaveCount; ++i) { + // Simulate real slave information. + SlaveInfo info; + info.set_hostname("localhost"); + info.mutable_id()->set_value( + std::string("201310101658-2280333834-5050-48574-") + stringify(i)); + info.mutable_resources()->MergeFrom(resources); + info.mutable_attributes()->MergeFrom(attributes); + infos.push_back(info); + } + + // Admit slaves. + Stopwatch watch; + watch.start(); + Future<bool> result; + foreach (const SlaveInfo& info, infos) { + result = registrar.apply(Owned<Operation>(new AdmitSlave(info))); + } + AWAIT_READY_FOR(result, Minutes(5)); + LOG(INFO) << "Admitted " << slaveCount << " slaves in " << watch.elapsed(); + + // Shuffle the slaves so we are readmitting them in random order ( + // same as in production). + std::random_shuffle(infos.begin(), infos.end()); + + // Readmit slaves. + watch.start(); + foreach (const SlaveInfo& info, infos) { + result = registrar.apply(Owned<Operation>(new ReadmitSlave(info))); + } + AWAIT_READY_FOR(result, Minutes(5)); + LOG(INFO) << "Readmitted " << slaveCount << " slaves in " << watch.elapsed(); + + // Recover slaves. + Registrar registrar2(flags, state); + watch.start(); + MasterInfo info; + info.set_id("master"); + info.set_ip(10000000); + info.set_port(5050); + Future<Registry> registry = registrar2.recover(info); + AWAIT_READY(registry); + LOG(INFO) << "Recovered " << slaveCount << " slaves (" + << Bytes(registry.get().ByteSize()) << ") in " << watch.elapsed(); + + // Shuffle the slaves so we are removing them in random order (same + // as in production). + std::random_shuffle(infos.begin(), infos.end()); + + // Remove slaves. + watch.start(); + foreach (const SlaveInfo& info, infos) { + result = registrar2.apply(Owned<Operation>(new RemoveSlave(info))); + } + AWAIT_READY_FOR(result, Minutes(5)); + LOG(INFO) << "Removed " << slaveCount << " slaves in " << watch.elapsed(); +} + } // namespace master { } // namespace internal { } // namespace mesos {
