package fr.inria.diversify.diversification; import fr.inria.diversify.statistic.RunResults; import fr.inria.diversify.statistic.SessionResults; import fr.inria.diversify.transformation.Transformation; import fr.inria.diversify.transformation.query.KnownSosieQuery; import fr.inria.diversify.transformation.query.QueryException; import fr.inria.diversify.transformation.query.SeveralTriesUnsuccessful; import fr.inria.diversify.transformation.query.TransformationQuery; import fr.inria.diversify.util.Log; import org.json.JSONException; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; /** * User: Simon * Date: 5/2/13 * Time: 5:39 PM */ public class Diversify extends AbstractDiversify { // /** // * Session report // */ // protected SessionResults sessionResults; /** * Number of compiled errors. TODO: This info is already in SessionResults */ protected int compileError = 0; /** * Number of sosies found */ protected int sosie = 0; private boolean earlyReport = false; private boolean earlyReportSosiesOnly = false; /** * Indicates if we must early report sosies only */ public boolean getEarlyReportSosiesOnly() { return earlyReportSosiesOnly; } public void setEarlyReportSosiesOnly(boolean earlyReportSosiesOnly) { this.earlyReportSosiesOnly = earlyReportSosiesOnly; } /** * Reports results on every step. Slower, but allows to stop the process without * loosing all the information */ public boolean getEarlyReport() { return earlyReport; } public void setEarlyReport(boolean earlyReport) { this.earlyReport = earlyReport; } public Diversify(InputConfiguration inputConfiguration, TransformationQuery transQuery, String projectDir) { this.transQuery = transQuery; this.projectDir = projectDir; transformations = new ArrayList<>(); sessionResults = new SessionResults(); String[] p = projectDir.split("/"); sessionResults.setName(p[p.length - 1]); this.inputConfiguration = inputConfiguration; } public Diversify(InputConfiguration inputConfiguration, String projectDir, String workingDir) { this.sourceDir = workingDir; this.projectDir = projectDir; transformations = new ArrayList<>(); this.inputConfiguration = inputConfiguration; sessionResults = new SessionResults(); String[] p = projectDir.split("/"); sessionResults.setName(p[p.length - 1]); } @Override /** * Runs the diversificator. * @param n Number of sosies we want * @throws Exception */ public void run(int n) throws Exception { //Create the folder for the output File f = new File(getResultDir()); if (earlyReport && !(f.exists())) { f.mkdirs(); } //Number of trials made and sosies achieved trial = 0; sosie = 0; String outputDir = tmpDir + "/" + sourceDir; //We will try several times, collecting errors in the way boolean success = true; boolean ableToFindMoreSosies = true; while (sosie < n && success && ableToFindMoreSosies) { Log.info("==========================="); Log.info("DIVERSIFICATION RUN :: " + trial); Log.info("==========================="); //Increase the trial count trial++; success = false; int attempts = 0; Exception[] causes = new Exception[10]; while (success == false && attempts < 10) { //1. We executeQuery for transformations. try { ((KnownSosieQuery) transQuery).executeQuery(); //Obtain transformations transformations = (List<Transformation>) ((KnownSosieQuery) transQuery).getMultiTransformations(); success = true; } catch (SeveralTriesUnsuccessful e ) { if ( e.getCauses()[0] instanceof QueryException) { QueryException qe = (QueryException)e.getCauses()[0]; if ( qe.getReason().equals(QueryException.Reasons.UNABLE_TO_FIND_SOSIE_PARENT) ) { //Gently stop the search attempts = 100; ableToFindMoreSosies = false; } } attempts++; success = false; } //2. We try to apply them if ( success ) { try { applyTransformations(transformations, outputDir); success = true; } catch (Exception ex) { ((KnownSosieQuery) transQuery).setLastTransformationStatus(Transformation.EXCEPTION); success = false; Log.error("Query application failed! " + ex.getMessage()); //Application failed!... we'll executeQuery and apply again causes[attempts] = ex; attempts++; } } //3. We run transformations found if (success) { try { run(); } catch (Exception ex) { ((KnownSosieQuery) transQuery).setLastTransformationStatus(Transformation.EXCEPTION); Log.error("Diversified program run failed! " + ex.getMessage()); success = false; //Application failed!... we'll executeQuery, apply and run again causes[attempts] = ex; attempts++; } } } //OK, we where unable to do anything... while there was chance to do something if (!success && ableToFindMoreSosies) { throw new SeveralTriesUnsuccessful(causes); } } } protected void applyTransformations(Collection<Transformation> trans, String outputDir) throws Exception { int successful = 0; try { //Try to apply transformations for (Transformation t : trans) { //Input the configuration if ( t instanceof Transformation) { ((Transformation)t).setInputProgram(inputConfiguration.getInputProgram()); } t.apply(outputDir); successful++; } } catch (Exception e) { //Revert to the original state try { for (Iterator<Transformation> i = trans.iterator(); i.hasNext() && successful > 0; successful--) { Transformation t = i.next(); if ( t instanceof Transformation) { ((Transformation)t).setInputProgram(inputConfiguration.getInputProgram()); } t.restore(outputDir); } } catch (Exception ex) { //From here I just don't want to recover throw new RuntimeException(ex); } //Once reverted, rethrow throw e; } } //@Override protected void run() throws Exception { Log.info("number of diversification: " + transformations.size()); int i = 0; int status; Log.info("============================"); Log.info("BUILDING DIVERSIFIED PROGRAM"); Log.info("============================"); //Build and run the transformation status = runTest(tmpDir); //Give back to the executeQuery the value of the las transformation ((KnownSosieQuery) transQuery).setLastTransformationStatus(status); if (status == Transformation.SOSIE) { sosie++; copySosieProgram(); } //Store transformation status for (Transformation tran : transformations) { if (tran.getStatus() == Transformation.NOT_TESTED) { tran.setStatus(status); tran.setFailures(builder.getTestFail()); } tran.restore(tmpDir + "/" + sourceDir); } String[] statusCode = {"SOSIE!!", "TEST FAILED :P", "COMPILE FAILED :("}; Log.info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); try { Log.info(statusCode[Math.abs(status)]); } catch (ArrayIndexOutOfBoundsException e) { Log.error("INVALID STATUS!! Status: " + status); throw new RuntimeException(e); } Log.debug("{} setCompile error on {} compilation", compileError, transformations.size()); Log.debug("{} sosie on {} trial", sosie, trial); Log.info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); if (earlyReport && getResultDir() != null) { earlyReport(status); } } /** * Early reports the advance of the system. * * @param status Status of the current transformations, Sosie, locate failed, etc. */ protected void earlyReport(int status) { if (getEarlyReportSosiesOnly() == false || status == 0) { try { RunResults result = buildRunResult(transformations, status, ((KnownSosieQuery) transQuery).getLastIncrementalSeries()); String jsonFile = getResultDir() + "/" + Thread.currentThread().getId() + "_trial_" + trial + "_size_" + transformations.size() + "_stat_" + status + ".json"; result.saveToFile(jsonFile); ((SessionResults) sessionResults).addRunResults(result, jsonFile, getResultDir() + "/buidOutput" + builder.getRunCount() + ".txt"); sessionResults.saveReport( getResultDir() + "/" + Thread.currentThread().getId() + "_session.html"); } catch (IOException | JSONException e) { //Not my mf problem!! (Hard rock in the background) //I mean, user usually want to stop process if no output is possible throw new RuntimeException(e); } } } /** * Builds the results from a transformation list and a resulting status * * @param trans Transformations list * @param status Resulting status * @return A run result */ protected RunResults buildRunResult(Collection<Transformation> trans, int status, int series) { RunResults result = new RunResults(); result.setId(trial); result.setIncrementalSeries(series); result.setStatus(status); result.setTransformations(trans); result.setFailedTests(builder.getTestFail()); return result; } /* protected void run(Transformation trans, String tmpDir) throws Exception { Log.debug("output dir: " + tmpDir + "/" + sourceDir); try { trans.apply(tmpDir + "/" + sourceDir); transformations.add(trans); int status = runTest(tmpDir); if (status == AbstractTransformation.SOSIE) sosie++; trial++; trans.setStatus(status); trans.setFailures(builder.getTestFail()); } catch (Exception e) { compileError++; trans.setStatus(-2); Log.warn("compile error during diversification", e); } trans.restore(tmpDir + "/" + sourceDir); Log.debug("run after restore: " + tmpDir + "/" + sourceDir); }*/ }