mirror of
https://github.com/Z3Prover/z3
synced 2025-04-15 13:28:47 +00:00
dont run atexit handlers as its not safe to do so with multiple threads code might be inside malloc, for example, and glibc tries to cleanup its heap state with an atexit handler
263 lines
7.3 KiB
C++
263 lines
7.3 KiB
C++
/*++
|
|
Copyright (c) 2006 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
datalog_frontend.cpp
|
|
|
|
Abstract:
|
|
|
|
<abstract>
|
|
|
|
Author:
|
|
|
|
Leonardo de Moura (leonardo) 2010-05-18.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include<iostream>
|
|
#include<time.h>
|
|
#include<signal.h>
|
|
#include "util/stopwatch.h"
|
|
#include "smt/params/smt_params.h"
|
|
#include "ast/arith_decl_plugin.h"
|
|
#include "ast/reg_decl_plugins.h"
|
|
#include "muz/rel/dl_compiler.h"
|
|
#include "muz/transforms/dl_mk_filter_rules.h"
|
|
#include "muz/rel/dl_finite_product_relation.h"
|
|
#include "muz/base/dl_context.h"
|
|
#include "muz/rel/rel_context.h"
|
|
#include "muz/fp/dl_register_engine.h"
|
|
#include "muz/fp/datalog_parser.h"
|
|
#include "shell/datalog_frontend.h"
|
|
#include "util/timeout.h"
|
|
#include "util/mutex.h"
|
|
|
|
static stopwatch g_overall_time;
|
|
static stopwatch g_piece_timer;
|
|
static unsigned t_parsing = 0;
|
|
|
|
static datalog::context * g_ctx = nullptr;
|
|
static datalog::rule_set * g_orig_rules;
|
|
static datalog::instruction_block * g_code;
|
|
static datalog::execution_context * g_ectx;
|
|
|
|
static mutex *display_stats_mux = new mutex;
|
|
|
|
|
|
static void display_statistics(
|
|
std::ostream& out,
|
|
datalog::context& ctx,
|
|
datalog::rule_set& orig_rules,
|
|
datalog::instruction_block& code,
|
|
datalog::execution_context& ex_ctx,
|
|
bool verbose
|
|
)
|
|
{
|
|
lock_guard lock(*display_stats_mux);
|
|
g_piece_timer.stop();
|
|
unsigned t_other = static_cast<int>(g_piece_timer.get_seconds()*1000);
|
|
g_overall_time.stop();
|
|
|
|
code.process_all_costs();
|
|
{
|
|
params_ref p;
|
|
p.set_bool("output_profile", true);
|
|
p.set_uint("profile_milliseconds_threshold", 100);
|
|
ctx.updt_params(p);
|
|
|
|
IF_VERBOSE(2,
|
|
out << "--------------\n";
|
|
out << "original rules\n";
|
|
orig_rules.display(out);
|
|
|
|
out << "---------------\n";
|
|
out << "generated rules\n";
|
|
ctx.display_rules(out);
|
|
|
|
out << "--------------\n";
|
|
out << "instructions \n";
|
|
code.display(ex_ctx, out);
|
|
|
|
out << "--------------\n";
|
|
out << "big relations \n";
|
|
ex_ctx.report_big_relations(1000, out););
|
|
}
|
|
IF_VERBOSE(2,
|
|
out << "--------------\n";
|
|
out << "relation sizes\n";
|
|
ctx.get_rel_context()->get_rmanager().display_relation_sizes(out););
|
|
|
|
if (verbose) {
|
|
out << "--------------\n";
|
|
out << "rules\n";
|
|
ctx.display_rules(out);
|
|
}
|
|
|
|
out << "Time: " << static_cast<int>(g_overall_time.get_seconds()*1000) << "ms\n";
|
|
out << "Parsing: " << t_parsing << "ms, other: " << t_other << "ms\n";
|
|
}
|
|
|
|
|
|
static void display_statistics() {
|
|
if (g_ctx) {
|
|
display_statistics(std::cout, *g_ctx, *g_orig_rules, *g_code, *g_ectx, true);
|
|
}
|
|
}
|
|
|
|
static void on_timeout() {
|
|
display_statistics();
|
|
_Exit(0);
|
|
}
|
|
|
|
static void STD_CALL on_ctrl_c(int) {
|
|
signal (SIGINT, SIG_DFL);
|
|
display_statistics();
|
|
raise(SIGINT);
|
|
}
|
|
|
|
|
|
unsigned read_datalog(char const * file) {
|
|
IF_VERBOSE(1, verbose_stream() << "Z3 Datalog Engine\n";);
|
|
smt_params s_params;
|
|
ast_manager m;
|
|
reg_decl_plugins(m);
|
|
datalog::register_engine re;
|
|
g_overall_time.start();
|
|
register_on_timeout_proc(on_timeout);
|
|
signal(SIGINT, on_ctrl_c);
|
|
params_ref params;
|
|
params.set_sym("engine", symbol("datalog"));
|
|
|
|
datalog::context ctx(m, re, s_params, params);
|
|
datalog::relation_manager & rmgr = ctx.get_rel_context()->get_rmanager();
|
|
datalog::relation_plugin & inner_plg = *rmgr.get_relation_plugin(symbol("tr_hashtable"));
|
|
rmgr.register_plugin(alloc(datalog::finite_product_relation_plugin, inner_plg, rmgr));
|
|
|
|
g_piece_timer.reset();
|
|
g_piece_timer.start();
|
|
|
|
bool wpa_benchmark = datalog::is_directory(std::string(file));
|
|
if (wpa_benchmark) {
|
|
scoped_ptr<datalog::wpa_parser> parser = datalog::wpa_parser::create(ctx, m);
|
|
if (!parser->parse_directory(file)) {
|
|
std::cerr << "ERROR: failed to parse file\n";
|
|
return 1;
|
|
}
|
|
}
|
|
else {
|
|
scoped_ptr<datalog::parser> parser = datalog::parser::create(ctx, m);
|
|
if (!parser->parse_file(file)) {
|
|
std::cerr << "ERROR: failed to parse file\n";
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
g_piece_timer.stop();
|
|
t_parsing = static_cast<int>(g_piece_timer.get_seconds()*1000);
|
|
IF_VERBOSE(1, verbose_stream() << "parsing finished\n";);
|
|
IF_VERBOSE(1, verbose_stream() << "running saturation...\n";);
|
|
g_piece_timer.reset();
|
|
g_piece_timer.start();
|
|
//all rules were added
|
|
ctx.close();
|
|
|
|
TRACE("dl_compiler", ctx.display(tout););
|
|
|
|
datalog::rule_set original_rules(ctx.get_rules());
|
|
|
|
datalog::instruction_block rules_code;
|
|
datalog::instruction_block termination_code;
|
|
datalog::execution_context ex_ctx(ctx);
|
|
|
|
IF_VERBOSE(10, original_rules.display_deps(verbose_stream()););
|
|
|
|
g_ctx = &ctx;
|
|
g_orig_rules = &original_rules;
|
|
g_code = &rules_code;
|
|
g_ectx = &ex_ctx;
|
|
|
|
try {
|
|
g_piece_timer.reset();
|
|
g_piece_timer.start();
|
|
|
|
bool early_termination;
|
|
unsigned timeout = ctx.initial_restart_timeout();
|
|
if (timeout == 0) {
|
|
timeout = UINT_MAX;
|
|
}
|
|
do {
|
|
ctx.get_rel_context()->transform_rules();
|
|
|
|
datalog::compiler::compile(ctx, ctx.get_rules(), rules_code, termination_code);
|
|
|
|
TRACE("dl_compiler", rules_code.display(ex_ctx, tout););
|
|
|
|
rules_code.make_annotations(ex_ctx);
|
|
|
|
ex_ctx.set_timelimit(timeout);
|
|
|
|
early_termination = !rules_code.perform(ex_ctx);
|
|
if(early_termination) {
|
|
IF_VERBOSE(10, ex_ctx.report_big_relations(1000, verbose_stream()););
|
|
if (memory::above_high_watermark()) {
|
|
throw out_of_memory_error();
|
|
}
|
|
}
|
|
ex_ctx.reset_timelimit();
|
|
TRUSTME( termination_code.perform(ex_ctx) );
|
|
ctx.saturation_was_run();
|
|
|
|
if (early_termination) {
|
|
IF_VERBOSE(1, verbose_stream() << "restarting saturation\n";);
|
|
|
|
uint64_t new_timeout = static_cast<uint64_t>(timeout)*ctx.initial_restart_timeout();
|
|
if(new_timeout>UINT_MAX) {
|
|
timeout=UINT_MAX;
|
|
}
|
|
else {
|
|
timeout=static_cast<unsigned>(new_timeout);
|
|
}
|
|
|
|
rules_code.process_all_costs();
|
|
rules_code.reset();
|
|
termination_code.reset();
|
|
ex_ctx.reset();
|
|
ctx.reopen();
|
|
ctx.replace_rules(original_rules);
|
|
ctx.close();
|
|
}
|
|
} while (early_termination);
|
|
|
|
|
|
TRACE("dl_compiler", ctx.display(tout);
|
|
rules_code.display(ex_ctx, tout););
|
|
|
|
if (ctx.output_tuples()) {
|
|
ctx.get_rel_context()->display_output_facts(ctx.get_rules(), std::cout);
|
|
}
|
|
display_statistics(
|
|
std::cout,
|
|
ctx,
|
|
original_rules,
|
|
rules_code,
|
|
ex_ctx,
|
|
false);
|
|
|
|
}
|
|
catch (const out_of_memory_error &) {
|
|
std::cout << "\n\nOUT OF MEMORY!\n\n";
|
|
display_statistics(
|
|
std::cout,
|
|
ctx,
|
|
original_rules,
|
|
rules_code,
|
|
ex_ctx,
|
|
true);
|
|
return ERR_MEMOUT;
|
|
}
|
|
return 0;
|
|
}
|