EventPipe support for ProcessInfo (#87562)
authorLakshan Fernando <lakshanf@hotmail.com>
Fri, 14 Jul 2023 15:24:12 +0000 (08:24 -0700)
committerGitHub <noreply@github.com>
Fri, 14 Jul 2023 15:24:12 +0000 (08:24 -0700)
* initial changes for process name

* add support to get managedEntrypointAssemblyName

* FB

* FB2

* fix main merge issues

* Using assembly location for coreclr per FB

* FB

* FB

* FB

eng/pipelines/runtime.yml
src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp
src/tests/Common/CoreCLRTestLibrary/Utilities.cs
src/tests/tracing/eventpipe/diagnosticport/diagnosticport.cs
src/tests/tracing/eventpipe/processinfo/processinfo.cs
src/tests/tracing/eventpipe/processinfo/processinfo.csproj
src/tests/tracing/eventpipe/processinfo2/processinfo2.cs
src/tests/tracing/eventpipe/processinfo2/processinfo2.csproj

index 6576974..4d75c6f 100644 (file)
@@ -248,7 +248,7 @@ extends:
             extraStepsTemplate: /eng/pipelines/coreclr/nativeaot-post-build-steps.yml
             extraStepsParameters:
               creator: dotnet-bot
-              testBuildArgs: 'nativeaot tree ";nativeaot;Loader;Interop;tracing/eventpipe/config;tracing/eventpipe/diagnosticport;tracing/eventpipe/reverse;tracing/eventpipe/processenvironment;tracing/eventpipe/simpleruntimeeventvalidation;" test tracing/eventcounter/runtimecounters.csproj /p:BuildNativeAotFrameworkObjects=true'
+              testBuildArgs: 'nativeaot tree ";nativeaot;Loader;Interop;tracing/eventpipe/config;tracing/eventpipe/diagnosticport;tracing/eventpipe/reverse;tracing/eventpipe/processenvironment;tracing/eventpipe/simpleruntimeeventvalidation;tracing/eventpipe/processinfo2;" test tracing/eventcounter/runtimecounters.csproj /p:BuildNativeAotFrameworkObjects=true'
               liveLibrariesBuildConfig: Release
             testRunNamePrefixSuffix: NativeAOT_$(_BuildConfig)
             extraVariablesTemplates:
index 90d2c27..944d771 100644 (file)
 #include "holder.h"
 #include "SpinLock.h"
 
+#ifndef DIRECTORY_SEPARATOR_CHAR
+#ifdef TARGET_UNIX
+#define DIRECTORY_SEPARATOR_CHAR '/'
+#else // TARGET_UNIX
+#define DIRECTORY_SEPARATOR_CHAR '\\'
+#endif // TARGET_UNIX
+#endif
+
 #ifdef TARGET_UNIX
 // Per module (1 for NativeAOT), key that will be used to implement TLS in Unix
 pthread_key_t eventpipe_tls_key;
@@ -41,7 +49,6 @@ thread_local EventPipeAotThreadHolderTLS EventPipeAotThreadHolderTLS::g_threadHo
 ep_rt_lock_handle_t _ep_rt_aot_config_lock_handle;
 CrstStatic _ep_rt_aot_config_lock;
 
-ep_char8_t *volatile _ep_rt_aot_diagnostics_cmd_line;
 
 #ifndef TARGET_UNIX
 uint32_t *_ep_rt_aot_proc_group_offsets;
@@ -88,9 +95,63 @@ ep_rt_aot_sample_profiler_write_sampling_event_for_threads (
 const ep_char8_t *
 ep_rt_aot_entrypoint_assembly_name_get_utf8 (void) 
 {
-    // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase
-    // TODO: Implement EventPipe assembly name - return filename in nativeaot?
-    return reinterpret_cast<const ep_char8_t*>("");
+    // We are (intentionally for now) using the module name rather than entry assembly
+    // Cannot use __cpp_threadsafe_static_init feature since it will bring in the C++ runtime and need to use threadsafe way to initialize entrypoint_assembly_name
+    static const ep_char8_t * entrypoint_assembly_name = nullptr;
+    if (entrypoint_assembly_name == nullptr) {
+        ep_char8_t * entrypoint_assembly_name_local;
+        const TCHAR * wszModuleFileName = NULL;
+        HANDLE moduleHandle = PalGetModuleHandleFromPointer((void*)&ep_rt_aot_entrypoint_assembly_name_get_utf8);
+        if(PalGetModuleFileName(&wszModuleFileName, moduleHandle) == 0) {
+            entrypoint_assembly_name_local = reinterpret_cast<ep_char8_t *>(malloc(1));
+            if(entrypoint_assembly_name_local==NULL) {
+                return NULL;
+            }
+            *entrypoint_assembly_name_local = '\0';
+        }
+        else {
+#ifdef HOST_WINDOWS
+            const wchar_t* process_name_const = wcsrchr(wszModuleFileName, DIRECTORY_SEPARATOR_CHAR);
+            if (process_name_const != NULL) {
+                process_name_const++;
+            }
+            else {
+                process_name_const = reinterpret_cast<const wchar_t *>(wszModuleFileName);
+            }
+            size_t len = -1;
+            const wchar_t* extension = wcsrchr(process_name_const, '.');
+            if (extension != NULL) {
+                len = extension - process_name_const;
+            }
+            entrypoint_assembly_name_local = ep_rt_utf16_to_utf8_string(reinterpret_cast<const ep_char16_t *>(process_name_const), len);
+#else
+            const ep_char8_t* process_name_const = strrchr(wszModuleFileName, DIRECTORY_SEPARATOR_CHAR);
+            if (process_name_const != NULL) {
+                process_name_const++;
+            }
+            else {
+                process_name_const = reinterpret_cast<const ep_char8_t *>(wszModuleFileName);
+            }
+            size_t len = strlen(process_name_const);
+            const ep_char8_t *extension = strrchr(process_name_const, '.');
+            if (extension != NULL) {
+                len = extension - process_name_const;
+            }
+            ep_char8_t* process_name = reinterpret_cast<ep_char8_t *>(malloc(len + 1));
+            if (process_name == NULL) {
+                return NULL;
+            }
+            memcpy(process_name, process_name_const, len);
+            process_name[len] = '\0';
+            entrypoint_assembly_name_local = reinterpret_cast<ep_char8_t*>(process_name);
+#endif // HOST_WINDOWS
+        }
+
+        if (PalInterlockedCompareExchangePointer((void**)(&entrypoint_assembly_name), (void*)(entrypoint_assembly_name_local), nullptr) != nullptr)
+            free(entrypoint_assembly_name_local);
+    }
+
+    return entrypoint_assembly_name;
 }
 
 const ep_char8_t *
@@ -101,6 +162,20 @@ ep_rt_aot_diagnostics_command_line_get (void)
 #ifdef TARGET_WINDOWS
     const ep_char16_t* command_line = reinterpret_cast<const ep_char16_t *>(::GetCommandLineW());
     return ep_rt_utf16_to_utf8_string(command_line, -1);
+#elif TARGET_LINUX
+    FILE *cmdline_file = ::fopen("/proc/self/cmdline", "r");
+    if (cmdline_file == nullptr)
+        return "";
+
+    char *line = NULL;
+    size_t line_len = 0;
+    if (::getline (&line, &line_len, cmdline_file) == -1) {
+        ::fclose (cmdline_file);
+        return "";
+    }
+
+    ::fclose (cmdline_file);
+    return reinterpret_cast<const ep_char8_t*>(line);
 #else
     return "";
 #endif
@@ -388,10 +463,10 @@ ep_rt_aot_file_close (ep_rt_file_handle_t file_handle)
 
 bool
 ep_rt_aot_file_write (
-       ep_rt_file_handle_t file_handle,
-       const uint8_t *buffer,
-       uint32_t bytes_to_write,
-       uint32_t *bytes_written)
+    ep_rt_file_handle_t file_handle,
+    const uint8_t *buffer,
+    uint32_t bytes_to_write,
+    uint32_t *bytes_written)
 {
 #ifdef TARGET_WINDOWS
     return ::WriteFile (file_handle, buffer, bytes_to_write, reinterpret_cast<LPDWORD>(bytes_written), NULL) != FALSE;
@@ -722,12 +797,12 @@ void ep_rt_aot_lock_requires_lock_not_held (const ep_rt_lock_handle_t *lock)
 void ep_rt_aot_spin_lock_requires_lock_held (const ep_rt_spin_lock_handle_t *spin_lock)
 {
     EP_ASSERT (ep_rt_spin_lock_is_valid (spin_lock));
-       EP_ASSERT (spin_lock->lock->OwnedByCurrentThread ());
+    EP_ASSERT (spin_lock->lock->OwnedByCurrentThread ());
 }
 
 void ep_rt_aot_spin_lock_requires_lock_not_held (const ep_rt_spin_lock_handle_t *spin_lock)
 {
-       EP_ASSERT (spin_lock->lock == NULL || !spin_lock->lock->OwnedByCurrentThread ());
+    EP_ASSERT (spin_lock->lock == NULL || !spin_lock->lock->OwnedByCurrentThread ());
 }
 
 #endif /* EP_CHECKED_BUILD */
index a4f5c78..c298a46 100644 (file)
@@ -95,6 +95,10 @@ namespace TestLibrary
         public static bool IsMonoRuntime => Type.GetType("Mono.RuntimeStructs") != null;
         public static bool IsNotMonoRuntime => !IsMonoRuntime;
         public static bool IsNativeAot => IsNotMonoRuntime && !IsReflectionEmitSupported;
+
+        public static bool HasAssemblyFiles => !string.IsNullOrEmpty(typeof(Utilities).Assembly.Location);
+        public static bool IsSingleFile => !HasAssemblyFiles;
+
 #if NETCOREAPP
         public static bool IsReflectionEmitSupported => RuntimeFeature.IsDynamicCodeSupported;
         public static bool IsNotReflectionEmitSupported => !IsReflectionEmitSupported;
index a1c08d4..7e2edfc 100644 (file)
@@ -403,10 +403,9 @@ namespace Tracing.Tests.DiagnosticPortValidation
                     }
                     else if (TestLibrary.Utilities.IsNativeAot)
                     {
-                        // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase
-                        // https://github.com/dotnet/runtime/issues/83051
-                        // NativeAOT currently always returns empty string
-                        Utils.Assert(processInfo2.ManagedEntrypointAssemblyName == string.Empty);
+                        string expectedName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
+                        Utils.Assert(expectedName.Equals(processInfo2.ManagedEntrypointAssemblyName),
+                            $"ManagedEntrypointAssemblyName must match. Expected: {expectedName}, Received: {processInfo2.ManagedEntrypointAssemblyName}");
                     }
                     else
                     {
index a62865b..4f0d613 100644 (file)
@@ -149,7 +149,9 @@ namespace Tracing.Tests.ProcessInfoValidation
                 // /path/to/corerun /path/to/processinfo.dll
                 // or
                 // "C:\path\to\CoreRun.exe" C:\path\to\processinfo.dll
-                string currentProcessCommandLine = $"{currentProcess.MainModule.FileName} {System.Reflection.Assembly.GetExecutingAssembly().Location}";
+                string currentProcessCommandLine = TestLibrary.Utilities.IsSingleFile
+                    ? currentProcess.MainModule.FileName
+                    : $"{currentProcess.MainModule.FileName} {System.Reflection.Assembly.GetExecutingAssembly().Location}";
                 string receivedCommandLine = NormalizeCommandLine(commandLine);
                 Utils.Assert(currentProcessCommandLine.Equals(receivedCommandLine, StringComparison.OrdinalIgnoreCase), $"CommandLine must match current process. Expected: {currentProcessCommandLine}, Received: {receivedCommandLine} (original: {commandLine})");
             }
index d4947c7..2c913f4 100644 (file)
@@ -15,5 +15,6 @@
   <ItemGroup>
     <Compile Include="$(MSBuildProjectName).cs" />
     <ProjectReference Include="../common/common.csproj" />
+    <ProjectReference Include="$(TestSourceDir)Common\CoreCLRTestLibrary\CoreCLRTestLibrary.csproj" />
   </ItemGroup>
 </Project>
index 0c04dd3..589af8d 100644 (file)
@@ -150,7 +150,9 @@ namespace Tracing.Tests.ProcessInfoValidation
                 // /path/to/corerun /path/to/processinfo.dll
                 // or
                 // "C:\path\to\CoreRun.exe" C:\path\to\processinfo.dll
-                string currentProcessCommandLine = $"{currentProcess.MainModule.FileName} {System.Reflection.Assembly.GetExecutingAssembly().Location}";
+                string currentProcessCommandLine = TestLibrary.Utilities.IsSingleFile
+                    ? currentProcess.MainModule.FileName
+                    : $"{currentProcess.MainModule.FileName} {System.Reflection.Assembly.GetExecutingAssembly().Location}";
                 string receivedCommandLine = NormalizeCommandLine(commandLine);
                 Utils.Assert(currentProcessCommandLine.Equals(receivedCommandLine, StringComparison.OrdinalIgnoreCase), $"CommandLine must match current process. Expected: {currentProcessCommandLine}, Received: {receivedCommandLine} (original: {commandLine})");
             }
index d4947c7..2c913f4 100644 (file)
@@ -15,5 +15,6 @@
   <ItemGroup>
     <Compile Include="$(MSBuildProjectName).cs" />
     <ProjectReference Include="../common/common.csproj" />
+    <ProjectReference Include="$(TestSourceDir)Common\CoreCLRTestLibrary\CoreCLRTestLibrary.csproj" />
   </ItemGroup>
 </Project>