Skip to content

Commit

Permalink
combine call and data dependence graph
Browse files Browse the repository at this point in the history
  • Loading branch information
dkarv committed Oct 31, 2017
1 parent d5a9ea8 commit 77c8838
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 34 deletions.
6 changes: 3 additions & 3 deletions examples/falo.ini
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ logLevel: 4
logConsole: false

# Do not remove duplicate edges
multiGraph: true
multiGraph: false

# One graph per <thread> <entry method> or <test>
groupBy: ENTRY

# store dot files and coverage matrix
# writeTo: DOT,TRACE,COVERAGE,DD_DOT,LINES
writeTo: DOT,DD_DOT,LINES
writeTo: DOT,TRACE,COVERAGE,DD_DOT,LINES,COMBINED_DOT
# writeTo: DOT,DD_DOT,LINES

format: {class}#{line}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
import com.dkarv.jdcallgraph.callgraph.CallGraph;
import com.dkarv.jdcallgraph.data.DataDependenceGraph;
import com.dkarv.jdcallgraph.util.StackItem;
import com.dkarv.jdcallgraph.util.config.*;
import com.dkarv.jdcallgraph.util.log.Logger;
import com.dkarv.jdcallgraph.util.options.*;

import java.io.IOException;
import java.util.HashMap;
Expand All @@ -40,6 +42,17 @@ public class FieldAccessRecorder {
* Collect the call graph per thread.
*/
static final Map<Long, DataDependenceGraph> GRAPHS = new HashMap<>();
private static final boolean needCombined;

static {
boolean combined = false;
for (Target t : Config.getInst().writeTo()) {
if (t == Target.COMBINED_DOT) {
combined = true;
}
}
needCombined = combined;
}

public static void write(String fromClass, String fromMethod, int lineNumber, String fieldClass, String fieldName) {
try {
Expand All @@ -65,7 +78,14 @@ public static void read(String fromClass, String fromMethod, int lineNumber, Str
LOG.trace("Read not interesting because there was no write before");
return;
}
graph.addRead(new StackItem(fromClass, fromMethod, lineNumber), fieldClass + "::" + fieldName);
if (needCombined) {
CallGraph callGraph = CallRecorder.GRAPHS.get(threadId);
graph.addRead(new StackItem(fromClass, fromMethod, lineNumber), fieldClass + "::" +
fieldName, callGraph);
} else {
graph.addRead(new StackItem(fromClass, fromMethod, lineNumber), fieldClass + "::" +
fieldName, null);
}
} catch (Exception e) {
LOG.error("Error in read", e);
}
Expand Down
18 changes: 0 additions & 18 deletions jdcallgraph/src/main/java/com/dkarv/jdcallgraph/Tracer.java
Original file line number Diff line number Diff line change
Expand Up @@ -203,24 +203,6 @@ public static int getLineNumber(CtBehavior method) {

public static String getMethodName(CtBehavior method) throws NotFoundException {
return method.getName() + Descriptor.toString(method.getSignature());

/*
StringBuilder methodName = new StringBuilder();
// boolean isConstructor = method.getMethodInfo().isConstructor();
// TODO replace with method.getLongName()
methodName.append(method.getName());
methodName.append('(');
CtClass[] params = method.getParameterTypes();
for (int i = 0; i < params.length; i++) {
if (i != 0) {
methodName.append(',');
}
methodName.append(getShortName(params[i]));
}
methodName.append(')');
return methodName.toString();
*/
}

static String getShortName(final CtClass clazz) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,18 @@ public void returned(StackItem method) throws IOException {
}
}

public void dataEdge(StackItem from, StackItem to) throws IOException {
if (calls.isEmpty()) {
LOG.info("Ignore dd egde {} -> {}", from, to);
} else {
for (GraphWriter w : writers) {
if (w instanceof DotFileWriter || w instanceof RemoveDuplicatesWriter) {
w.edge(from, to, "[style=dotted]");
}
}
}
}

public void finish() throws IOException {
if (!calls.isEmpty()) {
LOG.error("Shutdown but call graph not empty: {}", calls);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/
package com.dkarv.jdcallgraph.data;

import com.dkarv.jdcallgraph.callgraph.*;
import com.dkarv.jdcallgraph.util.StackItem;
import com.dkarv.jdcallgraph.util.options.Target;
import com.dkarv.jdcallgraph.util.config.Config;
Expand All @@ -48,7 +49,7 @@ public class DataDependenceGraph {
public DataDependenceGraph(long threadId) throws IOException {
Target[] targets = Config.getInst().writeTo();
for (Target target : targets) {
if (target.isDataDependency()) {
if (target.isDataDependency() && target != Target.COMBINED_DOT) {
GraphWriter writer = createWriter(target);
writer.start(FOLDER + "data_" + threadId);
writers.add(writer);
Expand All @@ -75,7 +76,7 @@ public void addWrite(StackItem location, String field) throws IOException {
// }
}

public void addRead(StackItem location, String field) throws IOException {
public void addRead(StackItem location, String field, CallGraph callGraph) throws IOException {
LOG.trace("Read to {} from {}", field, location);
StackItem lastWrite = lastWrites.get(field);
if (lastWrite != null) {
Expand All @@ -85,6 +86,9 @@ public void addRead(StackItem location, String field) throws IOException {
for (GraphWriter writer : writers) {
writer.edge(lastWrite, location, field);
}
if (callGraph != null) {
callGraph.dataEdge(lastWrite, location);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,14 @@ public enum Target {
/**
* Data dependence graph as csv.
*/
DD_TRACE;
DD_TRACE,
/**
* Combined call and dd graph in dot file format.
*/
COMBINED_DOT;

public boolean isDataDependency() {
return this == Target.DD_DOT || this == Target.DD_TRACE;
return this == Target.DD_DOT || this == Target.DD_TRACE ||
this == Target.COMBINED_DOT;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,19 @@ public void edge(StackItem from, StackItem to) throws IOException {
}

@Override
public void edge(StackItem from, StackItem to, String label) throws IOException {
writer.append("\t\"" + from.toString() + "\" -> \"" + to.toString() + "\" [label=\"" + label + "\"];\n");
public void edge(StackItem from, StackItem to, String attributes) throws IOException {
writer.append('\t');
writer.append('"');
writer.append(from.toString());
writer.append('"');
writer.append(" -> ");
writer.append('"');
writer.append(to.toString());
writer.append('"');
writer.append(' ');
writer.append(attributes);
writer.append(';');
writer.append('\n');
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ public interface GraphWriter extends Closeable {
void edge(StackItem from, StackItem to) throws IOException;

/**
* Write an edge with a label. If the writer does not support labels it will write the edge without.
* Write an edge with additional attributes. If the writer does not support labels it will write
* the edge without. For dot files the attributes should look like [style=dotted, label="asdf"]
*/
void edge(StackItem from, StackItem to, String label) throws IOException;
void edge(StackItem from, StackItem to, String attributes) throws IOException;

/**
* Finish the graph.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import javassist.CtBehavior;
import javassist.CtClass;
import javassist.NotFoundException;
import javassist.bytecode.*;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
Expand Down Expand Up @@ -41,7 +42,8 @@ private String expected(String cName, String mName) {

@Test
public void testConstructor() throws NotFoundException, CannotCompileException {
Mockito.when(behavior.getLongName()).thenReturn("Example()");
Mockito.when(behavior.getName()).thenReturn("Example");
Mockito.when(behavior.getSignature()).thenReturn("()");

p.enhanceMethod(behavior, className);

Expand All @@ -52,19 +54,24 @@ public void testConstructor() throws NotFoundException, CannotCompileException {

@Test
public void testParameters() throws NotFoundException, CannotCompileException {
Mockito.when(behavior.getLongName()).thenReturn("method(String,int,byte)");
Mockito.when(behavior.getName()).thenReturn("method");
Mockito.when(behavior.getSignature()).thenReturn(
Descriptor.ofMethod(null,
new CtClass[]{CtClass.booleanType, CtClass.intType, CtClass.byteType}));

p.enhanceMethod(behavior, className);

ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
Mockito.verify(behavior).insertBefore(captor.capture());
Assert.assertEquals(expected(className, "method(String,int,byte)"), captor.getValue());
Assert.assertEquals(expected(className, "method(boolean,int,byte)"), captor.getValue());
}

@Test
@SuppressWarnings("unchecked")
public void testIsTest() throws NotFoundException, CannotCompileException, ClassNotFoundException {
Mockito.when(behavior.getLongName()).thenReturn("method()");
Mockito.when(behavior.getName()).thenReturn("method");
Mockito.when(behavior.getSignature()).thenReturn(
Descriptor.ofMethod(null, new CtClass[0]));

Annotation[] annotations = new Annotation[]{
Mockito.mock(Annotation.class, Mockito.RETURNS_DEEP_STUBS),
Expand Down

0 comments on commit 77c8838

Please sign in to comment.