-
-
Notifications
You must be signed in to change notification settings - Fork 45
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
Fix enode memoization #238
Changes from all commits
4d24031
59718eb
e4a3f03
2677542
c5c4776
de83bd9
9f504fe
a606a15
29890ce
8e95e4a
c398f31
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,6 @@ | ||
name: CI | ||
on: | ||
pull_request: | ||
branches: | ||
- master | ||
push: | ||
branches: | ||
- master | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -223,38 +223,20 @@ Returns the canonical e-class id for a given e-class. | |
|
||
@inline Base.getindex(g::EGraph, i::Id) = g.classes[IdKey(find(g, i))] | ||
|
||
# function canonicalize(g::EGraph, n::VecExpr)::VecExpr | ||
# if !v_isexpr(n) | ||
# v_hash!(n) | ||
# return n | ||
# end | ||
# l = v_arity(n) | ||
# new_n = v_new(l) | ||
# v_set_flag!(new_n, v_flags(n)) | ||
# v_set_head!(new_n, v_head(n)) | ||
# for i in v_children_range(n) | ||
# @inbounds new_n[i] = find(g, n[i]) | ||
# end | ||
# v_hash!(new_n) | ||
# new_n | ||
# end | ||
|
||
function canonicalize!(g::EGraph, n::VecExpr) | ||
v_isexpr(n) || @goto ret | ||
for i in (VECEXPR_META_LENGTH + 1):length(n) | ||
@inbounds n[i] = find(g, n[i]) | ||
if v_isexpr(n) | ||
for i in (VECEXPR_META_LENGTH + 1):length(n) | ||
@inbounds n[i] = find(g, n[i]) | ||
end | ||
end | ||
v_unset_hash!(n) | ||
@label ret | ||
v_hash!(n) | ||
Comment on lines
-247
to
-249
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't the hash going to mutate as well? What is the difference from caching it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, you are right, the main issue is that VecExpr must not be updated after they have been added to memo. Caching of hash values is an independent concern. The cached value can make up 15% to 20% of the memory required for VecExpr. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using the annotations in https://github.com/gkronber/Metatheory.jl/tree/count_vecexpr_hash_calls julia> using Metatheory
Precompiling Metatheory
1 dependency successfully precompiled in 2 seconds. 6 already precompiled.
julia> include("benchmark/benchmarks.jl")
Benchmark(evals=1, seconds=5.0, samples=10000)
julia> run(SUITE)
[...]
julia> Metatheory.VecExprModule.vexpr_created
12355173
julia> Metatheory.VecExprModule.v_copy_calls
5247759
julia> Metatheory.VecExprModule.v_new_calls
3975935
julia> Metatheory.VecExprModule.unset_hash_calls
41556639
julia> Metatheory.VecExprModule.hash_calls
93167599
julia> Metatheory.VecExprModule.cached_hash_computation
40712170
julia> Metatheory.VecExprModule.cached_hash_access
1205819
julia> Metatheory.EGraphs.memo_lookups
31998547
julia> Metatheory.EGraphs.memo_add
15708295 In this run of the benchmarks:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think this happens as well in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In egg they are careful to clone nodes before adding them to memo. |
||
n | ||
end | ||
|
||
function lookup(g::EGraph, n::VecExpr)::Id | ||
canonicalize!(g, n) | ||
h = IdKey(v_hash(n)) | ||
|
||
haskey(g.memo, n) ? find(g, g.memo[n]) : 0 | ||
id = get(g.memo, n, zero(Id)) | ||
iszero(id) ? id : find(g, id) | ||
end | ||
|
||
|
||
|
@@ -272,9 +254,10 @@ Inserts an e-node in an [`EGraph`](@ref) | |
""" | ||
function add!(g::EGraph{ExpressionType,Analysis}, n::VecExpr, should_copy::Bool)::Id where {ExpressionType,Analysis} | ||
canonicalize!(g, n) | ||
|
||
haskey(g.memo, n) && return g.memo[n] | ||
|
||
|
||
id = get(g.memo, n, zero(Id)) | ||
iszero(id) || return id | ||
|
||
if should_copy | ||
n = copy(n) | ||
end | ||
|
@@ -319,28 +302,21 @@ function addexpr!(g::EGraph, se)::Id | |
se isa EClass && return se.id | ||
e = preprocess(se) | ||
|
||
n = if isexpr(e) | ||
args = iscall(e) ? arguments(e) : children(e) | ||
ar = length(args) | ||
n = v_new(ar) | ||
v_set_flag!(n, VECEXPR_FLAG_ISTREE) | ||
iscall(e) && v_set_flag!(n, VECEXPR_FLAG_ISCALL) | ||
|
||
h = iscall(e) ? operation(e) : head(e) | ||
v_set_head!(n, add_constant!(g, h)) | ||
|
||
# get the signature from op and arity | ||
v_set_signature!(n, hash(maybe_quote_operation(h), hash(ar))) | ||
|
||
for i in v_children_range(n) | ||
@inbounds n[i] = addexpr!(g, args[i - VECEXPR_META_LENGTH]) | ||
end | ||
n | ||
else # constant enode | ||
VecExpr(Id[Id(0), Id(0), Id(0), add_constant!(g, e)]) | ||
isexpr(e) || return add!(g, VecExpr(Id[Id(0), Id(0), add_constant!(g, e)]), false) # constant enode | ||
|
||
args = iscall(e) ? arguments(e) : children(e) | ||
ar = length(args) | ||
n = v_new(ar) | ||
v_set_flag!(n, VECEXPR_FLAG_ISTREE) | ||
iscall(e) && v_set_flag!(n, VECEXPR_FLAG_ISCALL) | ||
h = iscall(e) ? operation(e) : head(e) | ||
v_set_head!(n, add_constant!(g, h)) | ||
# get the signature from op and arity | ||
v_set_signature!(n, hash(maybe_quote_operation(h), hash(ar))) | ||
for i in v_children_range(n) | ||
@inbounds n[i] = addexpr!(g, args[i - VECEXPR_META_LENGTH]) | ||
end | ||
id = add!(g, n, false) | ||
return id | ||
add!(g, n, false) | ||
end | ||
|
||
""" | ||
|
@@ -431,9 +407,8 @@ function process_unions!(g::EGraph{ExpressionType,AnalysisType})::Int where {Exp | |
while !isempty(g.pending) | ||
(node::VecExpr, eclass_id::Id) = pop!(g.pending) | ||
canonicalize!(g, node) | ||
if haskey(g.memo, node) | ||
old_class_id = g.memo[node] | ||
g.memo[node] = eclass_id | ||
old_class_id = get!(g.memo, node, eclass_id) | ||
if old_class_id != eclass_id | ||
did_something = union!(g, old_class_id, eclass_id) | ||
# TODO unique! can node dedup be moved here? compare performance | ||
# did_something && unique!(g[eclass_id].nodes) | ||
|
@@ -473,17 +448,16 @@ function check_memo(g::EGraph)::Bool | |
for (id, class) in g.classes | ||
@assert id.val == class.id | ||
for node in class.nodes | ||
if haskey(test_memo, node) | ||
old_id = test_memo[node] | ||
test_memo[node] = id.val | ||
old_id = get!(test_memo, node, id.val) | ||
if old_id != id.val | ||
@assert find(g, old_id) == find(g, id.val) "Unexpected equivalence $node $(g[find(g, id.val)].nodes) $(g[find(g, old_id)].nodes)" | ||
end | ||
end | ||
end | ||
|
||
for (node, id) in test_memo | ||
@assert id == find(g, id) | ||
@assert id == find(g, g.memo[node]) | ||
@assert id == find(g, g.memo[node]) "Entry for $node at $id in test_memo was incorrect." | ||
end | ||
|
||
true | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is also changed in master i think