Skip to content

Commit

Permalink
Merge pull request #605 from intel/lukevalenty/aggressive_flow_step_i…
Browse files Browse the repository at this point in the history
…nline

enable more aggressive inlining of flows
  • Loading branch information
lukevalenty authored Aug 27, 2024
2 parents 4b0fbb3 + f5aa4e5 commit 6367d04
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 83 deletions.
9 changes: 8 additions & 1 deletion include/flow/graph_builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,14 @@ struct graph_builder {
constexpr auto built = build(v);
static_assert(built.has_value(),
"Topological sort failed: cycle in flow");
return *built;

constexpr auto functionPtrs = built->functionPtrs;
constexpr auto size = functionPtrs.size();
constexpr auto name = built->name;

return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return detail::inlined_func_list<name, functionPtrs[Is]...>{};
}(std::make_index_sequence<size>{});
}

constexpr static auto run() { built()(); }
Expand Down
31 changes: 16 additions & 15 deletions include/flow/impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,6 @@
#include <type_traits>

namespace flow {
// NOLINTNEXTLINE(cppcoreguidelines-virtual-class-destructor)
struct interface {
virtual auto operator()() const -> void {}
};

/**
* flow::impl is a constant representation of a series of Milestones and actions
* to be executed in a specific order.
Expand All @@ -35,8 +30,7 @@ struct interface {
*
* @see flow::builder
*/
template <stdx::ct_string Name, std::size_t NumSteps>
class impl : public interface {
template <stdx::ct_string Name, std::size_t NumSteps> class impl {
private:
constexpr static bool loggingEnabled = not Name.empty();

Expand All @@ -48,12 +42,14 @@ class impl : public interface {
}
}();

public:
stdx::cx_vector<FunctionPtr, capacity> functionPtrs{};

public:
using node_t = rt_node;
constexpr static bool active = capacity > 0;

constexpr static auto name = Name;

/**
* Create a new flow::impl of Milestones.
*
Expand All @@ -77,24 +73,29 @@ class impl : public interface {
[](auto const &milestone) { return milestone.run; });
}
}
};

namespace detail {
template <stdx::ct_string Name, auto... FuncPtrs> struct inlined_func_list {
constexpr static auto active = sizeof...(FuncPtrs) > 0;

__attribute__((flatten, always_inline)) auto operator()() const -> void {
constexpr static bool loggingEnabled = not Name.empty();

/**
* Execute the entire flow in order.
*/
__attribute__((flatten)) auto operator()() const -> void final {
constexpr auto name =
stdx::ct_string_to_type<Name, sc::string_constant>();

if constexpr (loggingEnabled) {
CIB_TRACE("flow.start({})", name);
}

[this]<std::size_t... Is>(std::index_sequence<Is...>) {
(functionPtrs[Is](), ...);
}(std::make_index_sequence<capacity>{});
(FuncPtrs(), ...);

if constexpr (loggingEnabled) {
CIB_TRACE("flow.end({})", name);
}
}
};
} // namespace detail

} // namespace flow
18 changes: 11 additions & 7 deletions include/flow/step.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,20 @@ template <stdx::ct_string Name> struct ct_node : rt_node {
decltype(stdx::ct_string_to_type<Name, sc::string_constant>());
};

template <stdx::ct_string Name, stdx::ct_string Type>
static void log_name_func() {
CIB_TRACE("flow.{}({})",
stdx::ct_string_to_type<Type, sc::string_constant>(),
stdx::ct_string_to_type<Name, sc::string_constant>());
}

namespace detail {
template <stdx::ct_string Name, stdx::ct_string Type, typename F>
[[nodiscard]] constexpr auto make_node() {
return ct_node<Name>{
{.run = F{}, .log_name = [] {
CIB_TRACE("flow.{}({})",
stdx::ct_string_to_type<Type, sc::string_constant>(),
stdx::ct_string_to_type<Name, sc::string_constant>());
}}};
return ct_node<Name>{{.run = F{}, .log_name = log_name_func<Name, Type>}};
}

constexpr auto empty_func = []() {};
} // namespace detail

template <stdx::ct_string Name, typename F>
Expand All @@ -54,7 +58,7 @@ template <stdx::ct_string Name> [[nodiscard]] constexpr auto step() {
}

template <stdx::ct_string Name> [[nodiscard]] constexpr auto milestone() {
return detail::make_node<Name, "milestone", decltype([] {})>();
return detail::make_node<Name, "milestone", decltype(detail::empty_func)>();
}

inline namespace literals {
Expand Down
154 changes: 94 additions & 60 deletions test/flow/graph_builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,106 +19,127 @@ constexpr auto d = flow::action<"d">([] { actual += "d"; });
using builder = flow::graph_builder<flow::impl>;
} // namespace

struct empty_flow {
constexpr static auto value = flow::graph<>{};
};
TEST_CASE("build and run empty flow", "[graph_builder]") {
auto g = flow::graph<>{};
auto const flow = builder::build(g);
REQUIRE(flow.has_value());
flow.value()();
constexpr auto f = builder::render<empty_flow>();
f();
}

struct single_action {
constexpr static auto value = flow::graph<>{}.add(a);
};
TEST_CASE("add single action", "[graph_builder]") {
actual.clear();
auto g = flow::graph<>{}.add(a);
auto const flow = builder::build(g);
REQUIRE(flow.has_value());
flow.value()();
constexpr auto f = builder::render<single_action>();
f();
CHECK(actual == "a");
}

struct two_milestone_linear_before {
constexpr static auto value = flow::graph<>{}.add(a >> milestone0);
};
TEST_CASE("two milestone linear before dependency", "[graph_builder]") {
actual.clear();
auto g = flow::graph<>{}.add(a >> milestone0);
auto const flow = builder::build(g);
REQUIRE(flow.has_value());
flow.value()();
constexpr auto f = builder::render<two_milestone_linear_before>();
f();
CHECK(actual == "a");
}

struct actions_get_executed_once {
constexpr static auto value = flow::graph<>{}
.add(a >> milestone0)
.add(a >> milestone1)
.add(milestone0 >> milestone1);
};
TEST_CASE("actions get executed once", "[graph_builder]") {
actual.clear();
auto g = flow::graph<>{}
.add(a >> milestone0)
.add(a >> milestone1)
.add(milestone0 >> milestone1);
auto const flow = builder::build(g);
flow.value()();
constexpr auto f = builder::render<actions_get_executed_once>();
f();
CHECK(actual == "a");
}

struct two_milestone_linear_after_dependency {
constexpr static auto value = flow::graph<>{}
.add(a >> milestone0)
.add(milestone0 >> milestone1)
.add(milestone0 >> b >> milestone1);
};
TEST_CASE("two milestone linear after dependency", "[graph_builder]") {
actual.clear();
auto g = flow::graph<>{}
.add(a >> milestone0)
.add(milestone0 >> milestone1)
.add(milestone0 >> b >> milestone1);
auto const flow = builder::build(g);
flow.value()();
constexpr auto f = builder::render<two_milestone_linear_after_dependency>();
f();
CHECK(actual == "ab");
}

struct three_milestone_linear_before_and_after_dependency {
constexpr static auto value = flow::graph<>{}.add(a >> b >> c);
};
TEST_CASE("three milestone linear before and after dependency",
"[graph_builder]") {
actual.clear();
auto g = flow::graph<>{}.add(a >> b >> c);
auto const flow = builder::build(g);
flow.value()();
constexpr auto f =
builder::render<three_milestone_linear_before_and_after_dependency>();
f();
CHECK(actual == "abc");
}

struct just_two_actions_in_order {
constexpr static auto value = flow::graph<>{}.add(a >> b);
};
TEST_CASE("just two actions in order", "[graph_builder]") {
actual.clear();
auto g = flow::graph<>{}.add(a >> b);
auto const flow = builder::build(g);
flow.value()();
constexpr auto f = builder::render<just_two_actions_in_order>();
f();
CHECK(actual == "ab");
}

struct insert_action_between_two_actions {
constexpr static auto value = flow::graph<>{}.add(a >> c).add(a >> b >> c);
};
TEST_CASE("insert action between two actions", "[graph_builder]") {
actual.clear();
auto g = flow::graph<>{}.add(a >> c).add(a >> b >> c);
auto const flow = builder::build(g);
flow.value()();
constexpr auto f = builder::render<insert_action_between_two_actions>();
f();
CHECK(actual == "abc");
}

struct add_single_parallel_2 {
constexpr static auto value = flow::graph<>{}.add(a && b);
};
TEST_CASE("add single parallel 2", "[graph_builder]") {
actual.clear();
auto g = flow::graph<>{}.add(a && b);
auto const flow = builder::build(g);
flow.value()();
constexpr auto f = builder::render<add_single_parallel_2>();
f();

CHECK(actual.find('a') != std::string::npos);
CHECK(actual.find('b') != std::string::npos);
CHECK(actual.size() == 2);
}

struct add_single_parallel_3 {
constexpr static auto value = flow::graph<>{}.add(a && b && c);
};
TEST_CASE("add single parallel 3", "[graph_builder]") {
actual.clear();
auto g = flow::graph<>{}.add(a && b && c);
auto const flow = builder::build(g);
flow.value()();
constexpr auto f = builder::render<add_single_parallel_3>();
f();

CHECK(actual.find('a') != std::string::npos);
CHECK(actual.find('b') != std::string::npos);
CHECK(actual.find('c') != std::string::npos);
CHECK(actual.size() == 3);
}

struct add_single_parallel_3_with_later_dependency_1 {
constexpr static auto value = flow::graph<>{}.add(a && b && c).add(c >> a);
};
TEST_CASE("add single parallel 3 with later dependency 1", "[graph_builder]") {
actual.clear();
auto g = flow::graph<>{}.add(a && b && c).add(c >> a);
auto const flow = builder::build(g);
flow.value()();
constexpr auto f =
builder::render<add_single_parallel_3_with_later_dependency_1>();
f();

CHECK(actual.find('a') != std::string::npos);
CHECK(actual.find('b') != std::string::npos);
Expand All @@ -127,11 +148,14 @@ TEST_CASE("add single parallel 3 with later dependency 1", "[graph_builder]") {
CHECK(actual.size() == 3);
}

struct add_single_parallel_3_with_later_dependency_2 {
constexpr static auto value = flow::graph<>{}.add(a && b && c).add(a >> c);
};
TEST_CASE("add single parallel 3 with later dependency 2", "[graph_builder]") {
actual.clear();
auto g = flow::graph<>{}.add(a && b && c).add(a >> c);
auto const flow = builder::build(g);
flow.value()();
constexpr auto f =
builder::render<add_single_parallel_3_with_later_dependency_2>();
f();

CHECK(actual.find('a') != std::string::npos);
CHECK(actual.find('b') != std::string::npos);
Expand All @@ -140,11 +164,13 @@ TEST_CASE("add single parallel 3 with later dependency 2", "[graph_builder]") {
CHECK(actual.size() == 3);
}

struct add_parallel_rhs {
constexpr static auto value = flow::graph<>{}.add(a >> (b && c));
};
TEST_CASE("add parallel rhs", "[graph_builder]") {
actual.clear();
auto g = flow::graph<>{}.add(a >> (b && c));
auto const flow = builder::build(g);
flow.value()();
constexpr auto f = builder::render<add_parallel_rhs>();
f();

CHECK(actual.find('a') != std::string::npos);
CHECK(actual.find('b') != std::string::npos);
Expand All @@ -154,11 +180,13 @@ TEST_CASE("add parallel rhs", "[graph_builder]") {
CHECK(actual.size() == 3);
}

struct add_parallel_lhs {
constexpr static auto value = flow::graph<>{}.add((a && b) >> c);
};
TEST_CASE("add parallel lhs", "[graph_builder]") {
actual.clear();
auto g = flow::graph<>{}.add((a && b) >> c);
auto const flow = builder::build(g);
flow.value()();
constexpr auto f = builder::render<add_parallel_lhs>();
f();

CHECK(actual.find('a') != std::string::npos);
CHECK(actual.find('b') != std::string::npos);
Expand All @@ -168,11 +196,13 @@ TEST_CASE("add parallel lhs", "[graph_builder]") {
CHECK(actual.size() == 3);
}

struct add_parallel_in_the_middle {
constexpr static auto value = flow::graph<>{}.add(a >> (b && c) >> d);
};
TEST_CASE("add parallel in the middle", "[graph_builder]") {
actual.clear();
auto g = flow::graph<>{}.add(a >> (b && c) >> d);
auto const flow = builder::build(g);
flow.value()();
constexpr auto f = builder::render<add_parallel_in_the_middle>();
f();

CHECK(actual.find('a') != std::string::npos);
CHECK(actual.find('b') != std::string::npos);
Expand All @@ -188,11 +218,13 @@ TEST_CASE("add parallel in the middle", "[graph_builder]") {
CHECK(actual.size() == 4);
}

struct add_dependency_lhs {
constexpr static auto value = flow::graph<>{}.add((a >> b) && c);
};
TEST_CASE("add dependency lhs", "[graph_builder]") {
actual.clear();
auto g = flow::graph<>{}.add((a >> b) && c);
auto const flow = builder::build(g);
flow.value()();
constexpr auto f = builder::render<add_dependency_lhs>();
f();

CHECK(actual.find('a') != std::string::npos);
CHECK(actual.find('b') != std::string::npos);
Expand All @@ -203,11 +235,13 @@ TEST_CASE("add dependency lhs", "[graph_builder]") {
CHECK(actual.size() == 3);
}

struct add_dependency_rhs {
constexpr static auto value = flow::graph<>{}.add(a && (b >> c));
};
TEST_CASE("add dependency rhs", "[graph_builder]") {
actual.clear();
auto g = flow::graph<>{}.add(a && (b >> c));
auto const flow = builder::build(g);
flow.value()();
constexpr auto f = builder::render<add_dependency_rhs>();
f();

CHECK(actual.find('a') != std::string::npos);
CHECK(actual.find('b') != std::string::npos);
Expand Down

0 comments on commit 6367d04

Please sign in to comment.