-
Notifications
You must be signed in to change notification settings - Fork 76
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
Optimize CFG representation #609
base: master
Are you sure you want to change the base?
Conversation
I think I will cherry-pick some (working) changes from this PR to a new PR that could be safely merged. Then we could already benefit from some optimizations while the full representation change isn't yet in working order. |
I've been debugging the reluctant destabilization problem and decided to do some tracing on Tracing the incremental run of 03-precision-annotation/01-change_precision on
Importantly the Therefore, I am now extremely suspicious of reluctant destabilization and have my doubts about the correctness of its implementation. Maybe it's so fast because it just computes trivial bottoms... @stilscher The extra tracing is by: diff --git a/src/framework/cfgTools.ml b/src/framework/cfgTools.ml
index b7bcd0781..e04509cab 100644
--- a/src/framework/cfgTools.ml
+++ b/src/framework/cfgTools.ml
@@ -598,7 +598,12 @@ let getCFG (file: file) : cfg * cfg =
(cfgF, cfgB)
in
if get_bool "justcfg" then fprint_hash_dot cfgB;
- H.find_all cfgF, H.find_all cfgB
+ let find_cfg f n =
+ let ns = f n in
+ if Messages.tracing then Messages.trace "cfg" "%a: %a\n" Node.pretty n (d_list ", " Node.pretty) (List.map snd ns);
+ ns
+ in
+ find_cfg (H.find_all cfgF), find_cfg (H.find_all cfgB)
(* TODO: unused *) |
So I reconstructed what you described above. The reluctant destabilization works fine on a minimized example without the precision annotation. In the run on 03-precision-annotation/01-change_precision, the problem arises because the new CIL file contains an added global, a |
Thanks for looking into it and constructing a test where the unsoundness actually shows. I wasn't 100% sure whether it actually ever would.
This feels like a quick hack than a proper fix, because really the problem is with the incremental comparison and updating, if it gets confused by a |
Actually I also have some doubts about whether the reluctant destabilization in the solver is the right place to handle this. But I think the comparison and updating of ids is actually quite consistent. The
That is probably true. However, a change that adds a function declaration for a function that already exists and is changed at the same time is probably rather rare. And as far as I know, this should be the only case were the problem occurs. Maybe one can do a quick fix, to make sure that our benchmarks are correct and open an issue to think about improving it later? |
I think the comparison and updating should still ensure that the invariant holds that they share the same
That makes sense, we don't have to make the more sophisticated general fix immediately and in this PR. |
Just to make it very clear, this is blocked by #627. |
I now brought this up to date and the previously failing incremental test at least passes now. EDIT: I managed to fix the major issue, but one failure still remains. EDIT 2: I managed to also fix the last issue for now. |
@michael-schwarz Was it the plan for some students to benchmark this? If so, then this should be in a suitable state for doing so. It's still suboptimal due to extra EDIT: Apparently not. My last fix broke the added test again, so there might be more to this with CFG comparison. |
The thought was that the students working on improving Goblint performance might want to consider this. However, if it is currently broken in a way we do not 100% understand ourselves, it may be better to not include it in the scope of their work. |
It does work non-incrementally, so it would still be possible to benchmark this. If there's no benefit, then there's no reason to try to fix it for CFG comparison either. So it could still be tried if there's interest/resources, but it's not a top priority. |
I merged |
As discussed at Gobcon today, one may try to evaluate this with If this turns out to be useful but still breaks the CFG comparison, one may remove the CFG comparison. |
Split CFG hashtables per function throughout, not just for the duration of connectedness checking (like in #603). This should speed up analogous lookups during transfer functions as well (which use
Cfg.prev
). The problem is that now looking up the predecessors of aStatement
node requires first looking up thefundec
of the statement in another mapping just to know which function's CFG hashtable to consult for the predecessors. This might not be too bad (or if it is, thenfundec
could also be added toStatement
orNode.t
itself, although changing that requires broader changes). The problem right now has to do with reluctant destabilization, see below.TODO
Fix reluctant destabilization. When reluctant destabilization is being applied, there's some limbo between the old CFG and the new CFG. The reluctant solve somehow ends up solving a function with its old ID (because that's what's in the unmarshaled hashtable), but the CFG and the constraint system only know about the function with its new ID. I'm not yet sure whether and how this can be fixed.
Figure out why a lot of GC is happening in innocent (non-allocating) functions like
Hashtbl.mem
andHashtbl.find
.find
shouldn't, butmem
does. To be fixed in OCaml standard library: Manually unbox closure inHashtbl.mem
ocaml/ocaml#11500.Move
fundec
intoNode.Statement
to avoid extraNode.find_fundec
lookups?