/*++ Copyright (c) 2006 Microsoft Corporation Module Name: datalog_frontend.cpp Abstract: Author: Leonardo de Moura (leonardo) 2010-05-18. Revision History: --*/ #include #include #include #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(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(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 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 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(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(timeout)*ctx.initial_restart_timeout(); if(new_timeout>UINT_MAX) { timeout=UINT_MAX; } else { timeout=static_cast(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; }