Salome HOME
[EDF28974] : Move to python implementation of driver and integrate monitoring into... emc2p_2.0.0-b1
authorAnthony Geay <anthony.geay@edf.fr>
Thu, 22 Feb 2024 10:40:12 +0000 (11:40 +0100)
committerAnthony Geay <anthony.geay@edf.fr>
Thu, 7 Mar 2024 10:38:44 +0000 (11:38 +0100)
18 files changed:
SalomeYACSConfig.cmake.in
src/engine/Node.cxx
src/engine/Node.hxx
src/runtime/RuntimeSALOME.cxx
src/runtime/RuntimeSALOME.hxx
src/runtime/SalomeContainerHelper.cxx
src/runtime/VisitorSalomeSaveState.cxx
src/runtime/VisitorSalomeSaveState.hxx
src/runtime/VisitorSaveSalomeSchema.cxx
src/runtime/VisitorSaveSalomeSchema.hxx
src/runtime_swig/CMakeLists.txt
src/runtime_swig/SALOMERuntime.i
src/runtime_swig/ThreadLauncher.cxx [new file with mode: 0644]
src/runtime_swig/ThreadLauncher.hxx [new file with mode: 0644]
src/yacsloader/CMakeLists.txt
src/yacsloader/driver [new file with mode: 0644]
src/yacsloader/driver_internal.py [new file with mode: 0644]
src/yacsloader_swig/loader.i

index 292a50390fefaa7ad428cc9b80e4419909c9574a..c6dcd8cf4e8b1fb83f663e571b299267d9f756b1 100644 (file)
@@ -150,6 +150,7 @@ SET(YACS_YACSloader YACSloader)
 SET(YACS_YACSBases YACSBases)
 SET(YACS_YACSlibEngine YACSlibEngine)
 SET(YACS_YACSRuntimeSALOME YACSRuntimeSALOME)
+SET(YACS_YACSRuntimePython YACSRuntimePython)
 SET(YACS_YACSevalYFX YACSevalYFX)
 SET(YACS_YACSDLTest YACSDLTest)
 SET(YACS_SalomeIDLYACS SalomeIDLYACS)
index 18309aa9a9ad41b7b7dc5eb4518e87e45a9c4adb..b2e41304dbad4c9e6beef515195c04789f794d3e 100644 (file)
@@ -27,6 +27,7 @@
 #include "InputDataStreamPort.hxx"
 #include "OutputDataStreamPort.hxx"
 #include <iostream>
+#include <fstream>
 
 //#define _DEVDEBUG_
 #include "YacsTrace.hxx"
@@ -616,6 +617,12 @@ void Node::writeDot(std::ostream &os) const
   os << getQualifiedName() <<"\"];\n";
 }
 
+void Node::writeDotInFile(const std::string& fileName) const
+{
+  std::ofstream f(fileName);
+  this->writeDot(f);
+}
+
 //! same as Node::getName() in most cases, but differs for children of switch
 /*!
  *  used by writeDot to distinguish children of switch, by adding a prefix to the name.
index 9955cb13e6285481cc73512bda1968abc8d26f6f..1e045a94bb3a829ea20507805d3be5696397a2c8 100644 (file)
@@ -129,6 +129,7 @@ namespace YACS
       bool exIsControlReady() const;
       std::list<Node *> getOutNodes() const;
       virtual void writeDot(std::ostream &os) const;
+      void writeDotInFile(const std::string& fileName) const;
       virtual void exUpdateState();
       virtual void exFailedState();
       virtual void exDisabledState();
index 20d20215073b790f601a4fcf2978bbbe86cec03a..c8ea03c2877a216b2e182dd17b8ef58a16a240a9 100644 (file)
@@ -420,7 +420,7 @@ void RuntimeSALOME::init(long flags, int argc, char* argv[])
     }
 }
 
-void RuntimeSALOME::fini()
+void RuntimeSALOME::fini(bool isFinalizingPython)
 {
   if (_usePython)
     {
@@ -449,8 +449,9 @@ void RuntimeSALOME::fini()
       nodeMap.erase("PyFunction");
       nodeMap.erase("PyScript");
       nodeMap.erase("SalomePythonNode");
-
-      Py_Finalize();
+      
+      if( isFinalizingPython )
+        Py_Finalize();
 #ifdef REFCNT
       DEBTRACE("_orb refCount: " << ((omniOrbORB*)_orb.in())->pd_refCount);
 #endif
index 4cbbc12c315cf74213717183184d4be213fe8851..a9c32672358d462dba309556af6b9abbe2a56cb8 100644 (file)
@@ -83,7 +83,7 @@ namespace YACS
       virtual std::string getVersion() const;
 
       virtual void init(long flags, int argc, char* argv[]);
-      virtual void fini();
+      virtual void fini(bool isFinalizingPython = true);
       PyObject *launchSubProcess(const std::vector<std::string>& cmds);
       virtual std::vector< std::pair<std::string,int> > getCatalogOfComputeNodes() const;
       virtual InputPort* createInputPort(const std::string& name,
index 4a6e9f4a202f7476615b0de754db6a4046838b3b..56c33016cbf3c20060978e6c28d8902d9f1bb707 100644 (file)
@@ -20,7 +20,8 @@
 #include "SalomeContainerHelper.hxx"
 
 #include "ServiceNode.hxx"
-#include "YacsTrace.hxx"
+
+#include "utilities.h"
 
 #include <sstream>
 #include <iostream>
@@ -92,15 +93,13 @@ void SalomeContainerMonoHelper::shutdown()
     return ;
   try
   {
-      DEBTRACE("shutdown SALOME container: " );
       CORBA::String_var containerName=_trueCont->name();
-      DEBTRACE(containerName);
+      INFO_MESSAGE("shutdown SALOME container: " << containerName);
       _trueCont->Shutdown();
-      std::cerr << "shutdown SALOME container: " << containerName << std::endl;
   }
   catch(...)
   {
-      DEBTRACE("Unknown exception ignored." );
+      ERROR_MESSAGE("Unknown exception ignored." );
   }
   _trueCont=Engines::Container::_nil();
 }
@@ -201,19 +200,17 @@ void SalomeContainerMultiHelper::shutdown()
   {
     try
     {
-        DEBTRACE("shutdown SALOME container: " );
         CORBA::String_var containerName=it->second->name();
-        DEBTRACE(containerName);
+        INFO_MESSAGE("shutdown SALOME container: " << containerName);
         it->second->Shutdown();
-        std::cerr << "shutdown SALOME container: " << containerName << std::endl;
     }
     catch(CORBA::Exception&)
     {
-        DEBTRACE("Unexpected CORBA failure detected." );
+        ERROR_MESSAGE("Unexpected CORBA failure detected." );
     }
     catch(...)
     {
-        DEBTRACE("Unknown exception ignored." );
+        ERROR_MESSAGE("Unknown exception ignored." );
     }
   }
   _containersForTasks.clear();
@@ -222,19 +219,18 @@ void SalomeContainerMultiHelper::shutdown()
     {
       try
       {
-          DEBTRACE("shutdown SALOME container: " );
           CORBA::String_var containerName=it->second->name();
-          DEBTRACE(containerName);
+          INFO_MESSAGE("shutdown SALOME container: " << containerName);
           it->second->Shutdown();
           std::cerr << "shutdown SALOME container: " << containerName << std::endl;
       }
       catch(CORBA::Exception&)
       {
-          DEBTRACE("Unexpected CORBA failure detected." );
+          ERROR_MESSAGE("Unexpected CORBA failure detected." );
       }
       catch(...)
       {
-          DEBTRACE("Unknown exception ignored." );
+          ERROR_MESSAGE("Unknown exception ignored." );
       }
     }
   _containersForComponents.clear();
index 187f7f680c02ba1ecf4d1040f233f417d54fa4c8..830a9c3abe59b464cdcfffb2eff79e40cd895320 100644 (file)
@@ -116,6 +116,11 @@ void YACS::ENGINE::schemaSaveState(Proc* proc,
                                   const std::string& xmlSchemaFile)
 {
   YACS::BASES::AutoLocker<YACS::BASES::Mutex> alck(&(exec->getTheMutexForSchedulerUpdate()));
+  schemaSaveStateUnsafe(proc,xmlSchemaFile);
+}
+
+void YACS::ENGINE::schemaSaveStateUnsafe(Proc* proc, const std::string& xmlSchemaFile)
+{
   VisitorSalomeSaveState vss(proc);
   vss.openFileDump(xmlSchemaFile);
   proc->accept(&vss);
index 3136955142325dc653c71502574a04b4626d551f..4c3a8e4302d370910ce5b4c815050977d9e616a0 100644 (file)
@@ -36,9 +36,10 @@ namespace YACS
       virtual void visitForEachLoop(ForEachLoop *node);
     };
 
-    YACSLIBENGINE_EXPORT void schemaSaveState(Proc* proc,
+    YACSRUNTIMESALOME_EXPORT void schemaSaveState(Proc* proc,
                                               Executor* exec,
                                               const std::string& xmlSchemaFile);
+    YACSRUNTIMESALOME_EXPORT void schemaSaveStateUnsafe(Proc* proc, const std::string& xmlSchemaFile);
   }
 }
 #endif // VISITORSALOMESAVESTATE_HXX
index 918539a6557ea1cf1d3099115dcf9c639569b959..b15638ce4470087893dbb16807fabb2833f080b2 100644 (file)
@@ -177,3 +177,11 @@ void VisitorSaveSalomeSchema::writeStudyOutNodeParameters(DataNode *node)
       _out << inp->getData() << "\"/>" << endl;
     }
 }
+
+void YACS::ENGINE::VisitorSaveSalomeSchemaUnsafe(ComposedNode* proc, const std::string& xmlSchema)
+{
+  VisitorSaveSalomeSchema vss(proc);
+  vss.openFileSchema(xmlSchema);
+  proc->accept(&vss);
+  vss.closeFileSchema();
+}
index c8e3b047bcce4916496b7084b4dc7847e1710bb8..3d817ff2e6a285e4bf51eeb0162ef0b27700bfc8 100644 (file)
@@ -42,6 +42,8 @@ namespace YACS
       virtual void writeOutNodeParameters(DataNode *node);
       virtual void writeStudyOutNodeParameters(DataNode *node);
     };
+
+    YACSRUNTIMESALOME_EXPORT void VisitorSaveSalomeSchemaUnsafe(ComposedNode* proc, const std::string& xmlSchema);
   }
 }
 
index d5033b31f989283c998962775bdd43703ae3ce4f..1b0316b2ba2ec051df27168dd4140e63dba8be1d 100644 (file)
@@ -27,6 +27,7 @@ ENDIF(SALOME_YACS_USE_KERNEL)
 
 # additional include directories
 INCLUDE_DIRECTORIES(
+  ${CMAKE_CURRENT_SOURCE_DIR}
   ${SALOME_INCL_PATH}
   ${PTHREAD_INCLUDE_DIRS}
   ${OMNIORB_INCLUDE_DIR}
@@ -55,9 +56,13 @@ ADD_DEFINITIONS(
   ${OMNIORB_DEFINITIONS}
   )
 
+ADD_LIBRARY(YACSRuntimePython ThreadLauncher.cxx)
+INSTALL(TARGETS YACSRuntimePython EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${SALOME_INSTALL_LIBS})
+
 # libraries to link to
 SET(_link_LIBRARIES
   YACSRuntimeSALOME
+  YACSRuntimePython
   ${PYTHON_LIBRARIES}
   ${OMNIORB_LIBRARIES}
   )
index 40a200ad244b428f66c54499ffddeadbc3dd37e8..7e99d48278048d92ea91b2c73ca2d47c06b858d1 100644 (file)
@@ -67,6 +67,7 @@
 #include "ExecutorSwig.hxx"
 #include <sstream>
 #include "Catalog.hxx"
+#include "ThreadLauncher.hxx"
 %}
 
 // ----------------------------------------------------------------------------
@@ -161,6 +162,9 @@ namespace YACS
     void schemaSaveState(Proc* proc,
                          Executor* exec,
                          const std::string& xmlSchemaFile);
+    void schemaSaveStateUnsafe(Proc* proc, const std::string& xmlSchemaFile);
+    
+    void VisitorSaveSalomeSchemaUnsafe(Proc* proc, const std::string& xmlSchema);
   }
 }
 
@@ -247,3 +251,18 @@ namespace YACS
                                   pyobj);
   }
 }
+
+namespace YACS
+{
+  namespace ENGINE
+  {
+    class YACSLIBENGINE_EXPORT ThreadDumpState
+    {
+    public:
+      ThreadDumpState(Proc *proc, int nbSeconds, const std::string& dumpFile, const std::string& lockFile);
+      ~ThreadDumpState();
+      void start();
+      void join();
+    };
+  }
+}
diff --git a/src/runtime_swig/ThreadLauncher.cxx b/src/runtime_swig/ThreadLauncher.cxx
new file mode 100644 (file)
index 0000000..ff5b83c
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright (C) 2024  CEA, EDF
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "ThreadLauncher.hxx"
+#include "VisitorSalomeSaveState.hxx"
+
+#include "PythonCppUtils.hxx"
+
+#include "Basics_Utils.hxx"
+
+#include "Python.h"
+
+using namespace YACS::ENGINE;
+
+ThreadDumpState::~ThreadDumpState()
+{
+  join();
+}
+
+void ThreadDumpState::run()
+{
+  AutoGIL agil;
+  AutoPyYielder yld;
+  YACS::StatesForNode state = _proc->getEffectiveState();
+  while((state != YACS::DONE) && (state != YACS::LOADFAILED) && (state != YACS::EXECFAILED) && (state != YACS::INTERNALERR) && (state != YACS::DISABLED) && (state != YACS::FAILED) && (state != YACS::ERROR))
+  {
+#ifdef WIN32
+    Sleep(_nb_seconds);
+#else 
+    sleep(_nb_seconds);
+#endif
+    std::string cmd = "touch " + _lock_file;
+    system(cmd.c_str());
+    schemaSaveStateUnsafe(_proc,_dump_file);
+    cmd = "rm -f " + _lock_file;
+    system(cmd.c_str());
+    state = _proc->getEffectiveState();
+  }
+}
+
+void ThreadDumpState::start()
+{
+  _my_thread.reset( new std::thread([this]{
+    this->run();
+  }) );
+}
+
+void ThreadDumpState::join()
+{
+  if(_my_thread)
+  {
+    AutoGIL agil;
+    AutoPyYielder yld;
+    _my_thread->join();
+    _my_thread.reset( nullptr );
+  }
+}
diff --git a/src/runtime_swig/ThreadLauncher.hxx b/src/runtime_swig/ThreadLauncher.hxx
new file mode 100644 (file)
index 0000000..f96e004
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright (C) 2024  CEA, EDF
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#pragma once
+
+#include "YACSlibEngineExport.hxx"
+#include "Proc.hxx"
+
+#include <thread>
+#include <memory>
+#include <string>
+
+namespace YACS
+{
+  namespace ENGINE
+  {
+    class YACSLIBENGINE_EXPORT ThreadDumpState
+    {
+    public:
+      ThreadDumpState(Proc *proc, int nbSeconds, const std::string& dumpFile, const std::string& lockFile):
+        _proc(proc),_nb_seconds(nbSeconds),_dump_file(dumpFile),_lock_file(lockFile) { }
+      ~ThreadDumpState();
+      void run();
+      void start();
+      void join();
+    private:
+      std::unique_ptr< std::thread > _my_thread;
+      Proc *_proc;
+      int _nb_seconds = 0;
+      std::string _dump_file;
+      std::string _lock_file;
+    };
+  }
+}
index 3a8cb97e5cb29e1e0d71bece893bb22295378fb2..4bea1942c122b7d262d0333bce7308264c2ee1fd 100644 (file)
@@ -138,9 +138,7 @@ SET(YACSloader_SOURCES
   ProcCataLoader.cxx
   componentinstanceParsers.cxx
   )
-SET(driver_SOURCES
-  driver.cxx
-  )
+
 SET(resume_SOURCES
   resume.cxx
   )
@@ -161,21 +159,22 @@ ADD_LIBRARY(ExampleOfObserversPluginForDriver ${ExampleOfObserversPluginForDrive
 TARGET_LINK_LIBRARIES(ExampleOfObserversPluginForDriver ${_link_LIBRARIES})
 INSTALL(TARGETS ExampleOfObserversPluginForDriver DESTINATION ${SALOME_INSTALL_LIBS})
 
-ADD_EXECUTABLE(driver ${driver_SOURCES})
-TARGET_LINK_LIBRARIES(driver ${_link_LIBRARIES})
-
 ADD_EXECUTABLE(resume ${resume_SOURCES})
 TARGET_LINK_LIBRARIES(resume ${_link_LIBRARIES})
 
 ADD_EXECUTABLE(debugger ${debugger_SOURCES})
 TARGET_LINK_LIBRARIES(debugger ${_link_LIBRARIES})
 
-SET_TARGET_PROPERTIES(driver resume debugger PROPERTIES COMPILE_FLAGS ${_exec_DEFINITIONS})
+SET_TARGET_PROPERTIES(resume debugger PROPERTIES COMPILE_FLAGS ${_exec_DEFINITIONS})
 
-INSTALL(TARGETS driver resume debugger EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${SALOME_INSTALL_BINS})
+INSTALL(TARGETS resume debugger EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${SALOME_INSTALL_BINS})
 
 INSTALL(FILES ${YACSloader_HEADERS} DESTINATION ${SALOME_INSTALL_HEADERS})
 
+INSTALL(FILES driver_internal.py DESTINATION ${SALOME_INSTALL_PYTHON})
+
+INSTALL(FILES driver PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ DESTINATION ${SALOME_INSTALL_BINS})
+
 FILE(GLOB sample_files
   ${PROJECT_SOURCE_DIR}/src/yacsloader/samples/*.xml 
   ${PROJECT_SOURCE_DIR}/src/yacsloader/samples/*.pmml
diff --git a/src/yacsloader/driver b/src/yacsloader/driver
new file mode 100644 (file)
index 0000000..3b43126
--- /dev/null
@@ -0,0 +1,76 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# Copyright (C) 2024  CEA, EDF
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+import driver_internal
+import subprocess as sp
+import salome
+import SALOME_Embedded_NamingService_ClientPy
+import NamingService
+from SALOME_PyNode import FileDeleter,FileHolder
+
+import signal
+import os
+
+proc = None
+ior_file = None
+
+def handler(signum, frame):
+  global proc,ior_file
+  try:
+    ns = SALOME_Embedded_NamingService_ClientPy.SALOME_Embedded_NamingService_ClientPy( NamingService.NamingService.LoadIORInFile( ior_file.filename ) )
+    del ior_file
+    ior_file = None # to avoid raises in __main__ function
+    cm = ns.Resolve(salome.CM_NAME_IN_NS)
+    cm.ShutdownContainersNow()
+  except:
+    pass
+  os.kill( proc.pid, signal.SIGKILL )
+
+def generateCmdForInternal():
+  import sys
+  import tempfile
+  global ior_file
+  args, _ = driver_internal.parseArgs()
+  iorNS = args[ driver_internal.IORKeyInARGS ]
+  firstPart = ["python3",driver_internal.__file__] 
+  lastPart = [elt for elt in sys.argv[1:] if elt != ""]
+  middlePart = []
+  #
+  if not iorNS:
+    with tempfile.NamedTemporaryFile(prefix="ior_driver_",suffix=".ior") as f:
+      ior_file = FileDeleter( f.name )
+    middlePart = [ "{}={}".format( driver_internal.IOREntryInCMD, ior_file.filename) ]
+  else:
+    ior_file = FileHolder( iorNS )
+  print(100*"*")
+  print( firstPart + middlePart + lastPart )
+  return firstPart + middlePart + lastPart
+
+if __name__ == "__main__":
+  signal.signal(signal.SIGINT, handler)
+  signal.signal(signal.SIGTERM, handler)
+  cmd = generateCmdForInternal()
+  proc = sp.Popen( cmd )
+  proc.communicate()
+  del ior_file
+  code = proc.returncode
+  if code != 0:
+    raise RuntimeError(f"Subprocess finished with a non zero status ({code}). Command returning non zero status was : {cmd}")
diff --git a/src/yacsloader/driver_internal.py b/src/yacsloader/driver_internal.py
new file mode 100644 (file)
index 0000000..1c48c9f
--- /dev/null
@@ -0,0 +1,412 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 2024  CEA, EDF
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+import salome
+import logging
+
+DisplayEntryInCMD = "--display"
+VerboseEntryInCMD = "--verbose"
+StopOnErrorEntryInCMD = "--stop-on-error"
+DumpOnErrorEntryInCMD = "--dump-on-error"
+DumpEntryInCMD = "--dump"
+KernelTraceEntryInCMD = "--kerneltrace"
+DumpStateEntryInCMD = "--dump-final"
+LoadStateEntryInCMD = "--load-state"
+SaveXMLSchemaEntryInCMD = "--save-xml-schema"
+ShutdownEntryInCMD = "--shutdown"
+ResetEntryInCMD = "--reset"
+InitPortEntryInCMD = "--init-port"
+DoNotSqueezeEntryInCMD = "--donotsqueeze"
+IOREntryInCMD = "--ior-ns"
+CPUTimeResOfContainerEntryInCMD = "--cpu-mem-container-time-res"
+HTOPFileEntryInCMD = "--htop-of-yacs-engine-process-file"
+HTOPServerFileEntryInCMD = "--htop-of-servers"
+HTOPFileTimeResEntryInCMD = "--htop-of-yacs-engine-process-time-res"
+HTOPServerFileTimeResEntryInCMD = "--htop-of-servers-time-res"
+MonitoringDirsEntryInCMD = "--monitoring-dirs-content"
+MonitoringDirsResEntryInCMD = "--monitoring-dirs-content-res"
+MonitoringDirsTimeResEntryInCMD = "--monitoring-dirs-content-time-res"
+
+DisplayKeyInARGS = "display"
+VerboseKeyInARGS = "verbose"
+StopOnErrorKeyInARGS = "stop"
+DumpOnErrorKeyInARGS = "dumpErrorFile"
+DumpKeyInARGS = "dump"
+KernelTraceKeyInARGS = "kerneltrace"
+DumpStateKeyInARGS = "finalDump"
+LoadStateKeyInARGS = "loadState"
+SaveXMLSchemaKeyInARGS = "saveXMLSchema"
+ShutdownKeyInARGS = "shutdown"
+ResetKeyInARGS = "reset"
+InitPortKeyInARGS = "init_port"
+DoNotSqueezeKeyInARGS = "donotsqueeze"
+IORKeyInARGS = "iorNS"
+CPUTimeResOfContainerKeyInARGS = "cpu_mem_container_time_res"
+HTOPFileKeyInARGS = "htop_of_yacs_engine_process_file"
+HTOPServerFileKeyInARGS = "htop_of_servers"
+HTOPFileTimeResKeyInARGS = "htop_of_yacs_engine_process_time_res"
+HTOPServerFileTimeResKeyInARGS = "htop_of_servers_time_res"
+MonitoringDirsInARGS = "monitoring_dirs_content"
+MonitoringDirsResInARGS = "monitoring_dirs_content_res"
+MonitoringDirsTimeResInARGS = "monitoring_dirs_content_time_res"
+
+KeyValnARGS = [(DisplayEntryInCMD,DisplayKeyInARGS),
+               (VerboseEntryInCMD,VerboseKeyInARGS),
+               (StopOnErrorEntryInCMD,StopOnErrorKeyInARGS),
+               (DumpOnErrorEntryInCMD,DumpOnErrorKeyInARGS),
+               (DumpEntryInCMD,DumpKeyInARGS),
+               (KernelTraceEntryInCMD,KernelTraceKeyInARGS),
+               (DumpStateEntryInCMD,DumpStateKeyInARGS),
+               (LoadStateEntryInCMD,LoadStateKeyInARGS),
+               (SaveXMLSchemaEntryInCMD,SaveXMLSchemaKeyInARGS),
+               (ShutdownEntryInCMD,ShutdownKeyInARGS),
+               (ResetEntryInCMD,ResetKeyInARGS),
+               (InitPortEntryInCMD,InitPortKeyInARGS),
+               (DoNotSqueezeEntryInCMD,DoNotSqueezeKeyInARGS),
+               (CPUTimeResOfContainerEntryInCMD,CPUTimeResOfContainerKeyInARGS),
+               (HTOPFileEntryInCMD,HTOPFileKeyInARGS),
+               (HTOPFileTimeResEntryInCMD,HTOPFileTimeResKeyInARGS),
+               (HTOPServerFileEntryInCMD,HTOPServerFileKeyInARGS),
+               (HTOPServerFileTimeResEntryInCMD,HTOPServerFileTimeResKeyInARGS),
+               (MonitoringDirsEntryInCMD,MonitoringDirsInARGS),
+               (MonitoringDirsResEntryInCMD,MonitoringDirsResInARGS),
+               (MonitoringDirsTimeResEntryInCMD,MonitoringDirsTimeResInARGS),
+               (IOREntryInCMD,IORKeyInARGS)]
+
+my_runtime_yacs = None
+
+my_ior_ns = None
+
+def initializeSALOME():
+  import SALOMERuntime
+  global my_runtime_yacs
+  if my_runtime_yacs:
+    return
+  salome.salome_init()
+  if my_ior_ns:
+    salome.naming_service.DumpIORInFile( my_ior_ns )
+  flags = SALOMERuntime.RuntimeSALOME.UsePython + SALOMERuntime.RuntimeSALOME.UseCorba + SALOMERuntime.RuntimeSALOME.UseXml + SALOMERuntime.RuntimeSALOME.UseCpp + SALOMERuntime.RuntimeSALOME.UseSalome
+  SALOMERuntime.RuntimeSALOME.setRuntime( flags )
+  my_runtime_yacs = SALOMERuntime.getSALOMERuntime()
+  anIOR = salome.orb.object_to_string ( salome.modulcat )
+  aCatalog = my_runtime_yacs.loadCatalog( "session", anIOR )
+  my_runtime_yacs.addCatalog( aCatalog )
+
+def SALOMEInitializationNeeded(func):
+  def decaratedFunc(*args,**kwargs):
+    initializeSALOME()
+    return func(*args,**kwargs)
+  return decaratedFunc
+
+@SALOMEInitializationNeeded
+def loadGraph( xmlFileName ):
+  """
+  Args:
+  -----
+  xmlFileName : XML file containing YACS schema
+
+  Returns
+  -------
+
+  SALOMERuntime.SalomeProc : YACS graph instance
+  """
+  import loader
+  l=loader.YACSLoader()
+  p=l.load( xmlFileName )
+  return p
+
+def patchGraph( proc, squeezeMemory, initPorts, xmlSchema, loadStateXmlFile, reset, display):
+  """
+  Args:
+  -----
+
+  proc ( SALOMERuntime.SalomeProc ) : YACS Proc instance to be evaluated
+  squeezeMemory ( bool ) : squeezememory to be activated
+  initPorts (list<string>) : list of bloc.node.port=value.
+  xmlSchema (string) :
+  loadStateXmlFile (string) : file if any of state to be loaded inside proc
+  reset (int) : 
+  display (int) :
+  """
+  import SALOMERuntime
+  import loader
+  import pilot
+  def parse_init_port(input):
+    """
+    Returns
+    -------
+    node, port, value
+    """
+    node_port, value = input.split("=")
+    nodePortSpl = node_port.split(".")
+    port = nodePortSpl[-1]
+    node = ".".join( nodePortSpl[:-1] )
+    return node,port,value
+      
+  if squeezeMemory:
+    logging.info("SqueezeMemory requested -> update proc")
+    allNodes = proc.getAllRecursiveNodes()
+    for node in allNodes:
+      if isinstance(proc,SALOMERuntime.PythonNode):
+        node.setSqueezeStatus( True )
+  #
+  for initPort in initPorts:
+      node,port,value = parse_init_port(initPort)
+      init_state = proc.setInPortValue(node, port, value)
+      if init_state != value:
+        raise RuntimeError(f"Error on initialization of {initPort}")
+  #
+  if xmlSchema:
+    SALOMERuntime.VisitorSaveSalomeSchemaUnsafe(proc,xmlSchema)
+    pass
+  #
+  info = pilot.LinkInfo( pilot.LinkInfo.ALL_DONT_STOP )
+  proc.checkConsistency(info)
+  if info.areWarningsOrErrors():
+    raise RuntimeError( info.getGlobalRepr() )
+  #
+  if loadStateXmlFile:
+    loader.loadState( proc, loadStateXmlFile )
+    if reset > 0:
+      proc.resetState(reset)
+      proc.exUpdateState()
+  #
+  if display > 0:
+      proc.writeDotInFile("toto")
+         
+@SALOMEInitializationNeeded
+def prepareExecution(proc, isStop, dumpErrorFile):
+  """
+  Returns
+  -------
+
+  pilot.ExecutorSwig : Instance of executor
+  """
+  import pilot
+  ex=pilot.ExecutorSwig()
+  if isStop:
+    logging.info(f"Stop has been activated with {dumpErrorFile}")
+    ex.setStopOnError( dumpErrorFile!="", dumpErrorFile )
+  return ex
+
+@SALOMEInitializationNeeded
+def executeGraph( executor, xmlfilename, proc, dump, finalDump, display, shutdown, CPUMemContainerTimeRes,
+                 HTopOfThisProcessFile, HTopTimeRes,
+                 HTopOfAllServersFile, HTopOfAllServersTimeRes, DirectoriesToMonitor):
+  """
+  Args:
+  -----
+
+  executor (pilot.ExecutorSwig) : Executor in charge of evaluation.
+  proc ( SALOMERuntime.SalomeProc ) : YACS Proc instance to be evaluated
+  xmlfilename (string)
+  dump (int) : time interval between 2 dump state
+  finalDump ( string ) : filename containing final result of graph, if any.
+  display (int) :
+  shutdown (int) : shutdown level
+  CPUMemContainerTimeRes (int) : time in second between two measures of CPU/Mem in container processes
+  HTopOfThisProcessFile (str) : file name (if not empty) containing the result of measure of current process
+  HTopTimeRes (int) : time in second between two measures of CPU/Mem of current process
+  HTopOfAllServersFile (str) : file name (if not empty) containing the result of measure of all servers
+  HTopOfAllServersTimeRes (int) : time in second between two measures of CPU/Mem of any of server
+  """
+  import SALOMERuntime
+  import pilot
+  import os
+  import contextlib
+
+  class AutoShutdown:
+    def __init__(self, proc, shutdown):
+      self._proc = proc
+      self._shutdown = shutdown
+    def __enter__(self):
+      pass
+    
+    def __exit__(self,exctype, exc, tb):
+      if self._shutdown < 999:
+        self._proc.shutdown(self._shutdown)
+      salome.dsm.shutdownScopes()
+      my_runtime_yacs.fini( False )
+
+  class AutoDumpThread:
+    def __init__(self, proc, dump, xmlfilename):
+      self._dumpFile = "dumpState_{}".format( os.path.basename(xmlfilename) )
+      self._lockFile = "{}.lock".format( os.path.splitext( os.path.basename(xmlfilename) )[0] )
+    def __enter__(self):
+      logging.info(f"Ready to launch thread of state dump with  dumpFile = {self._dumpFile}  lockFile = {self._lockFile}")
+      self._dump_thread = SALOMERuntime.ThreadDumpState(proc,dump,self._dumpFile,self._lockFile)
+      self._dump_thread.start()
+    def __exit__(self,exctype, exc, tb):
+      self._dump_thread.join()
+  
+  def MonitoringDirectories( DirectoriesToMonitor ):
+    import SALOME_PyNode
+    if len( DirectoriesToMonitor ) > 0:
+      return [ SALOME_PyNode.GenericPythonMonitoringLauncherCtxMgr( SALOME_PyNode.FileSystemMonitoring(timeRes*1000,zeDir,zeDirRes) ) for zeDir,zeDirRes,timeRes in DirectoriesToMonitor ]
+    else:
+      return [ ]
+
+  def MonitoringThisProcess(HTopOfThisProcessFile,HTopTimeRes):
+    import SALOME_PyNode
+    if HTopOfThisProcessFile:
+      return [ SALOME_PyNode.GenericPythonMonitoringLauncherCtxMgr( SALOME_PyNode.CPUMemoryMonitoring(1000*HTopTimeRes,HTopOfThisProcessFile) ) ]
+    else:
+      return [ ]
+    
+  def MonitoringAllKernelServers(HTopOfAllServersFile, HTopOfAllServersTimeRes):
+    if HTopOfAllServersFile:
+      return [ salome.LogManagerLaunchMonitoringFileCtxMgr( 1000*HTopOfAllServersTimeRes, HTopOfAllServersFile ) ]
+    else:
+      return [ ]
+
+  #
+  salome.cm.SetDeltaTimeBetweenCPUMemMeasureInMilliSecond( 1000*CPUMemContainerTimeRes )
+  # Start part of context manager instances
+  ctxManagers = [ AutoShutdown(proc,shutdown) ] # the first one must be this one. Because orb.shutdown must be called last !
+  #
+  ctxManagers += MonitoringDirectories( DirectoriesToMonitor ) + MonitoringThisProcess(HTopOfThisProcessFile, HTopTimeRes) + MonitoringAllKernelServers(HTopOfAllServersFile, HTopOfAllServersTimeRes)
+  #
+  if dump != 0:
+    ctxManagers += [ AutoDumpThread(proc,dump,xmlfilename) ]
+  # end of part of context managers
+  with contextlib.ExitStack() as stack:
+    for mgr in ctxManagers:
+      stack.enter_context(mgr)
+    executor.RunPy(proc,display,isPyThread=True,fromscratch=True) # same as RunW but releasing GIL
+  #
+  if proc.getEffectiveState() != pilot.DONE:
+    raise RuntimeError( proc.getErrorReport() )
+  #
+  if display > 0:
+      proc.writeDotInFile("titi")
+  #
+  if finalDump:
+    logging.info(f"Final dump requested : {finalDump}")
+    SALOMERuntime.schemaSaveStateUnsafe( proc, finalDump )
+
+def EntryFromCoarseEntry( entry ):
+  if entry[:2] != "--":
+    raise RuntimeError("Unexpected entry")
+  return entry[2:]
+
+def toDict( args ):
+  """
+  Convert argparse.Namespace to dict
+  """
+  return {EntryFromCoarseEntry(entry):getattr(args,key) for entry,key in KeyValnARGS}
+
+def reprAfterArgParsing( args ):
+  """
+  Args:
+  -----
+
+  args (argparse.Namespace) : instance after parsing
+  """
+  return "\n".join( [ f"{EntryFromCoarseEntry(entry)} : {args[key]}" for entry,key in KeyValnARGS ] )
+
+def getArgumentParser():
+  import argparse
+  parser = argparse.ArgumentParser()
+  parser.add_argument('xmlfilename',help = "XML file containing YACS schema to be executed")
+  parser.add_argument("-d", DisplayEntryInCMD, dest = DisplayKeyInARGS, type=int, const=1, nargs='?', default=0, help="Display dot files: 0=never to 3=very often")
+  parser.add_argument("-v", VerboseEntryInCMD, dest = VerboseKeyInARGS,help="Produce verbose output", action='store_true')
+  parser.add_argument("-s",StopOnErrorEntryInCMD,dest=StopOnErrorKeyInARGS,help="Stop on first error", action='store_true')
+  parser.add_argument("-e",DumpOnErrorEntryInCMD,dest=DumpOnErrorKeyInARGS, type=str, const='dumpErrorState.xml', default="", nargs='?', help="Stop on first error and dump state")
+  parser.add_argument("-g",DumpEntryInCMD,dest=DumpKeyInARGS, type=int, const=60, default=0, nargs='?', help="dump state")
+  parser.add_argument("-kt", KernelTraceEntryInCMD, dest = KernelTraceKeyInARGS,help="Produce verbose of SALOME/KERNEL", action='store_true')
+  parser.add_argument("-f",DumpStateEntryInCMD, dest =DumpStateKeyInARGS, type=str, const='finalDumpState.xml', default="", nargs='?', help="dump final state")
+  parser.add_argument("-l",LoadStateEntryInCMD, dest=LoadStateKeyInARGS, type=str, default="", help="Load State from a previous partial execution")
+  parser.add_argument("-x",SaveXMLSchemaEntryInCMD, dest=SaveXMLSchemaKeyInARGS, type=str, const="saveSchema.xml", nargs='?', default="", help = "dump xml schema")
+  parser.add_argument("-t",ShutdownEntryInCMD, dest = ShutdownKeyInARGS, type=int , default=3, help="Shutdown the schema: 0=no shutdown to 3=full shutdown")
+  parser.add_argument("-r",ResetEntryInCMD, dest = ResetKeyInARGS, type=int , default = 0, help="Reset the schema before execution: 0=nothing, 1=reset error nodes to ready state")
+  parser.add_argument("-i",InitPortEntryInCMD, dest = InitPortKeyInARGS, type=str, default =[], action='append', help="Initialisation value of a port, specified as bloc.node.port=value. For multiple settings use comma.")
+  parser.add_argument("-z",DoNotSqueezeEntryInCMD, dest = DoNotSqueezeKeyInARGS, help = "Desactivate squeeze memory optimization.", action='store_true')
+  parser.add_argument(CPUTimeResOfContainerEntryInCMD, dest = CPUTimeResOfContainerKeyInARGS, type=int, default = 10, help="Time in second between two measures of CPU/Mem in container processes")
+  parser.add_argument(HTOPFileEntryInCMD, dest = HTOPFileKeyInARGS, type=str, default ="", help="File name (if not empty) containing the result of measure of current process")
+  parser.add_argument(HTOPFileTimeResEntryInCMD, dest = HTOPFileTimeResKeyInARGS, type=int, default = 60, help="Time in second between between two measures of CPU/Mem of current process")
+  parser.add_argument(HTOPServerFileEntryInCMD, dest = HTOPServerFileKeyInARGS, type=str, default ="", help="File name (if not empty) containing the result of measure of all server processes")
+  parser.add_argument(HTOPServerFileTimeResEntryInCMD, dest = HTOPServerFileTimeResKeyInARGS, type=int, default = 30, help="Time in second between between two measures of CPU/Mem of any server process")
+  parser.add_argument(MonitoringDirsEntryInCMD, dest = MonitoringDirsInARGS, nargs='+', type=str, default =[], help="List of directories to be monitored")
+  parser.add_argument(MonitoringDirsResEntryInCMD, dest = MonitoringDirsResInARGS, nargs='+', type=str, default =[], help=f"List of files with result of monitoring of directories to be monitored (see {MonitoringDirsInARGS}). The size of lists are expected to be the same.")
+  parser.add_argument(MonitoringDirsTimeResEntryInCMD, dest = MonitoringDirsTimeResInARGS, nargs='+', type=int, default =[], help=f"List of time resolution (in second) of monitoring of directories to be monitored (see {MonitoringDirsInARGS}). The size of lists are expected to be the same.")
+  parser.add_argument(IOREntryInCMD, dest = IORKeyInARGS, type=str, default ="", help="file inside which the ior of NS will be stored")
+  parser.add_argument("--options_from_json", dest = "options_from_json", type=str, default ="", help="Json file of options. If defined options in json will override those specified in command line.")
+  return parser
+
+def mainRun( args, xmlFileName):
+  """
+  Args:
+  -----
+
+  args (dict) : options for treatment
+
+  """
+  global my_ior_ns
+  from salome_utils import positionVerbosityOfLoggerRegardingState,setVerboseLevel,setVerbose
+  #
+  iorNS = args[IORKeyInARGS]
+  #
+  if iorNS:
+    my_ior_ns = iorNS
+  #
+  if args[VerboseKeyInARGS]:
+    setVerbose( args[ KernelTraceKeyInARGS ] )
+    setVerboseLevel(logging.INFO)
+    positionVerbosityOfLoggerRegardingState()
+    logging.info( reprAfterArgParsing(args) )
+  #
+  proc = loadGraph( xmlFileName )
+  patchGraph( proc, not args[DoNotSqueezeKeyInARGS], args[InitPortKeyInARGS], args[SaveXMLSchemaKeyInARGS], args[LoadStateKeyInARGS], args[ResetKeyInARGS], args[DisplayKeyInARGS])
+  executor = prepareExecution( proc, args[StopOnErrorKeyInARGS], args[DumpOnErrorKeyInARGS])
+  #
+  executeGraph( executor, xmlFileName, proc, args[DumpKeyInARGS], args[DumpStateKeyInARGS], args[DisplayKeyInARGS], args[ShutdownKeyInARGS], args[CPUTimeResOfContainerKeyInARGS],
+               args[HTOPFileKeyInARGS], args[HTOPFileTimeResKeyInARGS],
+               args[HTOPServerFileKeyInARGS], args[HTOPServerFileTimeResKeyInARGS], [(dirToMonitor,resFile,timeRes) for dirToMonitor,resFile,timeRes in zip(args[MonitoringDirsInARGS],args[MonitoringDirsResInARGS],args[MonitoringDirsTimeResInARGS])] )
+
+def parseArgs():
+  """
+  Returns
+  -------
+
+  - args (dict) : dictionnary containing all args taken into account. If json, the params in json will override entries
+  - xmlFileName (str) : XML YACS schema
+  
+  """
+  import json
+  parser = getArgumentParser()
+  args = parser.parse_args()
+  iorNS = args.iorNS
+  xmlFileName = args.xmlfilename
+  optionFromJSon = args.options_from_json
+  args = toDict( args )
+  if optionFromJSon:
+    # in case of Json overrides 
+    with open( optionFromJSon ) as f:
+      opts_from_json = json.load( f )
+    for k,v in opts_from_json.items():
+      if k != EntryFromCoarseEntry(IOREntryInCMD) or v:# for IOR if v is null -> do not override
+        args[k] = v
+  # change key of args from entryCMD to KeyInARGS
+  args = {key:args[EntryFromCoarseEntry(entry)] for entry,key in KeyValnARGS}
+  return args, xmlFileName
+
+if __name__ == "__main__":
+  args, xmlFileName = parseArgs()
+  mainRun( args, xmlFileName)
index 3466b4c4f4267f6b721f66835456ffdd35d13587..e9b3f03131d923a901f4b80403656a8f6b64ae16 100644 (file)
 %import "xmlParserBase.hxx"
 %include "LoadState.hxx"
 
+namespace YACS
+{
+  namespace ENGINE
+  {
+    void loadState(YACS::ENGINE::Proc *p,const std::string& xmlStateFile);
+  }
+}