changeset 124:35c0b2fc751c fix-leak

added configuration section "Python" and option "DisplayMemoryUsage"
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 30 Aug 2023 10:09:37 +0200
parents 5f0b7795afaf
children 262189b417cd
files NEWS Sources/Plugin.cpp
diffstat 2 files changed, 53 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Wed Aug 30 08:14:21 2023 +0200
+++ b/NEWS	Wed Aug 30 10:09:37 2023 +0200
@@ -1,6 +1,12 @@
 Pending changes in the mainline
 ===============================
 
+* New configuration section "Python" to group settings related to the plugin:
+  - "Python.Path" is an alias for global option "PythonScript"
+  - "Python.Verbose" is an alias for global option "PythonVerbose"
+* New configuration option "Python.DisplayMemoryUsage" to periodically
+  display memory allocations that stem from Python plugins
+
 
 Version 4.0 (2022-02-23)
 ========================
--- a/Sources/Plugin.cpp	Wed Aug 30 08:14:21 2023 +0200
+++ b/Sources/Plugin.cpp	Wed Aug 30 10:09:37 2023 +0200
@@ -42,6 +42,7 @@
 
 #include <boost/algorithm/string/predicate.hpp>
 #include <boost/filesystem.hpp>
+#include <boost/thread.hpp>
 
 // The "dl_iterate_phdr()" function (to walk through shared libraries)
 // is not available on Microsoft Windows and Apple OS X
@@ -283,6 +284,8 @@
 static bool pythonEnabled_ = false;
 static std::string userScriptName_;
 static std::vector<PyMethodDef>  globalFunctions_;
+static boost::thread displayMemoryUsageThread_;
+static bool displayMemoryUsageStopping_ = false;
 
 
 static void InstallClasses(PyObject* module)
@@ -461,6 +464,27 @@
 #endif
 
 
+static void DisplayMemoryUsageThread()
+{
+  {
+    PythonLock lock;
+    lock.ExecuteCommand("import tracemalloc");
+    lock.ExecuteCommand("tracemalloc.start()");
+  }
+
+  while (!displayMemoryUsageStopping_)
+  {
+    {
+      PythonLock lock;
+      lock.ExecuteCommand("print('Python memory usage: %0.03fMB' % "
+                          "(tracemalloc.get_traced_memory() [0] / (1024.0 * 1024.0)))");
+    }
+
+    boost::this_thread::sleep(boost::posix_time::seconds(1));
+  }
+}
+
+
 extern "C"
 {
   ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* c)
@@ -490,16 +514,18 @@
        * Detection of the user script
        **/
 
-      OrthancPlugins::OrthancConfiguration config;
+      OrthancPlugins::OrthancConfiguration globalConfig;
 
-      static const char* const OPTION = "PythonScript";
-    
+      OrthancPlugins::OrthancConfiguration pythonConfig;
+      globalConfig.GetSection(pythonConfig, "Python");
+
       std::string script;
-      if (!config.LookupStringValue(script, OPTION))
+      if (!globalConfig.LookupStringValue(script, "PythonScript") &&
+          !pythonConfig.LookupStringValue(script, "Path"))
       {
         pythonEnabled_ = false;
       
-        OrthancPlugins::LogWarning("The option \"" + std::string(OPTION) + "\" is not provided: " +
+        OrthancPlugins::LogWarning("Options \"PythonScript\" and \"Python.Path\" are not provided: "
                                    "Python scripting is disabled");
       }
       else
@@ -540,16 +566,22 @@
          * Initialization of Python
          **/
 
+        const bool isVerbose = (globalConfig.GetBooleanValue("PythonVerbose", false) ||
+                                pythonConfig.GetBooleanValue("Verbose", false));
+
 #if HAS_DL_ITERATE == 1
         dl_iterate_phdr(ForceImportCallback, NULL);
 #endif
 
         SetupGlobalFunctions();
-        PythonLock::GlobalInitialize("orthanc", "OrthancException",
-                                     GetGlobalFunctions, InstallClasses,
-                                     config.GetBooleanValue("PythonVerbose", false));
+        PythonLock::GlobalInitialize("orthanc", "OrthancException", GetGlobalFunctions, InstallClasses, isVerbose);
         PythonLock::AddSysPath(userScriptDirectory.string());
 
+        if (pythonConfig.GetBooleanValue("DisplayMemoryUsage", false))
+        {
+          displayMemoryUsageThread_ = boost::thread(DisplayMemoryUsageThread);
+        }
+
       
         /**
          * Force loading the declarations in the user script
@@ -592,6 +624,13 @@
       FinalizeOnStoredInstanceCallback();
       FinalizeIncomingHttpRequestFilter();
       FinalizeDicomScpCallbacks();
+
+      displayMemoryUsageStopping_ = true;
+
+      if (displayMemoryUsageThread_.joinable())
+      {
+        displayMemoryUsageThread_.join();
+      }
       
       PythonLock::GlobalFinalize();
     }