Skip to content

Commit

Permalink
introduced support for timeouts (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
bigerl authored Feb 12, 2020
1 parent 4aa096a commit 5acb362
Show file tree
Hide file tree
Showing 14 changed files with 339 additions and 212 deletions.
9 changes: 7 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.13)
project(hypertrie VERSION 0.5.0)
project(hypertrie VERSION 0.5.1)
set(CMAKE_CXX_STANDARD 17)

include(${CMAKE_BINARY_DIR}/conan_paths.cmake)
Expand All @@ -12,7 +12,12 @@ endif ()

if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -fomit-frame-pointer -momit-leaf-frame-pointer")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi")

set(CMAKE_THREAD_LIBS_INIT "-lpthread")
set(CMAKE_HAVE_THREADS_LIBRARY 1)
set(CMAKE_USE_WIN32_THREADS_INIT 0)
set(CMAKE_USE_PTHREADS_INIT 1)
set(THREADS_PREFER_PTHREAD_FLAG ON)
else ()
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -fomit-frame-pointer")
endif ()
Expand Down
2 changes: 1 addition & 1 deletion conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

class Hypertrie(ConanFile):
name = "hypertrie"
version = "0.5"
version = "0.5.1"
author = "DICE Group <[email protected]>"
description = "A flexible data structure for low-rank, sparse tensors supporting slices by any dimension and einstein summation (einsum)"
homepage = "https://github.com/dice-group/hypertrie"
Expand Down
7 changes: 2 additions & 5 deletions include/Dice/einsum/internal/CardinalityEstimation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
#include "Dice/einsum/internal/Subscript.hpp"
#include "Dice/einsum/internal/Entry.hpp"

#define DEBUGCARD

namespace einsum::internal {


Expand All @@ -23,7 +21,8 @@ namespace einsum::internal {
* @return
*/
static Label getMinCardLabel(const std::vector<const_BoolHypertrie_t> &operands,
const std::shared_ptr<Subscript> &sc) {
const std::shared_ptr<Subscript> &sc,
std::shared_ptr<Context> context) {
const tsl::hopscotch_set <Label> &operandsLabelSet = sc->getOperandsLabelSet();
const tsl::hopscotch_set <Label> &lonely_non_result_labels = sc->getLonelyNonResultLabelSet();
if (operandsLabelSet.size() == 1) {
Expand Down Expand Up @@ -100,7 +99,5 @@ namespace einsum::internal {
return card;
}
};


}
#endif //HYPERTRIE_CARDINALITYESTIMATION_HPP
15 changes: 11 additions & 4 deletions include/Dice/einsum/internal/CartesianOperator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define HYPERTRIE_CARTESIANOPERATOR_HPP

#include "Dice/einsum/internal/Operator.hpp"
#include "Dice/einsum/internal/Context.hpp"
#include <tsl/sparse_map.h>

namespace einsum::internal {
Expand All @@ -21,6 +22,7 @@ namespace einsum::internal {
class FullCartesianResult;

std::shared_ptr<Subscript> subscript; // set in construct
std::shared_ptr<Context> context;
std::vector<Operator_t> sub_operators; // set in construct
std::vector<Entry < key_part_type, value_type>> sub_entries;
Entry <key_part_type, value_type> *entry;
Expand All @@ -31,14 +33,15 @@ namespace einsum::internal {
bool ended_ = true; // set in load_impl // updated in load_impl, next

public:
CartesianOperator(std::shared_ptr<Subscript> subscript)
: subscript(std::move(subscript)) {
CartesianOperator(std::shared_ptr<Subscript> subscript, std::shared_ptr<Context> context)
: subscript(std::move(subscript)),
context(context) {
// generate sub-operators
const std::vector<std::shared_ptr<Subscript>> &sub_subscripts = this->subscript->getCartesianSubscript().getSubSubscripts();
sub_operators.reserve(sub_subscripts.size());
sub_entries.reserve(sub_subscripts.size());
for (const auto &sub_subscript : sub_subscripts) {
sub_operators.push_back(Operator_t::construct(sub_subscript));
sub_operators.push_back(Operator_t::construct(sub_subscript, context));
using EntryKey = typename Entry<key_part_type, value_type>::key_type;
sub_entries.push_back({value_type(0), EntryKey(sub_subscript->resultLabelCount(), default_key_part)});
}
Expand Down Expand Up @@ -80,7 +83,7 @@ namespace einsum::internal {

static bool ended(void *self_raw) {
auto &self = *static_cast<CartesianOperator *>(self_raw);
return self.ended_;
return self.ended_ or self.context->hasTimedOut();
}

static std::size_t hash(void *self_raw) {
Expand Down Expand Up @@ -152,6 +155,10 @@ namespace einsum::internal {
assert(sub_entry.value);
sub_result[sub_entry.key] += sub_entry.value;
++cart_op;
if (this->context->hasTimedOut()){
ended_ = true;
return;
}
}
if (sub_result.empty()) {
ended_ = true;
Expand Down
58 changes: 58 additions & 0 deletions include/Dice/einsum/internal/Context.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#ifndef HYPERTRIE_CONTEXT_HPP
#define HYPERTRIE_CONTEXT_HPP

#include "Dice/einsum/internal/Subscript.hpp"

namespace einsum::internal {

using TimePoint = std::chrono::steady_clock::time_point;

/**
* The context is passed to very operator. It helps to pass information into the operator graph and allows the
* operators to communicate during execution.
* It is also responsible for managing timeouts.
*/
class Context {
constexpr static const uint max_counter = 500;
public:
/**
* The time after that the processing shall be stopped.
*/
TimePoint timeout;

/**
* The time is only checked when counter hits max_counter.
*/
uint counter = 0;

/**
* Indicates if the timeout was already reached.
*/
bool timed_out = false;

Context(TimePoint const &timeout = TimePoint::max()) : timeout(timeout) {}

/**
* Checks if the timeout is already reached. This method is intentionally unsynchronized.
* @return if the timeout was reached. If true, the timeout was reached for sure.
* If false, the timeout may already be reached.
* It will be reported monotonically starting approximately at one of the next max_counter calls of this method.
*/
inline bool hasTimedOut() {
if (this->timed_out)
return true;
else if (this->counter > max_counter) {
this->timed_out = this->timeout <= std::chrono::steady_clock::now();
if (not this->timed_out) {
this->counter = 0;
}
return this->counter;
}

++this->counter;
return false;
}
};

}
#endif //HYPERTRIE_CONTEXT_HPP
11 changes: 7 additions & 4 deletions include/Dice/einsum/internal/CountOperator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ namespace einsum::internal {
static constexpr key_part_type default_key_part = (std::is_pointer_v<key_part_type>) ? nullptr : std::numeric_limits<key_part_type>::max();

std::shared_ptr<Subscript> subscript;
std::shared_ptr<Context> context;
Entry<key_part_type, value_type> *entry;
bool _ended;


public:
CountOperator(std::shared_ptr<Subscript> subscript)
: subscript(std::move(subscript)) {}
CountOperator(std::shared_ptr<Subscript> subscript, std::shared_ptr<Context> context)
: subscript(std::move(subscript)),
context(context) {}


static void next(void *self_raw) {
Expand All @@ -26,7 +28,8 @@ namespace einsum::internal {
}

static bool ended(void *self_raw) {
return static_cast<CountOperator *>(self_raw)->_ended;
auto &self = *static_cast<CountOperator *>(self_raw);
return self._ended;
}

static void load(void *self_raw, std::vector<const_BoolHypertrie_t> operands, Entry<key_part_type, value_type> &entry) {
Expand All @@ -43,7 +46,7 @@ namespace einsum::internal {
assert(operands.size() == 1); // only one operand must be left to be resolved
this->entry->value = operands[0].size();
_ended = not this->entry->value;
if(not _ended)
if(not ended(this))
for(auto &key_part : entry.key)
key_part = std::numeric_limits<key_part_type>::max();
}
Expand Down
14 changes: 9 additions & 5 deletions include/Dice/einsum/internal/Einsum.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "Dice/einsum/internal/ResolveOperator.hpp"
#include "Dice/einsum/internal/CountOperator.hpp"
#include "Dice/einsum/internal/EntryGeneratorOperator.hpp"
#include "Dice/einsum/internal/Context.hpp"

namespace einsum::internal {
template<typename value_type, typename key_part_type, template<typename, typename> class map_type,
Expand All @@ -24,6 +25,7 @@ namespace einsum::internal {


std::shared_ptr<Subscript> subscript{};
std::shared_ptr<Context> context{};
std::vector<const_BoolHypertrie_t> operands{};
Operator_t op{};
Entry_t entry{};
Expand All @@ -32,8 +34,9 @@ namespace einsum::internal {
public:
Einsum() = default;

Einsum(std::shared_ptr<Subscript> subscript, const std::vector<const_BoolHypertrie_t> &operands)
: subscript(std::move(subscript)), operands(operands), op{Operator_t::construct(this->subscript)},
Einsum(std::shared_ptr<Subscript> subscript, const std::vector<const_BoolHypertrie_t> &operands, TimePoint timeout = TimePoint::max())
: subscript(std::move(subscript)), context{std::make_shared<Context>(timeout)},
operands(operands), op{Operator_t::construct(this->subscript, context)},
entry{0, Key_t(this->subscript->resultLabelCount(), std::numeric_limits<key_part_type>::max())} {}

[[nodiscard]] const std::shared_ptr<Subscript> &getSubscript() const {
Expand All @@ -51,7 +54,6 @@ namespace einsum::internal {
struct iterator {
private:


Operator_t *op;
Entry_t *current_entry;
bool ended_ = false;
Expand Down Expand Up @@ -107,13 +109,15 @@ namespace einsum::internal {
using Key_t = typename Entry_t::key_type;

std::shared_ptr<Subscript> subscript{};
std::shared_ptr<Context> context{};
std::vector<const_BoolHypertrie_t> operands{};
Operator_t op{};
Entry_t entry{};

public:
Einsum(std::shared_ptr<Subscript> subscript, const std::vector<const_BoolHypertrie_t> &operands)
: subscript(std::move(subscript)), operands(operands), op{Operator_t::construct(this->subscript)},
Einsum(std::shared_ptr<Subscript> subscript, const std::vector<const_BoolHypertrie_t> &operands, TimePoint timeout = std::numeric_limits<TimePoint>::max())
: subscript(std::move(subscript)), context{std::make_shared<Context>(timeout)},
operands(operands), op{Operator_t::construct(this->subscript, context)},
entry{false, Key_t(this->subscript->resultLabelCount(), std::numeric_limits<key_part_type>::max())} {}

[[nodiscard]] const std::shared_ptr<Subscript> &getSubscript() const {
Expand Down
6 changes: 4 additions & 2 deletions include/Dice/einsum/internal/EntryGeneratorOperator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ namespace einsum::internal {


std::shared_ptr<Subscript> subscript;
std::shared_ptr<Context> context;
Entry<key_part_type, value_type> *entry;
bool _ended = true;


public:
EntryGeneratorOperator(std::shared_ptr<Subscript> subscript)
: subscript(std::move(subscript)) {}
EntryGeneratorOperator(std::shared_ptr<Subscript> subscript, std::shared_ptr<Context> context)
: subscript(std::move(subscript)),
context(context) {}


static void next(void *self_raw) {
Expand Down
17 changes: 11 additions & 6 deletions include/Dice/einsum/internal/JoinOperator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "Dice/einsum/internal/Operator.hpp"
#include "Dice/einsum/internal/CardinalityEstimation.hpp"
#include "Dice/einsum/internal/Context.hpp"

namespace einsum::internal {

Expand All @@ -17,6 +18,7 @@ namespace einsum::internal {


std::shared_ptr<Subscript> subscript;
std::shared_ptr<Context> context;

Join_t join;
typename Join_t::iterator join_iter;
Expand All @@ -32,7 +34,9 @@ namespace einsum::internal {
bool ended_ = true;

public:
JoinOperator(std::shared_ptr<Subscript> subscript) : subscript(std::move(subscript)) {}
JoinOperator(std::shared_ptr<Subscript> subscript, std::shared_ptr<Context> context)
: subscript(std::move(subscript)),
context(context){}


static void next(void *self_raw) {
Expand All @@ -47,7 +51,7 @@ namespace einsum::internal {
++self.sub_operator;
while (self.sub_operator.ended()) {
++self.join_iter;
if (self.join_iter) {
if (self.join_iter and not self.context->hasTimedOut()){
std::vector<const_BoolHypertrie_t> next_operands;
std::tie(next_operands, self.current_key_part) = *self.join_iter;
self.sub_operator.load(std::move(next_operands), *self.entry);
Expand All @@ -64,7 +68,8 @@ namespace einsum::internal {
}

static bool ended(void *self_raw) {
return static_cast<JoinOperator *>(self_raw)->ended_;
auto &self = *static_cast<JoinOperator *>(self_raw);
return self.ended_ or self.context->hasTimedOut();
}

static void load(void *self_raw, std::vector<const_BoolHypertrie_t> operands, Entry<key_part_type, value_type> &entry) {
Expand All @@ -82,7 +87,7 @@ namespace einsum::internal {
this->entry = &entry;
ended_ = false;
Label last_label = label;
label = CardinalityEstimation_t::getMinCardLabel(operands, subscript);
label = CardinalityEstimation_t::getMinCardLabel(operands, subscript, context);
if (label != last_label) {
label_poss_in_ops = subscript->getLabelPossInOperands(label);
is_result_label = subscript->isResultLabel(label);
Expand All @@ -92,12 +97,12 @@ namespace einsum::internal {
const std::shared_ptr<Subscript> &next_subscript = subscript->removeLabel(label);
// check if sub_operator was not yet initialized or if the next subscript is different
if (sub_operator.type == Subscript::Type::None or sub_operator.hash() != next_subscript->hash()) {
sub_operator = Operator_t::construct(next_subscript);
sub_operator = Operator_t::construct(next_subscript, context);
}

join = Join_t{operands, label_poss_in_ops};
join_iter = join.begin();
while (join_iter != join.end()) {
while (join_iter != join.end() and not this->context->hasTimedOut()) {
std::vector<const_BoolHypertrie_t> next_operands;
std::tie(next_operands, current_key_part) = *join_iter;
sub_operator.load(std::move(next_operands), *this->entry);
Expand Down
14 changes: 8 additions & 6 deletions include/Dice/einsum/internal/Operator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

namespace einsum::internal {

class Context;


template<typename value_type, typename key_part_type, template<typename, typename> class map_type,
template<typename> class set_type>
Expand Down Expand Up @@ -86,21 +88,21 @@ namespace einsum::internal {

public:
static Operator
construct(std::shared_ptr<Subscript> subscript) {
construct(std::shared_ptr<Subscript> subscript, std::shared_ptr<Context> context) {
switch (subscript->type) {
case Subscript::Type::Join:
return {std::make_shared<JoinOperator<value_type, key_part_type, map_type, set_type >>(subscript)};
return {std::make_shared<JoinOperator<value_type, key_part_type, map_type, set_type >>(subscript, context)};
case Subscript::Type::Resolve:
return {std::make_shared<ResolveOperator<value_type, key_part_type, map_type, set_type >>(
subscript)};
subscript, context)};
case Subscript::Type::Count:
return {std::make_shared<CountOperator<value_type, key_part_type, map_type, set_type >>(subscript)};
return {std::make_shared<CountOperator<value_type, key_part_type, map_type, set_type >>(subscript, context)};
case Subscript::Type::Cartesian:
return {std::make_shared<CartesianOperator<value_type, key_part_type, map_type, set_type >>(
subscript)};
subscript, context)};
case Subscript::Type::EntryGenerator:
return {std::make_shared<EntryGeneratorOperator<value_type, key_part_type, map_type, set_type >>(
subscript)};
subscript, context)};
default:
throw std::invalid_argument{"subscript is of an undefined type."};
}
Expand Down
Loading

0 comments on commit 5acb362

Please sign in to comment.