Add a function to stop profiling after period
authorWoongsuk Cho <ws77.cho@samsung.com>
Thu, 12 Aug 2021 01:01:16 +0000 (10:01 +0900)
committer조웅석/Common Platform Lab(SR)/Principal Engineer/삼성전자 <ws77.cho@samsung.com>
Thu, 12 Aug 2021 21:11:17 +0000 (06:11 +0900)
CLR environment "MultiCoreJitProfileWriteDelay" doesnot work on Linux.

In some specific cases, application is terminated without calling coreclr_shutdown() function.
As a result, MCJ profiling data is not written.
Added a function to generate profiling data after delay so that MCJ can be used even in this case.

It works by adding delay to the environment variable as follows:
 - CLR_MCJ_PROFILE_WRITE_DELAY={delay}
(The unit of delay is second)

If you want to stop profiling after 10 seconds, add environment variable like below:
 - CLR_MCJ_PROFILE_WRITE_DELAY=10

Managed/Tizen.Runtime/Profiler.cs [new file with mode: 0644]
Managed/Tizen.Runtime/Tizen.Runtime.csproj
NativeLauncher/inc/coreclr_host.h
NativeLauncher/launcher/lib/core_runtime.cc

diff --git a/Managed/Tizen.Runtime/Profiler.cs b/Managed/Tizen.Runtime/Profiler.cs
new file mode 100644 (file)
index 0000000..4c77fe1
--- /dev/null
@@ -0,0 +1,37 @@
+/*\r
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the License);\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an AS IS BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+using System;\r
+using System.Runtime;\r
+using System.Threading.Tasks;\r
+\r
+namespace Tizen.Runtime\r
+{\r
+    public class Profiler\r
+    {\r
+        private static void stop()\r
+        {\r
+            Console.WriteLine("Stop profile and write collected data");\r
+            ProfileOptimization.StartProfile(null);\r
+        }\r
+\r
+        public static void StopProfileAfterDelay(int sec)\r
+        {\r
+            Console.WriteLine($"Stop profile after {sec} sec");\r
+            Task.Delay(sec * 1000).ContinueWith(_ => stop());\r
+        }\r
+    }\r
+}\r
index 9dfd602..cd5f4a8 100644 (file)
@@ -1,6 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
     <PropertyGroup>
-           <TargetFramework>netcoreapp2.1</TargetFramework>
+           <TargetFramework>netcoreapp3.1</TargetFramework>
            <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
            <NoWin32Manifest>True</NoWin32Manifest>
            <Configuration>Release</Configuration>
index 56f780b..702b7ec 100644 (file)
@@ -51,6 +51,8 @@ extern "C"
        typedef bool (*set_environment_variable_ptr)(const char* name,
                        const char* value);
 
+       typedef bool (*stop_profile_after_delay_ptr)(int sec);
+
        typedef int (*multi_byte_to_wide_char_ptr)(
                        unsigned int CodePage,
                        unsigned int dwFlags,
index f78dd54..64cc962 100644 (file)
@@ -56,6 +56,7 @@ static coreclr_execute_assembly_ptr executeAssembly = nullptr;
 static coreclr_shutdown_ptr shutdown = nullptr;
 static coreclr_create_delegate_ptr createDelegate = nullptr;
 static set_environment_variable_ptr setEnvironmentVariable = nullptr;
+static stop_profile_after_delay_ptr stopProfileAfterDelay = nullptr;
 static void* __coreclrLib = nullptr;
 static void* __hostHandle = nullptr;
 static unsigned int __domainId = -1;
@@ -63,6 +64,8 @@ static bool __initialized = false;
 static bool __isProfileMode = false;
 PathManager* CoreRuntime::__pm = nullptr;
 
+#define MAX_DELAY_SEC 100
+
 static std::vector<std::string> __envList;
 
 static void setEnvFromFile()
@@ -443,6 +446,12 @@ int CoreRuntime::initialize(const char* appType, LaunchMode launchMode)
                return -1;
        }
 
+       st = createDelegate(__hostHandle, __domainId, "Tizen.Runtime", "Tizen.Runtime.Profiler", "StopProfileAfterDelay", (void**)&stopProfileAfterDelay);
+       if (st < 0 || stopProfileAfterDelay == nullptr) {
+               _ERR("Create delegate for Tizen.Runtime.dll -> Tizen.Runtime.Profiler -> StopProfileAfterDelay failed (0x%08x)", st);
+               return -1;
+       }
+
        if (launchMode == LaunchMode::loader) {
                // terminate candidate process if language is changed.
                // CurrentCulture created for preloaded dlls should be updated.
@@ -549,6 +558,18 @@ int CoreRuntime::launch(const char* appId, const char* root, const char* path, i
 
                        setEnvironmentVariable("COMPlus_MultiCoreJitProfile", multiCoreJitProfile);
                        setEnvironmentVariable("COMPlus_MultiCoreJitMinNumCpus", "1");
+
+                       // stop profiling and write collected data after delay if env value is set.
+                       char *env = getenv("CLR_MCJ_PROFILE_WRITE_DELAY");
+                       if (env != nullptr) {
+                               int delay = std::atoi(env);
+                               // To avoid undefined behavior by out-of-range input(atoi), set max delay value to 100.
+                               if (delay > 0) {
+                                       if (delay > MAX_DELAY_SEC) delay = MAX_DELAY_SEC;
+                                       stopProfileAfterDelay(delay);
+                               }
+                       }
+
                        if (exist(multiCoreJitProfile)) {
                                setEnvironmentVariable("COMPlus_MultiCoreJitNoProfileGather", "1");
                        }