From 2ecc837269674994ae4db400ef5bed09c4fd392a Mon Sep 17 00:00:00 2001 From: Mahder Gebremedhin Date: Sat, 31 Oct 2020 11:24:49 +0100 Subject: [PATCH] Simulation paralleization support with parmodauto (#6825) @mahge Fix serialization a894bea - Traversal now handles der, pre, previous ... properly, i.e., treats them as crefs instead of calls. @mahge Update ParModAuto sources. 4c135b3 - There are so many changes here. - Capability for monitoring and rescheduling added. - Use JSON instead of XML - updated compilation settings. e.g. use GC_THREADS from the compilation command instead of defining it in the files. - many other fixes and changes. @mahge Move parmodauto flag from debug to config flags. 724a4ab - It is now used as --parmodauto instead of -d=parmodauto @mahge Remove unused parmodelica code. f78687c - We do not try to parallelize all the systems anymore. We only parallelize ODE system for now. So cleanup the rest. @mahge Update the code gen for the updated interface. f5b3713 - We now use a global model variable in the C code. - Pass this global variable to the C interface functions. Basically acts as the 'this' argument for the C++ counterparts of the functions. @mahge Changed dumping of linear torn systems 8ecba32 - The internal equations are now dumped as fields of the main equation. They used to be dumped before the actual equation which made parsing them contrived. - Diabled old parsing and wrote a new one since the dump format has changed. In order to avoid surprises, we stick to parsing only what we know we can handle for now. - Disabled source dumping for now. It is not really needed anyway. - Normalized debug and log dumping a bit. @mahge Move ParModAuto library handling to SimCode 61a1c64 - Move the managment of ParModAuto libs out of the templates The templates was not the right place to do this. We should do things in SimCode when possible. @mahge Clean up to avoid warnings 49add1b @mahge Restructure parsing of task system json dump. d497cec - Parsing is more structured and are a bit cleaner now. - Try to make sure we fail on anything that we have not vetted manudally and are sure we are handling properly. Since some of the format for linear/non-linear as well as dynamic/non-dynamic tearing combinations can be similar it is easy to parse something by miskae as something else. @mahge Changed dumping of non-linear systems 30d7d3e - Updated dumping of non-linear [torn] systems with NO alternative tearing. - The internal equations are now dumped as fields of the main equation. They used to be dumped before the actual equation which made parsing them contrived. - This is similar to 54ce151 @mahge Add a separate file for tasksystem serialization. 9134a76 - Unfortunately we need to dump the task syste a bit different from from the dbug dump for a number of reasons: - We need to simplify things so that it is convenient to parse it later. - We also have a different function for extracting crefs from expressions. this treats der(x), pre(x) .. 'correctly' as differnt crefs from x. - There is a lot of information that is not need for paraellization that is dumped by the original serialization. So this helps us in striping that information without affecting the debugging. - Removed the old XML task system dumping which is not not used anymore. @mahge Allow parsing of single output algorithms. e890be6 - Multiple output algorithms will be checked again and allowed later. @mahge Refactor and format all source files. 0724dc4 @mahge Always build debug version om parmodauto for now. b068c06 - I hope I won't forget to change this later. @mahge Cleanup and normalize the makefiles. 83a972d @mahge Explicitly link to boost system d5e172e @mahge Fix TBB include path. 1f57456 - TBB is now assumed to be in `OMCompiler/3rdParty/tbb` instead of `OMCompiler/3rdParty/tbb_cmake` @mahge Add parmodauto configure/build to omc compilation. 4d124ad - parmodauto con now be enabled with --enable-parmodauto during configuration of OpenModelica. - This will check for the existence of modified TBB sources in 3rdParty/tbb_omc and if will fail if the directory does not exist. - If it exists, omc_tbb will be configured using cmake during OpenModelica's autoconf configuration. - configuration will set two new variables ENABLE_PARMODAUTO and OMC_TBB_ROOT. These values are used to enable parmodauto compilation and find TBB source directory respectively. @mahge Fix cmake compilation. d9b9a66 - Add new file and remove old file from MM sources list. @mahge Specify number of threads during pm model creation 20b24c4 - This used to be set during compilation. That was find for testing but for general usage it should be settable during simulation time. - It is still recommended to just let the system pick the number of threads unless you have specific reasons to do otherwise, e.g. comparing performance for research reasons. @mahge Add parmodauto to OMCompiler's CMake compilation. 06f5b5f @mahge If parmodauto link using g++. 1192d7d - We need to either compile with g++ or explicitly link to libstdc++. I think it is better to let g++ do its full c++ thing instead of linking just libstdc++ only. @mahge Propagate maximum number of threads. 7035b01 - This is preparation to be able to set the desired number of threads at simulation start. Now the max number of threads to be used at any time can be set with the interface function PM_Model_create() when the parmodauto model representation is created by the OpenModelica simulation executable code. The maximum number of threads is passed to TBB by OMModel constructor using tbb::task_scheduler_init. @mahge Do not install om_pm_model.hpp. 69383d9 - It is not needed. Just the interface file om_pm_interface.hpp is enough. If needed we will add it later. --- OMCompiler/.gitignore | 1 - .../.cmake/meta_modelica_source_list.cmake | 2 +- OMCompiler/Compiler/FrontEnd/Expression.mo | 144 ++- .../SimCode/SerializeTaskSystemInfo.mo | 962 ++++++++++++++ .../Compiler/SimCode/SimCodeFunctionUtil.mo | 3 + OMCompiler/Compiler/SimCode/SimCodeMain.mo | 16 +- OMCompiler/Compiler/Template/CodegenC.tpl | 127 +- OMCompiler/Compiler/Template/Makefile.common | 7 +- OMCompiler/Compiler/Template/SimCodeTV.mo | 2 +- .../Compiler/Template/TaskSystemDump.tpl | 447 ------- OMCompiler/Compiler/Util/Flags.mo | 390 +++--- OMCompiler/Compiler/Util/FlagsUtil.mo | 5 +- .../Compiler/boot/LoadCompilerSources.mos | 2 +- OMCompiler/Makefile.common | 17 +- OMCompiler/Makefile.in | 2 + OMCompiler/Makefile.omdev.mingw | 2 +- OMCompiler/SimulationRuntime/CMakeLists.txt | 2 +- .../ParModelica/auto/CMakeLists.txt | 55 +- .../ParModelica/auto/Makefile.common | 20 +- .../ParModelica/auto/Makefile.in | 14 +- .../ParModelica/auto/Makefile.omdev.mingw | 13 +- .../ParModelica/auto/om_pm_equation.cpp | 17 +- .../ParModelica/auto/om_pm_equation.hpp | 120 +- .../ParModelica/auto/om_pm_interface.cpp | 109 +- .../ParModelica/auto/om_pm_interface.hpp | 28 +- .../ParModelica/auto/om_pm_model.cpp | 316 ++--- .../ParModelica/auto/om_pm_model.hpp | 35 +- .../auto/pm_cluster_dynamic_scheduler.hpp | 352 +++-- .../auto/pm_cluster_level_scheduler.hpp | 356 ++++-- .../ParModelica/auto/pm_cluster_system.hpp | 441 +++---- .../ParModelica/auto/pm_clustering.hpp | 525 ++++---- .../ParModelica/auto/pm_dynamic_scheduler.hpp | 330 +++-- .../ParModelica/auto/pm_graph_dump.hpp | 108 +- .../ParModelica/auto/pm_graph_dump.inl | 178 +-- .../ParModelica/auto/pm_level_scheduler.hpp | 572 ++++----- .../ParModelica/auto/pm_level_scheduler.inl | 1132 ++++++++--------- .../ParModelica/auto/pm_load_xml.inl | 537 ++++---- .../ParModelica/auto/pm_posix_timer.cpp | 21 +- .../ParModelica/auto/pm_task_system.hpp | 326 +++-- .../ParModelica/auto/pm_task_system.inl | 189 ++- .../ParModelica/auto/pm_timer.hpp | 48 +- .../ParModelica/auto/pm_utility.cpp | 30 +- .../ParModelica/auto/pm_utility.hpp | 342 +++-- .../ParModelica/auto/pm_win_timer.cpp | 43 +- .../ParModelica/auto/test_task_graph.cpp | 16 +- OMCompiler/configure.ac | 27 + .../bootstrapping/LoadCompilerSources.mos | 1 - .../MatlabTranslator/LoadCompilerSources.mos | 1 - 48 files changed, 4364 insertions(+), 4069 deletions(-) create mode 100644 OMCompiler/Compiler/SimCode/SerializeTaskSystemInfo.mo delete mode 100644 OMCompiler/Compiler/Template/TaskSystemDump.tpl diff --git a/OMCompiler/.gitignore b/OMCompiler/.gitignore index 815d32b228e..2f248eadaec 100644 --- a/OMCompiler/.gitignore +++ b/OMCompiler/.gitignore @@ -139,7 +139,6 @@ Compiler/Template/MMToJulia.mo Compiler/Template/NFInstDumpTpl.mo Compiler/Template/SCodeDumpTpl.mo Compiler/Template/SimCodeDump.mo -Compiler/Template/TaskSystemDump.mo Compiler/Template/TplCodegen.mo Compiler/Template/Unparsing.mo Compiler/Template/VisualXMLTpl.mo diff --git a/OMCompiler/Compiler/.cmake/meta_modelica_source_list.cmake b/OMCompiler/Compiler/.cmake/meta_modelica_source_list.cmake index f7d043c43aa..7437740761b 100644 --- a/OMCompiler/Compiler/.cmake/meta_modelica_source_list.cmake +++ b/OMCompiler/Compiler/.cmake/meta_modelica_source_list.cmake @@ -378,6 +378,7 @@ set(OMC_MM_BACKEND_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/SimCode/HpcOmSimCodeMain.mo ${CMAKE_CURRENT_SOURCE_DIR}/SimCode/SerializeInitXML.mo ${CMAKE_CURRENT_SOURCE_DIR}/SimCode/SerializeModelInfo.mo + ${CMAKE_CURRENT_SOURCE_DIR}/SimCode/SerializeTaskSystemInfo.mo ${CMAKE_CURRENT_SOURCE_DIR}/SimCode/SimCode.mo ${CMAKE_CURRENT_SOURCE_DIR}/SimCode/SimCodeMain.mo ${CMAKE_CURRENT_SOURCE_DIR}/SimCode/SimCodeUtil.mo @@ -419,7 +420,6 @@ set(OMC_MM_BACKEND_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Template/GraphMLDumpTpl.mo ${CMAKE_CURRENT_SOURCE_DIR}/Template/NFInstDumpTpl.mo ${CMAKE_CURRENT_SOURCE_DIR}/Template/SimCodeDump.mo - ${CMAKE_CURRENT_SOURCE_DIR}/Template/TaskSystemDump.mo ${CMAKE_CURRENT_SOURCE_DIR}/Template/VisualXMLTpl.mo ${CMAKE_CURRENT_SOURCE_DIR}/Util/AvlTree.mo diff --git a/OMCompiler/Compiler/FrontEnd/Expression.mo b/OMCompiler/Compiler/FrontEnd/Expression.mo index 0120860a44a..1142e068542 100644 --- a/OMCompiler/Compiler/FrontEnd/Expression.mo +++ b/OMCompiler/Compiler/FrontEnd/Expression.mo @@ -6129,6 +6129,15 @@ algorithm outDims := if outChanged then listReverse(outDims) else inDims; end traverseExpTypeDims2; +public function extractUniqueCrefsFromExp + "Extracts all unique ComponentRef from an Expression." + input DAE.Exp inExp; + output list ocrefs; +algorithm + // ocrefs := List.unique(List.flatten(List.map1(extractCrefsFromExp(inExp), ComponentReference.expandCref, true))); + ocrefs := List.unique(extractCrefsFromExp(inExp)); +end extractUniqueCrefsFromExp; + public function extractCrefsFromExp " Author: BZ 2008-06, Extracts all ComponentRef from an Expression." input DAE.Exp inExp; @@ -6137,14 +6146,37 @@ algorithm (_,ocrefs) := traverseExpBottomUp(inExp, traversingComponentRefFinder, {}); end extractCrefsFromExp; -public function extractUniqueCrefsFromExp - "Extracts all unique ComponentRef from an Expression." +public function traversingComponentRefFinder " +Author: BZ 2008-06 +Exp traverser that Union the current ComponentRef with list if it is already there. +Returns a list containing, unique, all componentRef in an Expression." + input DAE.Exp inExp; + input list inCrefs; + output DAE.Exp outExp; + output list crefs; +algorithm + (outExp,crefs) := match (inExp,inCrefs) + local + ComponentRef cr; + case (DAE.CREF(componentRef=cr), crefs) + equation + crefs = List.unionEltOnTrue(cr,crefs,ComponentReference.crefEqual); + then (inExp,crefs); + else (inExp,inCrefs); + end match; +end traversingComponentRefFinder; + +public function extractUniqueCrefsFromExpDerPreStart + "author mahge: Same as extractUniqueCrefsFromExp except: + This function will not treat der(), pre() and start() as calls + but as unique ids. i.e. x is different from der(x) and given der(x) x will not + be extreacted as a unique id. Instead you get $DER.x. Same oes for pre and start.." input DAE.Exp inExp; output list ocrefs; algorithm // ocrefs := List.unique(List.flatten(List.map1(extractCrefsFromExp(inExp), ComponentReference.expandCref, true))); - ocrefs := List.unique(extractCrefsFromExp(inExp)); -end extractUniqueCrefsFromExp; + ocrefs := List.unique(extractCrefsFromExpDerPreStart(inExp)); +end extractUniqueCrefsFromExpDerPreStart; public function extractCrefsFromExpDerPreStart " author mahge: Same as extractCrefsFromExp except: @@ -6154,21 +6186,49 @@ public function extractCrefsFromExpDerPreStart input DAE.Exp inExp; output list ocrefs; algorithm - (_,ocrefs) := traverseExpDerPreStart(inExp, traversingComponentRefFinder, {}); + (_,ocrefs) := traverseExpTopDown(inExp, traversingComponentRefFinderDerPreStart, {}); end extractCrefsFromExpDerPreStart; -public function extractUniqueCrefsFromExpDerPreStart - "author mahge: Same as extractUniqueCrefsFromExp except: - This function will not treat der(), pre() and start() as calls - but as unique ids. i.e. x is different from der(x) and given der(x) x will not - be extreacted as a unique id. Instead you get $DER.x. Same oes for pre and start.." +public function traversingComponentRefFinderDerPreStart " +" input DAE.Exp inExp; - output list ocrefs; + input list inCrefs; + output DAE.Exp e; + output Boolean cont; + output list crefs; algorithm - // ocrefs := List.unique(List.flatten(List.map1(extractCrefsFromExp(inExp), ComponentReference.expandCref, true))); - ocrefs := List.unique(extractCrefsFromExpDerPreStart(inExp)); -end extractUniqueCrefsFromExpDerPreStart; + (e,cont,crefs) := match (inExp,inCrefs) + local + ComponentRef cr; + case (DAE.CREF(componentRef=cr), crefs) + algorithm + crefs := List.unionEltOnTrue(cr,inCrefs,ComponentReference.crefEqual); + then (inExp, false, crefs); + + case (DAE.CALL(path = Absyn.IDENT(name="der"), expLst={DAE.CREF(componentRef=cr)}),_) algorithm + cr := ComponentReference.crefPrefixDer(cr); + crefs := List.unionEltOnTrue(cr,inCrefs,ComponentReference.crefEqual); + then (inExp, false, crefs); + + case (DAE.CALL(path = Absyn.IDENT(name="pre"), expLst={DAE.CREF(componentRef=cr)}),_) algorithm + cr := ComponentReference.crefPrefixPre(cr); + crefs := List.unionEltOnTrue(cr,inCrefs,ComponentReference.crefEqual); + then (inExp, false, crefs); + + case (DAE.CALL(path = Absyn.IDENT(name="previous"), expLst={DAE.CREF(componentRef=cr)}),_) algorithm + cr := ComponentReference.crefPrefixPrevious(cr); + crefs := List.unionEltOnTrue(cr,inCrefs,ComponentReference.crefEqual); + then (inExp, false, crefs); + + case (DAE.CALL(path = Absyn.IDENT(name="start"), expLst={DAE.CREF(componentRef=cr)}),_) algorithm + Error.addInternalError(getInstanceName() + " - Found a start call expression " + ExpressionDump.printExpStr(inExp), sourceInfo()); + cr := ComponentReference.crefPrefixStart(cr); + crefs := List.unionEltOnTrue(cr,inCrefs,ComponentReference.crefEqual); + then (inExp, false, crefs); + else (inExp,true,inCrefs); + end match; +end traversingComponentRefFinderDerPreStart; public function extractUniqueCrefsFromStatmentS "authot mahge: Extracts all unique ComponentRef from Statments." @@ -6373,26 +6433,6 @@ algorithm end match; end traversingComponentRefPresent; -public function traversingComponentRefFinder " -Author: BZ 2008-06 -Exp traverser that Union the current ComponentRef with list if it is already there. -Returns a list containing, unique, all componentRef in an Expression." - input DAE.Exp inExp; - input list inCrefs; - output DAE.Exp outExp; - output list crefs; -algorithm - (outExp,crefs) := match (inExp,inCrefs) - local - ComponentRef cr; - case (DAE.CREF(componentRef=cr), crefs) - equation - crefs = List.unionEltOnTrue(cr,crefs,ComponentReference.crefEqual); - then (inExp,crefs); - else (inExp,inCrefs); - end match; -end traversingComponentRefFinder; - public function traversingComponentRefFinderNoPreDer " Author: BZ 2008-06 Exp traverser that Union the current ComponentRef with list if it is already there. @@ -6417,40 +6457,6 @@ algorithm end match; end traversingComponentRefFinderNoPreDer; -public function traversingDerAndComponentRefFinder " -Author: Frenkel TUD 2012-06 -Exp traverser that Union the current ComponentRef with list if it is already there. -Returns a list containing, unique, all componentRef in an Expression and a second list -containing all componentRef from a der function." - input tuple,list>> inExp; - output tuple,list>> outExp; -algorithm - outExp := matchcontinue(inExp) - local - list crefs,dcrefs; - ComponentRef cr; - Type ty; - DAE.Exp e; - - case((e as DAE.CREF(cr,_), (crefs,dcrefs))) - equation - crefs = List.unionEltOnTrue(cr,crefs,ComponentReference.crefEqual); - // e = makeCrefExp(cr,ty); - then - ((e, (crefs,dcrefs) )); - - case((e as DAE.CALL(path = Absyn.IDENT(name = "der"),expLst={DAE.CREF(cr,_)}), (crefs,dcrefs))) - equation - dcrefs = List.unionEltOnTrue(cr,dcrefs,ComponentReference.crefEqual); - // e = makeCrefExp(cr,ty); - then - ((e, (crefs,dcrefs) )); - - else inExp; - - end matchcontinue; -end traversingDerAndComponentRefFinder; - public function expHasCref "author: Frenkel TUD 2011-04 returns true if the expression contains the cref" input DAE.Exp inExp; @@ -11730,6 +11736,7 @@ algorithm end matchcontinue; end isCrefListWithEqualIdents; +/* protected function traverseExpDerPreStart " TODO: REPLACE THIS ABOMINATION WITH A BETTER traverseExpBottomUp @@ -12106,6 +12113,7 @@ algorithm then (expl,ext_arg); end match; end traverseExpDerPreStartList; +*/ public function renameExpCrefIdent input DAE.Exp inExp; diff --git a/OMCompiler/Compiler/SimCode/SerializeTaskSystemInfo.mo b/OMCompiler/Compiler/SimCode/SerializeTaskSystemInfo.mo new file mode 100644 index 00000000000..177dc13d277 --- /dev/null +++ b/OMCompiler/Compiler/SimCode/SerializeTaskSystemInfo.mo @@ -0,0 +1,962 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-2014, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR + * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from OSMC, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ + +encapsulated package SerializeTaskSystemInfo + +import Absyn; +import BackendDAE; +import DAE; +import SimCode; + +protected +import Algorithm; +import DAEDump; +import Error; +import Expression; +import File; +import File.Escape.JSON; +import writeCref = ComponentReference.writeCref; +import expStr = ExpressionDump.printExpStr; +import List; +import SimCodeUtil; +import SimCodeFunctionUtil; +import Util; + +public +function serializeParMod + input SimCode.SimCode code; + input Boolean withOperations; + output String fileName; +algorithm + (true,fileName) := serializeParModWork(code,withOperations); +end serializeParMod; + +protected +function serializeParModWork "Always succeeds in order to clean-up external objects" + input SimCode.SimCode code; + input Boolean withOperations; + output Boolean success; // We always need to return in order to clean up external objects + output String fileName; +protected + File.File file = File.File(); + SimCode.ModelInfo mi; + SimCodeVar.SimVars vars; +algorithm + try + SimCode.SIMCODE(modelInfo=mi as SimCode.MODELINFO(vars=vars)) := code; + fileName := code.fileNamePrefix + "_ode.json"; + File.open(file,fileName,File.Mode.Write); + File.write(file, "{\"format\":\"ParModlica task system info\",\"version\":1,\n\"info\":{\"name\":"); + serializePath(file, mi.name); + File.write(file, ",\"description\":\""); + File.writeEscape(file, mi.description, escape=JSON); + File.write(file, "\"},\n\"ode-equations\":["); + // Handle no comma for the first equation + File.write(file,"{\"eqIndex\":0,\"tag\":\"dummy\"}"); + min(serializeEquation(file,eq,"regular",withOperations) for eq in SimCodeUtil.sortEqSystems(List.flatten(code.odeEquations))); + File.write(file, "\n]\n}"); + // file.close(); + success := true; + else + Error.addInternalError("SerializeTaskSystemInfo.serializeParModWork failed", sourceInfo()); + success := false; + end try; +end serializeParModWork; + +function serializeEquation + input File.File file; + input SimCode.SimEqSystem eq; + input String section; + input Boolean withOperations; + input Integer parent = 0 "No parent"; + input Boolean first = false; + input Integer assign_type = 0 "0: normal equation, 1: torn equation, 2: jacobian equation"; + output Boolean success; +algorithm + if not first then + File.write(file, ","); + end if; + success := match eq + local + Integer i,j; + DAE.Statement stmt; + list eqs,jeqs,constantEqns; + SimCode.LinearSystem lSystem, atL; + SimCode.NonlinearSystem nlSystem, atNL; + BackendDAE.WhenOperator whenOp; + list crefs; + + case SimCode.SES_RESIDUAL() equation + File.write(file, "\n{\"eqIndex\":"); + File.writeInt(file, eq.index); + if parent <> 0 then + File.write(file, ",\"parent\":"); + File.writeInt(file, parent); + end if; + File.write(file, ",\"section\":\""); + File.write(file, section); + File.write(file, "\",\"tag\":\"residual\",\"uses\":["); + serializeUses(file,Expression.extractUniqueCrefsFromExpDerPreStart(eq.exp)); + File.write(file, "],\"equation\":[\""); + File.writeEscape(file,expStr(eq.exp),escape=JSON); + File.write(file, "\"],\"source\":"); + serializeSource(file,eq.source,withOperations); + File.write(file, "}"); + then true; + + case SimCode.SES_SIMPLE_ASSIGN() equation + File.write(file, "\n{\"eqIndex\":"); + File.writeInt(file, eq.index); + if parent <> 0 then + File.write(file, ",\"parent\":"); + File.writeInt(file, parent); + end if; + File.write(file, ",\"section\":\""); + File.write(file, section); + if (assign_type==1) then + File.write(file, "\",\"tag\":\"torn\",\"defines\":[\""); + elseif (assign_type==2) then + File.write(file, "\",\"tag\":\"jacobian\",\"defines\":[\""); + else + File.write(file, "\",\"tag\":\"assign\",\"defines\":[\""); + end if; + writeCref(file,eq.cref,escape=JSON); + File.write(file, "\"],\"uses\":["); + serializeUses(file,Expression.extractUniqueCrefsFromExpDerPreStart(eq.exp)); + File.write(file, "],\"equation\":[\""); + File.writeEscape(file,expStr(eq.exp),escape=JSON); + File.write(file, "\"],\"source\":"); + serializeSource(file,eq.source,withOperations); + File.write(file, "}"); + then true; + + case SimCode.SES_SIMPLE_ASSIGN_CONSTRAINTS() equation + File.write(file, "\n{\"eqIndex\":"); + File.writeInt(file, eq.index); + if parent <> 0 then + File.write(file, ",\"parent\":"); + File.writeInt(file, parent); + end if; + File.write(file, ",\"section\":\""); + File.write(file, section); + if (assign_type==1) then + File.write(file, "\",\"tag\":\"torn\",\"defines\":[\""); + elseif (assign_type==2) then + File.write(file, "\",\"tag\":\"jacobian\",\"defines\":[\""); + else + File.write(file, "\",\"tag\":\"assign\",\"defines\":[\""); + end if; + writeCref(file,eq.cref,escape=JSON); + File.write(file, "\"],\"uses\":["); + serializeUses(file,Expression.extractUniqueCrefsFromExpDerPreStart(eq.exp)); + File.write(file, "],\"equation\":[\""); + File.writeEscape(file,expStr(eq.exp),escape=JSON); + File.write(file, "\"],\"source\":"); + serializeSource(file,eq.source,withOperations); + File.write(file, "}"); + then true; + + case SimCode.SES_ARRAY_CALL_ASSIGN() equation + File.write(file, "\n{\"eqIndex\":"); + File.writeInt(file, eq.index); + if parent <> 0 then + File.write(file, ",\"parent\":"); + File.writeInt(file, parent); + end if; + File.write(file, ",\"section\":\""); + File.write(file, section); + if (assign_type==1) then + File.write(file, "\",\"tag\":\"torn\",\"defines\":[\""); + elseif (assign_type==2) then + File.write(file, "\",\"tag\":\"jacobian\",\"defines\":[\""); + else + File.write(file, "\",\"tag\":\"assign\",\"defines\":[\""); + end if; + writeCref(file,Expression.expCref(eq.lhs),escape=JSON); + File.write(file, "\"],\"uses\":["); + serializeUses(file,Expression.extractUniqueCrefsFromExpDerPreStart(eq.exp)); + File.write(file, "],\"equation\":[\""); + File.writeEscape(file,expStr(eq.exp),escape=JSON); + File.write(file, "\"],\"source\":"); + serializeSource(file,eq.source,withOperations); + File.write(file, "}"); + then true; + + // no dynamic tearing + case SimCode.SES_LINEAR(lSystem = lSystem as SimCode.LINEARSYSTEM(), alternativeTearing = NONE()) equation + i = listLength(lSystem.beqs); + j = listLength(lSystem.simJac); + eqs = SimCodeUtil.sortEqSystems(lSystem.residual); + jeqs = match lSystem.jacobianMatrix + case SOME(SimCode.JAC_MATRIX(columns={SimCode.JAC_COLUMN(columnEqns=jeqs,constantEqns=constantEqns)})) then SimCodeUtil.sortEqSystems(listAppend(jeqs,constantEqns)); + else {}; + end match; + + File.write(file, "\n{\"eqIndex\":"); + File.writeInt(file, lSystem.index); + + if parent <> 0 then + File.write(file, ",\"parent\":"); + File.writeInt(file, parent); + end if; + File.write(file, ",\"section\":\""); + File.write(file, section); + + // Ax=b + if lSystem.tornSystem then + File.write(file, "\",\"tag\":\"tornsystem\""); + else + File.write(file, "\",\"tag\":\"system\""); + end if; + + File.write(file, ",\"display\":\"linear\",\"unknowns\":" + intString(lSystem.nUnknowns) + ",\"defines\":["); + serializeUses(file,list(match v case SimCodeVar.SIMVAR() then v.name; end match + for v in lSystem.vars)); + File.write(file, "],\"equation\":[{\"size\":"); + File.write(file,intString(i)); + if i <> 0 then + File.write(file,",\"density\":"); + File.writeReal(file,j / (i*i),format="%.2f"); + end if; + File.write(file,",\"A\":["); + serializeList1(file,lSystem.simJac,withOperations,serializeLinearCell); + File.write(file,"],\"b\":["); + serializeList(file,lSystem.beqs,serializeExp); + File.write(file,"]}]"); + + File.write(file, ",\n\"internal-equations\":["); + + if not listEmpty(eqs) then + serializeEquation(file,listHead(eqs),section,withOperations,parent=lSystem.index,first=true,assign_type=if lSystem.tornSystem then 1 else 0); + min(serializeEquation(file,e,section,withOperations,parent=lSystem.index,assign_type=if lSystem.tornSystem then 1 else 0) for e in List.rest(eqs)); + end if; + File.write(file, "\n]"); + + File.write(file, ",\n\"jacobian-equations\":["); + if not listEmpty(jeqs) then + serializeEquation(file,listHead(jeqs),section,withOperations,parent=lSystem.index,first=true,assign_type=2); + min(serializeEquation(file,e,section,withOperations,parent=lSystem.index,assign_type=2) for e in List.rest(jeqs)); + end if; + + File.write(file, "\n]}"); + then true; + + // dynamic tearing + case SimCode.SES_LINEAR(lSystem = lSystem as SimCode.LINEARSYSTEM(), alternativeTearing = SOME(atL as SimCode.LINEARSYSTEM())) equation + // for strict tearing set + i = listLength(lSystem.beqs); + j = listLength(lSystem.simJac); + + eqs = SimCodeUtil.sortEqSystems(lSystem.residual); + if not listEmpty(eqs) then + serializeEquation(file,listHead(eqs),section,withOperations,parent=lSystem.index,first=true,assign_type=if lSystem.tornSystem then 1 else 0); + min(serializeEquation(file,e,section,withOperations,parent=lSystem.index,assign_type=if lSystem.tornSystem then 1 else 0) for e in List.rest(eqs)); + end if; + + jeqs = match lSystem.jacobianMatrix + case SOME(SimCode.JAC_MATRIX(columns={SimCode.JAC_COLUMN(columnEqns=jeqs,constantEqns=constantEqns)})) then SimCodeUtil.sortEqSystems(listAppend(jeqs,constantEqns)); + else {}; + end match; + if not listEmpty(jeqs) then + File.write(file, ","); + serializeEquation(file,listHead(jeqs),section,withOperations,parent=lSystem.index,first=true,assign_type=2); + min(serializeEquation(file,e,section,withOperations,parent=lSystem.index,assign_type=2) for e in List.rest(jeqs)); + end if; + + if listEmpty(eqs) and listEmpty(jeqs) then + File.write(file, "\n{\"eqIndex\":"); + else + File.write(file, ",\n{\"eqIndex\":"); + end if; + File.writeInt(file, lSystem.index); + if parent <> 0 then + File.write(file, ",\"parent\":"); + File.writeInt(file, parent); + end if; + File.write(file, ",\"section\":\""); + File.write(file, section); + + // Ax=b + if lSystem.tornSystem then + File.write(file, "\",\"tag\":\"tornsystem-dynamic\""); + else + File.write(file, "\",\"tag\":\"system-dynamic\""); + end if; + + File.write(file, ",\"display\":\"linear\",\"unknowns\":" + intString(lSystem.nUnknowns) + ",\"defines\":["); + serializeUses(file,list(match v case SimCodeVar.SIMVAR() then v.name; end match + for v in lSystem.vars)); + File.write(file, "],\"equation\":[{\"size\":"); + File.write(file,intString(i)); + if i <> 0 then + File.write(file,",\"density\":"); + File.writeReal(file,j / (i*i),format="%.2f"); + end if; + File.write(file,",\"A\":["); + serializeList1(file,lSystem.simJac,withOperations,serializeLinearCell); + File.write(file,"],\"b\":["); + serializeList(file,lSystem.beqs,serializeExp); + File.write(file,"]}]},"); + + // for casual tearing set + i = listLength(atL.beqs); + j = listLength(atL.simJac); + + eqs = SimCodeUtil.sortEqSystems(atL.residual); + if not listEmpty(eqs) then + serializeEquation(file,listHead(eqs),section,withOperations,parent=atL.index,first=true,assign_type=if atL.tornSystem then 1 else 0); + min(serializeEquation(file,e,section,withOperations,parent=atL.index,assign_type=if atL.tornSystem then 1 else 0) for e in List.rest(eqs)); + end if; + + jeqs = match atL.jacobianMatrix + case SOME(SimCode.JAC_MATRIX(columns={SimCode.JAC_COLUMN(columnEqns=jeqs,constantEqns=constantEqns)})) then SimCodeUtil.sortEqSystems(listAppend(jeqs,constantEqns)); + else {}; + end match; + if not listEmpty(jeqs) then + File.write(file, ","); + serializeEquation(file,listHead(jeqs),section,withOperations,parent=atL.index,first=true,assign_type=2); + min(serializeEquation(file,e,section,withOperations,parent=atL.index,assign_type=2) for e in List.rest(jeqs)); + end if; + + if listEmpty(eqs) and listEmpty(jeqs) then + File.write(file, "\n{\"eqIndex\":"); + else + File.write(file, ",\n{\"eqIndex\":"); + end if; + File.writeInt(file, atL.index); + if parent <> 0 then + File.write(file, ",\"parent\":"); + File.writeInt(file, parent); + end if; + File.write(file, ",\"section\":\""); + File.write(file, section); + + // Ax=b + if atL.tornSystem then + File.write(file, "\",\"tag\":\"tornsystem\""); + else + File.write(file, "\",\"tag\":\"system\""); + end if; + + File.write(file, ",\"display\":\"linear\",\"unknowns\":" + intString(atL.nUnknowns) + ",\"defines\":["); + serializeUses(file,list(match v case SimCodeVar.SIMVAR() then v.name; end match + for v in atL.vars)); + File.write(file, "],\"equation\":[{\"size\":"); + File.write(file,intString(i)); + if i <> 0 then + File.write(file,",\"density\":"); + File.writeReal(file,j / (i*i),format="%.2f"); + end if; + File.write(file,",\"A\":["); + serializeList1(file,atL.simJac,withOperations,serializeLinearCell); + File.write(file,"],\"b\":["); + serializeList(file,atL.beqs,serializeExp); + File.write(file,"]}]}"); + then true; + + case SimCode.SES_ALGORITHM(statements={stmt as DAE.STMT_ASSIGN()}) equation + File.write(file, "\n{\"eqIndex\":"); + File.writeInt(file, eq.index); + if parent <> 0 then + File.write(file, ",\"parent\":"); + File.writeInt(file, parent); + end if; + File.write(file, ",\"section\":\""); + File.write(file, section + "\",\"tag\":\"algorithm\",\"defines\":[\""); + writeCref(file, Expression.expCref(stmt.exp1),escape=JSON); + File.write(file, "\"],\"uses\":["); + serializeUses(file,Expression.extractUniqueCrefsFromExpDerPreStart(stmt.exp)); + File.write(file, "],\"equation\":["); + serializeList(file,eq.statements,serializeStatement); + File.write(file, "],\"source\":"); + serializeSource(file,Algorithm.getStatementSource(stmt),withOperations); + File.write(file, "}"); + then true; + + case SimCode.SES_ALGORITHM(statements=stmt::_) equation + File.write(file, "\n{\"eqIndex\":"); + File.writeInt(file, eq.index); + if parent <> 0 then + File.write(file, ",\"parent\":"); + File.writeInt(file, parent); + end if; + File.write(file, ",\"section\":\""); + File.write(file, section + "\",\"tag\":\"algorithm\",\"equation\":["); + serializeList(file,eq.statements,serializeStatement); + File.write(file, "],\"source\":"); + serializeSource(file,Algorithm.getStatementSource(stmt),withOperations); + File.write(file, "}"); + then true; + + case SimCode.SES_INVERSE_ALGORITHM(statements=stmt::_) equation + File.write(file, "\n{\"eqIndex\":"); + File.writeInt(file, eq.index); + if parent <> 0 then + File.write(file, ",\"parent\":"); + File.writeInt(file, parent); + end if; + File.write(file, ",\"section\":\""); + File.write(file, section + "\",\"tag\":\"algorithm\",\"equation\":["); + serializeList(file,eq.statements,serializeStatement); + File.write(file, "],\"source\":"); + serializeSource(file,Algorithm.getStatementSource(stmt),withOperations); + File.write(file, "}"); + then true; + + // no dynamic tearing + case SimCode.SES_NONLINEAR(nlSystem = nlSystem as SimCode.NONLINEARSYSTEM(), alternativeTearing = NONE()) equation + eqs = SimCodeUtil.sortEqSystems(nlSystem.eqs); + jeqs = match nlSystem.jacobianMatrix + case SOME(SimCode.JAC_MATRIX(columns={SimCode.JAC_COLUMN(columnEqns=jeqs,constantEqns=constantEqns)})) then SimCodeUtil.sortEqSystems(listAppend(jeqs,constantEqns)); + else {}; + end match; + + File.write(file, "\n{\"eqIndex\":"); + File.writeInt(file, nlSystem.index); + + if parent <> 0 then + File.write(file, ",\"parent\":"); + File.writeInt(file, parent); + end if; + File.write(file, ",\"section\":\""); + File.write(file, section); + + if nlSystem.tornSystem then + File.write(file, "\",\"tag\":\"tornsystem\""); + else + File.write(file, "\",\"tag\":\"system\""); + end if; + + File.write(file, ",\"display\":\"non-linear\",\"unknowns\":" + intString(nlSystem.nUnknowns) + ",\"defines\":["); + serializeUses(file,nlSystem.crefs); + File.write(file, "],\"equation\":[["); + serializeList(file,eqs,serializeEquationIndex); + File.write(file, "],["); + serializeList(file,jeqs,serializeEquationIndex); + File.write(file, "]]"); + + File.write(file, ",\n\"internal-equations\":["); + + if not listEmpty(eqs) then + serializeEquation(file,listHead(eqs),section,withOperations,parent=nlSystem.index,first=true,assign_type=if nlSystem.tornSystem then 1 else 0); + min(serializeEquation(file,e,section,withOperations,parent=nlSystem.index,assign_type=if nlSystem.tornSystem then 1 else 0) for e in List.rest(eqs)); + end if; + File.write(file, "\n]"); + + File.write(file, ",\n\"jacobian-equations\":["); + if not listEmpty(jeqs) then + serializeEquation(file,listHead(jeqs),section,withOperations,parent=nlSystem.index,first=true,assign_type=2); + min(serializeEquation(file,e,section,withOperations,parent=nlSystem.index,assign_type=2) for e in List.rest(jeqs)); + end if; + + File.write(file, "\n]}"); + then true; + + // dynamic tearing + case SimCode.SES_NONLINEAR(nlSystem = nlSystem as SimCode.NONLINEARSYSTEM(), alternativeTearing = SOME(atNL as SimCode.NONLINEARSYSTEM())) equation + // for strict tearing set + eqs = SimCodeUtil.sortEqSystems(nlSystem.eqs); + serializeEquation(file,listHead(eqs),section,withOperations,parent=nlSystem.index,first=true,assign_type=if nlSystem.tornSystem then 1 else 0); + min(serializeEquation(file,e,section,withOperations,parent=nlSystem.index,assign_type=if nlSystem.tornSystem then 1 else 0) for e in List.rest(eqs)); + + jeqs = match nlSystem.jacobianMatrix + case SOME(SimCode.JAC_MATRIX(columns={SimCode.JAC_COLUMN(columnEqns=jeqs,constantEqns=constantEqns)})) then SimCodeUtil.sortEqSystems(listAppend(jeqs,constantEqns)); + else {}; + end match; + if not listEmpty(jeqs) then + File.write(file, ","); + serializeEquation(file,listHead(jeqs),section,withOperations,parent=nlSystem.index,first=true,assign_type=2); + min(serializeEquation(file,e,section,withOperations,parent=nlSystem.index,assign_type=2) for e in List.rest(jeqs)); + end if; + + File.write(file, ",\n{\"eqIndex\":"); + File.writeInt(file, nlSystem.index); + if parent <> 0 then + File.write(file, ",\"parent\":"); + File.writeInt(file, parent); + end if; + File.write(file, ",\"section\":\""); + File.write(file, section); + + if nlSystem.tornSystem then + File.write(file, "\",\"tag\":\"tornsystem\""); + else + File.write(file, "\",\"tag\":\"system\""); + end if; + + File.write(file, ",\"display\":\"non-linear\",\"unknowns\":" + intString(nlSystem.nUnknowns) + ",\"defines\":["); + serializeUses(file,nlSystem.crefs); + File.write(file, "],\"equation\":[["); + serializeList(file,eqs,serializeEquationIndex); + File.write(file, "],["); + serializeList(file,jeqs,serializeEquationIndex); + File.write(file, "]]},"); + + // for casual tearing set + eqs = SimCodeUtil.sortEqSystems(atNL.eqs); + serializeEquation(file,listHead(eqs),section,withOperations,parent=atNL.index,first=true,assign_type=if atNL.tornSystem then 1 else 0); + min(serializeEquation(file,e,section,withOperations,parent=atNL.index,assign_type=if atNL.tornSystem then 1 else 0) for e in List.rest(eqs)); + + jeqs = match atNL.jacobianMatrix + case SOME(SimCode.JAC_MATRIX(columns={SimCode.JAC_COLUMN(columnEqns=jeqs,constantEqns=constantEqns)})) then SimCodeUtil.sortEqSystems(listAppend(jeqs,constantEqns)); + else {}; + end match; + if not listEmpty(jeqs) then + File.write(file, ","); + serializeEquation(file,listHead(jeqs),section,withOperations,parent=atNL.index,first=true,assign_type=2); + min(serializeEquation(file,e,section,withOperations,parent=atNL.index,assign_type=2) for e in List.rest(jeqs)); + end if; + + File.write(file, ",\n{\"eqIndex\":"); + File.writeInt(file, atNL.index); + if parent <> 0 then + File.write(file, ",\"parent\":"); + File.writeInt(file, parent); + end if; + File.write(file, ",\"section\":\""); + File.write(file, section); + + if atNL.tornSystem then + File.write(file, "\",\"tag\":\"tornsystem\""); + else + File.write(file, "\",\"tag\":\"system\""); + end if; + + File.write(file, ",\"display\":\"non-linear\",\"unknowns\":" + intString(atNL.nUnknowns) + ",\"defines\":["); + serializeUses(file,atNL.crefs); + File.write(file, "],\"equation\":[["); + serializeList(file,eqs,serializeEquationIndex); + File.write(file, "],["); + serializeList(file,jeqs,serializeEquationIndex); + File.write(file, "]]}"); + then true; + + case SimCode.SES_IFEQUATION() equation + eqs = listAppend(List.flatten(list(Util.tuple22(e) for e in eq.ifbranches)), eq.elsebranch); + serializeEquation(file,listHead(eqs),section,withOperations,first=true); + min(serializeEquation(file,e,section,withOperations) for e in List.rest(eqs)); + File.write(file, ",\n{\"eqIndex\":"); + File.writeInt(file, eq.index); + if parent <> 0 then + File.write(file, ",\"parent\":"); + File.writeInt(file, parent); + end if; + File.write(file, ",\"section\":\""); + File.write(file, section); + File.write(file, "\",\"tag\":\"if-equation\",\"display\":\"if-equation\",\"equation\":["); + serializeList(file,eq.ifbranches,serializeIfBranch); + File.write(file, ","); + serializeIfBranch(file,(DAE.BCONST(true),eq.elsebranch)); + File.write(file, "]}"); + then true; + + case SimCode.SES_MIXED() + algorithm + serializeEquation(file,eq.cont,section,withOperations,first=true); + min(serializeEquation(file,e,section,withOperations) for e in eq.discEqs); + File.write(file, ",\n{\"eqIndex\":"); + File.writeInt(file, eq.index); + if parent <> 0 then + File.write(file, ",\"parent\":"); + File.writeInt(file, parent); + end if; + File.write(file, ",\"section\":\""); + File.write(file, section); + File.write(file, "\",\"tag\":\"container\",\"display\":\"mixed\",\"defines\":["); + serializeUses(file,list(SimCodeFunctionUtil.varName(v) for v in eq.discVars)); + File.write(file, "],\"equation\":["); + serializeEquationIndex(file,eq.cont); + for e1 in eq.discEqs loop + File.write(file,","); + serializeEquationIndex(file,e1); + end for; + File.write(file, "]}"); + then true; + + case SimCode.SES_WHEN() algorithm + File.write(file, "\n{\"eqIndex\":"); + File.writeInt(file, eq.index); + if parent <> 0 then + File.write(file, ",\"parent\":"); + File.writeInt(file, parent); + end if; + File.write(file, ",\"section\":\""); + File.write(file, section); + for whenOps in eq.whenStmtLst loop + _ := match whenOps + case whenOp as BackendDAE.ASSIGN() equation + File.write(file, "\",\"tag\":\"when\",\"defines\":["); + serializeExp(file,whenOp.left); + File.write(file, "],\"uses\":["); + serializeUses(file,List.union(eq.conditions,Expression.extractUniqueCrefsFromExpDerPreStart(whenOp.right))); + File.write(file, "],\"equation\":["); + serializeExp(file,whenOp.right); + File.write(file, "],\"source\":"); + serializeSource(file,eq.source,withOperations); + File.write(file, "}"); + then (); + case whenOp as BackendDAE.REINIT() equation + File.write(file, "\",\"tag\":\"when\",\"defines\":["); + serializeCref(file,whenOp.stateVar); + File.write(file, "],\"uses\":["); + serializeUses(file,List.union(eq.conditions,Expression.extractUniqueCrefsFromExpDerPreStart(whenOp.value))); + File.write(file, "],\"equation\":["); + serializeExp(file,whenOp.value); + File.write(file, "],\"source\":"); + serializeSource(file,eq.source,withOperations); + File.write(file, "}"); + then (); + case whenOp as BackendDAE.ASSERT() equation + File.write(file, "\",\"tag\":\"when\""); + File.write(file, ",\"uses\":["); + crefs = listAppend(Expression.extractUniqueCrefsFromExpDerPreStart(whenOp.condition), Expression.extractUniqueCrefsFromExpDerPreStart(whenOp.message)); + serializeUses(file,List.union(eq.conditions,crefs)); + File.write(file, "],\"equation\":["); + serializeExp(file,whenOp.message); + File.write(file, "],\"source\":"); + serializeSource(file,eq.source,withOperations); + File.write(file, "}"); + then (); + case whenOp as BackendDAE.TERMINATE() equation + File.write(file, "\",\"tag\":\"when\""); + File.write(file, ",\"uses\":["); + serializeUses(file,List.union(eq.conditions,Expression.extractUniqueCrefsFromExpDerPreStart(whenOp.message))); + File.write(file, "],\"equation\":["); + serializeExp(file,whenOp.message); + File.write(file, "],\"source\":"); + serializeSource(file,eq.source,withOperations); + File.write(file, "}"); + then (); + case whenOp as BackendDAE.NORETCALL() equation + File.write(file, "\",\"tag\":\"when\""); + File.write(file, ",\"uses\":["); + serializeUses(file,List.union(eq.conditions,Expression.extractUniqueCrefsFromExpDerPreStart(whenOp.exp))); + File.write(file, "],\"equation\":["); + serializeExp(file,whenOp.exp); + File.write(file, "],\"source\":"); + serializeSource(file,eq.source,withOperations); + File.write(file, "}"); + then (); + end match; + end for; + _ := match eq.elseWhen + local + SimCode.SimEqSystem e; + case SOME(e) equation if SimCodeUtil.simEqSystemIndex(e) <>0 then serializeEquation(file,e,section,withOperations); end if; then (); + else (); + end match; + then true; + + case SimCode.SES_FOR_LOOP() equation + File.write(file, "\n{\"eqIndex\":"); + File.writeInt(file, eq.index); + if parent <> 0 then + File.write(file, ",\"parent\":"); + File.writeInt(file, parent); + end if; + File.write(file, ",\"section\":\""); + File.write(file, section); + if (assign_type==1) then + File.write(file, "\",\"tag\":\"torn\",\"defines\":[\""); + elseif (assign_type==2) then + File.write(file, "\",\"tag\":\"jacobian\",\"defines\":[\""); + else + File.write(file, "\",\"tag\":\"assign\",\"defines\":[\""); + end if; + writeCref(file,eq.cref,escape=JSON); + File.write(file, "\"],\"uses\":["); + serializeUses(file,Expression.extractUniqueCrefsFromExpDerPreStart(eq.exp)); + File.write(file, "],\"equation\":[\""); + File.writeEscape(file,expStr(eq.exp),escape=JSON); + File.write(file, "\"],\"source\":"); + serializeSource(file,eq.source,withOperations); + File.write(file, "}"); + then true; + + case SimCode.SES_ALIAS() equation + File.write(file, "\n{\"eqIndex\":"); + File.writeInt(file, eq.index); + File.write(file, ",\"tag\":\"alias\",\"equation\":["); + File.writeInt(file, eq.aliasOf); + File.write(file, "],\"section\":\""); + File.write(file, section); + File.write(file, "\"}"); + then true; + + else equation + Error.addInternalError("serializeEquation failed: " + anyString(eq), sourceInfo()); + then fail(); + end match; +end serializeEquation; + +function serializeLinearCell + input File.File file; + input tuple cell; + input Boolean withOperations; +algorithm + _ := match cell + local + Integer i,j; + SimCode.SimEqSystem eq; + case (i,j,eq as SimCode.SES_RESIDUAL()) + equation + File.write(file,"{\"row\":"); + File.write(file,intString(i)); + File.write(file,",\"column\":"); + File.write(file,intString(j)); + File.write(file,",\"exp\":\""); + File.writeEscape(file,expStr(eq.exp),escape=JSON); + File.write(file,"\",\"source\":"); + serializeSource(file,eq.source,withOperations); + File.write(file,"}"); + then (); + else + equation + Error.addMessage(Error.INTERNAL_ERROR,{"SerializeTaskSystemInfo.serializeLinearCell failed. Expected only SES_RESIDUAL as input."}); + then fail(); + end match; +end serializeLinearCell; + +function serializeUses + input File.File file; + input list crefs; +algorithm + _ := match crefs + local + DAE.ComponentRef cr; + list rest; + case {} then (); + case {cr} + equation + File.write(file, "\""); + writeCref(file, cr, escape=JSON); + File.write(file, "\""); + then (); + case cr::rest + equation + File.write(file, "\""); + writeCref(file, cr, escape=JSON); + File.write(file, "\","); + serializeUses(file,rest); + then (); + end match; +end serializeUses; + +function serializeStatement + input File.File file; + input DAE.Statement stmt; +algorithm + File.write(file,"\""); + File.writeEscape(file, System.trim(DAEDump.ppStatementStr(stmt)), escape=JSON); + File.write(file,"\""); +end serializeStatement; + +function serializeList + input File.File file; + input list lst; + input FuncType func; + + partial function FuncType + input File.File file; + input ArgType a; + end FuncType; +algorithm + _ := match lst + local + ArgType a; + list rest; + case {} then (); + case {a} + equation + func(file,a); + then (); + case a::rest + equation + func(file,a); + File.write(file, ","); + serializeList(file,rest,func); + then (); + end match; +end serializeList; + +function serializeList1 + input File.File file; + input list lst; + input Extra extra; + input FuncType func; + + partial function FuncType + input File.File file; + input ArgType a; + input Extra extra; + end FuncType; +algorithm + _ := match lst + local + ArgType a; + list rest; + case {} then (); + case {a} + equation + func(file,a,extra); + then (); + case a::rest + equation + func(file,a,extra); + File.write(file, ","); + serializeList1(file,rest,extra,func); + then (); + end match; +end serializeList1; + +function serializeExp + input File.File file; + input DAE.Exp exp; +algorithm + File.write(file, "\""); + File.writeEscape(file, expStr(exp), escape=JSON); + File.write(file, "\""); +end serializeExp; + +function serializeCref + input File.File file; + input DAE.ComponentRef cr; +algorithm + File.write(file, "\""); + writeCref(file, cr, escape=JSON); + File.write(file, "\""); +end serializeCref; + +function serializeString + input File.File file; + input String string; +algorithm + File.write(file, "\""); + File.writeEscape(file, string, escape=JSON); + File.write(file, "\""); +end serializeString; + +function serializePath + input File.File file; + input Absyn.Path path; +protected + Absyn.Path p=path; + Boolean b=true; +algorithm + File.write(file, "\""); + while b loop + (p,b) := match p + case Absyn.IDENT() + algorithm + File.writeEscape(file, p.name, escape=JSON); + then (p,false); + case Absyn.QUALIFIED() + algorithm + File.writeEscape(file, p.name, escape=JSON); + File.write(file, "."); + then (p.path,true); + case Absyn.FULLYQUALIFIED() + then (p.path,true); + end match; + end while; + File.write(file, "\""); +end serializePath; + +function serializeEquationIndex + input File.File file; + input SimCode.SimEqSystem eq; +algorithm + File.writeInt(file, SimCodeUtil.simEqSystemIndex(eq)); +end serializeEquationIndex; + +function serializeIfBranch + input File.File file; + input tuple> branch; +protected + DAE.Exp exp; + list eqs; +algorithm + (exp,eqs) := branch; + File.write(file,"["); + serializeExp(file,exp); + File.write(file,","); + serializeList(file,eqs,serializeEquationIndex); + File.write(file,"]"); +end serializeIfBranch; + +function writeEqExpStr + input File.File file; + input DAE.EquationExp eqExp; +algorithm + _ := match eqExp + case DAE.PARTIAL_EQUATION() + equation + File.writeEscape(file,expStr(eqExp.exp),escape=JSON); + then (); + case DAE.RESIDUAL_EXP() + equation + File.write(file,"0 = "); + File.writeEscape(file,expStr(eqExp.exp),escape=JSON); + then (); + case DAE.EQUALITY_EXPS() + equation + File.writeEscape(file,expStr(eqExp.lhs),escape=JSON); + File.write(file," = "); + File.writeEscape(file,expStr(eqExp.rhs),escape=JSON); + then (); + end match; +end writeEqExpStr; + +function serializeFunction + input File.File file; + input SimCodeFunction.Function func; +algorithm + File.write(file, "\n"); + serializePath(file, SimCodeUtil.functionPath(func)); +end serializeFunction; + +function serializeSource + input File.File file; + input DAE.ElementSource source; + input Boolean withOperations; +protected + SourceInfo info; + list paths,typeLst; + list partOfLst; + DAE.ComponentPrefix instance; + Integer i; + list operations; +algorithm + File.write(file,"{}"); +end serializeSource; + +annotation(__OpenModelica_Interface="backend"); +end SerializeTaskSystemInfo; diff --git a/OMCompiler/Compiler/SimCode/SimCodeFunctionUtil.mo b/OMCompiler/Compiler/SimCode/SimCodeFunctionUtil.mo index 223dfae2a13..88909c12ab6 100644 --- a/OMCompiler/Compiler/SimCode/SimCodeFunctionUtil.mo +++ b/OMCompiler/Compiler/SimCode/SimCodeFunctionUtil.mo @@ -2644,6 +2644,9 @@ algorithm (if Flags.isSet(Flags.HPCOM) then "-fopenmp" else ""); cflags := if stringEq(Config.simCodeTarget(),"JavaScript") then "-Os -Wno-warn-absolute-paths" else cflags; ldflags := System.getLDFlags(); + if Flags.getConfigBool(Flags.PARMODAUTO) then + ldflags := "-lParModelicaAuto -ltbb_static -lboost_system" + ldflags; + end if; rtlibs := if isFunction then Autoconf.ldflags_runtime else (if isFMU then Autoconf.ldflags_runtime_fmu else Autoconf.ldflags_runtime_sim); platform := System.modelicaPlatform(); compileDir := System.pwd() + Autoconf.pathDelimiter; diff --git a/OMCompiler/Compiler/SimCode/SimCodeMain.mo b/OMCompiler/Compiler/SimCode/SimCodeMain.mo index b3b6f95aaf7..d6819ae9208 100644 --- a/OMCompiler/Compiler/SimCode/SimCodeMain.mo +++ b/OMCompiler/Compiler/SimCode/SimCodeMain.mo @@ -96,7 +96,6 @@ import HpcOmSimCodeMain; import HpcOmTaskGraph; import RuntimeSources; import SerializeModelInfo; -import TaskSystemDump; import SerializeInitXML; import SimCodeUtil; import StackOverflow; @@ -106,6 +105,7 @@ import SymbolTable; import System; import Testsuite; import Util; +import SerializeTaskSystemInfo; public constant Boolean debug=true; @@ -538,7 +538,6 @@ algorithm System.realtimeTick(ClockIndexes.RT_PROFILER0); codegenFuncs := {}; codegenFuncs := (function runToBoolean(func=function SerializeInitXML.simulationInitFileReturnBool(simCode=simCode, guid=guid))) :: codegenFuncs; - dumpTaskSystemIfFlag(simCode); codegenFuncs := (function runTpl(func=function CodegenC.translateModel(in_a_simCode=simCode))) :: codegenFuncs; for f in { // external objects @@ -580,6 +579,11 @@ algorithm codegenFuncs := (function runTplWriteFile(func=function CodegenC.simulationFunctionsFile(a_filePrefix=simCode.fileNamePrefix, a_functions=simCode.modelInfo.functions), file=simCode.fileNamePrefix + "_functions.c")) :: codegenFuncs; codegenFuncs := (function runToStr(func=function SerializeModelInfo.serialize(code=simCode, withOperations=Flags.isSet(Flags.INFO_XML_OPERATIONS)))) :: codegenFuncs; + + if Flags.getConfigBool(Flags.PARMODAUTO) then + codegenFuncs := (function runToStr(func=function SerializeTaskSystemInfo.serializeParMod(code=simCode, withOperations=Flags.isSet(Flags.INFO_XML_OPERATIONS)))) :: codegenFuncs; + end if; + // Test the parallel code generator in the test suite. Should give decent results given that the task is disk-intensive. numThreads := max(1, if Testsuite.isRunning() then min(2, System.numProcessors()) else Config.noProc()); if (not Flags.isSet(Flags.PARALLEL_CODEGEN)) or numThreads==1 then @@ -665,14 +669,6 @@ algorithm setGlobalRoot(Global.optionSimCode, NONE()); end callTargetTemplates; -protected function dumpTaskSystemIfFlag - input SimCode.SimCode simCode; -algorithm - if Flags.isSet(Flags.PARMODAUTO) then - Tpl.tplNoret2(TaskSystemDump.dumpTaskSystem, simCode, Flags.isSet(Flags.INFO_XML_OPERATIONS)); - end if; -end dumpTaskSystemIfFlag; - protected function callTargetTemplatesCPP input SimCode.SimCode iSimCode; algorithm diff --git a/OMCompiler/Compiler/Template/CodegenC.tpl b/OMCompiler/Compiler/Template/CodegenC.tpl index 0e4e778f0ce..8fedb05ddcf 100644 --- a/OMCompiler/Compiler/Template/CodegenC.tpl +++ b/OMCompiler/Compiler/Template/CodegenC.tpl @@ -82,7 +82,7 @@ import ExpressionDumpTpl.*; let &records += recordsFile(fileNamePrefix, recordDecls, true /*isSimulation*/) let &records += closeFile() - // adpro: write the main .c file last! Make on windows doesn't seem to realize that + // adpro: write the main .c file last! Make on windows does not seem to realize that // the .c file is newer than the .o file if we have succesive simulate commands // for the same model (i.e. see testsuite/linearize/simextfunction.mos). @@ -192,7 +192,7 @@ end translateModel; #include "<%fileNamePrefix%>_literals.h" - <%if Flags.isSet(Flags.PARMODAUTO) then "#include \"ParModelica/auto/om_pm_interface.hpp\""%> + <%if Flags.getConfigBool(Flags.PARMODAUTO) then "#include \"ParModelica/auto/om_pm_interface.hpp\""%> <%if stringEq(getConfigString(HPCOM_CODE),"pthreads_spin") then "#include \"util/omc_spinlock.h\""%> @@ -1019,7 +1019,7 @@ template simulationFile(SimCode simCode, String guid, String isModelExchangeFMU) match simCode case simCode as SIMCODE(modelInfo=MODELINFO(varInfo=varInfo as VARINFO(__)), hpcomData=HPCOMDATA(__)) then let modelNamePrefixStr = modelNamePrefix(simCode) - let mainInit = if boolOr(boolNot(stringEq("",isModelExchangeFMU)), boolOr(Flags.isSet(Flags.PARMODAUTO), Flags.isSet(HPCOM))) then + let mainInit = if boolOr(boolNot(stringEq("",isModelExchangeFMU)), Flags.isSet(HPCOM)) then << mmc_init_nogc(); omc_alloc_interface = omc_alloc_interface_pooled; @@ -1036,7 +1036,14 @@ template simulationFile(SimCode simCode, String guid, String isModelExchangeFMU) MMC_INIT(0); omc_alloc_interface.init(); >> - let pminit = if Flags.isSet(Flags.PARMODAUTO) then 'PM_Model_init("<%fileNamePrefix%>", &data, threadData, functionODE_systems);' else '' + let pminit = if Flags.getConfigBool(Flags.PARMODAUTO) then + << + + pm_model = PM_Model_create("<%fileNamePrefix%>", &data, threadData, 0 /*num threads*/); + PM_Model_load_ODE_system(pm_model, functionODE_systems); + + >> + else '' let mainBody = << <%symbolName(modelNamePrefixStr,"setupDataStruc")%>(&data, threadData); @@ -1064,6 +1071,12 @@ template simulationFile(SimCode simCode, String guid, String isModelExchangeFMU) >> %> + <% if Flags.getConfigBool(Flags.PARMODAUTO) then + << + void* pm_model = NULL; + >> + %> + /* dummy VARINFO and FILEINFO */ const FILE_INFO dummyFILE_INFO = omc_dummyFileInfo; const VAR_INFO dummyVAR_INFO = omc_dummyVarInfo; @@ -1191,7 +1204,7 @@ template simulationFile(SimCode simCode, String guid, String isModelExchangeFMU) <%mainTop(mainBody,"https://trac.openmodelica.org/OpenModelica/newticket")%> <%if Flags.isSet(HPCOM) then "terminateHpcOmThreads();" %> - <%if Flags.isSet(Flags.PARMODAUTO) then "dump_times();" %> + <%if Flags.getConfigBool(Flags.PARMODAUTO) then "dump_times(pm_model);" %> fflush(NULL); EXIT(res); return res; @@ -3149,34 +3162,19 @@ template functionInitialEquations(list initalEquations, Integer num ::= let () = System.tmpTickReset(0) let &eqfuncs = buffer "" - let &eqArray = buffer "" - let fncalls = if Flags.isSet(Flags.PARMODAUTO) then - (initalEquations |> eq hasindex i0 => - equation_arrayFormat(eq, "InitialEquations", contextSimulationDiscrete, i0, &eqArray, &eqfuncs, modelNamePrefix, true) - ;separator="\n") - else functionEquationsMultiFiles(initalEquations, numInitialEquations, Flags.getConfigInt(Flags.EQUATIONS_PER_FILE), fileNamePrefix, fullPathPrefix, modelNamePrefix, - "functionInitialEquations", "06inz", &eqfuncs, /* not static */ false, /* do optimize */ false, /* initial */ init) - let eqArrayDecl = if Flags.isSet(Flags.PARMODAUTO) then - << - static void (*functionInitialEquations_systems[<%listLength(initalEquations)%>])(DATA *, threadData_t*) = { - <%eqArray%> - }; - >> - else - "" + let fncalls = functionEquationsMultiFiles(initalEquations, numInitialEquations, Flags.getConfigInt(Flags.EQUATIONS_PER_FILE), + fileNamePrefix, fullPathPrefix, modelNamePrefix, "functionInitialEquations", "06inz", &eqfuncs, /* not static */ false, + /* do optimize */ false, /* initial */ init) << <%eqfuncs%> - <%eqArrayDecl%> - int <%symbolName(modelNamePrefix,"functionInitialEquations")%>(DATA *data, threadData_t *threadData) { TRACE_PUSH data->simulationInfo->discreteCall = 1; - <%if Flags.isSet(Flags.PARMODAUTO) then 'PM_functionInitialEquations(<%numInitialEquations%>, data, threadData, functionInitialEquations_systems);' - else fncalls %> + <%fncalls %> data->simulationInfo->discreteCall = 0; TRACE_POP @@ -3191,38 +3189,19 @@ template functionInitialEquations_lambda0(list initalEquations_lamb let () = System.tmpTickReset(0) let nrfuncs = listLength(initalEquations_lambda0) let &eqfuncs = buffer "" - let &eqArray = buffer "" - let fncalls = if Flags.isSet(Flags.PARMODAUTO) then - (initalEquations_lambda0 |> eq hasindex i0 => - equation_arrayFormat(eq, "InitialEquations", contextSimulationDiscrete, i0, &eqArray, &eqfuncs, modelNamePrefix, true) - ;separator="\n") - else - let &eqfuncs += (initalEquations_lambda0 |> eq hasindex i0 => - equation_impl(-1, eq, contextSimulationDiscrete, modelNamePrefix, true) - ;separator="\n") - (initalEquations_lambda0 |> eq hasindex i0 => equation_call(eq, modelNamePrefix) ;separator="\n") - - let eqArrayDecl = if Flags.isSet(Flags.PARMODAUTO) then - << - static void (*functionInitialEquations_systems[<%listLength(initalEquations_lambda0)%>])(DATA *, threadData_t*) = { - <%eqArray%> - }; - >> - else - "" - + let fncalls = + let &eqfuncs += (initalEquations_lambda0 |> eq hasindex i0 => equation_impl(-1, eq, contextSimulationDiscrete, + modelNamePrefix, true) ;separator="\n") + (initalEquations_lambda0 |> eq hasindex i0 => equation_call(eq, modelNamePrefix) ;separator="\n") << <%eqfuncs%> - <%eqArrayDecl%> - int <%symbolName(modelNamePrefix,"functionInitialEquations_lambda0")%>(DATA *data, threadData_t *threadData) { TRACE_PUSH data->simulationInfo->discreteCall = 1; - <%if Flags.isSet(Flags.PARMODAUTO) then 'PM_functionInitialEquations_lambda0(<%nrfuncs%>, data, threadData, functionInitialEquations_lambda0_systems);' - else fncalls %> + <%fncalls %> data->simulationInfo->discreteCall = 0; TRACE_POP @@ -3346,14 +3325,6 @@ template functionXXX_systems_HPCOM(list> eqs, String name, Tex let funcNames = eqs |> e hasindex i0 fromindex 0 => 'function<%name%>_system<%i0%>' ; separator=",\n" let &varDecls += 'int id;<%\n%>' let &loop += - if Flags.isSet(Flags.PARMODAUTO) then /* Text for the loop body that calls the equations */ - << - #pragma omp parallel for private(id) schedule(<%match noProc() case 0 then "dynamic" else "static"%>) - for(id=0; id<<%nFuncs%>; id++) { - function<%name%>_systems[id](data, threadData); - } - >> - else << for(id=0; id<<%nFuncs%>; id++) { function<%name%>_systems[id](data, threadData); @@ -3953,13 +3924,11 @@ template functionXXX_systems(list> eqs, String name, Text &loo funcs //just the one function case nFuncs then //2 and more let funcNames = eqs |> e hasindex i0 fromindex 0 => 'function<%name%>_system<%i0%>' ; separator=",\n" - let head = if Flags.isSet(Flags.PARMODAUTO) then '#pragma omp parallel for private(id) schedule(<%match noProc() case 0 then "dynamic" else "static"%>)' let &varDecls += 'int id;<%\n%>' let &loop += /* Text for the loop body that calls the equations */ << - <%head%> for(id=0; id<<%nFuncs%>; id++) { function<%name%>_systems[id](data, threadData); } @@ -4062,7 +4031,7 @@ template functionODE(list> derivativEquations, Text method, Op let &fncalls = buffer "" let systems = if Flags.isSet(Flags.HPCOM) then (functionXXX_systems_HPCOM(derivativEquations, "ODE", &fncalls, &varDecls, hpcOmSchedules, modelNamePrefix)) - else if Flags.isSet(Flags.PARMODAUTO) then + else if Flags.getConfigBool(Flags.PARMODAUTO) then (functionXXX_systems_arrayFormat(derivativEquations, "ODE", &fncalls, &nrfuncs, &varDecls, modelNamePrefix)) else (functionXXX_systems(derivativEquations, "ODE", &fncalls, &varDecls, modelNamePrefix)) @@ -4084,7 +4053,7 @@ template functionODE(list> derivativEquations, Text method, Op data->simulationInfo->callStatistics.functionODE++; <%symbolName(modelNamePrefix,"functionLocalKnownVars")%>(data, threadData); - <%if Flags.isSet(Flags.PARMODAUTO) then 'PM_functionODE(<%nrfuncs%>, data, threadData, functionODE_systems);' + <%if Flags.getConfigBool(Flags.PARMODAUTO) then 'PM_evaluate_ODE_system(pm_model);' else fncalls %> #if !defined(OMC_MINIMAL_RUNTIME) @@ -4101,12 +4070,8 @@ template functionAlgebraic(list> algebraicEquations, String mo "Generates function in simulation file." ::= let &varDecls = buffer "" - let &nrfuncs = buffer "" let &fncalls = buffer "" - let systems = if Flags.isSet(Flags.PARMODAUTO) then - (functionXXX_systems_arrayFormat(algebraicEquations, "Alg", &fncalls, &nrfuncs, &varDecls, modelNamePrefix)) - else - (functionXXX_systems(algebraicEquations, "Alg", &fncalls, &varDecls, modelNamePrefix)) + let systems = functionXXX_systems(algebraicEquations, "Alg", &fncalls, &varDecls, modelNamePrefix) << @@ -4122,8 +4087,7 @@ template functionAlgebraic(list> algebraicEquations, String mo #endif data->simulationInfo->callStatistics.functionAlgebraics++; - <%if Flags.isSet(Flags.PARMODAUTO) then 'PM_functionAlg(<%nrfuncs%>, data, threadData, functionAlg_systems);' - else fncalls %> + <%fncalls %> <%symbolName(modelNamePrefix,"function_savePreSynchronous")%>(data, threadData); @@ -4258,31 +4222,16 @@ template functionDAE(list allEquationsPlusWhen, String modelNamePre let nrfuncs = listLength(allEquationsPlusWhen) let &eqfuncs = buffer "" let &eqArray = buffer "" - let fncalls = if Flags.isSet(Flags.PARMODAUTO) then - (allEquationsPlusWhen |> eq hasindex i0 => - equation_arrayFormat(eq, "DAE", contextSimulationDiscrete, i0, &eqArray, &eqfuncs, modelNamePrefix, false) - ;separator="\n") - else - (allEquationsPlusWhen |> eq hasindex i0 => + let fncalls = (allEquationsPlusWhen |> eq hasindex i0 => let &eqfuncs += equation_impl(-1, eq, contextSimulationDiscrete, modelNamePrefix, false) equation_call(eq, modelNamePrefix) ;separator="\n") - let eqArrayDecl = if Flags.isSet(Flags.PARMODAUTO) then - << - static void (*functionDAE_systems[<%nrfuncs%>])(DATA *, threadData_t *) = { - <%eqArray%> - }; - >> - else - "" - << <%auxFunction%> <%&eqfuncs%> - <%eqArrayDecl%> OMC_DISABLE_OPT int <%symbolName(modelNamePrefix,"functionDAE")%>(DATA *data, threadData_t *threadData) { @@ -4296,8 +4245,7 @@ template functionDAE(list allEquationsPlusWhen, String modelNamePre data->simulationInfo->needToIterate = 0; data->simulationInfo->discreteCall = 1; <%symbolName(modelNamePrefix,"functionLocalKnownVars")%>(data, threadData); - <%if Flags.isSet(Flags.PARMODAUTO) then 'PM_functionDAE(<%nrfuncs%>, data, threadData, functionDAE_systems);' - else fncalls %> + <%fncalls %> data->simulationInfo->discreteCall = 0; #if !defined(OMC_MINIMAL_RUNTIME) @@ -6200,7 +6148,6 @@ case SIMCODE(modelInfo=MODELINFO(varInfo=varInfo as VARINFO(__)), delayedExps=DE let libsPos1 = if not dirExtra then libsStr //else "" let libsPos2 = if dirExtra then libsStr // else "" let ParModelicaExpLibs = if acceptParModelicaGrammar() then '-lParModelicaExpl -lOpenCL' // else "" - let ParModelicaAutoLibs = if Flags.isSet(Flags.PARMODAUTO) then '-lParModelicaAuto -ltbb -lpugixml -lboost_system' // else "" let ExtraStack = if boolOr(stringEq(makefileParams.platform, "win32"),stringEq(makefileParams.platform, "win64")) then '--stack,16777216,' let extraCflags = match sopt case SOME(s as SIMULATION_SETTINGS(__)) then match s.method case "dassljac" then "-D_OMC_JACOBIAN " @@ -6210,7 +6157,7 @@ case SIMCODE(modelInfo=MODELINFO(varInfo=varInfo as VARINFO(__)), delayedExps=DE # Platform: <%makefileParams.platform%> # Simulations use -O3 by default - CC=<%if boolOr(Flags.isSet(Flags.PARMODAUTO),acceptParModelicaGrammar()) then 'g++' else '<%makefileParams.ccompiler%>'%> + CC=<%if acceptParModelicaGrammar() then 'g++' else '<%makefileParams.ccompiler%>'%> CXX=<%makefileParams.cxxcompiler%> LINK=<%makefileParams.linker%> EXEEXT=<%makefileParams.exeext%> @@ -6222,7 +6169,7 @@ case SIMCODE(modelInfo=MODELINFO(varInfo=varInfo as VARINFO(__)), delayedExps=DE %>CPPFLAGS=<%makefileParams.includes ; separator=" "%> -I"<%makefileParams.omhome%>/include/omc/c" -I. -DOPENMODELICA_XML_FROM_FILE_AT_RUNTIME<% if stringEq(Config.simCodeTarget(),"JavaScript") then " -DOMC_EMCC"%><% if Flags.isSet(Flags.OMC_RELOCATABLE_FUNCTIONS) then " -DOMC_GENERATE_RELOCATABLE_CODE"%> -DOMC_MODEL_PREFIX=<%modelNamePrefix(simCode)%> -DOMC_NUM_MIXED_SYSTEMS=<%varInfo.numMixedSystems%> -DOMC_NUM_LINEAR_SYSTEMS=<%varInfo.numLinearSystems%> -DOMC_NUM_NONLINEAR_SYSTEMS=<%varInfo.numNonLinearSystems%> -DOMC_NDELAY_EXPRESSIONS=<%maxDelayedIndex%> -DOMC_NVAR_STRING=<%varInfo.numStringAlgVars%> LDFLAGS=<% if stringEq(Config.simCodeTarget(),"JavaScript") then <<-L'<%makefileParams.omhome%>/lib/<%Autoconf.triple%>/omc/emcc' -lblas -llapack -lexpat -lSimulationRuntimeC -s TOTAL_MEMORY=805306368 -s OUTLINING_LIMIT=20000 --pre-js $(OMC_EMCC_PRE_JS)>> - else <<-L"<%makefileParams.omhome%>/lib/<%Autoconf.triple%>/omc" -L"<%makefileParams.omhome%>/lib" -Wl,<%ExtraStack%>-rpath,"<%makefileParams.omhome%>/lib/<%Autoconf.triple%>/omc" -Wl,-rpath,"<%makefileParams.omhome%>/lib" <%ParModelicaExpLibs%> <%ParModelicaAutoLibs%> <%makefileParams.ldflags%> <%makefileParams.runtimelibs%> >> + else <<-L"<%makefileParams.omhome%>/lib/<%Autoconf.triple%>/omc" -L"<%makefileParams.omhome%>/lib" -Wl,<%ExtraStack%>-rpath,"<%makefileParams.omhome%>/lib/<%Autoconf.triple%>/omc" -Wl,-rpath,"<%makefileParams.omhome%>/lib" <%ParModelicaExpLibs%> <%makefileParams.ldflags%> <%makefileParams.runtimelibs%> >> %> DIREXTRA=<%stringReplace(dirExtra,"#","\\#") /* make strips everything after # */%> MAINFILE=<%fileNamePrefix%>.c @@ -6241,7 +6188,7 @@ case SIMCODE(modelInfo=MODELINFO(varInfo=varInfo as VARINFO(__)), delayedExps=DE .PHONY: $(CFILES) omc_main_target: $(MAINOBJ) <%fileNamePrefix%>_functions.h <%fileNamePrefix%>_literals.h $(OFILES) - <%\t%>$(CC) -I. -o <%fileNamePrefix%>$(EXEEXT) $(MAINOBJ) $(OFILES) $(CPPFLAGS) $(DIREXTRA) <%libsPos1%> <%libsPos2%> $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) + <%\t%><% if Flags.getConfigBool(Flags.PARMODAUTO) then '$(CXX)' else '$(CC)'%> -I. -o <%fileNamePrefix%>$(EXEEXT) $(MAINOBJ) $(OFILES) $(CPPFLAGS) $(DIREXTRA) <%libsPos1%> <%libsPos2%> $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) <% if stringEq(Config.simCodeTarget(),"JavaScript") then '<%\t%>rm -f <%fileNamePrefix%>'%> <% if stringEq(Config.simCodeTarget(),"JavaScript") then '<%\t%>ln -s <%fileNamePrefix%>_node.js <%fileNamePrefix%>'%> <% if stringEq(Config.simCodeTarget(),"JavaScript") then '<%\t%>chmod +x <%fileNamePrefix%>_node.js'%> @@ -6522,13 +6469,11 @@ template functionXXX_systemsPartial(list> eqs, String name, Te funcs //just the one function case nFuncs then //2 and more let funcNames = eqs |> e hasindex i0 fromindex 0 => 'function<%name%>_system<%i0%>' ; separator=",\n" - let head = if Flags.isSet(Flags.PARMODAUTO) then '#pragma omp parallel for private(id) schedule(<%match noProc() case 0 then "dynamic" else "static"%>)' let &varDecls += 'int id;<%\n%>' let &loop += /* Text for the loop body that calls the equations */ << - <%head%> for(id=0; id<<%nFuncs%>; id++) { function<%name%>_systems[id](data, threadData); } diff --git a/OMCompiler/Compiler/Template/Makefile.common b/OMCompiler/Compiler/Template/Makefile.common index 4a38235de6f..a617e7a3371 100644 --- a/OMCompiler/Compiler/Template/Makefile.common +++ b/OMCompiler/Compiler/Template/Makefile.common @@ -5,7 +5,7 @@ GENERATED_FILES=$(GENERATED_FILES_BOOT_STAGE2) CodegenC.mo CodegenUtilSimulation CodegenFMU.mo CodegenFMU1.mo CodegenFMU2.mo CodegenCSharp.mo CodegenCppCommon.mo CodegenCpp.mo CodegenCppHpcom.mo CodegenFMUCpp.mo \ CodegenOMSI_common.mo CodegenOMSIC.mo CodegenOMSICpp.mo CodegenOMSIC_Equations.mo CodegenFMUCppHpcom.mo CodegenCppInit.mo \ CodegenMidToC.mo CodegenModelica.mo GraphvizDump.mo GraphMLDumpTpl.mo NFInstDumpTpl.mo SimCodeDump.mo CodegenAdevs.mo CodegenSparseFMI.mo \ -CodegenXML.mo CodegenJava.mo CodegenJS.mo TaskSystemDump.mo VisualXMLTpl.mo \ +CodegenXML.mo CodegenJava.mo CodegenJS.mo VisualXMLTpl.mo \ CodegenCppCommonOld.mo CodegenCppHpcomOld.mo CodegenCppOld.mo CodegenFMUCppHpcomOld.mo CodegenFMUCppOld.mo UNUSED=../boot/find-unused-import.sh @@ -219,11 +219,6 @@ TplCodegen.mo : ../susan_codegen/TplCodegen.tpl ../susan_codegen/TplCodegenTV.mo (cd ../susan_codegen && $(OMC) -d=failtrace TplCodegen.tpl) > $@.log || (cat $@.log && false) cp -a ../susan_codegen/TplCodegen.mo $@ -TaskSystemDump.mo : TaskSystemDump.tpl SimCodeTV.mo CodegenUtil.tpl SCodeDumpTpl.tpl - @echo " ** TaskSystemDump template compilation ** " - $(OMC) $< > $@.log || (cat $@.log && false) - @echo " " && ($(UNUSED) "$@" || true) - GenerateAPIFunctionsTpl.mo : GenerateAPIFunctionsTpl.tpl SimCodeTV.mo @echo " ** GenerateAPIFunctionsTpl template compilation ** " $(OMC) $< > $@.log || (cat $@.log && false) diff --git a/OMCompiler/Compiler/Template/SimCodeTV.mo b/OMCompiler/Compiler/Template/SimCodeTV.mo index 217ac842708..1ae0cf94859 100644 --- a/OMCompiler/Compiler/Template/SimCodeTV.mo +++ b/OMCompiler/Compiler/Template/SimCodeTV.mo @@ -3851,7 +3851,6 @@ package Flags uniontype DebugFlag end DebugFlag; uniontype ConfigFlag end ConfigFlag; - constant DebugFlag PARMODAUTO; constant DebugFlag HPCOM; constant DebugFlag HPCOM_MEMORY_OPT; constant DebugFlag GEN_DEBUG_SYMBOLS; @@ -3863,6 +3862,7 @@ package Flags constant DebugFlag OMC_RECORD_ALLOC_WORDS; constant DebugFlag OMC_RELOCATABLE_FUNCTIONS; constant DebugFlag NF_SCALARIZE; + constant ConfigFlag PARMODAUTO; constant ConfigFlag NUM_PROC; constant ConfigFlag HPCOM_CODE; constant ConfigFlag PROFILING_LEVEL; diff --git a/OMCompiler/Compiler/Template/TaskSystemDump.tpl b/OMCompiler/Compiler/Template/TaskSystemDump.tpl deleted file mode 100644 index 27892ef7a3a..00000000000 --- a/OMCompiler/Compiler/Template/TaskSystemDump.tpl +++ /dev/null @@ -1,447 +0,0 @@ -package TaskSystemDump - -import interface SimCodeTV; -import CodegenUtil.*; -import DAEDumpTpl.*; -import SCodeDumpTpl.*; -import ExpressionDumpTpl; - -template dumpTaskSystem(SimCode code, Boolean withOperations) -::= - match code - case sc as SIMCODE(modelInfo=mi as MODELINFO(vars=vars as SIMVARS(__))) then - let res = tasksystemdump_dispatch(code,withOperations) - let() = textFile(res,'<%fileNamePrefix%>_tasks.xml') - '<%fileNamePrefix%>_info' -end dumpTaskSystem; - -template tasksystemdump_dispatch(SimCode code, Boolean withOperations) -::= - match code - case sc as SIMCODE(modelInfo=mi as MODELINFO(vars=vars as SIMVARS(__))) then - let name = Util.escapeModelicaStringToXmlString(dotPath(mi.name)) - << - - - - - <%dumpEqs(SimCodeUtil.sortEqSystems(initialEquations),0,withOperations)%> - - - <%dumpEqs(SimCodeUtil.sortEqSystems(allEquations),0,withOperations)%> - - - <%if odeEquations then dumpEqs(SimCodeUtil.sortEqSystems(listGet(odeEquations,1)),0,withOperations)%> - - - <%if algebraicEquations then dumpEqs(SimCodeUtil.sortEqSystems(listGet(algebraicEquations,1)),0,withOperations)%> - - - <%dumpEqs(SimCodeUtil.sortEqSystems(startValueEquations),0,withOperations)%> - - - <%dumpEqs(SimCodeUtil.sortEqSystems(nominalValueEquations),0,withOperations)%> - - - <%dumpEqs(SimCodeUtil.sortEqSystems(minValueEquations),0,withOperations)%> - - - <%dumpEqs(SimCodeUtil.sortEqSystems(maxValueEquations),0,withOperations)%> - - - <%dumpEqs(SimCodeUtil.sortEqSystems(parameterEquations),0,withOperations)%> - - - <%dumpEqs(SimCodeUtil.sortEqSystems(algorithmAndEquationAsserts),0,withOperations)%> - - - <%dumpEqs(SimCodeUtil.sortEqSystems(jacobianEquations),0,withOperations)%> - - - <% literals |> exp => '<%printExpStrEscaped(exp)%>' ; separator="\n" %> - - - <% mi.functions |> func => match func - case FUNCTION(__) - case EXTERNAL_FUNCTION(__) - case KERNEL_FUNCTION(__) - case PARALLEL_FUNCTION(__) - case RECORD_CONSTRUCTOR(__) then - '<%dumpInfo(info)%>' ; separator="\n" - %> - - <%\n%> - >> -end tasksystemdump_dispatch; - -template eqIndex(SimEqSystem eq) -::= -match eq - case SES_RESIDUAL(__) - case SES_SIMPLE_ASSIGN(__) - case SES_SIMPLE_ASSIGN_CONSTRAINTS(__) - case SES_ARRAY_CALL_ASSIGN(__) - case SES_ALGORITHM(__) then index - case SES_LINEAR(lSystem=ls as LINEARSYSTEM(__)) then ls.index - case SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__)) then nls.index - case SES_MIXED(__) - case SES_WHEN(__) - case SES_IFEQUATION(__) then index - else error(sourceInfo(), "dumpEqs: Unknown equation") -end eqIndex; - -template hasParent(Integer parent) -::= - if intEq(parent,0) then "" else ' parent="<%parent%>"' -end hasParent; - -template dumpEqs(list eqs, Integer parent, Boolean withOperations) -::= eqs |> eq hasindex i0 => - match eq - case e as SES_RESIDUAL(__) then - let &defines = buffer "" - let &depends = buffer "" - let _ = eqDefinesDepends(e, defines, depends) - << - > - - <%defines%> - <%depends%> - <%printExpStrEscaped(e.exp)%> - - <%\n%> - >> - case e as SES_SIMPLE_ASSIGN(__) - case e as SES_SIMPLE_ASSIGN_CONSTRAINTS(__) then - let &defines = buffer "" - let &depends = buffer "" - let _ = eqDefinesDepends(e, defines, depends) - << - > - - <%defines%> - <%depends%> - <%printExpStrEscaped(e.exp)%> - - <%\n%> - >> - case e as SES_ARRAY_CALL_ASSIGN(__) then - let &defines = buffer "" - let &depends = buffer "" - let _ = eqDefinesDepends(e, defines, depends) - << - > - - <%defines%> - <%depends%> - <%printExpStrEscaped(e.exp)%> - - <%\n%> - >> - case e as SES_ALGORITHM(statements={}) then 'empty algorithm<%\n%>' - case e as SES_ALGORITHM(statements=first::_) - then - let uniqcrefs = getdependcies(extractUniqueCrefsFromStatmentS(e.statements)) - << - > - - <%uniqcrefs%> - - <%e.statements |> stmt => escapeModelicaStringToXmlString(ppStmtStr(stmt,2)) %> - - - <%\n%> - >> - case e as SES_LINEAR(lSystem=ls as LINEARSYSTEM(__)) then - let &defines = buffer "" - let &depends = buffer "" - let &defines += ls.vars |> SIMVAR(name=cr) => '' ; separator = "\n" - let _ = SimCodeUtil.sortEqSystems(ls.residual) |> reseq => - eqDefinesDepends(reseq, defines, depends) - let _ = (match ls.jacobianMatrix - case SOME(SimCode.JAC_MATRIX(columns={JAC_COLUMN(columnEqns=eqns)})) then - let _ = SimCodeUtil.sortEqSystems(eqns) |> jeq => - eqDefinesDepends(jeq, defines, depends) - "" - ) - << - > - - <%defines%> - <%depends%> - - <%ls.residual |> eq => '' ; separator = "\n" %> - - - <%match ls.jacobianMatrix case SOME(SimCode.JAC_MATRIX(columns={JAC_COLUMN(columnEqns=eqns)})) then (eqns |> eq => '' ; separator = "\n") else ''%> - - - <%\n%> - >> - case e as SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__)) then - let &defines = buffer "" - let &depends = buffer "" - let &defines += nls.crefs |> cr => '' ; separator = "\n" - let _ = SimCodeUtil.sortEqSystems(nls.eqs) |> nleq => - eqDefinesDepends(nleq, defines, depends) - let _ = (match nls.jacobianMatrix - case SOME(SimCode.JAC_MATRIX(columns={JAC_COLUMN(columnEqns=eqns)})) then - let _ = SimCodeUtil.sortEqSystems(eqns) |> jeq => - eqDefinesDepends(jeq, defines, depends) - "" - ) - << - <%match nls.jacobianMatrix case SOME(SimCode.JAC_MATRIX(columns={JAC_COLUMN(columnEqns=eqns)})) then dumpEqs(SimCodeUtil.sortEqSystems(eqns),nls.index,withOperations) else ''%> - > - - <%defines%> - <%depends%> - <%nls.eqs |> eq => '' ; separator = "\n" %> - - <%\n%> - >> - case e as SES_MIXED(__) then - << - > - - <%e.discVars |> SIMVAR(name=cr) => '' ; separator = ","%> - <%e.discEqs |> eq => ''%> - - - <%\n%> - <%dumpEqs(fill(e.cont,1),e.index,withOperations)%> - <%dumpEqs(e.discEqs,e.index,withOperations)%> - >> - case e as SES_WHEN(__) then - let body = dumpWhenOps(whenStmtLst) - << - > - - <%conditions |> cond => '<%crefStrNoUnderscore(cond)%>' ; separator="\n" %> - <%body%> - - <%\n%> - >> - case e as SES_IFEQUATION(__) then - let branches = ifbranches |> (_,eqs) => dumpEqs(eqs,e.index,withOperations) - let elsebr = dumpEqs(elsebranch,e.index,withOperations) - << - <%branches%> - <%elsebr%> - > - - <%\n%> - >> - else error(sourceInfo(),"dumpEqs: Unknown equation") -end dumpEqs; - -template dumpWhenOps(list whenOps) -::= - match whenOps - case ({}) then <<>> - case ((e as BackendDAE.ASSIGN(left = left as DAE.CREF(componentRef = leftCr)))::rest) then - let restbody = dumpWhenOps(rest) - << - - <% extractUniqueCrefsFromExpDerPreStart(e.right) |> cr => '' ; separator = "\n" %> - <%printExpStrEscaped(e.right)%> - <%restbody%> - >> - case ((e as BackendDAE.REINIT(__))::rest) then - let restbody = dumpWhenOps(rest) - << - - TODO: fix this case. - - <%restbody%> - >> - case ((e as BackendDAE.ASSERT(__))::rest) then - let restbody = dumpWhenOps(rest) - << - - TODO: fix this case. - - <%restbody%> - >> - case ((e as BackendDAE.TERMINATE(__))::rest) then - let restbody = dumpWhenOps(rest) - << - - TODO: fix this case. - - <%restbody%> - >> - case ((e as BackendDAE.NORETCALL(__))::rest) then - let restbody = dumpWhenOps(rest) - << - - TODO: fix this case. - - <%restbody%> - >> - else error(sourceInfo(),"dumpEqs: Unknown equation") -end dumpWhenOps; - -template getdependcies(tuple, list> ocrefs) -::= - match ocrefs - case (olhscrefs,orhscrefs) then - << - <%olhscrefs |> cr => '' ; separator = "\n"%> - <%orhscrefs |> cr => '' ; separator = "\n"%> - >> - else "Error Printing dependenices" -end getdependcies; - -template eqDefinesDepends(SimEqSystem eq, Text &defines, Text &depends) -::= - match eq - case e as SES_RESIDUAL(__) then - let &depends += extractUniqueCrefsFromExpDerPreStart(e.exp) |> cr => '' ; separator = "\n" - "" - case e as SES_SIMPLE_ASSIGN(__) - case e as SES_SIMPLE_ASSIGN_CONSTRAINTS(__) then - let &defines += '<%\n%>' - let &depends += extractUniqueCrefsFromExpDerPreStart(e.exp) |> cr => '' ; separator = "\n" - "" - case e as SES_ARRAY_CALL_ASSIGN(__) then - let &defines += extractUniqueCrefsFromExpDerPreStart(e.lhs) |> cr => '' ; separator = "\n" - let &depends += extractUniqueCrefsFromExpDerPreStart(e.exp) |> cr => '' ; separator = "\n" - "" - else "Unrecognized Equation in eqDefinesDepends" -end eqDefinesDepends; - -template dumpWithin(Within w) -::= - match w - case TOP(__) then "within ;" - case WITHIN(__) then 'within <%dotPath(path)%>;' -end dumpWithin; - -template dumpOperation(SymbolicOperation op, builtin.SourceInfo info) -::= - match op - case FLATTEN(__) then - << - - <% Util.escapeModelicaStringToXmlString(dumpEEquation(scode,SCodeDump.defaultOptions)) %> - <% match dae case SOME(dae) then '<% Util.escapeModelicaStringToXmlString(dumpEquationElement(dae)) %>' %> - - >> - case SIMPLIFY(__) then - << - - <%printEquationExpStrEscaped(before)%> - <%printEquationExpStrEscaped(after)%> - - >> - case SUBSTITUTION(__) then - << - - <%printExpStrEscaped(source)%> - <%listReverse(substitutions) |> target => '<%printExpStrEscaped(target)%>' ; separator="\n" %> - - >> - case op as OP_INLINE(__) then - << - - <%printEquationExpStrEscaped(op.before)%> - <%printEquationExpStrEscaped(op.after)%> - - >> - case op as OP_SCALARIZE(__) then - << - - <%printEquationExpStrEscaped(op.before)%> - <%printEquationExpStrEscaped(op.after)%> - - >> - case op as SOLVED(__) then - << - - <%crefStrNoUnderscore(op.cr)%> - <%printExpStrEscaped(op.exp)%> - - >> - case op as LINEAR_SOLVED(__) then - << - - simple equation from linear system: - [<%vars |> v => crefStrNoUnderscore(v) ; separator = " ; "%>] = [<%result |> r => r ; separator = " ; "%>] - [ - <% jac |> row => (row |> r => r ; separator = " "); separator = "\n"%> - ] - * - X - = - [<%rhs |> r => r ; separator = " ; "%>] - - >> - case op as SOLVE(__) then - << - - - <%printExpStrEscaped(op.exp1)%> - <%printExpStrEscaped(op.exp2)%> - - - <%crefStrNoUnderscore(op.cr)%> - <%printExpStrEscaped(op.res)%> - - - <%op.assertConds |> cond => '<%printExpStrEscaped(cond)%>'; separator="\n"%> - - - >> - case op as OP_DIFFERENTIATE(__) then - << - - <%printExpStrEscaped(op.before)%> - <%crefStrNoUnderscore(op.cr)%> - <%printExpStrEscaped(op.after)%> - - >> - case OP_RESIDUAL(__) then - << - - <%printExpStrEscaped(e1)%> - <%printExpStrEscaped(e2)%> - <%printExpStrEscaped(e)%> - - >> - case op as NEW_DUMMY_DER(__) then - << - - <%crefStrNoUnderscore(op.chosen)%> - <%op.candidates |> cr => '<%crefStrNoUnderscore(cr)%>' ; separator = "\n"%> - - >> - else Tpl.addSourceTemplateError("Unknown operation",info) -end dumpOperation; - -template dumpInfo(builtin.SourceInfo info) -::= - match info - case info as SOURCEINFO(__) then - '' -end dumpInfo; - -template printExpStrEscaped(Exp exp) -::= - escapeModelicaStringToXmlString(ExpressionDumpTpl.dumpExp(exp,"\"")) -end printExpStrEscaped; - -template printEquationExpStrEscaped(EquationExp eq) -::= - match eq - case PARTIAL_EQUATION(__) - case RESIDUAL_EXP(__) then - printExpStrEscaped(exp) - case EQUALITY_EXPS(__) then - '<%printExpStrEscaped(lhs)%> = <%printExpStrEscaped(rhs)%>' -end printEquationExpStrEscaped; - -annotation(__OpenModelica_Interface="backend"); -end TaskSystemDump; - -// vim: filetype=susan sw=2 sts=2 diff --git a/OMCompiler/Compiler/Util/Flags.mo b/OMCompiler/Compiler/Util/Flags.mo index 12560b5e8e0..dcc047b76d0 100644 --- a/OMCompiler/Compiler/Util/Flags.mo +++ b/OMCompiler/Compiler/Util/Flags.mo @@ -177,392 +177,390 @@ constant DebugFlag CEVAL = DEBUG_FLAG(2, "ceval", false, Gettext.gettext("Prints extra information from Ceval.")); constant DebugFlag CHECK_BACKEND_DAE = DEBUG_FLAG(3, "checkBackendDae", false, Gettext.gettext("Do some simple analyses on the datastructure from the frontend to check if it is consistent.")); -constant DebugFlag PARMODAUTO = DEBUG_FLAG(4, "parmodauto", false, - Gettext.gettext("Experimental: Enable parallelization of independent systems of equations in the translated model.")); -constant DebugFlag PTHREADS = DEBUG_FLAG(5, "pthreads", false, +constant DebugFlag PTHREADS = DEBUG_FLAG(4, "pthreads", false, Gettext.gettext("Experimental: Unused parallelization.")); -constant DebugFlag EVENTS = DEBUG_FLAG(6, "events", true, +constant DebugFlag EVENTS = DEBUG_FLAG(5, "events", true, Gettext.gettext("Turns on/off events handling.")); -constant DebugFlag DUMP_INLINE_SOLVER = DEBUG_FLAG(7, "dumpInlineSolver", false, +constant DebugFlag DUMP_INLINE_SOLVER = DEBUG_FLAG(6, "dumpInlineSolver", false, Gettext.gettext("Dumps the inline solver equation system.")); -constant DebugFlag EVAL_FUNC = DEBUG_FLAG(8, "evalfunc", true, +constant DebugFlag EVAL_FUNC = DEBUG_FLAG(7, "evalfunc", true, Gettext.gettext("Turns on/off symbolic function evaluation.")); -constant DebugFlag GEN = DEBUG_FLAG(9, "gen", false, +constant DebugFlag GEN = DEBUG_FLAG(8, "gen", false, Gettext.gettext("Turns on/off dynamic loading of functions that are compiled during translation. Only enable this if external functions are needed to calculate structural parameters or constants.")); -constant DebugFlag DYN_LOAD = DEBUG_FLAG(10, "dynload", false, +constant DebugFlag DYN_LOAD = DEBUG_FLAG(9, "dynload", false, Gettext.gettext("Display debug information about dynamic loading of compiled functions.")); -constant DebugFlag GENERATE_CODE_CHEAT = DEBUG_FLAG(11, "generateCodeCheat", false, +constant DebugFlag GENERATE_CODE_CHEAT = DEBUG_FLAG(10, "generateCodeCheat", false, Gettext.gettext("Used to generate code for the bootstrapped compiler.")); -constant DebugFlag CGRAPH_GRAPHVIZ_FILE = DEBUG_FLAG(12, "cgraphGraphVizFile", false, +constant DebugFlag CGRAPH_GRAPHVIZ_FILE = DEBUG_FLAG(11, "cgraphGraphVizFile", false, Gettext.gettext("Generates a graphviz file of the connection graph.")); -constant DebugFlag CGRAPH_GRAPHVIZ_SHOW = DEBUG_FLAG(13, "cgraphGraphVizShow", false, +constant DebugFlag CGRAPH_GRAPHVIZ_SHOW = DEBUG_FLAG(12, "cgraphGraphVizShow", false, Gettext.gettext("Displays the connection graph with the GraphViz lefty tool.")); -constant DebugFlag GC_PROF = DEBUG_FLAG(14, "gcProfiling", false, +constant DebugFlag GC_PROF = DEBUG_FLAG(13, "gcProfiling", false, Gettext.gettext("Prints garbage collection stats to standard output.")); -constant DebugFlag CHECK_DAE_CREF_TYPE = DEBUG_FLAG(15, "checkDAECrefType", false, +constant DebugFlag CHECK_DAE_CREF_TYPE = DEBUG_FLAG(14, "checkDAECrefType", false, Gettext.gettext("Enables extra type checking for cref expressions.")); -constant DebugFlag CHECK_ASUB = DEBUG_FLAG(16, "checkASUB", false, +constant DebugFlag CHECK_ASUB = DEBUG_FLAG(15, "checkASUB", false, Gettext.gettext("Prints out a warning if an ASUB is created from a CREF expression.")); -constant DebugFlag INSTANCE = DEBUG_FLAG(17, "instance", false, +constant DebugFlag INSTANCE = DEBUG_FLAG(16, "instance", false, Gettext.gettext("Prints extra failtrace from InstanceHierarchy.")); -constant DebugFlag CACHE = DEBUG_FLAG(18, "Cache", true, +constant DebugFlag CACHE = DEBUG_FLAG(17, "Cache", true, Gettext.gettext("Turns off the instantiation cache.")); -constant DebugFlag RML = DEBUG_FLAG(19, "rml", false, +constant DebugFlag RML = DEBUG_FLAG(18, "rml", false, Gettext.gettext("Converts Modelica-style arrays to lists.")); -constant DebugFlag TAIL = DEBUG_FLAG(20, "tail", false, +constant DebugFlag TAIL = DEBUG_FLAG(19, "tail", false, Gettext.gettext("Prints out a notification if tail recursion optimization has been applied.")); -constant DebugFlag LOOKUP = DEBUG_FLAG(21, "lookup", false, +constant DebugFlag LOOKUP = DEBUG_FLAG(20, "lookup", false, Gettext.gettext("Print extra failtrace from lookup.")); -constant DebugFlag PATTERNM_SKIP_FILTER_UNUSED_AS_BINDINGS = DEBUG_FLAG(22, "patternmSkipFilterUnusedBindings", false, +constant DebugFlag PATTERNM_SKIP_FILTER_UNUSED_AS_BINDINGS = DEBUG_FLAG(21, "patternmSkipFilterUnusedBindings", false, Gettext.notrans("")); -constant DebugFlag PATTERNM_ALL_INFO = DEBUG_FLAG(23, "patternmAllInfo", false, +constant DebugFlag PATTERNM_ALL_INFO = DEBUG_FLAG(22, "patternmAllInfo", false, Gettext.gettext("Adds notifications of all pattern-matching optimizations that are performed.")); -constant DebugFlag PATTERNM_DCE = DEBUG_FLAG(24, "patternmDeadCodeElimination", true, +constant DebugFlag PATTERNM_DCE = DEBUG_FLAG(23, "patternmDeadCodeElimination", true, Gettext.gettext("Performs dead code elimination in match-expressions.")); -constant DebugFlag PATTERNM_MOVE_LAST_EXP = DEBUG_FLAG(25, "patternmMoveLastExp", true, +constant DebugFlag PATTERNM_MOVE_LAST_EXP = DEBUG_FLAG(24, "patternmMoveLastExp", true, Gettext.gettext("Optimization that moves the last assignment(s) into the result of a match-expression. For example: equation c = fn(b); then c; => then fn(b);")); -constant DebugFlag EXPERIMENTAL_REDUCTIONS = DEBUG_FLAG(26, "experimentalReductions", false, +constant DebugFlag EXPERIMENTAL_REDUCTIONS = DEBUG_FLAG(25, "experimentalReductions", false, Gettext.gettext("Turns on custom reduction functions (OpenModelica extension).")); -constant DebugFlag EVAL_PARAM = DEBUG_FLAG(27, "evaluateAllParameters", false, +constant DebugFlag EVAL_PARAM = DEBUG_FLAG(26, "evaluateAllParameters", false, Gettext.gettext("Evaluates all parameters if set.")); -constant DebugFlag TYPES = DEBUG_FLAG(28, "types", false, +constant DebugFlag TYPES = DEBUG_FLAG(27, "types", false, Gettext.gettext("Prints extra failtrace from Types.")); -constant DebugFlag SHOW_STATEMENT = DEBUG_FLAG(29, "showStatement", false, +constant DebugFlag SHOW_STATEMENT = DEBUG_FLAG(28, "showStatement", false, Gettext.gettext("Shows the statement that is currently being evaluated when evaluating a script.")); -constant DebugFlag DUMP = DEBUG_FLAG(30, "dump", false, +constant DebugFlag DUMP = DEBUG_FLAG(29, "dump", false, Gettext.gettext("Dumps the absyn representation of a program.")); -constant DebugFlag DUMP_GRAPHVIZ = DEBUG_FLAG(31, "graphviz", false, +constant DebugFlag DUMP_GRAPHVIZ = DEBUG_FLAG(30, "graphviz", false, Gettext.gettext("Dumps the absyn representation of a program in graphviz format.")); -constant DebugFlag EXEC_STAT = DEBUG_FLAG(32, "execstat", false, +constant DebugFlag EXEC_STAT = DEBUG_FLAG(31, "execstat", false, Gettext.gettext("Prints out execution statistics for the compiler.")); -constant DebugFlag TRANSFORMS_BEFORE_DUMP = DEBUG_FLAG(33, "transformsbeforedump", false, +constant DebugFlag TRANSFORMS_BEFORE_DUMP = DEBUG_FLAG(32, "transformsbeforedump", false, Gettext.gettext("Applies transformations required for code generation before dumping flat code.")); -constant DebugFlag DAE_DUMP_GRAPHV = DEBUG_FLAG(34, "daedumpgraphv", false, +constant DebugFlag DAE_DUMP_GRAPHV = DEBUG_FLAG(33, "daedumpgraphv", false, Gettext.gettext("Dumps the DAE in graphviz format.")); -constant DebugFlag INTERACTIVE_TCP = DEBUG_FLAG(35, "interactive", false, +constant DebugFlag INTERACTIVE_TCP = DEBUG_FLAG(34, "interactive", false, Gettext.gettext("Starts omc as a server listening on the socket interface.")); -constant DebugFlag INTERACTIVE_CORBA = DEBUG_FLAG(36, "interactiveCorba", false, +constant DebugFlag INTERACTIVE_CORBA = DEBUG_FLAG(35, "interactiveCorba", false, Gettext.gettext("Starts omc as a server listening on the Corba interface.")); -constant DebugFlag INTERACTIVE_DUMP = DEBUG_FLAG(37, "interactivedump", false, +constant DebugFlag INTERACTIVE_DUMP = DEBUG_FLAG(36, "interactivedump", false, Gettext.gettext("Prints out debug information for the interactive server.")); -constant DebugFlag RELIDX = DEBUG_FLAG(38, "relidx", false, +constant DebugFlag RELIDX = DEBUG_FLAG(37, "relidx", false, Gettext.notrans("Prints out debug information about relations, that are used as zero crossings.")); -constant DebugFlag DUMP_REPL = DEBUG_FLAG(39, "dumprepl", false, +constant DebugFlag DUMP_REPL = DEBUG_FLAG(38, "dumprepl", false, Gettext.gettext("Dump the found replacements for simple equation removal.")); -constant DebugFlag DUMP_FP_REPL = DEBUG_FLAG(40, "dumpFPrepl", false, +constant DebugFlag DUMP_FP_REPL = DEBUG_FLAG(39, "dumpFPrepl", false, Gettext.gettext("Dump the found replacements for final parameters.")); -constant DebugFlag DUMP_PARAM_REPL = DEBUG_FLAG(41, "dumpParamrepl", false, +constant DebugFlag DUMP_PARAM_REPL = DEBUG_FLAG(40, "dumpParamrepl", false, Gettext.gettext("Dump the found replacements for remove parameters.")); -constant DebugFlag DUMP_PP_REPL = DEBUG_FLAG(42, "dumpPPrepl", false, +constant DebugFlag DUMP_PP_REPL = DEBUG_FLAG(41, "dumpPPrepl", false, Gettext.gettext("Dump the found replacements for protected parameters.")); -constant DebugFlag DUMP_EA_REPL = DEBUG_FLAG(43, "dumpEArepl", false, +constant DebugFlag DUMP_EA_REPL = DEBUG_FLAG(42, "dumpEArepl", false, Gettext.gettext("Dump the found replacements for evaluate annotations (evaluate=true) parameters.")); -constant DebugFlag DEBUG_ALIAS = DEBUG_FLAG(44, "debugAlias", false, +constant DebugFlag DEBUG_ALIAS = DEBUG_FLAG(43, "debugAlias", false, Gettext.gettext("Dumps some information about the process of removeSimpleEquations.")); -constant DebugFlag TEARING_DUMP = DEBUG_FLAG(45, "tearingdump", false, +constant DebugFlag TEARING_DUMP = DEBUG_FLAG(44, "tearingdump", false, Gettext.gettext("Dumps tearing information.")); -constant DebugFlag JAC_DUMP = DEBUG_FLAG(46, "symjacdump", false, +constant DebugFlag JAC_DUMP = DEBUG_FLAG(45, "symjacdump", false, Gettext.gettext("Dumps information about symbolic Jacobians. Can be used only with postOptModules: generateSymbolicJacobian, generateSymbolicLinearization.")); -constant DebugFlag JAC_DUMP2 = DEBUG_FLAG(47, "symjacdumpverbose", false, +constant DebugFlag JAC_DUMP2 = DEBUG_FLAG(46, "symjacdumpverbose", false, Gettext.gettext("Dumps information in verbose mode about symbolic Jacobians. Can be used only with postOptModules: generateSymbolicJacobian, generateSymbolicLinearization.")); -constant DebugFlag JAC_DUMP_EQN = DEBUG_FLAG(48, "symjacdumpeqn", false, +constant DebugFlag JAC_DUMP_EQN = DEBUG_FLAG(47, "symjacdumpeqn", false, Gettext.gettext("Dump for debug purpose of symbolic Jacobians. (deactivated now).")); -constant DebugFlag JAC_WARNINGS = DEBUG_FLAG(49, "symjacwarnings", false, +constant DebugFlag JAC_WARNINGS = DEBUG_FLAG(48, "symjacwarnings", false, Gettext.gettext("Prints warnings regarding symoblic jacbians.")); -constant DebugFlag DUMP_SPARSE = DEBUG_FLAG(50, "dumpSparsePattern", false, +constant DebugFlag DUMP_SPARSE = DEBUG_FLAG(49, "dumpSparsePattern", false, Gettext.gettext("Dumps sparse pattern with coloring used for simulation.")); -constant DebugFlag DUMP_SPARSE_VERBOSE = DEBUG_FLAG(51, "dumpSparsePatternVerbose", false, +constant DebugFlag DUMP_SPARSE_VERBOSE = DEBUG_FLAG(50, "dumpSparsePatternVerbose", false, Gettext.gettext("Dumps in verbose mode sparse pattern with coloring used for simulation.")); -constant DebugFlag BLT_DUMP = DEBUG_FLAG(52, "bltdump", false, +constant DebugFlag BLT_DUMP = DEBUG_FLAG(51, "bltdump", false, Gettext.gettext("Dumps information from index reduction.")); -constant DebugFlag DUMMY_SELECT = DEBUG_FLAG(53, "dummyselect", false, +constant DebugFlag DUMMY_SELECT = DEBUG_FLAG(52, "dummyselect", false, Gettext.gettext("Dumps information from dummy state selection heuristic.")); -constant DebugFlag DUMP_DAE_LOW = DEBUG_FLAG(54, "dumpdaelow", false, +constant DebugFlag DUMP_DAE_LOW = DEBUG_FLAG(53, "dumpdaelow", false, Gettext.gettext("Dumps the equation system at the beginning of the back end.")); -constant DebugFlag DUMP_INDX_DAE = DEBUG_FLAG(55, "dumpindxdae", false, +constant DebugFlag DUMP_INDX_DAE = DEBUG_FLAG(54, "dumpindxdae", false, Gettext.gettext("Dumps the equation system after index reduction and optimization.")); -constant DebugFlag OPT_DAE_DUMP = DEBUG_FLAG(56, "optdaedump", false, +constant DebugFlag OPT_DAE_DUMP = DEBUG_FLAG(55, "optdaedump", false, Gettext.gettext("Dumps information from the optimization modules.")); -constant DebugFlag EXEC_HASH = DEBUG_FLAG(57, "execHash", false, +constant DebugFlag EXEC_HASH = DEBUG_FLAG(56, "execHash", false, Gettext.gettext("Measures the time it takes to hash all simcode variables before code generation.")); -constant DebugFlag PARAM_DLOW_DUMP = DEBUG_FLAG(58, "paramdlowdump", false, +constant DebugFlag PARAM_DLOW_DUMP = DEBUG_FLAG(57, "paramdlowdump", false, Gettext.gettext("Enables dumping of the parameters in the order they are calculated.")); -constant DebugFlag DUMP_ENCAPSULATECONDITIONS = DEBUG_FLAG(59, "dumpEncapsulateConditions", false, +constant DebugFlag DUMP_ENCAPSULATECONDITIONS = DEBUG_FLAG(58, "dumpEncapsulateConditions", false, Gettext.gettext("Dumps the results of the preOptModule encapsulateWhenConditions.")); -constant DebugFlag ON_RELAXATION = DEBUG_FLAG(60, "onRelaxation", false, +constant DebugFlag ON_RELAXATION = DEBUG_FLAG(59, "onRelaxation", false, Gettext.gettext("Perform O(n) relaxation.\nDeprecated flag: Use --postOptModules+=relaxSystem instead.")); -constant DebugFlag SHORT_OUTPUT = DEBUG_FLAG(61, "shortOutput", false, +constant DebugFlag SHORT_OUTPUT = DEBUG_FLAG(60, "shortOutput", false, Gettext.gettext("Enables short output of the simulate() command. Useful for tools like OMNotebook.")); -constant DebugFlag COUNT_OPERATIONS = DEBUG_FLAG(62, "countOperations", false, +constant DebugFlag COUNT_OPERATIONS = DEBUG_FLAG(61, "countOperations", false, Gettext.gettext("Count operations.")); -constant DebugFlag CGRAPH = DEBUG_FLAG(63, "cgraph", false, +constant DebugFlag CGRAPH = DEBUG_FLAG(62, "cgraph", false, Gettext.gettext("Prints out connection graph information.")); -constant DebugFlag UPDMOD = DEBUG_FLAG(64, "updmod", false, +constant DebugFlag UPDMOD = DEBUG_FLAG(63, "updmod", false, Gettext.gettext("Prints information about modification updates.")); -constant DebugFlag STATIC = DEBUG_FLAG(65, "static", false, +constant DebugFlag STATIC = DEBUG_FLAG(64, "static", false, Gettext.gettext("Enables extra debug output from the static elaboration.")); -constant DebugFlag TPL_PERF_TIMES = DEBUG_FLAG(66, "tplPerfTimes", false, +constant DebugFlag TPL_PERF_TIMES = DEBUG_FLAG(65, "tplPerfTimes", false, Gettext.gettext("Enables output of template performance data for rendering text to file.")); -constant DebugFlag CHECK_SIMPLIFY = DEBUG_FLAG(67, "checkSimplify", false, +constant DebugFlag CHECK_SIMPLIFY = DEBUG_FLAG(66, "checkSimplify", false, Gettext.gettext("Enables checks for expression simplification and prints a notification whenever an undesirable transformation has been performed.")); -constant DebugFlag SCODE_INST = DEBUG_FLAG(68, "newInst", false, +constant DebugFlag SCODE_INST = DEBUG_FLAG(67, "newInst", false, Gettext.gettext("Enables experimental new instantiation phase.")); -constant DebugFlag WRITE_TO_BUFFER = DEBUG_FLAG(69, "writeToBuffer", false, +constant DebugFlag WRITE_TO_BUFFER = DEBUG_FLAG(68, "writeToBuffer", false, Gettext.gettext("Enables writing simulation results to buffer.")); -constant DebugFlag DUMP_BACKENDDAE_INFO = DEBUG_FLAG(70, "backenddaeinfo", false, +constant DebugFlag DUMP_BACKENDDAE_INFO = DEBUG_FLAG(69, "backenddaeinfo", false, Gettext.gettext("Enables dumping of back-end information about system (Number of equations before back-end,...).")); -constant DebugFlag GEN_DEBUG_SYMBOLS = DEBUG_FLAG(71, "gendebugsymbols", false, +constant DebugFlag GEN_DEBUG_SYMBOLS = DEBUG_FLAG(70, "gendebugsymbols", false, Gettext.gettext("Generate code with debugging symbols.")); -constant DebugFlag DUMP_STATESELECTION_INFO = DEBUG_FLAG(72, "stateselection", false, +constant DebugFlag DUMP_STATESELECTION_INFO = DEBUG_FLAG(71, "stateselection", false, Gettext.gettext("Enables dumping of selected states. Extends -d=backenddaeinfo.")); -constant DebugFlag DUMP_EQNINORDER = DEBUG_FLAG(73, "dumpeqninorder", false, +constant DebugFlag DUMP_EQNINORDER = DEBUG_FLAG(72, "dumpeqninorder", false, Gettext.gettext("Enables dumping of the equations in the order they are calculated.")); -constant DebugFlag SEMILINEAR = DEBUG_FLAG(74, "semiLinear", false, +constant DebugFlag SEMILINEAR = DEBUG_FLAG(73, "semiLinear", false, Gettext.gettext("Enables dumping of the optimization information when optimizing calls to semiLinear.")); -constant DebugFlag UNCERTAINTIES = DEBUG_FLAG(75, "uncertainties", false, +constant DebugFlag UNCERTAINTIES = DEBUG_FLAG(74, "uncertainties", false, Gettext.gettext("Enables dumping of status when calling modelEquationsUC.")); -constant DebugFlag SHOW_START_ORIGIN = DEBUG_FLAG(76, "showStartOrigin", false, +constant DebugFlag SHOW_START_ORIGIN = DEBUG_FLAG(75, "showStartOrigin", false, Gettext.gettext("Enables dumping of the DAE startOrigin attribute of the variables.")); -constant DebugFlag DUMP_SIMCODE = DEBUG_FLAG(77, "dumpSimCode", false, +constant DebugFlag DUMP_SIMCODE = DEBUG_FLAG(76, "dumpSimCode", false, Gettext.gettext("Dumps the simCode model used for code generation.")); -constant DebugFlag DUMP_INITIAL_SYSTEM = DEBUG_FLAG(78, "dumpinitialsystem", false, +constant DebugFlag DUMP_INITIAL_SYSTEM = DEBUG_FLAG(77, "dumpinitialsystem", false, Gettext.gettext("Dumps the initial equation system.")); -constant DebugFlag GRAPH_INST = DEBUG_FLAG(79, "graphInst", false, +constant DebugFlag GRAPH_INST = DEBUG_FLAG(78, "graphInst", false, Gettext.gettext("Do graph based instantiation.")); -constant DebugFlag GRAPH_INST_RUN_DEP = DEBUG_FLAG(80, "graphInstRunDep", false, +constant DebugFlag GRAPH_INST_RUN_DEP = DEBUG_FLAG(79, "graphInstRunDep", false, Gettext.gettext("Run scode dependency analysis. Use with -d=graphInst")); -constant DebugFlag GRAPH_INST_GEN_GRAPH = DEBUG_FLAG(81, "graphInstGenGraph", false, +constant DebugFlag GRAPH_INST_GEN_GRAPH = DEBUG_FLAG(80, "graphInstGenGraph", false, Gettext.gettext("Dumps a graph of the program. Use with -d=graphInst")); -constant DebugFlag GRAPH_INST_SHOW_GRAPH = DEBUG_FLAG(82, "graphInstShowGraph", false, +constant DebugFlag GRAPH_INST_SHOW_GRAPH = DEBUG_FLAG(81, "graphInstShowGraph", false, Gettext.gettext("Display a graph of the program interactively. Use with -d=graphInst")); -constant DebugFlag DUMP_CONST_REPL = DEBUG_FLAG(83, "dumpConstrepl", false, +constant DebugFlag DUMP_CONST_REPL = DEBUG_FLAG(82, "dumpConstrepl", false, Gettext.gettext("Dump the found replacements for constants.")); -constant DebugFlag SHOW_EQUATION_SOURCE = DEBUG_FLAG(84, "showEquationSource", false, +constant DebugFlag SHOW_EQUATION_SOURCE = DEBUG_FLAG(83, "showEquationSource", false, Gettext.gettext("Display the element source information in the dumped DAE for easier debugging.")); -constant DebugFlag LS_ANALYTIC_JACOBIAN = DEBUG_FLAG(85, "LSanalyticJacobian", false, +constant DebugFlag LS_ANALYTIC_JACOBIAN = DEBUG_FLAG(84, "LSanalyticJacobian", false, Gettext.gettext("Enables analytical jacobian for linear strong components. Defaults to false")); -constant DebugFlag NLS_ANALYTIC_JACOBIAN = DEBUG_FLAG(86, "NLSanalyticJacobian", true, +constant DebugFlag NLS_ANALYTIC_JACOBIAN = DEBUG_FLAG(85, "NLSanalyticJacobian", true, Gettext.gettext("Enables analytical jacobian for non-linear strong components without user-defined function calls, for that see forceNLSanalyticJacobian")); -constant DebugFlag INLINE_SOLVER = DEBUG_FLAG(87, "inlineSolver", false, +constant DebugFlag INLINE_SOLVER = DEBUG_FLAG(86, "inlineSolver", false, Gettext.gettext("Generates code for inline solver.")); -constant DebugFlag HPCOM = DEBUG_FLAG(88, "hpcom", false, +constant DebugFlag HPCOM = DEBUG_FLAG(87, "hpcom", false, Gettext.gettext("Enables parallel calculation based on task-graphs.")); -constant DebugFlag INITIALIZATION = DEBUG_FLAG(89, "initialization", false, +constant DebugFlag INITIALIZATION = DEBUG_FLAG(88, "initialization", false, Gettext.gettext("Shows additional information from the initialization process.")); -constant DebugFlag INLINE_FUNCTIONS = DEBUG_FLAG(90, "inlineFunctions", true, +constant DebugFlag INLINE_FUNCTIONS = DEBUG_FLAG(89, "inlineFunctions", true, Gettext.gettext("Controls if function inlining should be performed.")); -constant DebugFlag DUMP_SCC_GRAPHML = DEBUG_FLAG(91, "dumpSCCGraphML", false, +constant DebugFlag DUMP_SCC_GRAPHML = DEBUG_FLAG(90, "dumpSCCGraphML", false, Gettext.gettext("Dumps graphml files with the strongly connected components.")); -constant DebugFlag TEARING_DUMPVERBOSE = DEBUG_FLAG(92, "tearingdumpV", false, +constant DebugFlag TEARING_DUMPVERBOSE = DEBUG_FLAG(91, "tearingdumpV", false, Gettext.gettext("Dumps verbose tearing information.")); -constant DebugFlag DISABLE_SINGLE_FLOW_EQ = DEBUG_FLAG(93, "disableSingleFlowEq", false, +constant DebugFlag DISABLE_SINGLE_FLOW_EQ = DEBUG_FLAG(92, "disableSingleFlowEq", false, Gettext.gettext("Disables the generation of single flow equations.")); -constant DebugFlag DUMP_DISCRETEVARS_INFO = DEBUG_FLAG(94, "discreteinfo", false, +constant DebugFlag DUMP_DISCRETEVARS_INFO = DEBUG_FLAG(93, "discreteinfo", false, Gettext.gettext("Enables dumping of discrete variables. Extends -d=backenddaeinfo.")); -constant DebugFlag ADDITIONAL_GRAPHVIZ_DUMP = DEBUG_FLAG(95, "graphvizDump", false, +constant DebugFlag ADDITIONAL_GRAPHVIZ_DUMP = DEBUG_FLAG(94, "graphvizDump", false, Gettext.gettext("Activates additional graphviz dumps (as .dot files). It can be used in addition to one of the following flags: {dumpdaelow|dumpinitialsystems|dumpindxdae}.")); -constant DebugFlag INFO_XML_OPERATIONS = DEBUG_FLAG(96, "infoXmlOperations", false, +constant DebugFlag INFO_XML_OPERATIONS = DEBUG_FLAG(95, "infoXmlOperations", false, Gettext.gettext("Enables output of the operations in the _info.xml file when translating models.")); -constant DebugFlag HPCOM_DUMP = DEBUG_FLAG(97, "hpcomDump", false, +constant DebugFlag HPCOM_DUMP = DEBUG_FLAG(96, "hpcomDump", false, Gettext.gettext("Dumps additional information on the parallel execution with hpcom.")); -constant DebugFlag RESOLVE_LOOPS_DUMP = DEBUG_FLAG(98, "resolveLoopsDump", false, +constant DebugFlag RESOLVE_LOOPS_DUMP = DEBUG_FLAG(97, "resolveLoopsDump", false, Gettext.gettext("Debug Output for ResolveLoops Module.")); -constant DebugFlag DISABLE_WINDOWS_PATH_CHECK_WARNING = DEBUG_FLAG(99, "disableWindowsPathCheckWarning", false, +constant DebugFlag DISABLE_WINDOWS_PATH_CHECK_WARNING = DEBUG_FLAG(98, "disableWindowsPathCheckWarning", false, Gettext.gettext("Disables warnings on Windows if OPENMODELICAHOME/MinGW is missing.")); -constant DebugFlag DISABLE_RECORD_CONSTRUCTOR_OUTPUT = DEBUG_FLAG(100, "disableRecordConstructorOutput", false, +constant DebugFlag DISABLE_RECORD_CONSTRUCTOR_OUTPUT = DEBUG_FLAG(99, "disableRecordConstructorOutput", false, Gettext.gettext("Disables output of record constructors in the flat code.")); -constant DebugFlag DUMP_TRANSFORMED_MODELICA_MODEL = DEBUG_FLAG(101, "dumpTransformedModelica", false, +constant DebugFlag DUMP_TRANSFORMED_MODELICA_MODEL = DEBUG_FLAG(100, "dumpTransformedModelica", false, Gettext.gettext("Dumps the back-end DAE to a Modelica-like model after all symbolic transformations are applied.")); -constant DebugFlag EVALUATE_CONST_FUNCTIONS = DEBUG_FLAG(102, "evalConstFuncs", true, +constant DebugFlag EVALUATE_CONST_FUNCTIONS = DEBUG_FLAG(101, "evalConstFuncs", true, Gettext.gettext("Evaluates functions complete and partially and checks for constant output.\nDeprecated flag: Use --preOptModules+=evalFunc instead.")); -constant DebugFlag IMPL_ODE = DEBUG_FLAG(103, "implOde", false, +constant DebugFlag IMPL_ODE = DEBUG_FLAG(102, "implOde", false, Gettext.gettext("activates implicit codegen")); -constant DebugFlag EVAL_FUNC_DUMP = DEBUG_FLAG(104, "evalFuncDump", false, +constant DebugFlag EVAL_FUNC_DUMP = DEBUG_FLAG(103, "evalFuncDump", false, Gettext.gettext("dumps debug information about the function evaluation")); -constant DebugFlag PRINT_STRUCTURAL = DEBUG_FLAG(105, "printStructuralParameters", false, +constant DebugFlag PRINT_STRUCTURAL = DEBUG_FLAG(104, "printStructuralParameters", false, Gettext.gettext("Prints the structural parameters identified by the front-end")); -constant DebugFlag ITERATION_VARS = DEBUG_FLAG(106, "iterationVars", false, +constant DebugFlag ITERATION_VARS = DEBUG_FLAG(105, "iterationVars", false, Gettext.gettext("Shows a list of all iteration variables.")); -constant DebugFlag ALLOW_RECORD_TOO_MANY_FIELDS = DEBUG_FLAG(107, "acceptTooManyFields", false, +constant DebugFlag ALLOW_RECORD_TOO_MANY_FIELDS = DEBUG_FLAG(106, "acceptTooManyFields", false, Gettext.gettext("Accepts passing records with more fields than expected to a function. This is not allowed, but is used in Fluid.Dissipation. See https://trac.modelica.org/Modelica/ticket/1245 for details.")); -constant DebugFlag HPCOM_MEMORY_OPT = DEBUG_FLAG(108, "hpcomMemoryOpt", false, +constant DebugFlag HPCOM_MEMORY_OPT = DEBUG_FLAG(107, "hpcomMemoryOpt", false, Gettext.gettext("Optimize the memory structure regarding the selected scheduler")); -constant DebugFlag DUMP_SYNCHRONOUS = DEBUG_FLAG(109, "dumpSynchronous", false, +constant DebugFlag DUMP_SYNCHRONOUS = DEBUG_FLAG(108, "dumpSynchronous", false, Gettext.gettext("Dumps information of the clock partitioning.")); -constant DebugFlag STRIP_PREFIX = DEBUG_FLAG(110, "stripPrefix", true, +constant DebugFlag STRIP_PREFIX = DEBUG_FLAG(109, "stripPrefix", true, Gettext.gettext("Strips the environment prefix from path/crefs. Defaults to true.")); -constant DebugFlag DO_SCODE_DEP = DEBUG_FLAG(111, "scodeDep", true, +constant DebugFlag DO_SCODE_DEP = DEBUG_FLAG(110, "scodeDep", true, Gettext.gettext("Does scode dependency analysis prior to instantiation. Defaults to true.")); -constant DebugFlag SHOW_INST_CACHE_INFO = DEBUG_FLAG(112, "showInstCacheInfo", false, +constant DebugFlag SHOW_INST_CACHE_INFO = DEBUG_FLAG(111, "showInstCacheInfo", false, Gettext.gettext("Prints information about instantiation cache hits and additions. Defaults to false.")); -constant DebugFlag DUMP_UNIT = DEBUG_FLAG(113, "dumpUnits", false, +constant DebugFlag DUMP_UNIT = DEBUG_FLAG(112, "dumpUnits", false, Gettext.gettext("Dumps all the calculated units.")); -constant DebugFlag DUMP_EQ_UNIT = DEBUG_FLAG(114, "dumpEqInUC", false, +constant DebugFlag DUMP_EQ_UNIT = DEBUG_FLAG(113, "dumpEqInUC", false, Gettext.gettext("Dumps all equations handled by the unit checker.")); -constant DebugFlag DUMP_EQ_UNIT_STRUCT = DEBUG_FLAG(115, "dumpEqUCStruct", false, +constant DebugFlag DUMP_EQ_UNIT_STRUCT = DEBUG_FLAG(114, "dumpEqUCStruct", false, Gettext.gettext("Dumps all the equations handled by the unit checker as tree-structure.")); -constant DebugFlag SHOW_DAE_GENERATION = DEBUG_FLAG(116, "showDaeGeneration", false, +constant DebugFlag SHOW_DAE_GENERATION = DEBUG_FLAG(115, "showDaeGeneration", false, Gettext.gettext("Show the dae variable declarations as they happen.")); -constant DebugFlag RESHUFFLE_POST = DEBUG_FLAG(117, "reshufflePost", false, +constant DebugFlag RESHUFFLE_POST = DEBUG_FLAG(116, "reshufflePost", false, Gettext.gettext("Reshuffles the systems of equations.")); -constant DebugFlag SHOW_EXPANDABLE_INFO = DEBUG_FLAG(118, "showExpandableInfo", false, +constant DebugFlag SHOW_EXPANDABLE_INFO = DEBUG_FLAG(117, "showExpandableInfo", false, Gettext.gettext("Show information about expandable connector handling.")); -constant DebugFlag DUMP_HOMOTOPY = DEBUG_FLAG(119, "dumpHomotopy", false, +constant DebugFlag DUMP_HOMOTOPY = DEBUG_FLAG(118, "dumpHomotopy", false, Gettext.gettext("Dumps the results of the postOptModule optimizeHomotopyCalls.")); -constant DebugFlag OMC_RELOCATABLE_FUNCTIONS = DEBUG_FLAG(120, "relocatableFunctions", false, +constant DebugFlag OMC_RELOCATABLE_FUNCTIONS = DEBUG_FLAG(119, "relocatableFunctions", false, Gettext.gettext("Generates relocatable code: all functions become function pointers and can be replaced at run-time.")); -constant DebugFlag GRAPHML = DEBUG_FLAG(121, "graphml", false, +constant DebugFlag GRAPHML = DEBUG_FLAG(120, "graphml", false, Gettext.gettext("Dumps .graphml files for the bipartite graph after Index Reduction and a task graph for the SCCs. Can be displayed with yEd. ")); -constant DebugFlag USEMPI = DEBUG_FLAG(122, "useMPI", false, +constant DebugFlag USEMPI = DEBUG_FLAG(121, "useMPI", false, Gettext.gettext("Add MPI init and finalize to main method (CPPruntime). ")); -constant DebugFlag DUMP_CSE = DEBUG_FLAG(123, "dumpCSE", false, +constant DebugFlag DUMP_CSE = DEBUG_FLAG(122, "dumpCSE", false, Gettext.gettext("Additional output for CSE module.")); -constant DebugFlag DUMP_CSE_VERBOSE = DEBUG_FLAG(124, "dumpCSE_verbose", false, +constant DebugFlag DUMP_CSE_VERBOSE = DEBUG_FLAG(123, "dumpCSE_verbose", false, Gettext.gettext("Additional output for CSE module.")); -constant DebugFlag ADD_DER_ALIASES = DEBUG_FLAG(125, "addDerAliases", false, +constant DebugFlag ADD_DER_ALIASES = DEBUG_FLAG(124, "addDerAliases", false, Gettext.gettext("Adds for every der-call an alias equation e.g. dx = der(x). It's a work-a-round flag, which helps in some cases to simulate the models e.g. Modelica.Fluid.Examples.HeatExchanger.HeatExchangerSimulation. Deprecated flag: Use --preOptModules+=introduceDerAlias instead.")); -constant DebugFlag DISABLE_COMSUBEXP = DEBUG_FLAG(126, "disableComSubExp", false, +constant DebugFlag DISABLE_COMSUBEXP = DEBUG_FLAG(125, "disableComSubExp", false, Gettext.gettext("Deactivates module 'comSubExp'\nDeprecated flag: Use --preOptModules-=comSubExp instead.")); -constant DebugFlag NO_START_CALC = DEBUG_FLAG(127, "disableStartCalc", false, +constant DebugFlag NO_START_CALC = DEBUG_FLAG(126, "disableStartCalc", false, Gettext.gettext("Deactivates the pre-calculation of start values during compile-time.")); -constant DebugFlag NO_PARTITIONING = DEBUG_FLAG(128, "disablePartitioning", false, +constant DebugFlag NO_PARTITIONING = DEBUG_FLAG(127, "disablePartitioning", false, Gettext.gettext("Deactivates partitioning of entire equation system.\nDeprecated flag: Use --preOptModules-=clockPartitioning instead.")); -constant DebugFlag CONSTJAC = DEBUG_FLAG(129, "constjac", false, +constant DebugFlag CONSTJAC = DEBUG_FLAG(128, "constjac", false, Gettext.gettext("solves linear systems with constant Jacobian and variable b-Vector symbolically")); -constant DebugFlag REDUCE_DYN_OPT = DEBUG_FLAG(130, "reduceDynOpt", false, +constant DebugFlag REDUCE_DYN_OPT = DEBUG_FLAG(129, "reduceDynOpt", false, Gettext.gettext("remove eqs which not need for the calculations of cost and constraints\nDeprecated flag: Use --postOptModules+=reduceDynamicOptimization instead.")); -constant DebugFlag VISUAL_XML = DEBUG_FLAG(131, "visxml", false, +constant DebugFlag VISUAL_XML = DEBUG_FLAG(130, "visxml", false, Gettext.gettext("Outputs a xml-file that contains information for visualization.")); -constant DebugFlag ADD_SCALED_VARS = DEBUG_FLAG(132, "addScaledVars", false, +constant DebugFlag ADD_SCALED_VARS = DEBUG_FLAG(131, "addScaledVars", false, Gettext.gettext("Adds an alias equation var_nrom = var/nominal where var is state\nDeprecated flag: Use --postOptModules+=addScaledVars_states instead.")); -constant DebugFlag ADD_SCALED_VARS_INPUT = DEBUG_FLAG(133, "addScaledVarsInput", false, +constant DebugFlag ADD_SCALED_VARS_INPUT = DEBUG_FLAG(132, "addScaledVarsInput", false, Gettext.gettext("Adds an alias equation var_nrom = var/nominal where var is input\nDeprecated flag: Use --postOptModules+=addScaledVars_inputs instead.")); -constant DebugFlag VECTORIZE = DEBUG_FLAG(134, "vectorize", false, +constant DebugFlag VECTORIZE = DEBUG_FLAG(133, "vectorize", false, Gettext.gettext("Activates vectorization in the backend.")); -constant DebugFlag CHECK_EXT_LIBS = DEBUG_FLAG(135, "buildExternalLibs", true, +constant DebugFlag CHECK_EXT_LIBS = DEBUG_FLAG(134, "buildExternalLibs", true, Gettext.gettext("Use the autotools project in the Resources folder of the library to build missing external libraries.")); -constant DebugFlag RUNTIME_STATIC_LINKING = DEBUG_FLAG(136, "runtimeStaticLinking", false, +constant DebugFlag RUNTIME_STATIC_LINKING = DEBUG_FLAG(135, "runtimeStaticLinking", false, Gettext.gettext("Use the static simulation runtime libraries (C++ simulation runtime).")); -constant DebugFlag SORT_EQNS_AND_VARS = DEBUG_FLAG(137, "dumpSortEqnsAndVars", false, +constant DebugFlag SORT_EQNS_AND_VARS = DEBUG_FLAG(136, "dumpSortEqnsAndVars", false, Gettext.gettext("Dumps debug output for the modules sortEqnsVars.")); -constant DebugFlag DUMP_SIMPLIFY_LOOPS = DEBUG_FLAG(138, "dumpSimplifyLoops", false, +constant DebugFlag DUMP_SIMPLIFY_LOOPS = DEBUG_FLAG(137, "dumpSimplifyLoops", false, Gettext.gettext("Dump between steps of simplifyLoops")); -constant DebugFlag DUMP_RTEARING = DEBUG_FLAG(139, "dumpRecursiveTearing", false, +constant DebugFlag DUMP_RTEARING = DEBUG_FLAG(138, "dumpRecursiveTearing", false, Gettext.gettext("Dump between steps of recursiveTearing")); -constant DebugFlag DIS_SIMP_FUN = DEBUG_FLAG(140, "disableSimplifyComplexFunction", false, +constant DebugFlag DIS_SIMP_FUN = DEBUG_FLAG(139, "disableSimplifyComplexFunction", false, Gettext.gettext("disable simplifyComplexFunction\nDeprecated flag: Use --postOptModules-=simplifyComplexFunction/--initOptModules-=simplifyComplexFunction instead.")); -constant DebugFlag DIS_SYMJAC_FMI20 = DEBUG_FLAG(141, "disableDirectionalDerivatives", true, +constant DebugFlag DIS_SYMJAC_FMI20 = DEBUG_FLAG(140, "disableDirectionalDerivatives", true, Gettext.gettext("For FMI 2.0 only dependecy analysis will be perform.")); -constant DebugFlag EVAL_OUTPUT_ONLY = DEBUG_FLAG(142, "evalOutputOnly", false, +constant DebugFlag EVAL_OUTPUT_ONLY = DEBUG_FLAG(141, "evalOutputOnly", false, Gettext.gettext("Generates equations to calculate outputs only.")); -constant DebugFlag HARDCODED_START_VALUES = DEBUG_FLAG(143, "hardcodedStartValues", false, +constant DebugFlag HARDCODED_START_VALUES = DEBUG_FLAG(142, "hardcodedStartValues", false, Gettext.gettext("Embed the start values of variables and parameters into the c++ code and do not read it from xml file.")); -constant DebugFlag DUMP_FUNCTIONS = DEBUG_FLAG(144, "dumpFunctions", false, +constant DebugFlag DUMP_FUNCTIONS = DEBUG_FLAG(143, "dumpFunctions", false, Gettext.gettext("Add functions to backend dumps.")); -constant DebugFlag DEBUG_DIFFERENTIATION = DEBUG_FLAG(145, "debugDifferentiation", false, +constant DebugFlag DEBUG_DIFFERENTIATION = DEBUG_FLAG(144, "debugDifferentiation", false, Gettext.gettext("Dumps debug output for the differentiation process.")); -constant DebugFlag DEBUG_DIFFERENTIATION_VERBOSE = DEBUG_FLAG(146, "debugDifferentiationVerbose", false, +constant DebugFlag DEBUG_DIFFERENTIATION_VERBOSE = DEBUG_FLAG(145, "debugDifferentiationVerbose", false, Gettext.gettext("Dumps verbose debug output for the differentiation process.")); -constant DebugFlag FMU_EXPERIMENTAL = DEBUG_FLAG(147, "fmuExperimental", false, - Gettext.gettext("Include an extra function in the FMU fmi2GetSpecificDerivatives.")); -constant DebugFlag DUMP_DGESV = DEBUG_FLAG(148, "dumpdgesv", false, +constant DebugFlag FMU_EXPERIMENTAL = DEBUG_FLAG(146, "fmuExperimental", false, + Gettext.gettext("Include an extra function in the FMU fmi7GetSpecificDerivatives.")); +constant DebugFlag DUMP_DGESV = DEBUG_FLAG(147, "dumpdgesv", false, Gettext.gettext("Enables dumping of the information whether DGESV is used to solve linear systems.")); -constant DebugFlag MULTIRATE_PARTITION = DEBUG_FLAG(149, "multirate", false, +constant DebugFlag MULTIRATE_PARTITION = DEBUG_FLAG(148, "multirate", false, Gettext.gettext("The solver can switch partitions in the system.")); -constant DebugFlag DUMP_EXCLUDED_EXP = DEBUG_FLAG(150, "dumpExcludedSymJacExps", false, +constant DebugFlag DUMP_EXCLUDED_EXP = DEBUG_FLAG(149, "dumpExcludedSymJacExps", false, Gettext.gettext("This flags dumps all expression that are excluded from differentiation of a symbolic Jacobian.")); -constant DebugFlag DEBUG_ALGLOOP_JACOBIAN = DEBUG_FLAG(151, "debugAlgebraicLoopsJacobian", false, +constant DebugFlag DEBUG_ALGLOOP_JACOBIAN = DEBUG_FLAG(150, "debugAlgebraicLoopsJacobian", false, Gettext.gettext("Dumps debug output while creating symbolic jacobians for non-linear systems.")); -constant DebugFlag DISABLE_JACSCC = DEBUG_FLAG(152, "disableJacsforSCC", false, +constant DebugFlag DISABLE_JACSCC = DEBUG_FLAG(151, "disableJacsforSCC", false, Gettext.gettext("Disables calculation of jacobians to detect if a SCC is linear or non-linear. By disabling all SCC will handled like non-linear.")); -constant DebugFlag FORCE_NLS_ANALYTIC_JACOBIAN = DEBUG_FLAG(153, "forceNLSanalyticJacobian", false, +constant DebugFlag FORCE_NLS_ANALYTIC_JACOBIAN = DEBUG_FLAG(152, "forceNLSanalyticJacobian", false, Gettext.gettext("Forces calculation analytical jacobian also for non-linear strong components with user-defined functions.")); -constant DebugFlag DUMP_LOOPS = DEBUG_FLAG(154, "dumpLoops", false, +constant DebugFlag DUMP_LOOPS = DEBUG_FLAG(153, "dumpLoops", false, Gettext.gettext("Dumps loop equation.")); -constant DebugFlag DUMP_LOOPS_VERBOSE = DEBUG_FLAG(155, "dumpLoopsVerbose", false, +constant DebugFlag DUMP_LOOPS_VERBOSE = DEBUG_FLAG(154, "dumpLoopsVerbose", false, Gettext.gettext("Dumps loop equation and enhanced adjacency matrix.")); -constant DebugFlag SKIP_INPUT_OUTPUT_SYNTACTIC_SUGAR = DEBUG_FLAG(156, "skipInputOutputSyntacticSugar", false, +constant DebugFlag SKIP_INPUT_OUTPUT_SYNTACTIC_SUGAR = DEBUG_FLAG(155, "skipInputOutputSyntacticSugar", false, Gettext.gettext("Used when bootstrapping to preserve the input output parsing of the code output by the list command.")); -constant DebugFlag OMC_RECORD_ALLOC_WORDS = DEBUG_FLAG(157, "metaModelicaRecordAllocWords", false, +constant DebugFlag OMC_RECORD_ALLOC_WORDS = DEBUG_FLAG(156, "metaModelicaRecordAllocWords", false, Gettext.gettext("Instrument the source code to record memory allocations (requires run-time and generated files compiled with -DOMC_RECORD_ALLOC_WORDS).")); -constant DebugFlag TOTAL_TEARING_DUMP = DEBUG_FLAG(158, "totaltearingdump", false, +constant DebugFlag TOTAL_TEARING_DUMP = DEBUG_FLAG(157, "totaltearingdump", false, Gettext.gettext("Dumps total tearing information.")); -constant DebugFlag TOTAL_TEARING_DUMPVERBOSE = DEBUG_FLAG(159, "totaltearingdumpV", false, +constant DebugFlag TOTAL_TEARING_DUMPVERBOSE = DEBUG_FLAG(158, "totaltearingdumpV", false, Gettext.gettext("Dumps verbose total tearing information.")); -constant DebugFlag PARALLEL_CODEGEN = DEBUG_FLAG(160, "parallelCodegen", true, +constant DebugFlag PARALLEL_CODEGEN = DEBUG_FLAG(159, "parallelCodegen", true, Gettext.gettext("Enables code generation in parallel (disable this if compiling a model causes you to run out of RAM).")); -constant DebugFlag SERIALIZED_SIZE = DEBUG_FLAG(161, "reportSerializedSize", false, +constant DebugFlag SERIALIZED_SIZE = DEBUG_FLAG(160, "reportSerializedSize", false, Gettext.gettext("Reports serialized sizes of various data structures used in the compiler.")); -constant DebugFlag BACKEND_KEEP_ENV_GRAPH = DEBUG_FLAG(162, "backendKeepEnv", true, +constant DebugFlag BACKEND_KEEP_ENV_GRAPH = DEBUG_FLAG(161, "backendKeepEnv", true, Gettext.gettext("When enabled, the environment is kept when entering the backend, which enables CevalFunction (function interpretation) to work. This module not essential for the backend to function in most cases, but can improve simulation performance by evaluating functions. The drawback to keeping the environment graph in memory is that it is huge (~80% of the total memory in use when returning the frontend DAE).")); -constant DebugFlag DUMPBACKENDINLINE = DEBUG_FLAG(163, "dumpBackendInline", false, +constant DebugFlag DUMPBACKENDINLINE = DEBUG_FLAG(162, "dumpBackendInline", false, Gettext.gettext("Dumps debug output while inline function.")); -constant DebugFlag DUMPBACKENDINLINE_VERBOSE = DEBUG_FLAG(164, "dumpBackendInlineVerbose", false, +constant DebugFlag DUMPBACKENDINLINE_VERBOSE = DEBUG_FLAG(163, "dumpBackendInlineVerbose", false, Gettext.gettext("Dumps debug output while inline function.")); -constant DebugFlag BLT_MATRIX_DUMP = DEBUG_FLAG(165, "bltmatrixdump", false, +constant DebugFlag BLT_MATRIX_DUMP = DEBUG_FLAG(164, "bltmatrixdump", false, Gettext.gettext("Dumps the blt matrix in html file. IE seems to be very good in displaying large matrices.")); -constant DebugFlag LIST_REVERSE_WRONG_ORDER = DEBUG_FLAG(166, "listAppendWrongOrder", true, +constant DebugFlag LIST_REVERSE_WRONG_ORDER = DEBUG_FLAG(165, "listAppendWrongOrder", true, Gettext.gettext("Print notifications about bad usage of listAppend.")); -constant DebugFlag PARTITION_INITIALIZATION = DEBUG_FLAG(167, "partitionInitialization", true, +constant DebugFlag PARTITION_INITIALIZATION = DEBUG_FLAG(166, "partitionInitialization", true, Gettext.gettext("This flag controls if partitioning is applied to the initialization system.")); -constant DebugFlag EVAL_PARAM_DUMP = DEBUG_FLAG(168, "evalParameterDump", false, +constant DebugFlag EVAL_PARAM_DUMP = DEBUG_FLAG(167, "evalParameterDump", false, Gettext.gettext("Dumps information for evaluating parameters.")); -constant DebugFlag NF_UNITCHECK = DEBUG_FLAG(169, "frontEndUnitCheck", false, +constant DebugFlag NF_UNITCHECK = DEBUG_FLAG(168, "frontEndUnitCheck", false, Gettext.gettext("Checks the consistency of units in equation.")); -constant DebugFlag DISABLE_COLORING = DEBUG_FLAG(170, "disableColoring", false, +constant DebugFlag DISABLE_COLORING = DEBUG_FLAG(169, "disableColoring", false, Gettext.gettext("Disables coloring algorithm while spasity detection.")); -constant DebugFlag MERGE_ALGORITHM_SECTIONS = DEBUG_FLAG(171, "mergeAlgSections", false, +constant DebugFlag MERGE_ALGORITHM_SECTIONS = DEBUG_FLAG(170, "mergeAlgSections", false, Gettext.gettext("Disables coloring algorithm while sparsity detection.")); -constant DebugFlag WARN_NO_NOMINAL = DEBUG_FLAG(172, "warnNoNominal", false, +constant DebugFlag WARN_NO_NOMINAL = DEBUG_FLAG(171, "warnNoNominal", false, Gettext.gettext("Prints the iteration variables in the initialization and simulation DAE, which do not have a nominal value.")); -constant DebugFlag REDUCE_DAE = DEBUG_FLAG(173, "backendReduceDAE", false, +constant DebugFlag REDUCE_DAE = DEBUG_FLAG(172, "backendReduceDAE", false, Gettext.gettext("Prints all Reduce DAE debug information.")); -constant DebugFlag IGNORE_CYCLES = DEBUG_FLAG(174, "ignoreCycles", false, +constant DebugFlag IGNORE_CYCLES = DEBUG_FLAG(173, "ignoreCycles", false, Gettext.gettext("Ignores cycles between constant/parameter components.")); -constant DebugFlag ALIAS_CONFLICTS = DEBUG_FLAG(175, "aliasConflicts", false, +constant DebugFlag ALIAS_CONFLICTS = DEBUG_FLAG(174, "aliasConflicts", false, Gettext.gettext("Dumps alias sets with different start or nominal values.")); -constant DebugFlag SUSAN_MATCHCONTINUE_DEBUG = DEBUG_FLAG(176, "susanDebug", false, +constant DebugFlag SUSAN_MATCHCONTINUE_DEBUG = DEBUG_FLAG(175, "susanDebug", false, Gettext.gettext("Makes Susan generate code using try/else to better debug which function broke the expected match semantics.")); -constant DebugFlag OLD_FE_UNITCHECK = DEBUG_FLAG(177, "oldFrontEndUnitCheck", false, +constant DebugFlag OLD_FE_UNITCHECK = DEBUG_FLAG(176, "oldFrontEndUnitCheck", false, Gettext.gettext("Checks the consistency of units in equation (for the old front-end).")); -constant DebugFlag EXEC_STAT_EXTRA_GC = DEBUG_FLAG(178, "execstatGCcollect", false, +constant DebugFlag EXEC_STAT_EXTRA_GC = DEBUG_FLAG(177, "execstatGCcollect", false, Gettext.gettext("When running execstat, also perform an extra full garbage collection.")); -constant DebugFlag DEBUG_DAEMODE = DEBUG_FLAG(179, "debugDAEmode", false, +constant DebugFlag DEBUG_DAEMODE = DEBUG_FLAG(178, "debugDAEmode", false, Gettext.gettext("Dump debug output for the DAEmode.")); -constant DebugFlag NF_SCALARIZE = DEBUG_FLAG(180, "nfScalarize", true, +constant DebugFlag NF_SCALARIZE = DEBUG_FLAG(179, "nfScalarize", true, Gettext.gettext("Run scalarization in NF, default true.")); -constant DebugFlag NF_EVAL_CONST_ARG_FUNCS = DEBUG_FLAG(181, "nfEvalConstArgFuncs", true, +constant DebugFlag NF_EVAL_CONST_ARG_FUNCS = DEBUG_FLAG(180, "nfEvalConstArgFuncs", true, Gettext.gettext("Evaluate all functions with constant arguments in the new frontend.")); -constant DebugFlag NF_EXPAND_OPERATIONS = DEBUG_FLAG(182, "nfExpandOperations", true, +constant DebugFlag NF_EXPAND_OPERATIONS = DEBUG_FLAG(181, "nfExpandOperations", true, Gettext.gettext("Expand all unary/binary operations to scalar expressions in the new frontend.")); -constant DebugFlag NF_API = DEBUG_FLAG(183, "nfAPI", false, +constant DebugFlag NF_API = DEBUG_FLAG(182, "nfAPI", false, Gettext.gettext("Enables experimental new instantiation use in the OMC API.")); -constant DebugFlag NF_API_DYNAMIC_SELECT = DEBUG_FLAG(184, "nfAPIDynamicSelect", false, +constant DebugFlag NF_API_DYNAMIC_SELECT = DEBUG_FLAG(183, "nfAPIDynamicSelect", false, Gettext.gettext("Show DynamicSelect(static, dynamic) in annotations. Default to false and will select the first (static) expression")); -constant DebugFlag NF_API_NOISE = DEBUG_FLAG(185, "nfAPINoise", false, +constant DebugFlag NF_API_NOISE = DEBUG_FLAG(184, "nfAPINoise", false, Gettext.gettext("Enables error display for the experimental new instantiation use in the OMC API.")); -constant DebugFlag FMI20_DEPENDENCIES = DEBUG_FLAG(186, "disableFMIDependency", false, +constant DebugFlag FMI20_DEPENDENCIES = DEBUG_FLAG(185, "disableFMIDependency", false, Gettext.gettext("Disables the dependency analysis and generation for FMI 2.0.")); -constant DebugFlag WARNING_MINMAX_ATTRIBUTES = DEBUG_FLAG(187, "warnMinMax", true, +constant DebugFlag WARNING_MINMAX_ATTRIBUTES = DEBUG_FLAG(186, "warnMinMax", true, Gettext.gettext("Makes a warning assert from min/max variable attributes instead of error.")); -constant DebugFlag NF_EXPAND_FUNC_ARGS = DEBUG_FLAG(188, "nfExpandFuncArgs", false, +constant DebugFlag NF_EXPAND_FUNC_ARGS = DEBUG_FLAG(187, "nfExpandFuncArgs", false, Gettext.gettext("Expand all function arguments in the new frontend.")); -constant DebugFlag DUMP_JL = DEBUG_FLAG(189, "dumpJL", false, +constant DebugFlag DUMP_JL = DEBUG_FLAG(188, "dumpJL", false, Gettext.gettext("Dumps the absyn representation of a program as a Julia representation")); -constant DebugFlag DUMP_ASSC = DEBUG_FLAG(190, "dumpASSC", false, +constant DebugFlag DUMP_ASSC = DEBUG_FLAG(189, "dumpASSC", false, Gettext.gettext("Dumps the conversion process of analytical to structural singularities.")); -constant DebugFlag SPLIT_CONSTANT_PARTS_SYMJAC = DEBUG_FLAG(191, "symJacConstantSplit", false, +constant DebugFlag SPLIT_CONSTANT_PARTS_SYMJAC = DEBUG_FLAG(190, "symJacConstantSplit", false, Gettext.gettext("Generates all symbolic Jacobians with splitted constant parts.")); -constant DebugFlag NF_DUMP_FLAT = DEBUG_FLAG(192, "nfDumpFlat", false, +constant DebugFlag NF_DUMP_FLAT = DEBUG_FLAG(191, "nfDumpFlat", false, Gettext.gettext("Dumps the flat model structure before generating the DAE.")); -constant DebugFlag DUMP_FORCE_FMI_ATTRIBUTES = DEBUG_FLAG(193, "force-fmi-attributes", false, +constant DebugFlag DUMP_FORCE_FMI_ATTRIBUTES = DEBUG_FLAG(192, "force-fmi-attributes", false, Gettext.gettext("Force to export all fmi attributes to the modelDescription.xml, including those which have default values")); -constant DebugFlag DUMP_DATARECONCILIATION = DEBUG_FLAG(194, "dataReconciliation", false, +constant DebugFlag DUMP_DATARECONCILIATION = DEBUG_FLAG(193, "dataReconciliation", false, Gettext.gettext("Dumps all the dataReconciliation extraction algorithm procedure")); -constant DebugFlag ARRAY_CONNECT = DEBUG_FLAG(195, "arrayConnect", false, +constant DebugFlag ARRAY_CONNECT = DEBUG_FLAG(194, "arrayConnect", false, Gettext.gettext("Use experimental array connection handler.")); public @@ -1383,6 +1381,10 @@ constant ConfigFlag NEW_BACKEND = CONFIG_FLAG(145, "newBackend", NONE(), EXTERNAL(), BOOL_FLAG(false), NONE(), Gettext.gettext("Activates experimental new backend for better array handling. This also activates the new frontend. [WIP]")); +constant ConfigFlag PARMODAUTO = CONFIG_FLAG(146, "parmodauto", + NONE(), EXTERNAL(), BOOL_FLAG(false), NONE(), + Gettext.gettext("Experimental: Enable parallelization of independent systems of equations in the translated model.")); + function getFlags "Loads the flags with getGlobalRoot. Assumes flags have been loaded." input Boolean initialize = true; diff --git a/OMCompiler/Compiler/Util/FlagsUtil.mo b/OMCompiler/Compiler/Util/FlagsUtil.mo index 4adae0ab036..30bba897850 100644 --- a/OMCompiler/Compiler/Util/FlagsUtil.mo +++ b/OMCompiler/Compiler/Util/FlagsUtil.mo @@ -60,7 +60,6 @@ constant list allDebugFlags = { Flags.FAILTRACE, Flags.CEVAL, Flags.CHECK_BACKEND_DAE, - Flags.PARMODAUTO, Flags.PTHREADS, Flags.EVENTS, Flags.DUMP_INLINE_SOLVER, @@ -403,7 +402,9 @@ constant list allConfigFlags = { Flags.FMI_FILTER, Flags.FMI_SOURCES, Flags.FMI_FLAGS, - Flags.NEW_BACKEND + Flags.NEW_BACKEND, + Flags.PARMODAUTO + }; public function new diff --git a/OMCompiler/Compiler/boot/LoadCompilerSources.mos b/OMCompiler/Compiler/boot/LoadCompilerSources.mos index 9acc277d22c..4ef85dc268d 100644 --- a/OMCompiler/Compiler/boot/LoadCompilerSources.mos +++ b/OMCompiler/Compiler/boot/LoadCompilerSources.mos @@ -404,6 +404,7 @@ if true then /* Suppress output */ "../SimCode/HpcOmSimCodeMain.mo", "../SimCode/SerializeInitXML.mo", "../SimCode/SerializeModelInfo.mo", + "../SimCode/SerializeTaskSystemInfo.mo", "../SimCode/SimCode.mo", "../SimCode/SimCodeMain.mo", "../SimCode/SimCodeUtil.mo", @@ -445,7 +446,6 @@ if true then /* Suppress output */ "../Template/GraphMLDumpTpl.mo", "../Template/NFInstDumpTpl.mo", "../Template/SimCodeDump.mo", - "../Template/TaskSystemDump.mo", "../Template/VisualXMLTpl.mo", "../Util/AvlTree.mo", diff --git a/OMCompiler/Makefile.common b/OMCompiler/Makefile.common index 57846068045..fd18220dc82 100644 --- a/OMCompiler/Makefile.common +++ b/OMCompiler/Makefile.common @@ -1,5 +1,5 @@ -inclu.PHONY : all omc release clean .testvariables checkMSVCwine bootstrap-dependencies-post bootstrap-dependencies-post-compiler-runtime bootstrap-dependencies-post-compiler-builtin bootstrap-dependencies-post-parser +inclu.PHONY : all omc release clean .testvariables checkMSVCwine bootstrap-dependencies-post bootstrap-dependencies-post-compiler-runtime bootstrap-dependencies-post-compiler-builtin bootstrap-dependencies-post-parser parmodauto unexport PREFIX @@ -103,7 +103,7 @@ bootstrap-dependencies: $(BOOTSTRAP_FMIL_DEP) cppzmq interactive-short antlr-copy: cp ./3rdParty/antlr/3.2/tool/antlr-3.2.jar ./3rdParty/antlr/3.2/tool/antlr-2.7.7.jar ${builddir_java}/ -sim-dependencies: fmi $(BOOTSTRAP_FMIL_DEP) opencl_rt lis metis opc +sim-dependencies: fmi $(BOOTSTRAP_FMIL_DEP) opencl_rt lis metis opc parmodauto install-openturns: (time cp SimulationRuntime/OpenTurns/* $(builddir_share)/omc/scripts/OpenTurns/) @@ -216,6 +216,17 @@ endif opencl_rt_clean: $(MAKE) -C SimulationRuntime/ParModelica/explicit/openclrt -f $(defaultMakefileTarget) clean OMBUILDDIR=$(OMBUILDDIR) + +parmodauto: boehm-gc +ifeq ("$(ENABLE_PARMODAUTO)","yes") + $(MAKE) -C $(OMC_TBB_ROOT)/build_cmake/ install_for_omc + $(MAKE) -C SimulationRuntime/ParModelica/auto/ -f $(defaultMakefileTarget) OMBUILDDIR=$(OMBUILDDIR) +endif + +parmodauto_clean: + $(MAKE) -C SimulationRuntime/ParModelica/auto/ -f $(defaultMakefileTarget) clean OMBUILDDIR=$(OMBUILDDIR) + + breakprocess: (cd tools/debugging/ && time g++ BreakProcess.cpp -o BreakProcess -static-libgcc) (cd tools/debugging/ && cp BreakProcess.exe $(builddir_bin)) @@ -474,7 +485,7 @@ openblas-clean: # OpenBLAS make clean actually gives error-messages. Let it do it, but silently test ! -d 3rdParty/OpenBLAS-0.2.8 || $(MAKE) -C 3rdParty/OpenBLAS-0.2.8 clean > /dev/null 2>&1 -clean: $(SEMLA_CLEAN) fmil-clean opencl_rt_clean gc-clean lis-clean runtimeCPPclean CMinpack-clean metis-clean Cdaskr-clean bootstrap-clean msgpack-clean graphstream-clean openblas-clean umfpack-clean OMSI-clean +clean: $(SEMLA_CLEAN) fmil-clean opencl_rt_clean gc-clean lis-clean runtimeCPPclean CMinpack-clean metis-clean Cdaskr-clean bootstrap-clean msgpack-clean graphstream-clean openblas-clean umfpack-clean OMSI-clean parmodauto_clean (cd SimulationRuntime/c && $(MAKE) -f $(defaultMakefileTarget) clean OMBUILDDIR=$(OMBUILDDIR)) (cd Compiler && $(MAKE) -f $(defaultMakefileTarget) clean OMBUILDDIR=$(OMBUILDDIR)) (cd Parser && $(MAKE) -f $(defaultMakefileTarget) clean OMBUILDDIR=$(OMBUILDDIR)) diff --git a/OMCompiler/Makefile.in b/OMCompiler/Makefile.in index 4c1aee5b693..897f1f8e04a 100644 --- a/OMCompiler/Makefile.in +++ b/OMCompiler/Makefile.in @@ -21,6 +21,8 @@ host = @host@ host_short = @host_short@ FC = @FC@ FCFLAGS = @FCFLAGS@ +ENABLE_PARMODAUTO = @ENABLE_PARMODAUTO@ +OMC_TBB_ROOT = @OMC_TBB_ROOT@ defaultMakefileTarget = Makefile MAKEFILE_BOOT = LinkMain.makefile diff --git a/OMCompiler/Makefile.omdev.mingw b/OMCompiler/Makefile.omdev.mingw index a207e0da0c5..46f627487f1 100644 --- a/OMCompiler/Makefile.omdev.mingw +++ b/OMCompiler/Makefile.omdev.mingw @@ -311,7 +311,7 @@ copycppmsvcheader_old: getMSVCversion (cp -puf $(BOOST_PATH_MSVC)/boost/*.hpp $(OMBUILDDIR)/include/omc/cpp/3rdParty/boost/msvc/boost) (cp -pufr $(BOOST_PATH_MSVC)/boost/* $(OMBUILDDIR)/include/omc/cpp/3rdParty/boost/msvc/boost) -omc: interactive fmil omdev_extra_dlls breakprocess opencl_rt CMinpack metis Cdaskr $(IPOPT_TARGET) graphstream $(SEMLA_LIB) OMSI +omc: interactive fmil omdev_extra_dlls breakprocess opencl_rt CMinpack metis Cdaskr $(IPOPT_TARGET) graphstream $(SEMLA_LIB) OMSI parmodauto (time $(MAKE) -f $(defaultMakefileTarget) CFLAGS="$(CFLAGS)" omc-bootstrapped OMBUILDDIR=$(OMBUILDDIR)) boehm-gc-lib: $(OMBUILDDIR)/$(LIB_OMC)/libomcgc.a diff --git a/OMCompiler/SimulationRuntime/CMakeLists.txt b/OMCompiler/SimulationRuntime/CMakeLists.txt index bb565c9ee67..bfc0cb4d1fb 100644 --- a/OMCompiler/SimulationRuntime/CMakeLists.txt +++ b/OMCompiler/SimulationRuntime/CMakeLists.txt @@ -1,6 +1,6 @@ omc_add_subdirectory(c) -# omc_add_subdirectory(ParModelica) +omc_add_subdirectory(ParModelica) #ADD_SUBDIRECTORY(cpp) #ADD_SUBDIRECTORY(fmi) #ADD_SUBDIRECTORY(interactive) diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/CMakeLists.txt b/OMCompiler/SimulationRuntime/ParModelica/auto/CMakeLists.txt index 3504628f851..4f92f80a892 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/CMakeLists.txt +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/CMakeLists.txt @@ -1,47 +1,24 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.8) +cmake_minimum_required(VERSION 3.14) -PROJECT(ParModelicaAuto) +project(ParModelicaAuto) -SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}") +find_package(Boost REQUIRED COMPONENTS graph chrono) -if( CMAKE_SIZEOF_VOID_P EQUAL 8 ) - SET(TBB_ARCHITECTURE intel64) -elseif( CMAKE_SIZEOF_VOID_P EQUAL 4 ) - SET(TBB_ARCHITECTURE ia32) +set(PARMODAUTO_SOURCES om_pm_equation.cpp om_pm_interface.cpp om_pm_model.cpp pm_utility.cpp) + +add_library(ParModelicaAuto STATIC) +target_sources(ParModelicaAuto PRIVATE ${PARMODAUTO_SOURCES}) +if(WIN32) + target_sources(ParModelicaAuto PRIVATE pm_win_timer.cpp) else() - MESSAGE(FATAL "Unknown Compiler Architecture") + target_sources(ParModelicaAuto PRIVATE pm_posix_timer.cpp) endif() -FIND_PACKAGE(TBB REQUIRED) -FIND_PACKAGE(PugiXML REQUIRED) -FIND_PACKAGE(Boost REQUIRED COMPONENTS system) - -SET(PARMODELICA_SRC om_pm_equation.cpp - om_pm_interface.cpp - om_pm_model.cpp - pm_utility.cpp) - -SET(PARMODELICA_TEST_SRC test_task_graph.cpp) - -IF(UNIX) - SET(PARMODELICA_SRC ${PARMODELICA_SRC} pm_posix_timer.cpp) -ELSE(UNIX) - SET(PARMODELICA_SRC ${PARMODELICA_SRC} pm_win_timer.cpp) -ENDIF(UNIX) - -IF(MSVC) - ADD_DEFINITIONS("/DNOMINMAX") -ENDIF() - -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) -INCLUDE_DIRECTORIES(${TBB_INCLUDE_DIR}) -INCLUDE_DIRECTORIES(${PUGIXML_INCLUDE_DIR}) -INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) -INCLUDE_DIRECTORIES(../../c) - -ADD_LIBRARY(ParModelicaAuto ${PARMODELICA_SRC}) - -ADD_EXECUTABLE(ParModelicaAutoTest ${PARMODELICA_TEST_SRC}) -TARGET_LINK_LIBRARIES(ParModelicaAutoTest ParModelicaAuto ${TBB_LIBRARY} ${PUGIXML_LIBRARY} ${Boost_SYSTEM_LIBRARY}) +target_link_libraries(ParModelicaAuto PUBLIC omc::simrt::runtime) +target_link_libraries(ParModelicaAuto PUBLIC omc::3rd::tbb) +target_compile_definitions(ParModelicaAuto PRIVATE USE_FLOW_SCHEDULER) +add_executable(ParModelicaAutoTest) +target_sources(ParModelicaAutoTest PRIVATE test_task_graph.cpp) +target_link_libraries(ParModelicaAutoTest ParModelicaAuto ParModelicaAuto) diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/Makefile.common b/OMCompiler/SimulationRuntime/ParModelica/auto/Makefile.common index 535d247b642..725625645f9 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/Makefile.common +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/Makefile.common @@ -8,8 +8,6 @@ om_pm_equation.cpp \ pm_utility.cpp \ om_pm_interface.cpp \ om_pm_model.cpp -# ParModelicaTaskGrapExt_rml.cpp -# ParModelicaTaskGrapExt_omc.cpp \ HDRS = *.hpp *.inl OBJS = $(SRCS:.cpp=.o) @@ -19,12 +17,24 @@ DPFLAGS = -MM .PHONY : clean +# default number of threads if not specified. +DEFAULT_NUM_THREADS=4 + +ifeq ($(USE_LEVEL_SCHEDULER), 1) +CPPFLAGS += -DUSE_LEVEL_SCHEDULER +# $(info ************ COMPILING FOR LEVEL SCHEDULER ************) +else +# $(info ************ COMPILING FOR FLOW SCHEDULER ************) +CPPFLAGS += -DUSE_FLOW_SCHEDULER +endif + + libParModelicaAuto.a: $(OBJS) @rm -f $@ $(AR_) $@ $(OBJS) .cpp.o: $(DPFILE) - $(CC) $(CPPFLAGS) $(INCDIRS) -c $< + $(CXX) $(CPPFLAGS) $(INCDIRS) -c $< test: test_task_graph.cpp libParModelicaAuto.a $(CXX) $(CPPFLAGS) -I. $(INCDIRS) test_task_graph.cpp -o gen_graph$(EXEEXT) libParModelicaAuto.a -L$(TBB_LIB) -ltbb @@ -34,6 +44,6 @@ clean : touch $(DPFILE) $(DPFILE) depend : $(HDRS) $(SRCS) - $(CC) $(DPFLAGS) $(CPPFLAGS) $(SRCS) > $(DPFILE) + $(CXX) $(DPFLAGS) $(CPPFLAGS) $(INCDIRS) $(SRCS) > $(DPFILE) -include $(DPFILE) \ No newline at end of file +include $(DPFILE) diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/Makefile.in b/OMCompiler/SimulationRuntime/ParModelica/auto/Makefile.in index 6b5d910c4db..2bf18c78be3 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/Makefile.in +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/Makefile.in @@ -1,20 +1,19 @@ TOP_BUILDDIR = @OMBUILDDIR@ -HOST_SHORT = @host_short@ +OMCOMPILER_ROOT = $(realpath ../../../) OPENMODELICA_INC=$(TOP_BUILDDIR)/include/omc/c/ PARMODELICAAUTO_INC=$(OPENMODELICA_INC)/ParModelica/auto/ -OPENMODELICA_LIB=$(TOP_BUILDDIR)/lib/$(HOST_SHORT)/omc +OPENMODELICA_LIB=$(TOP_BUILDDIR)/lib/@host_short@/omc OPENMODELICA_BIN=$(TOP_BUILDDIR)/bin/ BOOST_HOME = @BOOSTHOME@ -INCDIRS = -I"../../c" -I$(BOOST_HOME) -I"../pugixml-1.2/src/" - - +OMC_TBB_ROOT = @OMC_TBB_ROOT@ +INCDIRS = -I"../../c" -I$(BOOST_HOME) -I$(OMC_TBB_ROOT)/include -I$(OMCOMPILER_ROOT)/3rdParty/gc/include CC=@CC@ CXX=@CXX@ -CFLAGS=@CFLAGS@ $(INCDIRS) -CPPFLAGS= -O3 -Wall -fPIC +CFLAGS=@CFLAGS@ +CPPFLAGS= -O3 -Wall -DGC_THREADS OS_SRCS = pm_posix_timer.cpp @@ -27,7 +26,6 @@ transfer: libParModelicaAuto.a $(COPY) libParModelicaAuto.a $(OPENMODELICA_LIB) mkdir -p $(PARMODELICAAUTO_INC) $(COPY) om_pm_interface.hpp $(PARMODELICAAUTO_INC) - $(COPY) om_pm_model.hpp $(PARMODELICAAUTO_INC) Makefile: Makefile.in (cd ../../../ && ./config.status) diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/Makefile.omdev.mingw b/OMCompiler/SimulationRuntime/ParModelica/auto/Makefile.omdev.mingw index 203bdac2588..99a084afd09 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/Makefile.omdev.mingw +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/Makefile.omdev.mingw @@ -1,19 +1,19 @@ -TOP_BUILDDIR = ../../../build/ +TOP_BUILDDIR = $(realpath ../../../../)/build +OMCOMPILER_ROOT = $(realpath ../../../) OPENMODELICA_INC=$(TOP_BUILDDIR)/include/omc/c/ PARMODELICAAUTO_INC=$(OPENMODELICA_INC)/ParModelica/auto/ OPENMODELICA_LIB=$(TOP_BUILDDIR)/lib/omc/ OPENMODELICA_BIN=$(TOP_BUILDDIR)/bin/ -TBB_INC = $(OMC_TBB_INC) -TBB_LIB = $(OMC_TBB_LIB) +OMC_TBB_ROOT = $(OMCOMPILER_ROOT)/3rdParty/tbb/ BOOST_HOME = $(OMDEV)/lib/3rdParty/boost-1_49 -INCDIRS = -I"../../c" -I$(TBB_INC) -I$(BOOST_HOME) -I"../pugixml-1.2/src/" +INCDIRS = -I"../../c" -I$(BOOST_HOME) -I$(OMC_TBB_ROOT)/include -I$(OMCOMPILER_ROOT)/3rdParty/gc/include CC=gcc CXX=g++ -CFLAGS= -O3 -Wall -CPPFLAGS= -O3 -Wall +CFLAGS= -O0 -g -Wall +CPPFLAGS= $(CFLAGS) -std=c++11 -DGC_THREADS OS_SRCS = pm_win_timer.cpp @@ -26,7 +26,6 @@ transfer: libParModelicaAuto.a $(COPY) libParModelicaAuto.a $(OPENMODELICA_LIB) mkdir -p $(PARMODELICAAUTO_INC) $(COPY) om_pm_interface.hpp $(PARMODELICAAUTO_INC) - $(COPY) om_pm_model.hpp $(PARMODELICAAUTO_INC) include Makefile.common diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_equation.cpp b/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_equation.cpp index 50c46172fca..6f2d54df9cf 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_equation.cpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_equation.cpp @@ -29,27 +29,16 @@ * */ - /* - Mahder.Gebremedhin@liu.se 2014-02-10 + Mahder.Gebremedhin@liu.se 2020-10-12 */ - - - #include #include #include "om_pm_equation.hpp" #include "pm_utility.hpp" +namespace openmodelica { namespace parmodelica { -namespace openmodelica { -namespace parmodelica { - - - -} // openmodelica -} // parmodelica - - +}} // namespace openmodelica::parmodelica diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_equation.hpp b/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_equation.hpp index 3b7e8d44a17..46fb0bdfec5 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_equation.hpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_equation.hpp @@ -1,61 +1,61 @@ -#pragma once -#ifndef idA890A2D6_30B0_44AD_B07DF074DD9AC126 -#define idA890A2D6_30B0_44AD_B07DF074DD9AC126 - - -/* - * This file is part of OpenModelica. - * - * Copyright (c) 1998-CurrentYear, Linköping University, - * Department of Computer and Information Science, - * SE-58183 Linköping, Sweden. - * - * All rights reserved. - * - * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 - * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). - * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S - * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. - * - * The OpenModelica software and the Open Source Modelica - * Consortium (OSMC) Public License (OSMC-PL) are obtained - * from Linköping University, either from the above address, - * from the URLs: http://www.ida.liu.se/projects/OpenModelica or - * http://www.openmodelica.org, and in the OpenModelica distribution. - * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. - * - * This program is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH - * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS - * OF OSMC-PL. - * - * See the full OSMC Public License conditions for more details. - * - */ - - -/* - Mahder.Gebremedhin@liu.se 2014-02-10 -*/ - - - - -#include -#include -#include -#include - - - -namespace openmodelica { -namespace parmodelica { - - -} // openmodelica -} // parmodelica - - - +#pragma once +#ifndef idA890A2D6_30B0_44AD_B07DF074DD9AC126 +#define idA890A2D6_30B0_44AD_B07DF074DD9AC126 + + +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Linköping University, + * Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 + * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S + * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from Linköping University, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS + * OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ + + +/* + Mahder.Gebremedhin@liu.se 2020-10-12 +*/ + + + + +#include +#include +#include +#include + + + +namespace openmodelica { +namespace parmodelica { + + +} // openmodelica +} // parmodelica + + + #endif // header \ No newline at end of file diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_interface.cpp b/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_interface.cpp index 650f2ecfe33..25a28dc00ef 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_interface.cpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_interface.cpp @@ -29,89 +29,96 @@ * */ - /* - Mahder.Gebremedhin@liu.se 2014-02-10 + Mahder.Gebremedhin@liu.se 2020-10-12 */ - #include #include "om_pm_interface.hpp" #include "om_pm_model.hpp" - extern "C" { using namespace openmodelica::parmodelica; typedef Equation::FunctionType FunctionType; -OMModel pm_om_model; +PMTimer seq_ode_timer; -void PM_Model_init(const char* model_name, DATA* data, threadData_t* threadData, FunctionType* ode_system) { - pm_om_model.initialize(model_name, data, threadData, ode_system); -} +void* PM_Model_create(const char* model_name, DATA* data, threadData_t* threadData, size_t in_max_num_threads) { -void PM_functionInitialEquations(int size, DATA* data, threadData_t* threadData, FunctionType* functionInitialEquations_systems) { + size_t max_num_threads = in_max_num_threads ? in_max_num_threads : tbb::this_task_arena::max_concurrency(); - // pm_om_model.ini_system_funcs = functionInitialEquations_systems; - // pm_om_model.INI_scheduler.execute(); - pm_om_model.INI_scheduler.execution_timer.start_timer(); - for(int i = 0; i < size; ++i) - functionInitialEquations_systems[i](data, threadData); - pm_om_model.INI_scheduler.execution_timer.stop_timer(); + OMModel* pm_om_model = new OMModel(model_name, max_num_threads); + pm_om_model->data = data; + pm_om_model->threadData = threadData; + return pm_om_model; } +void PM_Model_load_ODE_system(void* v_model, FunctionType* ode_system_funcs) { -void PM_functionDAE(int size, DATA* data, threadData_t* threadData, FunctionType* functionDAE_systems) { - - // pm_om_model.dae_system_funcs = functionDAE_systems; - // pm_om_model.DAE_scheduler.execute(); - - pm_om_model.DAE_scheduler.execution_timer.start_timer(); - for(int i = 0; i < size; ++i) - functionDAE_systems[i](data, threadData); - pm_om_model.DAE_scheduler.execution_timer.stop_timer(); - + OMModel& model = *(static_cast(v_model)); + model.ode_system_funcs = ode_system_funcs; + model.load_ODE_system(); } +void PM_evaluate_ODE_system(void* v_model) { -void PM_functionODE(int size, DATA* data, threadData_t* threadData, FunctionType* functionODE_systems) { + OMModel& model = *(static_cast(v_model)); + model.ODE_scheduler.execute(); - pm_om_model.ODE_scheduler.execute(); - - // pm_om_model.ODE_scheduler.execution_timer.start_timer(); + // pm_om_model.ODE_scheduler.execution_timer.start_timer(); // for(int i = 0; i < size; ++i) - // functionODE_systems[i](data, threadData); - // pm_om_model.ODE_scheduler.execution_timer.stop_timer(); - - - // double step_cost = pm_om_model.ODE_scheduler.execution_timer.get_elapsed_time(); - // std::cout << step_cost << std::endl; - // pm_om_model.ODE_scheduler.execution_timer.reset_timer(); + // functionODE_systems[i](data, threadData); + // pm_om_model.ODE_scheduler.execution_timer.stop_timer(); } -void PM_functionAlg(int size, DATA* data, threadData_t* threadData, FunctionType* functionAlg_systems) { - - pm_om_model.total_alg_time.start_timer(); - - for(int i = 0; i < size; ++i) - functionAlg_systems[i](data, threadData); - - pm_om_model.total_alg_time.stop_timer(); +void seq_ode_timer_start() { + seq_ode_timer.start_timer(); +} +void seq_ode_timer_stop() { + seq_ode_timer.stop_timer(); } -void dump_times() { - utility::log("") << "Total INI: " << pm_om_model.INI_scheduler.execution_timer.get_elapsed_time() << std::endl; - utility::log("") << "Total DAE: " << pm_om_model.DAE_scheduler.execution_timer.get_elapsed_time() << std::endl; - utility::log("") << "Total ODE: " << pm_om_model.ODE_scheduler.execution_timer.get_elapsed_time() << std::endl; - utility::log("") << "Total ODE: " << pm_om_model.ODE_scheduler.clustering_timer.get_elapsed_time() << std::endl; - utility::log("") << "Total ALG: " << pm_om_model.total_alg_time.get_elapsed_time() << std::endl; +void seq_ode_timer_reset() { + seq_ode_timer.reset_timer(); } +void seq_ode_timer_get_elapsed_time2() { + std::cerr << seq_ode_timer.get_elapsed_time(); +} +double seq_ode_timer_get_elapsed_time() { + return seq_ode_timer.get_elapsed_time(); +} +void dump_times(void* v_model) { + OMModel& model = *(static_cast(v_model)); + +#ifdef USE_LEVEL_SCHEDULER + utility::log("") << "Using level scheduler" << std::endl; +#else +#ifdef USE_FLOW_SCHEDULER + utility::log("") << "Using flow scheduler" << std::endl; +#else +#error "please specify scheduler. See makefile" +#endif +#endif + utility::log("") << "Nr.of threads " << model.max_num_threads << std::endl; + utility::log("") << "Nr.of ODE evaluations: " << model.ODE_scheduler.total_evaluations << std::endl; + utility::log("") << "Nr.of profiling ODE Evaluations: " << model.ODE_scheduler.sequential_evaluations << std::endl; + // utility::log("") << "Total ODE evaluation time : " << model.ODE_scheduler.total_parallel_cost << std::endl; + utility::log("") << "Total ODE evaluation time : " << model.ODE_scheduler.execution_timer.get_elapsed_time() + << std::endl; + utility::log("") << "Avg. ODE evaluation time : " + << model.ODE_scheduler.execution_timer.get_elapsed_time() / + model.ODE_scheduler.parallel_evaluations + << std::endl; + utility::log("") << "Total ODE loading time: " << model.load_system_timer.get_elapsed_time() << std::endl; + utility::log("") << "Total ODE Clustering time: " << model.ODE_scheduler.clustering_timer.get_elapsed_time() + << std::endl; +} -} // extern "C" \ No newline at end of file +} // extern "C" diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_interface.hpp b/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_interface.hpp index cf80d2a3804..37ebf43c408 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_interface.hpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_interface.hpp @@ -39,7 +39,7 @@ Mahder.Gebremedhin@liu.se 2014-02-19 */ -#include +#include "simulation_data.h" #ifdef __cplusplus @@ -48,17 +48,31 @@ extern "C" { typedef void (*FunctionType)(DATA *, threadData_t*); -void PM_Model_init(const char* , DATA* , threadData_t*, FunctionType*); +void* PM_Model_create(const char* name, DATA* simdata, threadData_t* threadData, size_t num_threads); -void PM_functionInitialEquations(int size, DATA* data, threadData_t* threadData, FunctionType*); +void PM_Model_load_ODE_system(void*, FunctionType*); -void PM_functionDAE(int size, DATA* data, threadData_t* threadData, FunctionType*); +// void PM_functionInitialEquations(int size, DATA* data, threadData_t* threadData, FunctionType*); -void PM_functionODE(int size, DATA* data, threadData_t* threadData, FunctionType*); +// void PM_functionDAE(int size, DATA* data, threadData_t* threadData, FunctionType*); -void PM_functionAlg(int size, DATA* data, threadData_t* threadData, FunctionType*); +void PM_evaluate_ODE_system(void*); -void dump_times(); +// void PM_functionAlg(int size, DATA* data, threadData_t* threadData, FunctionType*); + + +void seq_ode_timer_start(); + +void seq_ode_timer_stop(); + +void seq_ode_timer_reset(); + +void seq_ode_timer_get_elapsed_time2(); + +double seq_ode_timer_get_elapsed_time(); + + +void dump_times(void*); diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_model.cpp b/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_model.cpp index 01000879236..4986fc4b375 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_model.cpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_model.cpp @@ -29,25 +29,20 @@ * */ - /* - Mahder.Gebremedhin@liu.se 2014-02-10 + Mahder.Gebremedhin@liu.se 2020-10-12 */ - - #include "om_pm_model.hpp" #include -#include +// #include +#include "json.hpp" -namespace openmodelica { -namespace parmodelica { +namespace openmodelica { namespace parmodelica { -Equation::Equation() : - TaskNode() -{ +Equation::Equation() : TaskNode() { index = -1; function_system = NULL; data = NULL; @@ -61,233 +56,250 @@ bool Equation::depends_on(const TaskNode& other_b) const { bool found_dep = false; // True dependency - found_dep = utility::has_intersection(this->rhs.begin(),this->rhs.end(), - other.lhs.begin(), other.lhs.end()); + found_dep = utility::has_intersection(this->rhs.begin(), this->rhs.end(), other.lhs.begin(), other.lhs.end()); // Anti-dependency - if(!found_dep) - found_dep = utility::has_intersection(this->lhs.begin(),this->lhs.end(), - other.rhs.begin(), other.rhs.end()); + if (!found_dep) { + found_dep = utility::has_intersection(this->lhs.begin(), this->lhs.end(), other.rhs.begin(), other.rhs.end()); + if (found_dep) + std::cout << "found anti-dep" << this->index << " and " << other.index << std::endl; + } // output-dependency - if(!found_dep) - found_dep = utility::has_intersection(this->lhs.begin(),this->lhs.end(), - other.lhs.begin(), other.lhs.end()); + if (!found_dep) { + found_dep = utility::has_intersection(this->lhs.begin(), this->lhs.end(), other.lhs.begin(), other.lhs.end()); + if (found_dep) + std::cout << "found output-dep" << this->index << " and " << other.index << std::endl; + } return found_dep; } - void Equation::execute() { function_system[task_id](data, threadData); } - -OMModel::OMModel() : - INI_scheduler(INI_system), - DAE_scheduler(DAE_system), - ODE_scheduler(ODE_system) -{ +OMModel::OMModel(const std::string& in_name, size_t mnt) + : name(in_name) + , max_num_threads(mnt) + , tbb_system(mnt) + , INI_system(name, mnt) + , INI_scheduler(INI_system, mnt) + , DAE_system(name, mnt) + , DAE_scheduler(DAE_system, mnt) + , ODE_system(name, mnt) + , ODE_scheduler(ODE_system, mnt) + , ALG_system(name, mnt) + , ALG_scheduler(ALG_system, mnt) { intialized = false; } +void OMModel::load_ODE_system() { - -void OMModel::initialize(const char* model_name_, DATA* data_, threadData_t* threadData_, FunctionType* ode_system_) { - - if(intialized) + if (intialized) return; - model_name = model_name_; - data = data_; - threadData = threadData_; - ode_system_funcs = ode_system_; - - load_from_xml(ODE_system, "ode-equations", ode_system_funcs); + load_system_timer.start_timer(); + load_from_json(ODE_system, "ode-equations", ode_system_funcs); + load_system_timer.stop_timer(); // ODE_system.construct_graph(); // ODE_scheduler.set_up_executor(ode_system_funcs, data); // ODE_scheduler.schedule(4); - intialized = true; +} +inline void check_tag(int index, const std::string& tag) { + if (tag == "dummy" or tag == "assign" or tag == "residual" or tag == "tornsystem" or tag == "system" or + tag == "algorithm") + return; + else { + utility::eq_index_fatal(index, "with unknown tag : " + tag); + } } +inline void check_container_dispaly(int index, const std::string& disp) { + if (disp == "linear" or disp == "non-linear") + return; + else { + utility::eq_index_fatal(index, "container with unknown disp : " + disp); + } +} -void load_equation(Equation& current_node, pugi::xml_node& xml_equ) { +void load_simple_assign(Equation& current_node, const nlohmann::json& json_eq) { - pugi::xml_node eq_type = xml_equ.first_child(); - current_node.type = eq_type.name(); +#ifndef NDEBUG + if (json_eq["defines"].size() != 1) { + utility::eq_index_fatal(current_node.index, "Assign with more than one define!"); + } +#endif - if( std::strcmp(eq_type.name(),"assign") == 0) { + current_node.lhs.insert(json_eq["defines"].front().get()); - pugi::xml_node current = eq_type.first_child(); + for (auto use : json_eq["uses"]) { + current_node.rhs.insert(use.get()); + } +} - while(std::strcmp(current.name(),"defines") == 0) { - current_node.lhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } +void load_algorithm(Equation& current_node, const nlohmann::json& json_eq) { + if (json_eq["defines"].size() != 1) { + utility::eq_index_error(current_node.index, "Algorithm with more than one define!"); + } - while(std::strcmp(current.name(),"depends") == 0) { - current_node.rhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } + current_node.lhs.insert(json_eq["defines"].front().get()); - current_node.cost = 1; + for (auto use : json_eq["uses"]) { + current_node.rhs.insert(use.get()); } - else if( std::strcmp(eq_type.name(),"statement") == 0) { +} - pugi::xml_node current = eq_type.first_child(); +void load_simple_assign_check_local_define(Equation& current_node, const nlohmann::json& int_eq) { - while(std::strcmp(current.name(),"defines") == 0) { - current_node.lhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } +#ifndef NDEBUG + if (int_eq["defines"].size() != 1) { + utility::eq_index_error(current_node.index, "Assign with more than one define!"); + } +#endif + current_node.lhs.insert(int_eq["defines"].front().get()); - while(std::strcmp(current.name(),"depends") == 0) { - current_node.rhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } + for (auto& use : int_eq["uses"]) { + auto var_s = use.get(); + utility::indexed_dlog(current_node.index, "Checking if " + var_s + " is defined localy"); + auto local_defined = current_node.lhs.find(var_s) != current_node.lhs.end(); - current_node.cost = 1; + // Disable me and see if graphs look different. + if (!local_defined) { + current_node.rhs.insert(use.get()); + utility::indexed_dlog(current_node.index, ": added uses: " + use.get() + " : due to " + + std::to_string(int_eq["eqIndex"].get())); + } + else { + utility::indexed_dlog(current_node.index, + ": skiped uses: " + use.get() + " : due to local define"); + } } - else if( std::strcmp(eq_type.name(),"when") == 0) { - - pugi::xml_node current = eq_type.first_child(); - current_node.rhs.insert(current.child_value()); - current = current.next_sibling(); +} - while(std::strcmp(current.name(),"defines") == 0) { - current_node.lhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } +void load_simple_residual(Equation& current_node, const nlohmann::json& json_eq) { + for (auto use : json_eq["uses"]) { + current_node.rhs.insert(use.get()); + } +} +void load_linear_system(Equation& current_node, const nlohmann::json& json_eq) { - while(std::strcmp(current.name(),"depends") == 0) { - current_node.rhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } - - current_node.cost = 2; + for (auto& def : json_eq["defines"]) { + current_node.lhs.insert(def.get()); + utility::indexed_dlog(current_node.index, ": added own defines: " + def.get()); } - else if( std::strcmp(eq_type.name(),"linear") == 0) { + for (auto& int_eq : json_eq["internal-equations"]) { - pugi::xml_node current = eq_type.first_child(); + int i_index = int_eq["eqIndex"]; + const std::string& i_tag = int_eq["tag"]; - int ls_size = 0; - while(std::strcmp(current.name(),"defines") == 0) { - current_node.lhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - ++ls_size; + if (i_tag == "assign") { + load_simple_assign_check_local_define(current_node, int_eq); } - while(std::strcmp(current.name(),"depends") == 0) { - current_node.rhs.insert(current.attribute("name").value()); - current = current.next_sibling(); + else if (i_tag == "torn") { + load_simple_assign_check_local_define(current_node, int_eq); } - current_node.cost = ls_size; - utility::warning() << current_node.index << ": Linear equations not fully handled yet: " << ls_size << newl; - } - - else if( std::strcmp(eq_type.name(),"nonlinear") == 0) { - - pugi::xml_node current = eq_type.first_child(); - - int nls_size = 0; - while(std::strcmp(current.name(),"defines") == 0) { - current_node.lhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - ++nls_size; + else if (i_tag == "residual") { + load_simple_residual(current_node, int_eq); } - while(std::strcmp(current.name(),"depends") == 0) { - current_node.rhs.insert(current.attribute("name").value()); - current = current.next_sibling(); + else { + utility::eq_index_fatal(i_index, "Internal Equation type not yet handled: " + i_tag); } - - current_node.cost = nls_size; - utility::warning() << current_node.index << ": Non linear equations not fully handled yet: " << nls_size << newl; } - else if( std::strcmp(eq_type.name(),"mixed") == 0) { - - int mix_size = eq_type.attribute("size").as_int(); + utility::indexed_dlog(current_node.index, "Total number of defines: " + std::to_string(current_node.lhs.size())); + utility::indexed_dlog(current_node.index, "Total number of uses: " + std::to_string(current_node.rhs.size())); +} - pugi::xml_node current = eq_type.first_child(); +void load_system_of_equations(Equation& current_node, const nlohmann::json& json_eq) { + const std::string& display = json_eq["display"]; + const std::string& tag = json_eq["tag"]; - while(std::strcmp(current.name(),"defines") == 0) { - current_node.lhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } + if (display == "linear") { + load_linear_system(current_node, json_eq); + } + else if (display == "non-linear") { + load_linear_system(current_node, json_eq); + } + else { + utility::eq_index_fatal(current_node.index, + "System (" + tag + ") Equation display not yet handled: " + display); + } +} - current_node.cost = mix_size; +void load_equation(Equation& current_node, const nlohmann::json& json_eq) { + const std::string& tag = json_eq["tag"]; - for(int count = 0; count < mix_size; ++count) { - xml_equ = xml_equ.next_sibling(); - Equation mix_eq_node; - load_node(mix_eq_node, xml_equ); - current_node.lhs.insert(mix_eq_node.lhs.begin(), mix_eq_node.lhs.end()); - current_node.rhs.insert(mix_eq_node.rhs.begin(), mix_eq_node.rhs.end()); - } + if (tag == "assign") { + load_simple_assign(current_node, json_eq); + return; + } - utility::warning() << current_node.index << ": Mixed equations not fully handled yet: " << mix_size << newl; + else if (tag == "residual") { + load_simple_residual(current_node, json_eq); + return; } - else { - current_node.cost = 1; - utility::error() << current_node.index << ": Unknown Equation type." << eq_type.name() << newl; + else if (tag == "algorithm") { + load_algorithm(current_node, json_eq); + return; } + else if (tag == "tornsystem" || tag == "system") { + load_system_of_equations(current_node, json_eq); + return; + } + else { + utility::eq_index_fatal(current_node.index, "Equation type not yet handled: " + tag); + } } -void OMModel::load_from_xml(TaskSystemT& task_system, const std::string& eq_to_read, FunctionType* function_system) { - - std::string xml_file = model_name + "_tasks.xml"; - utility::log("") << "Loading " << xml_file << std::endl; - - pugi::xml_document doc; - if(!doc.load_file(xml_file.c_str())) { - std::cerr << "Error loading XML file '" << xml_file << "'." << std::endl; - exit(1); - } +void OMModel::load_from_json(TaskSystemT& task_system, const std::string& eq_to_read, FunctionType* function_system) { + std::string json_file = this->name + "_ode.json"; + // utility::log("") << "Loading " << json_file << std::endl; + std::ifstream f_s(json_file); + nlohmann::json jmodel_info; - pugi::xml_node xml_equs = doc.child("tasksystemdump").child(eq_to_read.c_str()); + jmodel_info << f_s; long node_count = 0; + for (auto& eq : jmodel_info[eq_to_read]) { + int index = eq["eqIndex"]; + // skip the 'dummy' node in OpenModelica generated JSON file. + if (index == 0) { + continue; + } - for (pugi::xml_node xml_equ = xml_equs.first_child(); xml_equ; ) - { + if (eq["section"] != "regular") { + utility::eq_index_fatal(index, "Unkown section!" + eq["section"].get()); + } Equation current_node; - pugi::xml_attribute index = xml_equ.first_attribute(); - current_node.index = index.as_int(); - + current_node.index = index; // Copy the pointers to the needed info from the Model // to each equation node. current_node.data = this->data; current_node.threadData = this->threadData; current_node.function_system = function_system; + load_equation(current_node, eq); - load_equation(current_node, xml_equ); ++node_count; - task_system.add_node(current_node); - - xml_equ = xml_equ.next_sibling(); } - - utility::log() << "Number of tasks = " << node_count << newl; - - + std::cout << "Number of tasks = " << node_count << std::endl; } - -} // openmodelica -} // parmodelica +}} // namespace openmodelica::parmodelica diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_model.hpp b/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_model.hpp index 836b8420ea5..3e651c8868c 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_model.hpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/om_pm_model.hpp @@ -35,18 +35,15 @@ /* - Mahder.Gebremedhin@liu.se 2014-02-10 + Mahder.Gebremedhin@liu.se 2020-10-12 */ +#include #include -#include "pm_task_system.hpp" #include "pm_cluster_level_scheduler.hpp" #include "pm_cluster_dynamic_scheduler.hpp" -#include "pm_level_scheduler.hpp" -#include "pm_dynamic_scheduler.hpp" - #include "pm_timer.hpp" #include "om_pm_equation.hpp" @@ -92,22 +89,34 @@ class OMModel // typedef LevelSchedulerThreadOblivious SchedulerT; // typedef DynamicScheduler SchedulerT; // typedef TaskSystem TaskSystemT; - +#ifdef USE_LEVEL_SCHEDULER typedef StepLevels SchedulerT; - // typedef ClusterDynamicScheduler SchedulerT; +#else + #ifdef USE_FLOW_SCHEDULER + typedef ClusterDynamicScheduler SchedulerT; + #else + #error "please specify scheduler. See makefile" + #endif +#endif typedef TaskSystem_v2 TaskSystemT; -private: - std::string model_name; +public: + std::string name; + size_t max_num_threads; + tbb::task_scheduler_init tbb_system; + bool intialized; DATA* data; threadData_t* threadData; + public: - OMModel(); - void initialize(const char* , DATA* , threadData_t* , FunctionType*); + OMModel(const std::string& name, size_t max_num_threads); + void load_ODE_system(); + + PMTimer load_system_timer; FunctionType* ini_system_funcs; TaskSystemT INI_system; @@ -121,10 +130,12 @@ class OMModel TaskSystemT ODE_system; SchedulerT ODE_scheduler; - PMTimer total_alg_time; + FunctionType alg_system_funcs; TaskSystemT ALG_system; + SchedulerT ALG_scheduler; void load_from_xml(TaskSystemT&, const std::string&, FunctionType*); + void load_from_json(TaskSystemT&, const std::string&, FunctionType*); }; diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_cluster_dynamic_scheduler.hpp b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_cluster_dynamic_scheduler.hpp index ff2866af16a..ba314ecfe5e 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_cluster_dynamic_scheduler.hpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_cluster_dynamic_scheduler.hpp @@ -1,180 +1,172 @@ -#pragma once -#ifndef id776A2949_F8C6_41C1_8E5205C1984621C1 -#define id776A2949_F8C6_41C1_8E5205C1984621C1 - -/* - * This file is part of OpenModelica. - * - * Copyright (c) 1998-CurrentYear, Linköping University, - * Department of Computer and Information Science, - * SE-58183 Linköping, Sweden. - * - * All rights reserved. - * - * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 - * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). - * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S - * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. - * - * The OpenModelica software and the Open Source Modelica - * Consortium (OSMC) Public License (OSMC-PL) are obtained - * from Linköping University, either from the above address, - * from the URLs: http://www.ida.liu.se/projects/OpenModelica or - * http://www.openmodelica.org, and in the OpenModelica distribution. - * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. - * - * This program is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH - * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS - * OF OSMC-PL. - * - * See the full OSMC Public License conditions for more details. - * - */ - - -/* - Mahder.Gebremedhin@liu.se 2014-03-06 -*/ - -#include -#include - -#include "pm_clustering.hpp" - - -namespace openmodelica { -namespace parmodelica { - -template -struct ClusterLauncher { - typedef TaskSystem_v2 TaskSystemType; - typedef typename TaskSystemType::ClusterType ClusterType; -private: - ClusterType& clust; - -public: - ClusterLauncher(ClusterType& c) - : clust(c) - {} - - void operator()( tbb::flow::continue_msg ) const { - clust.execute(); - } -}; - -template -class ClusterDynamicScheduler { -public: - typedef TaskSystem_v2 TaskSystemType; - - typedef typename TaskSystemType::GraphType GraphType; - typedef typename TaskSystemType::ClusterType ClusterType; - typedef typename TaskSystemType::ClusterIdType ClusterIdType; - - typedef typename TaskType::FunctionType FunctionType; - -private: - tbb::task_scheduler_init tbb_system; - - tbb::flow::graph dynamic_graph; - tbb::flow::broadcast_node flow_root; - - bool flow_graph_created; - - - std::map* > cluster_flow_id_map; - -public: - PMTimer execution_timer; - PMTimer clustering_timer; - TaskSystemType& task_system; - - ClusterDynamicScheduler(TaskSystemType& task_system) - : tbb_system() - , flow_root(dynamic_graph) - , flow_graph_created(false) - , task_system(task_system) - { - } - - void schedule() { - clustering_timer.start_timer(); - cluster_merge_common::apply(task_system); - cluster_merge_common::dump_graph(task_system); - construct_flow_graph(); - clustering_timer.stop_timer(); - } - - void construct_flow_graph() - { - - using namespace tbb; - GraphType& sys_graph = task_system.sys_graph; - ClusterIdType& root_node_id = task_system.root_node_id; - - typename GraphType::vertex_iterator vert_iter, vert_end; - boost::tie(vert_iter, vert_end) = vertices(sys_graph); - - /*! skip the root node. */ - ++vert_iter; - for ( ; vert_iter != vert_end; ++vert_iter) { - ClusterIdType& curr_clust_id = *vert_iter; - ClusterType& curr_clust = sys_graph[curr_clust_id]; - // std::cout << "adding " << curr_b_node.index << std::endl; - - /*! create new flow node for tbb. */ - flow::continue_node* curr_f_node = - new flow::continue_node(dynamic_graph, - ClusterLauncher(curr_clust)); - - /*! create a maping. we use it to add edges from this node to its children later. */ - cluster_flow_id_map.insert(std::make_pair(curr_clust_id,curr_f_node)); - - /*! Iterate through all parents of the current node and add edges.*/ - typename GraphType::inv_adjacency_iterator par_iter, par_end; - boost::tie(par_iter, par_end) = inv_adjacent_vertices( curr_clust_id, sys_graph ); - for(; par_iter != par_end; ++par_iter) { - const ClusterIdType& curr_parent_id = *par_iter; - // ClusterType& curr_parent = sys_graph[curr_parent_id]; - /*! the parent is the root in the task_graph. So here connect it to - the root of the flow graph*/ - if(curr_parent_id == root_node_id) { - flow::make_edge(flow_root, *curr_f_node); - // std::cout << " edge to root " << std::endl; - } - else { - flow::make_edge(*(cluster_flow_id_map.at(curr_parent_id)), *curr_f_node); - // std::cout << " edge to " << sys_graph[*par_iter].index << std::endl; - } - } - } - - flow_graph_created = true; - } - - - void execute() { - - if(!flow_graph_created) { - construct_flow_graph(); - } - - execution_timer.start_timer(); - flow_root.try_put( tbb::flow::continue_msg() ); - dynamic_graph.wait_for_all(); - execution_timer.stop_timer(); - } - -}; - - - -} // parmodelica -} // openmodelica - - - - -#endif // header +#pragma once +#ifndef id776A2949_F8C6_41C1_8E5205C1984621C1 +#define id776A2949_F8C6_41C1_8E5205C1984621C1 + +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Linköping University, + * Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 + * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S + * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from Linköping University, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS + * OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ + +/* + Mahder.Gebremedhin@liu.se 2014-03-06 +*/ + +#include +#include "pm_clustering.hpp" + +namespace openmodelica { namespace parmodelica { + +template +struct ClusterLauncher { + typedef TaskSystem_v2 TaskSystemType; + typedef typename TaskSystemType::ClusterType ClusterType; + + private: + ClusterType& clust; + + public: + ClusterLauncher(ClusterType& c) : clust(c) {} + + void operator()(tbb::flow::continue_msg) const { clust.execute(); } +}; + +template +class ClusterDynamicScheduler { + public: + typedef TaskSystem_v2 TaskSystemType; + + typedef typename TaskSystemType::GraphType GraphType; + typedef typename TaskSystemType::ClusterType ClusterType; + typedef typename TaskSystemType::ClusterIdType ClusterIdType; + + typedef typename TaskType::FunctionType FunctionType; + + private: + + size_t max_num_threads; + + tbb::flow::graph dynamic_graph; + tbb::flow::broadcast_node flow_root; + + bool flow_graph_created; + + std::map*> cluster_flow_id_map; + + public: + PMTimer execution_timer; + PMTimer clustering_timer; + TaskSystemType& task_system; + + int sequential_evaluations; + int total_evaluations; + int parallel_evaluations; + + ClusterDynamicScheduler(TaskSystemType& task_system, size_t mnt) + : max_num_threads(mnt) + , flow_root(dynamic_graph) + , flow_graph_created(false) + , task_system(task_system) { + sequential_evaluations = 0; + parallel_evaluations = 0; + total_evaluations = 0; + } + + void schedule() { + // task_system.dump_graphml("original"); + clustering_timer.start_timer(); + // cluster_merge_common::apply(task_system); + // cluster_merge_common::dump_graph(task_system); + construct_flow_graph(); + clustering_timer.stop_timer(); + } + + void construct_flow_graph() { + + using namespace tbb; + GraphType& sys_graph = task_system.sys_graph; + ClusterIdType& root_node_id = task_system.root_node_id; + + typename GraphType::vertex_iterator vert_iter, vert_end; + boost::tie(vert_iter, vert_end) = vertices(sys_graph); + + /*! skip the root node. */ + ++vert_iter; + for (; vert_iter != vert_end; ++vert_iter) { + ClusterIdType& curr_clust_id = *vert_iter; + ClusterType& curr_clust = sys_graph[curr_clust_id]; + // std::cout << "adding " << curr_b_node.index << std::endl; + + /*! create new flow node for tbb. */ + flow::continue_node* curr_f_node = + new flow::continue_node(dynamic_graph, ClusterLauncher(curr_clust)); + + /*! create a maping. we use it to add edges from this node to its children later. */ + cluster_flow_id_map.insert(std::make_pair(curr_clust_id, curr_f_node)); + + /*! Iterate through all parents of the current node and add edges.*/ + typename GraphType::inv_adjacency_iterator par_iter, par_end; + boost::tie(par_iter, par_end) = inv_adjacent_vertices(curr_clust_id, sys_graph); + for (; par_iter != par_end; ++par_iter) { + const ClusterIdType& curr_parent_id = *par_iter; + // ClusterType& curr_parent = sys_graph[curr_parent_id]; + /*! the parent is the root in the task_graph. So here connect it to + the root of the flow graph*/ + if (curr_parent_id == root_node_id) { + flow::make_edge(flow_root, *curr_f_node); + // std::cout << " edge to root " << std::endl; + } + else { + flow::make_edge(*(cluster_flow_id_map.at(curr_parent_id)), *curr_f_node); + // std::cout << " edge to " << sys_graph[*par_iter].index << std::endl; + } + } + } + + flow_graph_created = true; + } + + void execute() { + + if (!flow_graph_created) { + schedule(); + } + + execution_timer.start_timer(); + flow_root.try_put(tbb::flow::continue_msg()); + dynamic_graph.wait_for_all(); + execution_timer.stop_timer(); + + total_evaluations++; + parallel_evaluations++; + } +}; + +}} // namespace openmodelica::parmodelica + +#endif // header diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_cluster_level_scheduler.hpp b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_cluster_level_scheduler.hpp index cb1523dbec8..860007afa14 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_cluster_level_scheduler.hpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_cluster_level_scheduler.hpp @@ -33,261 +33,339 @@ * */ - /* Mahder.Gebremedhin@liu.se 2014-03-13 */ -#include -#include +#include "gc.h" -#include "pm_clustering.hpp" +#include +#include +// #include +// #include -namespace openmodelica { -namespace parmodelica { +#include "pm_clustering.hpp" +namespace openmodelica { namespace parmodelica { -template +template struct TBBConcurrentStepExecutor { typedef TaskSystem_v2 TaskSystemType; - typedef typename TaskSystemType::GraphType GraphType; - typedef typename TaskSystemType::ClusterType ClusterType; + typedef typename TaskSystemType::GraphType GraphType; + typedef typename TaskSystemType::ClusterType ClusterType; typedef typename TaskSystemType::ClusterIdType ClusterIdType; - typedef typename TaskSystemType::ClusterLevels ClusterLevels; - typedef typename ClusterLevels::value_type SameLevelClusterIdsType; + typedef typename TaskSystemType::ClusterLevels ClusterLevels; + typedef typename ClusterLevels::value_type SameLevelClusterIdsType; typedef typename SameLevelClusterIdsType::iterator ClusteIdIter; -private: - GraphType& sys_graph; + private: + GraphType& sys_graph; -public: + public: TBBConcurrentStepExecutor(GraphType& g) : sys_graph(g) {} - void operator()( tbb::blocked_range& range ) const { - - for(ClusteIdIter clustid_iter = range.begin(); clustid_iter != range.end(); ++clustid_iter) { + void operator()(tbb::blocked_range& range) const { + + // pid_t id; + // /* Register thread to bohem GC if it is not registered already*/ + // if(!GC_thread_is_registered()) { + // id = syscall(SYS_gettid); + // fprintf(stderr,"Found unregisterd thread = %d \n", id); + + // struct GC_stack_base sb; + // memset (&sb, 0, sizeof(sb)); + // GC_get_stack_base(&sb); + // GC_register_my_thread (&sb); + // // std::cerr << "New Theread registerd = " << GC_thread_is_registered() << std::endl; + // } + // else { + // id = syscall(SYS_gettid); + // if(!knownthreads.count(id)) { + // fprintf(stderr,"parmod registerd thread = %d \n", id); + // knownthreads.insert(id); + // } + // } + + for (ClusteIdIter clustid_iter = range.begin(); clustid_iter != range.end(); ++clustid_iter) { ClusterIdType& curr_clust_id = *clustid_iter; - ClusterType& curr_clust = sys_graph[curr_clust_id]; + ClusterType& curr_clust = sys_graph[curr_clust_id]; curr_clust.execute(); } } - }; - - -template -class StepLevels : - boost::noncopyable { -public: - - typedef TaskSystem_v2 TaskSystemType; - typedef typename TaskSystemType::GraphType GraphType; - typedef typename TaskSystemType::ClusterType ClusterType; +template +class StepLevels : boost::noncopyable { + public: + typedef TaskSystem_v2 TaskSystemType; + typedef typename TaskSystemType::GraphType GraphType; + typedef typename TaskSystemType::ClusterType ClusterType; typedef typename TaskSystemType::ClusterIdType ClusterIdType; typedef typename TaskSystemType::ClusterLevels ClusterLevels; - typedef typename ClusterLevels::value_type SameLevelClusterIdsType; + typedef typename ClusterLevels::value_type SameLevelClusterIdsType; + + public: + size_t max_num_threads; + + const TaskSystemType& task_system_org; + TaskSystemType task_system; + TBBConcurrentStepExecutor step_executor; -private: - TaskSystemType& task_system; bool profiled; - bool schedule_valid; + bool schedule_available; - tbb::task_scheduler_init tbb_system; - TBBConcurrentStepExecutor step_executor; + int total_evaluations; + int parallel_evaluations; + int sequential_evaluations; + + double par_avg_at_last_sch; + double par_current_avg; + double total_parallel_cost; + bool has_run_parallel; -public: + public: PMTimer execution_timer; - PMTimer clustering_timer; - // PMTimer extra_timer; - - StepLevels(TaskSystemType& ts) : - task_system(ts) - , tbb_system(4) - , step_executor(task_system.sys_graph) - { + PMTimer clustering_timer; + PMTimer step_timer; + + std::vector parallel_eval_costs; + + StepLevels(TaskSystemType& ts, size_t mnt) + : max_num_threads(mnt) + , task_system_org(ts) + , task_system("invalid", mnt) // implement a constrctor with no parameters and remove this + , step_executor(task_system.sys_graph) { + // GC_allow_register_threads(); + // GC_use_threads_discovery(); + profiled = false; - schedule_valid = false; + schedule_available = false; + + total_evaluations = 0; + parallel_evaluations = 0; + sequential_evaluations = 0; + + total_parallel_cost = 0; + par_avg_at_last_sch = 0; + has_run_parallel = false; } - void estimate_speedup() { + bool avg_needs_reschedule() { - if(task_system.levels_valid == false) - task_system.update_node_levels(); + double diff = std::abs(par_avg_at_last_sch - par_current_avg); + double change = diff / par_avg_at_last_sch; - GraphType& sys_graph = task_system.sys_graph; + if (change > 0.5) { + // std::cout << "Reschedule needed P: " << par_avg_at_last_sch << " :C: " << par_current_avg << std::endl; + return true; + } - double total_level_scheduler_cost = 0; - double total_system_cost = 0; - typename ClusterLevels::iterator level_iter = task_system.clusters_by_level.begin(); - /*! Skip the first level. Which contains only the root node and some invlaidated clusters.*/ - ++level_iter; - int level_number = 1; - for( ;level_iter != task_system.clusters_by_level.end(); ++level_iter, ++level_number) { - SameLevelClusterIdsType& current_level = *level_iter; + return false; + } - cluster_cost_comparator_by_id cccbi(sys_graph); - std::sort(current_level.begin(), current_level.end(), cccbi); - total_level_scheduler_cost += sys_graph[current_level.front()].cost; + bool reschedule_needed() { + if (!this->schedule_available) + return true; - total_system_cost += current_level.level_cost; - } + if (this->avg_needs_reschedule()) + return true; + + return false; + } + + void clear_schedule() { + task_system = task_system_org; - utility::log("") << "total_system_cost: " << total_system_cost << std::endl; - utility::log("") << "total_level_scheduler_cost: " << total_level_scheduler_cost << std::endl; - utility::log("") << "speedup: " << total_system_cost/total_level_scheduler_cost << std::endl; + profiled = false; + schedule_available = false; + } + void execute_and_schedule() { + clear_schedule(); + profile_execute(); + schedule(); + par_avg_at_last_sch = par_current_avg; } void schedule() { - if(schedule_valid) - return; - clustering_timer.start_timer(); - if(task_system.levels_valid == false) + if (task_system.levels_valid == false) task_system.update_node_levels(); - task_system.dump_graphml("original"); - clustetring1::apply(task_system); - clustetring1::dump_graph(task_system); + clustetring1::dump_graph(task_system); clustetring2::apply(task_system); - clustetring2::dump_graph(task_system); + clustetring2::dump_graph(task_system); clustetring3::apply(task_system); - clustetring3::dump_graph(task_system); + clustetring3::dump_graph(task_system); - clustetring4::apply(task_system); - clustetring4::dump_graph(task_system); + clustetring4::apply(task_system); + clustetring4::dump_graph(task_system); clustetring5::apply(task_system); - clustetring5::dump_graph(task_system); + clustetring5::dump_graph(task_system); - schedule_valid = true; + schedule_available = true; task_system.levels_valid = false; + task_system.update_node_levels(); estimate_speedup(); - clustering_timer.stop_timer(); + clustering_timer.stop_timer(); } + void execute() { - void execute() - { + if (this->reschedule_needed()) + return execute_and_schedule(); - if(!this->profiled) - return profile_execute(); + // paranoia + if (task_system.levels_valid == false) + exit(1); execution_timer.start_timer(); - // extra_timer.start_timer(); - - // GraphType& sys_graph = task_system.sys_graph; - - if(task_system.levels_valid == false) - task_system.update_node_levels(); + step_timer.start_timer(); typename ClusterLevels::iterator level_iter = task_system.clusters_by_level.begin(); /*! Skip the first level. Which contains only the root node */ ++level_iter; int level_number = 1; - for( ;level_iter != task_system.clusters_by_level.end(); ++level_iter, ++level_number) { + for (; level_iter != task_system.clusters_by_level.end(); ++level_iter, ++level_number) { SameLevelClusterIdsType& current_level = *level_iter; // if(current_level.level_cost > 0.009) { - tbb::parallel_for( - tbb::blocked_range( - current_level.begin(), current_level.end()) - , step_executor); + tbb::parallel_for(tbb::blocked_range(current_level.begin(), + current_level.end()), + step_executor); // } // else { - // typename SameLevelClusterIdsType::iterator clustid_iter = current_level.begin(); - // for( ;clustid_iter != current_level.end(); ++clustid_iter) { - // ClusterIdType& curr_clust_id = *clustid_iter; - // ClusterType& curr_clust = sys_graph[curr_clust_id]; + // typename SameLevelClusterIdsType::iterator clustid_iter = current_level.begin(); + // for( ;clustid_iter != current_level.end(); ++clustid_iter) { + // ClusterIdType& curr_clust_id = *clustid_iter; + // ClusterType& curr_clust = sys_graph[curr_clust_id]; - // curr_clust.execute(); + // curr_clust.execute(); - // } + // } // } } execution_timer.stop_timer(); - // extra_timer.stop_timer(); - // double step_cost = extra_timer.get_elapsed_time(); - // std::cout << "E: " << step_cost << std::endl; - // extra_timer.reset_timer(); - + step_timer.stop_timer(); + + ++this->total_evaluations; + ++this->parallel_evaluations; + + // if(total_evaluations%100 == 0) { + double step_cost = step_timer.get_elapsed_time(); + parallel_eval_costs.push_back(step_cost); + total_parallel_cost += step_cost; + par_current_avg = total_parallel_cost / this->parallel_evaluations; + // std::cout << total_evaluations << " : " << parallel_evaluations << " : " << step_cost << " : " << + // par_current_avg << std::endl; std::cout << "P" << " : " << total_evaluations << " : " << step_cost << " : + // "<< par_current_avg << std::endl; + step_timer.reset_timer(); + // } + + if (!has_run_parallel) { + par_avg_at_last_sch = par_current_avg; + has_run_parallel = true; + } } + void profile_execute() { - void profile_execute() - { - execution_timer.start_timer(); - + // if(this->total_evaluations == 0) + // std::cout << "Type" << " : " << "Eval" << " : " << "Eval_cost" << " : "<< "Curr_Par_Avg" << " : " << + // "Prev_Sch_Avg"<< std::endl; GraphType& sys_graph = task_system.sys_graph; typename GraphType::vertex_iterator vert_iter, vert_end; boost::tie(vert_iter, vert_end) = vertices(sys_graph); + + execution_timer.start_timer(); + step_timer.start_timer(); /*! skip the root node. */ ++vert_iter; - for ( ; vert_iter != vert_end; ++vert_iter) { + for (; vert_iter != vert_end; ++vert_iter) { sys_graph[*vert_iter].profile_execute(); } + ++this->total_evaluations; + ++this->sequential_evaluations; + step_timer.stop_timer(); execution_timer.stop_timer(); - // double step_cost = execution_timer.get_elapsed_time(); - // std::cout << "P: " << step_cost << std::endl; - // execution_timer.reset_timer(); - - this->profiled = true; - this->schedule_valid = false; - schedule(); - - } -}; + double step_cost = step_timer.get_elapsed_time(); + // utility::log("") << "Profiled on step :" << this->total_evaluations << " cost: " << step_cost << std::endl; + std::cout << "S" + << " : " << this->total_evaluations << " : " << step_cost << " : " << par_current_avg << " : " + << par_avg_at_last_sch << std::endl; + step_timer.reset_timer(); + // task_system.dump_graphml("profiled_" + std::to_string(this->total_evaluations)); -/*! The default level scheduler uses these two clusterings*/ -//template -//using LevelScheduler = StepLevels; + this->profiled = true; + } -template -struct LevelScheduler : StepLevels {}; + void estimate_speedup() { + if (task_system.levels_valid == false) + task_system.update_node_levels(); + GraphType& sys_graph = task_system.sys_graph; + double total_level_scheduler_cost = 0; + double total_system_cost = 0; + typename ClusterLevels::iterator level_iter = task_system.clusters_by_level.begin(); + /*! Skip the first level. Which contains only the root node and some invlaidated clusters.*/ + ++level_iter; + int level_number = 1; + for (; level_iter != task_system.clusters_by_level.end(); ++level_iter, ++level_number) { + SameLevelClusterIdsType& current_level = *level_iter; -} // openmodelica -} // parmodelica + cluster_cost_comparator_by_id cccbi(sys_graph); + // sort in decreasing order + std::sort(current_level.rbegin(), current_level.rend(), cccbi); + total_level_scheduler_cost += sys_graph[current_level.front()].cost; + total_system_cost += current_level.total_level_cost; + } + // utility::log("") << "Total_system_cost: " << total_system_cost << std::endl; + // utility::log("") << "Total_level_scheduler_cost: " << total_level_scheduler_cost << std::endl; + // utility::log("") << "Ideal speedup: " << total_system_cost/total_level_scheduler_cost << std::endl; + } +}; +/*! The default level scheduler uses these two clusterings*/ +// template +// using LevelScheduler = StepLevels; +template +struct LevelScheduler : StepLevels {}; +}} // namespace openmodelica::parmodelica #endif // header diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_cluster_system.hpp b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_cluster_system.hpp index 9a5e41f01d1..bfa268bf44d 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_cluster_system.hpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_cluster_system.hpp @@ -2,7 +2,6 @@ #ifndef id51EE4BD8_93E1_4245_A0B1E55CDC703CF8 #define id51EE4BD8_93E1_4245_A0B1E55CDC703CF8 - /* * This file is part of OpenModelica. * @@ -34,63 +33,52 @@ * */ - /* Mahder.Gebremedhin@liu.se 2014-03-07 */ - - #include +#include #include +#include + #include #include +#include -#include "pm_utility.hpp" #include "pm_timer.hpp" +#include "pm_utility.hpp" +namespace openmodelica { namespace parmodelica { -namespace openmodelica { -namespace parmodelica { - - -// struct TaskNode { - // TaskNode() : - // level(0) - // , cost(0) - // {}; - - // long task_id; - // int level; - // double cost; - - // virtual bool depends_on(const TaskNode&) const = 0; - // // virtual void execute() const = 0; -// }; - +struct TaskNode { + TaskNode() : level(0), cost(0){}; + long task_id; + int level; + double cost; + virtual bool depends_on(const TaskNode&) const = 0; + virtual void execute() = 0; +}; -template -struct TaskCluster : - public utility::pm_vector -{ - typedef T TaskType; - typedef typename utility::pm_vector::iterator iterator; +template +struct TaskCluster : public utility::pm_vector { + typedef T TaskType; + typedef typename utility::pm_vector::iterator iterator; typedef typename utility::pm_vector::const_iterator const_iterator; -private: + private: // TaskCluster& operator=(const TaskCluster& other); -public: - double cost; - long level; + public: + double cost; + long level; std::string index_list; - int group; + int group; - TaskCluster() - { + TaskCluster() { cost = 0; level = 0; index_list = "$"; @@ -109,15 +97,16 @@ struct TaskCluster : void clear_cluster() { this->clear(); this->cost = 0; + this->index_list = "$"; } bool depends_on(const TaskCluster& other) const { - bool found = false; + bool found = false; const_iterator t_iter, o_iter; - for(t_iter = this->begin(); t_iter != this->end(); ++t_iter) { - for(o_iter = other.begin(); o_iter != other.end(); ++o_iter) { + for (t_iter = this->begin(); t_iter != this->end(); ++t_iter) { + for (o_iter = other.begin(); o_iter != other.end(); ++o_iter) { found = t_iter->depends_on(*o_iter); - if(found) + if (found) return true; } } @@ -125,31 +114,28 @@ struct TaskCluster : return false; } - - void execute() - { + void execute() { iterator t_iter; - for(t_iter = this->begin(); t_iter != this->end(); ++t_iter) { + for (t_iter = this->begin(); t_iter != this->end(); ++t_iter) { t_iter->execute(); } } - void profile_execute() - { + void profile_execute() { this->cost = 0; - double elapsed = 0; + double elapsed = 0; PMTimer task_timer; iterator t_iter; - for(t_iter = this->begin(); t_iter != this->end(); ++t_iter) { + for (t_iter = this->begin(); t_iter != this->end(); ++t_iter) { task_timer.start_timer(); t_iter->execute(); task_timer.stop_timer(); elapsed = task_timer.get_elapsed_time(); // if(elapsed == 0) - // t_iter->cost = 0.0005; + // t_iter->cost = 0.0005; // else - t_iter->cost = elapsed; + t_iter->cost = elapsed; this->cost += t_iter->cost; @@ -157,106 +143,144 @@ struct TaskCluster : } } - - static bool - cost_comparator(const TaskCluster& lhs, - const TaskCluster& rhs) { + static bool cost_comparator(const TaskCluster& lhs, const TaskCluster& rhs) { return lhs.cost < rhs.cost; } - }; - -template -struct cluster_cost_comparator_by_id -{ - typedef T GraphType; +template +struct cluster_cost_comparator_by_id { + typedef T GraphType; typedef typename GraphType::vertex_descriptor ClusterIdType; const GraphType& graph; cluster_cost_comparator_by_id(const GraphType& g) : graph(g) {} - bool operator() (const ClusterIdType& lhs, const ClusterIdType& rhs) { + bool operator()(const ClusterIdType& lhs, const ClusterIdType& rhs) { double lhs_cost = graph[lhs].cost; double rhs_cost = graph[rhs].cost; - if(lhs_cost == rhs_cost) { + if (lhs_cost == rhs_cost) { int lhs_degree = out_degree(lhs, graph); int rhs_degree = out_degree(rhs, graph); // if(lhs_degree == rhs_degree) { // } - return lhs_degree > rhs_degree; + return lhs_degree < rhs_degree; } - return lhs_cost > rhs_cost; + return lhs_cost < rhs_cost; } }; - -template -struct SameLevelClusterIds : - public utility::pm_vector -{ +template +struct SameLevelClusterIds : public utility::pm_vector { typedef T ClusterIdType; - double level_cost; - - SameLevelClusterIds() : - level_cost(0) - {} + double total_level_cost; + SameLevelClusterIds() : total_level_cost(0) {} }; - - template -class TaskSystem_v2 : boost::noncopyable { +class TaskSystem_v2 { -public: - typedef T TaskType; + public: + typedef T TaskType; typedef TaskCluster ClusterType; - typedef typename boost::adjacency_list< - boost::setS, boost::listS, - boost::bidirectionalS, ClusterType - > GraphType; + typedef typename boost::adjacency_list GraphType; - typedef typename GraphType::vertex_descriptor ClusterIdType; - typedef typename GraphType::vertex_iterator vertex_iterator; - typedef typename GraphType::adjacency_iterator adjacency_iterator; + typedef typename GraphType::vertex_descriptor ClusterIdType; + typedef typename GraphType::vertex_iterator vertex_iterator; + typedef typename GraphType::adjacency_iterator adjacency_iterator; typedef typename GraphType::inv_adjacency_iterator inv_adjacency_iterator; - typedef typename GraphType::edge_descriptor EdgeIdType; - typedef typename GraphType::in_edge_iterator in_edge_iterator; - typedef typename GraphType::out_edge_iterator out_edge_iterator; + typedef typename GraphType::edge_descriptor EdgeIdType; + typedef typename GraphType::in_edge_iterator in_edge_iterator; + typedef typename GraphType::out_edge_iterator out_edge_iterator; - typedef std::list > ClusterLevels; + typedef std::vector> ClusterLevels; -private: + private: long node_count; -public: + public: + std::string name; + + size_t max_num_threads; - std::set active_nodes; ClusterLevels clusters_by_level; - bool levels_valid; - double total_cost; - GraphType sys_graph; + bool levels_valid; + double total_cost; + + GraphType sys_graph; ClusterIdType root_node_id; - TaskSystem_v2() - { + TaskSystem_v2(const std::string& in_name, size_t mnt) { + max_num_threads = mnt; + name = in_name; levels_valid = false; node_count = 0; total_cost = 0; + + // add a new cluster for root node. root_node_id = boost::add_vertex(sys_graph); + // add an empty task to the root node. TaskType& root_node = sys_graph[root_node_id].add_task(TaskType()); root_node.task_id = -1; } - TaskType& add_node(const TaskType& task) - { + TaskSystem_v2(const TaskSystem_v2& other) { + this->name = other.name; + this->max_num_threads = other.max_num_threads; + this->node_count = other.node_count; + + this->clusters_by_level = other.clusters_by_level; + + this->levels_valid = other.levels_valid; + this->total_cost = other.total_cost; + + this->sys_graph = other.sys_graph; + // typedef std::map IndexMap; + // IndexMap mapIndex; + // boost::associative_property_map propmapIndex(mapIndex); + + // int i=0; + // BGL_FORALL_VERTICES_T(v, other.sys_graph, GraphType) + // { + // boost::put(propmapIndex, v, i++); + // } + // boost::copy_graph(other.sys_graph,this->sys_graph, boost::vertex_index_map( propmapIndex )); + // for (typename IndexMap::iterator p = mapIndex.begin(); p != mapIndex.end(); ++p) { + // std::cout << p->first << " -> " << p->second << std::endl; + // } + + vertex_iterator vert_iter, vert_end; + boost::tie(vert_iter, vert_end) = vertices(this->sys_graph); + this->root_node_id = *vert_iter; + } + + TaskSystem_v2& operator=(const TaskSystem_v2& other) { + + this->name = other.name; + this->max_num_threads = other.max_num_threads; + this->node_count = other.node_count; + + this->clusters_by_level = other.clusters_by_level; + + this->levels_valid = other.levels_valid; + this->total_cost = other.total_cost; + + this->sys_graph = other.sys_graph; + + vertex_iterator vert_iter, vert_end; + boost::tie(vert_iter, vert_end) = vertices(this->sys_graph); + this->root_node_id = *vert_iter; + + return *this; + } + + TaskType& add_node(const TaskType& task) { ClusterIdType new_clust_id = boost::add_vertex(sys_graph); - active_nodes.insert(new_clust_id); ClusterType& new_clust = sys_graph[new_clust_id]; @@ -264,58 +288,56 @@ class TaskSystem_v2 : boost::noncopyable { new_task.task_id = node_count; ++node_count; - int parent_count = 0; + int parent_count = 0; vertex_iterator vert_iter, vert_end; boost::tie(vert_iter, vert_end) = vertices(sys_graph); /*! skip the root node. */ ++vert_iter; /*! stop just before the new node. */ --vert_end; - for ( ; vert_iter != vert_end; ++vert_iter) { + for (; vert_iter != vert_end; ++vert_iter) { const ClusterIdType& prev_clust_id = *vert_iter; - ClusterType& prev_clust = sys_graph[prev_clust_id]; + ClusterType& prev_clust = sys_graph[prev_clust_id]; bool found_dep = new_clust.depends_on(prev_clust); - if(found_dep) { - boost::add_edge(prev_clust_id,new_clust_id,sys_graph); + if (found_dep) { + boost::add_edge(prev_clust_id, new_clust_id, sys_graph); ++parent_count; } } - if(parent_count == 0) { - boost::add_edge(root_node_id,new_clust_id,sys_graph); + if (parent_count == 0) { + boost::add_edge(root_node_id, new_clust_id, sys_graph); } total_cost += new_task.cost; return new_task; - } -public: - + public: void concat_same_level_clusters(const ClusterIdType& dest_id, const ClusterIdType& src_id) { ClusterType& dest = sys_graph[dest_id]; ClusterType& src = sys_graph[src_id]; typename ClusterType::iterator task_iter; - for(task_iter = src.begin(); task_iter != src.end(); ++task_iter) { + for (task_iter = src.begin(); task_iter != src.end(); ++task_iter) { dest.add_task(*task_iter); } adjacency_iterator src_child_iter, src_child_end, curr_src_child_iter; boost::tie(src_child_iter, src_child_end) = adjacent_vertices(src_id, sys_graph); - while(src_child_iter != src_child_end) { - /*! Increment before erase. Apparently erasing an edge invalidates the vertex iterators in VS. - something is going on inside boost that I don't know yet. Or VS is just being VS as ususal. - (the edge container is in fact a set, but that should matter only if we iterate over ages. - well apparently not :) )*/ - curr_src_child_iter = src_child_iter; - ++src_child_iter; - - boost::add_edge(dest_id, *curr_src_child_iter, sys_graph); + while (src_child_iter != src_child_end) { + /*! Increment before erase. Apparently erasing an edge invalidates the vertex iterators in VS. + something is going on inside boost that I don't know yet. Or VS is just being VS as ususal. + (the edge container is in fact a set, but that should matter only if we iterate over ages. + well apparently not :) )*/ + curr_src_child_iter = src_child_iter; + ++src_child_iter; + + boost::add_edge(dest_id, *curr_src_child_iter, sys_graph); boost::remove_edge(src_id, *curr_src_child_iter, sys_graph); - } + } /*for (; src_child_iter != src_child_end; ++src_child_iter) { boost::add_edge(dest_id, *src_child_iter, sys_graph); @@ -325,28 +347,25 @@ class TaskSystem_v2 : boost::noncopyable { inv_adjacency_iterator src_parent_iter, src_parent_end, curr_src_parent_iter; boost::tie(src_parent_iter, src_parent_end) = inv_adjacent_vertices(src_id, sys_graph); + while (src_parent_iter != src_parent_end) { + /*! Increment before erase. Apparently erasing an edge invalidates the vertex iterators in VS. + something is going on inside boost that I don't know yet. Or VS is just being VS as ususal. + (the edge container is in fact a set, but that should matter only if we iterate over ages. + well apparently not :) )*/ + curr_src_parent_iter = src_parent_iter; + ++src_parent_iter; - while(src_parent_iter != src_parent_end) { - /*! Increment before erase. Apparently erasing an edge invalidates the vertex iterators in VS. - something is going on inside boost that I don't know yet. Or VS is just being VS as ususal. - (the edge container is in fact a set, but that should matter only if we iterate over ages. - well apparently not :) )*/ - curr_src_parent_iter = src_parent_iter; - ++src_parent_iter; - - boost::add_edge(*curr_src_parent_iter, dest_id, sys_graph); + boost::add_edge(*curr_src_parent_iter, dest_id, sys_graph); boost::remove_edge(*curr_src_parent_iter, src_id, sys_graph); - } - + } /*for (; src_parent_iter != src_parent_end; ++src_parent_iter) { boost::add_edge(*src_parent_iter, dest_id, sys_graph); boost::remove_edge(*src_parent_iter, src_id, sys_graph); }*/ - // boost::clear_vertex(src_id, sys_graph); - boost::remove_vertex(src_id, sys_graph); - + // boost::clear_vertex(src_id, sys_graph); + boost::remove_vertex(src_id, sys_graph); } void concat_with_parent(const ClusterIdType& parent_id, const ClusterIdType& child_id) { @@ -354,60 +373,52 @@ class TaskSystem_v2 : boost::noncopyable { ClusterType& child = sys_graph[child_id]; typename ClusterType::iterator task_iter; - for(task_iter = child.begin(); task_iter != child.end(); ++task_iter) { + for (task_iter = child.begin(); task_iter != child.end(); ++task_iter) { parent.add_task(*task_iter); } adjacency_iterator grand_child_iter, grand_child_end, curr_grand_child_iter; boost::tie(grand_child_iter, grand_child_end) = adjacent_vertices(child_id, sys_graph); - while(grand_child_iter != grand_child_end) { + while (grand_child_iter != grand_child_end) { - /*! Increment before erase. Apparently erasing an edge invalidates the vertex iterators in VS. - something is going on inside boost that I don't know yet. Or VS is just being VS as ususal. - (the edge container is in fact a set, but that should matter only if we iterate over ages. - well apparently not :) )*/ - curr_grand_child_iter = grand_child_iter; - ++grand_child_iter; + /*! Increment before erase. Apparently erasing an edge invalidates the vertex iterators in VS. + something is going on inside boost that I don't know yet. Or VS is just being VS as ususal. + (the edge container is in fact a set, but that should matter only if we iterate over ages. + well apparently not :) )*/ + curr_grand_child_iter = grand_child_iter; + ++grand_child_iter; - boost::add_edge(parent_id, *curr_grand_child_iter, sys_graph); + boost::add_edge(parent_id, *curr_grand_child_iter, sys_graph); boost::remove_edge(child_id, *curr_grand_child_iter, sys_graph); - - } - + } boost::remove_edge(parent_id, child_id, sys_graph); - // boost::clear_vertex(child_id, sys_graph); - boost::remove_vertex(child_id, sys_graph); - + // boost::clear_vertex(child_id, sys_graph); + boost::remove_vertex(child_id, sys_graph); } -public: - + public: void print_leveled_nodes() { typedef typename ClusterLevels::value_type SameLevelClusterIdsType; - int level_number = 0; + int level_number = 0; typename ClusterLevels::iterator level_iter = clusters_by_level.begin(); - for( ;level_iter != clusters_by_level.end(); ++level_iter, ++level_number) { + for (; level_iter != clusters_by_level.end(); ++level_iter, ++level_number) { SameLevelClusterIdsType& current_level = *level_iter; - std::cout << "Level " << level_number << " : " << current_level.level_cost << " : "; + std::cout << "Level " << level_number << " : " << current_level.total_level_cost << " : "; typename SameLevelClusterIdsType::iterator clustid_iter = current_level.begin(); - for( ;clustid_iter != current_level.end(); ++clustid_iter) { + for (; clustid_iter != current_level.end(); ++clustid_iter) { std::cout << sys_graph[*clustid_iter].index_list << ", "; } std::cout << std::endl; - } - } - struct level_update_visitor : public boost::default_bfs_visitor - { - template < typename Vertex, typename Graph > - void discover_vertex(Vertex u, const Graph & g) const - { + struct level_update_visitor : public boost::default_bfs_visitor { + template + void discover_vertex(Vertex u, const Graph& g) const { std::cout << g[u].index_list << std::endl; } }; @@ -419,104 +430,108 @@ class TaskSystem_v2 : boost::noncopyable { void update_node_levels() { - typedef typename ClusterLevels::value_type SameLevelClusterIdsType; - - clusters_by_level.clear(); - - long critical_path = 0; + /* compute the level of each node*/ + long critical_path = 0; vertex_iterator vert_iter, vert_end; boost::tie(vert_iter, vert_end) = vertices(sys_graph); /*! skip the root node. */ ++vert_iter; - for ( ; vert_iter != vert_end; ++vert_iter) { + for (; vert_iter != vert_end; ++vert_iter) { const ClusterIdType& curr_clust_id = *vert_iter; - ClusterType& curr_clust = sys_graph[curr_clust_id]; + ClusterType& curr_clust = sys_graph[curr_clust_id]; long max_parent_level = 0; inv_adjacency_iterator parent_iter, parent_end; boost::tie(parent_iter, parent_end) = inv_adjacent_vertices(curr_clust_id, sys_graph); - for ( ; parent_iter != parent_end; ++parent_iter) { + for (; parent_iter != parent_end; ++parent_iter) { const ClusterIdType& curr_parent_id = *parent_iter; - ClusterType& curr_parent = sys_graph[curr_parent_id]; + ClusterType& curr_parent = sys_graph[curr_parent_id]; max_parent_level = std::max(max_parent_level, curr_parent.level); - } curr_clust.level = max_parent_level + 1; critical_path = std::max(curr_clust.level, critical_path); - } - clusters_by_level.resize(critical_path + 1); - - typename ClusterLevels::iterator level_iter; - boost::tie(vert_iter, vert_end) = vertices(sys_graph); - for ( ; vert_iter != vert_end; ++vert_iter) { - const ClusterIdType& curr_clust_id = *vert_iter; - ClusterType& curr_clust = sys_graph[curr_clust_id]; - - - level_iter = clusters_by_level.begin(); - std::advance(level_iter, curr_clust.level); - level_iter->push_back(curr_clust_id); - level_iter->level_cost += curr_clust.cost; - } - - + // Check the levels are correct. Paranoia! boost::tie(vert_iter, vert_end) = vertices(sys_graph); /*! skip the root node. */ ++vert_iter; - for ( ; vert_iter != vert_end; ++vert_iter) - { + for (; vert_iter != vert_end; ++vert_iter) { ClusterIdType& curr_clust_id = *vert_iter; - ClusterType& curr_clust = sys_graph[curr_clust_id]; + ClusterType& curr_clust = sys_graph[curr_clust_id]; long max_parent_level = 0; inv_adjacency_iterator parent_iter, parent_end; boost::tie(parent_iter, parent_end) = inv_adjacent_vertices(curr_clust_id, sys_graph); - for ( ; parent_iter != parent_end; ++parent_iter) - { + for (; parent_iter != parent_end; ++parent_iter) { const ClusterIdType& curr_parent_id = *parent_iter; - ClusterType& curr_parent = sys_graph[curr_parent_id]; + ClusterType& curr_parent = sys_graph[curr_parent_id]; max_parent_level = std::max(max_parent_level, curr_parent.level); } - if(curr_clust.level != max_parent_level+1) - { + if (curr_clust.level != max_parent_level + 1) { std::cerr << curr_clust.level << " vs " << max_parent_level << std::endl; std::cerr << curr_clust.index_list << std::endl; std::cerr << "level check failure " << std::endl; // exit(1); } - } + // create a list of nodes per level + // Collect nodes of the same level in to a vector and add it to the list of levels + clusters_by_level.clear(); + clusters_by_level.resize(critical_path + 1); + typedef typename ClusterLevels::value_type SameLevelClusterIdsType; + typename ClusterLevels::iterator level_iter; + boost::tie(vert_iter, vert_end) = vertices(sys_graph); + for (; vert_iter != vert_end; ++vert_iter) { + const ClusterIdType& curr_clust_id = *vert_iter; + ClusterType& curr_clust = sys_graph[curr_clust_id]; - this->levels_valid = true; - - } - - - void load_from_xml(const std::string& file_name, const std::string& eq_to_read); - void dump_graphml(const std::string& filename); - -}; - - + // find the entry in the level list for the current node. its level defines where it goes + SameLevelClusterIdsType& my_level = clusters_by_level[curr_clust.level]; + // std::advance(level_iter, curr_clust.level); + // Add it to the vector of nodes of that level. + my_level.push_back(curr_clust_id); + my_level.total_level_cost += curr_clust.cost; + } + this->levels_valid = true; + } + void dump_graphml(const std::string& suffix) { + if (levels_valid == false) + update_node_levels(); + std::string out_filename = this->name + "_" + suffix + ".graphml"; + std::ofstream outfileml(out_filename.c_str()); + boost::dynamic_properties dp; + dp.property("index", boost::get(&ClusterType::index_list, sys_graph)); + dp.property("level", boost::get(&ClusterType::level, sys_graph)); + dp.property("cost", boost::get(&ClusterType::cost, sys_graph)); -} // openmodelica -} // parmodelica + /*! Now we have listS as vertex container. listS doesn't have VertexIndexMap + created by default. So we create one for it here. */ + typedef std::map ClustIndexMap; + ClustIndexMap clust_map_index; + boost::associative_property_map clust_prop_map_index(clust_map_index); + size_t node_count = 0; + BGL_FORALL_VERTICES_T(clust_id, sys_graph, GraphType) { + boost::put(clust_prop_map_index, clust_id, node_count++); + } + write_graphml(outfileml, sys_graph, clust_prop_map_index, dp, true); + } +}; +}} // namespace openmodelica::parmodelica #endif // header \ No newline at end of file diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_clustering.hpp b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_clustering.hpp index d6230de86db..307032ec8ba 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_clustering.hpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_clustering.hpp @@ -33,47 +33,42 @@ * */ - /* Mahder.Gebremedhin@liu.se 2014-03-13 */ - #include "pm_cluster_system.hpp" +#include -namespace openmodelica { -namespace parmodelica { - - +namespace openmodelica { namespace parmodelica { struct concat_clusters { - template - static void apply(TaskSystemType& task_system, - const typename TaskSystemType::ClusterIdType& dest_id, - const typename TaskSystemType::ClusterIdType& src_id) { + template + static void apply(TaskSystemType& task_system, const typename TaskSystemType::ClusterIdType& dest_id, + const typename TaskSystemType::ClusterIdType& src_id) { - typedef typename TaskSystemType::GraphType GraphType; - typedef typename TaskSystemType::ClusterType ClusterType; - typedef typename TaskSystemType::adjacency_iterator adjacency_iterator; + typedef typename TaskSystemType::GraphType GraphType; + typedef typename TaskSystemType::ClusterType ClusterType; + typedef typename TaskSystemType::adjacency_iterator adjacency_iterator; typedef typename TaskSystemType::inv_adjacency_iterator inv_adjacency_iterator; GraphType& sys_graph = task_system.sys_graph; - if(dest_id == src_id) + if (dest_id == src_id) return; ClusterType& dest = sys_graph[dest_id]; ClusterType& src = sys_graph[src_id]; - if(dest.level > src.level) { - std::cout << "trying to add edge : " << dest.level << " -> " << src.level << std::endl; + if (dest.level > src.level) { + std::cout << "trying to add edge : " << dest.level << " -> " << src.level << std::endl; } // std::cout << "Trying merege " << dest.index_list << " and " << src.index_list << std::endl; typename ClusterType::iterator task_iter; - for(task_iter = src.begin(); task_iter != src.end(); ++task_iter) { + for (task_iter = src.begin(); task_iter != src.end(); ++task_iter) { dest.add_task(*task_iter); } @@ -81,51 +76,50 @@ struct concat_clusters { boost::tie(src_child_iter, src_child_end) = adjacent_vertices(src_id, sys_graph); while (src_child_iter != src_child_end) { - /*! Increment before erase. Apparently erasing an edge invalidates the vertex iterators in VS. - something is going on inside boost that I don't know yet. Or VS is just being VS as ususal. - (the edge container is in fact a set, but that should matter only if we iterate over ages. - well apparently not :) )*/ - curr_src_child_iter = src_child_iter; - ++src_child_iter; + /*! Increment before erase. Apparently erasing an edge invalidates the vertex iterators in VS. + something is going on inside boost that I don't know yet. Or VS is just being VS as ususal. + (the edge container is in fact a set, but that should matter only if we iterate over ages. + well apparently not :) )*/ + curr_src_child_iter = src_child_iter; + ++src_child_iter; - if(dest_id != *curr_src_child_iter) { + if (dest_id != *curr_src_child_iter) { boost::add_edge(dest_id, *curr_src_child_iter, sys_graph); } else { - std::cout << "trying to add edge : " << sys_graph[dest_id].index_list << " -> " << sys_graph[*curr_src_child_iter].index_list << std::endl; + std::cout << "trying to add edge : " << sys_graph[dest_id].index_list << " -> " + << sys_graph[*curr_src_child_iter].index_list << std::endl; } boost::remove_edge(src_id, *curr_src_child_iter, sys_graph); - } inv_adjacency_iterator src_parent_iter, src_parent_end, curr_src_parent_iter; boost::tie(src_parent_iter, src_parent_end) = inv_adjacent_vertices(src_id, sys_graph); while (src_parent_iter != src_parent_end) { - /*! Increment before erase. Apparently erasing an edge invalidates the vertex iterators in VS. - something is going on inside boost that I don't know yet. Or VS is just being VS as ususal. - (the edge container is in fact a set, but that should matter only if we iterate over ages. - well apparently not :) )*/ - curr_src_parent_iter = src_parent_iter; - ++src_parent_iter; + /*! Increment before erase. Apparently erasing an edge invalidates the vertex iterators in VS. + something is going on inside boost that I don't know yet. Or VS is just being VS as ususal. + (the edge container is in fact a set, but that should matter only if we iterate over ages. + well apparently not :) )*/ + curr_src_parent_iter = src_parent_iter; + ++src_parent_iter; - if(*curr_src_parent_iter != dest_id) { + if (*curr_src_parent_iter != dest_id) { boost::add_edge(*curr_src_parent_iter, dest_id, sys_graph); } else { - std::cout << "trying to add edge : " << sys_graph[*curr_src_parent_iter].index_list << " -> " << sys_graph[dest_id].index_list << std::endl; + std::cout << "trying to add edge : " << sys_graph[*curr_src_parent_iter].index_list << " -> " + << sys_graph[dest_id].index_list << std::endl; } boost::remove_edge(*curr_src_parent_iter, src_id, sys_graph); } - // boost::clear_vertex(src_id, sys_graph); + // boost::clear_vertex(src_id, sys_graph); boost::remove_vertex(src_id, sys_graph); - } - }; -//struct concat_same_level_clusters { +// struct concat_same_level_clusters { // // template // static void apply(TaskSystemType& task_system, @@ -193,7 +187,7 @@ struct concat_clusters { // //}; -//struct concat_with_parent { +// struct concat_with_parent { // static std::string name() { // return "concat_with_parent"; // } @@ -242,89 +236,79 @@ struct concat_clusters { // //}; - - - - struct cluster_none { - static std::string name() { - return "cluster_none"; - } + static std::string name() { return "cluster_none"; } - template - static void dump_graph(TaskSystemType& task_system) { + template + static void dump_graph(TaskSystemType& task_system, std::string suffix = "") { /*! No op*/ } - template - static void apply(TaskSystemType& task_system) - { + template + static void apply(TaskSystemType& task_system) { /*! No op. */ } }; - struct cluster_merge_level_for_cost { - static std::string name() { - return "cluster_merge_level_for_cost"; - } + static std::string name() { return "cluster_merge_level_for_cost"; } - template - static void dump_graph(TaskSystemType& task_system) { - task_system.dump_graphml(cluster_merge_level_for_cost::name()); + template + static void dump_graph(TaskSystemType& task_system, std::string suffix = "cluster_merge_level_for_cost") { + task_system.dump_graphml(cluster_merge_level_for_cost::name() + "_" + suffix); } - template + template static void apply(TaskSystemType& task_system) { - typedef typename TaskSystemType::GraphType GraphType; + typedef typename TaskSystemType::GraphType GraphType; typedef typename TaskSystemType::ClusterLevels ClusterLevels; - typedef typename TaskSystemType::ClusterType ClusterType; + typedef typename TaskSystemType::ClusterType ClusterType; typedef typename TaskSystemType::ClusterIdType ClusterIdType; typedef typename ClusterLevels::value_type SameLevelClusterIdsType; ClusterLevels& clusters_by_level = task_system.clusters_by_level; - GraphType& sys_graph = task_system.sys_graph; + GraphType& sys_graph = task_system.sys_graph; - int nr_of_clusters = 4; + int nr_of_clusters = 8; - if(task_system.levels_valid == false) + if (task_system.levels_valid == false) task_system.update_node_levels(); - typename ClusterLevels::iterator level_iter = clusters_by_level.begin(); /*! Skip the first level. Which contains only the root node and some invlaidated clusters.*/ ++level_iter; int level_number = 1; - for( ;level_iter != clusters_by_level.end(); ++level_iter, ++level_number) { + for (; level_iter != clusters_by_level.end(); ++level_iter, ++level_number) { SameLevelClusterIdsType& current_level = *level_iter; /*!Sort the level by cost so that we can pick the nodes that fits the gap easily*/ + // sort in decreasing order cluster_cost_comparator_by_id cccbi(sys_graph); - std::sort(current_level.begin(), current_level.end(), cccbi); + std::sort(current_level.rbegin(), current_level.rend(), cccbi); - double target_cost = current_level.level_cost/nr_of_clusters; - if(target_cost < sys_graph[current_level.front()].cost) { + double target_cost = current_level.total_level_cost / nr_of_clusters; + if (target_cost < sys_graph[current_level.front()].cost) { target_cost = sys_graph[current_level.front()].cost; } - target_cost = std::max(target_cost,0.0); + target_cost = std::max(target_cost, 0.0); - int cluster_count = 0; + int cluster_count = 0; typename SameLevelClusterIdsType::iterator clustid_iter = current_level.begin(); /*! Cluster in to 'n' groups. Anything that doesn't fit in the target cost is handled in the next for loop. DO NOT modify the iterator if you are not sure.*/ - for( ;clustid_iter != current_level.end() && cluster_count < nr_of_clusters; ++clustid_iter) { + for (; clustid_iter != current_level.end() && cluster_count < nr_of_clusters; ++clustid_iter) { ClusterIdType& curr_clust_id = *clustid_iter; - ClusterType& curr_clust = sys_graph[curr_clust_id]; + ClusterType& curr_clust = sys_graph[curr_clust_id]; /*! cluster is valid*/ ++cluster_count; double gap = target_cost - curr_clust.cost; - if(gap == 0) { + if (gap == 0) { continue; } @@ -332,11 +316,11 @@ struct cluster_merge_level_for_cost { /*! start from the next node.*/ ++othersid_iter; - while(othersid_iter != current_level.end()) { + while (othersid_iter != current_level.end()) { ClusterIdType& other_clust_id = *othersid_iter; - ClusterType& other_clust = sys_graph[other_clust_id]; + ClusterType& other_clust = sys_graph[other_clust_id]; - if(other_clust.cost <= gap) { + if (other_clust.cost <= gap) { gap = gap - other_clust.cost; task_system.concat_same_level_clusters(curr_clust_id, other_clust_id); othersid_iter = current_level.erase(othersid_iter); @@ -345,44 +329,117 @@ struct cluster_merge_level_for_cost { ++othersid_iter; } } - } typename SameLevelClusterIdsType::iterator remaining_iter, smallest_clust_iter; - while(clustid_iter != current_level.end()) { - smallest_clust_iter = std::min_element(current_level.begin(), current_level.begin() + nr_of_clusters); + while (clustid_iter != current_level.end()) { + smallest_clust_iter = + std::min_element(current_level.begin(), current_level.begin() + nr_of_clusters, cccbi); task_system.concat_same_level_clusters(*smallest_clust_iter, *clustid_iter); clustid_iter = current_level.erase(clustid_iter); } - } task_system.levels_valid = false; + } +}; + +struct cluster_merge_level_for_bins { + static std::string name() { return "cluster_merge_level_for_bins"; } + template + static void dump_graph(TaskSystemType& task_system, std::string suffix = "cluster_merge_level_for_bins") { + task_system.dump_graphml(cluster_merge_level_for_bins::name() + "_" + suffix); } -}; + template + static void apply(TaskSystemType& task_system) { + typedef typename TaskSystemType::GraphType GraphType; + typedef typename TaskSystemType::ClusterLevels ClusterLevels; + // typedef typename TaskSystemType::ClusterType ClusterType; + // typedef typename TaskSystemType::ClusterIdType ClusterIdType; -struct cluster_merge_common { - static std::string name() { - return "cluster_merge_common"; + typedef typename ClusterLevels::value_type SameLevelClusterIdsType; + + ClusterLevels& clusters_by_level = task_system.clusters_by_level; + GraphType& sys_graph = task_system.sys_graph; + + unsigned nr_of_clusters = task_system.max_num_threads * 2; + + if (task_system.levels_valid == false) + task_system.update_node_levels(); + + typename ClusterLevels::iterator level_iter = clusters_by_level.begin(); + /*! Skip the first level. Which contains only the root node and some invlaidated clusters.*/ + ++level_iter; + int level_number = 1; + for (; level_iter != clusters_by_level.end(); ++level_iter, ++level_number) { + SameLevelClusterIdsType& current_level = *level_iter; + + if (current_level.size() <= nr_of_clusters) + continue; + + /*!Sort the level by cost so that we can pick the nodes that fits the gap easily*/ + // sort in decreasing order + cluster_cost_comparator_by_id cccbi(sys_graph); + std::sort(current_level.rbegin(), current_level.rend(), cccbi); + + // std::cout << "current level {"; + // for(auto& c: current_level) + // std::cout << sys_graph[c].cost << ","; + // std::cout << "}" << std::endl; + + typename SameLevelClusterIdsType::iterator smallest_clust_iter, clustid_iter, end_of_accepted; + + // Accept the first n clusters as merged tasks + end_of_accepted = current_level.begin(); + std::advance(end_of_accepted, nr_of_clusters); + // std::cout << "will start at: " << std::distance(current_level.begin(), end_of_accepted) << ": "<< + // sys_graph[*end_of_accepted].cost << std::endl; + + // iterate through the rest and merge with the smallest currently + clustid_iter = end_of_accepted; + while (clustid_iter != current_level.end()) { + // std::cout << "current level {"; + // for(auto& c: current_level) + // std::cout << sys_graph[c].cost << ","; + // std::cout << "}" << std::endl; + + smallest_clust_iter = std::min_element(current_level.begin(), end_of_accepted, cccbi); + // std::cout << "smallest is " << std::distance(current_level.begin(), smallest_clust_iter) << ": "<< + // sys_graph[*smallest_clust_iter].cost << std::endl; + task_system.concat_same_level_clusters(*smallest_clust_iter, *clustid_iter); + clustid_iter = current_level.erase(clustid_iter); + } + + // std::cout << "current level {"; + // for(auto& c: current_level) + // std::cout << sys_graph[c].cost << ","; + // std::cout << "}" << std::endl; + } + + task_system.levels_valid = false; } +}; - template - static void dump_graph(TaskSystemType& task_system) { - task_system.dump_graphml(cluster_merge_common::name()); +struct cluster_merge_common { + static std::string name() { return "cluster_merge_common"; } + + template + static void dump_graph(TaskSystemType& task_system, std::string suffix = "cluster_merge_common") { + task_system.dump_graphml(cluster_merge_common::name() + "_" + suffix); } - template - static int concat_children_recursive(TaskSystemType& task_system, - const typename TaskSystemType::ClusterIdType& curr_clust_id) { + template + static int concat_children_recursive(TaskSystemType& task_system, + const typename TaskSystemType::ClusterIdType& curr_clust_id) { - typedef typename TaskSystemType::GraphType GraphType; - typedef typename TaskSystemType::ClusterType ClusterType; - typedef typename TaskSystemType::ClusterIdType ClusterIdType; + typedef typename TaskSystemType::GraphType GraphType; + typedef typename TaskSystemType::ClusterType ClusterType; + typedef typename TaskSystemType::ClusterIdType ClusterIdType; typedef typename TaskSystemType::adjacency_iterator adjacency_iterator; - typedef typename TaskSystemType::out_edge_iterator out_edge_iterator; + // typedef typename TaskSystemType::out_edge_iterator out_edge_iterator; GraphType& sys_graph = task_system.sys_graph; @@ -390,41 +447,41 @@ struct cluster_merge_common { double target_cost = 20; - int nr_of_parents; + int nr_of_parents; adjacency_iterator child_iter, child_end, next_child_iter; boost::tie(child_iter, child_end) = adjacent_vertices(curr_clust_id, sys_graph); std::vector child_ids; - for ( ; child_iter != child_end; ++child_iter) { + for (; child_iter != child_end; ++child_iter) { const ClusterIdType& curr_child_id = *child_iter; nr_of_parents = in_degree(curr_child_id, sys_graph); - if(nr_of_parents == 1) + if (nr_of_parents == 1) child_ids.push_back(curr_child_id); } + // sort in decreasing order cluster_cost_comparator_by_id cccbi(sys_graph); - std::sort(child_ids.begin(), child_ids.end(), cccbi); + std::sort(child_ids.rbegin(), child_ids.rend(), cccbi); typename std::vector::iterator id_iter = child_ids.begin(); - for ( ; id_iter != child_ids.end(); ++id_iter) { + for (; id_iter != child_ids.end(); ++id_iter) { const ClusterIdType& curr_child_id = *id_iter; - ClusterType& curr_child = sys_graph[curr_child_id]; + ClusterType& curr_child = sys_graph[curr_child_id]; double gap = target_cost - curr_child.cost; - if(gap < 0.005) { + if (gap < 0.005) { continue; } - typename std::vector::iterator othersid_iter = id_iter; /*! start from the next node.*/ ++othersid_iter; - while(othersid_iter != child_ids.end()) { + while (othersid_iter != child_ids.end()) { ClusterIdType& other_child_id = *othersid_iter; - ClusterType& other_child = sys_graph[other_child_id]; + ClusterType& other_child = sys_graph[other_child_id]; - if(other_child.cost <= gap) { + if (other_child.cost <= gap) { gap = gap - other_child.cost; task_system.concat_same_level_clusters(curr_child_id, other_child_id); othersid_iter = child_ids.erase(othersid_iter); @@ -433,84 +490,70 @@ struct cluster_merge_common { ++othersid_iter; } } - - - } - - adjacency_iterator curr_child_iter; + adjacency_iterator curr_child_iter; boost::tie(child_iter, child_end) = adjacent_vertices(curr_clust_id, sys_graph); - while(child_iter != child_end) { - - /*! Increment before concat. Apparently erasing an edge invalidates the vertex iterators in VS. - something is going on inside boost that I don't know yet. Or VS is just being VS as ususal. - (the edge container is in fact a set, but that should matter only if we iterate over ages. - well apparently not :) )*/ - curr_child_iter = child_iter; - ++child_iter; + while (child_iter != child_end) { + /*! Increment before concat. Apparently erasing an edge invalidates the vertex iterators in VS. + something is going on inside boost that I don't know yet. Or VS is just being VS as ususal. + (the edge container is in fact a set, but that should matter only if we iterate over ages. + well apparently not :) )*/ + curr_child_iter = child_iter; + ++child_iter; - const ClusterIdType& curr_child_id = *curr_child_iter; - ClusterType& curr_child = sys_graph[curr_child_id]; + const ClusterIdType& curr_child_id = *curr_child_iter; + ClusterType& curr_child = sys_graph[curr_child_id]; nr_of_parents = concat_children_recursive(task_system, curr_child_id); - if(nr_of_parents == 1) { - if(curr_clust.cost + curr_child.cost < target_cost) { + if (nr_of_parents == 1) { + if (curr_clust.cost + curr_child.cost < target_cost) { task_system.concat_with_parent(curr_clust_id, curr_child_id); - } + } } - - } - + } return in_degree(curr_clust_id, sys_graph); - } - template + template static void apply(TaskSystemType& task_system) { - typedef typename TaskSystemType::GraphType GraphType; - typedef typename TaskSystemType::ClusterIdType ClusterIdType; + typedef typename TaskSystemType::GraphType GraphType; + typedef typename TaskSystemType::ClusterIdType ClusterIdType; typedef typename TaskSystemType::adjacency_iterator adjacency_iterator; - GraphType& sys_graph = task_system.sys_graph; + GraphType& sys_graph = task_system.sys_graph; const ClusterIdType& root_node_id = task_system.root_node_id; adjacency_iterator child_iter, child_end; boost::tie(child_iter, child_end) = adjacent_vertices(root_node_id, sys_graph); - for ( ; child_iter != child_end; ++child_iter) { + for (; child_iter != child_end; ++child_iter) { const ClusterIdType& curr_child_id = *child_iter; concat_children_recursive(task_system, curr_child_id); - } task_system.levels_valid = false; - } - }; - struct cluster_merge_single_parent { - static std::string name() { - return "cluster_merge_single_parent"; - } + static std::string name() { return "cluster_merge_single_parent"; } - template - static void dump_graph(TaskSystemType& task_system) { - task_system.dump_graphml(cluster_merge_single_parent::name()); + template + static void dump_graph(TaskSystemType& task_system, std::string suffix = "cluster_merge_single_parent") { + task_system.dump_graphml(cluster_merge_single_parent::name() + "_" + suffix); } - template + template static void apply(TaskSystemType& task_system) { - typedef typename TaskSystemType::GraphType GraphType; - typedef typename TaskSystemType::ClusterType ClusterType; - typedef typename TaskSystemType::ClusterIdType ClusterIdType; - typedef typename TaskSystemType::vertex_iterator vertex_iterator; + typedef typename TaskSystemType::GraphType GraphType; + typedef typename TaskSystemType::ClusterType ClusterType; + typedef typename TaskSystemType::ClusterIdType ClusterIdType; + typedef typename TaskSystemType::vertex_iterator vertex_iterator; typedef typename TaskSystemType::adjacency_iterator adjacency_iterator; GraphType& sys_graph = task_system.sys_graph; @@ -519,70 +562,62 @@ struct cluster_merge_single_parent { boost::tie(vert_iter, vert_end) = vertices(sys_graph); /*! skip the root node. */ ++vert_iter; - for ( ; vert_iter != vert_end; ++vert_iter) { + for (; vert_iter != vert_end; ++vert_iter) { const ClusterIdType& curr_clust_id = *vert_iter; - ClusterType& curr_clust = sys_graph[curr_clust_id]; + ClusterType& curr_clust = sys_graph[curr_clust_id]; - if(!curr_clust.is_valid()) { + if (!curr_clust.is_valid()) { continue; } adjacency_iterator child_iter, child_end, curr_child_iter; boost::tie(child_iter, child_end) = adjacent_vertices(curr_clust_id, sys_graph); while (child_iter != child_end) { - /*! Increment before concat. Apparently erasing an edge invalidates the vertex iterators in VS. - something is going on inside boost that I don't know yet. Or VS is just being VS as ususal. - (the edge container is in fact a set, but that should matter only if we iterate over ages. - well apparently not :) )*/ - curr_child_iter = child_iter; - ++child_iter; + /*! Increment before concat. Apparently erasing an edge invalidates the vertex iterators in VS. + something is going on inside boost that I don't know yet. Or VS is just being VS as ususal. + (the edge container is in fact a set, but that should matter only if we iterate over ages. + well apparently not :) )*/ + curr_child_iter = child_iter; + ++child_iter; const ClusterIdType& curr_child_id = *curr_child_iter; // ClusterType& curr_child = sys_graph[curr_child_id]; int nr_parents = in_degree(curr_child_id, sys_graph); - if(nr_parents == 1) { + if (nr_parents == 1) { task_system.concat_with_parent(curr_clust_id, curr_child_id); } } - } task_system.levels_valid = false; - } - }; - struct cluster_merge_level_parents { - static std::string name() { - return "cluster_merge_level_parents"; - } + static std::string name() { return "cluster_merge_level_parents"; } - template - static void dump_graph(TaskSystemType& task_system) { - task_system.dump_graphml(cluster_merge_level_parents::name()); + template + static void dump_graph(TaskSystemType& task_system, std::string suffix = "cluster_merge_level_parents") { + task_system.dump_graphml(cluster_merge_level_parents::name() + "_" + suffix); } - template + template static void apply(TaskSystemType& task_system) { - typedef typename TaskSystemType::GraphType GraphType; - typedef typename TaskSystemType::ClusterLevels ClusterLevels; - typedef typename TaskSystemType::ClusterType ClusterType; - typedef typename TaskSystemType::ClusterIdType ClusterIdType; + typedef typename TaskSystemType::GraphType GraphType; + typedef typename TaskSystemType::ClusterLevels ClusterLevels; + typedef typename TaskSystemType::ClusterType ClusterType; + typedef typename TaskSystemType::ClusterIdType ClusterIdType; typedef typename TaskSystemType::inv_adjacency_iterator inv_adjacency_iterator; - typedef typename ClusterLevels::value_type SameLevelClusterIdsType; + typedef typename ClusterLevels::value_type SameLevelClusterIdsType; - GraphType& sys_graph = task_system.sys_graph; + GraphType& sys_graph = task_system.sys_graph; ClusterLevels& clusters_by_level = task_system.clusters_by_level; - - if(task_system.levels_valid == false) + if (task_system.levels_valid == false) task_system.update_node_levels(); - typename ClusterLevels::iterator level_iter = clusters_by_level.begin(); /*! Skip the first level. Which contains only the root node and some invlaidated clusters.*/ ++level_iter; @@ -590,97 +625,85 @@ struct cluster_merge_level_parents { ++level_iter; int level_number = 2; - for( ;level_iter != clusters_by_level.end(); ++level_iter, ++level_number) { + for (; level_iter != clusters_by_level.end(); ++level_iter, ++level_number) { SameLevelClusterIdsType& current_level = *level_iter; typename SameLevelClusterIdsType::iterator clustid_iter = current_level.begin(); - for( ;clustid_iter != current_level.end(); ++clustid_iter) { + for (; clustid_iter != current_level.end(); ++clustid_iter) { ClusterIdType& curr_clust_id = *clustid_iter; - ClusterType& curr_clust = sys_graph[curr_clust_id]; + ClusterType& curr_clust = sys_graph[curr_clust_id]; - if(!curr_clust.is_valid()) { + if (!curr_clust.is_valid()) { continue; } - if(in_degree(curr_clust_id, sys_graph) == 1) { + if (in_degree(curr_clust_id, sys_graph) == 1) { continue; } std::vector parent_ids; - inv_adjacency_iterator parent_iter, parent_end; + inv_adjacency_iterator parent_iter, parent_end; boost::tie(parent_iter, parent_end) = inv_adjacent_vertices(curr_clust_id, sys_graph); const ClusterIdType& main_parent_id = *parent_iter; - ClusterType& main_parent = sys_graph[main_parent_id]; + ClusterType& main_parent = sys_graph[main_parent_id]; /*! start from the second parent.*/ parent_iter++; - for ( ; parent_iter != parent_end; ++parent_iter) { + for (; parent_iter != parent_end; ++parent_iter) { const ClusterIdType& other_parent_id = *parent_iter; - ClusterType& other_parent = sys_graph[other_parent_id]; + ClusterType& other_parent = sys_graph[other_parent_id]; /*! Don't merge different level parents for now.*/ - if(other_parent.level == main_parent.level) + if (other_parent.level == main_parent.level) parent_ids.push_back(*parent_iter); } typename std::vector::iterator id_iter; - for(id_iter = parent_ids.begin(); id_iter != parent_ids.end(); ++id_iter) { + for (id_iter = parent_ids.begin(); id_iter != parent_ids.end(); ++id_iter) { task_system.concat_same_level_clusters(main_parent_id, *id_iter); } - - - - } - } - task_system.levels_valid = false; - } - }; - struct cluster_merge_connected_for_cost { - static std::string name() { - return "cluster_merge_connected_for_cost"; - } + static std::string name() { return "cluster_merge_connected_for_cost"; } - template - static void dump_graph(TaskSystemType& task_system) { - task_system.dump_graphml(cluster_merge_connected_for_cost::name()); + template + static void dump_graph(TaskSystemType& task_system, std::string suffix = "cluster_merge_connected_for_cost") { + task_system.dump_graphml(cluster_merge_connected_for_cost::name() + "_" + suffix); } - template - static void find_connected(TaskSystemType& task_system, - const typename TaskSystemType::ClusterIdType& curr_clust_id, - std::list& connected_comps, int nr_of_connected) { + template + static void find_connected(TaskSystemType& task_system, const typename TaskSystemType::ClusterIdType& curr_clust_id, + std::list& connected_comps, + int nr_of_connected) { - typedef typename TaskSystemType::GraphType GraphType; - typedef typename TaskSystemType::ClusterType ClusterType; - typedef typename TaskSystemType::ClusterIdType ClusterIdType; + typedef typename TaskSystemType::GraphType GraphType; + typedef typename TaskSystemType::ClusterType ClusterType; + typedef typename TaskSystemType::ClusterIdType ClusterIdType; typedef typename TaskSystemType::inv_adjacency_iterator inv_adjacency_iterator; - typedef typename TaskSystemType::adjacency_iterator adjacency_iterator; + typedef typename TaskSystemType::adjacency_iterator adjacency_iterator; GraphType& sys_graph = task_system.sys_graph; ClusterType& curr_clust = sys_graph[curr_clust_id]; - if(!curr_clust.is_valid()) + if (!curr_clust.is_valid()) return; inv_adjacency_iterator parent_iter, parent_end; boost::tie(parent_iter, parent_end) = inv_adjacent_vertices(curr_clust_id, sys_graph); - for ( ; parent_iter != parent_end; ++parent_iter) { + for (; parent_iter != parent_end; ++parent_iter) { const ClusterIdType& curr_parent_id = *parent_iter; // ClusterType& curr_parent = sys_graph[curr_parent_id]; find_connected(task_system, curr_parent_id, connected_comps, nr_of_connected); } - - if(curr_clust.group != 0) + if (curr_clust.group != 0) std::cout << "Already visited node " << curr_clust.index_list << std::endl; else { connected_comps.push_back(curr_clust_id); @@ -691,38 +714,36 @@ struct cluster_merge_connected_for_cost { adjacency_iterator child_iter, child_end; boost::tie(child_iter, child_end) = adjacent_vertices(curr_clust_id, sys_graph); - for ( ; child_iter != child_end; ++child_iter) { + for (; child_iter != child_end; ++child_iter) { const ClusterIdType& curr_child_id = *child_iter; // ClusterType& curr_child = sys_graph[curr_child_id]; find_connected(task_system, curr_child_id, connected_comps, nr_of_connected); } - } - template + template static void apply(TaskSystemType& task_system) { - typedef typename TaskSystemType::GraphType GraphType; - typedef typename TaskSystemType::ClusterType ClusterType; - typedef typename TaskSystemType::ClusterIdType ClusterIdType; + typedef typename TaskSystemType::GraphType GraphType; + typedef typename TaskSystemType::ClusterType ClusterType; + typedef typename TaskSystemType::ClusterIdType ClusterIdType; typedef typename TaskSystemType::adjacency_iterator adjacency_iterator; - GraphType& sys_graph = task_system.sys_graph; + GraphType& sys_graph = task_system.sys_graph; ClusterIdType& root_node_id = task_system.root_node_id; adjacency_iterator top_iter, top_end; boost::tie(top_iter, top_end) = adjacent_vertices(root_node_id, sys_graph); sys_graph[root_node_id].valid = false; - - std::vector< std::list > connected_comps_list; - int nr_of_connected = 0; - for ( ; top_iter != top_end; ++top_iter) { + std::vector> connected_comps_list; + int nr_of_connected = 0; + for (; top_iter != top_end; ++top_iter) { const ClusterIdType& curr_top_id = *top_iter; - ClusterType& curr_top = sys_graph[curr_top_id]; + ClusterType& curr_top = sys_graph[curr_top_id]; - if(!curr_top.is_valid()) + if (!curr_top.is_valid()) continue; curr_top.valid = false; @@ -731,7 +752,7 @@ struct cluster_merge_connected_for_cost { connected_comps_list.push_back(std::list()); std::list& connected_comps = connected_comps_list.back(); connected_comps.push_back(curr_top_id); - if(curr_top.group != 0) + if (curr_top.group != 0) std::cout << "Top Already visited node " << curr_top.index_list << std::endl; curr_top.group = nr_of_connected; @@ -739,73 +760,67 @@ struct cluster_merge_connected_for_cost { adjacency_iterator child_iter, child_end; boost::tie(child_iter, child_end) = adjacent_vertices(curr_top_id, sys_graph); - for ( ; child_iter != child_end; ++child_iter) { + for (; child_iter != child_end; ++child_iter) { const ClusterIdType& curr_child_id = *child_iter; // const ClusterType& curr_child = sys_graph[curr_child_id]; find_connected(task_system, curr_child_id, connected_comps, nr_of_connected); } - typename std::list::iterator iter = connected_comps.begin(); - for( ; iter != connected_comps.end(); ++iter) { + for (; iter != connected_comps.end(); ++iter) { const ClusterIdType& curr_clust_id = *iter; - ClusterType& curr_clust = sys_graph[curr_clust_id]; + ClusterType& curr_clust = sys_graph[curr_clust_id]; // curr_clust.valid = true; std::cout << curr_clust.index_list << ", "; } std::cout << std::endl; - } sys_graph[root_node_id].valid = true; - double target_cost = 2000; - typename std::vector< std::list >::iterator list_iter; + double target_cost = 2000; + typename std::vector>::iterator list_iter; list_iter = connected_comps_list.begin(); - for( ; list_iter != connected_comps_list.end(); ++list_iter) { - std::list& connected_comps = *list_iter; + for (; list_iter != connected_comps_list.end(); ++list_iter) { + std::list& connected_comps = *list_iter; typename std::list::iterator iter = connected_comps.begin(); - ClusterIdType main_clust_id = *iter; + ClusterIdType main_clust_id = *iter; sys_graph[main_clust_id].valid = true; ++iter; long prev_level = sys_graph[main_clust_id].level; - for( ; iter != connected_comps.end(); ++iter) { + for (; iter != connected_comps.end(); ++iter) { const ClusterIdType& curr_clust_id = *iter; - ClusterType& curr_clust = sys_graph[curr_clust_id]; + ClusterType& curr_clust = sys_graph[curr_clust_id]; curr_clust.valid = true; - if( (sys_graph[main_clust_id].cost + curr_clust.cost <= target_cost) && - (prev_level <= curr_clust.level) ) { - std::cout << "Merging " << sys_graph[main_clust_id].index_list << " " << curr_clust.index_list << std::endl; + if ((sys_graph[main_clust_id].cost + curr_clust.cost <= target_cost) && + (prev_level <= curr_clust.level)) { + std::cout << "Merging " << sys_graph[main_clust_id].index_list << " " << curr_clust.index_list + << std::endl; prev_level = curr_clust.level; concat_clusters::apply(task_system, main_clust_id, curr_clust_id); } else { - std::cout << "Chainging main " << sys_graph[main_clust_id].index_list << " " << sys_graph[main_clust_id].level << " "; - std::cout << curr_clust.index_list << " " << curr_clust.level << " = " << sys_graph[main_clust_id].cost + curr_clust.cost << std::endl; + std::cout << "Chainging main " << sys_graph[main_clust_id].index_list << " " + << sys_graph[main_clust_id].level << " "; + std::cout << curr_clust.index_list << " " << curr_clust.level << " = " + << sys_graph[main_clust_id].cost + curr_clust.cost << std::endl; main_clust_id = curr_clust_id; prev_level = curr_clust.level; std::cout << "New main " << sys_graph[main_clust_id].index_list << std::endl; } - } } task_system.levels_valid = true; task_system.update_node_levels2(); - std::cout << "Done connected : " << connected_comps_list.size() << std::endl; - } - }; - - -} // openmodelica -} // parmodelica +}} // namespace openmodelica::parmodelica #endif // header diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_dynamic_scheduler.hpp b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_dynamic_scheduler.hpp index 22283534b2e..aa724261b75 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_dynamic_scheduler.hpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_dynamic_scheduler.hpp @@ -1,177 +1,153 @@ -#pragma once -#ifndef id7426C38B_09FD_4530_95712AEE15226ED9 -#define id7426C38B_09FD_4530_95712AEE15226ED9 - -/* - * This file is part of OpenModelica. - * - * Copyright (c) 1998-CurrentYear, Linköping University, - * Department of Computer and Information Science, - * SE-58183 Linköping, Sweden. - * - * All rights reserved. - * - * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 - * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). - * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S - * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. - * - * The OpenModelica software and the Open Source Modelica - * Consortium (OSMC) Public License (OSMC-PL) are obtained - * from Linköping University, either from the above address, - * from the URLs: http://www.ida.liu.se/projects/OpenModelica or - * http://www.openmodelica.org, and in the OpenModelica distribution. - * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. - * - * This program is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH - * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS - * OF OSMC-PL. - * - * See the full OSMC Public License conditions for more details. - * - */ - - -/* - Mahder.Gebremedhin@liu.se 2014-03-06 -*/ - -#include - -#include "pm_task_system.hpp" - - -namespace openmodelica { -namespace parmodelica { - -template -struct TaskLauncher { - typedef TaskTypeT TaskType; - typedef typename TaskType::FunctionType FunctionType; -private: - /*! These refere to the dynamic schedulers funcs and data. - This is to allow setting up the data and funcs after scheduling by - DynamicScheduler::scheduler(). */ - long task_id; - FunctionType** function_systems; - void** data; - -public: - TaskLauncher(long id, FunctionType** f, void** d) : - task_id(id) - , function_systems(f) - , data(d) - {} - - void operator()( tbb::flow::continue_msg ) const { - (*function_systems)[task_id](*data); - } -}; - -template -class DynamicScheduler { -public: - typedef TaskTypeT TaskType; - typedef typename TaskSystem::Graph GraphType; - typedef typename TaskSystem::Node NodeIdType; - - typedef typename TaskType::FunctionType FunctionType; - -private: - bool is_set_up_; - - FunctionType* function_systems; - void* data; - - tbb::flow::graph dynamic_graph; - tbb::flow::broadcast_node flow_root; - std::vector< tbb::flow::continue_node* > fnode_ps; - -public: - PMTimer execution_timer; - TaskSystem& task_system; - - DynamicScheduler(TaskSystem& task_system) : - flow_root(dynamic_graph) - , task_system(task_system) - { - is_set_up_ = false; - } - - void set_up_executor(FunctionType* f, void* d) - { - function_systems = f; - data = d; - is_set_up_ = true; - } - - bool is_set_up() { return is_set_up_; } - - void schedule(int number_of_processors) - { - using namespace tbb; - GraphType& b_graph = task_system.graph; - - typename GraphType::vertex_iterator vert_iter, vert_end; - boost::tie(vert_iter, vert_end) = vertices(b_graph); - - /*! skip the root node. */ - ++vert_iter; - for ( ; vert_iter != vert_end; ++vert_iter) { - TaskTypeT& curr_b_node = b_graph[*vert_iter]; - // std::cout << "adding " << curr_b_node.index << std::endl; - - /*! create new flow node for tbb. */ - flow::continue_node* curr_f_node = - new flow::continue_node(dynamic_graph, - TaskLauncher(curr_b_node.node_id, &function_systems, &data)); - - /*! store the node pointer. we use to add edges from it's children later. */ - fnode_ps.push_back(curr_f_node); - - /*! Iterate through all parents of the current node and add edges.*/ - typename GraphType::inv_adjacency_iterator par_iter, par_end; - boost::tie(par_iter, par_end) = inv_adjacent_vertices( *vert_iter, b_graph ); - for(; par_iter != par_end; ++par_iter) { - /*! the parent is the root in the task_graph. So here connect it to - the root of the flow graph*/ - if(b_graph[*par_iter].node_id == -1) { - flow::make_edge(flow_root, *curr_f_node); - // std::cout << " edge to root " << std::endl; - } - else { - flow::make_edge(*(fnode_ps[b_graph[*par_iter].node_id]), *curr_f_node); - // std::cout << " edge to " << b_graph[*par_iter].index << std::endl; - } - } - } - - - } - - - void execute() { - if(!this->is_set_up_) { - std::cerr << "Set up the executor for the dynmaic scheduler first" << std::endl; - exit(1); - } - - execution_timer.start_timer(); - flow_root.try_put( tbb::flow::continue_msg() ); - dynamic_graph.wait_for_all(); - execution_timer.stop_timer(); - } - -}; - - - -} // parmodelica -} // openmodelica - - - - -#endif // header +#pragma once +#ifndef id7426C38B_09FD_4530_95712AEE15226ED9 +#define id7426C38B_09FD_4530_95712AEE15226ED9 + +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Linköping University, + * Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 + * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S + * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from Linköping University, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS + * OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ + +/* + Mahder.Gebremedhin@liu.se 2014-03-06 +*/ + +#include + +#include "pm_task_system.hpp" + +namespace openmodelica { namespace parmodelica { + +template +struct TaskLauncher { + typedef TaskTypeT TaskType; + typedef typename TaskType::FunctionType FunctionType; + + private: + /*! These refere to the dynamic schedulers funcs and data. + This is to allow setting up the data and funcs after scheduling by + DynamicScheduler::scheduler(). */ + long task_id; + FunctionType** function_systems; + void** data; + + public: + TaskLauncher(long id, FunctionType** f, void** d) : task_id(id), function_systems(f), data(d) {} + + void operator()(tbb::flow::continue_msg) const { (*function_systems)[task_id](*data); } +}; + +template +class DynamicScheduler { + public: + typedef TaskTypeT TaskType; + typedef typename TaskSystem::Graph GraphType; + typedef typename TaskSystem::Node NodeIdType; + + typedef typename TaskType::FunctionType FunctionType; + + private: + bool is_set_up_; + + FunctionType* function_systems; + void* data; + + tbb::flow::graph dynamic_graph; + tbb::flow::broadcast_node flow_root; + std::vector*> fnode_ps; + + public: + PMTimer execution_timer; + TaskSystem& task_system; + + DynamicScheduler(TaskSystem& task_system) : flow_root(dynamic_graph), task_system(task_system) { + is_set_up_ = false; + } + + void set_up_executor(FunctionType* f, void* d) { + function_systems = f; + data = d; + is_set_up_ = true; + } + + bool is_set_up() { return is_set_up_; } + + void schedule(int number_of_processors) { + using namespace tbb; + GraphType& b_graph = task_system.graph; + + typename GraphType::vertex_iterator vert_iter, vert_end; + boost::tie(vert_iter, vert_end) = vertices(b_graph); + + /*! skip the root node. */ + ++vert_iter; + for (; vert_iter != vert_end; ++vert_iter) { + TaskTypeT& curr_b_node = b_graph[*vert_iter]; + // std::cout << "adding " << curr_b_node.index << std::endl; + + /*! create new flow node for tbb. */ + flow::continue_node* curr_f_node = new flow::continue_node( + dynamic_graph, TaskLauncher(curr_b_node.node_id, &function_systems, &data)); + + /*! store the node pointer. we use to add edges from it's children later. */ + fnode_ps.push_back(curr_f_node); + + /*! Iterate through all parents of the current node and add edges.*/ + typename GraphType::inv_adjacency_iterator par_iter, par_end; + boost::tie(par_iter, par_end) = inv_adjacent_vertices(*vert_iter, b_graph); + for (; par_iter != par_end; ++par_iter) { + /*! the parent is the root in the task_graph. So here connect it to + the root of the flow graph*/ + if (b_graph[*par_iter].node_id == -1) { + flow::make_edge(flow_root, *curr_f_node); + // std::cout << " edge to root " << std::endl; + } + else { + flow::make_edge(*(fnode_ps[b_graph[*par_iter].node_id]), *curr_f_node); + // std::cout << " edge to " << b_graph[*par_iter].index << std::endl; + } + } + } + } + + void execute() { + if (!this->is_set_up_) { + std::cerr << "Set up the executor for the dynmaic scheduler first" << std::endl; + exit(1); + } + + execution_timer.start_timer(); + flow_root.try_put(tbb::flow::continue_msg()); + dynamic_graph.wait_for_all(); + execution_timer.stop_timer(); + } +}; + +}} // namespace openmodelica::parmodelica + +#endif // header diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_graph_dump.hpp b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_graph_dump.hpp index adb5e9de1e6..0277d52cda3 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_graph_dump.hpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_graph_dump.hpp @@ -1,60 +1,54 @@ #pragma once #ifndef id5027FB4B_65C3_4A98_A042BA5E9DCB193A -#define id5027FB4B_65C3_4A98_A042BA5E9DCB193A - -/* - * This file is part of OpenModelica. - * - * Copyright (c) 1998-CurrentYear, Linköping University, - * Department of Computer and Information Science, - * SE-58183 Linköping, Sweden. - * - * All rights reserved. - * - * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 - * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). - * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S - * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. - * - * The OpenModelica software and the Open Source Modelica - * Consortium (OSMC) Public License (OSMC-PL) are obtained - * from Linköping University, either from the above address, - * from the URLs: http://www.ida.liu.se/projects/OpenModelica or - * http://www.openmodelica.org, and in the OpenModelica distribution. - * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. - * - * This program is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH - * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS - * OF OSMC-PL. - * - * See the full OSMC Public License conditions for more details. - * - */ - - -/* - Mahder.Gebremedhin@liu.se 2014-02-10 +#define id5027FB4B_65C3_4A98_A042BA5E9DCB193A + +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Linköping University, + * Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 + * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S + * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from Linköping University, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS + * OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ + +/* + Mahder.Gebremedhin@liu.se 2020-10-12 */ - -#include "pm_task_system.hpp" - - -namespace openmodelica { -namespace parmodelica { - -template -void dump_graphml(const TaskSystem& task_system, const std::string& filename); - -template -void dump_graphviz(const TaskSystem& task_system, const std::string& filename); - - - -} // openmodelica -} // parmodelica - -#include "pm_graph_dump.inl" - -#endif // header + +#include "pm_task_system.hpp" + +namespace openmodelica { namespace parmodelica { + +// template +// void dump_graphml(const TaskSystem& task_system, const std::string& filename); + +// template +// void dump_graphviz(const TaskSystem& task_system, const std::string& filename); + +}} // namespace openmodelica::parmodelica + +#include "pm_graph_dump.inl" + +#endif // header diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_graph_dump.inl b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_graph_dump.inl index 54fcc589717..bee9601342b 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_graph_dump.inl +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_graph_dump.inl @@ -1,111 +1,67 @@ -/* - * This file is part of OpenModelica. - * - * Copyright (c) 1998-CurrentYear, Linköping University, - * Department of Computer and Information Science, - * SE-58183 Linköping, Sweden. - * - * All rights reserved. - * - * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 - * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). - * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S - * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. - * - * The OpenModelica software and the Open Source Modelica - * Consortium (OSMC) Public License (OSMC-PL) are obtained - * from Linköping University, either from the above address, - * from the URLs: http://www.ida.liu.se/projects/OpenModelica or - * http://www.openmodelica.org, and in the OpenModelica distribution. - * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. - * - * This program is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH - * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS - * OF OSMC-PL. - * - * See the full OSMC Public License conditions for more details. - * - */ - - -/* - Mahder.Gebremedhin@liu.se 2014-02-10 -*/ - - -#include -#include -#include - - -namespace openmodelica { -namespace parmodelica { - - -template -void dump_graphml(TaskSystem& task_system, const std::string& filename) { - - typedef typename TaskSystem::TaskType Tasktype; - - std::string out_filename = filename + ".graphml"; - std::ofstream outfileml(out_filename.c_str()); - boost::dynamic_properties dp; - dp.property("index", boost::get(&Tasktype::index, task_system.graph)); - dp.property("level", boost::get(&Tasktype::level, task_system.graph)); - dp.property("cost", boost::get(&Tasktype::cost, task_system.graph)); - write_graphml(outfileml, task_system.graph, dp, true); - -} - - - - -template -void dump_graphviz(const TaskSystem& task_system, const std::string& filename) { - - std::string out_filename = filename + ".dot"; - std::ofstream outfileviz(out_filename.c_str()); - // write_graphviz(std::cout, task_system.graph, boost::make_label_writer(boost::get(&TaskTypeT::index, task_system.graph))); - write_graphviz(outfileviz, task_system.graph, boost::make_label_writer(boost::get(&TaskTypeT::index, task_system.graph))); - -} - - -template -void TaskSystem_v2::dump_graphml(const std::string& filename) { - - if(levels_valid == false) - update_node_levels(); - - - std::string out_filename = filename + ".graphml"; - std::ofstream outfileml(out_filename.c_str()); - boost::dynamic_properties dp; - dp.property("index", boost::get(&ClusterType::index_list, sys_graph)); - dp.property("level", boost::get(&ClusterType::level, sys_graph)); - dp.property("cost", boost::get(&ClusterType::cost, sys_graph)); - - - - /*! Now we have listS as vertex container. listS doesn't have VertexIndexMap - created by default. So we create one for it here. */ - typedef std::map ClustIndexMap; - ClustIndexMap clust_map_index; - boost::associative_property_map clust_prop_map_index(clust_map_index); - - size_t node_count = 0; - BGL_FORALL_VERTICES_T(clust_id, sys_graph, GraphType) - { - boost::put(clust_prop_map_index, clust_id, node_count++); - } - - write_graphml(outfileml, sys_graph, clust_prop_map_index, dp, true); - -} - - - -} // openmodelica -} // parmodelica \ No newline at end of file +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Linköping University, + * Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 + * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S + * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from Linköping University, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS + * OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ + +/* + Mahder.Gebremedhin@liu.se 2020-10-12 +*/ + +#include +#include +#include + +namespace openmodelica { namespace parmodelica { + +template +void dump_graphml(TaskSystem& task_system, const std::string& filename) { + + typedef typename TaskSystem::TaskType Tasktype; + + std::string out_filename = filename + ".graphml"; + std::ofstream outfileml(out_filename.c_str()); + boost::dynamic_properties dp; + dp.property("index", boost::get(&Tasktype::index, task_system.graph)); + dp.property("level", boost::get(&Tasktype::level, task_system.graph)); + dp.property("cost", boost::get(&Tasktype::cost, task_system.graph)); + write_graphml(outfileml, task_system.graph, dp, true); +} + +template +void dump_graphviz(const TaskSystem& task_system, const std::string& filename) { + + std::string out_filename = filename + ".dot"; + std::ofstream outfileviz(out_filename.c_str()); + // write_graphviz(std::cout, task_system.graph, boost::make_label_writer(boost::get(&TaskTypeT::index, + // task_system.graph))); + write_graphviz(outfileviz, task_system.graph, + boost::make_label_writer(boost::get(&TaskTypeT::index, task_system.graph))); +} + +}} // namespace openmodelica::parmodelica diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_level_scheduler.hpp b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_level_scheduler.hpp index 7f4c3d3e5af..322cc8964fb 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_level_scheduler.hpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_level_scheduler.hpp @@ -1,314 +1,260 @@ -#pragma once -#ifndef idDB873A43_F8D8_4666_8209C3B5AB1F01C2 -#define idDB873A43_F8D8_4666_8209C3B5AB1F01C2 - - -/* - * This file is part of OpenModelica. - * - * Copyright (c) 1998-CurrentYear, Linköping University, - * Department of Computer and Information Science, - * SE-58183 Linköping, Sweden. - * - * All rights reserved. - * - * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 - * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). - * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S - * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. - * - * The OpenModelica software and the Open Source Modelica - * Consortium (OSMC) Public License (OSMC-PL) are obtained - * from Linköping University, either from the above address, - * from the URLs: http://www.ida.liu.se/projects/OpenModelica or - * http://www.openmodelica.org, and in the OpenModelica distribution. - * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. - * - * This program is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH - * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS - * OF OSMC-PL. - * - * See the full OSMC Public License conditions for more details. - * - */ - - -/* - Mahder.Gebremedhin@liu.se 2014-02-10 -*/ - - - -#include - -#include -#include - -#include "pm_task_system.hpp" -#include "pm_timer.hpp" - - -namespace openmodelica { -namespace parmodelica { - - -template -class LevelSchedulerThreadOblivious; - -template -class LevelSchedulerThreadAware; - -/*! Using the thread aware level scheduler by default*/ -// template -// using LevelScheduler = LevelSchedulerThreadAware; - - - -template -struct Level : - public utility::pm_vector< - typename TaskSystem< - TaskTypeT - >::Node - > -{ - typedef TaskTypeT TaskType; - typedef typename TaskSystem::Node NodeIdType; - - Level() : level_cost(0) {} - double level_cost; - - std::vector task_ids; -}; - - -template -struct TBBLevelExecutor { - - typedef TaskTypeT TaskType; - typedef typename TaskType::FunctionType FunctionType; - typedef std::vector::const_iterator TaskIdIter; - -private: - FunctionType* function_systems; - void* data; -public: - TBBLevelExecutor() : data(NULL) {} - void set_up(FunctionType* function_systems_, void* data_) { - data = data_; - function_systems = function_systems_; - } - - void operator()( const tbb::blocked_range& range ) const { - for(TaskIdIter iter = range.begin(); iter != range.end(); ++iter) { - function_systems[*iter](data); - } - } - -}; - - -template -class LevelSchedulerThreadOblivious : boost::noncopyable { -public: - typedef TaskTypeT TaskType; - typedef typename TaskSystem::Graph GraphType; - typedef typename TaskSystem::Node NodeIdType; - - typedef typename TaskType::FunctionType FunctionType; - typedef std::vector< Level > LevelsType; - -private: - bool is_set_up_; - int number_of_processors; - bool nodes_have_been_leveled; - std::vector< Level > levels; - FunctionType* function_systems; - void* data; - bool profiled; - -public: - LevelSchedulerThreadOblivious(TaskSystem& task_system); - - TaskSystem& task_system; - tbb::task_scheduler_init tbb_task_init; - TBBLevelExecutor level_executor; - - double total_parallel_cost; - PMTimer execution_timer; - - void get_node_levels(); - void set_up_executor(FunctionType*, void*); - bool is_set_up() { return is_set_up_; } - - void schedule(int number_of_processors); - void execute(); - void profile_execute(); - - void print_schedule(std::ostream& ) const; - void print_node_levels(std::ostream& ) const; - -}; - - - - - - - - -template -struct TaskQueue : - public utility::pm_vector< - typename TaskSystem< - TaskTypeT - >::Node - > -{ - typedef TaskTypeT TaskType; - typedef typename TaskTypeT::FunctionType FunctionType; - - TaskQueue() : total_cost(0) {} - double total_cost; - - /*! this is just to avoid refering to the actual graph to get the task_ids since - the whole scheduling operations work on node_ids i.e. ids of nodes in the graph - which has in a sense nothing to do with the acutal task. So once we get all the - nodes that belong in this queue we collect the task_id for each node here and use - it to launch tasks.*/ - std::vector task_ids; - - static bool - cost_comparator(const TaskQueue& lhs, - const TaskQueue& rhs) { - return lhs.total_cost < rhs.total_cost; - } - - void execute(FunctionType* function_systems, void* data) const { - for(unsigned i = 0; i < this->size(); ++i) { - function_systems[task_ids[i]](data); - } - } - -}; - - -template -struct ConcurrentQueues : - public utility::pm_vector< - TaskQueueTypeT - > -{ - typedef TaskQueueTypeT TaskQueueType; - typedef typename TaskQueueType::FunctionType FunctionType; - typedef typename utility::pm_vector::const_iterator const_iterator; - - ConcurrentQueues() : - total_cost(0), - parallel_cost(0) - {} - - double total_cost; - double parallel_cost; - - void execute(FunctionType* function_systems, void* data) const { - const_iterator iter; - for(iter = this->begin(); iter != this->end(); ++iter) { - iter->execute(function_systems, data); - } - } - -}; - - -template -struct TBBConcurrentExecutor { - - typedef ConcurrentQueuesTypeT ConcurrentQueuesType; - typedef typename ConcurrentQueuesType::FunctionType FunctionType; - typedef typename ConcurrentQueuesType::const_iterator ConQueIter; - -private: - FunctionType* function_systems; - void* data; - -public: - TBBConcurrentExecutor() : data(NULL) {} - void set_up(FunctionType* function_systems_, void* data_) { - data = data_; - function_systems = function_systems_; - } - - void operator()( const tbb::blocked_range& range ) const { - for(ConQueIter iter = range.begin(); iter != range.end(); ++iter) { - iter->execute(function_systems, data); - } - } - -}; - - - -template -class LevelSchedulerThreadAware : boost::noncopyable { -public: - typedef TaskTypeT TaskType; - typedef typename TaskSystem::Graph GraphType; - typedef typename TaskSystem::Node NodeIdType; - - typedef TaskQueue TaskQueueType; - typedef typename TaskQueueType::FunctionType FunctionType; - typedef ConcurrentQueues ConcurrentQueuesType; - typedef std::vector TaskQueueGroupAllLevelsType; - -private: - bool is_set_up_; - bool profiled; - int number_of_processors; - bool nodes_have_been_leveled; - - std::vector< Level > levels; - - FunctionType* function_systems; - void* data; - -public: - LevelSchedulerThreadAware(TaskSystem& task_system); - - TaskSystem& task_system; - tbb::task_scheduler_init tbb_task_init; - TBBConcurrentExecutor level_executor; - - double total_parallel_cost; - PMTimer execution_timer; - TaskQueueGroupAllLevelsType processor_queue_levels; - - - void get_node_levels(); - void set_up_executor(FunctionType*, void*); - bool is_set_up() { return is_set_up_; } - - // void schedule(); - void schedule(int number_of_processors); - // void re_schedule(); - void re_schedule(int number_of_processors); - void execute(); - void profile_execute(); - - void print_node_levels(std::ostream& ) const; - void print_schedule(std::ostream& ) const; - - -}; - - - -} // parmodelica -} // openmodelica - - -#include "pm_level_scheduler.inl" - +#pragma once +#ifndef idDB873A43_F8D8_4666_8209C3B5AB1F01C2 +#define idDB873A43_F8D8_4666_8209C3B5AB1F01C2 + +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Linköping University, + * Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 + * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S + * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from Linköping University, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS + * OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ + +/* + Mahder.Gebremedhin@liu.se 2020-10-12 +*/ + +#include + +#include +#include + +#include "pm_task_system.hpp" +#include "pm_timer.hpp" + +namespace openmodelica { namespace parmodelica { + +template +class LevelSchedulerThreadOblivious; + +template +class LevelSchedulerThreadAware; + +/*! Using the thread aware level scheduler by default*/ +// template +// using LevelScheduler = LevelSchedulerThreadAware; + +template +struct Level : public utility::pm_vector::Node> { + typedef TaskTypeT TaskType; + typedef typename TaskSystem::Node NodeIdType; + + Level() : level_cost(0) {} + double level_cost; + + std::vector task_ids; +}; + +template +struct TBBLevelExecutor { + + typedef TaskTypeT TaskType; + typedef typename TaskType::FunctionType FunctionType; + typedef std::vector::const_iterator TaskIdIter; + + private: + FunctionType* function_systems; + void* data; + + public: + TBBLevelExecutor() : data(NULL) {} + void set_up(FunctionType* function_systems_, void* data_) { + data = data_; + function_systems = function_systems_; + } + + void operator()(const tbb::blocked_range& range) const { + for (TaskIdIter iter = range.begin(); iter != range.end(); ++iter) { + function_systems[*iter](data); + } + } +}; + +template +class LevelSchedulerThreadOblivious : boost::noncopyable { + public: + typedef TaskTypeT TaskType; + typedef typename TaskSystem::Graph GraphType; + typedef typename TaskSystem::Node NodeIdType; + + typedef typename TaskType::FunctionType FunctionType; + typedef std::vector> LevelsType; + + private: + bool is_set_up_; + int number_of_processors; + bool nodes_have_been_leveled; + std::vector> levels; + FunctionType* function_systems; + void* data; + bool profiled; + + public: + LevelSchedulerThreadOblivious(TaskSystem& task_system); + + TaskSystem& task_system; + tbb::task_scheduler_init tbb_task_init; + TBBLevelExecutor level_executor; + + double total_parallel_cost; + PMTimer execution_timer; + + void get_node_levels(); + void set_up_executor(FunctionType*, void*); + bool is_set_up() { return is_set_up_; } + + void schedule(int number_of_processors); + void execute(); + void profile_execute(); + + void print_schedule(std::ostream&) const; + void print_node_levels(std::ostream&) const; +}; + +template +struct TaskQueue : public utility::pm_vector::Node> { + typedef TaskTypeT TaskType; + typedef typename TaskTypeT::FunctionType FunctionType; + + TaskQueue() : total_cost(0) {} + double total_cost; + + /*! this is just to avoid refering to the actual graph to get the task_ids since + the whole scheduling operations work on node_ids i.e. ids of nodes in the graph + which has in a sense nothing to do with the acutal task. So once we get all the + nodes that belong in this queue we collect the task_id for each node here and use + it to launch tasks.*/ + std::vector task_ids; + + static bool cost_comparator(const TaskQueue& lhs, const TaskQueue& rhs) { + return lhs.total_cost < rhs.total_cost; + } + + void execute(FunctionType* function_systems, void* data) const { + for (unsigned i = 0; i < this->size(); ++i) { + function_systems[task_ids[i]](data); + } + } +}; + +template +struct ConcurrentQueues : public utility::pm_vector { + typedef TaskQueueTypeT TaskQueueType; + typedef typename TaskQueueType::FunctionType FunctionType; + typedef typename utility::pm_vector::const_iterator const_iterator; + + ConcurrentQueues() : total_cost(0), parallel_cost(0) {} + + double total_cost; + double parallel_cost; + + void execute(FunctionType* function_systems, void* data) const { + const_iterator iter; + for (iter = this->begin(); iter != this->end(); ++iter) { + iter->execute(function_systems, data); + } + } +}; + +template +struct TBBConcurrentExecutor { + + typedef ConcurrentQueuesTypeT ConcurrentQueuesType; + typedef typename ConcurrentQueuesType::FunctionType FunctionType; + typedef typename ConcurrentQueuesType::const_iterator ConQueIter; + + private: + FunctionType* function_systems; + void* data; + + public: + TBBConcurrentExecutor() : data(NULL) {} + void set_up(FunctionType* function_systems_, void* data_) { + data = data_; + function_systems = function_systems_; + } + + void operator()(const tbb::blocked_range& range) const { + for (ConQueIter iter = range.begin(); iter != range.end(); ++iter) { + iter->execute(function_systems, data); + } + } +}; + +template +class LevelSchedulerThreadAware : boost::noncopyable { + public: + typedef TaskTypeT TaskType; + typedef typename TaskSystem::Graph GraphType; + typedef typename TaskSystem::Node NodeIdType; + + typedef TaskQueue TaskQueueType; + typedef typename TaskQueueType::FunctionType FunctionType; + typedef ConcurrentQueues ConcurrentQueuesType; + typedef std::vector TaskQueueGroupAllLevelsType; + + private: + bool is_set_up_; + bool profiled; + int number_of_processors; + bool nodes_have_been_leveled; + + std::vector> levels; + + FunctionType* function_systems; + void* data; + + public: + LevelSchedulerThreadAware(TaskSystem& task_system); + + TaskSystem& task_system; + tbb::task_scheduler_init tbb_task_init; + TBBConcurrentExecutor level_executor; + + double total_parallel_cost; + PMTimer execution_timer; + TaskQueueGroupAllLevelsType processor_queue_levels; + + void get_node_levels(); + void set_up_executor(FunctionType*, void*); + bool is_set_up() { return is_set_up_; } + + // void schedule(); + void schedule(int number_of_processors); + // void re_schedule(); + void re_schedule(int number_of_processors); + void execute(); + void profile_execute(); + + void print_node_levels(std::ostream&) const; + void print_schedule(std::ostream&) const; +}; + +}} // namespace openmodelica::parmodelica + +#include "pm_level_scheduler.inl" + #endif // header \ No newline at end of file diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_level_scheduler.inl b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_level_scheduler.inl index af06bfee588..fce2bc45ddb 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_level_scheduler.inl +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_level_scheduler.inl @@ -1,607 +1,525 @@ -/* - * This file is part of OpenModelica. - * - * Copyright (c) 1998-CurrentYear, Linköping University, - * Department of Computer and Information Science, - * SE-58183 Linköping, Sweden. - * - * All rights reserved. - * - * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 - * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). - * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S - * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. - * - * The OpenModelica software and the Open Source Modelica - * Consortium (OSMC) Public License (OSMC-PL) are obtained - * from Linköping University, either from the above address, - * from the URLs: http://www.ida.liu.se/projects/OpenModelica or - * http://www.openmodelica.org, and in the OpenModelica distribution. - * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. - * - * This program is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH - * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS - * OF OSMC-PL. - * - * See the full OSMC Public License conditions for more details. - * - */ - - -/* - Mahder.Gebremedhin@liu.se 2014-02-10 -*/ - - -#include -#include - -#include "pm_graph_dump.hpp" - - -// #include - -namespace openmodelica { -namespace parmodelica { - - -template -LevelSchedulerThreadOblivious::LevelSchedulerThreadOblivious(TaskSystem& task_system) : - task_system(task_system), - tbb_task_init(4) -{ - nodes_have_been_leveled = false; - total_parallel_cost = 0; - is_set_up_ = false; - profiled = false; -} - -template -void LevelSchedulerThreadOblivious::get_node_levels() { - - GraphType& graph = this->task_system.graph; - - int critical_path = 0; - // boost::dijkstra_shortest_paths(graph,task_system.root_node,boost::weight_map( - // boost::make_constant_property::Edge>(1)).distance_map(boost::get(&TaskTypeT::level,graph))); - BGL_FORALL_VERTICES_T(v,graph,GraphType) - { - int max_p_lvl = graph[v].level - 1; - typename GraphType::inv_adjacency_iterator neighbourIt, neighbourEnd; - boost::tie(neighbourIt, neighbourEnd) = inv_adjacent_vertices( v, graph ); - for(typename GraphType::inv_adjacency_iterator adj_iter = neighbourIt; adj_iter != neighbourEnd; ++adj_iter) { - max_p_lvl = std::max(max_p_lvl, graph[*adj_iter].level); - } - graph[v].level = max_p_lvl + 1; - critical_path = max_p_lvl > critical_path ? max_p_lvl : critical_path; - } - - levels.resize(critical_path + 2); - BGL_FORALL_VERTICES_T(node,graph,GraphType) - { - levels[graph[node].level].push_back(node); - levels[graph[node].level].level_cost += graph[node].cost; - } - - /*! Sort the level by cost so that we can pick the node that fits the scheduling time easily.*/ - Node_cost_comparatorR vccR(graph); - typename std::vector >::iterator level_iter; - for(level_iter = levels.begin() + 1; level_iter != levels.end(); ++level_iter) { - Level& current_level = *level_iter; - std::sort(current_level.begin(), current_level.end(), vccR); - } - - this->nodes_have_been_leveled = true; - -} - -template -void LevelSchedulerThreadOblivious::print_node_levels(std::ostream& ostr) const { - - GraphType& graph = this->task_system.graph; - - ostr << "------------------------------------------------------------------------------------------" << newl; - - for(unsigned curr_lvl = 0; curr_lvl < levels.size(); curr_lvl++) { - ostr << "Level " << curr_lvl << " : " << levels[curr_lvl].level_cost << " : "; - for(unsigned curr_eq = 0; curr_eq < levels[curr_lvl].size(); ++curr_eq) { - typename TaskSystem::Node node = levels[curr_lvl][curr_eq]; - ostr << "(" << graph[node].index << ", " << graph[node].cost << "), "; - - } - ostr << newl; - - } - ostr << "------------------------------------------------------------------------------------------" << newl; - -} - -template -void LevelSchedulerThreadOblivious::set_up_executor(FunctionType* function_systems_, void* data_) { - this->function_systems = function_systems_; - this->data = data_; - level_executor.set_up(function_systems_, data_); - this->is_set_up_ = true; -} - -template -void LevelSchedulerThreadOblivious::schedule(int number_of_processors) { - - if(!this->nodes_have_been_leveled) - this->get_node_levels(); - -} - -template -void LevelSchedulerThreadOblivious::print_schedule(std::ostream& ostr) const { - print_node_levels(ostr); -} - -template -void LevelSchedulerThreadOblivious::execute() { - - if(!this->is_set_up_) { - std::cerr << "Set up the executor first" << std::endl; - exit(1); - } - if(!profiled) - return profile_execute(); - - execution_timer.start_timer(); - - typename LevelsType::iterator level_iter; - level_iter = levels.begin() + 1; - for( ; level_iter != levels.end(); ++level_iter) { - unsigned nr_of_tasks = level_iter->size(); - std::vector& l_task_ids = level_iter->task_ids; - /*! cutoff cost. For now here is no optimal value. Just try to pick a cost that will give - benefit over the overhead of thread context switching*/ - if(level_iter->level_cost > 0.1) { - tbb::parallel_for( - tbb::blocked_range::const_iterator>( - l_task_ids.begin(), l_task_ids.end()) - , level_executor); - } - else { - for(unsigned j = 0; j < nr_of_tasks; ++j) { - function_systems[l_task_ids[j]](data); - } - } - - } - - execution_timer.stop_timer(); - -} - - -template -void LevelSchedulerThreadOblivious::profile_execute() { - - GraphType& system_graph = this->task_system.graph; - Node_cost_comparatorR vccR(system_graph); - - std::cout << "system cost before = " << task_system.total_cost << std::endl; - std::cout << "Scheduler cost before = " << total_parallel_cost << std::endl; - std::cout << "Peak speedup before = " << task_system.total_cost/total_parallel_cost << std::endl; - - - task_system.total_cost = 0; - PMTimer cost_timer; - double curr_cost; - - execution_timer.start_timer(); - - typename LevelsType::iterator level_iter; - level_iter = levels.begin() + 1; - for( ; level_iter != levels.end(); ++level_iter) { - level_iter->level_cost = 0; - unsigned nr_of_tasks = level_iter->size(); - for(unsigned j = 0; j < nr_of_tasks; ++j) { - cost_timer.start_timer(); - function_systems[system_graph[level_iter->at(j)].node_id](data); - cost_timer.stop_timer(); - curr_cost = cost_timer.get_elapsed_time() * 10000; - cost_timer.reset_timer(); - system_graph[level_iter->at(j)].cost = curr_cost; - level_iter->level_cost += curr_cost; - } - task_system.total_cost += level_iter->level_cost; - - /*! Sort if needed. hoping that larger tasks will be picked up first*/ - std::sort(level_iter->begin(), level_iter->end(), vccR); - - /*! save the task_ids so that we don't have to access them using the node id and then going - to the graph every time.*/ - for(unsigned j = 0; j < nr_of_tasks; ++j) { - level_iter->task_ids.push_back(system_graph[level_iter->at(j)].node_id); - } - } - - profiled = true; - - execution_timer.stop_timer(); - - - - std::cout << "system cost after = " << task_system.total_cost << std::endl; - std::cout << "Scheduler cost after = " << total_parallel_cost << std::endl; - std::cout << "Peak speedup after = " << task_system.total_cost/total_parallel_cost << std::endl; - std::cout << "-------------------------------------------------------------" << std::endl; - - print_node_levels(std::cout); - -} - - - - - - - - - - - - - - - - - - - - -template -LevelSchedulerThreadAware::LevelSchedulerThreadAware(TaskSystem& task_system) : - task_system(task_system), - tbb_task_init(4) -{ - nodes_have_been_leveled = false; - total_parallel_cost = 0; - is_set_up_ = false; - profiled = false; -} - - -template -void LevelSchedulerThreadAware::get_node_levels() { - - GraphType& graph = this->task_system.graph; - - int critical_path = 0; - // boost::dijkstra_shortest_paths(graph,task_system.root_node,boost::weight_map( - // boost::make_constant_property::Edge>(1)).distance_map(boost::get(&TaskTypeT::level,graph))); - BGL_FORALL_VERTICES_T(v,graph,GraphType) - { - int max_p_lvl = graph[v].level - 1; - typename GraphType::inv_adjacency_iterator neighbourIt, neighbourEnd; - boost::tie(neighbourIt, neighbourEnd) = inv_adjacent_vertices( v, graph ); - for(typename GraphType::inv_adjacency_iterator adj_iter = neighbourIt; adj_iter != neighbourEnd; ++adj_iter) { - max_p_lvl = std::max(max_p_lvl, graph[*adj_iter].level); - } - graph[v].level = max_p_lvl + 1; - critical_path = max_p_lvl > critical_path ? max_p_lvl : critical_path; - } - - levels.resize(critical_path + 2); - BGL_FORALL_VERTICES_T(node,graph,GraphType) - { - levels[graph[node].level].push_back(node); - levels[graph[node].level].level_cost += graph[node].cost; - } - - /*! Sort the level by cost so that we can pick the node that fits the scheduling time easily.*/ - Node_cost_comparatorR vccR(graph); - typename std::vector >::iterator level_iter; - for(level_iter = levels.begin() + 1; level_iter != levels.end(); ++level_iter) { - Level& current_level = *level_iter; - std::sort(current_level.begin(), current_level.end(), vccR); - } - - this->nodes_have_been_leveled = true; - -} - - -template -void LevelSchedulerThreadAware::print_node_levels(std::ostream& ostr) const { - - GraphType& graph = this->task_system.graph; - - ostr << "------------------------------------------------------------------------------------------" << newl; - - for(unsigned curr_lvl = 0; curr_lvl < levels.size(); curr_lvl++) { - ostr << "Level " << curr_lvl << " : " << levels[curr_lvl].level_cost << " : "; - for(unsigned curr_eq = 0; curr_eq < levels[curr_lvl].size(); ++curr_eq) { - typename TaskSystem::Node node = levels[curr_lvl][curr_eq]; - ostr << "(" << graph[node].index << ", " << graph[node].cost << "), "; - - } - ostr << newl; - - } - ostr << "------------------------------------------------------------------------------------------" << newl; - -} - - -template -void LevelSchedulerThreadAware::set_up_executor(FunctionType* function_systems_, void* data_) { - this->function_systems = function_systems_; - this->data = data_; - level_executor.set_up(function_systems_, data_); - this->is_set_up_ = true; -} - -// template -// void LevelSchedulerThreadAware::schedule() { - // schedule(boost::thread::hardware_concurrency()); -// } - - -template -void LevelSchedulerThreadAware::schedule(int number_of_processors) { - - GraphType& system_graph = this->task_system.graph; - - /*! get the node levels if they haven't been leveled yet. */ - if(!this->nodes_have_been_leveled) - this->get_node_levels(); - - // print_node_levels(std::cout); - - - processor_queue_levels.resize(levels.size()); - - long level_number = 1; - - /*! Iterate over all levels. That means visiting all children of the root first and then children of each node in there and so on*/ - typename std::vector >::iterator level_iter; - for(level_iter = this->levels.begin() + 1; level_iter != this->levels.end(); ++level_iter, ++level_number) { - Level& current_level = *level_iter; - - /*! calculate the maximum parallel cost of the current level*/ - double max = current_level.level_cost/number_of_processors; - if(max < system_graph[current_level.front()].cost) { - max = system_graph[current_level.front()].cost; - } - - - ConcurrentQueuesType& current_group = processor_queue_levels[level_number]; - current_group.resize(number_of_processors); - - - typename ConcurrentQueuesType::iterator pqueue_iter; - for(pqueue_iter = current_group.begin(); pqueue_iter != current_group.end(); ++pqueue_iter) { - TaskQueueType& current_queue = *(pqueue_iter); - - // We have free processor but we run out of tasks. - if(current_level.empty()) { - break; - } - - current_queue.push_back(current_level.front()); - current_queue.total_cost += system_graph[current_level.front()].cost; - current_level.erase(current_level.begin()); - - double gap = max - current_queue.total_cost; - if(gap != 0) - { - typename std::vector::iterator node_iter; - for(node_iter = current_level.begin(); node_iter != current_level.end() && gap != 0; ) { - if(system_graph[*node_iter].cost <= gap) { - gap = gap - system_graph[*node_iter].cost; - current_queue.push_back(*node_iter); - current_queue.total_cost += system_graph[*node_iter].cost; - node_iter = current_level.erase(node_iter); - } - else - ++node_iter; - - } - } - - current_group.total_cost = current_queue.total_cost; - - } - - /*! See if any nodes remain in the current level that have not been assigned by the - loop above. can happpen for some combination of costs. If there are nodes remaining - add them to the queue with the least cost currently.*/ - while(current_level.size() != 0) { - // utility::test_log("Info") << "vertices remaining. " << current_level.size() << " " << system_graph[current_level.front()].index << newl; - pqueue_iter = std::min_element(current_group.begin(), current_group.end(), - TaskQueueType::cost_comparator); - pqueue_iter->push_back(current_level.front()); - pqueue_iter->total_cost += system_graph[current_level.front()].cost; - current_level.erase(current_level.begin()); - } - - - current_group.parallel_cost = std::max_element(current_group.begin(), current_group.end(), - TaskQueueType::cost_comparator)->total_cost; - total_parallel_cost += current_group.parallel_cost; - - /*! check if there are empty queues i.e. processors with no possible jobs. Then resize the - queue vector to avoid launching threads for empty queues later.*/ - pqueue_iter = std::find_if(current_group.begin(), current_group.end(), - std::mem_fun_ref(&TaskQueueType::empty)); - - if(pqueue_iter != current_group.end()) { - current_group.resize(std::distance(current_group.begin(), pqueue_iter)); - } - - /*! now that scheduling is done collect the task ids in the correct order - so that we don't have to refere to the actuall system system_graph in execution time - to get the task id using a node id.*/ - for(pqueue_iter = current_group.begin(); pqueue_iter != current_group.end(); ++pqueue_iter) { - TaskQueueType& current_queue = *(pqueue_iter); - for(unsigned i = 0; i < current_queue.size(); ++i) { - current_queue.task_ids.push_back(system_graph[current_queue[i]].node_id); - } - - } - - - } - -} - - -// template -// void LevelSchedulerThreadAware::re_schedule() { - // re_schedule(boost::thread::hardware_concurrency()); -// } - -template -void LevelSchedulerThreadAware::re_schedule(int number_of_processors) { - - /*TODO nodes should not be releveled here. Save the old level somehow and use it. - maybe copy it before rescheduling. The scheduler as it is now removes nodes from it - as it schedules. */ - nodes_have_been_leveled = false; - total_parallel_cost = 0; - - levels.clear(); - processor_queue_levels.clear(); - - schedule(number_of_processors); - // print_node_levels(std::cout); - // print_schedule(std::cout); -} - - -template -void LevelSchedulerThreadAware::print_schedule(std::ostream& ostr) const { - - GraphType& graph = this->task_system.graph; - - - long level_number = 1; - typename TaskQueueGroupAllLevelsType::const_iterator pq_level_iter; - for(pq_level_iter = this->processor_queue_levels.begin() + 1; pq_level_iter != this->processor_queue_levels.end(); ++pq_level_iter, ++level_number) { - const ConcurrentQueuesType& current_group = *pq_level_iter; - - double total_level_cost = 0; - ostr << "-------------------------------Strarting level "<< level_number << " ---------------------------------------------" << newl; - - for(unsigned j = 0; j < current_group.size(); ++j) { - for(unsigned i = 0; i < current_group[j].size(); ++i) - ostr << graph[current_group[j][i]].index << ", "; - - total_level_cost += current_group[j].total_cost; - ostr << newl << "---" << current_group[j].total_cost << newl; - } - - ostr << "Level total cost : " << total_level_cost << newl; - ostr << "Level parallel cost : " << current_group.parallel_cost << newl; - - } - ostr << "-------------------------------------------------------------------------------------------------------------------" << newl; - -} - - -template -void LevelSchedulerThreadAware::execute() { - - if(!this->is_set_up_) { - std::cerr << "Set up the executor first" << std::endl; - exit(1); - } - if(!profiled) - return profile_execute(); - - - - execution_timer.start_timer(); - - typename TaskQueueGroupAllLevelsType::const_iterator pq_level_iter; - pq_level_iter = processor_queue_levels.begin() + 1; - for( ; pq_level_iter != processor_queue_levels.end(); ++pq_level_iter) { - const ConcurrentQueuesType& current_group = *pq_level_iter; - - if(current_group.parallel_cost > 0.05) { - tbb::parallel_for( - tbb::blocked_range( - current_group.begin(), current_group.end()) - , level_executor); - } - else { - pq_level_iter->execute(function_systems, data); - } - - // std::for_each(current_group.begin(), current_group.end(), level_executor); - - } - - execution_timer.stop_timer(); - -} - - -template -void LevelSchedulerThreadAware::profile_execute() { - - GraphType& system_graph = this->task_system.graph; - - std::cout << "system cost before = " << task_system.total_cost << std::endl; - std::cout << "Scheduler cost before = " << total_parallel_cost << std::endl; - std::cout << "Peak speedup before = " << task_system.total_cost/total_parallel_cost << std::endl; - - - task_system.total_cost = 0; - PMTimer cost_timer; - double curr_cost; - - execution_timer.start_timer(); - - typename TaskQueueGroupAllLevelsType::iterator pq_level_iter; - pq_level_iter = processor_queue_levels.begin() + 1; - for(; pq_level_iter != processor_queue_levels.end(); ++pq_level_iter) - { - const ConcurrentQueuesType& current_group = *pq_level_iter; - for(unsigned j = 0; j < current_group.size(); ++j) - { - const TaskQueueType& current_queue = current_group[j]; - for(unsigned i = 0; i < current_queue.size(); ++i) - { - cost_timer.start_timer(); - function_systems[system_graph[current_queue[i]].node_id](data); - cost_timer.stop_timer(); - curr_cost = cost_timer.get_elapsed_time() * 10000; - cost_timer.reset_timer(); - - system_graph[current_queue[i]].cost = curr_cost; - task_system.total_cost += curr_cost; - } - } - - } - - profiled = true; - re_schedule(4); - - execution_timer.stop_timer(); - - - - std::cout << "system cost after = " << task_system.total_cost << std::endl; - std::cout << "Scheduler cost after = " << total_parallel_cost << std::endl; - std::cout << "Peak speedup after = " << task_system.total_cost/total_parallel_cost << std::endl; - std::cout << "-------------------------------------------------------------" << std::endl; - - print_schedule(std::cout); - - dump_graphml(task_system, "current-"); - -} - - - - -} // parmodelica -} // openmodelica \ No newline at end of file +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Linköping University, + * Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 + * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S + * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from Linköping University, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS + * OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ + +/* + Mahder.Gebremedhin@liu.se 2020-10-12 +*/ + +#include +#include + +#include "pm_graph_dump.hpp" + +// #include + +namespace openmodelica { namespace parmodelica { + +template +LevelSchedulerThreadOblivious::LevelSchedulerThreadOblivious(TaskSystem& task_system) + : task_system(task_system) + , tbb_task_init(4) { + nodes_have_been_leveled = false; + total_parallel_cost = 0; + is_set_up_ = false; + profiled = false; +} + +template +void LevelSchedulerThreadOblivious::get_node_levels() { + + GraphType& graph = this->task_system.graph; + + int critical_path = 0; + // boost::dijkstra_shortest_paths(graph,task_system.root_node,boost::weight_map( + // boost::make_constant_property::Edge>(1)).distance_map(boost::get(&TaskTypeT::level,graph))); + BGL_FORALL_VERTICES_T(v, graph, GraphType) { + int max_p_lvl = graph[v].level - 1; + typename GraphType::inv_adjacency_iterator neighbourIt, neighbourEnd; + boost::tie(neighbourIt, neighbourEnd) = inv_adjacent_vertices(v, graph); + for (typename GraphType::inv_adjacency_iterator adj_iter = neighbourIt; adj_iter != neighbourEnd; ++adj_iter) { + max_p_lvl = std::max(max_p_lvl, graph[*adj_iter].level); + } + graph[v].level = max_p_lvl + 1; + critical_path = max_p_lvl > critical_path ? max_p_lvl : critical_path; + } + + levels.resize(critical_path + 2); + BGL_FORALL_VERTICES_T(node, graph, GraphType) { + levels[graph[node].level].push_back(node); + levels[graph[node].level].level_cost += graph[node].cost; + } + + /*! Sort the level by cost so that we can pick the node that fits the scheduling time easily.*/ + Node_cost_comparatorR vccR(graph); + typename std::vector>::iterator level_iter; + for (level_iter = levels.begin() + 1; level_iter != levels.end(); ++level_iter) { + Level& current_level = *level_iter; + std::sort(current_level.begin(), current_level.end(), vccR); + } + + this->nodes_have_been_leveled = true; +} + +template +void LevelSchedulerThreadOblivious::print_node_levels(std::ostream& ostr) const { + + GraphType& graph = this->task_system.graph; + + ostr << "------------------------------------------------------------------------------------------" << newl; + + for (unsigned curr_lvl = 0; curr_lvl < levels.size(); curr_lvl++) { + ostr << "Level " << curr_lvl << " : " << levels[curr_lvl].level_cost << " : "; + for (unsigned curr_eq = 0; curr_eq < levels[curr_lvl].size(); ++curr_eq) { + typename TaskSystem::Node node = levels[curr_lvl][curr_eq]; + ostr << "(" << graph[node].index << ", " << graph[node].cost << "), "; + } + ostr << newl; + } + ostr << "------------------------------------------------------------------------------------------" << newl; +} + +template +void LevelSchedulerThreadOblivious::set_up_executor(FunctionType* function_systems_, void* data_) { + this->function_systems = function_systems_; + this->data = data_; + level_executor.set_up(function_systems_, data_); + this->is_set_up_ = true; +} + +template +void LevelSchedulerThreadOblivious::schedule(int number_of_processors) { + + if (!this->nodes_have_been_leveled) + this->get_node_levels(); +} + +template +void LevelSchedulerThreadOblivious::print_schedule(std::ostream& ostr) const { + print_node_levels(ostr); +} + +template +void LevelSchedulerThreadOblivious::execute() { + + if (!this->is_set_up_) { + std::cerr << "Set up the executor first" << std::endl; + exit(1); + } + if (!profiled) + return profile_execute(); + + execution_timer.start_timer(); + + typename LevelsType::iterator level_iter; + level_iter = levels.begin() + 1; + for (; level_iter != levels.end(); ++level_iter) { + unsigned nr_of_tasks = level_iter->size(); + std::vector& l_task_ids = level_iter->task_ids; + /*! cutoff cost. For now here is no optimal value. Just try to pick a cost that will give + benefit over the overhead of thread context switching*/ + if (level_iter->level_cost > 0.1) { + tbb::parallel_for( + tbb::blocked_range::const_iterator>(l_task_ids.begin(), l_task_ids.end()), + level_executor); + } + else { + for (unsigned j = 0; j < nr_of_tasks; ++j) { + function_systems[l_task_ids[j]](data); + } + } + } + + execution_timer.stop_timer(); +} + +template +void LevelSchedulerThreadOblivious::profile_execute() { + + GraphType& system_graph = this->task_system.graph; + Node_cost_comparatorR vccR(system_graph); + + std::cout << "system cost before = " << task_system.total_cost << std::endl; + std::cout << "Scheduler cost before = " << total_parallel_cost << std::endl; + std::cout << "Peak speedup before = " << task_system.total_cost / total_parallel_cost << std::endl; + + task_system.total_cost = 0; + PMTimer cost_timer; + double curr_cost; + + execution_timer.start_timer(); + + typename LevelsType::iterator level_iter; + level_iter = levels.begin() + 1; + for (; level_iter != levels.end(); ++level_iter) { + level_iter->level_cost = 0; + unsigned nr_of_tasks = level_iter->size(); + for (unsigned j = 0; j < nr_of_tasks; ++j) { + cost_timer.start_timer(); + function_systems[system_graph[level_iter->at(j)].node_id](data); + cost_timer.stop_timer(); + curr_cost = cost_timer.get_elapsed_time() * 10000; + cost_timer.reset_timer(); + system_graph[level_iter->at(j)].cost = curr_cost; + level_iter->level_cost += curr_cost; + } + task_system.total_cost += level_iter->level_cost; + + /*! Sort if needed. hoping that larger tasks will be picked up first*/ + std::sort(level_iter->begin(), level_iter->end(), vccR); + + /*! save the task_ids so that we don't have to access them using the node id and then going + to the graph every time.*/ + for (unsigned j = 0; j < nr_of_tasks; ++j) { + level_iter->task_ids.push_back(system_graph[level_iter->at(j)].node_id); + } + } + + profiled = true; + + execution_timer.stop_timer(); + + std::cout << "system cost after = " << task_system.total_cost << std::endl; + std::cout << "Scheduler cost after = " << total_parallel_cost << std::endl; + std::cout << "Peak speedup after = " << task_system.total_cost / total_parallel_cost << std::endl; + std::cout << "-------------------------------------------------------------" << std::endl; + + print_node_levels(std::cout); +} + +template +LevelSchedulerThreadAware::LevelSchedulerThreadAware(TaskSystem& task_system) + : task_system(task_system) + , tbb_task_init(4) { + nodes_have_been_leveled = false; + total_parallel_cost = 0; + is_set_up_ = false; + profiled = false; +} + +template +void LevelSchedulerThreadAware::get_node_levels() { + + GraphType& graph = this->task_system.graph; + + int critical_path = 0; + // boost::dijkstra_shortest_paths(graph,task_system.root_node,boost::weight_map( + // boost::make_constant_property::Edge>(1)).distance_map(boost::get(&TaskTypeT::level,graph))); + BGL_FORALL_VERTICES_T(v, graph, GraphType) { + int max_p_lvl = graph[v].level - 1; + typename GraphType::inv_adjacency_iterator neighbourIt, neighbourEnd; + boost::tie(neighbourIt, neighbourEnd) = inv_adjacent_vertices(v, graph); + for (typename GraphType::inv_adjacency_iterator adj_iter = neighbourIt; adj_iter != neighbourEnd; ++adj_iter) { + max_p_lvl = std::max(max_p_lvl, graph[*adj_iter].level); + } + graph[v].level = max_p_lvl + 1; + critical_path = max_p_lvl > critical_path ? max_p_lvl : critical_path; + } + + levels.resize(critical_path + 2); + BGL_FORALL_VERTICES_T(node, graph, GraphType) { + levels[graph[node].level].push_back(node); + levels[graph[node].level].level_cost += graph[node].cost; + } + + /*! Sort the level by cost so that we can pick the node that fits the scheduling time easily.*/ + Node_cost_comparatorR vccR(graph); + typename std::vector>::iterator level_iter; + for (level_iter = levels.begin() + 1; level_iter != levels.end(); ++level_iter) { + Level& current_level = *level_iter; + std::sort(current_level.begin(), current_level.end(), vccR); + } + + this->nodes_have_been_leveled = true; +} + +template +void LevelSchedulerThreadAware::print_node_levels(std::ostream& ostr) const { + + GraphType& graph = this->task_system.graph; + + ostr << "------------------------------------------------------------------------------------------" << newl; + + for (unsigned curr_lvl = 0; curr_lvl < levels.size(); curr_lvl++) { + ostr << "Level " << curr_lvl << " : " << levels[curr_lvl].level_cost << " : "; + for (unsigned curr_eq = 0; curr_eq < levels[curr_lvl].size(); ++curr_eq) { + typename TaskSystem::Node node = levels[curr_lvl][curr_eq]; + ostr << "(" << graph[node].index << ", " << graph[node].cost << "), "; + } + ostr << newl; + } + ostr << "------------------------------------------------------------------------------------------" << newl; +} + +template +void LevelSchedulerThreadAware::set_up_executor(FunctionType* function_systems_, void* data_) { + this->function_systems = function_systems_; + this->data = data_; + level_executor.set_up(function_systems_, data_); + this->is_set_up_ = true; +} + +// template +// void LevelSchedulerThreadAware::schedule() { +// schedule(boost::thread::hardware_concurrency()); +// } + +template +void LevelSchedulerThreadAware::schedule(int number_of_processors) { + + GraphType& system_graph = this->task_system.graph; + + /*! get the node levels if they haven't been leveled yet. */ + if (!this->nodes_have_been_leveled) + this->get_node_levels(); + + // print_node_levels(std::cout); + + processor_queue_levels.resize(levels.size()); + + long level_number = 1; + + /*! Iterate over all levels. That means visiting all children of the root first and then children of each node in + * there and so on*/ + typename std::vector>::iterator level_iter; + for (level_iter = this->levels.begin() + 1; level_iter != this->levels.end(); ++level_iter, ++level_number) { + Level& current_level = *level_iter; + + /*! calculate the maximum parallel cost of the current level*/ + double max = current_level.level_cost / number_of_processors; + if (max < system_graph[current_level.front()].cost) { + max = system_graph[current_level.front()].cost; + } + + ConcurrentQueuesType& current_group = processor_queue_levels[level_number]; + current_group.resize(number_of_processors); + + typename ConcurrentQueuesType::iterator pqueue_iter; + for (pqueue_iter = current_group.begin(); pqueue_iter != current_group.end(); ++pqueue_iter) { + TaskQueueType& current_queue = *(pqueue_iter); + + // We have free processor but we run out of tasks. + if (current_level.empty()) { + break; + } + + current_queue.push_back(current_level.front()); + current_queue.total_cost += system_graph[current_level.front()].cost; + current_level.erase(current_level.begin()); + + double gap = max - current_queue.total_cost; + if (gap != 0) { + typename std::vector::iterator node_iter; + for (node_iter = current_level.begin(); node_iter != current_level.end() && gap != 0;) { + if (system_graph[*node_iter].cost <= gap) { + gap = gap - system_graph[*node_iter].cost; + current_queue.push_back(*node_iter); + current_queue.total_cost += system_graph[*node_iter].cost; + node_iter = current_level.erase(node_iter); + } + else + ++node_iter; + } + } + + current_group.total_cost = current_queue.total_cost; + } + + /*! See if any nodes remain in the current level that have not been assigned by the + loop above. can happpen for some combination of costs. If there are nodes remaining + add them to the queue with the least cost currently.*/ + while (current_level.size() != 0) { + // utility::test_log("Info") << "vertices remaining. " << current_level.size() << " " << + // system_graph[current_level.front()].index << newl; + pqueue_iter = std::min_element(current_group.begin(), current_group.end(), TaskQueueType::cost_comparator); + pqueue_iter->push_back(current_level.front()); + pqueue_iter->total_cost += system_graph[current_level.front()].cost; + current_level.erase(current_level.begin()); + } + + current_group.parallel_cost = + std::max_element(current_group.begin(), current_group.end(), TaskQueueType::cost_comparator)->total_cost; + total_parallel_cost += current_group.parallel_cost; + + /*! check if there are empty queues i.e. processors with no possible jobs. Then resize the + queue vector to avoid launching threads for empty queues later.*/ + pqueue_iter = std::find_if(current_group.begin(), current_group.end(), std::mem_fun_ref(&TaskQueueType::empty)); + + if (pqueue_iter != current_group.end()) { + current_group.resize(std::distance(current_group.begin(), pqueue_iter)); + } + + /*! now that scheduling is done collect the task ids in the correct order + so that we don't have to refere to the actuall system system_graph in execution time + to get the task id using a node id.*/ + for (pqueue_iter = current_group.begin(); pqueue_iter != current_group.end(); ++pqueue_iter) { + TaskQueueType& current_queue = *(pqueue_iter); + for (unsigned i = 0; i < current_queue.size(); ++i) { + current_queue.task_ids.push_back(system_graph[current_queue[i]].node_id); + } + } + } +} + +// template +// void LevelSchedulerThreadAware::re_schedule() { +// re_schedule(boost::thread::hardware_concurrency()); +// } + +template +void LevelSchedulerThreadAware::re_schedule(int number_of_processors) { + + /*TODO nodes should not be releveled here. Save the old level somehow and use it. + maybe copy it before rescheduling. The scheduler as it is now removes nodes from it + as it schedules. */ + nodes_have_been_leveled = false; + total_parallel_cost = 0; + + levels.clear(); + processor_queue_levels.clear(); + + schedule(number_of_processors); + // print_node_levels(std::cout); + // print_schedule(std::cout); +} + +template +void LevelSchedulerThreadAware::print_schedule(std::ostream& ostr) const { + + GraphType& graph = this->task_system.graph; + + long level_number = 1; + typename TaskQueueGroupAllLevelsType::const_iterator pq_level_iter; + for (pq_level_iter = this->processor_queue_levels.begin() + 1; pq_level_iter != this->processor_queue_levels.end(); + ++pq_level_iter, ++level_number) { + const ConcurrentQueuesType& current_group = *pq_level_iter; + + double total_level_cost = 0; + ostr << "-------------------------------Strarting level " << level_number + << " ---------------------------------------------" << newl; + + for (unsigned j = 0; j < current_group.size(); ++j) { + for (unsigned i = 0; i < current_group[j].size(); ++i) + ostr << graph[current_group[j][i]].index << ", "; + + total_level_cost += current_group[j].total_cost; + ostr << newl << "---" << current_group[j].total_cost << newl; + } + + ostr << "Level total cost : " << total_level_cost << newl; + ostr << "Level parallel cost : " << current_group.parallel_cost << newl; + } + ostr << "----------------------------------------------------------------------------------------------------------" + "---------" + << newl; +} + +template +void LevelSchedulerThreadAware::execute() { + + if (!this->is_set_up_) { + std::cerr << "Set up the executor first" << std::endl; + exit(1); + } + if (!profiled) + return profile_execute(); + + execution_timer.start_timer(); + + typename TaskQueueGroupAllLevelsType::const_iterator pq_level_iter; + pq_level_iter = processor_queue_levels.begin() + 1; + for (; pq_level_iter != processor_queue_levels.end(); ++pq_level_iter) { + const ConcurrentQueuesType& current_group = *pq_level_iter; + + if (current_group.parallel_cost > 0.05) { + tbb::parallel_for(tbb::blocked_range(current_group.begin(), + current_group.end()), + level_executor); + } + else { + pq_level_iter->execute(function_systems, data); + } + + // std::for_each(current_group.begin(), current_group.end(), level_executor); + } + + execution_timer.stop_timer(); +} + +template +void LevelSchedulerThreadAware::profile_execute() { + + GraphType& system_graph = this->task_system.graph; + + std::cout << "system cost before = " << task_system.total_cost << std::endl; + std::cout << "Scheduler cost before = " << total_parallel_cost << std::endl; + std::cout << "Peak speedup before = " << task_system.total_cost / total_parallel_cost << std::endl; + + task_system.total_cost = 0; + PMTimer cost_timer; + double curr_cost; + + execution_timer.start_timer(); + + typename TaskQueueGroupAllLevelsType::iterator pq_level_iter; + pq_level_iter = processor_queue_levels.begin() + 1; + for (; pq_level_iter != processor_queue_levels.end(); ++pq_level_iter) { + const ConcurrentQueuesType& current_group = *pq_level_iter; + for (unsigned j = 0; j < current_group.size(); ++j) { + const TaskQueueType& current_queue = current_group[j]; + for (unsigned i = 0; i < current_queue.size(); ++i) { + cost_timer.start_timer(); + function_systems[system_graph[current_queue[i]].node_id](data); + cost_timer.stop_timer(); + curr_cost = cost_timer.get_elapsed_time() * 10000; + cost_timer.reset_timer(); + + system_graph[current_queue[i]].cost = curr_cost; + task_system.total_cost += curr_cost; + } + } + } + + profiled = true; + re_schedule(4); + + execution_timer.stop_timer(); + + std::cout << "system cost after = " << task_system.total_cost << std::endl; + std::cout << "Scheduler cost after = " << total_parallel_cost << std::endl; + std::cout << "Peak speedup after = " << task_system.total_cost / total_parallel_cost << std::endl; + std::cout << "-------------------------------------------------------------" << std::endl; + + print_schedule(std::cout); + + dump_graphml(task_system, "current-"); +} + +}} // namespace openmodelica::parmodelica diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_load_xml.inl b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_load_xml.inl index 99248e3e536..e8b99f02f28 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_load_xml.inl +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_load_xml.inl @@ -1,285 +1,252 @@ -/* - * This file is part of OpenModelica. - * - * Copyright (c) 1998-CurrentYear, Linköping University, - * Department of Computer and Information Science, - * SE-58183 Linköping, Sweden. - * - * All rights reserved. - * - * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 - * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). - * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S - * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. - * - * The OpenModelica software and the Open Source Modelica - * Consortium (OSMC) Public License (OSMC-PL) are obtained - * from Linköping University, either from the above address, - * from the URLs: http://www.ida.liu.se/projects/OpenModelica or - * http://www.openmodelica.org, and in the OpenModelica distribution. - * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. - * - * This program is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH - * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS - * OF OSMC-PL. - * - * See the full OSMC Public License conditions for more details. - * - */ - - -/* - Mahder.Gebremedhin@liu.se 2014-02-10 -*/ - - - -#include - -#include - - -namespace openmodelica { -namespace parmodelica { - -template -void load_node(TaskTypeT& current_node, pugi::xml_node& xml_equ) { - - pugi::xml_attribute index = xml_equ.first_attribute(); - current_node.index = index.as_int(); - - pugi::xml_node eq_type = xml_equ.first_child(); - current_node.type = eq_type.name(); - - if( std::strcmp(eq_type.name(),"assign") == 0) { - - pugi::xml_node current = eq_type.first_child(); - - while(std::strcmp(current.name(),"defines") == 0) { - current_node.lhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } - - - while(std::strcmp(current.name(),"depends") == 0) { - current_node.rhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } - - current_node.cost = 1; - } - else if( std::strcmp(eq_type.name(),"residual") == 0) { - - pugi::xml_node current = eq_type.first_child(); - - while(std::strcmp(current.name(),"defines") == 0) { - current_node.lhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } - - - while(std::strcmp(current.name(),"depends") == 0) { - current_node.rhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } - - current_node.cost = 1; - } - else if( std::strcmp(eq_type.name(),"statement") == 0) { - - pugi::xml_node current = eq_type.first_child(); - - while(std::strcmp(current.name(),"defines") == 0) { - current_node.lhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } - - - while(std::strcmp(current.name(),"depends") == 0) { - current_node.rhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } - - current_node.cost = 1; - } - else if( std::strcmp(eq_type.name(),"when") == 0) { - - pugi::xml_node current = eq_type.first_child(); - current_node.rhs.insert(current.child_value()); - current = current.next_sibling(); - - while(std::strcmp(current.name(),"defines") == 0) { - current_node.lhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } - - - while(std::strcmp(current.name(),"depends") == 0) { - current_node.rhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } - - current_node.cost = 2; - } - - else if( std::strcmp(eq_type.name(),"linear") == 0) { - - pugi::xml_node current = eq_type.first_child(); - - int ls_size = 0; - while(std::strcmp(current.name(),"defines") == 0) { - current_node.lhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - ++ls_size; - } - - while(std::strcmp(current.name(),"depends") == 0) { - current_node.rhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } - - current_node.cost = ls_size; - utility::warning("") << current_node.index << ": Linear equations not fully handled yet: " << ls_size << newl; - } - - else if( std::strcmp(eq_type.name(),"nonlinear") == 0) { - - pugi::xml_node current = eq_type.first_child(); - - while(std::strcmp(current.name(),"defines") == 0) { - current_node.lhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } - - - long nls_size = 0; - while(std::strcmp(current.name(),"eq") == 0) { - // current_node.eqs.push_back(current.attribute("index").as_int()); - current = current.next_sibling(); - ++nls_size; - } - - current_node.cost = nls_size; - - for(int count = 0; count < nls_size; ++count) { - xml_equ = xml_equ.next_sibling(); - typename TaskSystem::TaskType nls_eq_node; - load_node(nls_eq_node, xml_equ); - current_node.lhs.insert(nls_eq_node.lhs.begin(), nls_eq_node.lhs.end()); - current_node.rhs.insert(nls_eq_node.rhs.begin(), nls_eq_node.rhs.end()); - } - utility::warning("") << current_node.index << ": Non linear equations not fully handled yet: " << nls_size << newl; - } - - else if( std::strcmp(eq_type.name(),"mixed") == 0) { - - int mix_size = eq_type.attribute("size").as_int(); - - pugi::xml_node current = eq_type.first_child(); - - while(std::strcmp(current.name(),"defines") == 0) { - current_node.lhs.insert(current.attribute("name").value()); - current = current.next_sibling(); - } - - current_node.cost = mix_size; - - for(int count = 0; count < mix_size; ++count) { - xml_equ = xml_equ.next_sibling(); - typename TaskSystem::TaskType mix_eq_node; - load_node(mix_eq_node, xml_equ); - current_node.lhs.insert(mix_eq_node.lhs.begin(), mix_eq_node.lhs.end()); - current_node.rhs.insert(mix_eq_node.rhs.begin(), mix_eq_node.rhs.end()); - } - - utility::warning("") << current_node.index << ": Mixed equations not fully handled yet: " << mix_size << newl; - } - - else { - current_node.cost = 1; - utility::error("") << current_node.index << ": Unknown Equation type." << eq_type.name() << newl; - } - - -} - - -template -void TaskSystem::load_from_xml(const std::string& file_name, const std::string& eq_to_read) { - - pugi::xml_document doc; - if(!doc.load_file(file_name.c_str())) { - std::cerr << "Error loading XML file '" << file_name << "'." << std::endl; - exit(1); - } - - - pugi::xml_node xml_equs = doc.child("tasksystemdump").child(eq_to_read.c_str()); - - long node_count = 0; - - - for (pugi::xml_node xml_equ = xml_equs.first_child(); xml_equ; ) - { - - TaskType& current_node = this->add_node(); - load_node(current_node, xml_equ); - ++node_count; - - total_cost += current_node.cost; - xml_equ = xml_equ.next_sibling(); - } - - - utility::log("") << "Number of tasks = " << node_count << newl; - utility::log("") << "Total Cost of system = " << total_cost << newl; - - -} - - - - -template -void TaskSystem_v2::load_from_xml(const std::string& file_name, const std::string& eq_to_read) { - - pugi::xml_document doc; - if(!doc.load_file(file_name.c_str())) { - std::cerr << "Error loading XML file '" << file_name << "'." << std::endl; - exit(1); - } - - - pugi::xml_node xml_equs = doc.child("tasksystemdump").child(eq_to_read.c_str()); - - long node_count = 0; - - - for (pugi::xml_node xml_equ = xml_equs.first_child(); xml_equ; ) - { - - TaskType current_node; - load_node(current_node, xml_equ); - ++node_count; - - this->add_node(current_node); - - xml_equ = xml_equ.next_sibling(); - } - - - utility::log("") << "Number of tasks = " << node_count << newl; - utility::log("") << "Total Cost of system = " << total_cost << newl; - - -} - - - - -} // openmodelica -} // parmodelica - - +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Linköping University, + * Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 + * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S + * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from Linköping University, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS + * OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ + +/* + Mahder.Gebremedhin@liu.se 2020-10-12 +*/ + +#include + +#include + +namespace openmodelica { namespace parmodelica { + +template +void load_node(TaskTypeT& current_node, pugi::xml_node& xml_equ) { + + pugi::xml_attribute index = xml_equ.first_attribute(); + current_node.index = index.as_int(); + + pugi::xml_node eq_type = xml_equ.first_child(); + current_node.type = eq_type.name(); + + if (std::strcmp(eq_type.name(), "assign") == 0) { + + pugi::xml_node current = eq_type.first_child(); + + while (std::strcmp(current.name(), "defines") == 0) { + current_node.lhs.insert(current.attribute("name").value()); + current = current.next_sibling(); + } + + while (std::strcmp(current.name(), "depends") == 0) { + current_node.rhs.insert(current.attribute("name").value()); + current = current.next_sibling(); + } + + current_node.cost = 1; + } + else if (std::strcmp(eq_type.name(), "residual") == 0) { + + pugi::xml_node current = eq_type.first_child(); + + while (std::strcmp(current.name(), "defines") == 0) { + current_node.lhs.insert(current.attribute("name").value()); + current = current.next_sibling(); + } + + while (std::strcmp(current.name(), "depends") == 0) { + current_node.rhs.insert(current.attribute("name").value()); + current = current.next_sibling(); + } + + current_node.cost = 1; + } + else if (std::strcmp(eq_type.name(), "statement") == 0) { + + pugi::xml_node current = eq_type.first_child(); + + while (std::strcmp(current.name(), "defines") == 0) { + current_node.lhs.insert(current.attribute("name").value()); + current = current.next_sibling(); + } + + while (std::strcmp(current.name(), "depends") == 0) { + current_node.rhs.insert(current.attribute("name").value()); + current = current.next_sibling(); + } + + current_node.cost = 1; + } + else if (std::strcmp(eq_type.name(), "when") == 0) { + + pugi::xml_node current = eq_type.first_child(); + current_node.rhs.insert(current.child_value()); + current = current.next_sibling(); + + while (std::strcmp(current.name(), "defines") == 0) { + current_node.lhs.insert(current.attribute("name").value()); + current = current.next_sibling(); + } + + while (std::strcmp(current.name(), "depends") == 0) { + current_node.rhs.insert(current.attribute("name").value()); + current = current.next_sibling(); + } + + current_node.cost = 2; + } + + else if (std::strcmp(eq_type.name(), "linear") == 0) { + + pugi::xml_node current = eq_type.first_child(); + + int ls_size = 0; + while (std::strcmp(current.name(), "defines") == 0) { + current_node.lhs.insert(current.attribute("name").value()); + current = current.next_sibling(); + ++ls_size; + } + + while (std::strcmp(current.name(), "depends") == 0) { + current_node.rhs.insert(current.attribute("name").value()); + current = current.next_sibling(); + } + + current_node.cost = ls_size; + utility::warning("") << current_node.index << ": Linear equations not fully handled yet: " << ls_size << newl; + } + + else if (std::strcmp(eq_type.name(), "nonlinear") == 0) { + + pugi::xml_node current = eq_type.first_child(); + + while (std::strcmp(current.name(), "defines") == 0) { + current_node.lhs.insert(current.attribute("name").value()); + current = current.next_sibling(); + } + + long nls_size = 0; + while (std::strcmp(current.name(), "eq") == 0) { + // current_node.eqs.push_back(current.attribute("index").as_int()); + current = current.next_sibling(); + ++nls_size; + } + + current_node.cost = nls_size; + + for (int count = 0; count < nls_size; ++count) { + xml_equ = xml_equ.next_sibling(); + typename TaskSystem::TaskType nls_eq_node; + load_node(nls_eq_node, xml_equ); + current_node.lhs.insert(nls_eq_node.lhs.begin(), nls_eq_node.lhs.end()); + current_node.rhs.insert(nls_eq_node.rhs.begin(), nls_eq_node.rhs.end()); + } + utility::warning("") << current_node.index << ": Non linear equations not fully handled yet: " << nls_size + << newl; + } + + else if (std::strcmp(eq_type.name(), "mixed") == 0) { + + int mix_size = eq_type.attribute("size").as_int(); + + pugi::xml_node current = eq_type.first_child(); + + while (std::strcmp(current.name(), "defines") == 0) { + current_node.lhs.insert(current.attribute("name").value()); + current = current.next_sibling(); + } + + current_node.cost = mix_size; + + for (int count = 0; count < mix_size; ++count) { + xml_equ = xml_equ.next_sibling(); + typename TaskSystem::TaskType mix_eq_node; + load_node(mix_eq_node, xml_equ); + current_node.lhs.insert(mix_eq_node.lhs.begin(), mix_eq_node.lhs.end()); + current_node.rhs.insert(mix_eq_node.rhs.begin(), mix_eq_node.rhs.end()); + } + + utility::warning("") << current_node.index << ": Mixed equations not fully handled yet: " << mix_size << newl; + } + + else { + current_node.cost = 1; + utility::error("") << current_node.index << ": Unknown Equation type." << eq_type.name() << newl; + } +} + +template +void TaskSystem::load_from_xml(const std::string& file_name, const std::string& eq_to_read) { + + pugi::xml_document doc; + if (!doc.load_file(file_name.c_str())) { + std::cerr << "Error loading XML file '" << file_name << "'." << std::endl; + exit(1); + } + + pugi::xml_node xml_equs = doc.child("tasksystemdump").child(eq_to_read.c_str()); + + long node_count = 0; + + for (pugi::xml_node xml_equ = xml_equs.first_child(); xml_equ;) { + + TaskType& current_node = this->add_node(); + load_node(current_node, xml_equ); + ++node_count; + + total_cost += current_node.cost; + xml_equ = xml_equ.next_sibling(); + } + + utility::log("") << "Number of tasks = " << node_count << newl; + utility::log("") << "Total Cost of system = " << total_cost << newl; +} + +template +void TaskSystem_v2::load_from_xml(const std::string& file_name, const std::string& eq_to_read) { + + pugi::xml_document doc; + if (!doc.load_file(file_name.c_str())) { + std::cerr << "Error loading XML file '" << file_name << "'." << std::endl; + exit(1); + } + + pugi::xml_node xml_equs = doc.child("tasksystemdump").child(eq_to_read.c_str()); + + long node_count = 0; + + for (pugi::xml_node xml_equ = xml_equs.first_child(); xml_equ;) { + + TaskType current_node; + load_node(current_node, xml_equ); + ++node_count; + + this->add_node(current_node); + + xml_equ = xml_equ.next_sibling(); + } + + utility::log("") << "Number of tasks = " << node_count << newl; + utility::log("") << "Total Cost of system = " << total_cost << newl; +} + +}} // namespace openmodelica::parmodelica diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_posix_timer.cpp b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_posix_timer.cpp index 006d4a07c5f..e3cceaa26b6 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_posix_timer.cpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_posix_timer.cpp @@ -30,37 +30,32 @@ * */ - /* Mahder.Gebremedhin@liu.se 2014-02-25 */ - #include "pm_timer.hpp" -namespace openmodelica { -namespace parmodelica { +namespace openmodelica { namespace parmodelica { -PMTimer::PMTimer(){ +PMTimer::PMTimer() { total_time = boost::chrono::seconds::zero(); } -void PMTimer::start_timer(){ +void PMTimer::start_timer() { started_at = boost::chrono::system_clock::now(); } -void PMTimer::stop_timer(){ +void PMTimer::stop_timer() { total_time += (boost::chrono::system_clock::now() - started_at); } -void PMTimer::reset_timer(){ +void PMTimer::reset_timer() { total_time = boost::chrono::seconds::zero(); } -double PMTimer::get_elapsed_time(){ - return boost::chrono::nanoseconds(total_time).count() / 1000000000.0; +double PMTimer::get_elapsed_time() { + return boost::chrono::nanoseconds(total_time).count() / 1000000.0; } -} // parmodelica -} // openmodelica - +}} // namespace openmodelica::parmodelica diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_task_system.hpp b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_task_system.hpp index eccc955f8b5..f55584d97ab 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_task_system.hpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_task_system.hpp @@ -1,175 +1,151 @@ -#pragma once -#ifndef idC32CC0E3_D0E1_479D_85BC0769EFD475C0 -#define idC32CC0E3_D0E1_479D_85BC0769EFD475C0 - - -/* - * This file is part of OpenModelica. - * - * Copyright (c) 1998-CurrentYear, Linköping University, - * Department of Computer and Information Science, - * SE-58183 Linköping, Sweden. - * - * All rights reserved. - * - * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 - * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). - * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S - * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. - * - * The OpenModelica software and the Open Source Modelica - * Consortium (OSMC) Public License (OSMC-PL) are obtained - * from Linköping University, either from the above address, - * from the URLs: http://www.ida.liu.se/projects/OpenModelica or - * http://www.openmodelica.org, and in the OpenModelica distribution. - * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. - * - * This program is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH - * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS - * OF OSMC-PL. - * - * See the full OSMC Public License conditions for more details. - * - */ - - -/* - Mahder.Gebremedhin@liu.se 2014-02-10 -*/ - - - -#include - -#include -#include - -#include "pm_utility.hpp" - - -namespace openmodelica { -namespace parmodelica { - - -struct TaskNode { - TaskNode() : - level(0) - , cost(0) - {}; - - long task_id; - int level; - double cost; - - virtual bool depends_on(const TaskNode&) const = 0; -}; - - -template -class TaskSystem : boost::noncopyable { - std::string model_name; - -public: - typedef TaskTypeT TaskType; - typedef typename boost::adjacency_list Graph; - typedef typename Graph::vertex_descriptor Node; // rename me to NodeType - typedef typename Graph::vertices_size_type vertices_size_type; - typedef typename boost::graph_traits::vertex_iterator vertex_iterator; - - typedef typename Graph::edge_descriptor Edge; - - Graph graph; - Node root_node; - double total_cost; - long node_count; - - TaskSystem() : - total_cost(0) - { - root_node = boost::add_vertex(graph); - graph[root_node].node_id = -1; - node_count = 0; - } - - TaskType& add_node() - { - Node node = boost::add_vertex(graph); - graph[node].node_id = node_count; - ++node_count; - - return graph[node]; - } - - void construct_graph() - { - Edge edge; - - std::pair vp_out = boost::vertices(graph); - for (unsigned i = 1; i != *vp_out.second; ++i) { - int neigh_count = 0; - for (unsigned j = i - 1; j > 0; --j) { - bool found_dep = graph[i].depends_on(graph[j]); - if(found_dep) { - bool b; - boost::tie(edge,b) = boost::add_edge(j,i,graph); - if(!b) - utility::log("") << "Error adding Edge- " << graph[j].index << " --> " << graph[i].index << newl; - ++neigh_count; - } - } - - if(!neigh_count) { - bool b; - boost::tie(edge,b) = boost::add_edge(root_node,i,graph); - if(!b) - utility::log("") << "Error adding Edge- " << graph[root_node].index << " --> " << graph[i].index << newl; - } - } - } - - void load_from_xml(const std::string& file_name, const std::string& eq_to_read); - - -}; - - -template -struct Node_cost_comparatorR { - typedef typename TaskSystem::Graph GraphType; - typedef typename TaskSystem::Node NodeType; - - const GraphType& graph; - Node_cost_comparatorR(const GraphType& g) : graph(g) {} - - bool operator() (const NodeType& lhs, const NodeType& rhs) { - double lhs_cost = graph[lhs].cost; - double rhs_cost = graph[rhs].cost; - if(lhs_cost == rhs_cost) { - int lhs_degree = out_degree(lhs, graph); - int rhs_degree = out_degree(rhs, graph); - // if(lhs_degree == rhs_degree) { - - // } - return lhs_degree > rhs_degree; - } - return lhs_cost > rhs_cost; - } -}; - - - - - -} // openmodelica -} // parmodelica - - -#include "pm_task_system.inl" -#include "pm_cluster_system.hpp" -#include "pm_load_xml.inl" - - - -#endif // header +#pragma once +#ifndef idC32CC0E3_D0E1_479D_85BC0769EFD475C0 +#define idC32CC0E3_D0E1_479D_85BC0769EFD475C0 + +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Linköping University, + * Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 + * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S + * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from Linköping University, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS + * OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ + +/* + Mahder.Gebremedhin@liu.se 2020-10-12 +*/ + +#include + +#include +#include + +#include "pm_utility.hpp" + +namespace openmodelica { namespace parmodelica { + +struct TaskNode { + TaskNode() : level(0), cost(0){}; + + long task_id; + int level; + double cost; + + virtual bool depends_on(const TaskNode&) const = 0; +}; + +template +class TaskSystem : boost::noncopyable { + std::string model_name; + + public: + typedef TaskTypeT TaskType; + typedef typename boost::adjacency_list Graph; + typedef typename Graph::vertex_descriptor Node; // rename me to NodeType + typedef typename Graph::vertices_size_type vertices_size_type; + typedef typename boost::graph_traits::vertex_iterator vertex_iterator; + + typedef typename Graph::edge_descriptor Edge; + + Graph graph; + Node root_node; + double total_cost; + long node_count; + + TaskSystem() : total_cost(0) { + root_node = boost::add_vertex(graph); + graph[root_node].node_id = -1; + node_count = 0; + } + + TaskType& add_node() { + Node node = boost::add_vertex(graph); + graph[node].node_id = node_count; + ++node_count; + + return graph[node]; + } + + void construct_graph() { + Edge edge; + + std::pair vp_out = boost::vertices(graph); + for (unsigned i = 1; i != *vp_out.second; ++i) { + int neigh_count = 0; + for (unsigned j = i - 1; j > 0; --j) { + bool found_dep = graph[i].depends_on(graph[j]); + if (found_dep) { + bool b; + boost::tie(edge, b) = boost::add_edge(j, i, graph); + if (!b) + utility::log("") << "Error adding Edge- " << graph[j].index << " --> " << graph[i].index + << newl; + ++neigh_count; + } + } + + if (!neigh_count) { + bool b; + boost::tie(edge, b) = boost::add_edge(root_node, i, graph); + if (!b) + utility::log("") << "Error adding Edge- " << graph[root_node].index << " --> " << graph[i].index + << newl; + } + } + } + + void load_from_xml(const std::string& file_name, const std::string& eq_to_read); +}; + +template +struct Node_cost_comparatorR { + typedef typename TaskSystem::Graph GraphType; + typedef typename TaskSystem::Node NodeType; + + const GraphType& graph; + Node_cost_comparatorR(const GraphType& g) : graph(g) {} + + bool operator()(const NodeType& lhs, const NodeType& rhs) { + double lhs_cost = graph[lhs].cost; + double rhs_cost = graph[rhs].cost; + if (lhs_cost == rhs_cost) { + int lhs_degree = out_degree(lhs, graph); + int rhs_degree = out_degree(rhs, graph); + // if(lhs_degree == rhs_degree) { + + // } + return lhs_degree > rhs_degree; + } + return lhs_cost > rhs_cost; + } +}; + +}} // namespace openmodelica::parmodelica + +#include "pm_cluster_system.hpp" +#include "pm_load_xml.inl" +#include "pm_task_system.inl" + +#endif // header diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_task_system.inl b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_task_system.inl index 9a18246fce4..97248edf40f 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_task_system.inl +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_task_system.inl @@ -1,100 +1,89 @@ -/* - * This file is part of OpenModelica. - * - * Copyright (c) 1998-CurrentYear, Linköping University, - * Department of Computer and Information Science, - * SE-58183 Linköping, Sweden. - * - * All rights reserved. - * - * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 - * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). - * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S - * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. - * - * The OpenModelica software and the Open Source Modelica - * Consortium (OSMC) Public License (OSMC-PL) are obtained - * from Linköping University, either from the above address, - * from the URLs: http://www.ida.liu.se/projects/OpenModelica or - * http://www.openmodelica.org, and in the OpenModelica distribution. - * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. - * - * This program is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH - * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS - * OF OSMC-PL. - * - * See the full OSMC Public License conditions for more details. - * - */ - - -/* - Mahder.Gebremedhin@liu.se 2014-02-10 -*/ - - - -#include - - -namespace openmodelica { -namespace parmodelica { - - -// template -// TaskSystem::TaskSystem() : - // total_cost(0) -// { - // root_node = boost::add_vertex(graph); - // graph[root_node].node_id = -1; - // node_count = 0; -// } - - -// template -// typename TaskSystem::TaskType& -// TaskSystem::add_node() { - // Node node = boost::add_vertex(graph); - // graph[node].node_id = node_count; - // ++node_count; - - // return graph[node]; -// } - - - -// template -// void -// TaskSystem::construct_graph() { - - // Edge edge; - - // std::pair vp_out = boost::vertices(graph); - // for (unsigned i = 1; i != *vp_out.second; ++i) { - // int neigh_count = 0; - // for (unsigned j = i - 1; j > 0; --j) { - // bool found_dep = graph[i].depends_on(graph[j]); - // if(found_dep) { - // bool b; - // boost::tie(edge,b) = boost::add_edge(j,i,graph); - // if(!b) - // utility::log() << "Error adding Edge- " << graph[j].index << " --> " << graph[i].index << newl; - // ++neigh_count; - // } - // } - - // if(!neigh_count) { - // bool b; - // boost::tie(edge,b) = boost::add_edge(root_node,i,graph); - // if(!b) - // utility::log() << "Error adding Edge- " << graph[root_node].index << " --> " << graph[i].index << newl; - // } - // } - -// } - - -} // parmodelica -} // openmodelica \ No newline at end of file +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Linköping University, + * Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 + * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S + * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from Linköping University, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS + * OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ + +/* + Mahder.Gebremedhin@liu.se 2020-10-12 +*/ + +#include + +namespace openmodelica { namespace parmodelica { + +// template +// TaskSystem::TaskSystem() : +// total_cost(0) +// { +// root_node = boost::add_vertex(graph); +// graph[root_node].node_id = -1; +// node_count = 0; +// } + +// template +// typename TaskSystem::TaskType& +// TaskSystem::add_node() { +// Node node = boost::add_vertex(graph); +// graph[node].node_id = node_count; +// ++node_count; + +// return graph[node]; +// } + +// template +// void +// TaskSystem::construct_graph() { + +// Edge edge; + +// std::pair vp_out = boost::vertices(graph); +// for (unsigned i = 1; i != *vp_out.second; ++i) { +// int neigh_count = 0; +// for (unsigned j = i - 1; j > 0; --j) { +// bool found_dep = graph[i].depends_on(graph[j]); +// if(found_dep) { +// bool b; +// boost::tie(edge,b) = boost::add_edge(j,i,graph); +// if(!b) +// utility::log() << "Error adding Edge- " << graph[j].index << " --> " << graph[i].index << newl; +// ++neigh_count; +// } +// } + +// if(!neigh_count) { +// bool b; +// boost::tie(edge,b) = boost::add_edge(root_node,i,graph); +// if(!b) +// utility::log() << "Error adding Edge- " << graph[root_node].index << " --> " << graph[i].index << newl; +// } +// } + +// } + +}} // namespace openmodelica::parmodelica diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_timer.hpp b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_timer.hpp index 938f804bd31..a7a88158474 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_timer.hpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_timer.hpp @@ -33,17 +33,15 @@ * */ - /* - Mahder.Gebremedhin@liu.se 2014-02-10 + Mahder.Gebremedhin@liu.se 2020-10-12 */ #ifdef _WIN32 // OS #include -namespace openmodelica { -namespace parmodelica { +namespace openmodelica { namespace parmodelica { struct PMStopWatch { LARGE_INTEGER start; @@ -52,51 +50,45 @@ struct PMStopWatch { class PMTimer { -private: - PMStopWatch timer; + private: + PMStopWatch timer; LARGE_INTEGER total_time; LARGE_INTEGER frequency; - double LI_to_secs(LARGE_INTEGER &LI) ; -public: + double LI_to_milli_secs(LARGE_INTEGER& LI); + + public: PMTimer(); - void start_timer(); - void stop_timer(); - void reset_timer(); + void start_timer(); + void stop_timer(); + void reset_timer(); double get_elapsed_time(); }; - -} // parmodelica -} // openmodelica +}} // namespace openmodelica::parmodelica #else // if not _WIN32 - #define BOOST_CHRONO_HEADER_ONLY #include - -namespace openmodelica { -namespace parmodelica { +namespace openmodelica { namespace parmodelica { class PMTimer { -private: - boost::chrono::system_clock::duration total_time; + private: + boost::chrono::system_clock::duration total_time; boost::chrono::system_clock::time_point started_at; -public: + + public: PMTimer(); - void start_timer(); - void stop_timer(); - void reset_timer(); + void start_timer(); + void stop_timer(); + void reset_timer(); double get_elapsed_time(); }; -} // parmodelica -} // openmodelica +}} // namespace openmodelica::parmodelica #endif // OS - - #endif // header diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_utility.cpp b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_utility.cpp index 6e09ae4c34d..142948db638 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_utility.cpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_utility.cpp @@ -29,18 +29,13 @@ * */ - /* - Mahder.Gebremedhin@liu.se 2014-02-10 + Mahder.Gebremedhin@liu.se 2020-10-12 */ #include "pm_utility.hpp" - -namespace openmodelica { -namespace parmodelica { - -namespace utility { +namespace openmodelica { namespace parmodelica { namespace utility { std::ostringstream log_stream; std::ostringstream warning_stream; @@ -52,7 +47,13 @@ std::ostream& log(const char* pref = "") { } std::ostream& log() { - return log_stream; + return std::cout; +} + +void indexed_dlog(int index, const std::string& message) { +#ifdef OM_PM_LOG_VERBOSE + std::cerr << "INFO: " << std::to_string(index) << " : " << message << std::endl; +#endif } std::ostream& warning(const char* pref = "") { @@ -75,10 +76,13 @@ std::ostream& error() { return std::cerr; } +void eq_index_error(int index, const std::string& message) { + std::cerr << std::to_string(index) << " : " << message << std::endl; +} -} // utility -} // parmodelica -} // openmodelica - - +void eq_index_fatal(int index, const std::string& message) { + utility::eq_index_error(index, message); + exit(1); +} +}}} // namespace openmodelica::parmodelica::utility diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_utility.hpp b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_utility.hpp index dabc1a99c1e..0bae71da23d 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_utility.hpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_utility.hpp @@ -1,181 +1,161 @@ -#pragma once -#ifndef id8073C0EB_D490_45E7_9F4AE20BF9C28736 -#define id8073C0EB_D490_45E7_9F4AE20BF9C28736 - -/* - * This file is part of OpenModelica. - * - * Copyright (c) 1998-CurrentYear, Linköping University, - * Department of Computer and Information Science, - * SE-58183 Linköping, Sweden. - * - * All rights reserved. - * - * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 - * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). - * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S - * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. - * - * The OpenModelica software and the Open Source Modelica - * Consortium (OSMC) Public License (OSMC-PL) are obtained - * from Linköping University, either from the above address, - * from the URLs: http://www.ida.liu.se/projects/OpenModelica or - * http://www.openmodelica.org, and in the OpenModelica distribution. - * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. - * - * This program is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH - * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS - * OF OSMC-PL. - * - * See the full OSMC Public License conditions for more details. - * - */ - - -/* - Mahder.Gebremedhin@liu.se 2014-02-10 -*/ - - -#include -#include -#include -#include -#include - - -#ifdef _MSC_VER -#define NOMINMAX -#endif - -#define newl "\n" - - -namespace openmodelica { -namespace parmodelica { - -namespace utility { - - -extern std::ostringstream log_stream; -std::ostream& log(const char* pref); -std::ostream& log(); - -extern std::ostringstream warning_stream; -std::ostream& warning(const char* pref); -std::ostream& warning(); - - -extern std::ostringstream error_stream; -std::ostream& error(const char* pref); -std::ostream& error(); - - - -template -bool -has_intersection(InputIterator1 first1, InputIterator1 last1, - InputIterator2 first2, InputIterator2 last2) -{ - for(; first1 != last1; ++first1) { - std::set::iterator loc = std::find(first2, last2, (*first1)); - if(loc != last2) { - return true; - } - } - - return false; -} - -/* Slow. Use has_intersection instead. */ -template -bool -set_find_anyof(const SetType& InSet1, const SetType& InSet2) { - - for(typename SetType::const_iterator iter = InSet1.begin(); iter != InSet1.end(); ++iter) { - typename SetType::const_iterator loc = std::find(InSet2.begin(), InSet2.end(), (*iter)); - if(loc != InSet2.end()) { - return true; - } - } - - return false; - -} - - - - -template -class pm_vector { -protected: - std::vector int_vector; - -public: - pm_vector() { }; - pm_vector(int i, T p) : int_vector(i, p) { }; - - typedef typename std::vector::value_type value_type; - - typedef typename std::vector::iterator iterator; - typedef typename std::vector::const_iterator const_iterator; - - typedef typename std::vector::reference reference; - typedef typename std::vector::const_reference const_reference; - - typedef typename std::vector::size_type size_type; - - std::vector& get_vector() { return int_vector; }; - - size_type size() const { return int_vector.size(); } - size_type capacity() const { return int_vector.capacity(); } - bool empty() const { return int_vector.empty(); } - - void resize (size_type n, value_type val = value_type()) { int_vector.resize(n,val); } - - iterator begin() { return int_vector.begin(); } - const_iterator begin() const { return int_vector.begin(); } - - iterator end() { return int_vector.end(); } - const_iterator end() const { return int_vector.end(); } - - void push_back(const_reference p) { int_vector.push_back(p); }; - void push_front(const_reference p) { int_vector.push_front(p); }; - - reference back() { return int_vector.back(); } - const_reference back() const { return int_vector.back(); } - - reference front() { return int_vector.front(); } - const_reference front() const { return int_vector.front(); } - - - template - void insert(iterator pos, InputIterator first, InputIterator last) - { return int_vector.insert(pos, first, last); } - - iterator insert(iterator pos, const T& val) { return int_vector.insert(pos,val); } - iterator erase(iterator pos) { return int_vector.erase(pos); } - - void clear() { int_vector.clear(); } - - reference operator[](const size_type index) { return int_vector[index]; } - const_reference operator[](const size_type index) const { return int_vector[index]; } - - reference at(const size_type index) { return int_vector[index]; } - const_reference at(const size_type index) const { return int_vector[index]; } - -}; - - - - - -} // utility -} // parmodelica -} // openmodelica - - - -#endif // header \ No newline at end of file +#pragma once +#ifndef id8073C0EB_D490_45E7_9F4AE20BF9C28736 +#define id8073C0EB_D490_45E7_9F4AE20BF9C28736 + +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-CurrentYear, Linköping University, + * Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 + * AND THIS OSMC PUBLIC LICENSE (OSMC-PL). + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S + * ACCEPTANCE OF THE OSMC PUBLIC LICENSE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from Linköping University, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS + * OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ + +/* + Mahder.Gebremedhin@liu.se 2020-10-12 +*/ + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#define NOMINMAX +#endif + +namespace openmodelica { namespace parmodelica { namespace utility { + +extern std::ostringstream log_stream; +std::ostream& log(const char* pref); +std::ostream& log(); + +extern std::ostringstream warning_stream; +std::ostream& warning(const char* pref); +std::ostream& warning(); + +extern std::ostringstream error_stream; +std::ostream& error(const char* pref); +std::ostream& error(); + +// debug only log +void indexed_dlog(int index, const std::string& message); +void eq_index_error(int index, const std::string& message); +void eq_index_fatal(int index, const std::string& message); + +template +bool has_intersection(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2) { + for (; first1 != last1; ++first1) { + std::set::iterator loc = std::find(first2, last2, (*first1)); + if (loc != last2) { + return true; + } + } + + return false; +} + +/* Slow. Use has_intersection instead. */ +template +bool set_find_anyof(const SetType& InSet1, const SetType& InSet2) { + + for (typename SetType::const_iterator iter = InSet1.begin(); iter != InSet1.end(); ++iter) { + typename SetType::const_iterator loc = std::find(InSet2.begin(), InSet2.end(), (*iter)); + if (loc != InSet2.end()) { + return true; + } + } + + return false; +} + +template +class pm_vector { + protected: + std::vector int_vector; + + public: + pm_vector(){}; + pm_vector(int i, T p) : int_vector(i, p){}; + + typedef typename std::vector::value_type value_type; + typedef typename std::vector::iterator iterator; + typedef typename std::vector::const_iterator const_iterator; + typedef typename std::vector::reverse_iterator reverse_iterator; + typedef typename std::vector::const_reverse_iterator const_reverse_iterator; + typedef typename std::vector::reference reference; + typedef typename std::vector::const_reference const_reference; + typedef typename std::vector::size_type size_type; + + std::vector& get_vector() { return int_vector; }; + + size_type size() const { return int_vector.size(); } + size_type capacity() const { return int_vector.capacity(); } + bool empty() const { return int_vector.empty(); } + + void resize(size_type n, value_type val = value_type()) { int_vector.resize(n, val); } + + iterator begin() { return int_vector.begin(); } + const_iterator begin() const { return int_vector.begin(); } + + iterator end() { return int_vector.end(); } + const_iterator end() const { return int_vector.end(); } + + reverse_iterator rbegin() { return int_vector.rbegin(); } + const_reverse_iterator rbegin() const { return int_vector.rbegin(); } + + reverse_iterator rend() { return int_vector.rend(); } + const_reverse_iterator rend() const { return int_vector.rend(); } + + void push_back(const_reference p) { int_vector.push_back(p); }; + void push_front(const_reference p) { int_vector.push_front(p); }; + + reference back() { return int_vector.back(); } + const_reference back() const { return int_vector.back(); } + + reference front() { return int_vector.front(); } + const_reference front() const { return int_vector.front(); } + + template + void insert(iterator pos, InputIterator first, InputIterator last) { + return int_vector.insert(pos, first, last); + } + + iterator insert(iterator pos, const T& val) { return int_vector.insert(pos, val); } + iterator erase(iterator pos) { return int_vector.erase(pos); } + + void clear() { int_vector.clear(); } + + reference operator[](const size_type index) { return int_vector[index]; } + const_reference operator[](const size_type index) const { return int_vector[index]; } + + reference at(const size_type index) { return int_vector[index]; } + const_reference at(const size_type index) const { return int_vector[index]; } +}; + +}}} // namespace openmodelica::parmodelica::utility + +#endif // header diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_win_timer.cpp b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_win_timer.cpp index df60ce745eb..56649ce5730 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/pm_win_timer.cpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/pm_win_timer.cpp @@ -30,49 +30,42 @@ * */ - /* - Mahder.Gebremedhin@liu.se 2014-02-10 + Mahder.Gebremedhin@liu.se 2020-10-12 */ - #include "pm_timer.hpp" +namespace openmodelica { namespace parmodelica { -namespace openmodelica { -namespace parmodelica { - - -double PMTimer::LI_to_secs(LARGE_INTEGER &LI) { - return ((double)LI.QuadPart /(double)frequency.QuadPart) ; - } +double PMTimer::LI_to_milli_secs(LARGE_INTEGER& LI) { + return (((double)LI.QuadPart * 1000) / (double)frequency.QuadPart); +} -PMTimer::PMTimer(){ - timer.start.QuadPart=0; - timer.stop.QuadPart=0; +PMTimer::PMTimer() { + timer.start.QuadPart = 0; + timer.stop.QuadPart = 0; total_time.QuadPart = 0; QueryPerformanceFrequency(&frequency); } -void PMTimer::start_timer(){ - QueryPerformanceCounter(&timer.start) ; +void PMTimer::start_timer() { + QueryPerformanceCounter(&timer.start); } -void PMTimer::stop_timer(){ - QueryPerformanceCounter(&timer.stop) ; +void PMTimer::stop_timer() { + QueryPerformanceCounter(&timer.stop); total_time.QuadPart += (timer.stop.QuadPart - timer.start.QuadPart); } -void PMTimer::reset_timer(){ - timer.start.QuadPart=0; - timer.stop.QuadPart=0; +void PMTimer::reset_timer() { + timer.start.QuadPart = 0; + timer.stop.QuadPart = 0; total_time.QuadPart = 0; } -double PMTimer::get_elapsed_time(){ - return LI_to_secs(total_time) ; +double PMTimer::get_elapsed_time() { + return LI_to_milli_secs(total_time); } -} // parmodelica -} // openmodelica - +}} // namespace openmodelica::parmodelica diff --git a/OMCompiler/SimulationRuntime/ParModelica/auto/test_task_graph.cpp b/OMCompiler/SimulationRuntime/ParModelica/auto/test_task_graph.cpp index c1c85d2c32e..638b9cef3ae 100644 --- a/OMCompiler/SimulationRuntime/ParModelica/auto/test_task_graph.cpp +++ b/OMCompiler/SimulationRuntime/ParModelica/auto/test_task_graph.cpp @@ -29,26 +29,20 @@ * */ - /* - Mahder.Gebremedhin@liu.se 2014-02-10 + Mahder.Gebremedhin@liu.se 2020-10-12 */ - - - // #include // #include #include "om_pm_model.hpp" // #include -#include "pm_cluster_system.hpp" #include "pm_cluster_level_scheduler.hpp" - +#include "pm_cluster_system.hpp" using namespace openmodelica::parmodelica; - int main(int argc, char** argv) { // typedef LevelSchedulerThreadAware LevelScheduler; @@ -57,7 +51,7 @@ int main(int argc, char** argv) { std::cout << "Reading file: " << xml_file << std::endl; std::string eq_to_read; - if(argc == 3) { + if (argc == 3) { eq_to_read = argv[2]; std::cout << "Reading eqs: " << eq_to_read << std::endl; } @@ -72,7 +66,6 @@ int main(int argc, char** argv) { // task_system.cluster_merge_level_for_cost(); // task_system.cluster_merge_level_parents(); - StepLevels level_scheduler(task_system); level_scheduler.schedule(); // level_scheduler.execute(NULL, NULL); @@ -94,10 +87,7 @@ int main(int argc, char** argv) { // std::cout << "scheduler cost = " << level_scheduler.total_parallel_cost << std::endl; // std::cout << "Peak speedup = " << task_system.total_cost/level_scheduler.total_parallel_cost << std::endl; - // DynamicScheduler dyn_scheduler(task_system); // dyn_scheduler.schedule(4); // dyn_scheduler.execute(); - - } \ No newline at end of file diff --git a/OMCompiler/configure.ac b/OMCompiler/configure.ac index 254b13704b9..5a49d0a79d9 100644 --- a/OMCompiler/configure.ac +++ b/OMCompiler/configure.ac @@ -98,6 +98,9 @@ AC_SUBST(CPP_RUNTIME_ARGS) AC_SUBST(OMENCRYPTION) AC_SUBST(MINGW_EXTRA_LIBS) AC_SUBST(BSTATIC) +AC_SUBST(OMC_TBB_ROOT) +AC_SUBST(ENABLE_PARMODAUTO) + FINAL_MESSAGES="\nConfigured OpenModelica successfully using the following options:" @@ -907,6 +910,30 @@ AC_ARG_WITH(ENCRYPTION, [ --with-ENCRYPTION Compile SEMLA and l OMENCRYPTION=no ]) + +AC_ARG_ENABLE([parmodauto], + AS_HELP_STRING([--enable-parmodauto], [Enable support for automatic parallelization of simulations with parmodauto])) + +AS_IF([test "x$enable_parmodauto" = "xyes"], [ + AC_MSG_NOTICE([parmodauto support is requested]) + AC_MSG_NOTICE([Checking if omc version of tbb exists]) + + OMC_TBB_ROOT="$ac_pwd/3rdParty/tbb_omc" + AC_CHECK_FILE($OMC_TBB_ROOT, [] + , [AC_MSG_ERROR([parmodauto support (--enable-parmodauto) was requested but TBB library not found in $OMC_TBB_ROOT directory.]) + ]) + + AC_MSG_NOTICE([Configuring omc_tbb]) + # This would have been the best way but the flags are not consistent. + # cmake -S $OMC_TBB_ROOT -B $OMC_TBB_ROOT/build_cmake CFLAGS=$CFLAGS CXXFLAGS=$CXXFLAGS + cmake -S $OMC_TBB_ROOT -B $OMC_TBB_ROOT/build_cmake -DOM_HOST_SHORT=$host_short -DOM_BUILD_DIR=$OMBUILDDIR + AC_MSG_NOTICE([omc_tbb has been configured]) + + ENABLE_PARMODAUTO="yes" + AC_MSG_NOTICE(parmodauto enabled... [$ENABLE_PARMODAUTO]) +]) + + m4_include([common/m4/semver.m4]) SOURCE_REVISION="$SOURCE_REVISION$NON_FREE_VERSION" diff --git a/testsuite/openmodelica/bootstrapping/LoadCompilerSources.mos b/testsuite/openmodelica/bootstrapping/LoadCompilerSources.mos index a1ac9040b7c..a86d1cce722 100644 --- a/testsuite/openmodelica/bootstrapping/LoadCompilerSources.mos +++ b/testsuite/openmodelica/bootstrapping/LoadCompilerSources.mos @@ -202,7 +202,6 @@ if true then /* Suppress output */ prefixPath + "Template/NFInstDumpTpl.mo", prefixPath + "Template/SCodeDumpTpl.mo", prefixPath + "Template/SimCodeDump.mo", - prefixPath + "Template/TaskSystemDump.mo", prefixPath + "Template/Tpl.mo", prefixPath + "Template/TplAbsyn.mo", prefixPath + "Template/TplCodegen.mo", diff --git a/testsuite/special/MatlabTranslator/LoadCompilerSources.mos b/testsuite/special/MatlabTranslator/LoadCompilerSources.mos index 80e480eb697..d19943a9160 100644 --- a/testsuite/special/MatlabTranslator/LoadCompilerSources.mos +++ b/testsuite/special/MatlabTranslator/LoadCompilerSources.mos @@ -201,7 +201,6 @@ if true then /* Suppress output */ prefixPath + "Template/GraphMLDumpTpl.mo", prefixPath + "Template/NFInstDumpTpl.mo", prefixPath + "Template/SCodeDumpTpl.mo", - prefixPath + "Template/TaskSystemDump.mo", prefixPath + "Template/SimCodeDump.mo", prefixPath + "Template/TplAbsyn.mo", prefixPath + "Template/TplCodegen.mo",