This is an automated email from the ASF dual-hosted git repository.
mzhu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git
The following commit(s) were added to refs/heads/master by this push:
new 69e92ae Added an benchmark for `allocator->UpdateAllocation()`.
69e92ae is described below
commit 69e92ae61ee352b3e0fbd7cfb577738ad66a7450
Author: Meng Zhu <[email protected]>
AuthorDate: Sun Oct 20 21:54:08 2019 -0700
Added an benchmark for `allocator->UpdateAllocation()`.
This benchmark evaluates the performance of
`allocator->UpdateAllocation()` where the agent has various
sizes of resource reservations.
Review: https://reviews.apache.org/r/71639
---
src/tests/hierarchical_allocator_tests.cpp | 209 +++++++++++++++++++++++++++++
1 file changed, 209 insertions(+)
diff --git a/src/tests/hierarchical_allocator_tests.cpp
b/src/tests/hierarchical_allocator_tests.cpp
index 38fd19c..882ab63 100644
--- a/src/tests/hierarchical_allocator_tests.cpp
+++ b/src/tests/hierarchical_allocator_tests.cpp
@@ -8367,6 +8367,215 @@ TEST_P(HierarchicalAllocator_BENCHMARK_Test,
AllocatorBacklog)
<< " allocation runs" << endl;
}
+
+struct ResourceParam
+{
+ ResourceParam(
+ const size_t _roleCount,
+ const size_t _reservationCount,
+ const size_t _portRangeCount)
+ : roleCount(_roleCount),
+ reservationCount(_reservationCount),
+ portRangeCount(_portRangeCount)
+ {}
+
+ ResourceParam() = default;
+
+ size_t roleCount;
+ size_t reservationCount;
+ size_t portRangeCount;
+};
+
+
+class HierarchicalAllocator__BENCHMARK_WithResourceParam
+ : public HierarchicalAllocatorTestBase,
+ public WithParamInterface<ResourceParam> {};
+
+
+// The `UpdateAllocation` benchmark is parametrized by the number of different
+// reservations of different roles on the agent. Specifically:
+//
+// Each set of reservations contains some cpu, memory, disk and port (number of
+// ranges is controlled by portRangeCount) with a random label, and is
allocated
+// to a framework.
+//
+// Each role will have `reservationCount` reservations (differed by labels)
+// on the given agent.
+//
+// Thus, in total, the given agent will have: "4 * reservationCount *
roleCount"
+// resource objects.
+INSTANTIATE_TEST_CASE_P(
+ ResourceParam,
+ HierarchicalAllocator__BENCHMARK_WithResourceParam,
+ ::testing::Values(
+ ResourceParam(50, 1, 1),
+ ResourceParam(100, 1, 1),
+ ResourceParam(200, 1, 1)));
+
+
+TEST_P(HierarchicalAllocator__BENCHMARK_WithResourceParam, UpdateAllocation)
+{
+ // This benchmark evaluates the performance of `UpdateAllocation()` call
+ // where an agent contains various sizes of resource reservations.
+ //
+ // During test setup, an agent is created with `roleCount` roles, each with
+ // `reservationCount` sets of allocated reservations. Each reservations
+ // is allocated to a framework. Each contains some cpu, memory, disk and port
+ // (number of ranges is controlled by `portRangeCount`) with a random label.
+ //
+ // During evaluation stage, one of the frameworks keeps reserving and
+ // unreseving its allocation. We measure the time spent in
`UpdateAllocation`.
+
+ initialize();
+
+ Clock::pause();
+
+ // Create agent resources.
+
+ // Helper to generate a random character with the given `length`.
+ auto randString = [](size_t length) -> string {
+ string s(length, 0);
+ std::generate(
+ s.begin(), s.end(), []() -> char { return 'a' + rand() % 26; });
+ return s;
+ };
+
+ const ResourceParam& param = GetParam();
+
+ const string LABEL_KEY = "Label";
+ const size_t labelValueLength = 36u;
+
+ const vector<string> RESOURCE_NAMES{"cpus", "mem", "disk", "port"};
+
+ // We introduce a level of role hierarchy here. Each role will be
+ // "parent_role/role-[random letters with childRoleLength]".
+ const size_t childRoleLength = 36u;
+ vector<string> roles(param.roleCount);
+ std::generate(roles.begin(), roles.end(), [&childRoleLength, &randString]() {
+ return "role-" + randString(childRoleLength);
+ });
+
+ Resources agentResources;
+ hashmap<FrameworkID, Resources> usedResources;
+
+ foreach (const string& role, roles) {
+ // Each slice of reservations is used by a framework.
+ // We first add that framework to the allocator.
+ FrameworkInfo framework = createFrameworkInfo({role});
+ usedResources.emplace(framework.id(), Resources());
+ allocator->addFramework(framework.id(), framework, {}, true, {});
+
+ // Create reservations.
+ for (size_t i = 0; i < param.reservationCount; ++i) {
+ foreach (const string& name, RESOURCE_NAMES) {
+ Resource resource = [&name, ¶m]() {
+ if (name != "port") {
+ return CHECK_NOTERROR(Resources::parse(name, "100", "*"));
+ } else {
+ Value::Ranges ranges;
+ for (size_t count = 1; count <= param.portRangeCount; ++count) {
+ *ranges.add_range() = createRange(count * 2, count * 2);
+ }
+
+ return createPorts(ranges);
+ }
+ }();
+
+ // Add reservation info.
+ Resource::ReservationInfo reservation;
+ reservation.set_type(Resource::ReservationInfo::DYNAMIC);
+ reservation.set_role(role);
+
+ // Each reservation will have one key-value label. The key is simply
+ // "Label", the value is a generated string with fixed length.
+ // Different labels will prevent resources of the same type
+ // from merging.
+ Label* label = reservation.mutable_labels()->add_labels();
+ label->set_key(LABEL_KEY);
+ label->set_value(randString(labelValueLength));
+ *resource.add_reservations() = std::move(reservation);
+
+ agentResources += resource;
+
+ // Allocate the resources to the framework.
+ resource.mutable_allocation_info()->set_role(role);
+ usedResources.at(framework.id()) += std::move(resource);
+ }
+ }
+ }
+
+ // We let one framework repeatedly reserve and unreserve allocated resources,
+ // and measure the `allocator->updateAllocation` time.
+
+ FrameworkID loopFrameworkId = usedResources.begin()->first;
+
+ // Operations to reserve and unreserve resources.
+
+ Resources reserveResources = usedResources.begin()->second;
+ Offer::Operation reserve = RESERVE(reserveResources);
+
+ Resources unReserveResources = reserveResources.toUnreserved();
+ Offer::Operation unreserve = UNRESERVE(reserveResources);
+
+ // Create an agent with the given resources.
+ SlaveInfo agent = createSlaveInfo(agentResources);
+ allocator->addSlave(
+ agent.id(),
+ agent,
+ AGENT_CAPABILITIES(),
+ None(),
+ agent.resources(),
+ usedResources);
+
+ Clock::settle();
+
+ size_t repetition = 20;
+
+ Duration reserveTime, unreserveTime;
+
+ Stopwatch watch;
+
+ for (size_t i = 0; i < repetition; ++i) {
+ watch.start();
+
+ allocator->updateAllocation(
+ loopFrameworkId,
+ agent.id(),
+ reserveResources,
+ CHECK_NOTERROR(getResourceConversions(unreserve)));
+
+ Clock::settle();
+
+ watch.stop();
+ unreserveTime += watch.elapsed();
+
+ watch.start();
+
+ allocator->updateAllocation(
+ loopFrameworkId,
+ agent.id(),
+ unReserveResources,
+ CHECK_NOTERROR(getResourceConversions(reserve)));
+ Clock::settle();
+
+ watch.stop();
+ reserveTime += watch.elapsed();
+ }
+
+ cout << "Agent resource object count: " << agentResources.size() << " ("
+ << param.roleCount << " roles, "
+ << param.reservationCount << " reservations per role, "
+ << param.portRangeCount << " ranges per port resource)"
+ << endl;
+ cout << repetition << " RESERVE operations took "
+ << reserveTime << ", each takes "
+ << reserveTime / repetition * 1.0 << endl;
+ cout << repetition << " UNRESERVE operations took "
+ << unreserveTime << ", each takes "
+ << unreserveTime / repetition * 1.0 << endl;
+}
+
+
} // namespace tests {
} // namespace internal {
} // namespace mesos {