Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide way to debug delta relations and expose iteration counter #2414

Merged
merged 10 commits into from
Jun 5, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ set(SOUFFLE_SOURCES
ast/transform/ComponentChecker.cpp
ast/transform/ComponentInstantiation.cpp
ast/transform/DebugReporter.cpp
ast/transform/DebugDeltaRelation.cpp
ast/transform/ExecutionPlanChecker.cpp
ast/transform/ExpandEqrels.cpp
ast/transform/FoldAnonymousRecords.cpp
Expand Down
2 changes: 2 additions & 0 deletions src/MainDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "ast/transform/ComponentChecker.h"
#include "ast/transform/ComponentInstantiation.h"
#include "ast/transform/Conditional.h"
#include "ast/transform/DebugDeltaRelation.h"
#include "ast/transform/ExecutionPlanChecker.h"
#include "ast/transform/ExpandEqrels.h"
#include "ast/transform/Fixpoint.h"
Expand Down Expand Up @@ -478,6 +479,7 @@ Own<ast::transform::PipelineTransformer> astTransformationPipeline(Global& glb)
// Main pipeline
auto pipeline = mk<ast::transform::PipelineTransformer>(mk<ast::transform::ComponentChecker>(),
mk<ast::transform::ComponentInstantiationTransformer>(),
mk<ast::transform::DebugDeltaRelationTransformer>(),
mk<ast::transform::IODefaultsTransformer>(),
mk<ast::transform::SimplifyAggregateTargetExpressionTransformer>(),
mk<ast::transform::UniqueAggregationVariablesTransformer>(),
Expand Down
1 change: 0 additions & 1 deletion src/ast/Directive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ std::ostream& operator<<(std::ostream& os, DirectiveType e) {
case DirectiveType::output: return os << "output";
case DirectiveType::printsize: return os << "printsize";
case DirectiveType::limitsize: return os << "limitsize";
case DirectiveType::debug_delta: return os << "debug_delta";
}

UNREACHABLE_BAD_CASE_ANALYSIS
Expand Down
2 changes: 1 addition & 1 deletion src/ast/Directive.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

namespace souffle::ast {

enum class DirectiveType { input, output, printsize, limitsize, debug_delta };
enum class DirectiveType { input, output, printsize, limitsize };

// FIXME: I'm going crazy defining these. There has to be a library that does this boilerplate for us.
std::ostream& operator<<(std::ostream& os, DirectiveType e);
Expand Down
7 changes: 6 additions & 1 deletion src/ast/Relation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,18 @@ void Relation::print(std::ostream& os) const {
if (!functionalDependencies.empty()) {
os << " choice-domain " << join(functionalDependencies, ", ");
}
if (isDeltaDebug) {
os << " delta_debug(" << isDeltaDebug.value() << ")";
}
}

bool Relation::equal(const Node& node) const {
const auto& other = asAssert<Relation>(node);
return name == other.name && equal_targets(attributes, other.attributes) &&
qualifiers == other.qualifiers &&
equal_targets(functionalDependencies, other.functionalDependencies) &&
representation == other.representation;
representation == other.representation &&
isDeltaDebug == other.isDeltaDebug;
}

Relation* Relation::cloning() const {
Expand All @@ -77,6 +81,7 @@ Relation* Relation::cloning() const {
res->qualifiers = qualifiers;
res->functionalDependencies = clone(functionalDependencies);
res->representation = representation;
res->isDeltaDebug = isDeltaDebug;
return res;
}

Expand Down
10 changes: 10 additions & 0 deletions src/ast/Relation.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@ class Relation : public Node {

void apply(const NodeMapper& map) override;

void setIsDeltaDebug(QualifiedName rel) {
isDeltaDebug = rel;
}

std::optional<QualifiedName> getIsDeltaDebug() const {
return isDeltaDebug;
}

protected:
void print(std::ostream& os) const override;

Expand All @@ -122,6 +130,8 @@ class Relation : public Node {

/** Datastructure to use for this relation */
RelationRepresentation representation{RelationRepresentation::DEFAULT};

std::optional<QualifiedName> isDeltaDebug;
};

/**
Expand Down
7 changes: 7 additions & 0 deletions src/ast/analysis/PrecedenceGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ void PrecedenceGraphAnalysis::run(const TranslationUnit& translationUnit) {
souffle::visit(literals[i], addEdgeToR);
}
}

// delta_debug relation are computed from the original relation
if (const auto deltaDebug = r->getIsDeltaDebug()) {
const auto* dbg = program.getRelation(deltaDebug.value());
backingGraph.insert(r, dbg);
backingGraph.insert(dbg, r);
}
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/ast/transform/ComponentInstantiation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,15 @@ ComponentContent getInstantiatedContent(Program& program, const ComponentInit& c
}
});

visit(node, [&](Relation& rel) {
if (rel.getIsDeltaDebug()) {
auto pos = relationNameMapping.find(rel.getIsDeltaDebug().value());
if (pos != relationNameMapping.end()) {
rel.setIsDeltaDebug(pos->second);
}
}
});

// rename directives
visit(node, [&](Directive& directive) {
auto pos = relationNameMapping.find(directive.getQualifiedName());
Expand Down
58 changes: 58 additions & 0 deletions src/ast/transform/DebugDeltaRelation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Souffle - A Datalog Compiler
* Copyright (c) 2023, The Souffle Developers. All rights reserved
* Licensed under the Universal Permissive License v 1.0 as shown at:
* - https://opensource.org/licenses/UPL
* - <souffle root>/licenses/SOUFFLE-UPL.txt
*/

/************************************************************************
*
* @file DebugDeltaRelation.cpp
*
***********************************************************************/

#include "ast/transform/DebugDeltaRelation.h"
#include "ast/Argument.h"
#include "ast/Atom.h"
#include "ast/Clause.h"
#include "ast/Program.h"
#include "ast/QualifiedName.h"
#include "ast/RecordInit.h"
#include "ast/Relation.h"
#include "ast/TranslationUnit.h"
#include "ast/Variable.h"
#include "ast/analysis/IOType.h"
#include "ast/utility/Utils.h"
#include "ast/utility/Visitor.h"
#include "souffle/utility/ContainerUtil.h"
#include <algorithm>
#include <cassert>
#include <map>
#include <set>
#include <utility>
#include <vector>

namespace souffle::ast::transform {

bool DebugDeltaRelationTransformer::updateSignature(TranslationUnit& translationUnit) {
bool changed = false;
Program& program = translationUnit.getProgram();

for (Relation* rel : program.getRelations()) {
if (!rel->getIsDeltaDebug().has_value()) {
continue;
}
const QualifiedName originalRelName = rel->getIsDeltaDebug().value();
Relation* orig = program.getRelation(originalRelName);
assert(orig != nullptr);


rel->setAttributes(clone(orig->getAttributes()));
changed = true;
rel->addAttribute(mk<Attribute>("<iteration>", "unsigned"));
}
return changed;
}

} // namespace souffle::ast::transform
44 changes: 44 additions & 0 deletions src/ast/transform/DebugDeltaRelation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Souffle - A Datalog Compiler
* Copyright (c) 2023, The Souffle Developers. All rights reserved
* Licensed under the Universal Permissive License v 1.0 as shown at:
* - https://opensource.org/licenses/UPL
* - <souffle root>/licenses/SOUFFLE-UPL.txt
*/

/************************************************************************
*
* @file DebugDeltaRelation.h
*
***********************************************************************/

#pragma once

#include "ast/TranslationUnit.h"
#include "ast/transform/Transformer.h"
#include <string>

namespace souffle::ast::transform {

/**
* Pass that assign the correct signature to relations declared as delta_debug
*/
class DebugDeltaRelationTransformer : public Transformer {
public:
std::string getName() const override {
return "DebugDeltaRelationTransformer";
}

private:
DebugDeltaRelationTransformer* cloning() const override {
return new DebugDeltaRelationTransformer();
}

bool updateSignature(TranslationUnit& translationUnit);

bool transform(TranslationUnit& translationUnit) override {
return updateSignature(translationUnit);
}
};

} // namespace souffle::ast::transform
12 changes: 0 additions & 12 deletions src/ast/transform/IOAttributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,6 @@ class IOAttributesTransformer : public Transformer {
// Casting due to json11.h type requirements.
long long arity{static_cast<long long>(rel->getArity())};

if (io->getType() == ast::DirectiveType::debug_delta) {
attributesParams.push_back("iteration");
arity++;
}

json11::Json relJson = json11::Json::object{{"arity", arity},
{"params", json11::Json::array(attributesParams.begin(), attributesParams.end())}};

Expand Down Expand Up @@ -125,9 +120,6 @@ class IOAttributesTransformer : public Transformer {
for (const auto* attribute : rel->getAttributes()) {
attributeNames.push_back(attribute->getName());
}
if (io->getType() == ast::DirectiveType::debug_delta) {
attributeNames.push_back("iteration");
}
io->addParameter("attributeNames", toString(join(attributeNames, delimiter)));
changed = true;
}
Expand All @@ -153,10 +145,6 @@ class IOAttributesTransformer : public Transformer {
// Casting due to json11.h type requirements.
long long arity{static_cast<long long>(rel->getArity())};

if (io->getType() == ast::DirectiveType::debug_delta) {
attributesTypes.push_back("u:unsigned");
arity++;
}
json11::Json relJson = json11::Json::object{{"arity", arity},
{"types", json11::Json::array(attributesTypes.begin(), attributesTypes.end())}};

Expand Down
9 changes: 2 additions & 7 deletions src/ast/transform/IODefaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,7 @@ class IODefaultsTransformer : public Transformer {

// Set the relation name
if (!io->hasParameter("name")) {
if (io->getType() == ast::DirectiveType::debug_delta) {
io->addParameter("name", "@delta_" + getRelationName(io));
} else {
io->addParameter("name", getRelationName(io));
}
io->addParameter("name", getRelationName(io));
changed = true;
}

Expand All @@ -99,8 +95,7 @@ class IODefaultsTransformer : public Transformer {
if (glb.config().has("fact-dir")) {
io->addParameter("fact-dir", glb.config().get("fact-dir"));
}
} else if (io->getType() == ast::DirectiveType::output ||
io->getType() == ast::DirectiveType::debug_delta) {
} else if (io->getType() == ast::DirectiveType::output) {
io->addParameter("operation", "output");
changed = true;
// Configure output directory
Expand Down
10 changes: 9 additions & 1 deletion src/ast/transform/SemanticChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -670,12 +670,20 @@ void SemanticCheckerImpl::checkRelation(const Relation& relation) {
checkRelationFunctionalDependencies(relation);

// check whether this relation is empty
if (program.getClauses(relation).empty() && !ioTypes.isInput(&relation) &&
if (program.getClauses(relation).empty() && !ioTypes.isInput(&relation) && !relation.getIsDeltaDebug().has_value() &&
!relation.hasQualifier(RelationQualifier::SUPPRESSED)) {
report.addWarning(WarnType::NoRulesNorFacts,
"No rules/facts defined for relation " + toString(relation.getQualifiedName()),
relation.getSrcLoc());
}

// if the relation is a delta_debug, make sure if has no clause
if (relation.getIsDeltaDebug().has_value()) {
if (!program.getClauses(relation).empty() || ioTypes.isInput(&relation)) {
report.addError("Unexpected rules/facts for delta_debug relation " + toString(relation.getQualifiedName()), relation.getSrcLoc());
}
}

}

void SemanticCheckerImpl::checkIO() {
Expand Down
35 changes: 2 additions & 33 deletions src/ast2ram/seminaive/UnitTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -482,15 +482,6 @@ Own<ram::Statement> UnitTranslator::generateStratumPostamble(const ast::Relation
return mk<ram::Sequence>(std::move(postamble));
}

bool UnitTranslator::requiresDebugRelation(const ast::Relation* relation) const {
for (const auto* store : context->getStoreDirectives(relation->getQualifiedName())) {
if (store->getType() == ast::DirectiveType::debug_delta) {
return true;
}
}
return false;
}

Own<ram::Statement> UnitTranslator::generateStratumTableUpdates(const ast::RelationSet& scc) const {
VecOwn<ram::Statement> updateTable;

Expand All @@ -499,7 +490,6 @@ Own<ram::Statement> UnitTranslator::generateStratumTableUpdates(const ast::Relat
std::string mainRelation = getConcreteRelationName(rel->getQualifiedName());
std::string newRelation = getNewRelationName(rel->getQualifiedName());
std::string deltaRelation = getDeltaRelationName(rel->getQualifiedName());
std::string debugRelation = getDeltaDebugRelationName(rel->getQualifiedName());

// swap new and and delta relation and clear new relation afterwards (if not a subsumptive relation)
Own<ram::Statement> updateRelTable;
Expand All @@ -518,7 +508,8 @@ Own<ram::Statement> UnitTranslator::generateStratumTableUpdates(const ast::Relat
}

appendStmt(updateTable, std::move(updateRelTable));
if (requiresDebugRelation(rel)) {
if (const auto* debugRel = context->getDeltaDebugRelation(rel)) {
const std::string debugRelation = getConcreteRelationName(debugRel->getQualifiedName());
appendStmt(updateTable, generateDebugRelation(rel, debugRelation, deltaRelation));
}
}
Expand Down Expand Up @@ -670,13 +661,6 @@ Own<ram::Statement> UnitTranslator::generateStoreRelation(const ast::Relation* r
}
addAuxiliaryArity(relation, directives);

if (store->getType() == ast::DirectiveType::debug_delta) {
std::string ramRelationName = getDeltaDebugRelationName(relation->getQualifiedName());
Own<ram::Statement> storeStmt = mk<ram::IO>(ramRelationName, directives);
appendStmt(storeStmts, std::move(storeStmt));
continue;
}

// Create the resultant store statement, with profile information
std::string ramRelationName = getConcreteRelationName(relation->getQualifiedName());
Own<ram::Statement> storeStmt = mk<ram::IO>(ramRelationName, directives);
Expand Down Expand Up @@ -724,21 +708,6 @@ VecOwn<ram::Relation> UnitTranslator::createRamRelations(const std::vector<std::
std::string deltaName = getDeltaRelationName(rel->getQualifiedName());
ramRelations.push_back(createRamRelation(rel, deltaName));

if (requiresDebugRelation(rel)) {
std::string debugName = getDeltaDebugRelationName(rel->getQualifiedName());
std::size_t arity = rel->getArity();
auto attributeNames = ramRelations.back()->getAttributeNames();
auto attributeTypeQualifiers = ramRelations.back()->getAttributeTypes();
auto representation = ramRelations.back()->getRepresentation();

arity++;
attributeNames.push_back("iteration");
attributeTypeQualifiers.push_back("u:unsigned");

ramRelations.push_back(mk<ram::Relation>(
debugName, arity, 0, attributeNames, attributeTypeQualifiers, representation));
}

// Add new relation
std::string newName = getNewRelationName(rel->getQualifiedName());
ramRelations.push_back(createRamRelation(rel, newName));
Expand Down
2 changes: 0 additions & 2 deletions src/ast2ram/seminaive/UnitTranslator.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ class UnitTranslator : public ast2ram::UnitTranslator {
const ast::Clause* clause, const ast::RelationSet& scc) const;
std::vector<ast::Atom*> getSccAtoms(const ast::Clause* clause, const ast::RelationSet& scc) const;

bool requiresDebugRelation(const ast::Relation* relation) const;

virtual void addAuxiliaryArity(
const ast::Relation* relation, std::map<std::string, std::string>& directives) const;

Expand Down
Loading