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

Add interface for defining external statistics. #23

Merged
merged 7 commits into from
May 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
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 CHANGES
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
clasp 3.3.4:
* fixed: Atoms of incremental programs not always marked as frozen.
* added internal interface for user-defined statistics

clasp 3.3.3: Sunday, 5th November 2017
* fixed: possible race condition in Windows alarm handling (libpotassco)
Expand Down
15 changes: 14 additions & 1 deletion clasp/clasp_facade.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,21 @@ class ClaspFacade : public ModelHandler {
* or the problem is unconditionally unsat.
*/
bool read();
//@}

typedef void(*StatsCallback)(Potassco::AbstractStatistics*, void*);
typedef Potassco::Span<std::pair<StatsCallback, void*> > StatsCallbacks;

//! Adds a callback for defining external (i.e. user-defined) statistics.
/*!
* \param cb Callback method to be called once before and after each solve step.
* \param data Additional data passed back on each call to cb.
*/
void addStatisticsCallback(StatsCallback cb, void* data);

//! Gets all registered callbacks for defining external statistics.
StatsCallbacks getStatisticsCallbacks() const;

//@}

/*!
* \name Solve functions
Expand Down
5 changes: 5 additions & 0 deletions clasp/cli/clasp_output.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,17 @@ class JsonOutput : public Output, private StatsVisitor {
virtual void visitLogicProgramStats(const Asp::LpStats& stats);
virtual void visitProblemStats(const ProblemStats& stats);
virtual void visitSolverStats(const SolverStats& stats);
virtual void visitExternalStats(const StatisticObject& stats);
virtual UPtr doPrint(const OutPair& out, UPtr data);
void printChildren(const StatisticObject& s);
enum ObjType { type_object, type_array };
void pushObject(const char* k = 0, ObjType t = type_object);
char popObject();
void printKeyValue(const char* k, const char* v) ;
void printKeyValue(const char* k, uint64 v);
void printKeyValue(const char* k, uint32 v);
void printKeyValue(const char* k, double d);
void printKeyValue(const char* k, const StatisticObject& o);
void printString(const char* s, const char* sep);
void printKey(const char* k);
void printModel(const OutputTable& out, const Model& m, PrintLevel x);
Expand Down Expand Up @@ -225,6 +228,7 @@ class TextOutput : public Output, private StatsVisitor {
virtual void visitLogicProgramStats(const Asp::LpStats& stats);
virtual void visitProblemStats(const ProblemStats& stats);
virtual void visitSolverStats(const SolverStats& stats);
virtual void visitExternalStats(const StatisticObject& stats);

virtual UPtr doPrint(const OutPair& out, UPtr data);
const char* fieldSeparator() const;
Expand All @@ -239,6 +243,7 @@ class TextOutput : public Output, private StatsVisitor {
void printSolveProgress(const Event& ev);
void printValues(const OutputTable& out, const Model& m);
void printMeta(const OutputTable& out, const Model& m);
void printChildren(const StatisticObject& s, unsigned level);
private:
struct SolveProgress {
int lines;
Expand Down
31 changes: 22 additions & 9 deletions clasp/statistics.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class StatisticObject {
* The following expression shall be valid:
* obj->size(): shall return the size of the array.
* obj->at(i): shall return the StatisticObject under the given key i >= 0.
* If k is invalid, shall either throw an exception or return an empty object.
* If i is invalid, shall either throw an exception or return an empty object.
*/
template <class T>
static StatisticObject array(const T* obj) {
Expand Down Expand Up @@ -123,6 +123,8 @@ class StatisticObject {
}
std::size_t hash() const;
uint64 toRep() const;
const void* self() const;
std::size_t typeId()const;
static StatisticObject fromRep(uint64);
private:
struct I {
Expand All @@ -146,8 +148,8 @@ class StatisticObject {
const char* (*key)(ObjPtr, uint32);
};
static uint32 registerType(const I* vtab) {
types_.push_back(vtab);
return static_cast<uint32>(types_.size() - 1);
types_s.push_back(vtab);
return static_cast<uint32>(types_s.size() - 1);
}
template <class T, double(*f)(const T*)>
static uint32 registerValue();
Expand All @@ -158,9 +160,9 @@ class StatisticObject {
StatisticObject(const void* obj, uint32 type);

typedef PodVector<const I*>::type RegVec;
const void* self() const;
const I* tid() const;
static RegVec types_;
static I empty_s;
static RegVec types_s;
uint64 handle_;
};

Expand Down Expand Up @@ -206,6 +208,7 @@ class StatsMap {
// Own interface
const StatisticObject* find(const char* k) const;
bool add(const char* k, const StatisticObject&);
void push(const char* k, const StatisticObject&);
StatisticObject toStats() const { return StatisticObject::map(this); }
private:
typedef PodVector<std::pair<const char*, StatisticObject> >::type MapType;
Expand Down Expand Up @@ -241,35 +244,44 @@ class StatsVec : private PodVector<T*>::type {
bool own_;
};

//! A class for traversing and querying statistics.
//! A class for traversing, querying, and adding statistics.
/*!
* \ingroup clingo
*/
class ClaspStatistics : public Potassco::AbstractStatistics {
public:
typedef Potassco::Statistics_t Type;
ClaspStatistics();
ClaspStatistics(StatisticObject root);
~ClaspStatistics();

StatsMap* makeRoot();

// Base interface
virtual Key_t root() const;
virtual Type type(Key_t key) const;
virtual size_t size(Key_t key) const;
virtual bool writable(Key_t key) const;
virtual Key_t at(Key_t arrK, size_t index) const;
virtual Key_t push(Key_t arr, Type type);
virtual const char* key(Key_t mapK, size_t i) const;
virtual Key_t get(Key_t mapK, const char* key) const;
virtual bool find(Key_t mapK, const char* element, Key_t* outKey) const;
virtual Key_t add(Key_t mapK, const char* name, Type type);
virtual double value(Key_t key) const;
virtual void set(Key_t key, double value);

// Register interface
Key_t setRoot(const StatisticObject&);
Key_t changeRoot(Key_t newRoot);
bool removeStat(const StatisticObject&, bool recurse);
bool removeStat(Key_t k, bool recurse);

// Remove unreachable stats
void update();
StatisticObject findObject(Key_t root, const char* path, Key_t* track = 0) const;
StatisticObject getObject(Key_t k) const;
private:
ClaspStatistics(const ClaspStatistics&);
ClaspStatistics& operator=(const ClaspStatistics&);
Key_t root_;
struct Impl;
Impl* impl_;
};
Expand Down Expand Up @@ -299,6 +311,7 @@ class StatsVisitor {
virtual void visitLogicProgramStats(const Asp::LpStats& stats) = 0;
virtual void visitProblemStats(const ProblemStats& stats) = 0;
virtual void visitSolverStats(const SolverStats& stats) = 0;
virtual void visitExternalStats(const StatisticObject& stats) = 0;
};

}
Expand Down
2 changes: 1 addition & 1 deletion libpotassco
Submodule libpotassco updated 1 files
+47 −2 potassco/clingo.h
75 changes: 57 additions & 18 deletions src/clasp_facade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -555,31 +555,37 @@ double _getResult(const SolveResult* r) { return static_cast<double>(r->operator
double _getSignal(const SolveResult* r) { return static_cast<double>(r->signal); }
double _getExhausted(const SolveResult* r) { return static_cast<double>(r->exhausted()); }
}

struct ClaspFacade::Statistics {
typedef std::pair<StatsCallback, void*> UserSource;
typedef PodVector<UserSource>::type CallbackVec;
Statistics(ClaspFacade& f) : self_(&f), tester_(0), level_(0), clingo_(0) {}
~Statistics() { delete clingo_; delete solvers_.multi; }
void start(uint32 level);
void initLevel(uint32 level);
void end();
void addTo(StatsMap& solving, StatsMap* accu) const;
void accept(StatsVisitor& out, bool final) const;
void addExternal(StatsCallback cb, void* data);
bool incremental() const { return self_->incremental(); }
Potassco::AbstractStatistics* getClingo();
Potassco::Span<UserSource> external() const { return Potassco::toSpan(sources_); }
typedef StatsVec<SolverStats> SolverVec;
typedef SingleOwnerPtr<Asp::LpStats> LpStatsPtr;
typedef PrgDepGraph::NonHcfStats TesterStats;
ClaspFacade* self_;
LpStatsPtr lp_; // level 0 and asp
SolverStats solvers_; // level 0
SolverVec solver_; // level > 1
SolverVec accu_; // level > 1 and incremental
TesterStats* tester_; // level > 0 and nonhcfs
uint32 level_; // active stats level
ClaspFacade* self_;
LpStatsPtr lp_; // level 0 and asp
SolverStats solvers_; // level 0
SolverVec solver_; // level > 1
SolverVec accu_; // level > 1 and incremental
CallbackVec sources_; // callbacks for user-defined stats
TesterStats* tester_; // level > 0 and nonhcfs
uint32 level_; // active stats level
// For clingo stats interface
class ClingoView : public ClaspStatistics {
public:
explicit ClingoView(const ClaspFacade& f);
void update(const Statistics& s);
Key_t user() const;
private:
struct StepStats {
SummaryStats times;
Expand All @@ -593,14 +599,16 @@ struct ClaspFacade::Statistics {
summary.add("models", models.toStats());
}
};
StatsMap keys_;
StatsMap problem_;
StatsMap solving_;
StatsMap* keys_;
StatsMap problem_;
StatsMap solving_;
struct Summary : StatsMap { StepStats step; } summary_;
struct Accu : StatsMap { StepStats step; StatsMap solving_; };
typedef SingleOwnerPtr<Accu> AccuPtr;
AccuPtr accu_;
}* clingo_; // new clingo stats interface;
Key_t user_;
}* clingo_; // new clingo stats interface
ClingoView* getClingo();
};
void ClaspFacade::Statistics::initLevel(uint32 level) {
if (level_ < level) {
Expand All @@ -614,6 +622,10 @@ void ClaspFacade::Statistics::initLevel(uint32 level) {
tester_ = self_->ctx.sccGraph->nonHcfStats();
}
}
void ClaspFacade::Statistics::addExternal(StatsCallback cb, void* data) {
sources_.push_back(UserSource(cb, data));
}

void ClaspFacade::Statistics::start(uint32 level) {
// cleanup previous state
solvers_.reset();
Expand Down Expand Up @@ -658,6 +670,9 @@ void ClaspFacade::Statistics::accept(StatsVisitor& out, bool final) const {
const SolverVec& solver = final ? accu_ : solver_;
const uint32 nThreads = final ? (uint32)accu_.size() : self_->ctx.concurrency();
const uint32 nSolver = (uint32)solver.size();
if (clingo_ && clingo_->user()) {
out.visitExternalStats(clingo_->getObject(clingo_->user()));
}
if (nThreads > 1 && nSolver > 1 && out.visitThreads(StatsVisitor::Enter)) {
for (uint32 i = 0, end = std::min(nSolver, nThreads); i != end; ++i) {
out.visitThread(i, *solver[i]);
Expand All @@ -671,14 +686,16 @@ void ClaspFacade::Statistics::accept(StatsVisitor& out, bool final) const {
out.visitTester(StatsVisitor::Leave);
}
}
Potassco::AbstractStatistics* ClaspFacade::Statistics::getClingo() {
ClaspFacade::Statistics::ClingoView* ClaspFacade::Statistics::getClingo() {
if (!clingo_) {
clingo_ = new ClingoView(*this->self_);
clingo_->update(*this);
}
return clingo_;
}
ClaspFacade::Statistics::ClingoView::ClingoView(const ClaspFacade& f) {
keys_ = makeRoot();
user_ = 0;
summary_.add("call" , StatisticObject::value(&f.step_.step));
summary_.add("result" , StatisticObject::value<SolveResult, _getResult>(&f.step_.result));
summary_.add("signal" , StatisticObject::value<SolveResult, _getSignal>(&f.step_.result));
Expand All @@ -693,17 +710,29 @@ ClaspFacade::Statistics::ClingoView::ClingoView(const ClaspFacade& f) {
if (f.incremental()) { problem_.add("lpStep", StatisticObject::map(f.step_.lpStep())); }
}
problem_.add("generator", StatisticObject::map(&f.ctx.stats()));
keys_.add("problem", problem_.toStats());
keys_.add("solving", solving_.toStats());
keys_.add("summary", summary_.toStats());
keys_->add("problem", problem_.toStats());
keys_->add("solving", solving_.toStats());
keys_->add("summary", summary_.toStats());

if (f.incremental()) {
accu_ = new Accu();
accu_->step.bind(*f.accu_.get());
}
setRoot(keys_.toStats());
}
Potassco::AbstractStatistics::Key_t ClaspFacade::Statistics::ClingoView::user() const {
return user_;
}
void ClaspFacade::Statistics::ClingoView::update(const ClaspFacade::Statistics& stats) {
if (stats.level_ > 0 && accu_.get() && keys_.add("accu", accu_->toStats())) {
StatsCallbacks sources = stats.external();
if (!Potassco::empty(sources)) {
user_ = add(root(), "user_defined", Potassco::Statistics_t::Map);
Key_t oldRoot = changeRoot(user_);
for (StatsCallbacks::iterator it = Potassco::begin(sources), end = Potassco::end(sources); it != end; ++it) {
it->first(this, it->second);
}
changeRoot(oldRoot);
}
if (stats.level_ > 0 && accu_.get() && keys_->add("accu", accu_->toStats())) {
accu_->step.addTo(*accu_);
accu_->add("solving", accu_->solving_.toStats());
}
Expand Down Expand Up @@ -914,6 +943,16 @@ bool ClaspFacade::read() {
if (!p.more()) { p.reset(); }
return true;
}

void ClaspFacade::addStatisticsCallback(StatsCallback cb, void* data) {
POTASSCO_REQUIRE(stats_.get(), "Statistics not yet available");
stats_->addExternal(cb, data);
}

ClaspFacade::StatsCallbacks ClaspFacade::getStatisticsCallbacks() const {
return stats_.get() ? stats_->external() : Potassco::toSpan<std::pair<StatsCallback, void*> >();
}

void ClaspFacade::prepare(EnumMode enumMode) {
POTASSCO_REQUIRE(solve_.get() && !solving());
EnumOptions& en = config_->solve;
Expand Down
Loading