blob: 413fac7cf72c855b996d14979f07a2d634c3e257 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2019 CEA LIST.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Arnault Lapitre (CEA LIST) arnault.lapitre@cea.fr
* - Initial API and Implementation
*******************************************************************************/
package org.eclipse.efm.execution.launchconfiguration.job.sew;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.efm.execution.core.preferences.SymbexPreferenceUtil;
public class LivenessCheckerSymbexWorkflow extends SymbexWorkflowProvider {
protected final IContainer fModelsContainer;
protected IPath fReportFilePath_ALL;
protected IPath fReportFilePath_LIVE;
protected IPath fReportFilePath_NOT;
protected PrintWriter fLoggerWriter_ALL;
protected PrintWriter fLoggerWriter_LIVE;
protected PrintWriter fLoggerWriter_NOT;
protected static String CSV_SEPARATOR = " ; ";
protected int fActorCount;
protected int fChannelCount;
protected int fTimedActorCount;
protected int fPhaseActorCount;
protected int fTickCount;
protected int fFiringCount;
protected boolean fLivenessFlag;
protected long fWellFormedCount;
protected long fConsistentCount;
protected long fLivenessCount;
protected long fTotalTick_LIVE;
protected long fTotalTick_NOT;
protected long fTotalFiring_LIVE;
protected long fTotalFiring_NOT;
protected long fTotalExecutionTime_LIVE;
protected long fTotalExecutionTime_NOT;
public LivenessCheckerSymbexWorkflow(
final IContainer container, final String reportFilename) {
super();
assert (container != null) : "Unexpected a null Workflow Container";
fModelsContainer = container;
IPath path = container.getLocation();
String filename = reportFilename;
if( ! (container instanceof IProject) ) {
filename = reportFilename + "_" + path.lastSegment();
path = path.removeLastSegments(1);
}
this.fReportFilePath_ALL = path.append(filename + "_ALL" ).addFileExtension("csv");
this.fReportFilePath_LIVE = path.append(filename + "_LIVE").addFileExtension("csv");
this.fReportFilePath_NOT = path.append(filename + "_NOT" ).addFileExtension("csv");
this.fLoggerWriter_ALL = null;
this.fLoggerWriter_LIVE = null;
this.fLoggerWriter_NOT = null;
this.fActorCount = 0;
this.fChannelCount = 0;
this.fTimedActorCount = 0;
this.fPhaseActorCount = 0;
this.fTickCount = 0;
this.fFiringCount = 0;
this.fLivenessFlag = false;
this.fWellFormedCount = 0;
this.fConsistentCount = 0;
this.fLivenessCount = 0;
this.fTotalTick_LIVE = 0;
this.fTotalTick_NOT = 0;
this.fTotalFiring_LIVE = 0;
this.fTotalFiring_NOT = 0;
this.fTotalExecutionTime_LIVE = 0;
this.fTotalExecutionTime_NOT = 0;
}
/*
* UTILS
*/
public void collectXliaModels() {
final ArrayList<IPath> xliaModels = new ArrayList<IPath>();
try {
for( final IResource resource : this.fModelsContainer.members() ) {
if( (resource instanceof IFile)
&& "xlia".equals(resource.getFileExtension()) )
{
xliaModels.add(resource.getLocation());
}
}
} catch (final CoreException e) {
e.printStackTrace();
}
super.fXliaModelsPath = xliaModels.toArray( new IPath[xliaModels.size()] );
}
public static String getSEW(final IPath folder, final IPath model)
{
final IPath launch = folder.makeRelativeTo(
ResourcesPlugin.getWorkspace().getRoot().getLocation());
final String sew = "@sew< workflow , 1.0 >:\n"
+ "\n// Symbolic Execution Workflow"
+ "\n// Diversity Tool Configuration"
+ "\n// CEA - LIST"
+ "\nworkflow {"
+ "\n workspace ["
+ "\n root = \"" + folder.toString() + "\""
+ "\n launch = \"" + launch.toString() + "\""
+ "\n output = \"out\""
+ "\n log = \"log\""
+ "\n debug = \"debug\""
+ "\n ] // end workspace"
+ "\n director exploration 'as main execution objective' {"
+ "\n manifest ["
+ "\n autoconf = true"
+ "\n autostart = true"
+ "\n ] // end manifest"
+ "\n project 'path of input model' ["
+ "\n source = \".\""
+ "\n model = \"" + model.makeRelativeTo(folder).toString() + "\""
+ "\n ] // end project"
+ "\n supervisor {"
+ "\n limit 'of graph exploration' ["
+ "\n step = -1"
+ "\n eval = -1"
+ "\n ] // end limit"
+ "\n queue 'defining the exploration/search strategy' ["
+ "\n strategy = 'DEPTH_FIRST_SEARCH'"
+ "\n ] // end queue"
+ "\n redundancy 'detection strategy' ["
+ "\n comparer = 'EQUALITY'"
+ "\n solver = 'OMEGA'"
+ "\n path_scope = 'CURRENT'"
+ "\n data_scope = 'ALL'"
+ "\n ] // end redundancy"
+ "\n console ["
+ "\n format = \"\\nstep:%1% , context:%2% , height:%3% , width:%4%\\n\""
+ "\n report = \"\\nstop:%1% , context:%2% , height:%3% , width:%4%\\n\""
// + "\n spider#init = \"\\n<$spider(%1%:%2%:%3%:%4%)%5%\\n\""
// + "\n spider#step = \"\\n$spider(%1%:%2%:%3%:%4%)%5%\\n\""
// + "\n spider#stop = \"\\n>$spider(%1%:%2%:%3%:%4%)%5%\\n\""
+ "\n ] // end console"
+ "\n }"
+ "\n worker ["
+ "\n ] // end worker"
+ "\n }"
+ "\n symbex 'option' ["
+ "\n name_id_separator = \"_\" // default \"#\""
+ "\n newfresh_param_name_pid = false"
+ "\n pretty_printer_var_name = true // default false"
+ "\n time_name_id = '$time'"
+ "\n delta_name_id = '$delta'"
+ "\n node_condition_enabled = false // default false"
+ "\n separation_of_pc_disjunction = false"
+ "\n check_pathcondition_satisfiability = true"
+ "\n constraint_solver = 'CVC4' // Z3"
+ "\n ] // end symbex"
+ "\n console ["
+ "\n verbose = 'SILENT'"
+ "\n ] // end console"
+ "\n shell ["
+ "\n // Stop stop the current execution if it detects the creation of the above file !"
+ "\n stop = \"symbex.stop\""
+ "\n ] // end shell"
+ "\n}"
;
return sew;
}
public static IPath generationSEW(final IPath folder,
final IPath model, final IPath sewPath)
{
try {
final FileWriter fileWriter = new FileWriter( sewPath.toOSString() );
final PrintWriter writer = new PrintWriter(fileWriter);
writer.write( getSEW(folder, model) );
writer.close();
} catch (final IOException e) {
e.printStackTrace();
}
return sewPath;
}
/*
* ANALYSIS PROFILE
*/
@Override
public String getSymbexlAnalysisProfileName() {
return "LIVENESS CHECKING";
}
/*
* WORKFLOW
*/
@Override
public boolean isIterable() {
return true;
}
@Override
public boolean isConsistent() {
return this.fWellFormednessFlag && super.isConsistent();
}
/*
* SYMBEX WORKFLOW
*/
@Override
public IPath getSymbexWorkflowPath() {
// if( hasXliaModel() ) {
// final IPath sewPath = this.fXliaModels[this.fXliaModelsIndex]
// .removeFileExtension().addFileExtension("sew");
//
//// final String name = path.lastSegment() + "_livness";
//// sewPath = sewPath.removeLastSegments(1).append(name).addFileExtension("sew");
// }
final IPath sewPath = this.fModelsContainer.getLocation()
.append("polygraph").addFileExtension("sew");
generationSEW(this.fModelsContainer.getLocation(), getXliaModelPath(), sewPath);
return sewPath;
}
@Override
public IPath genSymbexWorkflow() {
final IPath sewPath = getSymbexWorkflowPath();
generationSEW(this.fModelsContainer.getLocation(), getXliaModelPath(), sewPath);
return sewPath;
}
/*
* XLIA MODEL
*/
@Override
public IPath getXliaModelPath() {
return hasNext() ? super.fXliaModelsPath[super.fIndex] : null;
}
/*
* COMMAND LINE
*/
@Override
public String[] getCommandLine() {
return hasWorkflow() ?
new String[] {
SymbexPreferenceUtil.strDiversityAvmExecLocation(),
genSymbexWorkflow().toOSString(),
SYMBEX_LAUNCH_OPTION_ENABLE_SERVER_MODE,
SYMBEX_LAUNCH_OPTION_ENABLE_PRINT_SPIDER_POSITIONS
}
: null;
}
/*
* UTILS
*/
final static Pattern PATTERN_ACTOR = Pattern.compile("actor\\s*=\\s*(\\d+)");
final static Pattern PATTERN_CHANNEL = Pattern.compile("channel\\s*=\\s*(\\d+)");
final static Pattern PATTERN_TIMED = Pattern.compile("timed\\s*=\\s*(\\d+)");
final static Pattern PATTERN_PHASE = Pattern.compile("phase\\s*=\\s*(\\d+)");
final static Pattern PATTERN_WELL_FORMED = Pattern.compile("well-formed\\s*=\\s*(\\w+)");
final static Pattern PATTERN_CONSISTENCY = Pattern.compile("consistency\\s*=\\s*(\\w+)");
final static Pattern PATTERN_TICKS = Pattern.compile("tick_period\\s*=\\s*(\\d+)");
final static Pattern PATTERN_FIRINGS = Pattern.compile("firings\\s*=\\s*(\\d+)");
final static Pattern PATTERN_XLIA_HEADER = Pattern.compile("@(xlia|fml|xfml|xfsp)\\s*<.+");
public void loadPolygraphInfo(final IPath xliaModel)
{
try {
final FileReader fileReader = new FileReader( xliaModel.toOSString() );
final BufferedReader bufReader = new BufferedReader(fileReader);
Matcher matcher = null;
String line = null;
while((line = bufReader.readLine())!= null) {
line = line.trim();
if( line.isEmpty() || line.startsWith("/") || line.startsWith("s") ) {
continue;
}
if( (matcher = PATTERN_ACTOR.matcher(line)).find() ) {
this.fActorCount = Integer.parseUnsignedInt( matcher.group(1) );
}
else if( (matcher = PATTERN_CHANNEL.matcher(line)).find() ) {
this.fChannelCount = Integer.parseUnsignedInt( matcher.group(1) );
}
else if( (matcher = PATTERN_TIMED.matcher(line)).find() ) {
this.fTimedActorCount = Integer.parseUnsignedInt( matcher.group(1) );
}
else if( (matcher = PATTERN_PHASE.matcher(line)).find() ) {
this.fPhaseActorCount = Integer.parseUnsignedInt( matcher.group(1) );
}
else if( (matcher = PATTERN_WELL_FORMED.matcher(line)).find() ) {
super.fWellFormednessFlag = Boolean.parseBoolean( matcher.group(1) );
}
else if( (matcher = PATTERN_CONSISTENCY.matcher(line)).find() ) {
super.fConsistencyFlag = Boolean.parseBoolean( matcher.group(1) );
if( ! super.fConsistencyFlag ) {
break;
}
}
else if( (matcher = PATTERN_TICKS.matcher(line)).find() ) {
this.fTickCount = Integer.parseUnsignedInt( matcher.group(1) );
}
else if( (matcher = PATTERN_FIRINGS.matcher(line)).find() ) {
this.fFiringCount = Integer.parseUnsignedInt( matcher.group(1) );
}
else if( (matcher = PATTERN_XLIA_HEADER.matcher(line)).find() ) {
super.fConsistencyFlag = true;
break;
}
else if( line.startsWith("}") ) {
break;
}
}
bufReader.close();
}
catch (final IOException e) {
e.printStackTrace();
}
catch (final NumberFormatException e) {
e.printStackTrace();
}
}
/*
* SYMBEX VERDICT
*/
@Override
public boolean hasVerdict() {
return true;
}
@Override
public String getVerdict() {
this.fLivenessFlag =
(super.fRedundancyCount == fExecutionWidthMax) &&
// (super.fRedundancyTest == 1) &&
(super.fDeadlockCount == 0) &&
(super.fRunExitCount == 0);
return this.fLivenessFlag ? "LIVE" : "NO";
}
/*
* INITIALIZE / FINALIZE
*/
@Override
public boolean initialize() {
collectXliaModels();
if( super.initialize() )
{
try {
final FileWriter buffer_ALL = new FileWriter( fReportFilePath_ALL.toOSString() );
fLoggerWriter_ALL = new PrintWriter(buffer_ALL);
final FileWriter buffer_LIVE = new FileWriter( fReportFilePath_LIVE.toOSString() );
fLoggerWriter_LIVE = new PrintWriter(buffer_LIVE);
final FileWriter buffer_NOT = new FileWriter( fReportFilePath_NOT.toOSString() );
fLoggerWriter_NOT = new PrintWriter(buffer_NOT);
}
catch (final IOException e) {
e.printStackTrace();
return false;
}
logHeader(fLoggerWriter_ALL);
logHeader(fLoggerWriter_LIVE);
logHeader(fLoggerWriter_NOT);
return true;
}
return false;
}
public void logHeader(final PrintWriter logger) {
logger.print( "Actor" );
logger.print( CSV_SEPARATOR );
logger.print( "Channel" );
logger.print( CSV_SEPARATOR );
logger.print( "Frequency" );
logger.print( CSV_SEPARATOR );
logger.print( "Phase" );
logger.print( CSV_SEPARATOR );
logger.print( "Execution Time" );
logger.print( CSV_SEPARATOR );
logger.print( "Liveness" );
logger.print( CSV_SEPARATOR );
logger.print( "Firings" );
logger.print( CSV_SEPARATOR );
logger.print( "Ticks" );
logger.print( CSV_SEPARATOR );
logger.print( "Min-CE" );
logger.print( CSV_SEPARATOR );
logger.print( "Filename" );
logger.println();
logger.flush();
}
@Override
public void finalize() {
fLoggerWriter_ALL.println();
fLoggerWriter_LIVE.println();
fLoggerWriter_NOT.println();
fLoggerWriter_ALL.print( "Total : " );
fLoggerWriter_ALL.println( super.fXliaModelsPath.length );
fLoggerWriter_ALL.print( "Well-Formed : " );
fLoggerWriter_ALL.println( this.fWellFormedCount );
fLoggerWriter_ALL.print( "Consistent : " );
fLoggerWriter_ALL.println( this.fConsistentCount );
fLoggerWriter_ALL.print( "Live : " );
fLoggerWriter_ALL.println( this.fLivenessCount );
final long notLiveCount = fConsistentCount - fLivenessCount;
fLoggerWriter_LIVE.print( "Average Execution Time: " );
fLoggerWriter_LIVE.println( (double)fTotalExecutionTime_LIVE / fLivenessCount );
fLoggerWriter_NOT.print( "Average Execution Time: " );
fLoggerWriter_NOT.println( (double)fTotalExecutionTime_NOT / notLiveCount );
fLoggerWriter_LIVE.print( "Average Tick: " );
fLoggerWriter_LIVE.println( (double)fTotalTick_LIVE / fLivenessCount );
fLoggerWriter_NOT.print( "Average Tick: " );
fLoggerWriter_NOT.println( (double)fTotalTick_NOT / notLiveCount );
fLoggerWriter_LIVE.print( "Average Firing: " );
fLoggerWriter_LIVE.println( (double)fTotalFiring_LIVE / fLivenessCount );
fLoggerWriter_NOT.print( "Average Firing: " );
fLoggerWriter_NOT.println( (double)fTotalFiring_NOT / notLiveCount );
fLoggerWriter_LIVE.print( "Average Minimal Consitent Execution (MCE): " );
fLoggerWriter_LIVE.println( (double)(fTotalFiring_LIVE + fTotalTick_LIVE) / fLivenessCount );
fLoggerWriter_ALL.close();
fLoggerWriter_LIVE.close();
fLoggerWriter_NOT.close();
}
/*
* LOGGING
*/
@Override
public void beginLoggingSymbex() {
super.fXliaModelPath = getXliaModelPath();
resetExecutionStats();
super.fConsistencyFlag = false;
super.fWellFormednessFlag = false;
this.fLivenessFlag = false;
loadPolygraphInfo(super.fXliaModelPath);
System.out.println( getTaskName() );
// fLoggerWriter.print( fXliaModel.lastSegment() );
}
@Override
public void log(final String message) {
System.out.print(message);
fLoggerWriter_ALL.print(message);
}
@Override
public void endLoggingSymbex() {
System.out.println();
if( super.fWellFormednessFlag ) {
++this.fWellFormedCount;
}
else {
System.out.println( " >> MAL-FORMED << " );
}
if( super.fConsistencyFlag ) {
this.fLivenessFlag = (super.fRedundancyCount == fExecutionWidthMax) &&
(super.fRedundancyTest == 1) &&
(super.fDeadlockCount == 0) &&
(super.fRunExitCount == 0);
++this.fConsistentCount;
if( this.fLivenessFlag ) {
++this.fLivenessCount;
logSymbex( fLoggerWriter_LIVE );
fTotalTick_LIVE += fTickCount;
fTotalFiring_LIVE += fFiringCount;
fTotalExecutionTime_LIVE += super.fExecutionTime;
}
else {
logSymbex( fLoggerWriter_NOT );
fTotalTick_NOT += super.fExecutionStepCount - 1;
// fTotalFiring_NOT += fFiringCount;
fTotalExecutionTime_NOT += super.fExecutionTime;
}
}
else {
System.out.println( " >> INCONSISTENT << " );
}
logSymbex( fLoggerWriter_ALL );
}
public void logSymbex(final PrintWriter logger) {
logger.format( "%5d" , this.fActorCount );
logger.print( CSV_SEPARATOR );
logger.format( "%6d" , this.fChannelCount );
logger.print( CSV_SEPARATOR );
logger.format( "%10d" , this.fTimedActorCount );
logger.print( CSV_SEPARATOR );
logger.format( "%5d" , this.fPhaseActorCount );
logger.print( CSV_SEPARATOR );
logger.format( "%11d" , super.fExecutionTime );
logger.print( " ms" );
logger.print( CSV_SEPARATOR );
if( this.fLivenessFlag ) {
logger.format( "%8s" ,"YES" );
logger.print( CSV_SEPARATOR );
logger.format( "%7d" , this.fFiringCount );
logger.print( CSV_SEPARATOR );
logger.format( "%5d" , this.fTickCount );
logger.print( CSV_SEPARATOR );
logger.format( "%6d" , this.fFiringCount + this.fTickCount );
}
else {
logger.format( "%8s" , super.fWellFormednessFlag ?
(super.fConsistencyFlag ? "NO" : "INCONS") : "MALFORMED" );
logger.print( CSV_SEPARATOR );
logger.format( "%7s" , "_" );
logger.print( CSV_SEPARATOR );
logger.format( "%5d" , super.fExecutionStepCount - 1);
logger.print( CSV_SEPARATOR );
logger.format( "%6s" , "_" );
}
logger.print( CSV_SEPARATOR );
logger.print( super.fXliaModelPath.lastSegment() );
logger.println();
logger.flush();
}
}