| /******************************************************************************* |
| * Copyright (c) 2016 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 |
| * |
| * Created on: 22 mars 2016 |
| * |
| * Contributors: |
| * Arnault Lapitre (CEA LIST) arnault.lapitre@cea.fr |
| * - Initial API and implementation |
| ******************************************************************************/ |
| |
| #include "GraphVizExecutionGraphSerializer.h" |
| |
| #include <fml/executable/AvmProgram.h> |
| #include <fml/executable/AvmTransition.h> |
| |
| #include <fml/expression/AvmCode.h> |
| |
| #include <fml/runtime/ExecutionConfiguration.h> |
| #include <fml/runtime/ExecutionContext.h> |
| #include <fml/runtime/ExecutionData.h> |
| #include <fml/runtime/ExecutionInformation.h> |
| #include <fml/runtime/RuntimeForm.h> |
| #include <fml/runtime/RuntimeID.h> |
| #include <fml/runtime/TableOfData.h> |
| |
| #include <fml/workflow/Query.h> |
| #include <fml/workflow/WObject.h> |
| |
| #include <sew/Configuration.h> |
| #include <sew/SymbexControllerUnitManager.h> |
| |
| #include <boost/format.hpp> |
| |
| |
| namespace sep |
| { |
| |
| |
| /** |
| * GLOBAL HEADER / END |
| * %1% --> graph name-id |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_GLOBAL_HEADER_PATTERN = "digraph %1% {"; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_GLOBAL_END_PATTERN = "\n}"; |
| |
| /** |
| * EXECUTION CONTEXT NODE |
| * %1% --> node#id |
| * %2% --> node#label |
| * %3% --> node#css |
| * %4% --> node#data |
| * %5% --> node#info |
| * %6% --> node#fired |
| * %7% --> node#trace |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_CONTEXT_NODE_PATTERN = "\nEC%1% [%2%%3%\n]%4%"; |
| |
| /** |
| * EXECUTION CONTEXT NODE LABEL |
| * %1% --> node#id |
| * %2% --> node#header |
| * %3% --> node#data |
| * %4% --> node#info |
| * %5% --> node#fired |
| * %6% --> node#trace |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_CONTEXT_NODE_LABEL_PATTERN = "\n\tlabel=\"%2%%4%\""; |
| |
| /** |
| * EXECUTION CONTEXT NODE CSS |
| * %1% --> node#id |
| * %2% --> node#color |
| * %3% --> node#shape |
| * %4% --> node#style |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_CONTEXT_NODE_CSS_PATTERN = |
| "\n\tcolor=%2%\n\tshape=%3%\n\tstyle=%4%"; |
| |
| // CSS PROFILE: COLOR / SHAPE |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_CONTEXT_NODE_COLOR = "lightblue"; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| WARNING_CONTEXT_NODE_COLOR = "orange"; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| ERROR_CONTEXT_NODE_COLOR = "red"; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| ALERT_CONTEXT_NODE_COLOR = "red"; |
| |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| OBJECTIVE_ACHIEVED_CONTEXT_NODE_COLOR = "lawngreen"; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| OBJECTIVE_ACHIEVED_CONTEXT_NODE_SHAPE = "tripleoctagon"; |
| |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| OBJECTIVE_FAILED_CONTEXT_NODE_COLOR = "orange"; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| OBJECTIVE_FAILED_CONTEXT_NODE_SHAPE = "doubleoctagon"; |
| |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| OBJECTIVE_ABORTED_CONTEXT_NODE_COLOR = "red"; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| OBJECTIVE_ABORTED_CONTEXT_NODE_SHAPE = "octagon"; |
| |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| COVERAGE_ELEMENT_CONTEXT_NODE_COLOR = "yellow"; |
| |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| REDUNDANCY_CONTEXT_NODE_COLOR = "green"; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| REDUNDANCY_CONTEXT_NODE_SHAPE = "cds"; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| REDUNDANCY_TARGET_CONTEXT_NODE_COLOR = "greenyellow"; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| REDUNDANCY_TARGET_CONTEXT_NODE_SHAPE = "septagon"; |
| |
| // CSS PROFILE: SHAPE |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_CONTEXT_NODE_SHAPE = "ellipse"; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| STATEMENT_EXIT_CONTEXT_NODE_SHAPE = "tripleoctagon"; |
| |
| // CSS PROFILE: STYLE |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_CONTEXT_NODE_STYLE = "filled"; |
| |
| |
| /** |
| * EXECUTION CONTEXT EDGE |
| * %1% --> node#source#id |
| * %2% --> node#target#id |
| * %3% --> node#target#data |
| * %4% --> node#target#info |
| * %5% --> node#target#fired |
| * %6% --> node#target#trace |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_CONTEXT_EDGE_PATTERN = "\nEC%1% -> EC%2% [\n\tlabel=\"%5%%6%\"\n]"; |
| |
| /** |
| * EXECUTION CONTEXT HEADER |
| * %1% --> ec#id |
| * %2% --> ec#eval |
| * %3% --> ec#hight |
| * %4% --> ec#width |
| * %5% --> ec#weight |
| * %6% --> statemachine configuration i.e. lifelines state identifier |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_CONTEXT_NODE_HEADER_PATTERN = "EC#%1%<Ev:%2%>\\n%6%"; |
| |
| /** |
| * EXECUTION DATA |
| * %1% --> ec#id |
| * %2% --> ec#assign |
| * %3% --> ec#path#condition |
| * %4% --> ec#path#timed#condition |
| * %5% --> ec#node#condition |
| * %6% --> ec#node#timed#condition |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_CONTEXT_NODE_DATA_PATTERN = "\nEC%1% -> ED%1%\nED%1% " |
| "[\n\tlabel=\"%3%%4%%5%%6%%2%\"\n\tshape=box\n]"; |
| |
| /** |
| * EXECUTION CONTEXT INFO |
| * %1% --> node#id |
| * %2% --> execution info |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_CONTEXT_NODE_INFO_PATTERN = "\n%2%"; |
| // "\nEC%1% -> EI%1%\nEI%1% [\n\tlabel=\"%2%\"" |
| // "\n\tshape=octagon\n\tcolor=yellow\n\tstyle=filled\n]"; |
| |
| /** |
| * EXECUTION CONTEXT INFO |
| * %1% --> node#id |
| * %2% --> execution fired |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_CONTEXT_NODE_FIRED_PATTERN = "%2%"; |
| |
| /** |
| * EXECUTION CONTEXT INFO |
| * %1% --> node#id |
| * %2% --> execution trace |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_CONTEXT_NODE_TRACE_PATTERN = "%2%"; |
| |
| /** |
| * INFO |
| * %1% --> info id |
| * %2% --> info data |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_INFO_PATTERN = "%1%: %2%"; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| STANDARD_INFO_PATTERN = "%2%"; |
| |
| /** |
| * CONDITION |
| * %1% --> condition |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_PATH_CONDITION_PATTERN = "" /*"PC: %1%"*/; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_PATH_TIMED_CONDITION_PATTERN = "" /*"PtC: %1%"*/; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_NODE_CONDITION_PATTERN = "" /*"NC: %1%"*/; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_NODE_TIMED_CONDITION_PATTERN = ""/*"NtC: %1%"*/; |
| |
| /** |
| * ASSIGN |
| * %1% --> machine runtime pid |
| * %2% --> machine container identifier |
| * %3% --> variable identifier |
| * %4% --> value |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_ASSIGN_PATTERN = "%1%:%2% = %3%"; |
| |
| /** |
| * NEWFRESH |
| * %1% --> machine runtime pid |
| * %2% --> machine container identifier |
| * %3% --> variable identifier |
| * %4% --> value |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_NEWFRESH_PATTERN = "newfresh %1%->%2%( %3% )"; |
| |
| /** |
| * INPUT / OUTPUT |
| * %1% --> machine runtime pid |
| * %2% --> machine container identifier |
| * %3% --> ( port | signal ) identifier |
| * %4% --> value |
| * %5% --> machine sender identifier name |
| * %6% --> machine receiver identifier name |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_INPUT_PATTERN = "%1%->%3% ? %4%"; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_OUTPUT_PATTERN = "%1%->%3% ! %4%"; |
| |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_INPUT_ENV_PATTERN = "env => %1%->%3% ? %4%"; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_OUTPUT_ENV_PATTERN = "env <= %1%->%3% ! %4%"; |
| |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_INPUT_RDV_PATTERN = "\tinput#rdv %2%->%3%%4%\n"; |
| |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_OUTPUT_RDV_PATTERN = "\toutput#rdv %2%->%3%%4%\n"; |
| |
| |
| /** |
| * LIFELINE STATE IDENTIFIER |
| * %1% --> lifeline runtime pid |
| * %2% --> lifeline identifier |
| * %3% --> state runtime pid |
| * %3% --> state identifier |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_LIFELINE_STATE_PATTERN = "%2%:%4%"; |
| |
| /** |
| * MACHINE |
| * %1% --> machine runtime pid |
| * %2% --> machine container identifier |
| * %3% --> machine identifier |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_MACHINE_PATTERN = "%3%"; |
| |
| /** |
| * TRANSITION |
| * %1% --> machine runtime pid |
| * %2% --> machine container identifier |
| * %3% --> transition identifier |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_TRANSITION_PATTERN = "%2%->%3%"; |
| |
| /** |
| * ROUTINE |
| * %1% --> machine runtime pid |
| * %2% --> machine container identifier |
| * %3% --> routine identifier |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_ROUTINE_PATTERN = "%2%->%3%"; |
| |
| /** |
| * VARIABLE |
| * %1% --> machine runtime pid |
| * %2% --> machine container identifier |
| * %3% --> variable identifier |
| */ |
| const std::string & GraphVizExecutionGraphSerializer:: |
| DEFAULT_VARIABLE_PATTERN = "%1%->%3%"; |
| |
| |
| |
| |
| |
| /******************************************************************************* |
| serializer += GraphVizExecutionGraphSerializer <name-id> "<description>" { |
| // ... |
| |
| @property: |
| |
| @trace: |
| |
| @format: |
| |
| @vfs: |
| file = "<save-file-path>" |
| } |
| *******************************************************************************/ |
| |
| /** |
| prototype processor::serializer#graph "serialize graph" as GraphVizExecutionGraphSerializer is |
| section PROPERTY |
| @info#selection = 'ALL'; // ALL | MODIFIED |
| @data#selection = 'ALL'; // ALL | MODIFIED |
| endsection PROPERTY |
| |
| section FORMAT |
| @line#wrap#width = 42; |
| @line#wrap#separator = "\\l"; |
| |
| // %1% --> graph name#id |
| @header = "digraph model_%1% {\n"; |
| @end = "\n}"; |
| |
| // %1% --> node#id |
| // %2% --> node#label |
| // %3% --> node#css |
| // %4% --> node#data |
| // %5% --> node#info |
| // %6% --> node#fired |
| // %7% --> node#trace |
| @node = "\nEC%1% [%2%%3%\n]%5%%4%"; |
| |
| // %1% --> node#id |
| // %2% --> node#header |
| // %3% --> node#data |
| // %4% --> node#info |
| // %5% --> node#fired |
| // %6% --> node#trace |
| @node#label = "\n\tlabel=\"%2%\""; |
| |
| // %1% --> node#id |
| // %2% --> node#color |
| // %3% --> node#shape |
| // %4% --> node#style |
| @node#css = "\n\tcolor=%2%\n\tshape=%3%\n\tstyle=%4%"; |
| |
| // %1% --> node#source#id |
| // %2% --> node#target#id |
| // %3% --> node#target#data |
| // %4% --> node#target#info |
| // %5% --> node#target#fired |
| // %6% --> node#target#trace |
| @edge = "\nEC%1% -> EC%2% [\n\tlabel=\"%5%%6%\"\n]"; |
| |
| // %1% --> ec#id |
| // %2% --> ec#eval |
| // %3% --> ec#hight |
| // %4% --> ec#width |
| // %5% --> ec#weight |
| // %6% --> statemachine configuration i.e. lifelines state identifier |
| @node#header = "EC#%1%<Ev:%2%>\n%6%"; |
| |
| // %1% --> ec#id |
| // %2% --> ec#assign |
| // %3% --> ec#path#condition |
| // %4% --> ec#path#timed#condition |
| // %5% --> ec#node#condition |
| // %6% --> ec#node#timed#condition |
| @node#data = "\nEC%1% -> ED%1%\nED%1% [\n\tlabel=\"%3%%4%%5%%6%%2%\"\n\tshape=box\n]"; |
| |
| // %1% --> node#id |
| // %2% --> execution info |
| @node#info = "\nEC%1% -> EI%1%\nEI%1% [\n\tlabel=\"%2%\"\n\tshape=box\n\tcolor=yellow\n\tstyle=filled\n]"; |
| |
| // %1% --> node#id |
| // %2% --> execution fired |
| @node#fired = "%2%"; |
| |
| // %1% --> node#id |
| // %2% --> execution trace |
| @node#trace = "%2%"; |
| |
| |
| // %1% --> info id |
| // %2% --> info data |
| @info = "%2%"; |
| |
| // %1% --> condition |
| @path#condition = "PC: %1%"; |
| @path#timed#condition = "PtC: %1%"; |
| @node#condition = "NC: %1%"; |
| @node#timed#condition = "NtC: %1%"; |
| |
| // %1% --> machine runtime pid |
| // %2% --> machine identifier name |
| // %3% --> port | signal | variable | machine | transition | routine |
| // %4% --> value |
| @assign = "%2%:%3%=%4%"; |
| |
| @newfresh = "newfresh(%1%:%3%) <- %4%"; |
| |
| @machine = ""; |
| @machine = "run %1%:%3%"; |
| |
| @transition = "fired %3%"; |
| @routine = "invoke %2%:%3%"; |
| |
| @input = "%3% ? %4%"; |
| @input = "%1%->%3% ? %4%"; |
| |
| @input#env = "env => %1%->%3% ? %4%"; |
| |
| @output = "%3% ! %4%"; |
| @output = "%1%->%3% ! %4%"; |
| |
| @output#env = "env <= %1%->%3% ! %4%"; |
| endsection FORMAT |
| section TRACE |
| @machine = "[*]"; |
| |
| @state = "[*]"; |
| @tatemachine = "[*]"; |
| |
| @transition = "[*]"; |
| |
| @routine = "[*]"; |
| |
| @com = "[*]"; |
| |
| @input = "[*]"; |
| @output = "[*]"; |
| |
| @newfresh = "[*]"; |
| @variable = "[*]"; |
| endsection TRACE |
| section VFS |
| @file = "graph.gv"; |
| endsection VFS |
| endprototype |
| */ |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // CONFIGURE API |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| bool GraphVizExecutionGraphSerializer::configureImpl() |
| { |
| mConfigFlag = Serializer::configureImpl(); |
| |
| // the Trace Point Filter configuration |
| mConfigFlag = mTraceFilter.configure(getENV(), getParameterWObject()) |
| && mConfigFlag; |
| |
| avm_size_t error = 0; |
| |
| // Standard profile |
| mContextNodeColor = DEFAULT_CONTEXT_NODE_COLOR; |
| mContextNodeShape = DEFAULT_CONTEXT_NODE_SHAPE; |
| mContextNodeStyle = DEFAULT_CONTEXT_NODE_STYLE; |
| |
| mContextNodeSeparator = "\\n"; |
| |
| mInfoPattern = STANDARD_INFO_PATTERN; |
| mInfoJustification = ""; |
| mInfoSeparator = "\\n"; |
| |
| |
| WObject * theFORMAT = Query::getRegexWSequence( |
| getParameterWObject(), OR_WID2("format", "FORMAT")); |
| if( theFORMAT != WObject::_NULL_ ) |
| { |
| mWrapData.SEPARATOR = Query::getRegexWPropertyString(theFORMAT, |
| CONS_WID3("line", "wrap", "separator"), mWrapData.SEPARATOR); |
| StringTools::replaceAll(mWrapData.SEPARATOR, "\\\\l", "\\l"); |
| |
| error += configureFormatter(theFORMAT, |
| mGlobalHeaderPattern, "header" ) ? 0 : 1; |
| error += configureFormatter(theFORMAT, |
| mGlobalEndPattern, "end" ) ? 0 : 1; |
| |
| error += configureFormatter(theFORMAT, |
| mContextNodePattern, "node" ) ? 0 : 1; |
| error += configureFormatter(theFORMAT, mContextNodeLabelPattern, |
| CONS_WID2("node", "label"), true ) ? 0 : 1; |
| error += configureFormatter(theFORMAT, mContextNodeCssPattern, |
| CONS_WID2("node", "css"), true ) ? 0 : 1; |
| |
| error += configureFormatter(theFORMAT, |
| mContextEdgePattern, "edge" ) ? 0 : 1; |
| |
| error += configureFormatter(theFORMAT, mContextNodeHeaderPattern, |
| CONS_WID2("node", "header"), true ) ? 0 : 1; |
| error += configureFormatter(theFORMAT, mContextNodeDataPattern, |
| CONS_WID2("node", "data"), true ) ? 0 : 1; |
| error += configureFormatter(theFORMAT, mContextNodeInfoPattern, |
| CONS_WID2("node", "info"), true ) ? 0 : 1; |
| error += configureFormatter(theFORMAT, mContextNodeFiredPattern, |
| CONS_WID2("node", "fired"), true ) ? 0 : 1; |
| error += configureFormatter(theFORMAT, mContextNodeTracePattern, |
| CONS_WID2("node", "trace"), true ) ? 0 : 1; |
| |
| error += configureFormatter(theFORMAT, mInfoPattern, "info" ) ? 0 : 1; |
| |
| error += configureFormatter(theFORMAT, mPathConditionPattern, |
| CONS_WID2("path", "condition"), true ) ? 0 : 1; |
| error += configureFormatter(theFORMAT, mPathTimedConditionPattern, |
| CONS_WID3("path", "timed", "condition"), true ) ? 0 : 1; |
| error += configureFormatter(theFORMAT, mNodeConditionPattern, |
| CONS_WID2("node", "condition"), true ) ? 0 : 1; |
| error += configureFormatter(theFORMAT, mNodeTimedConditionPattern, |
| CONS_WID3("node", "timed", "condition"), true ) ? 0 : 1; |
| |
| error += configureFormatter(theFORMAT, |
| mAssignPattern, "assign" ) ? 0 : 1; |
| error += configureFormatter(theFORMAT, |
| mNewfreshPattern, "newfresh" ) ? 0 : 1; |
| |
| error += configureFormatter(theFORMAT, |
| mInputPattern, "input" ) ? 0 : 1; |
| error += configureFormatter(theFORMAT, |
| mOutputPattern, "output" ) ? 0 : 1; |
| |
| |
| error += configureFormatter(theFORMAT, |
| mInputEnvPattern, CONS_WID2("input", "env"), true ) ? 0 : 1; |
| error += configureFormatter(theFORMAT, |
| mOutputEnvPattern, CONS_WID2("output", "env"), true ) ? 0 : 1; |
| |
| error += configureFormatter(theFORMAT, |
| mInputRdvPattern , CONS_WID2("input", "rdv"), true ) ? 0 : 1; |
| error += configureFormatter(theFORMAT, |
| mOutputRdvPattern, CONS_WID2("output", "rdv"), true) ? 0 : 1; |
| |
| |
| if( Query::hasWPropertyString(theFORMAT, "input") ) |
| { |
| if( not Query::hasRegexWProperty( |
| theFORMAT, CONS_WID2("input", "env")) ) |
| { |
| mInputEnvPattern = mInputPattern; |
| } |
| if( not Query::hasRegexWProperty( |
| theFORMAT, CONS_WID2("input", "rdv")) ) |
| { |
| mInputRdvPattern = mInputPattern; |
| } |
| } |
| |
| if( Query::hasWPropertyString(theFORMAT, "output") ) |
| { |
| if( not Query::hasRegexWProperty( |
| theFORMAT, CONS_WID2("output", "env")) ) |
| { |
| mOutputEnvPattern = mOutputPattern; |
| } |
| |
| if( not Query::hasRegexWProperty( |
| theFORMAT, CONS_WID2("output", "rdv")) ) |
| { |
| mOutputRdvPattern = mOutputPattern; |
| } |
| } |
| |
| |
| error += configureFormatter(theFORMAT, mLifelineStatePattern, |
| CONS_WID2("lifeline", "state"), true ) ? 0 : 1; |
| |
| error += configureFormatter(theFORMAT, |
| mMachinePattern, "machine" ) ? 0 : 1; |
| error += configureFormatter(theFORMAT, |
| mTransitionPattern, "transition") ? 0 : 1; |
| error += configureFormatter(theFORMAT, |
| mRoutinePattern, "routine" ) ? 0 : 1; |
| error += configureFormatter(theFORMAT, |
| mVariablePattern, "variable" ) ? 0 : 1; |
| } |
| // else // Standard profile |
| // { |
| // mContextNodeColor = DEFAULT_CONTEXT_NODE_COLOR; |
| // mContextNodeShape = DEFAULT_CONTEXT_NODE_SHAPE; |
| // mContextNodeStyle = DEFAULT_CONTEXT_NODE_STYLE; |
| // |
| // mContextNodeSeparator = "\\n"; |
| // |
| // mInfoPattern = STANDARD_INFO_PATTERN; |
| // mInfoJustification = ""; |
| // mInfoSeparator = "\\n"; |
| // } |
| |
| mShowNodeHeaderFlag = (not mContextNodeHeaderPattern.empty()); |
| mShowNodeDataFlag = (not mContextNodeDataPattern.empty()); |
| mShowNodeInfoFlag = (not mContextNodeInfoPattern.empty()); |
| |
| mConfigFlag = (error == 0) && mConfigFlag; |
| |
| return( mConfigFlag ); |
| } |
| |
| |
| bool GraphVizExecutionGraphSerializer::configureFormatter(WObject * FORMAT, |
| std::string & formatPattern, const std::string & id, bool isRegex) |
| { |
| formatPattern = isRegex |
| ? Query::getRegexWPropertyString(FORMAT, id, formatPattern) |
| : Query::getWPropertyString(FORMAT, id, formatPattern); |
| |
| StringTools::replaceAll(formatPattern, "\\t" , "\t"); |
| StringTools::replaceAll(formatPattern, "\\n" , "\n"); |
| StringTools::replaceAll(formatPattern, "\\\"", "\""); |
| |
| try |
| { |
| boost::format formatter(formatPattern); |
| } |
| catch(const boost::io::bad_format_string & bfs) |
| { |
| Query::reportErrorAttribute(FORMAT, id, bfs.what()); |
| |
| return( false ); |
| } |
| |
| return( true ); |
| } |
| |
| |
| |
| /** |
| * REPORT TRACE |
| */ |
| void GraphVizExecutionGraphSerializer::reportDefault(OutStream & os) const |
| { |
| AVM_OS_VERBOSITY_MEDIUM( os ) |
| << TAB << "GRAPHVIZ EXECUTION GRAPH SERIALIZER< " |
| << getParameterWObject()->getFullyQualifiedNameID() |
| << " > DONE !!!" << EOL_FLUSH; |
| } |
| |
| |
| /** |
| * FILTERING API |
| */ |
| bool GraphVizExecutionGraphSerializer::prefilter() |
| { |
| return( true ); |
| } |
| |
| bool GraphVizExecutionGraphSerializer::postfilter() |
| { |
| return( true ); |
| } |
| |
| |
| /** |
| * POST-PROCESSING API |
| */ |
| bool GraphVizExecutionGraphSerializer::postprocess() |
| { |
| const ExecutionContext & anEC = *( getConfiguration().getFirstTrace() ); |
| |
| bool saveFlag = String::USE_BACKSLASH_QUOTE; |
| String::USE_BACKSLASH_QUOTE = true; |
| |
| beginStream(); |
| while( hasStream() ) |
| { |
| dotFormat(currentStream(), anEC); |
| } |
| |
| String::USE_BACKSLASH_QUOTE = saveFlag; |
| |
| closeStream(); |
| |
| return( true ); |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| // DEFAULT FORMAT API |
| //////////////////////////////////////////////////////////////////////////// |
| |
| void GraphVizExecutionGraphSerializer::format( |
| SymbexControllerUnitManager & aManager, |
| OutStream & out, const ExecutionContext & rootEC) |
| { |
| AbstractProcessorUnit * existingSerializer = |
| aManager.getControllerUnit( |
| GraphVizExecutionGraphSerializer::AUTO_REGISTER_TOOL); |
| |
| if( existingSerializer != NULL ) |
| { |
| GraphVizExecutionGraphSerializer gvSerializer( |
| aManager, existingSerializer->getParameterWObject()); |
| |
| if( gvSerializer.configureImpl() ) |
| { |
| gvSerializer.dotFormat(out, rootEC); |
| |
| return; |
| } |
| } |
| else |
| { |
| GraphVizExecutionGraphSerializer gvSerializer(aManager, WObject::_NULL_); |
| |
| if( gvSerializer.configureImpl() ) |
| { |
| gvSerializer.dotFormat(out, rootEC); |
| |
| return; |
| } |
| } |
| |
| out << "digraph fscn {" << std::endl |
| << "ERROR [ " << std::endl |
| << "\tlabel=\"" |
| << "Unfound,\n" |
| "in the current SymbexControllerUnitManager,\\n" |
| "an existing GraphVizExecutionGraphSerializer\\n" |
| "which configuration could be used\n" |
| "to configure the default GraphViz's serializer!\"" |
| << std::endl |
| << "\tshape=tripleoctagon" << std::endl |
| << "\tcolor=red" << std::endl |
| << "\tstyle=filled" << std::endl |
| << "]" << std::endl |
| << "}" << std::endl; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // FORMAT API |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| void GraphVizExecutionGraphSerializer::dotFormat( |
| OutStream & os, const ExecutionContext & rootEC) |
| { |
| os.setSymbexValueCSS(mMultiValueArrayCSS, |
| mMultiValueParamsCSS, mMultiValueStructCSS); |
| |
| doFormatHeader( os ); |
| |
| mDotFormatNodeWaitingQueue.push_back( & rootEC ); |
| |
| const ExecutionContext * itEC = NULL; |
| while( mDotFormatNodeWaitingQueue.nonempty() ) |
| { |
| mDotFormatNodeWaitingQueue.pop_first_to( itEC ); |
| |
| dotFormatNode(os, (* itEC)); |
| } |
| |
| doFormatEnd( os ); |
| |
| os.restoreSymbexValueCSS(); |
| } |
| |
| /** |
| * GLOBAL HEADER |
| * %1% --> graph name-id |
| */ |
| void GraphVizExecutionGraphSerializer::doFormatHeader(OutStream & os) |
| { |
| boost::format formatter(mGlobalHeaderPattern); |
| formatter.exceptions( boost::io::no_error_bits ); |
| |
| os << formatter |
| % "fscn"; |
| } |
| |
| /** |
| * GLOBAL END |
| * %1% --> graph name#id |
| */ |
| void GraphVizExecutionGraphSerializer::doFormatEnd(OutStream & os) |
| { |
| boost::format formatter(mGlobalEndPattern); |
| formatter.exceptions( boost::io::no_error_bits ); |
| |
| os << formatter |
| % "fscn"; |
| } |
| |
| |
| /** |
| * EXECUTION CONTEXT NODE |
| * %1% --> node#id |
| * %2% --> node#label |
| * %3% --> node#css |
| * %4% --> node#data |
| * %5% --> node#info |
| * %6% --> node#fired |
| * %7% --> node#trace |
| */ |
| void GraphVizExecutionGraphSerializer::dotFormatNode( |
| OutStream & os, const ExecutionContext & anEC) |
| { |
| StringOutStream ecLabel; |
| StringOutStream ecCSS; |
| |
| StringOutStream ecHeader; |
| StringOutStream ecData; |
| StringOutStream ecInfo; |
| StringOutStream ecFired; |
| StringOutStream ecTrace; |
| |
| if( mShowNodeHeaderFlag ) |
| { |
| dotFormatNodeHeader(ecHeader, anEC); |
| } |
| if( mShowNodeDataFlag ) |
| { |
| dotFormatNodeData(ecData, anEC); |
| } |
| if( mShowNodeInfoFlag ) |
| { |
| dotFormatNodeInfo(ecInfo, anEC); |
| } |
| if( mTraceFilter.hasRunnablePoint() ) |
| { |
| dotFormatNodeRunnableTrace(ecFired, anEC); |
| } |
| if( mTraceFilter.hasIOTracePoint() ) |
| { |
| dotFormatNodeIOTrace(ecFired, anEC); |
| } |
| |
| /* |
| * EXECUTION CONTEXT NODE LABEL |
| * %1% --> node#id |
| * %2% --> node#header |
| * %3% --> node#data |
| * %4% --> node#info |
| * %5% --> node#fired |
| * %6% --> node#trace |
| */ |
| boost::format formatterLabel(mContextNodeLabelPattern); |
| formatterLabel.exceptions( boost::io::no_error_bits ); |
| |
| ecLabel << formatterLabel |
| % anEC.getIdNumber() |
| % ecHeader.str() |
| % ecData.str() |
| % ecInfo.str() |
| % ecFired.str() |
| % ecTrace.str(); |
| |
| /* |
| * EXECUTION CONTEXT NODE CSS |
| * %1% --> node#id |
| * %2% --> node#color |
| * %3% --> node#shape |
| * %4% --> node#style |
| */ |
| boost::format formatterCSS(mContextNodeCssPattern); |
| formatterCSS.exceptions( boost::io::no_error_bits ); |
| |
| ecCSS << formatterCSS |
| % anEC.getIdNumber() |
| % dotNodeColor( anEC ) |
| % dotNodeShape( anEC ) |
| % dotNodeStyle( anEC ); |
| |
| /* |
| * EXECUTION CONTEXT NODE |
| * %1% --> node#id |
| * %2% --> node#label |
| * %3% --> node#css |
| * %4% --> node#data |
| * %5% --> node#info |
| * %6% --> node#fired |
| * %7% --> node#trace |
| */ |
| boost::format formatter(mContextNodePattern); |
| formatter.exceptions( boost::io::no_error_bits ); |
| |
| os << formatter |
| % anEC.getIdNumber() |
| % ecLabel.str() |
| % ecCSS.str() |
| % ecData.str() |
| % ecInfo.str() |
| % ecFired.str() |
| % ecTrace.str(); |
| |
| ExecutionContext::child_iterator itEC = anEC.begin(); |
| ExecutionContext::child_iterator endEC = anEC.end(); |
| for( ; itEC != endEC ; ++itEC ) |
| { |
| dotFormatEdge(os, anEC, *(*itEC)); |
| |
| mDotFormatNodeWaitingQueue.push_back( *itEC ); |
| } |
| } |
| |
| |
| std::string GraphVizExecutionGraphSerializer::dotNodeColor( |
| const ExecutionContext & anEC) |
| { |
| const ExecutionContextFlags & flags = anEC.getFlags(); |
| |
| if( flags.hasObjectiveAchieved() ) |
| { |
| return( OBJECTIVE_ACHIEVED_CONTEXT_NODE_COLOR ); |
| } |
| if( flags.hasObjectiveFailed() ) |
| { |
| return( OBJECTIVE_FAILED_CONTEXT_NODE_COLOR ); |
| } |
| if( flags.hasObjectiveAborted() ) |
| { |
| return( OBJECTIVE_ABORTED_CONTEXT_NODE_COLOR ); |
| } |
| |
| if( flags.hasError() ) |
| { |
| return( ERROR_CONTEXT_NODE_COLOR ); |
| } |
| |
| if( flags.hasAlert() ) |
| { |
| return( ALERT_CONTEXT_NODE_COLOR ); |
| } |
| |
| if( flags.hasWarning() ) |
| { |
| return( WARNING_CONTEXT_NODE_COLOR ); |
| } |
| |
| if( flags.hasRedundancy() ) |
| { |
| return( REDUNDANCY_CONTEXT_NODE_COLOR ); |
| } |
| |
| if( flags.hasRedundancyTarget() ) |
| { |
| return( REDUNDANCY_TARGET_CONTEXT_NODE_COLOR ); |
| } |
| |
| if( flags.hasCoverageElement() /*&& anEC.hasInfo()*/ ) |
| { |
| return( COVERAGE_ELEMENT_CONTEXT_NODE_COLOR ); |
| } |
| |
| return( mContextNodeColor ); |
| } |
| |
| std::string GraphVizExecutionGraphSerializer::dotNodeShape( |
| const ExecutionContext & anEC) |
| { |
| const ExecutionContextFlags & flags = anEC.getFlags(); |
| |
| if( flags.hasObjectiveAchieved() ) |
| { |
| return( OBJECTIVE_ACHIEVED_CONTEXT_NODE_SHAPE ); |
| } |
| if( flags.hasObjectiveFailed() ) |
| { |
| return( OBJECTIVE_FAILED_CONTEXT_NODE_SHAPE ); |
| } |
| if( flags.hasObjectiveAborted() ) |
| { |
| return( OBJECTIVE_ABORTED_CONTEXT_NODE_SHAPE ); |
| } |
| |
| if( flags.isExecutionStatementExitTrace() ) |
| { |
| return( STATEMENT_EXIT_CONTEXT_NODE_SHAPE ); |
| } |
| |
| if( flags.hasRedundancy() ) |
| { |
| return( REDUNDANCY_CONTEXT_NODE_SHAPE ); |
| } |
| |
| if( flags.hasRedundancyTarget() ) |
| { |
| return( REDUNDANCY_TARGET_CONTEXT_NODE_SHAPE ); |
| } |
| |
| return( mContextNodeShape ); |
| } |
| |
| std::string GraphVizExecutionGraphSerializer::dotNodeStyle( |
| const ExecutionContext & anEC) |
| { |
| return( mContextNodeStyle ); |
| } |
| |
| |
| /** |
| * EXECUTION CONTEXT EDGE |
| * %1% --> node#source#id |
| * %2% --> node#target#id |
| * %3% --> node#target#data |
| * %4% --> node#target#info |
| * %5% --> node#target#fired |
| * %6% --> node#target#trace |
| */ |
| void GraphVizExecutionGraphSerializer::dotFormatInfo( |
| OutStream & os, GenericInfoData * anInfo) |
| { |
| std::string strInfo = anInfo->strData(); |
| if( not strInfo.empty() ) |
| { |
| boost::format formatter(mInfoPattern); |
| formatter.exceptions( boost::io::no_error_bits ); |
| |
| os << formatter |
| % anInfo->strUID() |
| % strInfo |
| << mInfoJustification; |
| } |
| } |
| |
| |
| |
| void GraphVizExecutionGraphSerializer::dotFormatEdge(OutStream & os, |
| const ExecutionContext & srcEC, const ExecutionContext & tgtEC) |
| { |
| StringOutStream ecData; |
| StringOutStream ecInfo; |
| StringOutStream ecFired; |
| StringOutStream ecTrace; |
| |
| if( mShowNodeDataFlag ) |
| { |
| dotFormatNodeData(ecData, tgtEC); |
| } |
| if( mShowNodeInfoFlag ) |
| { |
| dotFormatNodeInfo(ecInfo, tgtEC); |
| } |
| if( mTraceFilter.hasRunnablePoint() ) |
| { |
| dotFormatNodeRunnableTrace(ecFired, tgtEC); |
| } |
| if( mTraceFilter.hasIOTracePoint() ) |
| { |
| dotFormatNodeIOTrace(ecFired, tgtEC); |
| } |
| |
| boost::format formatter(mContextEdgePattern); |
| formatter.exceptions( boost::io::no_error_bits ); |
| |
| os << formatter |
| % srcEC.getIdNumber() |
| % tgtEC.getIdNumber() |
| % ecData.str() |
| % ecInfo.str() |
| % ecFired.str() |
| % ecTrace.str(); |
| } |
| |
| |
| /** |
| * EXECUTION CONTEXT HEADER |
| * %1% --> ec#id |
| * %2% --> ec#eval |
| * %3% --> ec#hight |
| * %4% --> ec#width |
| * %5% --> ec#weight |
| * %6% --> statemachine configuration i.e. lifelines state identifier |
| */ |
| void GraphVizExecutionGraphSerializer::dotFormatNodeHeader( |
| OutStream & os, const ExecutionContext & anEC) |
| { |
| boost::format formatter(mContextNodeHeaderPattern); |
| formatter.exceptions( boost::io::no_error_bits ); |
| |
| os << formatter |
| % anEC.getIdNumber() |
| % anEC.getEvalNumber() |
| % anEC.getHeight() |
| % anEC.getWidth() |
| % anEC.getWeight() |
| % anEC.refExecutionData().strStateConf(mLifelineStatePattern); |
| |
| if( anEC.getFlags().hasReachedLimitOrExecutionTrace() ) |
| { |
| os << "\\n" << anEC.getFlags().str(); |
| } |
| } |
| |
| /** |
| * EXECUTION DATA |
| * %1% --> ec#id |
| * %2% --> ec#assign |
| * %3% --> ec#path#condition |
| * %4% --> ec#path#timed#condition |
| * %5% --> ec#node#condition |
| * %6% --> ec#node#timed#condition |
| */ |
| void GraphVizExecutionGraphSerializer::dotFormatNodeData( |
| OutStream & os, const ExecutionContext & anEC) |
| { |
| StringOutStream edAssign; |
| StringOutStream edPC; |
| StringOutStream edPtC; |
| StringOutStream edFC; |
| StringOutStream edFtC; |
| |
| bool hasData = false; |
| |
| const ExecutionData & anED = anEC.refExecutionData(); |
| |
| if( mTraceFilter.hasPathConditionPoint() |
| && (not anED.getPathCondition().isEqualTrue()) ) |
| { |
| dotFormatCondition(edPC, mPathConditionPattern, |
| anED.getPathCondition() ); |
| |
| hasData = true; |
| } |
| else if( mTraceFilter.hasPathConditionLeafNodePoint() |
| && anEC.isLeafNode() |
| && (not anED.getPathCondition().isEqualTrue()) ) |
| { |
| dotFormatCondition(edPC, mPathConditionPattern, |
| anED.getPathCondition() ); |
| |
| hasData = true; |
| } |
| |
| if( mTraceFilter.hasPathTimedConditionPoint() |
| && (not anED.getPathTimedCondition().isEqualTrue()) ) |
| { |
| dotFormatCondition(edPtC, mPathTimedConditionPattern, |
| anED.getPathTimedCondition() ); |
| |
| hasData = true; |
| } |
| else if( mTraceFilter.hasPathTimedConditionLeafNodePoint() |
| && anEC.isLeafNode() |
| && (not anED.getPathTimedCondition().isEqualTrue()) ) |
| { |
| dotFormatCondition(edPtC, mPathTimedConditionPattern, |
| anED.getPathTimedCondition() ); |
| |
| hasData = true; |
| } |
| |
| if( mTraceFilter.hasNodeConditionPoint() |
| && (not anED.getNodeCondition().isEqualTrue()) ) |
| { |
| dotFormatCondition(edFC, mNodeConditionPattern, |
| anED.getNodeCondition() ); |
| |
| hasData = true; |
| } |
| if( mTraceFilter.hasNodeTimedConditionPoint() |
| && (not anED.getNodeTimedCondition().isEqualTrue()) ) |
| { |
| dotFormatCondition(edFtC, mNodeTimedConditionPattern, |
| anED.getNodeTimedCondition() ); |
| |
| hasData = true; |
| } |
| |
| if( mTraceFilter.hasAssignPoint() ) |
| { |
| dotFormatAssign(edAssign, anED, anEC.isnotRoot()); |
| |
| hasData = hasData || (not edAssign.str().empty()); |
| } |
| |
| |
| if( hasData ) |
| { |
| boost::format formatter(mContextNodeDataPattern); |
| formatter.exceptions( boost::io::no_error_bits ); |
| |
| os << formatter |
| % anEC.getIdNumber() |
| % edAssign.str() |
| % edPC.str() |
| % edPtC.str() |
| % edFC.str() |
| % edFtC.str(); |
| } |
| } |
| |
| /** |
| * EXECUTION CONTEXT INFO |
| * %1% --> node#id |
| * %2% --> execution info |
| */ |
| void GraphVizExecutionGraphSerializer::dotFormatNodeInfo( |
| OutStream & os, const ExecutionContext & anEC) |
| { |
| if( anEC.hasInfo() ) |
| { |
| StringOutStream ecInfo; |
| |
| BFList::const_raw_iterator< |
| GenericInfoData > itInfo = anEC.getInfos().begin(); |
| BFList::const_raw_iterator< |
| GenericInfoData > endInfo = anEC.getInfos().end(); |
| dotFormatInfo(ecInfo, itInfo); |
| for( ++itInfo ; itInfo != endInfo ; ++itInfo ) |
| { |
| ecInfo << mInfoSeparator; |
| dotFormatInfo(ecInfo, itInfo); |
| } |
| |
| std::string strInfo = ecInfo.str(); |
| if( not strInfo.empty() ) |
| { |
| boost::format formatter(mContextNodeInfoPattern); |
| formatter.exceptions( boost::io::no_error_bits ); |
| |
| os << formatter |
| % anEC.getIdNumber() |
| % strInfo; |
| } |
| } |
| } |
| |
| |
| /** |
| * INFO |
| * %1% --> info id |
| * %2% --> info data |
| */ |
| /** |
| * EXECUTION CONTEXT INFO |
| * %1% --> node#id |
| * %2% --> execution fired |
| */ |
| void GraphVizExecutionGraphSerializer::dotFormatNodeRunnableTrace( |
| OutStream & os, const ExecutionContext & anEC) |
| { |
| if( anEC.hasRunnableElementTrace() ) |
| { |
| StringOutStream ecFired; |
| dotFormatRunnableTrace(ecFired, anEC.getRunnableElementTrace()); |
| |
| std::string strFired = ecFired.str(); |
| |
| if( not strFired.empty() ) |
| { |
| boost::format formatter(mContextNodeFiredPattern); |
| formatter.exceptions( boost::io::no_error_bits ); |
| |
| os << formatter |
| % anEC.getIdNumber() |
| % strFired; |
| } |
| } |
| } |
| |
| /** |
| * FIRED |
| * running machine |
| * fired transition |
| * invoked routine |
| */ |
| void GraphVizExecutionGraphSerializer::dotFormatRunnableTrace( |
| OutStream & os, const BF & aFired) |
| { |
| if( aFired.is< ExecutionConfiguration >() ) |
| { |
| ExecutionConfiguration * aConf = |
| aFired.to_ptr< ExecutionConfiguration >(); |
| |
| if( aConf->isTransition() ) |
| { |
| dotFormatTransition(os, |
| aConf->getRuntimeID(), aConf->getTransition()); |
| } |
| else if( aConf->isOperator() && |
| aConf->getOperator()->isOpCode( AVM_OPCODE_RUN ) ) |
| { |
| dotFormatMachine(os, aConf->getRuntimeID()); |
| } |
| } |
| else if( aFired.is< AvmCode >() ) |
| { |
| AvmCode * aCode = aFired.to_ptr< AvmCode >(); |
| |
| AvmCode::const_iterator it = aCode->begin(); |
| AvmCode::const_iterator endCode = aCode->end(); |
| for( ; it != endCode ; ++it ) |
| { |
| dotFormatRunnableTrace(os, (*it)); |
| } |
| } |
| } |
| |
| /** |
| * MACHINE |
| * %1% --> machine runtime pid |
| * %2% --> machine container identifier |
| * %3% --> machine identifier |
| */ |
| void GraphVizExecutionGraphSerializer::dotFormatMachine( |
| OutStream & os, const RuntimeID & aRID) |
| { |
| if( mTraceFilter.pass(aRID) ) |
| { |
| boost::format formatter(mMachinePattern); |
| formatter.exceptions( boost::io::no_error_bits ); |
| |
| os << formatter |
| % aRID.strPid() |
| % aRID.getInstance()->getNameID() |
| % aRID.getInstance()->getNameID() |
| << mWrapData.SEPARATOR; |
| } |
| } |
| |
| /** |
| * TRANSITION |
| * %1% --> machine runtime pid |
| * %2% --> machine container identifier |
| * %3% --> transition identifier |
| */ |
| void GraphVizExecutionGraphSerializer::dotFormatTransition(OutStream & os, |
| const RuntimeID & aRID, AvmTransition * aTransition) |
| { |
| if( mTraceFilter.hasTransitionPoint() ) |
| { |
| boost::format formatter(mTransitionPattern); |
| formatter.exceptions( boost::io::no_error_bits ); |
| |
| os << formatter |
| % aRID.strPid() |
| % aRID.getInstance()->getNameID() |
| % aTransition->getNameID() |
| << mWrapData.SEPARATOR; |
| } |
| } |
| |
| /** |
| * ROUTINE |
| * %1% --> machine runtime pid |
| * %2% --> machine container identifier |
| * %3% --> routine identifier |
| */ |
| void GraphVizExecutionGraphSerializer::dotFormatRoutine(OutStream & os, |
| const RuntimeID & aRID, AvmProgram * aRoutine) |
| { |
| if( mTraceFilter.hasRoutinePoint() ) |
| { |
| boost::format formatter(mRoutinePattern); |
| formatter.exceptions( boost::io::no_error_bits ); |
| |
| os << formatter |
| % aRID.strPid() |
| % aRID.getInstance()->getNameID() |
| % aRoutine->getNameID() |
| << mWrapData.SEPARATOR; |
| } |
| } |
| |
| |
| /** |
| * EXECUTION CONTEXT INFO |
| * %1% --> node#id |
| * %2% --> execution trace |
| */ |
| void GraphVizExecutionGraphSerializer::dotFormatNodeIOTrace( |
| OutStream & os, const ExecutionContext & anEC) |
| { |
| StringOutStream ecTrace; |
| dotFormatIOTrace(ecTrace, anEC.getIOElementTrace()); |
| |
| std::string strTrace = ecTrace.str(); |
| |
| if( not strTrace.empty() ) |
| { |
| boost::format formatter(mContextNodeTracePattern); |
| formatter.exceptions( boost::io::no_error_bits ); |
| |
| os << formatter |
| % anEC.getIdNumber() |
| % strTrace; |
| } |
| } |
| |
| /** |
| * TRACE |
| * input ( port | signal | message ) [ values ] |
| * output ( port | signal | message ) [ values ] |
| * newfresh variable <- value |
| */ |
| void GraphVizExecutionGraphSerializer::dotFormatIOTrace( |
| OutStream & os, const BF & aTrace) |
| { |
| if( aTrace.is< ExecutionConfiguration >() ) |
| { |
| ExecutionConfiguration * aConf = |
| aTrace.to_ptr< ExecutionConfiguration >(); |
| |
| if( aConf->isAvmCode() ) |
| { |
| AvmCode * aCode = aConf->getAvmCode(); |
| |
| switch( aCode->getOptimizedOpCode() ) |
| { |
| case AVM_OPCODE_INPUT_ENV: |
| { |
| if( mTraceFilter.hasInputEnvPoint() |
| && mTraceFilter.pass(aCode) ) |
| { |
| dotFormatInputOutput(os, mInputEnvPattern, |
| aConf->getRuntimeID(), aCode); |
| } |
| break; |
| } |
| case AVM_OPCODE_INPUT_RDV: |
| { |
| if( mTraceFilter.hasInputRdvPoint() |
| && mTraceFilter.pass(aCode) ) |
| { |
| dotFormatInputOutput(os, mInputRdvPattern, |
| aConf->getRuntimeID(), aCode); |
| } |
| break; |
| } |
| case AVM_OPCODE_INPUT: |
| { |
| if( mTraceFilter.hasInputPoint() |
| && mTraceFilter.pass(aCode) ) |
| { |
| dotFormatInputOutput(os, mInputPattern, |
| aConf->getRuntimeID(), aCode); |
| } |
| break; |
| } |
| |
| case AVM_OPCODE_OUTPUT_ENV: |
| { |
| if( mTraceFilter.hasOutputEnvPoint() |
| && mTraceFilter.pass(aCode) ) |
| { |
| dotFormatInputOutput(os, mOutputEnvPattern, |
| aConf->getRuntimeID(), aCode); |
| } |
| break; |
| } |
| case AVM_OPCODE_OUTPUT_RDV: |
| { |
| if( mTraceFilter.hasOutputRdvPoint() |
| && mTraceFilter.pass(aCode) ) |
| { |
| dotFormatInputOutput(os, mOutputRdvPattern, |
| aConf->getRuntimeID(), aCode); |
| } |
| break; |
| } |
| case AVM_OPCODE_OUTPUT: |
| { |
| if( mTraceFilter.hasOutputPoint() |
| && mTraceFilter.pass(aCode) ) |
| { |
| dotFormatInputOutput(os, mOutputPattern, |
| aConf->getRuntimeID(), aCode); |
| } |
| break; |
| } |
| |
| case AVM_OPCODE_ASSIGN_NEWFRESH: |
| { |
| if( mTraceFilter.hasNewfreshPoint() |
| && mTraceFilter.pass(aCode) ) |
| { |
| dotFormatNewfresh(os, aConf->getRuntimeID(), aCode); |
| } |
| break; |
| } |
| |
| default: |
| { |
| break; |
| } |
| } |
| } |
| } |
| else if( aTrace.is< AvmCode >() ) |
| { |
| AvmCode * aCode = aTrace.to_ptr< AvmCode >(); |
| |
| AvmCode::const_iterator it = aCode->begin(); |
| AvmCode::const_iterator endCode = aCode->end(); |
| for( ; it != endCode ; ++it ) |
| { |
| dotFormatIOTrace(os, (*it)); |
| } |
| } |
| } |
| |
| /** |
| * INPUT / OUTPUT |
| * %1% --> machine runtime pid |
| * %2% --> machine container identifier |
| * %3% --> port | signal | message identifier |
| * %4% --> value |
| * %5% --> machine sender identifier name |
| * %6% --> machine receiver identifier name |
| */ |
| void GraphVizExecutionGraphSerializer::dotFormatInputOutput( |
| OutStream & os, const std::string & pattern, |
| const RuntimeID & aRID, AvmCode * aCode) |
| { |
| InstanceOfPort * aPort = aCode->first().to_ptr< InstanceOfPort >(); |
| |
| OSS oss( AVM_STR_INDENT ); |
| |
| if( aCode->populated() ) |
| { |
| AvmCode::const_iterator it = aCode->begin(); |
| AvmCode::const_iterator endCode = aCode->end(); |
| if( (++it) != endCode ) |
| { |
| oss << os.VALUE_PARAMS_CSS.BEGIN; |
| |
| aPort->getParameterType(0)->formatStream(oss, (*it)); |
| |
| avm_size_t offset = 1; |
| for( ++it ; it != endCode ; ++it , ++offset ) |
| { |
| oss << os.VALUE_PARAMS_CSS.SEPARATOR; |
| |
| aPort->getParameterType(offset)->formatStream(oss, (*it)); |
| } |
| |
| oss << os.VALUE_PARAMS_CSS.END; |
| } |
| } |
| |
| boost::format formatter(pattern); |
| formatter.exceptions( boost::io::no_error_bits ); |
| |
| RuntimeID ridContainer = aRID.getCommunicator( aPort ); |
| |
| os << mWrapData << formatter |
| % ridContainer.strPid() |
| % ridContainer.getInstance()->getNameID() |
| % aCode->first().to_ptr< InstanceOfPort >()->getNameID() |
| % oss.str(); |
| |
| os << END_WRAP << mWrapData.SEPARATOR; |
| } |
| |
| |
| /** |
| * NEWFRESH |
| * %1% --> machine runtime pid |
| * %2% --> machine container identifier |
| * %3% --> variable identifier |
| * %4% --> value |
| */ |
| void GraphVizExecutionGraphSerializer::dotFormatNewfresh(OutStream & os, |
| const RuntimeID & aRID, AvmCode * aCode) |
| { |
| InstanceOfData * aVar = aCode->first().to_ptr< InstanceOfData >(); |
| |
| boost::format formatter(mNewfreshPattern); |
| formatter.exceptions( boost::io::no_error_bits ); |
| |
| RuntimeID ridContainer = aRID.getAncestorContaining(aVar); |
| |
| os << mWrapData << formatter |
| % ridContainer.strPid() |
| % ridContainer.getInstance()->getNameID() |
| % aVar->getNameID() |
| % aVar->strValue( aCode->second() ); |
| |
| os << END_WRAP << mWrapData.SEPARATOR; |
| } |
| |
| |
| /** |
| * CONDITION |
| * [ Timed ] [ Path | Fired ] Condition |
| */ |
| void GraphVizExecutionGraphSerializer::dotFormatCondition(OutStream & os, |
| const std::string & formatPattern, const BF & aCondition) |
| { |
| boost::format formatter(formatPattern); |
| formatter.exceptions( boost::io::no_error_bits ); |
| |
| os << mWrapData << formatter % aCondition.str(); |
| |
| os << END_WRAP << mWrapData.SEPARATOR; |
| } |
| |
| /** |
| * ASSIGN |
| * Assignment: var = value |
| */ |
| void GraphVizExecutionGraphSerializer::dotFormatAssign( |
| OutStream & os, const ExecutionData & anED, bool isnotRoot) |
| { |
| TableOfInstanceOfData::const_raw_iterator itVariable; |
| TableOfInstanceOfData::const_raw_iterator endVariable; |
| |
| TableOfRuntimeT::const_iterator itRF = anED.getTableOfRuntime().begin(); |
| TableOfRuntimeT::const_iterator endRF = anED.getTableOfRuntime().end(); |
| RuntimeForm * pRF = NULL; |
| for( ++itRF; (itRF != endRF) ; ++itRF ) |
| { |
| pRF = (*itRF); |
| |
| if( pRF->hasData() ) |
| { |
| itVariable = pRF->getExecutable()->getAllData().begin(); |
| endVariable = pRF->getExecutable()->getAllData().end(); |
| for( ; itVariable != endVariable ; ++itVariable ) |
| { |
| if( mDataSelectionModifiedFlags && isnotRoot ) |
| { |
| if( not anED.isAssigned( |
| pRF->getRID(), itVariable->getOffset()) ) |
| { |
| continue; |
| } |
| } |
| |
| if( mTraceFilter.pass(pRF->getRID(), |
| static_cast< InstanceOfData * >(itVariable)) ) |
| { |
| dotFormatAssign(os, pRF->getRID(), itVariable, |
| pRF->getDataTable()->get(itVariable)); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * ASSIGN |
| * %1% --> machine runtime pid |
| * %2% --> machine container identifier |
| * %3% --> variable identifier |
| * %4% --> value |
| */ |
| void GraphVizExecutionGraphSerializer::dotFormatAssign(OutStream & os, |
| const RuntimeID & aRID, InstanceOfData * aVar, const BF & aValue) |
| { |
| boost::format formatter(mAssignPattern); |
| formatter.exceptions( boost::io::no_error_bits ); |
| |
| os << mWrapData << formatter |
| % aRID.strPid() |
| % aRID.getInstance()->getNameID() |
| % aVar->getNameID() |
| % aVar->strValue( aValue ); |
| |
| os << END_WRAP << mWrapData.SEPARATOR; |
| } |
| |
| |
| } /* namespace sep */ |