diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d875829b49..5ab514d43d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ if (SOUFFLE_GIT) else() string(REGEX REPLACE "\n$" "" PACKAGE_VERSION "${GIT_PACKAGE_VERSION}") message(STATUS "Building souffle version ${PACKAGE_VERSION}") - + # SOUFFLE_VERSION only includes the major/minor triplet string(REGEX REPLACE "-.*$" "" SOUFFLE_VERSION "${PACKAGE_VERSION}") @@ -319,7 +319,7 @@ if (SOUFFLE_GENERATE_DOXYGEN) add_custom_target(doxygen COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_CFG} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMENT "Generating API documentation with Doxygen") endif() @@ -391,7 +391,7 @@ IF (SOUFFLE_BASH_COMPLETION) endif() install( - FILES "${CMAKE_SOURCE_DIR}/debian/souffle.bash-completion" + FILES "${PROJECT_SOURCE_DIR}/debian/souffle.bash-completion" DESTINATION ${BASH_COMPLETION_COMPLETIONSDIR} RENAME "souffle" ) @@ -402,7 +402,7 @@ if (NOT WIN32) # -------------------------------------------------- # CPack configuration # -------------------------------------------------- -execute_process(COMMAND bash "${CMAKE_SOURCE_DIR}/sh/check_os.sh" +execute_process(COMMAND bash "${PROJECT_SOURCE_DIR}/sh/check_os.sh" RESULT_VARIABLE CHECK_OS_RESULT OUTPUT_VARIABLE CHECK_OS_OUTPUT) @@ -414,7 +414,7 @@ SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A Datalog Compiler") SET(CPACK_THREADS 0) # Make sure changelog, bash-completion and other important files in debian directory also packaged -SET(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/debian/changelog" "${CMAKE_SOURCE_DIR}/debian/souffle.bash-completion" "${CMAKE_SOURCE_DIR}/debian/copyright") +SET(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${PROJECT_SOURCE_DIR}/debian/changelog" "${PROJECT_SOURCE_DIR}/debian/souffle.bash-completion" "${PROJECT_SOURCE_DIR}/debian/copyright") # -------------------------------------------------- # CPack configuration diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fa159d5923a..eb638c4d60b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,6 +8,7 @@ set(SOUFFLE_SOURCES FunctorOps.cpp Global.cpp + GraphUtils.cpp MainDriver.cpp ast/Annotation.cpp ast/Aggregator.cpp @@ -197,6 +198,8 @@ else () # OSX compiler doesn't recognise `(void)var;` ideom set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/parser/scanner.cc PROPERTIES COMPILE_FLAGS "-Wno-error=unused-parameter") + set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/parser/parser.cc PROPERTIES + COMPILE_FLAGS "-Wno-error=unused-but-set-variable") endif () # -------------------------------------------------- diff --git a/src/GraphUtils.cpp b/src/GraphUtils.cpp new file mode 100644 index 00000000000..714316510aa --- /dev/null +++ b/src/GraphUtils.cpp @@ -0,0 +1,87 @@ +/* + * Souffle - A Datalog Compiler + * Copyright (c) 2024, The Souffle Developers. All rights reserved + * Licensed under the Universal Permissive License v 1.0 as shown at: + * - https://opensource.org/licenses/UPL + * - /licenses/SOUFFLE-UPL.txt + */ +#include "GraphUtils.h" +#include "souffle/utility/FileUtil.h" + +#include +#include +#include + +namespace souffle { + +std::string toBase64(const std::string& data) { + static const std::vector table = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', + 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; + std::string result; + std::string tmp = data; + unsigned int padding = 0; + if (data.size() % 3 == 2) { + padding = 1; + } else if (data.size() % 3 == 1) { + padding = 2; + } + + for (unsigned int i = 0; i < padding; i++) { + tmp.push_back(0); + } + for (unsigned int i = 0; i < tmp.size(); i += 3) { + auto c1 = static_cast(tmp[i]); + auto c2 = static_cast(tmp[i + 1]); + auto c3 = static_cast(tmp[i + 2]); + unsigned char index1 = c1 >> 2; + unsigned char index2 = ((c1 & 0x03) << 4) | (c2 >> 4); + unsigned char index3 = ((c2 & 0x0F) << 2) | (c3 >> 6); + unsigned char index4 = c3 & 0x3F; + + result.push_back(table[index1]); + result.push_back(table[index2]); + result.push_back(table[index3]); + result.push_back(table[index4]); + } + if (padding == 1) { + result[result.size() - 1] = '='; + } else if (padding == 2) { + result[result.size() - 1] = '='; + result[result.size() - 2] = '='; + } + return result; +} + +std::string convertDotToSVG(const std::string& dotSpec) { + // Check if dot is present + std::string cmd = which("dot"); + if (!isExecutable(cmd)) { + return ""; + } + + if (dotSpec.size() > 50000) { + std::cerr << "skip graph with DOT spec length: " << dotSpec.size() << "\n"; + return ""; + } + + TempFileStream dotFile; + dotFile << dotSpec; + dotFile.flush(); + return execStdOut("dot -Tsvg < " + dotFile.getFileName()).str(); +} + +void printHTMLGraph(std::ostream& out, const std::string& dotSpec, const std::string& id) { + std::string data = convertDotToSVG(dotSpec); + + if (data.find("
\n"; + } else { + out << "
\n
" << dotSpec << "
\n"; + out << "
\n"; + } +} + +} // namespace souffle diff --git a/src/GraphUtils.h b/src/GraphUtils.h index aab91cfb9aa..104fe2bc3d8 100644 --- a/src/GraphUtils.h +++ b/src/GraphUtils.h @@ -13,84 +13,14 @@ * A simple utility graph for conducting simple, graph-based operations. * ***********************************************************************/ - #pragma once -#include "souffle/datastructure/Graph.h" -#include "souffle/utility/FileUtil.h" -#include -#include #include -#include #include -#include #include namespace souffle { - -inline std::string toBase64(const std::string& data) { - static const std::vector table = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', - 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; - std::string result; - std::string tmp = data; - unsigned int padding = 0; - if (data.size() % 3 == 2) { - padding = 1; - } else if (data.size() % 3 == 1) { - padding = 2; - } - - for (unsigned int i = 0; i < padding; i++) { - tmp.push_back(0); - } - for (unsigned int i = 0; i < tmp.size(); i += 3) { - auto c1 = static_cast(tmp[i]); - auto c2 = static_cast(tmp[i + 1]); - auto c3 = static_cast(tmp[i + 2]); - unsigned char index1 = c1 >> 2; - unsigned char index2 = ((c1 & 0x03) << 4) | (c2 >> 4); - unsigned char index3 = ((c2 & 0x0F) << 2) | (c3 >> 6); - unsigned char index4 = c3 & 0x3F; - - result.push_back(table[index1]); - result.push_back(table[index2]); - result.push_back(table[index3]); - result.push_back(table[index4]); - } - if (padding == 1) { - result[result.size() - 1] = '='; - } else if (padding == 2) { - result[result.size() - 1] = '='; - result[result.size() - 2] = '='; - } - return result; -} - -inline std::string convertDotToSVG(const std::string& dotSpec) { - // Check if dot is present - std::string cmd = which("dot"); - if (!isExecutable(cmd)) { - return ""; - } - - TempFileStream dotFile; - dotFile << dotSpec; - dotFile.flush(); - return execStdOut("dot -Tsvg < " + dotFile.getFileName()).str(); -} - -inline void printHTMLGraph(std::ostream& out, const std::string& dotSpec, const std::string& id) { - std::string data = convertDotToSVG(dotSpec); - - if (data.find("
\n"; - } else { - out << "
\n
" << dotSpec << "
\n"; - out << "
\n"; - } -} - +std::string toBase64(const std::string& data); +std::string convertDotToSVG(const std::string& dotSpec); +void printHTMLGraph(std::ostream& out, const std::string& dotSpec, const std::string& id); } // end of namespace souffle diff --git a/src/ast/Node.cpp b/src/ast/Node.cpp index 07bfe0d814d..18acab44e3a 100644 --- a/src/ast/Node.cpp +++ b/src/ast/Node.cpp @@ -6,6 +6,8 @@ * - /licenses/SOUFFLE-UPL.txt */ #include "ast/Node.h" + +#include #include namespace souffle::ast { diff --git a/src/ast/analysis/PrecedenceGraph.h b/src/ast/analysis/PrecedenceGraph.h index f50ae3a2e49..fda88f6b66d 100644 --- a/src/ast/analysis/PrecedenceGraph.h +++ b/src/ast/analysis/PrecedenceGraph.h @@ -21,7 +21,9 @@ #include "GraphUtils.h" #include "ast/Relation.h" #include "ast/TranslationUnit.h" -#include +#include "souffle/datastructure/Graph.h" +#include +#include namespace souffle::ast { diff --git a/src/ast/analysis/typesystem/Type.cpp b/src/ast/analysis/typesystem/Type.cpp index 4a267a70a0c..b50ae83ca6e 100644 --- a/src/ast/analysis/typesystem/Type.cpp +++ b/src/ast/analysis/typesystem/Type.cpp @@ -73,12 +73,12 @@ Own TypeAnalysis::createAnnotatedClause( Own operator()(Own node) const override { if (auto* var = as(node)) { std::stringstream newVarName; - newVarName << var->getName() << "∈" << types.find(var)->second; + newVarName << var->getName() << "∈" << types.find(var)->second; return mk(newVarName.str()); } else if (auto* var = as(node)) { std::stringstream newVarName; newVarName << "_" - << "∈" << types.find(var)->second; + << "∈" << types.find(var)->second; return mk(newVarName.str()); } node->apply(*this); @@ -707,8 +707,7 @@ void TypeAnnotationPrinter::print_(type_identity, const User auto arguments = fun.getArguments(); os << "@" << fun.getName() << "("; for (std::size_t i = 0; i < arguments.size(); ++i) { - TypeAttribute argType = typeAnalysis.getFunctorParamTypeAttribute(fun, i); - auto& ty = typeEnv.getConstantType(argType); + const auto& ty = typeAnalysis.getFunctorParamType(fun, i); branchOnArgument(arguments[i], ty); if (i + 1 < arguments.size()) { os << ","; @@ -736,7 +735,7 @@ void TypeAnnotationPrinter::print_(type_identity, const ast::TypeCast& void TypeAnnotationPrinter::print_( type_identity, const RecordInit& record, const RecordType& type) { auto arguments = record.getArguments(); - auto& ftypes = type.getFields(); + const auto& ftypes = type.getFields(); os << "["; for (std::size_t i = 0; i < arguments.size(); ++i) { branchOnArgument(arguments[i], *ftypes[i]); diff --git a/src/ast/analysis/typesystem/TypeEnvironment.cpp b/src/ast/analysis/typesystem/TypeEnvironment.cpp index cb82f1e449c..d43272864db 100644 --- a/src/ast/analysis/typesystem/TypeEnvironment.cpp +++ b/src/ast/analysis/typesystem/TypeEnvironment.cpp @@ -15,7 +15,6 @@ ***********************************************************************/ #include "ast/analysis/typesystem/TypeEnvironment.h" -#include "GraphUtils.h" #include "ast/AlgebraicDataType.h" #include "ast/AliasType.h" #include "ast/Attribute.h" @@ -27,6 +26,7 @@ #include "ast/Type.h" #include "ast/UnionType.h" #include "ast/analysis/typesystem/TypeSystem.h" +#include "souffle/datastructure/Graph.h" #include "souffle/utility/MiscUtil.h" #include "souffle/utility/tinyformat.h" #include diff --git a/src/ast/transform/InlineRelations.cpp b/src/ast/transform/InlineRelations.cpp index b95cf62b532..15401d725ca 100644 --- a/src/ast/transform/InlineRelations.cpp +++ b/src/ast/transform/InlineRelations.cpp @@ -42,7 +42,9 @@ #include "ast/UnnamedVariable.h" #include "ast/UserDefinedFunctor.h" #include "ast/Variable.h" +#include "ast/analysis/Ground.h" #include "ast/analysis/typesystem/PolymorphicObjects.h" +#include "ast/analysis/typesystem/TypeEnvironment.h" #include "ast/utility/Utils.h" #include "ast/utility/Visitor.h" #include "souffle/BinaryConstraintOps.h" diff --git a/src/ast/transform/PartitionBodyLiterals.cpp b/src/ast/transform/PartitionBodyLiterals.cpp index 0a7ad5bfc09..88ecb8e37a0 100644 --- a/src/ast/transform/PartitionBodyLiterals.cpp +++ b/src/ast/transform/PartitionBodyLiterals.cpp @@ -13,7 +13,6 @@ ***********************************************************************/ #include "ast/transform/PartitionBodyLiterals.h" -#include "GraphUtils.h" #include "ast/Atom.h" #include "ast/Clause.h" #include "ast/Literal.h" @@ -23,6 +22,7 @@ #include "ast/TranslationUnit.h" #include "ast/Variable.h" #include "ast/utility/Visitor.h" +#include "souffle/datastructure/Graph.h" #include "souffle/utility/MiscUtil.h" #include #include diff --git a/src/ast/transform/ReduceExistentials.cpp b/src/ast/transform/ReduceExistentials.cpp index 54d4904d8a6..02daf9983e5 100644 --- a/src/ast/transform/ReduceExistentials.cpp +++ b/src/ast/transform/ReduceExistentials.cpp @@ -13,7 +13,6 @@ ***********************************************************************/ #include "ast/transform/ReduceExistentials.h" -#include "GraphUtils.h" #include "RelationTag.h" #include "ast/Aggregator.h" #include "ast/Argument.h" @@ -30,6 +29,7 @@ #include "ast/analysis/IOType.h" #include "ast/utility/Utils.h" #include "ast/utility/Visitor.h" +#include "souffle/datastructure/Graph.h" #include "souffle/utility/MiscUtil.h" #include #include diff --git a/src/include/souffle/RecordTable.h b/src/include/souffle/RecordTable.h index 5c173cb4ee3..2a6c1ddcdcc 100644 --- a/src/include/souffle/RecordTable.h +++ b/src/include/souffle/RecordTable.h @@ -19,6 +19,8 @@ #include "souffle/RamTypes.h" #include "souffle/utility/span.h" + +#include #include namespace souffle { @@ -35,6 +37,10 @@ class RecordTable { virtual RamDomain pack(const std::initializer_list& List) = 0; virtual const RamDomain* unpack(const RamDomain Ref, const std::size_t Arity) const = 0; + + /// Enumerate each record. + virtual void enumerate(const std::function& Callback) const = 0; }; /** @brief helper to convert tuple to record reference for the synthesiser */ diff --git a/src/include/souffle/SignalHandler.h b/src/include/souffle/SignalHandler.h index 3e9beec20fc..d42897f077b 100644 --- a/src/include/souffle/SignalHandler.h +++ b/src/include/souffle/SignalHandler.h @@ -16,6 +16,8 @@ #pragma once +#include "souffle/profile/ProfileEvent.h" + #include #include #include @@ -52,6 +54,15 @@ class SignalHandler { void enableLogging() { logMessages = true; } + + void enableProfiling() { + profileEnabled = true; + } + + bool profilingEnabled() const { + return profileEnabled; + } + // set signal message void setMsg(const char* m) { if (logMessages && m != nullptr) { @@ -104,7 +115,9 @@ class SignalHandler { } /*** - * reset signal handlers + * Reset signal handlers. + * + * Disable profiling. */ void reset() { if (isSet) { @@ -125,6 +138,7 @@ class SignalHandler { } isSet = false; } + profileEnabled = false; } /*** @@ -150,6 +164,8 @@ class SignalHandler { bool logMessages = false; + bool profileEnabled = false; + // previous signal handler routines void (*prevFpeHandler)(int) = nullptr; void (*prevIntHandler)(int) = nullptr; @@ -196,6 +212,12 @@ class SignalHandler { else write({error, " signal.\n"}); + if (instance()->profilingEnabled()) { + write({error, "dumping profiling data...\n"}); + ProfileEventSingleton::instance().stopTimer(); + ProfileEventSingleton::instance().dump(); + } + std::_Exit(EXIT_FAILURE); } diff --git a/src/include/souffle/datastructure/BTree.h b/src/include/souffle/datastructure/BTree.h index 72b4fc90105..5adc0b57d5b 100644 --- a/src/include/souffle/datastructure/BTree.h +++ b/src/include/souffle/datastructure/BTree.h @@ -1857,9 +1857,11 @@ class btree { out << " Size of inner node: " << sizeof(inner_node) << "\n"; out << " Size of leaf node: " << sizeof(leaf_node) << "\n"; out << " Size of Key: " << sizeof(Key) << "\n"; - out << " max keys / node: " << node::maxKeys << "\n"; - out << " avg keys / node: " << (size() / (double)nodes) << "\n"; - out << " avg filling rate: " << ((size() / (double)nodes) / node::maxKeys) << "\n"; + out << " max keys / node: " << node::maxKeys << "\n"; + out << " avg keys / node: " << (nodes == 0 ? 0 : ((double)size() / (double)nodes)) << "\n"; + out << " avg filling rate: " + << (nodes == 0 ? 0 : (((double)size() / (double)nodes) / node::maxKeys)) << "\n"; + out << " Memory usage: " << (getMemoryUsage() / 1'000'000) << "MB\n"; out << " ---------------------------------\n"; out << " insert-hint (hits/misses/total): " << hint_stats.inserts.getHits() << "/" << hint_stats.inserts.getMisses() << "/" << hint_stats.inserts.getAccesses() << "\n"; diff --git a/src/include/souffle/datastructure/BTreeDelete.h b/src/include/souffle/datastructure/BTreeDelete.h index fc747ff1c46..13bdfad09e8 100644 --- a/src/include/souffle/datastructure/BTreeDelete.h +++ b/src/include/souffle/datastructure/BTreeDelete.h @@ -2418,9 +2418,11 @@ class btree_delete { out << " Size of inner node: " << sizeof(inner_node) << "\n"; out << " Size of leaf node: " << sizeof(leaf_node) << "\n"; out << " Size of Key: " << sizeof(Key) << "\n"; - out << " max keys / node: " << node::maxKeys << "\n"; - out << " avg keys / node: " << (size() / (double)nodes) << "\n"; - out << " avg filling rate: " << ((size() / (double)nodes) / node::maxKeys) << "\n"; + out << " max keys / node: " << node::maxKeys << "\n"; + out << " avg keys / node: " << (nodes == 0 ? 0 : ((double)size() / (double)nodes)) << "\n"; + out << " avg filling rate: " + << (nodes == 0 ? 0 : (((double)size() / (double)nodes) / node::maxKeys)) << "\n"; + out << " Memory usage: " << (getMemoryUsage() / 1'000'000) << "MB\n"; out << " ---------------------------------\n"; out << " insert-hint (hits/misses/total): " << hint_stats.inserts.getHits() << "/" << hint_stats.inserts.getMisses() << "/" << hint_stats.inserts.getAccesses() << "\n"; diff --git a/src/include/souffle/datastructure/ConcurrentFlyweight.h b/src/include/souffle/datastructure/ConcurrentFlyweight.h index ed41d11c8e9..afba41665cd 100644 --- a/src/include/souffle/datastructure/ConcurrentFlyweight.h +++ b/src/include/souffle/datastructure/ConcurrentFlyweight.h @@ -190,10 +190,15 @@ class ConcurrentFlyweight { static_assert(NONE == std::numeric_limits::max(), "required for wrap around to 0 for begin-iterator-scan"); static_assert(NONE + 1 == 0, "required for wrap around to 0 for begin-iterator-scan"); + while (Slot != END) { assert(Slot + 1 < SLOT_MAX); + if (Slot + 1 < NextMaybeUnassignedSlot) { // next unassigned slot not reached Slot = Slot + 1; + if (Slot == 0 && This->FirstSlotIsReserved) { + continue; + } return true; } @@ -226,10 +231,11 @@ class ConcurrentFlyweight { const bool ReserveFirst, const Hash& hash = Hash(), const KeyEqual& key_equal = KeyEqual(), const KeyFactory& key_factory = KeyFactory()) : Lanes(LaneCount), HandleCount(LaneCount), - Mapping(LaneCount, InitialCapacity, hash, key_equal, key_factory) { + Mapping(LaneCount, InitialCapacity, hash, key_equal, key_factory), + FirstSlotIsReserved(ReserveFirst) { Slots = std::make_unique(InitialCapacity); Handles = std::make_unique(HandleCount); - NextSlot = (ReserveFirst ? 1 : 0); + NextSlot = (FirstSlotIsReserved ? 1 : 0); SlotCount = InitialCapacity; } @@ -394,6 +400,9 @@ class ConcurrentFlyweight { // Number of slots. std::atomic SlotCount; + /// If true, the first slot (index 0) is not a valid entry. + const bool FirstSlotIsReserved; + /// Grow the datastructure if needed. bool tryGrow(const lane_id H) { // This call may release and re-acquire the lane to diff --git a/src/include/souffle/datastructure/EqRel.h b/src/include/souffle/datastructure/EqRel.h index 0254702f09b..4ca5bd9c3d2 100644 --- a/src/include/souffle/datastructure/EqRel.h +++ b/src/include/souffle/datastructure/EqRel.h @@ -173,7 +173,7 @@ struct t_eqrel { res[1] = t[0]; return res; } - void printStatistics(std::ostream& /* o */) const {} + void printStats(std::ostream& /* o */) const {} }; } // namespace souffle \ No newline at end of file diff --git a/src/include/souffle/datastructure/EquivalenceRelation.h b/src/include/souffle/datastructure/EquivalenceRelation.h index aebc569a40f..07651c1bf29 100644 --- a/src/include/souffle/datastructure/EquivalenceRelation.h +++ b/src/include/souffle/datastructure/EquivalenceRelation.h @@ -54,7 +54,7 @@ class EquivalenceRelation { public: using element_type = TupleType; - EquivalenceRelation() : statesMapStale(false){}; + EquivalenceRelation() : statesMapStale(false) {} ~EquivalenceRelation() { emptyPartition(); } @@ -79,7 +79,7 @@ class EquivalenceRelation { bool insert(value_type x, value_type y) { operation_hints z; return insert(x, y, z); - }; + } /** * Insert the tuple symbolically. @@ -89,7 +89,7 @@ class EquivalenceRelation { bool insert(const TupleType& tuple) { operation_hints hints; return insert(tuple[0], tuple[1], hints); - }; + } /** * Insert the two values symbolically as a binary relation @@ -208,11 +208,11 @@ class EquivalenceRelation { */ bool contains(const TupleType& tuple, operation_hints&) const { return contains(tuple[0], tuple[1]); - }; + } bool contains(const TupleType& tuple) const { return contains(tuple[0], tuple[1]); - }; + } void emptyPartition() const { // delete the beautiful values inside (they're raw ptrs, so they need to be.) @@ -270,7 +270,7 @@ class EquivalenceRelation { // one iterator for signalling the end (simplifies) explicit iterator(const EquivalenceRelation* br, bool /* signalIsEndIterator */) - : br(br), isEndVal(true){}; + : br(br), isEndVal(true) {} explicit iterator(const EquivalenceRelation* br) : br(br), ityp(IterType::ALL), djSetMapListIt(br->equivalencePartition.begin()), @@ -716,6 +716,8 @@ class EquivalenceRelation { return find(t, context); } + void printStats(std::ostream& /* o */) const {} + protected: bool containsElement(value_type e) const { return this->sds.nodeExists(e); diff --git a/src/include/souffle/datastructure/RecordTableImpl.h b/src/include/souffle/datastructure/RecordTableImpl.h index 2e7b9659c31..c96fda9efab 100644 --- a/src/include/souffle/datastructure/RecordTableImpl.h +++ b/src/include/souffle/datastructure/RecordTableImpl.h @@ -344,6 +344,8 @@ class RecordMap { virtual RamDomain pack(const RamDomain* Tuple) = 0; virtual RamDomain pack(const std::initializer_list& List) = 0; virtual const RamDomain* unpack(RamDomain index) const = 0; + virtual void enumerate(const std::function& Callback) const = 0; }; /** @brief Bidirectional mappping between records and record references, for any record arity. */ @@ -388,6 +390,16 @@ class GenericRecordMap : public RecordMap, const RamDomain* unpack(RamDomain Index) const override { return fetch(Index).data(); } + + void enumerate(const std::function& Callback) const override { + const auto End = end(); + for (auto It = begin(); It != End; ++It) { + RamDomain key = It->second; + const std::vector& tuple = It->first; + Callback(tuple.data(), Arity, key); + } + } }; /** @brief Bidirectional mappping between records and record references, specialized for a record arity. */ @@ -437,6 +449,16 @@ class SpecializedRecordMap const RamDomain* unpack(RamDomain Index) const override { return Base::fetch(Index).data(); } + + void enumerate(const std::function& Callback) const override { + const auto End = Base::end(); + for (auto It = Base::begin(); It != End; ++It) { + RamDomain key = It->second; + const auto& tuple = It->first; + Callback(tuple.data(), Arity, key); + } + } }; /** Record map specialized for arity 0 */ @@ -479,6 +501,9 @@ class SpecializedRecordMap<0> : public RecordMap { assert(Index == EmptyRecordIndex); return EmptyRecordData; } + + void enumerate(const std::function&) const override {} }; /** A concurrent Record Table with some specialized record maps. */ @@ -552,6 +577,17 @@ class SpecializedRecordTable : public RecordTable { return lookupMap(Arity).unpack(Ref); } + void enumerate(const std::function& Callback) const override { + auto Guard = Lanes.guard(); + for (std::size_t Arity = 0; Arity < Maps.size(); ++Arity) { + const RecordMap* Map = Maps.at(Arity); + if (Map != nullptr) { + Map->enumerate(Callback); + } + } + } + private: /** @brief lookup RecordMap for a given arity; the map for that arity must exist. */ RecordMap& lookupMap(const std::size_t Arity) const { diff --git a/src/interpreter/Engine.cpp b/src/interpreter/Engine.cpp index dd6dd7ecb60..41683d32853 100644 --- a/src/interpreter/Engine.cpp +++ b/src/interpreter/Engine.cpp @@ -482,6 +482,8 @@ void Engine::executeMain() { visit(program, [&](const ram::Query&) { ++ruleCount; }); ProfileEventSingleton::instance().makeConfigRecord("ruleCount", std::to_string(ruleCount)); + SignalHandler::instance()->enableProfiling(); + Context ctxt; execute(main.get(), ctxt); ProfileEventSingleton::instance().stopTimer(); @@ -1372,15 +1374,11 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { return execute(shadow.getChild(), ctxt); ESAC(DebugInfo) -#define CLEAR(Structure, Arity, AuxiliaryArity, ...) \ - CASE(Clear, Structure, Arity, AuxiliaryArity) \ - auto& rel = *static_cast(shadow.getRelation()); \ - rel.__purge(); \ - return true; \ - ESAC(Clear) - - FOR_EACH(CLEAR) -#undef CLEAR + CASE(Clear) + auto* rel = shadow.getRelation(); + rel->purge(); + return true; + ESAC(Clear) #define ESTIMATEJOINSIZE(Structure, Arity, AuxiliaryArity, ...) \ CASE(EstimateJoinSize, Structure, Arity, AuxiliaryArity) \ diff --git a/src/interpreter/Generator.cpp b/src/interpreter/Generator.cpp index 3de7aeaf825..07e134a6833 100644 --- a/src/interpreter/Generator.cpp +++ b/src/interpreter/Generator.cpp @@ -562,8 +562,7 @@ NodePtr NodeGenerator::visit_(type_identity, const ram::DebugInf NodePtr NodeGenerator::visit_(type_identity, const ram::Clear& clear) { std::size_t relId = encodeRelation(clear.getRelation()); auto rel = getRelationHandle(relId); - NodeType type = constructNodeType(global, "Clear", lookup(clear.getRelation())); - return mk(type, &clear, rel); + return mk(I_Clear, &clear, rel); } NodePtr NodeGenerator::visit_( diff --git a/src/interpreter/Index.h b/src/interpreter/Index.h index b2a35fc42a3..734a9e4c673 100644 --- a/src/interpreter/Index.h +++ b/src/interpreter/Index.h @@ -312,6 +312,10 @@ class Index { void clear() { data.clear(); } + + void printStats(std::ostream& o) const { + data.printStats(o); + } }; /** @@ -449,6 +453,8 @@ class Index<0, 0, Structure> { void clear() { data = false; } + + void printStats(std::ostream&) const {} }; /** diff --git a/src/interpreter/Node.h b/src/interpreter/Node.h index 1e07aa7eed4..61503440fff 100644 --- a/src/interpreter/Node.h +++ b/src/interpreter/Node.h @@ -106,7 +106,7 @@ struct RelationWrapper; Forward(LogRelationTimer)\ Forward(LogTimer)\ Forward(DebugInfo)\ - FOR_EACH(Expand, Clear)\ + Forward(Clear)\ FOR_EACH(Expand, EstimateJoinSize)\ Forward(LogSize)\ Forward(IO)\ diff --git a/src/interpreter/Relation.h b/src/interpreter/Relation.h index 57b764cafb3..7c06ea924a0 100644 --- a/src/interpreter/Relation.h +++ b/src/interpreter/Relation.h @@ -125,6 +125,8 @@ struct RelationWrapper { return auxiliaryArity; } + virtual void printStats(std::ostream& o) const = 0; + // -- Defines methods and interfaces for Interpreter execution. -- public: using IndexViewPtr = Own; @@ -393,6 +395,13 @@ class Relation : public RelationWrapper { return indexes.at(idx).get(); } + void printStats(std::ostream& o) const override { + for (std::size_t i = 0; i < indexes.size(); ++i) { + o << "Index " << i << ":\n"; + indexes[i]->printStats(o); + } + } + protected: // a map of managed indexes VecOwn indexes; diff --git a/src/parser/parser.yy b/src/parser/parser.yy index b78981babeb..b52ed1e82f8 100644 --- a/src/parser/parser.yy +++ b/src/parser/parser.yy @@ -804,9 +804,8 @@ fact : annotations atom DOT { @$ = @$.from(@2); - auto atom = $atom; - atom->setAnnotations($annotations); - $$ = mk(std::move(atom), VecOwn {}, nullptr, @$); + $$ = mk($atom, VecOwn {}, nullptr, @$); + $$->setAnnotations($annotations); } ; diff --git a/src/ram/UserDefinedOperator.h b/src/ram/UserDefinedOperator.h index be6d57fe5dc..66a82f2b233 100644 --- a/src/ram/UserDefinedOperator.h +++ b/src/ram/UserDefinedOperator.h @@ -83,11 +83,7 @@ class UserDefinedOperator : public AbstractOperator { protected: void print(std::ostream& os) const override { - os << "@" << name << "_" << argsTypes; - os << "_" << returnType; - if (stateful) { - os << "_stateful"; - } + os << "@" << name; os << "(" << join(arguments, ",", [](std::ostream& out, const Own& arg) { out << *arg; }) << ")"; } diff --git a/src/tests/graph_utils_test.cpp b/src/tests/graph_utils_test.cpp index b3da73dfee3..64863f59b86 100644 --- a/src/tests/graph_utils_test.cpp +++ b/src/tests/graph_utils_test.cpp @@ -17,6 +17,7 @@ #include "tests/test.h" #include "GraphUtils.h" +#include "souffle/datastructure/Graph.h" #include "souffle/utility/StringUtil.h" #include #include diff --git a/src/tests/record_table_test.cpp b/src/tests/record_table_test.cpp index 79f35c4cd64..76e0ad53435 100644 --- a/src/tests/record_table_test.cpp +++ b/src/tests/record_table_test.cpp @@ -70,6 +70,27 @@ TEST(Pack, InitListHelper) { EXPECT_EQ(3, ptr[2]); } +TEST(Enumerate, Empty) { + SpecializedRecordTable<2> recordTable; + + std::size_t count = 0; + recordTable.enumerate([&](const RamDomain*, std::size_t, RamDomain) { count += 1; }); + EXPECT_EQ(0, count); +} + +TEST(Enumerate, Three) { + SpecializedRecordTable<3> recordTable; + RamDomain ref = pack(recordTable, {1, 2, 3}); + + recordTable.enumerate([&](const RamDomain* t, std::size_t arity, RamDomain idx) { + EXPECT_EQ(3, arity); + EXPECT_EQ(ref, idx); + EXPECT_EQ(1, t[0]); + EXPECT_EQ(2, t[1]); + EXPECT_EQ(3, t[2]); + }); +} + // Generate random tuples // pack them all // unpack and test for equality