package cmu.utils; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import cmu.conditional.Conditional; import de.fosd.typechef.featureexpr.FeatureExpr; import de.fosd.typechef.featureexpr.FeatureExprFactory; import de.ovgu.log.LOGGER; /** * Compares the traces of the variability-aware approach with brute force. Brute * force traces have to be at a trace file in /traces * * @author Jens Meinicke * */ public class TraceComparator { private static Set<FeatureExpr> falseCtx = new HashSet<>(); private static Set<FeatureExpr> validCtx = new HashSet<>(); private static String lastInstruction; /** * Contains all instructions of the variability-aware approach. */ private static final List<Tuple<FeatureExpr, String>> trace = new ArrayList<>(10_000_000); private static final Set<FeatureExpr> buffer = new HashSet<>(); public static void putInstruction(final FeatureExpr ctx, final String instr) { FeatureExpr useCtx = ctx; if (buffer.contains(ctx)) { for (FeatureExpr bufferCtx : buffer) { if (bufferCtx.equivalentTo(ctx)) { useCtx = bufferCtx; break; } } } else { buffer.add(ctx); } trace.add(new Tuple<>(useCtx, instr.intern())); } public static void compare() { System.out.println("=============================================="); System.out.println("COMPARE"); System.out.println("=============================================="); File traceFolder = new File("traces"); if (!traceFolder.exists()) { LOGGER.logError("no trace folder found!"); return; } try { for (File child : traceFolder.listFiles()) { String fileName = child.getName(); System.out.println("Compare traces of " + fileName); boolean error = false; try (BufferedReader reader = new BufferedReader(new FileReader(child))) { final FeatureExpr ctx = createFeatureExpr(reader.readLine()); if (ctx == null) { LOGGER.logError("No configuration"); continue; } System.out.println("Configuration: " + ctx); System.out.println("==================================="); int vaIndex = 0; int bfIndex = 0; String expected = ""; while (true) { expected = reader.readLine(); if (expected == null) { break; } if (expected.isEmpty()) { continue; } while (true) { // skip invalid instructions FeatureExpr next = trace.get(vaIndex).x; if (falseCtx.contains(next)) { vaIndex++; continue; } if (validCtx.contains(next)) { break; } if (Conditional.isContradiction(next.and(ctx))) { falseCtx.add(next); vaIndex++; continue; } validCtx.add(next); break; } String va = trace.get(vaIndex).y; String nomalizedVA = removeLine(va); String normalizedExpected = removeLine(expected); if (!nomalizedVA.equals(normalizedExpected)) { if (nomalizedVA.startsWith("SET FILED") && normalizedExpected.startsWith("SET FILED")) { System.out.println(); LOGGER.log(LOGGER.COLOR.YELLOW, "================WARNING=================="); LOGGER.log(LOGGER.COLOR.YELLOW, lastInstruction); LOGGER.log(LOGGER.COLOR.YELLOW, "Line: " + bfIndex); LOGGER.log(LOGGER.COLOR.YELLOW, "Expected: " + expected); LOGGER.log(LOGGER.COLOR.YELLOW, "But was: " + va + " " + trace.get(vaIndex).x); LOGGER.log(LOGGER.COLOR.YELLOW, "========================================="); } else { System.out.println(lastInstruction); LOGGER.log(LOGGER.COLOR.YELLOW, "================WARNING=============="); LOGGER.log(LOGGER.COLOR.YELLOW, bfIndex); LOGGER.log(LOGGER.COLOR.YELLOW, "Expected: " + expected); LOGGER.log(LOGGER.COLOR.YELLOW, "But was: " + va + " " + trace.get(vaIndex).x); LOGGER.log(LOGGER.COLOR.YELLOW, "Line does NOT match! Skipped one line for brute force."); LOGGER.log(LOGGER.COLOR.YELLOW, "==================================="); if (error) { break; } error = true; bfIndex++; continue; } } else { error = false; lastInstruction = bfIndex + " " + expected + " | " + va + " " + trace.get(vaIndex).x; } vaIndex++; bfIndex++; } if (!error) { String instructions = toSeparatedNumber(bfIndex); LOGGER.log(LOGGER.COLOR.GREEN, "Traces match! (" + instructions + " instructions)"); System.out.println("==================================="); } else { LOGGER.logError("Traces do not match!"); System.out.println("==================================="); } } falseCtx.clear(); validCtx.clear(); } } catch (IOException e) { e.printStackTrace(); } } private static String toSeparatedNumber(int bfIndex) { String number = ""; while (bfIndex > 1000) { number = "." + addZeros(bfIndex % 1000) + number; bfIndex = bfIndex / 1000; } return bfIndex + number; } private static String addZeros(int number) { if (number < 10) { return "00" + number; } if (number < 100) { return "0" + number; } return number + ""; } private static String removeLine(String va) { return va.split("[:]")[0]; } private static FeatureExpr createFeatureExpr(String content) { if (content == null) { return null; } String[] features = content.split("[&]"); FeatureExpr ctx = FeatureExprFactory.True(); for (String f : features) { boolean selection = !f.startsWith("!"); FeatureExpr feature = FeatureExprFactory.createDefinedExternal("CONFIG_" + f.replace("!", "")); if (selection) { ctx = ctx.and(feature); } else { ctx = ctx.andNot(feature); } } return ctx; } static class Tuple<X, Y> { final X x; final Y y; Tuple(X x, Y y) { this.x = x; this.y = y; } @Override public String toString() { return x.toString() + " " + y.toString(); } } public static void clear() { trace.clear(); buffer.clear(); } }