Skip to content

Commit

Permalink
dispenso::Node remove std::function, use allocSmallBuffer
Browse files Browse the repository at this point in the history
Summary: Save functor inside `dispenso::Node` class for type erasure.

Reviewed By: graphicsMan

Differential Revision: D51058724

fbshipit-source-id: f0fb4e1b7e5d8e735c727e3227f61f1a1a21222d
  • Loading branch information
RomanFedotovFB authored and facebook-github-bot committed Nov 7, 2023
1 parent fd413d6 commit 4bced1d
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 13 deletions.
6 changes: 3 additions & 3 deletions benchmarks/graph_benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class BigTree {
};

template <class G>
static void BM_graph_big_tree(benchmark::State& state) {
static void BM_build_big_tree(benchmark::State& state) {
BigTree<G> bigTree;
bigTree.allocateMemory();
for (auto _ : state) {
Expand Down Expand Up @@ -174,8 +174,8 @@ static void BM_forward_propagator_node(benchmark::State& state) {
}
}

BENCHMARK(BM_graph_big_tree<dispenso::Graph>);
BENCHMARK(BM_graph_big_tree<dispenso::BiPropGraph>);
BENCHMARK(BM_build_big_tree<dispenso::Graph>);
BENCHMARK(BM_build_big_tree<dispenso::BiPropGraph>);
BENCHMARK(BM_build_bi_prop_dependency_chain);
BENCHMARK(BM_build_bi_prop_dependency_group);
BENCHMARK(BM_build_dependnecy_chain<dispenso::Graph>);
Expand Down
51 changes: 42 additions & 9 deletions dispenso/graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
#pragma once

#include <dispenso/platform.h>
#include <dispenso/small_buffer_allocator.h>
#include <atomic>
#include <deque>
#include <functional>
#include <limits>
#include <memory>
#include <type_traits>
Expand Down Expand Up @@ -197,6 +197,19 @@ Please read tests from `graph_test.cpp` for more examples.

namespace detail {
class ExecutorBase;

template <typename F>
void callFunctor(void* ptr) {
(*static_cast<F*>(ptr))();
}

template <typename F>
void destroyFunctor(void* ptr) {
static_cast<F*>(ptr)->~F();
constexpr size_t kFuncSize = static_cast<size_t>(dispenso::detail::nextPow2(sizeof(F)));
dispenso::deallocSmallBuffer<kFuncSize>(ptr);
}

} // namespace detail

namespace dispenso {
Expand All @@ -211,8 +224,17 @@ class Node {
Node(Node&& other) noexcept
: numIncompletePredecessors_(other.numIncompletePredecessors_.load()),
numPredecessors_(other.numPredecessors_),
f_(std::move(other.f_)),
dependents_(std::move(other.dependents_)) {}
invoke_(other.invoke_),
destroy_(other.destroy_),
funcBuffer_(other.funcBuffer_),
dependents_(std::move(other.dependents_)) {
other.funcBuffer_ = nullptr;
}
~Node() {
if (funcBuffer_) {
destroy_(funcBuffer_);
}
};
/**
* Make this node depends on nodes. This is not concurrency safe.
*
Expand All @@ -227,7 +249,7 @@ class Node {
* Concurrency safe.
**/
inline void run() const {
f_();
invoke_(funcBuffer_);
numIncompletePredecessors_.store(kCompleted, std::memory_order_release);
}
/**
Expand Down Expand Up @@ -292,8 +314,16 @@ class Node {
}

protected:
template <class T, class X = std::enable_if_t<!std::is_base_of<Node, T>::value, void>>
Node(T&& f) : numIncompletePredecessors_(0), f_(std::forward<T>(f)) {}
template <class F, class X = std::enable_if_t<!std::is_base_of<Node, F>::value, void>>
Node(F&& f) : numIncompletePredecessors_(0) {
using FNoRef = typename std::remove_reference<F>::type;

constexpr size_t kFuncSize = static_cast<size_t>(detail::nextPow2(sizeof(FNoRef)));
funcBuffer_ = allocSmallBuffer<kFuncSize>();
new (funcBuffer_) FNoRef(std::forward<F>(f));
invoke_ = ::detail::callFunctor<FNoRef>;
destroy_ = ::detail::destroyFunctor<FNoRef>;
}

void dependsOnOneNode(Node& node) {
node.dependents_.emplace_back(this);
Expand All @@ -305,9 +335,12 @@ class Node {
size_t numPredecessors_ = 0;

private:
// TODO(roman fedotov):create more efficient implementation than std::function
// (like dispenso::OnceFunction)
std::function<void()> f_;
using InvokerType = void (*)(void* ptr);

InvokerType invoke_;
InvokerType destroy_;
char* funcBuffer_;

std::vector<Node*> dependents_; // nodes depend on this

template <class N>
Expand Down
2 changes: 1 addition & 1 deletion dispenso/small_buffer_allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ inline char* allocSmallBuffer() {
return detail::allocSmallOrLarge<kBlockSize>();
}
/**
* Allocate a small buffer from a small buffer pool.
* Free a small buffer from a small buffer pool.
*
* @tparam kBlockSize The size of the block to allocate. Must be a power of two, and must be less
* than or equal to kMaxSmallBufferSize.
Expand Down

0 comments on commit 4bced1d

Please sign in to comment.