feat(library/definition_cache): store the hashcode of direct dependencies

Actually we store the has code of their types.
This commit is contained in:
Leonardo de Moura 2014-09-29 17:28:23 -07:00
parent b538b3e0bf
commit 530997638a
3 changed files with 101 additions and 28 deletions

View file

@ -120,12 +120,12 @@ parser::~parser() {
void parser::cache_definition(name const & n, expr const & pre_type, expr const & pre_value,
level_param_names const & ls, expr const & type, expr const & value) {
if (m_cache)
m_cache->add(n, pre_type, pre_value, ls, type, value);
m_cache->add(m_env, n, pre_type, pre_value, ls, type, value);
}
optional<std::tuple<level_param_names, expr, expr>> parser::find_cached_definition(name const & n, expr const & pre_type, expr const & pre_value) {
if (m_cache)
return m_cache->find(n, pre_type, pre_value);
return m_cache->find(m_env, n, pre_type, pre_value);
else
return optional<std::tuple<level_param_names, expr, expr>>();
}

View file

@ -5,6 +5,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include "util/interrupt.h"
#include "kernel/for_each_fn.h"
#include "library/placeholder.h"
#include "library/kernel_serializer.h"
#include "library/definition_cache.h"
@ -118,6 +119,12 @@ public:
bool operator()(expr const & a, expr const & b) { return compare(a, b); }
};
definition_cache::entry::entry(expr const & pre_t, expr const & pre_v,
level_param_names const & ps, expr const & t, expr const & v,
dependencies const & deps):
m_pre_type(pre_t), m_pre_value(pre_v), m_params(ps),
m_type(t), m_value(v), m_dependencies(deps) {}
definition_cache::definition_cache() {}
void definition_cache::load(std::istream & in) {
@ -130,19 +137,46 @@ void definition_cache::load(std::istream & in) {
level_param_names ls;
expr pre_type, pre_value, type, value;
d >> n >> pre_type >> pre_value >> ls >> type >> value;
add_core(n, pre_type, pre_value, ls, type, value);
dependencies deps;
unsigned num;
d >> num;
for (unsigned i = 0; i < num; i++) {
name n; unsigned h;
d >> n >> h;
deps.insert(n, h);
}
add_core(n, pre_type, pre_value, ls, type, value, deps);
}
}
void definition_cache::add_core(name const & n, expr const & pre_type, expr const & pre_value,
level_param_names const & ls, expr const & type, expr const & value) {
m_definitions.insert(n, entry(pre_type, pre_value, ls, type, value));
void definition_cache::collect_dependencies(environment const & env, expr const & e, dependencies & deps) {
for_each(e, [&](expr const & e, unsigned) {
if (!is_constant(e))
return true;
name const & n = const_name(e);
if (deps.contains(n))
return true;
auto d = env.find(n);
if (!d)
return true;
deps.insert(n, hash_bi(d->get_type()));
return true;
});
}
void definition_cache::add(name const & n, expr const & pre_type, expr const & pre_value,
level_param_names const & ls, expr const & type, expr const & value) {
void definition_cache::add_core(name const & n, expr const & pre_type, expr const & pre_value,
level_param_names const & ls, expr const & type, expr const & value,
dependencies const & deps) {
m_definitions.insert(n, entry(pre_type, pre_value, ls, type, value, deps));
}
void definition_cache::add(environment const & env, name const & n, expr const & pre_type, expr const & pre_value,
level_param_names const & ls, expr const & type, expr const & value) {
dependencies deps;
collect_dependencies(env, type, deps);
collect_dependencies(env, value, deps);
lock_guard<mutex> lc(m_mutex);
add_core(n, pre_type, pre_value, ls, type, value);
add_core(n, pre_type, pre_value, ls, type, value, deps);
}
void definition_cache::erase(name const & n) {
@ -155,21 +189,42 @@ void definition_cache::clear() {
m_definitions.clear();
}
optional<std::tuple<level_param_names, expr, expr>> definition_cache::find(name const & n, expr const & pre_type, expr const & pre_value) {
entry const * it;
/** \brief Return true iff the type of all declarations in deps still have the same hashcode
stored in deps. */
bool definition_cache::check_dependencies(environment const & env, dependencies const & deps) {
bool ok = true;
deps.for_each([&](name const & n, unsigned h) {
if (ok) {
if (auto d = env.find(n)) {
if (h != hash_bi(d->get_type()))
ok = false;
} else {
ok = false;
}
}
});
return ok;
}
optional<std::tuple<level_param_names, expr, expr>>
definition_cache::find(environment const & env, name const & n, expr const & pre_type, expr const & pre_value) {
entry e;
{
lock_guard<mutex> lc(m_mutex);
it = m_definitions.find(n);
if (auto it = m_definitions.find(n)) {
e = *it;
} else {
return optional<std::tuple<level_param_names, expr, expr>>();
}
}
if (it) {
level_param_names ls;
expr c_pre_type, c_pre_value, type, value;
std::tie(c_pre_type, c_pre_value, ls, type, value) = *it;
if (expr_eq_modulo_placeholders_fn()(c_pre_type, pre_type) &&
expr_eq_modulo_placeholders_fn()(c_pre_value, pre_value))
return some(std::make_tuple(ls, type, value));
level_param_names ls;
if (expr_eq_modulo_placeholders_fn()(e.m_pre_type, pre_type) &&
expr_eq_modulo_placeholders_fn()(e.m_pre_value, pre_value) &&
check_dependencies(env, e.m_dependencies)) {
return some(std::make_tuple(e.m_params, e.m_type, e.m_value));
} else {
return optional<std::tuple<level_param_names, expr, expr>>();
}
return optional<std::tuple<level_param_names, expr, expr>>();
}
void definition_cache::save(std::ostream & out) {
@ -177,10 +232,12 @@ void definition_cache::save(std::ostream & out) {
serializer s(out);
s << m_definitions.size();
m_definitions.for_each([&](name const & n, entry const & e) {
level_param_names ls;
expr c_pre_type, c_pre_value, type, value;
std::tie(c_pre_type, c_pre_value, ls, type, value) = e;
s << n << c_pre_type << c_pre_value << ls << type << value;
s << n << e.m_pre_type << e.m_pre_value << e.m_params
<< e.m_type << e.m_value;
s << static_cast<unsigned>(e.m_dependencies.size());
e.m_dependencies.for_each([&](name const & n, unsigned h) {
s << n << h;
});
});
}
}

View file

@ -15,21 +15,37 @@ namespace lean {
after elaboration.
*/
class definition_cache {
typedef std::tuple<expr, expr, level_param_names, expr, expr> entry;
typedef name_map<unsigned> dependencies; // store the hash code for the type of used constants
struct entry {
expr m_pre_type;
expr m_pre_value;
level_param_names m_params;
expr m_type;
expr m_value;
dependencies m_dependencies;
entry() {}
entry(expr const & pre_t, expr const & pre_v, level_param_names const & ps, expr const & t, expr const & v,
dependencies const & deps);
entry(expr const & pre_t, expr const & pre_v, level_param_names const & ps, expr const & t, expr const & v);
};
mutex m_mutex;
name_map<entry> m_definitions;
void collect_dependencies(environment const & env, expr const & e, dependencies & deps);
bool check_dependencies(environment const & env, dependencies const & deps);
void add_core(name const & n, expr const & pre_type, expr const & pre_value, level_param_names const & ls,
expr const & type, expr const & value);
expr const & type, expr const & value, dependencies const & deps);
public:
definition_cache();
/** \brief Add the cache entry (n, pre_type, pre_value) -> (ls, type, value) */
void add(name const & n, expr const & pre_type, expr const & pre_value, level_param_names const & ls, expr const & type, expr const & value);
void add(environment const & env, name const & n, expr const & pre_type, expr const & pre_value,
level_param_names const & ls, expr const & type, expr const & value);
/** \brief Return (if available) elaborated (level_names, type, value) for (n, pre_type, pre_value).
The pre_type and pre_value are compared modulo placeholders names if the cached values.
In principle, we could have compared only the name and pre_type, but we only want to use cached values if the
user intent (captured by pre_value) did not change.
*/
optional<std::tuple<level_param_names, expr, expr>> find(name const & n, expr const & pre_type, expr const & pre_value);
optional<std::tuple<level_param_names, expr, expr>>
find(environment const & env, name const & n, expr const & pre_type, expr const & pre_value);
/** \brief Store the cache content into the given stream */
void save(std::ostream & out);
/** \brief Load the cache content from the given stream */