Commit 4d630beb authored by Carlos Galindo's avatar Carlos Galindo
Browse files

Benchmarks for non-recursive tabular slicing.

- ️️SummaryTable: actual-out node may none or multiple matching formal-out.
- EDG, SummaryTable: get and clear methods for stats.
- EKnife, BencherTest: adapted for benchmarks in which running the benchmark alters the graph itself.
parent 830c6df6
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -37,6 +37,18 @@ public class EDG extends LAST {
		return summaryTable.get(actualOut, stack);
	}

	public SummaryTable getSummaryTable() {
		return summaryTable;
	}

	/**
	 * Clears any modifications made by slicing traversals over this graph.
	 * This method is mainly used for benchmarking.
	 */
	public void clearState() {
		summaryTable.clearTable();
	}

	// ================================================= //
	// ===================== NODES ===================== //
	// ================================================= //
+32 −9
Original line number Diff line number Diff line
@@ -26,10 +26,19 @@ public class SummaryTable {
    }

    public List<Value> get(Node actualOut, Constraints stack) {
        Node formalOut = locateFormalOut(actualOut);
        List<Node> formalOuts = locateFormalOut(actualOut);
        List<Value> res = new LinkedList<>();
        for (Node formalOut : formalOuts) {
            Key key = new Key(formalOut, stack);
        if (map.containsKey(key)) cacheHits++; else misses++;
        return locateActualIns(map.computeIfAbsent(key, this::computeSummaries), actualOut);
            if (map.containsKey(key)) {
                cacheHits++;
            } else {
                misses++;
                map.put(key, computeSummaries(key));
            }
            res.addAll(locateActualIns(map.get(key), actualOut));
        }
        return res;
    }

    private List<Value> computeSummaries(Key key) {
@@ -97,12 +106,9 @@ public class SummaryTable {
    /**
     * Locates the formal-out node that corresponds to the given actual-out node.
     */
    private Node locateFormalOut(Node actualOut) {
    private List<Node> locateFormalOut(Node actualOut) {
        List<Node> nodes = edg.getNodes(actualOut, LAST.Direction.Backwards, Edge.Type.Output);
        if (nodes.size() != 1)
            throw new IllegalStateException(String.format("Actual-out node %d has %d matching formal-out",
                    actualOut.getId(), nodes.size()));
        return nodes.get(0);
        return nodes;
    }

    /**
@@ -126,6 +132,23 @@ public class SummaryTable {
        return res;
    }

    public double hitRatio() {
        return cacheHits / (double) (cacheHits + misses);
    }

    public int cacheHits() {
        return cacheHits;
    }

    public void clearTable() {
        map.clear();
        cacheHits = misses = 0;
    }

    public void clearStats() {
        cacheHits = misses = 0;
    }

    private static class Key {
        protected final Node formalOut;
        protected final Constraints stack;
+2 −2
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@ import java.util.function.Supplier;

public class BencherTest {

    private static String TEST_PKG = "erlsom";
    private static String TEST_PKG = "terminating-bench";
    private static final String TEST_PKG_INTRA = "bencher_intraprocedural";
    private static final String DOT_ERLANG = ".erl";
    private static final String EDG_OUTPUT_SLICE = ".edg.slice.output";
@@ -51,7 +51,7 @@ public class BencherTest {
    public static void main(String[] args) {
//        TEST_PKG = "SetA";
//        TEST_PKG = "SetB";
        File testFolder = new File("./e-Knife/src/test/resources/PaperExperiments/", TEST_PKG);
        File testFolder = new File("./", TEST_PKG);
        findFiles(testFolder, DOT_ERLANG, file -> {
            File outputDir = testFolder.getAbsoluteFile();

+68 −35
Original line number Diff line number Diff line
@@ -46,7 +46,7 @@ public class EKnife {
	// TODO: OUTPUT FILES PATH

	// Graph Generation Time
	public static final String baseDir = "JSS_Empirical_Evaluation/";
	public static final String baseDir = "tabular_Evaluation/";
	public static final String outputTimeFolder = baseDir + "Times/";
	public static final String outputSizeFolder = baseDir + "Sizes/";
	public static final String sliceTimeFolder = outputTimeFolder + "Slices/";
@@ -237,12 +237,12 @@ public class EKnife {
	 */
	private static void timedRun(Args a, String setName) {
		// CONFIGURE MEASURED DIMENSIONS
		boolean measureGenerationTime = true;
		boolean measureGenerationTime = false;
		boolean performAllSCs = true;
		boolean countSlices = true;
		boolean measureSlicingTime = true;
		boolean measureAccessConstraints = true;
		boolean outputSlice = false;
		boolean outputSlice = true;
		/* ***************************************************** */
		/* ** MEASUREMENT OF GENERATION TIME (100 executions) ** */
		/* ***************************************************** */
@@ -354,6 +354,7 @@ public class EKnife {
			clauses.removeIf(c -> edg.getParent(c).getType() != Node.Type.Routine);

			// printHeadings("/Users/serperu/Desktop/SlicerOutput/Times/slicingStatistics.txt", a.file);
			// Round 1: clear summaries right after slicing
			int scCounter = 0;
			for (Node clause : clauses) {
				int arity = edg.getChildrenNonResult(edg.getChild(clause, Node.Type.Parameters)).size();
@@ -361,47 +362,83 @@ public class EKnife {

				List<Node> resultNodes = extractSlicingCriteria(edg, clause, a.file);

				final SlicingAlgorithm standardAlgorithm = new AdaptedStandardAlgorithm(edg);
				final SlicingAlgorithm constrainedAlgorithm = outputSlice || measureSlicingTime ? new OnePassConstrainedAlgorithm(edg) : null;
				final SlicingAlgorithm constrainedAlgorithm = outputSlice || measureSlicingTime ? new ConstrainedAlgorithm(edg) : null;
				final CounterOnePassConstrainedAlgorithm counterAlgorithm = countSlices ? new CounterOnePassConstrainedAlgorithm(edg) : null;

				if (setName.equals("SetA"))
				if (setName.equals("SetA")) {
					scCounter = 0;
				}

				for (Node SC : resultNodes) {
					// INITIALIZATIONS
					double[] standardTime = new double[numberOfIterationsSlice];
					double[] constrainedTime = new double[numberOfIterationsSlice];

					// MEASURE SIZE OF SLICE
					if (countSlices) {
						Set<Node> stdSlice = standardAlgorithm.slice(SC);
						Set<Node> ctdSlice = counterAlgorithm.slice(SC);
						printPrecisionData(setName, moduleName, functionName, scCounter, stdSlice, ctdSlice,
								counterAlgorithm.getVisitedAccessCons());
					}

					if (outputSlice) {
						Set<Node> stdSlice = standardAlgorithm.slice(SC);
						edg.clearState();
						Set<Node> ctdSlice = constrainedAlgorithm.slice(SC);
						ErlangCodeFactory.createErlangFile(new File(slicesFolder + moduleName +"/PDG_" + scCounter + ".erl"), edg, stdSlice);
						ErlangCodeFactory.createErlangFile(new File(slicesFolder + moduleName +"/CE-PDG_" + scCounter + ".erl"), edg, ctdSlice);
						ErlangCodeFactory.createErlangFile(new File(slicesFolder + moduleName + "/computed_" + scCounter + ".erl"), edg, ctdSlice);
					}

					// MEASURE TIME FOR EACH SC
					if (measureSlicingTime) {
						for (int j = -1; j < numberOfIterationsSlice; j++) {
							long initialStandardTime = System.nanoTime();
							standardAlgorithm.slice(SC);
							long finalStandardTime = System.nanoTime();
							edg.clearState();
							long initialConstrainedTime = System.nanoTime();
							constrainedAlgorithm.slice(SC);
							long finalConstrainedTime = System.nanoTime();

							if (j == -1)
								continue;

							standardTime[j] = (finalStandardTime - initialStandardTime) / 1000.0;
							constrainedTime[j] = (finalConstrainedTime - initialConstrainedTime) / 1000.0;
						}

						printEachSCData(setName + "_computed", moduleName, functionName, scCounter, constrainedTime, edg.getSummaryTable().cacheHits(), edg.getSummaryTable().hitRatio());
					}
					scCounter++;
				}
			}
			{ // Round 2: run all SCs to populate edg.summaryTable
				ConstrainedAlgorithm constrainedAlgorithm = new ConstrainedAlgorithm(edg);
				double[] constrainedTime = new double[numberOfIterationsSlice];
				List<Node> SCs = new LinkedList<>();
				for (Node clause : clauses)
					SCs.addAll(extractSlicingCriteria(edg, clause, a.file));
				// Measure the time taken to compute all slices in a given benchmark.
				for (int j = -1; j < numberOfIterationsSlice; j++) {
					edg.clearState();
					long initialConstrainedTime = System.nanoTime();
					for (Node SC : SCs)
						constrainedAlgorithm.slice(SC);
					long finalConstrainedTime = System.nanoTime();
					if (j == -1) {
						continue;
					}
					constrainedTime[j] = (finalConstrainedTime - initialConstrainedTime) / 1000.0;
				}
				printEachSCData(setName + "_incremental", moduleName, "all/0", SCs.size(), constrainedTime, edg.getSummaryTable().cacheHits(), edg.getSummaryTable().hitRatio());
			}
			// Round 3: run all benchmarks once the cache is as full as can be.
			scCounter = 0;
			for (Node clause : clauses) {
				int arity = edg.getChildrenNonResult(edg.getChild(clause, Node.Type.Parameters)).size();
				String functionName = edg.getParent(clause).getName() + "/" + arity;
				List<Node> resultNodes = extractSlicingCriteria(edg, clause, a.file);
				final SlicingAlgorithm constrainedAlgorithm = new ConstrainedAlgorithm(edg);
				for (Node SC : resultNodes) {
					// INITIALIZATIONS
					double[] constrainedTime = new double[numberOfIterationsSlice];

					if (outputSlice) {
						Set<Node> ctdSlice = constrainedAlgorithm.slice(SC);
						ErlangCodeFactory.createErlangFile(new File(slicesFolder + moduleName +"/cached_" + scCounter + ".erl"), edg, ctdSlice);
					}

					// MEASURE TIME FOR EACH SC
					if (measureSlicingTime) {
						for (int j = -1; j < numberOfIterationsSlice; j++) {
							edg.getSummaryTable().clearStats();
							long initialConstrainedTime = System.nanoTime();
							constrainedAlgorithm.slice(SC);
							long finalConstrainedTime = System.nanoTime();
@@ -412,7 +449,7 @@ public class EKnife {
							constrainedTime[j] = (finalConstrainedTime - initialConstrainedTime) / 1000.0;
						}

						printEachSCData(setName, moduleName, functionName, scCounter, standardTime, constrainedTime);
						printEachSCData(setName + "_cached", moduleName, functionName, scCounter, constrainedTime, edg.getSummaryTable().cacheHits(), edg.getSummaryTable().hitRatio());
					}
					scCounter++;
				}
@@ -613,22 +650,18 @@ public class EKnife {
	/* *********************** *********************** *********************** *********************** */
	/* *********************** ****************** PRINT METHODS ************** *********************** */
	/* *********************** *********************** *********************** *********************** */
	public static void printEachSCData(String setName, String file, String funName, int iteration,double[] stdTime, double[] consTime) {

	public static void printEachSCData(String setName, String file, String funName, int iteration, double[] consTime, int cacheHits, double hitRatio) {
		new File(sliceTimeFolder + setName + "/").mkdirs();
		File outputFile = new File(sliceTimeFolder + setName + "/" + file + ".txt");

		FileWriter timeFileWriter;
		int numberOfElems = stdTime.length;
		try {
			if (!outputFile.exists())
				outputFile.createNewFile();

			timeFileWriter = new FileWriter(outputFile, true);

			// FILE; FunName; #SC; StandardTIME; ConstrainedTIME => ROW FORMAT
			for (int i = 0; i < numberOfElems; i++) {
				timeFileWriter.append(file + ";" + funName + ";" + "#"+ iteration + ";" + stdTime[i] + ";" + consTime[i] + "\n");
		try (FileWriter timeFileWriter = new FileWriter(outputFile, true)) {
			// FILE, FunName, #SC, ConstrainedTIME, cacheHits, hitRatio => ROW FORMAT
			for (double v : consTime) {
				timeFileWriter.append(file).append(',').append(funName).append(',')
						.append('#').append(String.valueOf(iteration)).append(',')
						.append(String.valueOf(v)).append(',')
						.append(String.valueOf(cacheHits)).append(',')
						.append(String.valueOf(hitRatio)).append("\n");
			}
			timeFileWriter.close();