Skip to content
EKnife.java 27.8 KiB
Newer Older
Carlos Galindo's avatar
Carlos Galindo committed
/*
 * e-Knife, a program slicing tool for Erlang based on the EDG
 * Copyright (c) 2021. David Insa, Sergio Pérez, Josep Silva, Salvador Tamarit.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

Carlos Galindo's avatar
Carlos Galindo committed
package eknife;

import edg.DotFactory;
import edg.EDGFactory;
Carlos Galindo's avatar
Carlos Galindo committed
import edg.PdfFactory;
import edg.constraint.AccessConstraint;
Carlos Galindo's avatar
Carlos Galindo committed
import edg.graph.EDG;
Sergio Pérez's avatar
Sergio Pérez committed
import edg.graph.Edge;
import edg.graph.LAST;
Carlos Galindo's avatar
Carlos Galindo committed
import edg.graph.Node;
Sergio Pérez's avatar
Sergio Pérez committed
import edg.slicing.*;
import eknife.erlang.ErlangCodeFactory;
Carlos Galindo's avatar
Carlos Galindo committed

import java.io.FileWriter;
import java.io.IOException;
Carlos Galindo's avatar
Carlos Galindo committed
import java.nio.file.Files;
import java.nio.file.Path;
Carlos Galindo's avatar
Carlos Galindo committed
import java.io.File;
Carlos Galindo's avatar
Carlos Galindo committed
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.lang.reflect.InvocationTargetException;
Carlos Galindo's avatar
Carlos Galindo committed

Carlos Galindo's avatar
Carlos Galindo committed
public class EKnife {
	public enum Language {Java, Erlang, Php}
Carlos Galindo's avatar
Carlos Galindo committed

Carlos Galindo's avatar
Carlos Galindo committed
	// TODO: OUTPUT FILES PATH

	// Graph Generation Time
	public static final String baseDir = "tabular_Evaluation/";
Carlos Galindo's avatar
Carlos Galindo committed
	public static final String outputTimeFolder = baseDir + "Times/";
	public static final String outputSizeFolder = baseDir + "Sizes/";
Carlos Galindo's avatar
Carlos Galindo committed
	public static final String sliceTimeFolder = outputTimeFolder + "Slices/";
	public static final String outputSliceGenerationFolder = baseDir + "Slices/";
Carlos Galindo's avatar
Carlos Galindo committed
	public static final String slicesFolder = "./ComputedSlices/";
Carlos Galindo's avatar
Carlos Galindo committed

	public static void main(String[] args) {
		if (args.length == 0) {
			EKnife.printHelp();
			return;
		}

Carlos Galindo's avatar
Carlos Galindo committed
		final Args arguments = EKnife.processArguments(args);

		if (!arguments.isValid()) {
			EKnife.printHelp();
			System.exit(3);
		}
		EKnife.run(arguments);
Carlos Galindo's avatar
Carlos Galindo committed
	}

Carlos Galindo's avatar
Carlos Galindo committed
	public static void generateAllSlices(String[] args, String setName) {
		if (args.length == 0) {
			EKnife.printHelp();
			return;
		}

		final Args arguments = EKnife.processArguments(args);

		if (!arguments.isValid()) {
			EKnife.printHelp();
			System.exit(3);
		}

		EKnife.sliceGenerationRun(arguments, setName);
	}

	public static void timedRun(String[] args, String setName) {

		if (args.length == 0) {
			EKnife.printHelp();
			return;
		}

		final Args arguments = EKnife.processArguments(args);

		if (!arguments.isValid()) {
			EKnife.printHelp();
			System.exit(3);
		}

		EKnife.timedRun(arguments,setName);
//		EKnife.SCCounter(arguments);
	}

	private static Args processArguments(String[] args) {
Carlos Galindo's avatar
Carlos Galindo committed
		Args kArgs = new Args();

Carlos Galindo's avatar
Carlos Galindo committed
		for (int argIndex = 0; argIndex < args.length; argIndex++) {
Carlos Galindo's avatar
Carlos Galindo committed
			final String arg = args[argIndex];

Carlos Galindo's avatar
Carlos Galindo committed
			switch (arg) {
				case "-i":
				case "--input":
				case "-o":
				case "--output":
				case "-f":
				case "--file":
				case "-l":
				case "--line":
				case "-v":
				case "--var":
				case "-n":
				case "--occurrence":
				case "-G":
				case "--print-graph":
Carlos Galindo's avatar
Carlos Galindo committed
					if (argIndex == args.length - 1) {
						System.out.printf("Parameter %s requires an argument\n", arg);
						printHelp();
						System.exit(1);
					}
Carlos Galindo's avatar
Carlos Galindo committed
			}
Carlos Galindo's avatar
Carlos Galindo committed
			switch (arg) {
Carlos Galindo's avatar
Carlos Galindo committed
				case "--help":
					printHelp();
					System.exit(0);
Carlos Galindo's avatar
Carlos Galindo committed
				case "-i":
				case "--input":
Carlos Galindo's avatar
Carlos Galindo committed
					kArgs.inputPath = args[argIndex + 1];
					break;
Carlos Galindo's avatar
Carlos Galindo committed
				case "-o":
				case "--output":
Carlos Galindo's avatar
Carlos Galindo committed
					kArgs.outputFile = new File(args[argIndex + 1]);
					break;
Carlos Galindo's avatar
Carlos Galindo committed
				case "-f":
				case "--file":
Carlos Galindo's avatar
Carlos Galindo committed
					kArgs.file = args[argIndex + 1];
					break;
Carlos Galindo's avatar
Carlos Galindo committed
				case "-l":
				case "--line":
Carlos Galindo's avatar
Carlos Galindo committed
					kArgs.line = Integer.parseInt(args[argIndex + 1]);
					break;
Carlos Galindo's avatar
Carlos Galindo committed
				case "-v":
				case "--var":
Carlos Galindo's avatar
Carlos Galindo committed
					kArgs.name = args[argIndex + 1];
					break;
Carlos Galindo's avatar
Carlos Galindo committed
				case "-n":
				case "--occurrence":
Carlos Galindo's avatar
Carlos Galindo committed
					kArgs.occurrence = Integer.parseInt(args[argIndex + 1]);
					break;
Carlos Galindo's avatar
Carlos Galindo committed
				case "-G":
				case "--print-graph":
Carlos Galindo's avatar
Carlos Galindo committed
					kArgs.setGraphFile(new File(args[argIndex + 1]));
					break;
				case "--ignore-constraints":
					kArgs.constrainedAlgorithm = false;
					break;
				case "--intraprocedural":
					kArgs.intraproceduralAlgorithm = true;
Carlos Galindo's avatar
Carlos Galindo committed
			}
		}

		kArgs.completeData();
		return kArgs;
	}
Carlos Galindo's avatar
Carlos Galindo committed

	private static void printHelp() {
Carlos Galindo's avatar
Carlos Galindo committed
		String help = "";

		help += "Use the following options:\n";
		help += "  -i,--input  <file/folder>   The file/folder where the source code is\n";
		help += "  -o,--output <file/folder>   The file/folder where the slice will be stored\n";
		help += "  -f,--file   <file>          The file (relative to -i) where the slicing criterion is\n";
		help += "  -l,--line   <num>           The line of the slicing criterion\n";
		help += "  -v,--var    <name>          The name of the slicing criterion (must be a variable)\n";
		help += "  -n,--occurrence <num>       The occurrence of the slicing criterion in that line\n";
		help += "  -G,--print-graph <file.dot> Exports the graph as a dot file\n";
		help += "  -G,--print-graph <file.pdf> Exports the graph as a PDF file\n";
		help += "  --ignore-constraints        Generates constraints but ignores when slicing\n";
		help += "  --intraprocedural           Makes the slice intraprocedural, the algorithm will not traverse function bounds\n";
Carlos Galindo's avatar
Carlos Galindo committed
		help += "  --help                      Show this message.\n";

		System.out.print(help);
	}

Carlos Galindo's avatar
Carlos Galindo committed
	private static void run(Args a) {
		final LAST last = LASTFactory.createLAST(Language.Erlang, a.inputPath, true);
		final EDG edg = new EDGFactory(last, !a.intraproceduralAlgorithm).createEDG();
Carlos Galindo's avatar
Carlos Galindo committed
		final SlicingCriterion slicingCriterion = new SlicingCriterion(a.file, a.line, a.name, a.occurrence);
		final Node SC;
			SC = edg.getNode(slicingCriterion);
			if (SC == null) {
				System.out.println("Error: the slicing criterion could not be found! " + slicingCriterion);
				System.exit(1);
			}
		} catch (IllegalArgumentException e) {
Carlos Galindo's avatar
Carlos Galindo committed
			System.out.println("Error: the slicing criterion could not be found! " + slicingCriterion);
			System.exit(1);
Carlos Galindo's avatar
Carlos Galindo committed
			return;
Carlos Galindo's avatar
Carlos Galindo committed
		}
		final SlicingAlgorithm slicingAlgorithm = a.getAlgorithm(edg);
		final Set<Node> slice = slicingAlgorithm.slice(SC);
Carlos Galindo's avatar
Carlos Galindo committed
		if (slice.isEmpty()) {
			System.out.println("Warning: no files will be written, as the slice is empty.");
			System.exit(2);
		}
Carlos Galindo's avatar
Carlos Galindo committed
		if (a.graphFile != null) {
			switch (a.graphFormat) {
				case DOT:
					DotFactory.createDot(a.graphFile, edg, SC, slice);
					break;
				case PDF:
					PdfFactory.createPdf(a.graphFile, edg, SC, slice);
					break;
			}
		}
Carlos Galindo's avatar
Carlos Galindo committed
		CodeFactory.createCode(Language.Erlang, a.outputFile, edg, slice);
	}

Carlos Galindo's avatar
Carlos Galindo committed
	/**
	 * Executes and measures time for graph generation and slicing according to measured dimensions
	 */
	private static void timedRun(Args a, String setName) {
Sergio Pérez's avatar
Sergio Pérez committed
		// CONFIGURE MEASURED DIMENSIONS
		boolean measureGenerationTime = false;
Sergio Pérez's avatar
Sergio Pérez committed
		boolean performAllSCs = true;
Carlos Galindo's avatar
Carlos Galindo committed
		boolean countSlices = true;
		boolean measureSlicingTime = true;
		boolean measureAccessConstraints = true;
		boolean outputSlice = true;
Sergio Pérez's avatar
Sergio Pérez committed
		/* ***************************************************** */
		/* ** MEASUREMENT OF GENERATION TIME (100 executions) ** */
		/* ***************************************************** */
		int numberOfIterationsGen = Integer.parseInt(System.getProperty("iterGen", "100"));
		int numberOfIterationsSlice = Integer.parseInt(System.getProperty("iterSlice", "1000"));
Sergio Pérez's avatar
Sergio Pérez committed

Carlos Galindo's avatar
Carlos Galindo committed
		// GET MODULE NAME:
		String moduleName = a.inputPath.lastIndexOf(File.separator) != -1 ?
				a.inputPath.substring(a.inputPath.lastIndexOf("/") + 1) : a.inputPath;
		moduleName = moduleName.lastIndexOf(".") != -1 ?
				moduleName.substring(0, moduleName.lastIndexOf(".")) : moduleName;
Sergio Pérez's avatar
Sergio Pérez committed

Carlos Galindo's avatar
Carlos Galindo committed
		// CREATE DIRECTORIES TO SAVE SLICES
		if (outputSlice)
			try {
				Files.createDirectories(Path.of(slicesFolder + moduleName +"/"));
			} catch (Exception e) {
				e.printStackTrace();
			}

		if (measureAccessConstraints) {
			LAST last = LASTFactory.createLAST(Language.Erlang, a.inputPath, true);
			EDG edg = new EDGFactory(last).createEDG();
			long accessConstraints = edg.edgeSet().stream()
					.filter(e -> e.getConstraint() instanceof AccessConstraint)
					.count();
			printAccessConstraint(setName, moduleName, accessConstraints);
		}

Carlos Galindo's avatar
Carlos Galindo committed
		if (measureGenerationTime) {
			double[] StructuralTime = new double[numberOfIterationsGen];
			double[] CFGTime = new double[numberOfIterationsGen];
			double[] ValueTime = new double[numberOfIterationsGen];
			double[] CompositeTime = new double[numberOfIterationsGen];
			double[] ControlTime = new double[numberOfIterationsGen];
			double[] FlowTime = new double[numberOfIterationsGen];
			double[] IPTime = new double[numberOfIterationsGen];
Sergio Pérez's avatar
Sergio Pérez committed

Carlos Galindo's avatar
Carlos Galindo committed
			double[] standardTime = new double[numberOfIterationsGen];
			double[] constrainedTime = new double[numberOfIterationsGen];
Sergio Pérez's avatar
Sergio Pérez committed

Carlos Galindo's avatar
Carlos Galindo committed
			for (int i = -1; i < numberOfIterationsGen; i++) {
Sergio Pérez's avatar
Sergio Pérez committed

				final LAST last = LASTFactory.createLAST(Language.Erlang, a.inputPath, true);
				final EDG edg = new EDGFactory(last).createEDG();

				if (i == -1)
					continue;

Sergio Pérez's avatar
Sergio Pérez committed
				StructuralTime[i] = edg.getGenerationTime().getStructureTime();
				CFGTime[i] = edg.getGenerationTime().getControlFlowTime();
				ValueTime[i] = edg.getGenerationTime().getValueTime();
				CompositeTime[i] = edg.getGenerationTime().getCompositeTime();
				ControlTime[i] = edg.getGenerationTime().getControlTime();
				FlowTime[i] = edg.getGenerationTime().getFlowTime();
				IPTime[i] = edg.getGenerationTime().getInterproceduralTime();
				standardTime[i] = StructuralTime[i] + CFGTime[i] + ValueTime[i] - CompositeTime[i]
						+ ControlTime[i] + FlowTime[i] + IPTime[i];
				constrainedTime[i] = StructuralTime[i] + CFGTime[i] + ValueTime[i]
						+ ControlTime[i] + FlowTime[i] + IPTime[i];
				// printArray("/Users/serperu/Desktop/SlicerOutput/Times/ArrayContent.txt",constrainedTime);
Sergio Pérez's avatar
Sergio Pérez committed
			}

Carlos Galindo's avatar
Carlos Galindo committed
			// Print RESULTS:
			try {

				new File(outputTimeFolder).mkdirs();

				File txtSDG = new File(outputTimeFolder + "graphGenerationPDG.txt");
				File txtEDG = new File(outputTimeFolder + "graphGenerationCE-PDG.txt");

				if (!txtSDG.exists())
					txtSDG.createNewFile();
				if (!txtEDG.exists())
					txtEDG.createNewFile();

				FileWriter fw = new FileWriter(txtSDG, true);
				for (int i = 0; i < numberOfIterationsGen; i++) {
					fw.append(moduleName + ";" + standardTime[i] + "\n");
				}
				fw.close();

				FileWriter fw2 = new FileWriter(txtEDG, true);
				for (int i = 0; i < numberOfIterationsGen; i++) {
					fw2.append(moduleName + ";" + constrainedTime[i] + "\n");
				}
				fw2.close();
			} catch (IOException e) {
				System.out.println("An error occurred.");
				e.printStackTrace();
			}


Sergio Pérez's avatar
Sergio Pérez committed
			// INTRAPROCEDURAL GENERATION TIME
			// TIME MEASSUREMENT:
Carlos Galindo's avatar
Carlos Galindo committed
			// printCSVGenerationTime(a.file, standardTime, constrainedTime);
Sergio Pérez's avatar
Sergio Pérez committed

Sergio Pérez's avatar
Sergio Pérez committed
		}

		final LAST last = LASTFactory.createLAST(Language.Erlang, a.inputPath, true);
		final EDG edg = new EDGFactory(last).createEDG();
Sergio Pérez's avatar
Sergio Pérez committed
		/* ************************ */
		/* ** MEASUREMENT OF SCs ** */
		/* ************************ */
Sergio Pérez's avatar
Sergio Pérez committed
		if (performAllSCs) {

			// SC SELECTION
			List<Node> clauses = edg.getNodes(Node.Type.Clause);
			clauses.removeIf(c -> edg.getParent(c).getType() != Node.Type.Routine);

Sergio Pérez's avatar
Sergio Pérez committed
			// printHeadings("/Users/serperu/Desktop/SlicerOutput/Times/slicingStatistics.txt", a.file);
			// Round 1: clear summaries right after slicing
Carlos Galindo's avatar
Carlos Galindo committed
			int scCounter = 0;
Sergio Pérez's avatar
Sergio Pérez committed
			for (Node clause : clauses) {
Sergio Pérez's avatar
Sergio Pérez committed
				int arity = edg.getChildrenNonResult(edg.getChild(clause, Node.Type.Parameters)).size();
				String functionName = edg.getParent(clause).getName() + "/" + arity;
Sergio Pérez's avatar
Sergio Pérez committed

Carlos Galindo's avatar
Carlos Galindo committed
				List<Node> resultNodes = extractSlicingCriteria(edg, clause, a.file);
Sergio Pérez's avatar
Sergio Pérez committed

				final SlicingAlgorithm constrainedAlgorithm = outputSlice || measureSlicingTime ? new ConstrainedAlgorithm(edg) : null;
				final CounterOnePassConstrainedAlgorithm counterAlgorithm = countSlices ? new CounterOnePassConstrainedAlgorithm(edg) : null;
Sergio Pérez's avatar
Sergio Pérez committed

				if (setName.equals("SetA")) {
Carlos Galindo's avatar
Carlos Galindo committed
					scCounter = 0;
Sergio Pérez's avatar
Sergio Pérez committed

				for (Node SC : resultNodes) {
					// INITIALIZATIONS
Carlos Galindo's avatar
Carlos Galindo committed
					double[] standardTime = new double[numberOfIterationsSlice];
					double[] constrainedTime = new double[numberOfIterationsSlice];
Sergio Pérez's avatar
Sergio Pérez committed

					if (outputSlice) {
						edg.clearState();
						Set<Node> ctdSlice = constrainedAlgorithm.slice(SC);
						ErlangCodeFactory.createErlangFile(new File(slicesFolder + moduleName + "/computed_" + scCounter + ".erl"), edg, ctdSlice);
Sergio Pérez's avatar
Sergio Pérez committed
					// MEASURE TIME FOR EACH SC
					if (measureSlicingTime) {
Carlos Galindo's avatar
Carlos Galindo committed
						for (int j = -1; j < numberOfIterationsSlice; j++) {
							edg.clearState();
							long initialConstrainedTime = System.nanoTime();
							constrainedAlgorithm.slice(SC);
							long finalConstrainedTime = System.nanoTime();
Sergio Pérez's avatar
Sergio Pérez committed

Sergio Pérez's avatar
Sergio Pérez committed
							if (j == -1)
								continue;

							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) {
Carlos Galindo's avatar
Carlos Galindo committed
						for (int j = -1; j < numberOfIterationsSlice; j++) {
							edg.getSummaryTable().clearStats();
Sergio Pérez's avatar
Sergio Pérez committed
							long initialConstrainedTime = System.nanoTime();
							constrainedAlgorithm.slice(SC);
							long finalConstrainedTime = System.nanoTime();

							if (j == -1)
								continue;

Carlos Galindo's avatar
Carlos Galindo committed
							constrainedTime[j] = (finalConstrainedTime - initialConstrainedTime) / 1000.0;
Sergio Pérez's avatar
Sergio Pérez committed
						}
Sergio Pérez's avatar
Sergio Pérez committed

						printEachSCData(setName + "_cached", moduleName, functionName, scCounter, constrainedTime, edg.getSummaryTable().cacheHits(), edg.getSummaryTable().hitRatio());
Sergio Pérez's avatar
Sergio Pérez committed
					}
					scCounter++;
				}
			}
		}
	}

Carlos Galindo's avatar
Carlos Galindo committed
	/** Extracts the possible SCs from a clause considering different factors commented inside the method body */
	public static List<Node> extractSlicingCriteria(EDG edg, Node clause, String fileName) {
		List<Node> descendants = edg.getDescendants(clause);
		descendants.add(clause);

		List<Node> resultNodes = new LinkedList<>();
		List<Node> nonResultNodes = new LinkedList<>();

		for (Node n : descendants)
			if (n.getType() == Node.Type.Result) {
				if (edg.getNodeFromRes(n).getType() != Node.Type.Callee)
					resultNodes.add(n);
			} else
				nonResultNodes.add(n);
		nonResultNodes.add(clause);
		resultNodes.add(edg.getResFromNode(clause));

		// IGNORE FUNCTIONS WITHOUT COMPOSITE STRUCTURES
		if (nonResultNodes.stream()
				.noneMatch(
						n -> {
							if (n.getType() == Node.Type.DataConstructor)
								return true;
							if (n.getType() == Node.Type.List)
								if (edg.getChildren(n).size() != 0 || edg.getParent(n).getType() == Node.Type.List)
									return true;
							return false;
						})) {
//			System.out.println("File Name: " + fileName);
//			int functionArity = edg.getChildrenNonResult(edg.getChild(clause, Node.Type.Parameters)).size();
//			System.out.println("Function " + edg.getParent(clause).getName() + "/" + functionArity + " has no valid slicing criteria.");
			return new LinkedList<>();
		}

		/* FILTER SC NODES BY A CRITERION (CONSIDER ONLY VARIABLES) */
		resultNodes.removeIf(n -> edg.getNodeFromRes(n).getType() != Node.Type.Variable);
		/* REMOVE NODES GENERATED BY HIGH ORDER FUNS (e.g., fun g/2) */
		resultNodes.removeIf(n -> edg.getAncestor(n, Node.Type.AnonymousRoutine) != null &&
				edg.getNodeFromRes(n).getName().startsWith("FreshVar"));
		/* REMOVE DEAD CODE FROM BEING SLICING CRITERIA */
		resultNodes.removeIf(n -> edg.incomingEdgesOf(edg.getNodeFromRes(n)).stream().noneMatch(Edge::isControlFlowEdge));

		return resultNodes;
	}

	/** Generates the slice and store it for all possible slicing criteria */
	private static void sliceGenerationRun(Args a, String setName)
	{

		final LAST last = LASTFactory.createLAST(Language.Erlang, a.inputPath, true);
		final EDG edg = new EDGFactory(last).createEDG();

		int scFunctionCounter = 0;
		/* ************************ */
		/* ** MEASUREMENT OF SCs ** */
		/* ************************ */
		// SC SELECTION
		List<Node> clauses = edg.getNodes(Node.Type.Clause);
		clauses.removeIf(c -> edg.getParent(c).getType() != Node.Type.Routine);

		for (Node clause : clauses) {
			Map<String,String> functionCriteria = new HashMap<>();
			List<Node> descendants = edg.getDescendants(clause);
			descendants.add(clause);

Carlos Galindo's avatar
Carlos Galindo committed
			List<Node> resultNodes = extractSlicingCriteria(edg,clause,a.file);
Carlos Galindo's avatar
Carlos Galindo committed
			int arity = edg.getChildrenNonResult(edg.getChild(clause, Node.Type.Parameters)).size();
			String functionName = edg.getParent(clause).getName() + "-" + arity;
			String moduleName = edg.getParent(edg.getParent(clause)).getName();
Carlos Galindo's avatar
Carlos Galindo committed
			moduleName = setName.equals("SetA") ? setName+"/"+moduleName + "-" + functionName : setName+"/"+moduleName;
Carlos Galindo's avatar
Carlos Galindo committed
			if (!resultNodes.isEmpty())
				new File(outputSliceGenerationFolder + moduleName).mkdirs();
Carlos Galindo's avatar
Carlos Galindo committed
			final SlicingAlgorithm standardAlgorithm = new AdaptedStandardAlgorithm(edg);
			final SlicingAlgorithm constrainedAlgorithm = new OnePassConstrainedAlgorithm(edg); // WITH LOOPS

			if(setName.equals("SetA"))
				scFunctionCounter = 0;
			for (Node SC : resultNodes) {
				Node normalNodeSC = edg.getNodeFromRes(SC);
				String scString = "<"+normalNodeSC.getInfo().getLine()+","+normalNodeSC.getName()+">";
				functionCriteria.put("#"+scFunctionCounter,scString);
				// MEASURE PERFORMARNCE
				final Set<Node> standardSlice = standardAlgorithm.slice(SC);
Carlos Galindo's avatar
Carlos Galindo committed
				final Set<Node> constrainedSlice = constrainedAlgorithm.slice(SC);

				if (constrainedSlice.size() > standardSlice.size())
					throw new RuntimeException("The CE-PDG slice cannot be greater than the PDG slice");
				// PDG PRINT
				CodeFactory.createCode(Language.Erlang,
Carlos Galindo's avatar
Carlos Galindo committed
						new File(outputSliceGenerationFolder+moduleName+"/PDG"+"#"+scFunctionCounter+".erl"),
Carlos Galindo's avatar
Carlos Galindo committed
				CodeFactory.createCode(Language.Erlang,
						new File(outputSliceGenerationFolder+moduleName+"/CE-PDG"+"#"+scFunctionCounter+".erl"),
						edg, constrainedSlice);
Carlos Galindo's avatar
Carlos Galindo committed
			if (scFunctionCounter > 0) {
Carlos Galindo's avatar
Carlos Galindo committed
					File txt = new File(outputSliceGenerationFolder + moduleName + "/criteria_map.txt");
Carlos Galindo's avatar
Carlos Galindo committed
					FileWriter fw = new FileWriter(txt, true);
					for (String k : functionCriteria.keySet()) {
						fw.append(k + " => " + functionCriteria.get(k) + "\n");
					}
					fw.close();
				} catch (IOException e) {
					System.out.println("An error occurred.");
					e.printStackTrace();
				}
Carlos Galindo's avatar
Carlos Galindo committed
			}
Carlos Galindo's avatar
Carlos Galindo committed
	/** Method to count the number of SCs in each program or pair program-function */
	public static void SCCounter(Args a) {
		final LAST last = LASTFactory.createLAST(Language.Erlang, a.inputPath, true);
		final EDG edg = new EDGFactory(last).createEDG();
Carlos Galindo's avatar
Carlos Galindo committed
		// SC SELECTION
		List<Node> clauses = edg.getNodes(Node.Type.Clause);
		clauses.removeIf(c -> edg.getParent(c).getType() != Node.Type.Routine);
		int scFunctionCounter = 0;
		for (Node clause : clauses) {

			Map<String,String> functionCriteria = new HashMap<>();
Sergio Pérez's avatar
Sergio Pérez committed

Carlos Galindo's avatar
Carlos Galindo committed
			int arity = edg.getChildrenNonResult(edg.getChild(clause, Node.Type.Parameters)).size();
			String functionName = edg.getParent(clause).getName() + "-" + arity;
			String moduleName = edg.getParent(edg.getParent(clause)).getName();


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

			for (Node SC : resultNodes ){
				Node normalNodeSC = edg.getNodeFromRes(SC);
				String scString = "<"+normalNodeSC.getInfo().getLine()+","+normalNodeSC.getName()+">";
				functionCriteria.put("#"+scFunctionCounter,scString);
				scFunctionCounter++;
			}
//
//			Map<String,String> functionCriteriaIncomplete = new HashMap<>();
//			Map<String,String> InversefunctionCriteriaIncomplete = new HashMap<>();
//			List<Node> resultNodesIncomplete = extractSlicingCriteriaIncomplete(edg,clause,a.file);
//
//			for (Node SC : resultNodesIncomplete ){
//				Node normalNodeSC = edg.getNodeFromRes(SC);
//				String scString = "<"+normalNodeSC.getInfo().getLine()+","+normalNodeSC.getName()+">";
//				functionCriteriaIncomplete.put("#"+scFunctionCounterIncomplete,scString);
//				InversefunctionCriteriaIncomplete.put(scString,"#"+scFunctionCounterIncomplete);
//				scFunctionCounterIncomplete++;
//			}
//
//			Collection<String> okValues = functionCriteria.values();
//
//			for (String s : functionCriteriaIncomplete.values()) {
//				if (!okValues.contains(s)) {
//					System.out.println("Benchmark"+moduleName+"_"+functionName+"Remove SC "+InversefunctionCriteriaIncomplete.get(s)+" => "+s);
//				}
//			}

			try {
				new File(outputSliceGenerationFolder+"SlicingCriteriaMaps/"+moduleName+"/").mkdirs();
				File txt = new File(outputSliceGenerationFolder+"SlicingCriteriaMaps/"+moduleName+"/criteria.txt");
				txt.createNewFile();
				FileWriter fw = new FileWriter(txt,true);
				for(String k : functionCriteria.keySet()){
					fw.append(k +" => "+ functionCriteria.get(k)+"\n");
				}
				fw.close();
			} catch (IOException e) {
				System.out.println("An error occurred.");
				e.printStackTrace();
Sergio Pérez's avatar
Sergio Pérez committed
			}
		}
Carlos Galindo's avatar
Carlos Galindo committed
		System.out.println("\tBenchmark: "+ a.file + " => " + scFunctionCounter +" SCs");
Sergio Pérez's avatar
Sergio Pérez committed
	}

Sergio Pérez's avatar
Sergio Pérez committed
	/* *********************** *********************** *********************** *********************** */
	/* *********************** ****************** PRINT METHODS ************** *********************** */
	/* *********************** *********************** *********************** *********************** */
	public static void printEachSCData(String setName, String file, String funName, int iteration, double[] consTime, int cacheHits, double hitRatio) {
Carlos Galindo's avatar
Carlos Galindo committed
		new File(sliceTimeFolder + setName + "/").mkdirs();
		File outputFile = new File(sliceTimeFolder + setName + "/" + file + ".txt");
Sergio Pérez's avatar
Sergio Pérez committed

		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");
Sergio Pérez's avatar
Sergio Pérez committed
			}
Carlos Galindo's avatar
Carlos Galindo committed
			timeFileWriter.close();
Sergio Pérez's avatar
Sergio Pérez committed

		} catch (IOException e) {
			System.out.println("FILE NOT FOUND ERROR");
		}
	}

	public static void printPrecisionData(String setName, String file, String funName, int iteration, Set<Node> stdSlice, Set<Node> ctdSlice, int ctdArcs) {
		new File(outputSizeFolder + setName + "/").mkdirs();
		try (FileWriter out = new FileWriter(outputSizeFolder + setName + "/sizes.txt", true)) {
			out.write(String.format("%s;%s;#%d;%d;%d;%d\n", file, funName, iteration, stdSlice.size(), ctdSlice.size(), ctdArcs));
		} catch (IOException e) {
			System.out.println("FILE NOT FOUND ERROR");
		}
	}

	public static void printAccessConstraint(String setName, String file, long count) {
		new File(outputSizeFolder + setName + "/").mkdirs();
		try (FileWriter out = new FileWriter(outputSizeFolder + setName + "/accessConstraints.txt", true)) {
			out.write(String.format("%s;%d\n", file, count));
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

Sergio Pérez's avatar
Sergio Pérez committed
	/* *********************** *********************** *********************** *********************** */
	/* *********************** *********************** *********************** *********************** */
	/* *********************** *********************** *********************** *********************** */

Carlos Galindo's avatar
Carlos Galindo committed
	static class Args {
Carlos Galindo's avatar
Carlos Galindo committed
		enum GraphFormat { PDF, DOT }

Carlos Galindo's avatar
Carlos Galindo committed
		String inputPath;
		File outputFile;
		String file;
		int line;
		String name;
		int occurrence = 1;
Carlos Galindo's avatar
Carlos Galindo committed
		File graphFile;
		GraphFormat graphFormat;
		boolean intraproceduralAlgorithm = false;
		boolean constrainedAlgorithm = true;
		Class<? extends SlicingAlgorithm> algClass;
Carlos Galindo's avatar
Carlos Galindo committed

		void setGraphFile(File graphFile) {
			if (graphFile.getName().endsWith(".dot"))
				graphFormat = GraphFormat.DOT;
			else if (graphFile.getName().endsWith(".pdf"))
				graphFormat = GraphFormat.PDF;
			else {
				System.out.println("The graph file must end in .dot or .pdf, you set it to " + graphFile);
				System.exit(1);
			}
			this.graphFile = graphFile;
		}
Carlos Galindo's avatar
Carlos Galindo committed

		void completeData() {
			if (file == null && inputPath != null && new File(inputPath).isFile())
				file = new File(inputPath).getName();
			if (intraproceduralAlgorithm)
				algClass = constrainedAlgorithm ? OnePassConstrainedAlgorithm.class : AdaptedStandardAlgorithm.class;
			else algClass = constrainedAlgorithm ? ConstrainedAlgorithm.class : StandardAlgorithm.class;
Carlos Galindo's avatar
Carlos Galindo committed
		}

		boolean isValid() {
			List<String> errors = new LinkedList<>();
			if (inputPath == null)
				errors.add("You must specify a file to analyze with '-i'.");
			else if (!new File(inputPath).exists())
				errors.add("The input file you've specified does not exist or isn't readable(" + inputPath + ").");
			else if (file == null)
				errors.add("The input file is a folder, so you must specify a the file that contains the slicing criterion with '-f'.");
			if (outputFile == null)
				errors.add("You must specify a location for the output with '-o'.");
			else if (!outputFile.exists() && !outputFile.getAbsoluteFile().getParentFile().isDirectory())
				errors.add("The output file's parent folder does not exist, or the output folder does not exist.");
			if (line <= 0)
				errors.add("You must specify a line number greater than 0 with '-l'.");
			if (name == null || name.isEmpty())
				errors.add("You must specify a valid variable name with '-v'.");
			if (occurrence <= 0)
				errors.add("You must specify an occurrence greater than 0 with '-n'.");
			for (String error : errors)
				System.out.println(error);
			return errors.isEmpty();
Carlos Galindo's avatar
Carlos Galindo committed
		}

		SlicingAlgorithm getAlgorithm(EDG edg) {
			try {
				return algClass.getConstructor(EDG.class).newInstance(edg);
			} catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
				throw new RuntimeException(e);
			}
		}
Carlos Galindo's avatar
Carlos Galindo committed
	}
Sergio Pérez's avatar
Sergio Pérez committed

Sergio Pérez's avatar
Sergio Pérez committed
	public static class SlicingCriterionState{
Sergio Pérez's avatar
Sergio Pérez committed
		private final double slicingPerformance;
		private final double slicingTime;

		public SlicingCriterionState(double performance, double time) {
			slicingPerformance = performance;
			slicingTime = time;
		}
		public double getPerformance() { return this.slicingPerformance; }
		public double getTime() { return this.slicingTime; }
	}
Carlos Galindo's avatar
Carlos Galindo committed
}