Skip to content
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

Proof caching: use dependency graph to increase hit rate #3305

Merged
merged 42 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
eb2b772
Move caching extension to gradle module
FliegendeWurst Oct 19, 2023
df58f4f
Use dependency graph information in caching
FliegendeWurst Oct 19, 2023
77140f2
Handle slicing data in cache copy
FliegendeWurst Oct 19, 2023
8c2ee38
Drop always-false instanceof check in constructor
FliegendeWurst Oct 23, 2023
c6390c7
Optimize dependency graph based sequent reduction
FliegendeWurst Oct 23, 2023
472f71a
SubtreeIterator: adhere to Iterator spec
FliegendeWurst Oct 23, 2023
abc94d0
Implement chain shortening in dependency graph
FliegendeWurst Oct 23, 2023
25ba99b
Merge remote-tracking branch 'origin/main' into caching-sliced
FliegendeWurst Oct 24, 2023
27a15d0
Merge remote-tracking branch 'origin/main' into caching-sliced
FliegendeWurst Oct 26, 2023
7e90a72
Test case (WIP)
FliegendeWurst Oct 29, 2023
1262ab4
Merge remote-tracking branch 'origin/main' into caching-sliced
FliegendeWurst Oct 30, 2023
0952001
Fix test case
FliegendeWurst Oct 30, 2023
f10fa9d
Remove debug print
FliegendeWurst Oct 30, 2023
5230459
Move over test files into keyext.caching
FliegendeWurst Oct 30, 2023
3cfd950
Fix testcase location
FliegendeWurst Nov 2, 2023
f4850f1
Merge remote-tracking branch 'origin/main' into caching-sliced
FliegendeWurst Nov 4, 2023
1dd5f47
Fix slicing of proofs with certain filenames
FliegendeWurst Nov 4, 2023
5c69849
Dependency Graph: tooltips for rendering modifiers
FliegendeWurst Nov 4, 2023
235a361
Merge remote-tracking branch 'origin/main' into caching-sliced
FliegendeWurst Nov 12, 2023
f3ae955
Chain shortening: more useful edge labels
FliegendeWurst Jan 11, 2024
61f29ca
Better tooltip for shortened chains
FliegendeWurst Jan 11, 2024
c795ff8
Merge remote-tracking branch 'origin/main' into caching-sliced
FliegendeWurst Jan 11, 2024
bfcdbca
Javadocs
FliegendeWurst Jan 11, 2024
f66241d
Codestyle
FliegendeWurst Jan 15, 2024
072ece1
Global disable for proof caching
FliegendeWurst Jan 15, 2024
c4b57fd
Refactor action into own package
FliegendeWurst Jan 15, 2024
58c8af6
Refactor CopyReferencedProof action into own class
FliegendeWurst Jan 15, 2024
2fbfe99
New action to re-open goals closed by cache
FliegendeWurst Jan 15, 2024
64453d3
Fix ProgramMethodFinder + javadocs
FliegendeWurst Jan 16, 2024
97633a3
Merge remote-tracking branch 'origin/main' into caching-sliced
FliegendeWurst Jan 18, 2024
5e3a0ae
Set tooltip of proof caching button
FliegendeWurst Jan 18, 2024
aa9ceec
Naming of cached goal re-open action
FliegendeWurst Jan 18, 2024
fab4ab7
Merge remote-tracking branch 'origin/main' into caching-sliced
FliegendeWurst Jan 25, 2024
f31d248
Handle prunes of proof cache targets
FliegendeWurst Jan 25, 2024
9c07e2c
Caching: make behaviour when reference proof is pruned configurable
FliegendeWurst Jan 29, 2024
d199118
Document other caching option
FliegendeWurst Jan 29, 2024
fa8471d
Move caching settings to extension package
FliegendeWurst Jan 29, 2024
910e32e
New proof context menu action to cache open goals
FliegendeWurst Jan 31, 2024
ba3bae1
Transparent proof caching icon
FliegendeWurst Feb 6, 2024
72da2a0
Fix caching bug where an exception was thrown
FliegendeWurst Feb 8, 2024
f4eae66
Make caching more robust by catching exceptions
FliegendeWurst Feb 8, 2024
82b0ac9
Merge remote-tracking branch 'origin/main' into caching-sliced
FliegendeWurst Feb 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions key.core/src/main/java/de/uka/ilkd/key/java/Comment.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

import de.uka.ilkd.key.java.visitor.Visitor;

/**
* Comment element of Java source code.
*/
public class Comment extends JavaSourceElement {

private final String text;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,35 @@
public class MethodDeclaration extends JavaDeclaration implements MemberDeclaration,
TypeReferenceContainer, NamedProgramElement, ParameterContainer, Method, VariableScope {

/**
* The return type of the method.
*/
protected final TypeReference returnType;
/**
* In case of void return type: comments associated with the method.
*/
protected final Comment[] voidComments;
/**
* The name of the method.
*/
protected final ProgramElementName name;
/**
* Parameters of the method.
*/
protected final ImmutableArray<ParameterDeclaration> parameters;
/**
* 'throws' part of the method. Indicates which exceptions the method may throw.
* May be null.
*/
protected final Throws exceptions;
/**
* Body of the method.
* May be null, in which case the body is referenced in a file using {@link #posInfo}.
*/
protected final StatementBlock body;
/**
* JML modifiers of the referenced method. Includes e.g. {@code pure}.
*/
protected final JMLModifiers jmlModifiers;

/**
Expand All @@ -53,12 +76,14 @@ public record JMLModifiers(boolean pure, boolean strictlyPure, boolean helper,
/**
* Method declaration.
*
* @param children an ExtList of children. May include: a TypeReference (as a reference to the
* return type), a de.uka.ilkd.key.logic.ProgramElementName (as Name of the method),
* several ParameterDeclaration (as parameters of the declared method), a StatementBlock
* (as body of the declared method), several Modifier (taken as modifiers of the
* declaration), a Comment
* @param children an ExtList of children. Must include: a TypeReference (as a reference to the
* return type),
* a {@link ProgramElementName} (as Name of the method),
* one or more {@link ParameterDeclaration} (as parameters of the declared method),
* optionally a {@link StatementBlock} (as body of the declared method),
* optionally a {@link Throws} to indicate exceptional behaviour
* @param parentIsInterfaceDeclaration a boolean set true iff parent is an InterfaceDeclaration
* @param voidComments in case of void return type: comments associated with the method
*/
public MethodDeclaration(ExtList children, boolean parentIsInterfaceDeclaration,
Comment[] voidComments) {
Expand Down Expand Up @@ -266,6 +291,12 @@ public TypeReference getTypeReference() {
}


/**
* Get the "void comments" of this method declaration.
* Only non-null if the method has void return type.
*
* @return the "void comments"
*/
public Comment[] getVoidComments() {
return voidComments;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class Throws extends JavaNonTerminalProgramElement implements TypeReferen


/**
* Exceptions.
* Exceptions thrown.
*/
protected final ImmutableArray<TypeReference> exceptions;

Expand Down
35 changes: 31 additions & 4 deletions key.core/src/main/java/de/uka/ilkd/key/logic/Semisequent.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* SPDX-License-Identifier: GPL-2.0-only */
package de.uka.ilkd.key.logic;

import java.util.Collection;
import java.util.Iterator;

import org.key_project.util.collection.ImmutableList;
Expand All @@ -27,11 +28,10 @@ private Semisequent() {
seqList = ImmutableSLList.nil();
}


/**
* creates a new Semisequent with the Semisequent elements in seqList; the provided list must be
* redundancy free, i.e., the created sequent must be exactly the same as when creating the
* sequent by subsequently inserting all formulas
* Create a new Semisequent from an ordered collection of formulas.
* The provided list must be redundancy free, i.e., the created sequent must be exactly
* the same as when creating the sequent by subsequently inserting all formulas
*
* @param seqList list of sequent formulas
*/
Expand All @@ -40,6 +40,33 @@ public Semisequent(ImmutableList<SequentFormula> seqList) {
this.seqList = seqList;
}

/**
* Create a new Semisequent from an ordered collection of formulas.
* The provided collection must be redundancy free, i.e., the created sequent must be exactly
* the same as when creating the sequent by subsequently inserting all formulas
*
* @param seqList list of sequent formulas
*/
public Semisequent(Collection<SequentFormula> seqList) {
assert !seqList.isEmpty();
this.seqList = ImmutableList.fromList(seqList);
}

/**
* Create a new Semisequent from an ordered collection of formulas (possibly empty).
* The provided collection must be redundancy free, i.e., the created sequent must be exactly
* the same as when creating the
* sequent by subsequently inserting all formulas.
*
* @param seqList list of sequent formulas
*/
public static Semisequent create(Collection<SequentFormula> seqList) {
if (seqList.isEmpty()) {
return EMPTY_SEMISEQUENT;
}
return new Semisequent(seqList);
}


/**
* creates a new Semisequent with the Semisequent elements in seqList
Expand Down
24 changes: 16 additions & 8 deletions key.core/src/main/java/de/uka/ilkd/key/logic/op/ProgramMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,31 @@
import org.key_project.util.collection.ImmutableArray;
import org.key_project.util.collection.ImmutableList;
import org.key_project.util.collection.ImmutableSLList;
import org.key_project.util.collection.ImmutableSet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The program method represents a (pure) method in the logic. In case of a non-static method the
* first argument represents the object on which the method is invoked.
* <p>
* This data is used in
* {@link de.uka.ilkd.key.speclang.QueryAxiom#getTaclets(ImmutableSet, Services)}.
*/
public final class ProgramMethod extends ObserverFunction
implements ProgramInLogic, IProgramMethod {

private static final Logger LOGGER = LoggerFactory.getLogger(ProgramMethod.class);

/**
* The referenced method.
*/
private final MethodDeclaration method;
/**
* Return type of the method. Must not be null. Use KeYJavaType.VOID_TYPE for void methods.
*/
private final KeYJavaType returnType;
/**
* Where the method is located in a .java file.
*/
private final PositionInfo pi;

// -------------------------------------------------------------------------
Expand All @@ -63,6 +70,12 @@ public ProgramMethod(MethodDeclaration method, KeYJavaType container, KeYJavaTyp
// internal methods
// -------------------------------------------------------------------------

/**
* Get the java types of the parameters required by the method md.
*
* @param md some method declaration
* @return java types of the parameters required by md
*/
private static ImmutableArray<KeYJavaType> getParamTypes(MethodDeclaration md) {
KeYJavaType[] result = new KeYJavaType[md.getParameterDeclarationCount()];
for (int i = 0; i < result.length; i++) {
Expand All @@ -80,11 +93,6 @@ private static ImmutableArray<KeYJavaType> getParamTypes(MethodDeclaration md) {
// MethodDeclaration
// in a direct way

/*
* (non-Javadoc)
*
* @see de.uka.ilkd.key.logic.op.IProgramMethod#getMethodDeclaration()
*/
@Override
public MethodDeclaration getMethodDeclaration() {
return method;
Expand Down
2 changes: 1 addition & 1 deletion key.core/src/main/java/de/uka/ilkd/key/proof/Node.java
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ public Collection<Node> children() {
}

/**
* @return an iterator for all nodes in the subtree.
* @return an iterator for all nodes in the subtree (including this node).
*/
public Iterator<Node> subtreeIterator() {
return new SubtreeIterator(this);
Expand Down
46 changes: 46 additions & 0 deletions key.core/src/main/java/de/uka/ilkd/key/proof/Proof.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;

import de.uka.ilkd.key.java.JavaInfo;
Expand All @@ -16,8 +17,11 @@
import de.uka.ilkd.key.proof.event.ProofDisposedListener;
import de.uka.ilkd.key.proof.init.InitConfig;
import de.uka.ilkd.key.proof.init.Profile;
import de.uka.ilkd.key.proof.io.IntermediateProofReplayer;
import de.uka.ilkd.key.proof.mgt.ProofCorrectnessMgt;
import de.uka.ilkd.key.proof.mgt.ProofEnvironment;
import de.uka.ilkd.key.proof.reference.ClosedBy;
import de.uka.ilkd.key.proof.replay.CopyingProofReplayer;
import de.uka.ilkd.key.rule.OneStepSimplifier;
import de.uka.ilkd.key.settings.GeneralSettings;
import de.uka.ilkd.key.settings.ProofIndependentSettings;
Expand Down Expand Up @@ -1254,4 +1258,46 @@ public <T> void deregister(T obj, Class<T> service) {
public void setMutedProofCloseEvents(boolean mutedProofCloseEvents) {
this.mutedProofCloseEvents = mutedProofCloseEvents;
}

/**
* For each branch closed by reference to another proof,
* copy the relevant proof steps into this proof.
*
* @param referencedFrom filter, if not null copy only from that proof
* @param callbackTotal callback that gets the total number of branches to complete
* @param callbackBranch callback notified every time a branch has been copied
*/
public void copyCachedGoals(Proof referencedFrom, Consumer<Integer> callbackTotal,
Runnable callbackBranch) {
// first, ensure that all cached goals are copied over
List<Goal> goals = closedGoals().toList();
List<Goal> todo = new ArrayList<>();
for (Goal g : goals) {
Node node = g.node();
ClosedBy c = node.lookup(ClosedBy.class);
if (c == null) {
continue;
}
if (referencedFrom != null && referencedFrom != c.proof()) {
continue;
}
todo.add(g);
}
if (callbackTotal != null) {
callbackTotal.accept(todo.size());
}
for (Goal g : todo) {
reOpenGoal(g);
ClosedBy c = g.node().lookup(ClosedBy.class);
g.node().deregister(c, ClosedBy.class);
try {
new CopyingProofReplayer(c.proof(), this).copy(c.node(), g, c.nodesToSkip());
} catch (IntermediateProofReplayer.BuiltInConstructionException e) {
throw new RuntimeException(e);
}
if (callbackBranch != null) {
callbackBranch.run();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package de.uka.ilkd.key.proof;

import java.util.Iterator;
import java.util.NoSuchElementException;

/**
* Iterator over subtree. Current implementation iteratively traverses the tree depth-first.
Expand Down Expand Up @@ -58,6 +59,8 @@ public Node next() {
Node s = nextSibling(n);
if (s != null) {
n = s;
} else {
throw new NoSuchElementException();
}
} else {
n = n.child(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@
* SPDX-License-Identifier: GPL-2.0-only */
package de.uka.ilkd.key.proof.reference;

import java.util.Set;

import de.uka.ilkd.key.proof.Node;
import de.uka.ilkd.key.proof.Proof;

/**
* Indicates that a branch has been closed by "reference" to another closed proof.
* This is always looked up using {@link Node#lookup(Class)} on the node of that branch.
*
* @param proof The proof referenced.
* @param node The node referenced.
* @param nodesToSkip If the referenced proof has dependency graph information: proof steps to skip.
* @author Arne Keller
*/
public record ClosedBy(Proof proof, Node node) {
public record ClosedBy(Proof proof, Node node, Set<Node> nodesToSkip) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public static void copyCachedGoals(
ClosedBy c = g.node().lookup(ClosedBy.class);
g.node().deregister(c, ClosedBy.class);
try {
new CopyingProofReplayer(c.proof(), toComplete).copy(c.node(), g);
new CopyingProofReplayer(c.proof(), toComplete).copy(c.node(), g, c.nodesToSkip());
} catch (IntermediateProofReplayer.BuiltInConstructionException e) {
throw new RuntimeException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Set;

import de.uka.ilkd.key.proof.Goal;
import de.uka.ilkd.key.proof.Node;
Expand Down Expand Up @@ -35,24 +36,36 @@ public CopyingProofReplayer(Proof originalProof, Proof proof) {
*
* @param originalNode original proof
* @param newNode open goal in new proof
* @param skippedNodes nodes to skip when copying
* @throws IntermediateProofReplayer.BuiltInConstructionException on error
*/
public void copy(Node originalNode, Goal newNode)
public void copy(Node originalNode, Goal newNode, Set<Node> skippedNodes)
throws IntermediateProofReplayer.BuiltInConstructionException {
newNode.proof().reOpenGoal(newNode);
newNode.proof().register(this, CopyingProofReplayer.class);
newNode.proof().setMutedProofCloseEvents(true);
OneStepSimplifier.refreshOSS(newNode.proof());

// nodeQueue: nodes in the ORIGINAL proof
Deque<Node> nodeQueue = new ArrayDeque<>();
// queue: nodes in the NEW proof
Deque<Goal> queue = new ArrayDeque<>();

queue.add(newNode);
nodeQueue.add(originalNode);
while (!nodeQueue.isEmpty()) {
while (!nodeQueue.isEmpty() && !queue.isEmpty()) {
Node nextNode = nodeQueue.pop();
Goal nextGoal = queue.pop();
for (int i = nextNode.childrenCount() - 1; i >= 0; i--) {
nodeQueue.addFirst(nextNode.child(i));
}
// skip explicitly requested nodes
if (skippedNodes.contains(nextNode)) {
if (!nextGoal.node().isClosed()) {
queue.addFirst(nextGoal);
}
continue;
}
// skip nextNode if it is a closed goal
if (nextNode.getAppliedRuleApp() == null) {
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ public ImmutableSet<Taclet> getTaclets(ImmutableSet<Pair<Sort, IObserverFunction
// create java block
final ImmutableList<KeYJavaType> sig = ImmutableSLList.<KeYJavaType>nil()
.append(target.getParamTypes().toArray(new KeYJavaType[target.getNumParams()]));
// get real implementation of program method
final IProgramMethod targetImpl =
services.getJavaInfo().getProgramMethod(kjt, target.getName(), sig, kjt);
final MethodBodyStatement mbs = new MethodBodyStatement(targetImpl, selfProgSV,
Expand Down
Loading
Loading