From 19892699e2b6df0521b191e2daa7f70fe1c51623 Mon Sep 17 00:00:00 2001
From: "le.truong" <le.truong@telecom-paris.fr>
Date: Mon, 23 Nov 2020 00:04:31 +0100
Subject: [PATCH] Fix variable initial condition and add the test for memory
 leak

---
 .../src_simulator/app/TMLSelectCommand.cpp    |   2 +-
 simulators/c++2/src_simulator/app/TMLTask.cpp |   9 +-
 simulators/c++2/src_simulator/app/TMLTask.h   |   6 +-
 simulators/c++2/src_simulator/arch/FPGA.cpp   |   1 +
 .../c++2/src_simulator/sim/SimComponents.cpp  |   8 +-
 .../c++2/src_simulator/sim/Simulator.cpp      |  14 +-
 .../java/tmltranslator/MemoryLeakTest.java    | 269 ++++++++++++++++++
 7 files changed, 294 insertions(+), 15 deletions(-)
 create mode 100644 ttool/src/test/java/tmltranslator/MemoryLeakTest.java

diff --git a/simulators/c++2/src_simulator/app/TMLSelectCommand.cpp b/simulators/c++2/src_simulator/app/TMLSelectCommand.cpp
index 3914ecaae7..5986246f83 100644
--- a/simulators/c++2/src_simulator/app/TMLSelectCommand.cpp
+++ b/simulators/c++2/src_simulator/app/TMLSelectCommand.cpp
@@ -44,7 +44,7 @@ Ludovic Apvrille, Renaud Pacalet
 #include <TMLTransaction.h>
 #include <Bus.h>
 
-TMLSelectCommand::TMLSelectCommand(ID iID, TMLTask* iTask, TMLEventChannel** iChannel, unsigned int iNumbChannels, const char* iLiveVarList, bool iCheckpoint, ParamFuncPointer* iParamFuncs):TMLCommand(iID, iTask, WAIT_SEND_VLEN, iNumbChannels, iLiveVarList, iCheckpoint), _channel(iChannel), _paramFuncs(iParamFuncs), /*_numbChannels(iNumbChannels),*/ _indexNextCommand(0) {
+TMLSelectCommand::TMLSelectCommand(ID iID, TMLTask* iTask, TMLEventChannel** iChannel, unsigned int iNumbChannels, const char* iLiveVarList, bool iCheckpoint, ParamFuncPointer* iParamFuncs):TMLCommand(iID, iTask, WAIT_SEND_VLEN, iNumbChannels, iLiveVarList, iCheckpoint), _channel(iChannel), _paramFuncs(iParamFuncs), /*_numbChannels(iNumbChannels),*/ _indexNextCommand(0), _maxChannelIndex(0) {
 	_type=SEL;
 }
 
diff --git a/simulators/c++2/src_simulator/app/TMLTask.cpp b/simulators/c++2/src_simulator/app/TMLTask.cpp
index a2361081f3..ea645d4084 100755
--- a/simulators/c++2/src_simulator/app/TMLTask.cpp
+++ b/simulators/c++2/src_simulator/app/TMLTask.cpp
@@ -48,7 +48,7 @@ Ludovic Apvrille, Renaud Pacalet
 
 unsigned int TMLTask::_instanceCount=1;
 
-TMLTask::TMLTask(ID iID, Priority iPriority, std::string iName, CPU** iCPU, unsigned int iNoOfCPUs, bool isDaemon): WorkloadSource(iPriority), _ID(iID), _name(iName), _endLastTransaction(0), _currCommand(0), _firstCommand(0), _currentCPU(0), _cpus(iCPU), _noOfCPUs(iNoOfCPUs), _isDaemon(isDaemon), _nextCellIndex(0), _comment(0), _busyCycles(0), _CPUContentionDelay(0), _noCPUTransactions(0), _justStarted(true), _myInstance(_instanceCount), /*_isScheduled(false),*/ _stateHash(0, 30) , _liveVarList(0), _hashInvalidated(true){
+TMLTask::TMLTask(ID iID, Priority iPriority, std::string iName, CPU** iCPU, unsigned int iNoOfCPUs, bool isDaemon): WorkloadSource(iPriority), _ID(iID), _name(iName), _endLastTransaction(0), _currCommand(0), _firstCommand(0), _currentCPU(0), _cpus(iCPU), _noOfCPUs(iNoOfCPUs), _isDaemon(isDaemon), _nextCellIndex(0), _comment(0), _busyCycles(0), _CPUContentionDelay(0), _noCPUTransactions(0), _justStarted(true), _myInstance(_instanceCount), /*_isScheduled(false),*/ _stateHash(0, 30) , _liveVarList(0), _hashInvalidated(true), _isFirstTranExecuted(false), _isCPUExist(true), _isFPGAExist(false){
 	for (unsigned int i=0; i< _noOfCPUs; i++)
 		_cpus[i]->registerTask(this);
 #ifdef ADD_COMMENTS
@@ -59,8 +59,7 @@ TMLTask::TMLTask(ID iID, Priority iPriority, std::string iName, CPU** iCPU, unsi
 	if (_noOfCPUs==1) _currentCPU = _cpus[0];
 }
 
-TMLTask::TMLTask(ID iID, Priority iPriority, std::string iName, FPGA** iFPGA, unsigned int iNoOfFPGAs, bool isDaemon): WorkloadSource(iPriority), _ID(iID), _name(iName), _endLastTransaction(0), _currCommand(0), _firstCommand(0), _currentFPGA(0), _fpgas(iFPGA), _noOfFPGAs(iNoOfFPGAs), _isDaemon(isDaemon), _nextCellIndex(0),_comment(0), _busyCycles(0), _FPGAContentionDelay(0), _noFPGATransactions(0), _justStarted(true), _myInstance(_instanceCount), 
- _stateHash(0, 30) , _liveVarList(0), _hashInvalidated(true){
+TMLTask::TMLTask(ID iID, Priority iPriority, std::string iName, FPGA** iFPGA, unsigned int iNoOfFPGAs, bool isDaemon): WorkloadSource(iPriority), _ID(iID), _name(iName), _endLastTransaction(0), _currCommand(0), _firstCommand(0), _currentFPGA(0), _fpgas(iFPGA), _noOfFPGAs(iNoOfFPGAs), _isDaemon(isDaemon), _nextCellIndex(0),_comment(0), _busyCycles(0), _FPGAContentionDelay(0), _noFPGATransactions(0), _justStarted(true), _myInstance(_instanceCount), _stateHash(0, 30) , _liveVarList(0), _hashInvalidated(true), _isFirstTranExecuted(false), _isCPUExist(false), _isFPGAExist(true){
 	for (unsigned int i=0; i< _noOfFPGAs; i++)
 		_fpgas[i]->registerTask(this);
 #ifdef ADD_COMMENTS
@@ -78,8 +77,8 @@ TMLTask::~TMLTask(){
 	}
 #endif
 	if (_comment!=0) delete [] _comment;
-	if(_cpus != 0) delete[] _cpus; // free the allocation of cpu array
-	if(_fpgas != 0) delete[] _fpgas; // free the allocation of fpga array
+	if(_isCPUExist) delete[] _cpus; // free the allocation of cpu array
+	if(_isFPGAExist) delete[] _fpgas; // free the allocation of fpga array
 }
 
 std::string TMLTask::toShortString() const{
diff --git a/simulators/c++2/src_simulator/app/TMLTask.h b/simulators/c++2/src_simulator/app/TMLTask.h
index 8c8e40a1ac..030eb59c4a 100755
--- a/simulators/c++2/src_simulator/app/TMLTask.h
+++ b/simulators/c++2/src_simulator/app/TMLTask.h
@@ -242,6 +242,8 @@ public:
 	bool getIsDaemon() {return _isDaemon;};
 	bool getIsFirstTranExecuted() {return _isFirstTranExecuted;};
 	inline void setIsFirstTranExecuted(bool x) {_isFirstTranExecuted = x;};
+	bool getIsFPGAExist() {return _isFPGAExist;};
+	bool getIsCPUExist() {return _isCPUExist;};
 protected:
 	///ID of the task
 	ID _ID;
@@ -266,7 +268,6 @@ protected:
 	///Number of cores assigned to the task
 	unsigned int _noOfFPGAs;
 	bool _isDaemon;
-	bool _isFirstTranExecuted;
 	unsigned int _nextCellIndex;
 
 #ifdef ADD_COMMENTS
@@ -312,6 +313,9 @@ protected:
 	HashAlgo _stateHash;
 	const char* _liveVarList;
 	bool _hashInvalidated;
+	bool _isFirstTranExecuted;
+	bool _isCPUExist;
+	bool _isFPGAExist;
 	static void writeHTMLColumn(	std::ofstream& myfile,
 									const unsigned int colSpan,
 									const std::string cellClass );
diff --git a/simulators/c++2/src_simulator/arch/FPGA.cpp b/simulators/c++2/src_simulator/arch/FPGA.cpp
index b27e4a91ae..5a8b58e349 100644
--- a/simulators/c++2/src_simulator/arch/FPGA.cpp
+++ b/simulators/c++2/src_simulator/arch/FPGA.cpp
@@ -56,6 +56,7 @@ FPGA::FPGA(    ID iID,
 	       unsigned int iCyclesPerExeci, 
 	       unsigned int iCyclesPerExecc ) : SchedulableDevice(iID, iName, iScheduler)
 					      ,_reconfigTime(iReconfigTime)
+					      ,_masterNextTransaction(0)
 					      ,_lastTransaction(0)
 					      ,_changeIdleModeCycles(iChangeIdleModeCycles)
 					      ,_cyclesBeforeIdle(iCyclesBeforeIdle)
diff --git a/simulators/c++2/src_simulator/sim/SimComponents.cpp b/simulators/c++2/src_simulator/sim/SimComponents.cpp
index 8ebc16f1a1..d267ac9083 100644
--- a/simulators/c++2/src_simulator/sim/SimComponents.cpp
+++ b/simulators/c++2/src_simulator/sim/SimComponents.cpp
@@ -76,10 +76,10 @@ SimComponents::~SimComponents(){
 		delete (*i);
 	}
 
-    for(TaskList::const_iterator i=_taskList.begin(); i != _taskList.end(); ++i){
-        //free tasks before terminate simulator
-        delete (*i);
-    }
+	for(TaskList::const_iterator i=_taskList.begin(); i != _taskList.end(); ++i){
+		//free tasks before terminate simulator
+		delete (*i);
+	}
 
 #ifdef EBRDD_ENABLED
 	for(EBRDDList::iterator i=_ebrddList.begin(); i != _ebrddList.end(); ++i){
diff --git a/simulators/c++2/src_simulator/sim/Simulator.cpp b/simulators/c++2/src_simulator/sim/Simulator.cpp
index b40e873042..c4bfd2743e 100644
--- a/simulators/c++2/src_simulator/sim/Simulator.cpp
+++ b/simulators/c++2/src_simulator/sim/Simulator.cpp
@@ -1066,8 +1066,14 @@ bool Simulator::simulate(TMLTransaction*& oLastTrans){
 #ifdef DEBUG_KERNEL
 	  std::cout << "kernel:simulate: dependent Task found" << std::endl;
 #endif
-	  depCPU=depTask->getCPU();
-	  depFPGA=depTask->getFPGA();
+	  if(depTask->getIsCPUExist())
+	      depCPU=depTask->getCPU();
+	  else
+	      depCPU = 0;
+	  if(depTask->getIsFPGAExist())
+	      depFPGA=depTask->getFPGA();
+	  else
+	      depFPGA = 0;
 	  
 	  if(depCPU){
 #ifdef DEBUG_SIMULATE
@@ -1119,7 +1125,7 @@ bool Simulator::simulate(TMLTransaction*& oLastTrans){
 #ifdef DEBUG_SIMULATE
 	    std::cout<<"lets start fpga"<<std::endl;
 #endif
-	    if (depFPGA!=deviceLET){
+	    if (depFPGA != 0 && depFPGA != deviceLET){
 #ifdef DEBUG_KERNEL
 	      std::cout << "kernel:simulate: Tasks running on different FPGAs" << std::endl;
 #endif
@@ -1412,7 +1418,7 @@ void Simulator::decodeCommand(std::string iCmd, std::ostream& iXmlOutStream){
   std::cout<<"decodeCommand"<<std::endl;
   //std::cout << "Not crashed. I: " << iCmd << std::endl;
   //std::cout << iCmd << std::endl;
-  unsigned int aCmd, aParam1, aParam2, anErrorCode=0;
+  unsigned int aCmd = 0, aParam1 = 0, aParam2 = 0, anErrorCode = 0;
   //std::string anIssuedCmd(iCmd);
   std::istringstream aInpStream(iCmd);
   //std::cout << "Not crashed. II\n";
diff --git a/ttool/src/test/java/tmltranslator/MemoryLeakTest.java b/ttool/src/test/java/tmltranslator/MemoryLeakTest.java
new file mode 100644
index 0000000000..b6aa2bfcb7
--- /dev/null
+++ b/ttool/src/test/java/tmltranslator/MemoryLeakTest.java
@@ -0,0 +1,269 @@
+package tmltranslator;
+
+import common.ConfigurationTTool;
+import common.SpecConfigTTool;
+import graph.AUTGraph;
+import myutil.FileUtils;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import req.ebrdd.EBRDD;
+import tepe.TEPE;
+import tmltranslator.tomappingsystemc2.DiploSimulatorFactory;
+import tmltranslator.tomappingsystemc2.IDiploSimulatorCodeGenerator;
+import tmltranslator.tomappingsystemc2.Penalties;
+import ui.AbstractUITest;
+import ui.TDiagramPanel;
+import ui.TMLArchiPanel;
+import ui.TURTLEPanel;
+import ui.tmldd.TMLArchiDiagramPanel;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertTrue;
+
+public class MemoryLeakTest extends AbstractUITest {
+    final String DIR_GEN = "test_diplo_simulator/";
+    final String [] MODELS_MEMORY_LEAK = {"fpga_reconfig5", "fpga_reconfig6"};
+    private String SIM_DIR;
+    final int [] NB_OF_ML_STATES = {20, 20};
+    final int [] NB_OF_ML_TRANSTIONS = {19, 19};
+    final int [] MIN_ML_CYCLES = {75, 76};
+    final int [] MAX_ML_CYCLES = {75, 76};
+    static String CPP_DIR = "../../../../simulators/c++2/";
+    static String valgrindVersionCmd = "valgrind --version";
+    static String valgrindExecCmd = "valgrind --leak-check=full --log-file=";
+
+    @BeforeClass
+    public static void setUpBeforeClass() throws Exception {
+        RESOURCES_DIR = getBaseResourcesDir() + "/tmltranslator/simulator/";
+    }
+
+    public MemoryLeakTest() {
+        super();
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        SIM_DIR = getBaseResourcesDir() + CPP_DIR;
+    }
+
+    @Test
+    public void testMemoryLeak() throws Exception {
+        for (int i = 0; i < MODELS_MEMORY_LEAK.length; i++) {
+            String s = MODELS_MEMORY_LEAK[i];
+            SIM_DIR = DIR_GEN + s + "_memoryLeak/";
+            System.out.println("executing: checking syntax " + s);
+            // select architecture tab
+            mainGUI.openProjectFromFile(new File(RESOURCES_DIR + s + ".xml"));
+            for (TURTLEPanel _tab : mainGUI.getTabs()) {
+                if (_tab instanceof TMLArchiPanel) {
+                    for (TDiagramPanel tdp : _tab.getPanels()) {
+                        if (tdp instanceof TMLArchiDiagramPanel) {
+                            mainGUI.selectTab(tdp);
+                            break;
+                        }
+                    }
+                    break;
+                }
+            }
+
+            mainGUI.checkModelingSyntax(true);
+            TMLMapping tmap = mainGUI.gtm.getTMLMapping();
+            TMLSyntaxChecking syntax = new TMLSyntaxChecking(tmap);
+            syntax.checkSyntax();
+            assertTrue(syntax.hasErrors() == 0);
+            // Generate SystemC code
+            System.out.println("executing: sim code gen for " + s);
+            final IDiploSimulatorCodeGenerator tml2systc;
+            List<EBRDD> al = new ArrayList<EBRDD>();
+            List<TEPE> alTepe = new ArrayList<TEPE>();
+            tml2systc = DiploSimulatorFactory.INSTANCE.createCodeGenerator(tmap, al, alTepe);
+            tml2systc.setModelName(s);
+            String error = tml2systc.generateSystemC(false, true);
+            assertTrue(error == null);
+
+            File directory = new File(SIM_DIR);
+            if (!directory.exists()) {
+                directory.mkdirs();
+            }
+
+            // Putting sim files
+            System.out.println("SIM executing: sim lib code copying for " + s);
+            ConfigurationTTool.SystemCCodeDirectory = getBaseResourcesDir() + CPP_DIR;
+            boolean simFiles = SpecConfigTTool.checkAndCreateSystemCDir(SIM_DIR);
+
+            System.out.println("SIM executing: sim lib code copying done with result " + simFiles);
+            assertTrue(simFiles);
+
+            System.out.println("SIM Saving file in: " + SIM_DIR);
+            tml2systc.saveFile(SIM_DIR, "appmodel");
+
+            // Compile it
+            System.out.println("executing: compile");
+            Process proc;
+            BufferedReader proc_in;
+            String str;
+            boolean mustRecompileAll;
+            Penalties penalty = new Penalties(SIM_DIR + "src_simulator");
+            int changed = penalty.handlePenalties(false);
+
+            if (changed == 1) {
+                mustRecompileAll = true;
+            } else {
+                mustRecompileAll = false;
+            }
+
+            if (mustRecompileAll) {
+                System.out.println("executing: " + "make -C " + SIM_DIR + " clean");
+                try {
+                    proc = Runtime.getRuntime().exec("make -C " + SIM_DIR + " clean");
+                    proc_in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+                    while ((str = proc_in.readLine()) != null) {
+                        // TraceManager.addDev( "Sending " + str + " from " + port + " to client..." );
+                        System.out.println("executing: " + str);
+                    }
+                } catch (Exception e) {
+                    // probably make is not installed
+                    System.out.println("FAILED: executing: " + "make -C " + SIM_DIR + " clean");
+                    return;
+                }
+            }
+
+            System.out.println("executing: " + "make -C " + SIM_DIR);
+            try {
+                proc = Runtime.getRuntime().exec("make -C " + SIM_DIR + "");
+                proc_in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+
+                monitorError(proc);
+
+                while ((str = proc_in.readLine()) != null) {
+                    // TraceManager.addDev( "Sending " + str + " from " + port + " to client..." );
+                    System.out.println("executing: " + str);
+                }
+            } catch (Exception e) {
+                // Probably make is not installed
+                System.out.println("FAILED: executing: " + "make -C " + SIM_DIR);
+                return;
+            }
+
+            System.out.println("SUCCESS: executing: " + "make -C " + SIM_DIR);
+            // check if valgrind installed or not
+            boolean isValgrindInstalled = false;
+            try {
+                proc = Runtime.getRuntime().exec(valgrindVersionCmd);
+                proc_in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+
+                monitorError(proc);
+
+                while ((str = proc_in.readLine()) != null) {
+                    // TraceManager.addDev( "Sending " + str + " from " + port + " to client..." );
+                    System.out.println("executing: " + str);
+                }
+                isValgrindInstalled = true;
+            } catch (Exception e) {
+                System.out.println("FAILED: valgrind is not installed");
+            }
+
+            //run test with valgrind
+            if(isValgrindInstalled) {
+                String logPath = SIM_DIR + "valgrind.log";
+                proc = Runtime.getRuntime().exec(valgrindExecCmd + logPath + " ./" + SIM_DIR + "run.x" + " -cmd 1 0");
+                proc_in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+
+                monitorError(proc);
+
+                while ((str = proc_in.readLine()) != null) {
+                    // TraceManager.addDev( "Sending " + str + " from " + port + " to client..." );
+                    System.out.println("executing valgrind: " + str);
+                }
+
+                int memoryLeakVerify = 0;
+                boolean errorFound = true;
+                String sCurrentLine = "";
+                BufferedReader br = new BufferedReader(new FileReader(logPath));
+                while ((sCurrentLine = br.readLine()) != null)
+                {
+                    if(sCurrentLine.contains("definitely lost: 0 bytes in 0 blocks")) {
+                        memoryLeakVerify++;
+                        System.out.println(sCurrentLine);
+                    }
+
+                    if(sCurrentLine.contains("indirectly lost: 0 bytes in 0 blocks")) {
+                        memoryLeakVerify++;
+                        System.out.println(sCurrentLine);
+                    }
+
+                    if(sCurrentLine.contains("possibly lost: 0 bytes in 0 blocks")) {
+                        memoryLeakVerify++;
+                        System.out.println(sCurrentLine);
+                    }
+
+                    if(sCurrentLine.contains("ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)")) {
+                        errorFound = false;
+                        System.out.println(sCurrentLine);
+                    }
+                }
+
+                assertTrue(memoryLeakVerify == 3); //no memory leak
+                assertTrue(!errorFound);// no error
+
+            } else {
+                //valgrind is not installed, so run test without it
+                String graphPath = SIM_DIR + "testgraph_" + s;
+                try {
+
+                    String[] params = new String[3];
+
+                    params[0] = "./" + SIM_DIR + "run.x";
+                    params[1] = "-cmd";
+                    params[2] = "1 0; 1 7 100 100 " + graphPath;
+                    proc = Runtime.getRuntime().exec(params);
+                    proc_in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+
+                    monitorError(proc);
+
+                    while ((str = proc_in.readLine()) != null) {
+                        // TraceManager.addDev( "Sending " + str + " from " + port + " to client..." );
+                        System.out.println("executing: " + str);
+                    }
+                } catch (Exception e) {
+                    // Probably make is not installed
+                    System.out.println("FAILED: executing simulation " + e.getCause());
+                    return;
+                }
+
+                File graphFile = new File(graphPath + ".aut");
+                String graphData = "";
+                try {
+                    graphData = FileUtils.loadFileData(graphFile);
+                } catch (Exception e) {
+                    assertTrue(false);
+                }
+
+                AUTGraph graph = new AUTGraph();
+                graph.buildGraph(graphData);
+
+                // States and transitions
+                System.out.println("executing: nb states of " + s + " " + graph.getNbOfStates());
+                assertTrue(NB_OF_ML_STATES[i] == graph.getNbOfStates());
+                System.out.println("executing: nb transitions of " + s + " " + graph.getNbOfTransitions());
+                assertTrue(NB_OF_ML_TRANSTIONS[i] == graph.getNbOfTransitions());
+
+                // Min and max cycles
+                int minValue = graph.getMinValue("allCPUsFPGAsTerminated");
+                System.out.println("executing: minvalue of " + s + " " + minValue);
+                assertTrue(MIN_ML_CYCLES[i] == minValue);
+
+                int maxValue = graph.getMaxValue("allCPUsFPGAsTerminated");
+                System.out.println("executing: maxvalue of " + s + " " + maxValue);
+                assertTrue(MAX_ML_CYCLES[i] == maxValue);
+            }
+        }
+    }
+}
-- 
GitLab