Implement AppDomain.Monitoring*MemorySize (#24610)
authorStephen Toub <stoub@microsoft.com>
Wed, 22 May 2019 04:27:00 +0000 (00:27 -0400)
committerJan Kotas <jkotas@microsoft.com>
Wed, 22 May 2019 04:26:59 +0000 (21:26 -0700)
* Implement AppDomain.MonitoringTotalAllocatedMemorySize

* Change precise:true back to precise:false in GetTotalAllocatedBytes

src/System.Private.CoreLib/Resources/Strings.resx
src/System.Private.CoreLib/shared/Interop/Unix/System.Native/Interop.GetCpuUtilization.cs
src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
src/System.Private.CoreLib/shared/System/AppDomain.Unix.cs [new file with mode: 0644]
src/System.Private.CoreLib/shared/System/AppDomain.Windows.cs [new file with mode: 0644]
src/System.Private.CoreLib/shared/System/AppDomain.cs
tests/CoreFX/CoreFX.issues.rsp

index 1b6c83c..48cbbcf 100644 (file)
   <data name="PlatformNotSupported_CAS" xml:space="preserve">
     <value>Code Access Security is not supported on this platform.</value>
   </data>
-  <data name="PlatformNotSupported_AppDomain_ResMon" xml:space="preserve">
-    <value>AppDomain resource monitoring is not supported on this platform.</value>
-  </data>
   <data name="PlatformNotSupported_Principal" xml:space="preserve">
     <value>Windows Principal functionality is not supported on this platform.</value>
   </data>
index 35e77c4..a630a3e 100644 (file)
@@ -13,9 +13,9 @@ internal static partial class Interop
         [StructLayout(LayoutKind.Sequential)]
         internal struct ProcessCpuInformation
         {
-            ulong lastRecordedCurrentTime;
-            ulong lastRecordedKernelTime;
-            ulong lastRecordedUserTime;
+            internal ulong lastRecordedCurrentTime;
+            internal ulong lastRecordedKernelTime;
+            internal ulong lastRecordedUserTime;
         }
 
         [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetCpuUtilization")]
index 35b10db..cb5180f 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)Internal\IO\File.Windows.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFileHandle.Windows.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFindHandle.Windows.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\AppDomain.Windows.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Buffer.Windows.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\DateTime.Windows.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Environment.Windows.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.Write.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Internal\IO\File.Unix.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFileHandle.Unix.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\AppDomain.Unix.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Buffer.Unix.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\DateTime.Unix.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\DebugProvider.Unix.cs" />
diff --git a/src/System.Private.CoreLib/shared/System/AppDomain.Unix.cs b/src/System.Private.CoreLib/shared/System/AppDomain.Unix.cs
new file mode 100644 (file)
index 0000000..3c1ef88
--- /dev/null
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System
+{
+    public sealed partial class AppDomain
+    {
+        public TimeSpan MonitoringTotalProcessorTime
+        {
+            get
+            {
+                Interop.Sys.ProcessCpuInformation cpuInfo = default;
+                Interop.Sys.GetCpuUtilization(ref cpuInfo);
+
+                ulong userTime100Nanoseconds = cpuInfo.lastRecordedUserTime / 100; // nanoseconds to 100-nanoseconds
+                if (userTime100Nanoseconds > long.MaxValue)
+                {
+                    userTime100Nanoseconds = long.MaxValue;
+                }
+
+                return new TimeSpan((long)userTime100Nanoseconds);
+            }
+        }
+    }
+}
diff --git a/src/System.Private.CoreLib/shared/System/AppDomain.Windows.cs b/src/System.Private.CoreLib/shared/System/AppDomain.Windows.cs
new file mode 100644 (file)
index 0000000..0763327
--- /dev/null
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System
+{
+    public sealed partial class AppDomain
+    {
+        public TimeSpan MonitoringTotalProcessorTime =>
+            Interop.Kernel32.GetProcessTimes(Interop.Kernel32.GetCurrentProcess(), out _, out _, out _, out long userTime100Nanoseconds) ?
+                new TimeSpan(userTime100Nanoseconds) :
+                TimeSpan.Zero;
+    }
+}
index 34e26ef..9c5a02c 100644 (file)
@@ -184,26 +184,28 @@ namespace System
 
         public static bool MonitoringIsEnabled
         {
-            get { return false; }
+            get { return true; }
             set
             {
                 if (!value)
                 {
                     throw new ArgumentException(SR.Arg_MustBeTrue);
                 }
-                throw new PlatformNotSupportedException(SR.PlatformNotSupported_AppDomain_ResMon);
             }
         }
 
-        public long MonitoringSurvivedMemorySize { get { throw CreateResMonNotAvailException(); } }
+        public long MonitoringSurvivedMemorySize => MonitoringSurvivedProcessMemorySize;
 
-        public static long MonitoringSurvivedProcessMemorySize { get { throw CreateResMonNotAvailException(); } }
-
-        public long MonitoringTotalAllocatedMemorySize { get { throw CreateResMonNotAvailException(); } }
-
-        public TimeSpan MonitoringTotalProcessorTime { get { throw CreateResMonNotAvailException(); } }
+        public static long MonitoringSurvivedProcessMemorySize
+        {
+            get
+            {
+                GCMemoryInfo mi = GC.GetGCMemoryInfo();
+                return mi.HeapSizeBytes - mi.FragmentedBytes;
+            }
+        }
 
-        private static Exception CreateResMonNotAvailException() => new InvalidOperationException(SR.PlatformNotSupported_AppDomain_ResMon);
+        public long MonitoringTotalAllocatedMemorySize => GC.GetTotalAllocatedBytes(precise: false);
 
         [ObsoleteAttribute("AppDomain.GetCurrentThreadId has been deprecated because it does not provide a stable Id when managed threads are running on fibers (aka lightweight threads). To get a stable identifier for a managed thread, use the ManagedThreadId property on Thread.  https://go.microsoft.com/fwlink/?linkid=14202", false)]
         public static int GetCurrentThreadId() => Environment.CurrentManagedThreadId;
index 8d48a84..78e1259 100644 (file)
 -nomethod System.CodeDom.Compiler.Tests.VBCodeGenerationTests.MetadataAttributes
 -nomethod System.CodeDom.Compiler.Tests.VBCodeGenerationTests.ProviderSupports
 -nomethod System.Runtime.InteropServices.RuntimeInformationTests.DescriptionNameTests.VerifyRuntimeDebugNameOnNetCoreApp
+-nomethod System.Tests.AppDomainTests.MonitoringIsEnabled
+-nomethod System.Tests.AppDomainTests.MonitoringSurvivedMemorySize
+-nomethod System.Tests.AppDomainTests.MonitoringSurvivedProcessMemorySize
+-nomethod System.Tests.AppDomainTests.MonitoringTotalAllocatedMemorySize
+-nomethod System.Tests.AppDomainTests.MonitoringTotalProcessorTime
 
 # Disable Tests from SqlClient entirely
 -nonamespace System.Data.SqlClient.Tests