Do not major_free_swept_blocks on Orbis.
--- /dev/null
+# Mono Code Owners File
+#
+# GitHub uses this file to determine who to ping for reviews on pull requests.
+# If you're the primary maintainer of an area of Mono and you don't mind
+# reviewing pull requests, please add yourself to this file. You may want to
+# avoid adding entries for commonly changed or automatically generated files
+# (e.g. stuff in external/, or various generated *.csproj files) so as not to
+# get spammed with emails.
+#
+# Note that if two patterns match a file, the later pattern takes precedence.
+#
+# Please keep this file alphabetically sorted.
+#
+# Reference:
+#
+# https://github.com/blog/2392-introducing-code-owners
+# https://help.github.com/articles/about-codeowners
+
+acceptance-tests/* @akoeplinger
+acceptance-tests/profiler-stress @alexrp
+docs/sources/mono-api-profiler.html @alexrp
+man/mprof-report.1 @alexrp
+mcs/class/Mono.Options @jonpryor
+mcs/class/Mono.Profiler.Log @alexrp
+mono/metadata/profiler* @alexrp
+mono/metadata/threads* @luhenry @kumpera
+mono/metadata/threadpool* @luhenry
+mono/metadata/w32* @luhenry
+mono/profiler @alexrp
+mono/utils/atomic* @alexrp
+mono/utils/mono-hwcap* @alexrp
+mono/utils/mono-mem* @alexrp
+mono/utils/mono-threads* @luhenry @kumpera
+msvc/*profiler* @alexrp
+packaging/Windows @akoeplinger
+samples/profiler @alexrp
+samples/size @alexrp
+scripts/ci/run-jenkins.sh @akoeplinger
+scripts/ci/run-test-acceptance-tests.sh @akoeplinger
+scripts/ci/run-test-default.sh @akoeplinger
+scripts/ci/run-test-profiler-stress-tests.sh @alexrp
+scripts/ci/util.sh @akoeplinger
The Mono runtime, compilers, and tools and most of the class libraries
are licensed under the MIT license. But include some bits of code
-licensed under different licenses. The exact list is [available here] (https://github.com/mono/mono/blob/master/LICENSE).
+licensed under different licenses. The exact list is [available here](https://github.com/mono/mono/blob/master/LICENSE).
Different parts of Mono use different licenses. The actual details of
which licenses are used for which parts are detailed on the LICENSE
CLA
=======
-Contributions are now taken under the [.NET Foundation CLA] (https://cla2.dotnetfoundation.org/).
+Contributions are now taken under the [.NET Foundation CLA](https://cla2.dotnetfoundation.org/).
Testing
=======
static class Program {
static readonly string[] _options = new [] {
- "domain",
- "assembly",
- "module",
- "class",
- "jit",
"exception",
- "gcalloc",
- "gc",
- "thread",
- // "calls", // Way too heavy.
"monitor",
+ "gc",
+ "gcalloc",
"gcmove",
"gcroot",
- "context",
+ "gchandle",
"finalization",
"counter",
- "gchandle",
+ "jit",
};
static readonly TimeSpan _timeout = TimeSpan.FromHours (6);
var bench = benchmarks [i];
var sampleFreq = rand.Next (-1000, 1001);
- var sampleMode = rand.Next (0, 2) == 1 ? "real" : "process";
+ var sampleMode = rand.Next (0, 2) == 1 ? "-real" : string.Empty;
var maxSamples = rand.Next (0, cpus * 2000 + 1);
var heapShotFreq = rand.Next (-10, 11);
var maxFrames = rand.Next (0, 33);
var profOptions = $"maxframes={maxFrames},{string.Join (",", options)},output=/dev/null";
if (sampleFreq > 0)
- profOptions += $",sample={sampleFreq},sampling-{sampleMode},maxsamples={maxSamples}";
+ profOptions += $",sample{sampleMode}={sampleFreq},maxsamples={maxSamples}";
if (heapShotFreq > 0)
profOptions += $",heapshot={heapShotFreq}gc";
-Subproject commit 7e70a4e9236104c350e7d9ca3505225755065569
+Subproject commit 797f074e49933b5fffb42d1a945270f3a88de042
/* pointer to a previously allocated heap */
/* object. */
-// Keep somewhat in sync with mono/metadata/profiler.h:enum MonoGCEvent
typedef enum {
GC_EVENT_START,
GC_EVENT_MARK_START,
run-test-local: run-test-lib
run-test-ondotnet-local: run-test-ondotnet-lib
-TEST_HARNESS_EXCLUDES = -exclude=$(PLATFORM_TEST_HARNESS_EXCLUDES)$(PROFILE_TEST_HARNESS_EXCLUDES)NotWorking,ValueAdd,CAS,InetAccess
+TEST_HARNESS_EXCLUDES = -exclude=$(PLATFORM_TEST_HARNESS_EXCLUDES)$(PROFILE_TEST_HARNESS_EXCLUDES)NotWorking,CAS
TEST_HARNESS_EXCLUDES_ONDOTNET = /exclude:$(PLATFORM_TEST_HARNESS_EXCLUDES)$(PROFILE_TEST_HARNESS_EXCLUDES)NotDotNet,CAS
NOSHADOW_FLAG =
[Test]
public void EndBuildWaitsForSubmissionCompletion ()
{
- // Windows does not have useful sleep or alternative, so skip it
- bool is_windows = true;
- switch (Environment.OSVersion.Platform) {
- case PlatformID.Unix:
- case PlatformID.MacOSX:
- is_windows = false;
- break;
- }
string project_xml = string.Format (@"<Project DefaultTargets='Wait1Sec' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
<Target Name='Wait1Sec'>
<Exec Command='{0}' />
</Target>
-</Project>", is_windows ? "powershell -command \"Start-Sleep -s 1\"" : "/bin/sleep 1");
+</Project>", Environment.OSVersion.Platform == PlatformID.Win32NT ? "powershell -command \"Start-Sleep -s 1\"" : "/bin/sleep 1");
var xml = XmlReader.Create (new StringReader (project_xml));
var root = ProjectRootElement.Create (xml);
root.FullPath = "BuildSubmissionTest.EndBuildWaitsForSubmissionCompletion.proj";
var proj = new ProjectInstance (root);
var bm = new BuildManager ();
bm.BeginBuild (new BuildParameters ());
- DateTime waitDone = DateTime.MinValue;
- DateTime beforeExec = DateTime.UtcNow;
+ var waitDone = TimeSpan.MinValue;
+ var sw = System.Diagnostics.Stopwatch.StartNew ();
var sub = bm.PendBuildRequest (new BuildRequestData (proj, new string [] { "Wait1Sec" }));
- sub.ExecuteAsync (delegate { waitDone = DateTime.UtcNow; }, null);
+ sub.ExecuteAsync (cb => waitDone = sw.Elapsed, null);
bm.EndBuild ();
Assert.AreEqual (BuildResultCode.Success, sub.BuildResult.OverallResult, "#1");
- DateTime endBuildDone = DateTime.UtcNow;
- AssertHelper.GreaterOrEqual (endBuildDone - beforeExec, TimeSpan.FromSeconds (1), "#2");
- AssertHelper.GreaterOrEqual (waitDone, beforeExec, "#3");
+ var endBuildDone = sw.Elapsed;
+ AssertHelper.GreaterOrEqual (endBuildDone, TimeSpan.FromSeconds (1), "#2");
+ AssertHelper.GreaterOrEqual (waitDone, TimeSpan.FromSeconds (1), "#3");
AssertHelper.GreaterOrEqual (endBuildDone, waitDone, "#4");
+ AssertHelper.LessOrEqual (endBuildDone, TimeSpan.FromSeconds (2), "#5");
+ AssertHelper.LessOrEqual (waitDone, TimeSpan.FromSeconds (2), "#6");
}
[Test]
Mono.Profiler.Log/LogEvents.cs
Mono.Profiler.Log/LogException.cs
Mono.Profiler.Log/LogProcessor.cs
+Mono.Profiler.Log/LogProfiler.cs
Mono.Profiler.Log/LogReader.cs
-Mono.Profiler.Log/LogRuntimeProfiler.cs
Mono.Profiler.Log/LogStream.cs
Mono.Profiler.Log/LogStreamHeader.cs
// mono/metadata/profiler.h : MonoProfilerGCEvent
public enum LogGCEvent {
- Begin = 0,
- MarkBegin = 1,
- MarkEnd = 2,
- ReclaimBegin = 3,
- ReclaimEnd = 4,
- End = 5,
PreStopWorld = 6,
+ PreStopWorldLocked = 10,
PostStopWorld = 7,
+ Begin = 0,
+ End = 5,
PreStartWorld = 8,
PostStartWorld = 9,
- PreStopWorldLocked = 10,
PostStartWorldUnlocked = 11,
}
WorldStop = 1,
WorldStart = 2,
}
+
+ // mono/metadata/profiler.h : MonoProfilerSampleMode
+ public enum LogSampleMode {
+ None = 0,
+ Process = 1,
+ Real = 2,
+ }
+
+ // mono/profiler/log.h : MonoProfilerHeapshotMode
+ public enum LogHeapshotMode {
+ None = 0,
+ EveryMajor = 1,
+ OnDemand = 2,
+ Milliseconds = 3,
+ Collections = 4,
+ }
}
long ReadObject ()
{
- return Reader.ReadSLeb128 () + _bufferHeader.ObjectBase;
+ return Reader.ReadSLeb128 () + _bufferHeader.ObjectBase << 3;
}
long ReadMethod ()
--- /dev/null
+// 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.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Mono.Profiler.Log {
+
+ public static class LogProfiler {
+
+ static bool? _attached;
+
+ public static bool IsAttached {
+ get {
+ if (_attached != null)
+ return (bool) _attached;
+
+ try {
+ GetMaxStackTraceFrames ();
+ return (bool) (_attached = true);
+ } catch (MissingMethodException) {
+ return (bool) (_attached = false);
+ }
+ }
+ }
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static int GetMaxStackTraceFrames ();
+
+ public static int MaxStackTraceFrames {
+ get { return GetMaxStackTraceFrames (); }
+ }
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static int GetStackTraceFrames ();
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static void SetStackTraceFrames (int value);
+
+ public static int StackTraceFrames {
+ get { return GetStackTraceFrames (); }
+ set {
+ var max = MaxStackTraceFrames;
+
+ if (value < 0 || value > max)
+ throw new ArgumentOutOfRangeException (nameof (value), value, $"Value must be between 0 and {max}.");
+
+ SetStackTraceFrames (value);
+ }
+ }
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static LogHeapshotMode GetHeapshotMode ();
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static void SetHeapshotMode (LogHeapshotMode value);
+
+ public static LogHeapshotMode HeapshotMode {
+ get { return GetHeapshotMode (); }
+ set {
+ if (!Enum.IsDefined (typeof (LogHeapshotMode), value))
+ throw new ArgumentException ("Invalid heapshot mode.", nameof (value));
+
+ SetHeapshotMode (value);
+ }
+ }
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static int GetHeapshotMillisecondsFrequency ();
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static void SetHeapshotMillisecondsFrequency (int value);
+
+ public static int HeapshotMillisecondsFrequency {
+ get { return GetHeapshotMillisecondsFrequency (); }
+ set {
+ if (value < 0)
+ throw new ArgumentOutOfRangeException (nameof (value), value, "Value must be non-negative.");
+
+ SetHeapshotMillisecondsFrequency (value);
+ }
+ }
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static int GetHeapshotCollectionsFrequency ();
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static void SetHeapshotCollectionsFrequency (int value);
+
+ public static int HeapshotCollectionsFrequency {
+ get { return GetHeapshotCollectionsFrequency (); }
+ set {
+ if (value < 0)
+ throw new ArgumentOutOfRangeException (nameof (value), value, "Value must be non-negative.");
+
+ SetHeapshotCollectionsFrequency (value);
+ }
+ }
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static int GetCallDepth ();
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static void SetCallDepth (int value);
+
+ public static int CallDepth {
+ get { return GetCallDepth (); }
+ set {
+ if (value < 0)
+ throw new ArgumentOutOfRangeException (nameof (value), value, "Value must be non-negative.");
+
+ SetCallDepth (value);
+ }
+ }
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static void GetSampleMode (out LogSampleMode mode, out int frequency);
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static bool SetSampleMode (LogSampleMode value, int frequency);
+
+ public static LogSampleMode SampleMode {
+ get {
+ GetSampleMode (out var mode, out var _);
+
+ return mode;
+ }
+ }
+
+ public static int SampleFrequency {
+ get {
+ GetSampleMode (out var _, out var frequency);
+
+ return frequency;
+ }
+ }
+
+ public static bool SetSampleParameters (LogSampleMode mode, int frequency)
+ {
+ if (!Enum.IsDefined (typeof (LogSampleMode), mode))
+ throw new ArgumentException ("Invalid sample mode.", nameof (mode));
+
+ if (frequency < 1)
+ throw new ArgumentOutOfRangeException (nameof (frequency), frequency, "Frequency must be positive.");
+
+ return SetSampleMode (mode, frequency);
+ }
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static bool GetExceptionEvents ();
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static void SetExceptionEvents (bool value);
+
+ public static bool ExceptionEventsEnabled {
+ get { return GetExceptionEvents (); }
+ set { SetExceptionEvents (value); }
+ }
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static bool GetMonitorEvents ();
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static void SetMonitorEvents (bool value);
+
+ public static bool MonitorEventsEnabled {
+ get { return GetMonitorEvents (); }
+ set { SetMonitorEvents (value); }
+ }
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static bool GetGCEvents ();
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static void SetGCEvents (bool value);
+
+ public static bool GCEventsEnabled {
+ get { return GetGCEvents (); }
+ set { SetGCEvents (value); }
+ }
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static bool GetGCAllocationEvents ();
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static void SetGCAllocationEvents (bool value);
+
+ public static bool GCAllocationEventsEnabled {
+ get { return GetGCAllocationEvents (); }
+ set { SetGCAllocationEvents (value); }
+ }
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static bool GetGCMoveEvents ();
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static void SetGCMoveEvents (bool value);
+
+ public static bool GCMoveEventsEnabled {
+ get { return GetGCMoveEvents (); }
+ set { SetGCMoveEvents (value); }
+ }
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static bool GetGCRootEvents ();
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static void SetGCRootEvents (bool value);
+
+ public static bool GCRootEventsEnabled {
+ get { return GetGCRootEvents (); }
+ set { SetGCRootEvents (value); }
+ }
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static bool GetGCHandleEvents ();
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static void SetGCHandleEvents (bool value);
+
+ public static bool GCHandleEventsEnabled {
+ get { return GetGCHandleEvents (); }
+ set { SetGCHandleEvents (value); }
+ }
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static bool GetGCFinalizationEvents ();
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static void SetGCFinalizationEvents (bool value);
+
+ public static bool GCFinalizationEventsEnabled {
+ get { return GetGCFinalizationEvents (); }
+ set { SetGCFinalizationEvents (value); }
+ }
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static bool GetCounterEvents ();
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static void SetCounterEvents (bool value);
+
+ public static bool CounterEventsEnabled {
+ get { return GetCounterEvents (); }
+ set { SetCounterEvents (value); }
+ }
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static bool GetJitEvents ();
+
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ extern static void SetJitEvents (bool value);
+
+ public static bool JitEventsEnabled {
+ get { return GetJitEvents (); }
+ set { SetJitEvents (value); }
+ }
+ }
+}
+++ /dev/null
-// 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.
-
-using System.Runtime.InteropServices;
-
-namespace Mono.Profiler.Log {
-
- public static class LogRuntimeProfiler {
-
- // TODO: Runtime profiler interface.
- }
-}
namespace MonoTests.System.DirectoryServices \r
{\r
[TestFixture]\r
- [Category ("InetAccess")]\r
public class DirectoryServicesDirectoryEntryTest\r
{\r
#region Fields\r
{\r
de = null;\r
configuration = new TestConfiguration ();\r
+\r
+ if (String.IsNullOrEmpty (configuration.ConnectionString))\r
+ Assert.Ignore ("No configuration");\r
}\r
\r
\r
namespace MonoTests.System.DirectoryServices \r
{\r
[TestFixture]\r
- [Category ("InetAccess")]\r
public class DirectoryServicesDirectorySearcherTest\r
{\r
#region Fields\r
{\r
de = null; \r
configuration = new TestConfiguration ();\r
+\r
+ if (String.IsNullOrEmpty (configuration.ConnectionString))\r
+ Assert.Ignore ("No configuration");\r
}\r
\r
\r
namespace MonoTests.System.DirectoryServices \r
{\r
[TestFixture]\r
- [Category ("InetAccess")]\r
public class DirectoryServicesSearchResultTest\r
{\r
#region Fields\r
{\r
de = null;\r
configuration = new TestConfiguration ();\r
+\r
+ if (String.IsNullOrEmpty (configuration.ConnectionString))\r
+ Assert.Ignore ("No configuration");\r
}\r
\r
\r
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />\r
<ItemGroup>\r
<Compile Include="..\..\..\external\corefx\src\System.Drawing.Common\src\AssemblyRef.cs" />\r
- <Compile Include="..\..\..\external\corefx\src\System.Drawing.Common\src\misc\ClientUtils.cs" />\r
<Compile Include="..\..\..\external\corefx\src\System.Drawing.Common\src\misc\HandleCollector.cs" />\r
<Compile Include="..\..\..\external\corefx\src\System.Drawing.Common\src\System\Drawing\BitmapSuffixInSameAssemblyAttribute.cs" />\r
<Compile Include="..\..\..\external\corefx\src\System.Drawing.Common\src\System\Drawing\BitmapSuffixInSatelliteAssemblyAttribute.cs" />\r
<Compile Include="..\..\..\external\corefx\src\System.Drawing.Common\src\System\Drawing\Brush.cs" />\r
+ <Compile Include="..\..\..\external\corefx\src\System.Drawing.Common\src\System\Drawing\ClientUtils.cs" />\r
<Compile Include="..\..\..\external\corefx\src\System.Drawing.Common\src\System\Drawing\DashCap.cs" />\r
<Compile Include="..\..\..\external\corefx\src\System.Drawing.Common\src\System\Drawing\Design\CategoryNameCollection.cs" />\r
<Compile Include="..\..\..\external\corefx\src\System.Drawing.Common\src\System\Drawing\Design\IPropertyValueUIService.cs" />\r
Assembly/AssemblyInfo.cs
../../build/common/Consts.cs
../../build/common/Locale.cs
-../../../external/corefx/src/System.Drawing.Common/src/misc/ClientUtils.cs
+../../../external/corefx/src/System.Drawing.Common/src/System/Drawing/ClientUtils.cs
../../../external/corefx/src/System.Drawing.Common/src/misc/HandleCollector.cs
../../../external/corefx/src/System.Drawing.Common/src/System/Drawing/Gdiplus.cs
../../../external/corefx/src/System.Drawing.Common/src/System/Drawing/NativeMethods.cs
../../../external/corefx/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatingEventHandler.cs
../../../external/corefx/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxItemCreatorCallback.cs
System.Drawing.Design/ToolboxItem.cs
- ../../../external/corefx/src/System.Drawing.Common/src/System/Drawing/Design/UITypeEditor.cs
+../../../external/corefx/src/System.Drawing.Common/src/System/Drawing/Design/UITypeEditor.cs
../../../external/corefx/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxItemCollection.cs
../../../external/corefx/src/System.Drawing.Common/src/System/Drawing/Drawing2D/AdjustableArrowCap.cs
../../../external/corefx/src/System.Drawing.Common/src/System/Drawing/Drawing2D/Blend.cs
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />\r
<ItemGroup>\r
<Compile Include="..\..\..\external\corefx\src\Common\src\System\Globalization\FormatProvider.Number.cs" />\r
+ <Compile Include="..\..\..\external\corefx\src\Common\src\System\MathF.netstandard.cs" />\r
<Compile Include="..\..\..\external\corefx\src\Common\src\System\Numerics\Hashing\HashHelpers.cs" />\r
- <Compile Include="..\..\..\external\corefx\src\System.Numerics.Vectors\src\System\MathF.cs" />\r
<Compile Include="..\..\..\external\corefx\src\System.Numerics.Vectors\src\System\Numerics\JitIntrinsicAttribute.cs" />\r
<Compile Include="..\..\..\external\corefx\src\System.Numerics.Vectors\src\System\Numerics\Matrix3x2.cs" />\r
<Compile Include="..\..\..\external\corefx\src\System.Numerics.Vectors\src\System\Numerics\Matrix4x4.cs" />\r
../../../external/corefx/src/System.Runtime.Numerics/src/System/Numerics/Complex.cs
../../../external/corefx/src/System.Runtime.Numerics/src/System/Numerics/NumericsHelpers.cs
-../../../external/corefx/src/System.Numerics.Vectors/src/System/MathF.cs
+../../../external/corefx/src/Common/src/System/MathF.netstandard.cs
../../../external/corefx/src/System.Numerics.Vectors/src/System/Numerics/JitIntrinsicAttribute.cs
../../../external/corefx/src/System.Numerics.Vectors/src/System/Numerics/Matrix3x2.cs
-../../../external/corefx/src/Common/tests/System/AssertExtensions.cs
+../../../external/corefx/src/CoreFx.Private.TestUtilities/src/System/AssertExtensions.cs
../../../external/corefx/src/Common/tests/System/PlatformDetection.cs
+../../../external/corefx/src/Common/src/System/MathF.netstandard.cs
# ../../../external/corefx/src/System.Runtime.Numerics/tests/*.cs
../../../external/corefx/src/System.Runtime.Numerics/tests/BigInteger/*.cs
WebRequest request = GetWebRequest (uri);
request.Method = "POST";
WebHeaderCollection headers = request.Headers;
- if (!message.IsSoap12)
- headers.Add ("SOAPAction", "\"" + message.Action + "\"");
request.ContentType = message.ContentType + "; charset=utf-8";
+ if (!message.IsSoap12) {
+ headers.Add ("SOAPAction", "\"" + message.Action + "\"");
+ } else {
+ request.ContentType += "; action=\"" + message.Action + "\"";
+ }
return request;
}
public class DiscoveryClientProtocolTest {
[Test] // Covers #36116
- [Category ("InetAccess")]
+ [Category ("NotWorking")]
public void ReadWriteTest ()
{
string directory = Path.Combine (Path.GetTempPath (), Path.GetRandomFileName ());
include ../../build/library.make
-TEST_HARNESS_EXCLUDES = -exclude=Interactive,NotWorking,ValueAdd,CAS,InetAccess
+TEST_HARNESS_EXCLUDES = -exclude=Interactive,NotWorking,CAS
TEST_HARNESS_EXCLUDES_ONDOTNET = -exclude=Interactive,NotDotNet,CAS
$(the_lib): $(RESOURCES)
ChainValidationHelper.Create (provider, ref settings, this);
#else
+ status = WebExceptionStatus.SecureChannelFailure;
throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
#endif
}
case 13882: /* ERROR_IPSEC_IKE_MM_LIMIT */ return "IPSEC IKE mm limit";
case 13883: /* ERROR_IPSEC_IKE_NEGOTIATION_DISABLED */ return "IPSEC IKE negotiation disabled";
case 13884: /* ERROR_IPSEC_IKE_NEG_STATUS_END */ return "IPSEC IKE neg status end";
+ case 100001: /* WSAENXIO */ return "Device not configured";
#endif // MOBILE
default:
return string.Format ("mono-io-layer-error ({0})", error);
}
}
#else
+#pragma warning disable 618
ConfigurationSettings.GetConfig ("system.net/authenticationModules");
+#pragma warning restore 618
#endif
}
}
try {
IPAddress newAddress = IPAddress.Parse(h_addrlist[i]);
+#pragma warning disable 618
if( (Socket.SupportsIPv6 && newAddress.AddressFamily == AddressFamily.InterNetworkV6) ||
(Socket.SupportsIPv4 && newAddress.AddressFamily == AddressFamily.InterNetwork) )
addrlist.Add(newAddress);
+#pragma warning restore 618
} catch (ArgumentNullException) {
/* Ignore this, as the
* internal call might have
if (hostNameOrAddress.Length > 0 && IPAddress.TryParse (hostNameOrAddress, out addr))
return GetHostEntry (addr);
+#pragma warning disable 618
return GetHostByName (hostNameOrAddress);
+#pragma warning restore 618
}
public static IPHostEntry GetHostEntry (IPAddress address)
addr = IPAddress.Any;
else if (IPAddress.TryParse(host, out addr) == false){
try {
+#pragma warning disable 618
IPHostEntry iphost = Dns.GetHostByName(host);
+#pragma warning restore 618
if (iphost != null)
addr = iphost.AddressList[0];
else
internal FtpWebRequest (Uri uri)
{
this.requestUri = uri;
+#pragma warning disable 618
this.proxy = GlobalProxySelection.Select;
+#pragma warning restore 618
}
static Exception GetMustImplement ()
{
defaultMaxResponseHeadersLength = 64 * 1024;
#if !MOBILE
+#pragma warning disable 618
NetConfig config = ConfigurationSettings.GetConfig ("system.net/settings") as NetConfig;
+#pragma warning restore 618
if (config != null) {
int x = config.MaxResponseHeadersLength;
if (x != -1)
[Test]
[EnvironmentPermission (SecurityAction.Deny, Read = "USERNAME")]
- [Category ("InetAccess")]
public void AsyncRead ()
{
message = "AsyncRead";
[Test]
[EnvironmentPermission (SecurityAction.Deny, Read = "USERNAME")]
- [Category ("InetAccess")]
public void AsyncWrite ()
{
message = "AsyncWrite";
[Test]
[EnvironmentPermission (SecurityAction.Deny, Read = "USERNAME")]
- [Category ("InetAccess")]
public void AsyncAccept ()
{
IPEndPoint ep = new IPEndPoint (IPAddress.Loopback, 16279);
[Test]
[EnvironmentPermission (SecurityAction.Deny, Read = "USERNAME")]
- [Category ("InetAccess")]
public void AsyncConnect ()
{
message = "AsyncConnect";
[Test]
[EnvironmentPermission (SecurityAction.Deny, Read = "USERNAME")]
- [Category ("InetAccess")]
public void AsyncReceive ()
{
message = "AsyncReceive";
[Test]
[EnvironmentPermission (SecurityAction.Deny, Read = "USERNAME")]
- [Category ("InetAccess")]
public void AsyncReceiveFrom ()
{
message = "AsyncReceiveFrom";
[Test]
[EnvironmentPermission (SecurityAction.Deny, Read = "USERNAME")]
- [Category ("InetAccess")]
public void AsyncSend ()
{
message = "AsyncSend";
[Test]
[EnvironmentPermission (SecurityAction.Deny, Read = "USERNAME")]
- [Category ("InetAccess")]
public void AsyncSendTo ()
{
message = "AsyncSendTo";
}
[Test]
- [Category ("InetAccess")]
+ [Category ("NotWorking")]
#if FEATURE_NO_BSD_SOCKETS
[ExpectedException (typeof (PlatformNotSupportedException))]
#endif
}
// async tests (for stack propagation)
-/* Oops - not yet implemented in Mono
private void ConnectCallback (IAsyncResult ar)
{
TcpClient c = (TcpClient)ar.AsyncState;
[Test]
[EnvironmentPermission (SecurityAction.Deny, Read = "USERNAME")]
- [Category ("InetAccess")]
public void AsyncConnect_StringIntAsyncCallbackObject ()
{
TcpClient s = new TcpClient ();
[Test]
[EnvironmentPermission (SecurityAction.Deny, Read = "USERNAME")]
- [Category ("InetAccess")]
public void AsyncConnect_IPAddressIntAsyncCallbackObject ()
{
IPHostEntry host = Dns.Resolve ("www.google.com");
[Test]
[EnvironmentPermission (SecurityAction.Deny, Read = "USERNAME")]
- [Category ("InetAccess")]
public void AsyncConnect_IPAddressArrayIntAsyncCallbackObject ()
{
IPHostEntry host = Dns.Resolve ("www.google.com");
Assert.Ignore ("Timeout");
Assert.IsNull (message, message);
}
-*/
}
}
}
[Test]
- [Category("InetAccess")]
#if FEATURE_NO_BSD_SOCKETS
[ExpectedException (typeof (PlatformNotSupportedException))]
#endif
}
[Test]
- //[Category("InetAccess")]
[Category ("NotWorking")] // Disabled until a server that meets requirements is found
public void Cookies1 ()
{
}\r
\r
[Test, ExpectedException (typeof (InvalidOperationException))]\r
- [Category ("InetAccess")]\r
+ [Category ("NotWorking")]\r
public void MaxServicePointManagers ()\r
{\r
Assert.AreEqual (0, ServicePointManager.MaxServicePoints, "#1");\r
-//\r
-// ServicePointTest.cs - NUnit Test Cases for System.Net.ServicePoint\r
-//\r
-// Authors:\r
-// Lawrence Pit (loz@cable.a2000.nl)\r
-// Martin Willemoes Hansen (mwh@sysrq.dk)\r
-//\r
-// (C) 2003 Martin Willemoes Hansen\r
-//\r
-\r
-using NUnit.Framework;\r
-using System;\r
-using System.Collections;\r
-using System.IO;\r
-using System.Net;\r
-using System.Reflection;\r
-using System.Threading;\r
-\r
-namespace MonoTests.System.Net\r
-{\r
-\r
-[TestFixture]\r
-public class ServicePointTest\r
-{\r
- static private int max;\r
-\r
-#if !FEATURE_NO_BSD_SOCKETS\r
- [SetUp]\r
- public void SaveMax () {\r
- max = ServicePointManager.MaxServicePoints;\r
- ServicePointManager.MaxServicePoints = 0;\r
- }\r
-\r
- [TearDown]\r
- public void RestoreMax () {\r
- ServicePointManager.MaxServicePoints = max;\r
- }\r
-#endif\r
-\r
- [Test]\r
- [Category ("InetAccess")]\r
- public void All ()\r
- {\r
- ServicePoint p = ServicePointManager.FindServicePoint (new Uri ("mailto:xx@yyy.com"));\r
- //WriteServicePoint ("A servicepoint that isn't really", p); \r
- \r
- ServicePointManager.MaxServicePoints = 2;\r
- ServicePoint google = ServicePointManager.FindServicePoint (new Uri ("http://www.google.com"));\r
- try { \r
- ServicePoint slashdot = ServicePointManager.FindServicePoint (new Uri ("http://www.slashdot.org"));\r
- Assert.Fail ("#1");\r
- } catch (InvalidOperationException) { }\r
- ServicePointManager.MaxServicePoints = 0;\r
- \r
- //WriteServicePoint ("google before getting a webrequest", google);\r
- \r
- HttpWebRequest req = (HttpWebRequest) WebRequest.Create ("http://www.google.com");\r
- HttpWebResponse res = (HttpWebResponse) req.GetResponse (); \r
- \r
-#if FOUND_SOME_OTHER_URL\r
- // URL is no longer found, disabled the test until a more reliable URL is found :P\r
- //WriteServicePoint ("google after getting a response", google);\r
- ServicePoint google2 = ServicePointManager.FindServicePoint (new Uri ("http://www.google.com/dilbert.html"));\r
- Assert.AreEqual (google, google2, "#equals");\r
- res.Close ();\r
-#endif\r
- \r
- // in both instances property CurrentConnections is 0 according to ms.net.\r
- // let's see what it says when we do async operations...\r
- \r
- HttpWebRequest req2 = (HttpWebRequest) WebRequest.Create ("http://www.google.com");\r
- req2.Method = "PUT";\r
- IAsyncResult async = req2.BeginGetRequestStream (null, null);\r
- //WriteServicePoint ("after async BeginGetRequestStream", google);\r
- // CurrentConnections: 1\r
- Stream stream2 = req2.EndGetRequestStream (async);\r
- //WriteServicePoint ("after async EndGetRequestStream", google);\r
- // CurrentConnections: 1\r
- stream2.Close ();\r
- \r
- req2 = (HttpWebRequest) WebRequest.Create ("http://www.google.com");\r
- async = req2.BeginGetResponse (null, null);\r
- //WriteServicePoint ("after async BeginGetResponse", google);\r
- // CurrentConnections: 2\r
- WebResponse res2 = req2.EndGetResponse (async);\r
- //WriteServicePoint ("after async EndGetResponse", google);\r
- // CurrentConnections: 0 \r
- // curious that after you get the webresponse object CurrentConnections is set to 0.\r
- // you'd think that you'd still be connected until you close the webresponse..\r
- //Console.WriteLine ("ContentLength: " + res2.ContentLength);\r
- res2.Close ();\r
- \r
- ServicePoint sp2;\r
-#if FOUND_SOME_OTHER_URL\r
- // unless of course some buffering is taking place.. let's check\r
- Uri uri2 = new Uri ("http://freedesktop.org/Software/pkgconfig/releases/pkgconfig-0.15.0.tar.gz");\r
- sp2 = ServicePointManager.FindServicePoint (uri2);\r
- req2 = (HttpWebRequest) WebRequest.Create (uri2);\r
- async = req2.BeginGetResponse (null, null);\r
- //WriteServicePoint ("Large file: after async BeginGetResponse", sp2);\r
- // CurrentConnections: 1\r
- res2 = req2.EndGetResponse (async);\r
- //WriteServicePoint ("Large file: after async EndGetResponse", sp2);\r
- // CurrentConnections: 1\r
- // and so it shows\r
- //Console.WriteLine ("ContentLength: " + res2.ContentLength);\r
- res2.Close ();\r
-#endif\r
- \r
- \r
- // what's the limit of the cache?\r
- req2 = (HttpWebRequest) WebRequest.Create ("http://www.apache.org/");\r
- res2 = req2.GetResponse ();\r
- sp2 = ServicePointManager.FindServicePoint (new Uri("http://www.apache.org/"));\r
- //WriteServicePoint ("apache", sp2);\r
- //Console.WriteLine ("ContentLength: " + res2.ContentLength);\r
- // CurrentConnections: 1\r
- res2.Close ();\r
- // curious other effect: address is actually the full Uri of the previous request\r
- // anyways, buffer is probably 4096 bytes\r
- }\r
-\r
- // try getting the stream to 5 web response objects \r
- // while ConnectionLimit equals 2\r
-\r
- [Test]\r
- [Category ("InetAccess")]\r
- public void ConnectionLimit ()\r
- { \r
- // the default is already 2, just in case it isn't..\r
- ServicePointManager.DefaultConnectionLimit = 5;\r
- \r
- Uri uri = new Uri ("http://www.go-mono.com/");\r
- ServicePoint sp = ServicePointManager.FindServicePoint (uri); \r
- WebResponse [] res = new WebResponse [5];\r
- for (int i = 0; i < 5; i++) {\r
- //Console.WriteLine ("GOT1 : " + i);\r
- HttpWebRequest req = (HttpWebRequest) WebRequest.Create (uri);\r
- //Console.WriteLine ("GOT2 : " + i);\r
- res [i] = req.GetResponse ();\r
- //WriteServicePoint ("after getting " + (i + 1) + " web response objects", sp);\r
- }\r
- \r
- for (int i = 0; i < 5; i++) {\r
- Stream stream = res [i].GetResponseStream();\r
- //Console.WriteLine ("Reading stream: " + i + " : " + stream);\r
- int len = 0;\r
- while (stream.ReadByte () != -1)\r
- len++;\r
- //Console.WriteLine ("Finished reading: " + len + " bytes");\r
- }\r
- \r
- for (int i = 0; i < 5; i++) {\r
- res [i].Close ();\r
- }\r
- }\r
-\r
- [Test]\r
- [Category ("InetAccess")]\r
- [Category ("AndroidNotWorking")] // #A1 fails\r
- public void EndPointBind ()\r
- {\r
- Uri uri = new Uri ("http://www.go-mono.com/");\r
- ServicePoint sp = ServicePointManager.FindServicePoint (uri);\r
-\r
- HttpWebRequest req = (HttpWebRequest) WebRequest.Create (uri);\r
-\r
- bool called = false;\r
- sp.BindIPEndPointDelegate = delegate {\r
- Assert.IsTrue (!called);\r
- called = true;\r
- return null;\r
- };\r
- req.GetResponse ().Close ();\r
-\r
- Assert.IsTrue (called, "#A1");\r
-\r
- req = (HttpWebRequest) WebRequest.Create (uri);\r
- called = false;\r
- sp.BindIPEndPointDelegate = delegate(ServicePoint point, IPEndPoint remote, int times) {\r
- Assert.IsTrue (times < 5);\r
- called = true;\r
- return new IPEndPoint(IPAddress.Parse("0.0.0.0"), 12345 + times);\r
- };\r
- req.GetResponse ().Close ();\r
-\r
- Assert.IsTrue (called, "#A2");\r
- }\r
-\r
- public static void GetRequestStreamCallback (IAsyncResult asynchronousResult)\r
- {\r
- }\r
-\r
- [Test] //Covers #19823\r
-#if FEATURE_NO_BSD_SOCKETS\r
- // This test uses HttpWebRequest\r
- [ExpectedException (typeof (PlatformNotSupportedException))]\r
-#endif\r
- public void CloseConnectionGroupConcurency ()\r
- {\r
- // Try with multiple service points\r
- for (var i = 0; i < 10; i++) {\r
- Uri targetUri = new Uri ("http://" + i + ".mono-project.com");\r
- var req = (HttpWebRequest) HttpWebRequest.Create (targetUri);\r
- req.ContentType = "application/x-www-form-urlencoded";\r
- req.Method = "POST";\r
- req.ConnectionGroupName = "" + i;\r
- req.ServicePoint.MaxIdleTime = 1;\r
-\r
- req.BeginGetRequestStream (new AsyncCallback (GetRequestStreamCallback), req);\r
- Thread.Sleep (1);\r
- req.ServicePoint.CloseConnectionGroup (req.ConnectionGroupName);\r
- }\r
- }\r
-\r
-\r
- [Test]\r
- [Category ("RequiresBSDSockets")] // Tests internals, so it doesn't make sense to assert that PlatformNotSupportedExceptions are thrown.\r
- public void DnsRefreshTimeout ()\r
- {\r
- const int dnsRefreshTimeout = 2000;\r
-\r
- ServicePoint sp;\r
- IPHostEntry host0, host1, host2;\r
- Uri uri;\r
- PropertyInfo hostEntryProperty;\r
-\r
- ServicePointManager.DnsRefreshTimeout = dnsRefreshTimeout;\r
-\r
- uri = new Uri ("http://localhost/");\r
- sp = ServicePointManager.FindServicePoint (uri);\r
-\r
- hostEntryProperty = typeof (ServicePoint).GetProperty ("HostEntry", BindingFlags.NonPublic | BindingFlags.Instance);\r
-\r
- host0 = hostEntryProperty.GetValue (sp, null) as IPHostEntry;\r
- host1 = hostEntryProperty.GetValue (sp, null) as IPHostEntry;\r
-\r
- Assert.AreSame (host0, host1, "HostEntry should result in the same IPHostEntry object.");\r
-\r
- Thread.Sleep (dnsRefreshTimeout * 2);\r
- host2 = hostEntryProperty.GetValue (sp, null) as IPHostEntry;\r
-\r
- Assert.AreNotSame(host0, host2, "HostEntry should result in a new IPHostEntry " +\r
- "object when DnsRefreshTimeout is reached.");\r
- }\r
-\r
-// Debug code not used now, but could be useful later\r
-/*\r
- private void WriteServicePoint (string label, ServicePoint sp)\r
- {\r
- Console.WriteLine ("\n" + label);\r
- Console.WriteLine ("Address: " + sp.Address);\r
- Console.WriteLine ("ConnectionLimit: " + sp.ConnectionLimit);\r
- Console.WriteLine ("ConnectionName: " + sp.ConnectionName);\r
- Console.WriteLine ("CurrentConnections: " + sp.CurrentConnections);\r
- Console.WriteLine ("IdleSince: " + sp.IdleSince);\r
- Console.WriteLine ("MaxIdletime: " + sp.MaxIdleTime);\r
- Console.WriteLine ("ProtocolVersion: " + sp.ProtocolVersion);\r
- Console.WriteLine ("SupportsPipelining: " + sp.SupportsPipelining); \r
- }\r
-*/\r
-}\r
-}\r
-\r
+//
+// ServicePointTest.cs - NUnit Test Cases for System.Net.ServicePoint
+//
+// Authors:
+// Lawrence Pit (loz@cable.a2000.nl)
+// Martin Willemoes Hansen (mwh@sysrq.dk)
+//
+// (C) 2003 Martin Willemoes Hansen
+//
+
+using NUnit.Framework;
+using System;
+using System.Collections;
+using System.IO;
+using System.Net;
+using System.Reflection;
+using System.Threading;
+
+namespace MonoTests.System.Net
+{
+
+[TestFixture]
+public class ServicePointTest
+{
+ static private int max;
+
+#if !FEATURE_NO_BSD_SOCKETS
+ [SetUp]
+ public void SaveMax () {
+ max = ServicePointManager.MaxServicePoints;
+ ServicePointManager.MaxServicePoints = 0;
+ }
+
+ [TearDown]
+ public void RestoreMax () {
+ ServicePointManager.MaxServicePoints = max;
+ }
+#endif
+
+ [Test]
+ [Category ("NotWorking")]
+ public void All ()
+ {
+ ServicePoint p = ServicePointManager.FindServicePoint (new Uri ("mailto:xx@yyy.com"));
+ //WriteServicePoint ("A servicepoint that isn't really", p);
+
+ ServicePointManager.MaxServicePoints = 2;
+ ServicePoint google = ServicePointManager.FindServicePoint (new Uri ("http://www.google.com"));
+ try {
+ ServicePoint slashdot = ServicePointManager.FindServicePoint (new Uri ("http://www.slashdot.org"));
+ Assert.Fail ("#1");
+ } catch (InvalidOperationException) { }
+ ServicePointManager.MaxServicePoints = 0;
+
+ //WriteServicePoint ("google before getting a webrequest", google);
+
+ HttpWebRequest req = (HttpWebRequest) WebRequest.Create ("http://www.google.com");
+ HttpWebResponse res = (HttpWebResponse) req.GetResponse ();
+
+#if FOUND_SOME_OTHER_URL
+ // URL is no longer found, disabled the test until a more reliable URL is found :P
+ //WriteServicePoint ("google after getting a response", google);
+ ServicePoint google2 = ServicePointManager.FindServicePoint (new Uri ("http://www.google.com/dilbert.html"));
+ Assert.AreEqual (google, google2, "#equals");
+ res.Close ();
+#endif
+
+ // in both instances property CurrentConnections is 0 according to ms.net.
+ // let's see what it says when we do async operations...
+
+ HttpWebRequest req2 = (HttpWebRequest) WebRequest.Create ("http://www.google.com");
+ req2.Method = "PUT";
+ IAsyncResult async = req2.BeginGetRequestStream (null, null);
+ //WriteServicePoint ("after async BeginGetRequestStream", google);
+ // CurrentConnections: 1
+ Stream stream2 = req2.EndGetRequestStream (async);
+ //WriteServicePoint ("after async EndGetRequestStream", google);
+ // CurrentConnections: 1
+ stream2.Close ();
+
+ req2 = (HttpWebRequest) WebRequest.Create ("http://www.google.com");
+ async = req2.BeginGetResponse (null, null);
+ //WriteServicePoint ("after async BeginGetResponse", google);
+ // CurrentConnections: 2
+ WebResponse res2 = req2.EndGetResponse (async);
+ //WriteServicePoint ("after async EndGetResponse", google);
+ // CurrentConnections: 0
+ // curious that after you get the webresponse object CurrentConnections is set to 0.
+ // you'd think that you'd still be connected until you close the webresponse..
+ //Console.WriteLine ("ContentLength: " + res2.ContentLength);
+ res2.Close ();
+
+ ServicePoint sp2;
+#if FOUND_SOME_OTHER_URL
+ // unless of course some buffering is taking place.. let's check
+ Uri uri2 = new Uri ("http://freedesktop.org/Software/pkgconfig/releases/pkgconfig-0.15.0.tar.gz");
+ sp2 = ServicePointManager.FindServicePoint (uri2);
+ req2 = (HttpWebRequest) WebRequest.Create (uri2);
+ async = req2.BeginGetResponse (null, null);
+ //WriteServicePoint ("Large file: after async BeginGetResponse", sp2);
+ // CurrentConnections: 1
+ res2 = req2.EndGetResponse (async);
+ //WriteServicePoint ("Large file: after async EndGetResponse", sp2);
+ // CurrentConnections: 1
+ // and so it shows
+ //Console.WriteLine ("ContentLength: " + res2.ContentLength);
+ res2.Close ();
+#endif
+
+
+ // what's the limit of the cache?
+ req2 = (HttpWebRequest) WebRequest.Create ("http://www.apache.org/");
+ res2 = req2.GetResponse ();
+ sp2 = ServicePointManager.FindServicePoint (new Uri("http://www.apache.org/"));
+ //WriteServicePoint ("apache", sp2);
+ //Console.WriteLine ("ContentLength: " + res2.ContentLength);
+ // CurrentConnections: 1
+ res2.Close ();
+ // curious other effect: address is actually the full Uri of the previous request
+ // anyways, buffer is probably 4096 bytes
+ }
+
+ // try getting the stream to 5 web response objects
+ // while ConnectionLimit equals 2
+
+ [Test]
+ [Category ("NotWorking")]
+ public void ConnectionLimit ()
+ {
+ // the default is already 2, just in case it isn't..
+ ServicePointManager.DefaultConnectionLimit = 5;
+
+ Uri uri = new Uri ("http://www.go-mono.com/");
+ ServicePoint sp = ServicePointManager.FindServicePoint (uri);
+ WebResponse [] res = new WebResponse [5];
+ for (int i = 0; i < 5; i++) {
+ //Console.WriteLine ("GOT1 : " + i);
+ HttpWebRequest req = (HttpWebRequest) WebRequest.Create (uri);
+ //Console.WriteLine ("GOT2 : " + i);
+ res [i] = req.GetResponse ();
+ //WriteServicePoint ("after getting " + (i + 1) + " web response objects", sp);
+ }
+
+ for (int i = 0; i < 5; i++) {
+ Stream stream = res [i].GetResponseStream();
+ //Console.WriteLine ("Reading stream: " + i + " : " + stream);
+ int len = 0;
+ while (stream.ReadByte () != -1)
+ len++;
+ //Console.WriteLine ("Finished reading: " + len + " bytes");
+ }
+
+ for (int i = 0; i < 5; i++) {
+ res [i].Close ();
+ }
+ }
+
+ [Test]
+ [Category ("NotWorking")] // #A1 fails
+ public void EndPointBind ()
+ {
+ Uri uri = new Uri ("http://www.go-mono.com/");
+ ServicePoint sp = ServicePointManager.FindServicePoint (uri);
+
+ HttpWebRequest req = (HttpWebRequest) WebRequest.Create (uri);
+
+ bool called = false;
+ sp.BindIPEndPointDelegate = delegate {
+ Assert.IsTrue (!called);
+ called = true;
+ return null;
+ };
+ req.GetResponse ().Close ();
+
+ Assert.IsTrue (called, "#A1");
+
+ req = (HttpWebRequest) WebRequest.Create (uri);
+ called = false;
+ sp.BindIPEndPointDelegate = delegate(ServicePoint point, IPEndPoint remote, int times) {
+ Assert.IsTrue (times < 5);
+ called = true;
+ return new IPEndPoint(IPAddress.Parse("0.0.0.0"), 12345 + times);
+ };
+ req.GetResponse ().Close ();
+
+ Assert.IsTrue (called, "#A2");
+ }
+
+ public static void GetRequestStreamCallback (IAsyncResult asynchronousResult)
+ {
+ }
+
+ [Test] //Covers #19823
+#if FEATURE_NO_BSD_SOCKETS
+ // This test uses HttpWebRequest
+ [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
+ public void CloseConnectionGroupConcurency ()
+ {
+ // Try with multiple service points
+ for (var i = 0; i < 10; i++) {
+ Uri targetUri = new Uri ("http://" + i + ".mono-project.com");
+ var req = (HttpWebRequest) HttpWebRequest.Create (targetUri);
+ req.ContentType = "application/x-www-form-urlencoded";
+ req.Method = "POST";
+ req.ConnectionGroupName = "" + i;
+ req.ServicePoint.MaxIdleTime = 1;
+
+ req.BeginGetRequestStream (new AsyncCallback (GetRequestStreamCallback), req);
+ Thread.Sleep (1);
+ req.ServicePoint.CloseConnectionGroup (req.ConnectionGroupName);
+ }
+ }
+
+
+ [Test]
+ [Category ("RequiresBSDSockets")] // Tests internals, so it doesn't make sense to assert that PlatformNotSupportedExceptions are thrown.
+ public void DnsRefreshTimeout ()
+ {
+ const int dnsRefreshTimeout = 2000;
+
+ ServicePoint sp;
+ IPHostEntry host0, host1, host2;
+ Uri uri;
+ PropertyInfo hostEntryProperty;
+
+ ServicePointManager.DnsRefreshTimeout = dnsRefreshTimeout;
+
+ uri = new Uri ("http://localhost/");
+ sp = ServicePointManager.FindServicePoint (uri);
+
+ hostEntryProperty = typeof (ServicePoint).GetProperty ("HostEntry", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ host0 = hostEntryProperty.GetValue (sp, null) as IPHostEntry;
+ host1 = hostEntryProperty.GetValue (sp, null) as IPHostEntry;
+
+ Assert.AreSame (host0, host1, "HostEntry should result in the same IPHostEntry object.");
+
+ Thread.Sleep (dnsRefreshTimeout * 2);
+ host2 = hostEntryProperty.GetValue (sp, null) as IPHostEntry;
+
+ Assert.AreNotSame(host0, host2, "HostEntry should result in a new IPHostEntry " +
+ "object when DnsRefreshTimeout is reached.");
+ }
+
+// Debug code not used now, but could be useful later
+/*
+ private void WriteServicePoint (string label, ServicePoint sp)
+ {
+ Console.WriteLine ("\n" + label);
+ Console.WriteLine ("Address: " + sp.Address);
+ Console.WriteLine ("ConnectionLimit: " + sp.ConnectionLimit);
+ Console.WriteLine ("ConnectionName: " + sp.ConnectionName);
+ Console.WriteLine ("CurrentConnections: " + sp.CurrentConnections);
+ Console.WriteLine ("IdleSince: " + sp.IdleSince);
+ Console.WriteLine ("MaxIdletime: " + sp.MaxIdleTime);
+ Console.WriteLine ("ProtocolVersion: " + sp.ProtocolVersion);
+ Console.WriteLine ("SupportsPipelining: " + sp.SupportsPipelining);
+ }
+*/
+}
+}
+
}
[Test]
- [Category ("InetAccess")]
public void DownloadTwice ()
{
WebClient wc = new WebClient();
}
[Test]
- [Category("InetAccess")]
public void DownloadFileTaskAsync ()
{
WebClient wc = new WebClient ();
}
[Test]
- [Category("InetAccess")]
- [Category ("AndroidNotWorking")] // Fails when ran as part of the entire BCL test suite. Works when only this fixture is ran
+ [Category ("NotWorking")] // Fails when ran as part of the entire BCL test suite. Works when only this fixture is ran
public void Cancellation ()
{
WebClient wc = new WebClient ();
}
[Test]
- [Category("InetAccess")]
- [Category ("AndroidNotWorking")] // Fails when ran as part of the entire BCL test suite. Works when only this fixture is ran
+ [Category ("NotWorking")] // Fails when ran as part of the entire BCL test suite. Works when only this fixture is ran
public void DownloadMultiple ()
{
WebClient wc = new WebClient ();
}
[Test]
- [Category("InetAccess")]
- [Category ("AndroidNotWorking")] // Fails when ran as part of the entire BCL test suite. Works when only this fixture is ran
+ [Category ("NotWorking")] // Fails when ran as part of the entire BCL test suite. Works when only this fixture is ran
public void DownloadMultiple2 ()
{
WebClient wc = new WebClient ();
}
[Test]
- [Category("InetAccess")]
- [Category ("AndroidNotWorking")] // Fails when ran as part of the entire BCL test suite. Works when only this fixture is ran
+ [Category ("NotWorking")] // Fails when ran as part of the entire BCL test suite. Works when only this fixture is ran
public void DownloadMultiple3 ()
{
WebClient wc = new WebClient ();
}
[Test]
- [Category ("InetAccess")]
public void Build_Cert1_X509RevocationMode_Online ()
{
X509Chain c = new X509Chain ();
Assert.IsNull (enumBuilder.DeclaringType, "#3");
Assert.IsNull (enumBuilder.ReflectedType, "#4");
Assert.AreEqual (_enumType, enumBuilder.UnderlyingSystemType, "#5");
- }
-
- [Test]
- [Category ("ValueAdd")]
- public void TestEnumBuilder_NotInMono ()
- {
- // If we decide to fix this (I dont see why we should),
- // move to the routine above
-
- EnumBuilder enumBuilder = GenerateEnum ();
Assert.IsFalse (enumBuilder.IsSerializable);
}
[Test]
[ExpectedException (typeof (NotSupportedException))]
- [Category ("ValueAdd")]
public void TestFindMembersIncomplete ()
{
EnumBuilder enumBuilder = GenerateEnum ();
[Test]
[ExpectedException (typeof (NotSupportedException))]
- [Category ("ValueAdd")]
public void TestGetConstructorIncomplete ()
{
EnumBuilder enumBuilder = GenerateEnum ();
[Test]
public void GetGenericMethodDefinitionOverInflatedMethodOnGTD () {
+ var s = new List<int> () { 1, 2, 3 }.ConvertAll ( i => i.ToString () );
+ Assert.AreEqual (3, s.Count);
var l = typeof (List<>);
var m = l.GetMethod ("ConvertAll");
var infl = m.MakeGenericMethod (typeof (int));
var res = m.GetGenericMethodDefinition ();
Assert.AreEqual (m, res, "#1");
+ Assert.AreEqual (1, infl.GetGenericArguments().Length, "#2");
}
[Test]
Assert.That(arg1, Is.LessThanOrEqualTo(arg2), message, args);
}
+ public static void LessOrEqual(long arg1, long arg2, string message = null, params object[] args)
+ {
+ Assert.That(arg1, Is.LessThanOrEqualTo(arg2), message, args);
+ }
+
+ public static void LessOrEqual(System.DateTime arg1, System.DateTime arg2, string message = null, params object[] args)
+ {
+ Assert.That(arg1, Is.LessThanOrEqualTo(arg2), message, args);
+ }
+
+ public static void LessOrEqual(System.TimeSpan arg1, System.TimeSpan arg2, string message = null, params object[] args)
+ {
+ Assert.That(arg1, Is.LessThanOrEqualTo(arg2), message, args);
+ }
+
public static void IsNotInstanceOfType(System.Type expected, object actual, string message, params object[] args )
{
Assert.IsFalse (actual.GetType ().IsInstanceOfType (expected), message, args);
parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
{
const gchar *pkey;
- gchar header [16], val, *arr;
+ gchar header [16], val, *arr, *endp;
gint i, j, offset, bitlen, keylen, pkeylen;
keylen = strlen (key) >> 1;
if (!pubkey)
return TRUE;
+ arr = (gchar *)g_malloc (keylen + 4);
/* Encode the size of the blob */
- offset = 0;
- if (keylen <= 127) {
- arr = (gchar *)g_malloc (keylen + 1);
- arr [offset++] = keylen;
- } else {
- arr = (gchar *)g_malloc (keylen + 2);
- arr [offset++] = 0x80; /* 10bs */
- arr [offset++] = keylen;
- }
+ mono_metadata_encode_value (keylen, &arr[0], &endp);
+ offset = (gint)(endp-arr);
for (i = offset, j = 0; i < keylen + offset; i++) {
arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
static void
on_gc_notification (GC_EventType event)
{
- MonoProfilerGCEvent e = (MonoProfilerGCEvent)event;
+ MonoProfilerGCEvent e;
- switch (e) {
- case MONO_GC_EVENT_PRE_STOP_WORLD:
+ switch (event) {
+ case GC_EVENT_PRE_STOP_WORLD:
+ e = MONO_GC_EVENT_PRE_STOP_WORLD;
MONO_GC_WORLD_STOP_BEGIN ();
break;
- case MONO_GC_EVENT_POST_STOP_WORLD:
+ case GC_EVENT_POST_STOP_WORLD:
+ e = MONO_GC_EVENT_POST_STOP_WORLD;
MONO_GC_WORLD_STOP_END ();
break;
- case MONO_GC_EVENT_PRE_START_WORLD:
+ case GC_EVENT_PRE_START_WORLD:
+ e = MONO_GC_EVENT_PRE_START_WORLD;
MONO_GC_WORLD_RESTART_BEGIN (1);
break;
- case MONO_GC_EVENT_POST_START_WORLD:
+ case GC_EVENT_POST_START_WORLD:
+ e = MONO_GC_EVENT_POST_START_WORLD;
MONO_GC_WORLD_RESTART_END (1);
break;
- case MONO_GC_EVENT_START:
+ case GC_EVENT_START:
+ e = MONO_GC_EVENT_START;
MONO_GC_BEGIN (1);
#ifndef DISABLE_PERFCOUNTERS
if (mono_perfcounters)
gc_start_time = mono_100ns_ticks ();
break;
- case MONO_GC_EVENT_END:
+ case GC_EVENT_END:
+ e = MONO_GC_EVENT_END;
MONO_GC_END (1);
#if defined(ENABLE_DTRACE) && defined(__sun__)
/* This works around a dtrace -G problem on Solaris.
break;
}
- MONO_PROFILER_RAISE (gc_event, (e, 0));
+ switch (event) {
+ case GC_EVENT_MARK_START:
+ case GC_EVENT_MARK_END:
+ case GC_EVENT_RECLAIM_START:
+ case GC_EVENT_RECLAIM_END:
+ break;
+ default:
+ MONO_PROFILER_RAISE (gc_event, (e, 0));
+ break;
+ }
- switch (e) {
- case MONO_GC_EVENT_PRE_STOP_WORLD:
+ switch (event) {
+ case GC_EVENT_PRE_STOP_WORLD:
mono_thread_info_suspend_lock ();
MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, 0));
break;
- case MONO_GC_EVENT_POST_START_WORLD:
+ case GC_EVENT_POST_START_WORLD:
mono_thread_info_suspend_unlock ();
MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_POST_START_WORLD_UNLOCKED, 0));
break;
#include <mono/metadata/class-internals.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/reflection.h>
-#include <mono/metadata/profiler.h>
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/exception.h>
#include <mono/metadata/marshal.h>
MONO_PROFILER_EVENT_1(gc_resize, GCResize, uintptr_t, size)
MONO_PROFILER_EVENT_3(gc_handle_created, GCHandleCreated, uint32_t, handle, MonoGCHandleType, type, MonoObject *, object)
MONO_PROFILER_EVENT_2(gc_handle_deleted, GCHandleDeleted, uint32_t, handle, MonoGCHandleType, type)
-MONO_PROFILER_EVENT_4(gc_roots, GCRoots, MonoObject *const *, roots, const MonoProfilerGCRootType *, types, const uintptr_t *, extra, uint64_t, count)
MONO_PROFILER_EVENT_0(gc_finalizing, GCFinalizing)
MONO_PROFILER_EVENT_0(gc_finalized, GCFinalized)
MONO_PROFILER_EVENT_1(gc_finalizing_object, GCFinalizingObject, MonoObject *, object)
MONO_PROFILER_EVENT_1(gc_finalized_object, GCFinalizedObject, MonoObject *, object)
+/*
+ * This callback provides very low quality data and doesn't really match how
+ * roots are actually handled in the runtime. It will be replaced with a more
+ * sensible callback in the future. **This will be a breaking change.**
+ *
+ * In the meantime, you must define MONO_PROFILER_UNSTABLE_GC_ROOTS to be able
+ * to use this interface.
+ */
+#ifdef MONO_PROFILER_UNSTABLE_GC_ROOTS
+MONO_PROFILER_EVENT_4(gc_roots, GCRoots, MonoObject *const *, roots, const MonoProfilerGCRootType *, types, const uintptr_t *, extra, uint64_t, count)
+#endif
+
MONO_PROFILER_EVENT_1(monitor_contention, MonitorContention, MonoObject *, object)
MONO_PROFILER_EVENT_1(monitor_failed, MonitorFailed, MonoObject *, object)
MONO_PROFILER_EVENT_1(monitor_acquired, MonitorAcquired, MonoObject *, object)
#ifndef __MONO_PROFILER_PRIVATE_H__
#define __MONO_PROFILER_PRIVATE_H__
+#define MONO_PROFILER_UNSTABLE_GC_ROOTS
#include <mono/metadata/profiler.h>
#include <mono/utils/mono-lazy-init.h>
#include <mono/utils/mono-os-mutex.h>
MonoProfilerHandle sampling_owner;
MonoSemType sampling_semaphore;
MonoProfilerSampleMode sample_mode;
- uint64_t sample_freq;
+ guint32 sample_freq;
gboolean allocations;
#define _MONO_PROFILER_EVENT(name) \
gboolean mono_profiler_should_instrument_method (MonoMethod *method, gboolean entry);
gboolean mono_profiler_sampling_enabled (void);
-void mono_profiler_sampling_thread_sleep (void);
+void mono_profiler_sampling_thread_post (void);
+void mono_profiler_sampling_thread_wait (void);
static inline gboolean
mono_profiler_allocations_enabled (void)
#include <mono/metadata/profiler-private.h>
#include <mono/utils/mono-dl.h>
#include <mono/utils/mono-error-internals.h>
+#include <mono/utils/mono-logger-internals.h>
MonoProfilerState mono_profiler_state;
char *err;
if (!(err = mono_dl_symbol (module, old_name, (gpointer) &func))) {
- g_warning ("Found old-style startup symbol %s; profiler has not been migrated to the new API.", old_name);
+ mono_profiler_printf_err ("Found old-style startup symbol %s for %s; profiler has not been migrated to the new API.", old_name, desc);
g_free (old_name);
return FALSE;
}
MonoDl *module = mono_dl_open (NULL, MONO_DL_EAGER, &err);
if (!module) {
- g_warning ("Could not open main executable (%s).", err);
+ mono_profiler_printf_err ("Could not open main executable: %s", err);
g_free (err);
return FALSE;
}
void
mono_profiler_load (const char *desc)
{
- mono_gc_base_init ();
-
if (!desc || !strcmp ("default", desc))
desc = "log:report";
res = load_profiler_from_directory (NULL, libname, desc);
if (!res)
- g_warning ("The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname);
+ mono_profiler_printf_err ("The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname);
g_free (libname);
}
}
mono_bool
-mono_profiler_set_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode mode, uint64_t freq)
+mono_profiler_set_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode mode, uint32_t freq)
{
if (handle != mono_profiler_state.sampling_owner)
return FALSE;
mono_profiler_state.sample_mode = mode;
mono_profiler_state.sample_freq = freq;
- mono_os_sem_post (&mono_profiler_state.sampling_semaphore);
+ mono_profiler_sampling_thread_post ();
return TRUE;
}
mono_bool
-mono_profiler_get_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode *mode, uint64_t *freq)
+mono_profiler_get_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode *mode, uint32_t *freq)
{
if (mode)
*mode = mono_profiler_state.sample_mode;
}
void
-mono_profiler_sampling_thread_sleep (void)
+mono_profiler_sampling_thread_post (void)
+{
+ mono_os_sem_post (&mono_profiler_state.sampling_semaphore);
+}
+
+void
+mono_profiler_sampling_thread_wait (void)
{
mono_os_sem_wait (&mono_profiler_state.sampling_semaphore, MONO_SEM_FLAGS_NONE);
}
MONO_API mono_bool mono_profiler_enable_sampling (MonoProfilerHandle handle);
/*
- * Sets the sampling mode and frequency (in Hz). If the calling profiler has
- * ownership over sampling settings, the settings will be changed and this
- * function will return TRUE; otherwise, it returns FALSE without changing any
- * settings.
+ * Sets the sampling mode and frequency (in Hz). The frequency must be a
+ * positive number. If the calling profiler has ownership over sampling
+ * settings, the settings will be changed and this function will return TRUE;
+ * otherwise, it returns FALSE without changing any settings.
*
* This function is async safe.
*/
-MONO_API mono_bool mono_profiler_set_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode mode, uint64_t freq);
+MONO_API mono_bool mono_profiler_set_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode mode, uint32_t freq);
/*
* Retrieves the current sampling mode and/or frequency (in Hz). Returns TRUE if
*
* This function is async safe.
*/
-MONO_API mono_bool mono_profiler_get_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode *mode, uint64_t *freq);
+MONO_API mono_bool mono_profiler_get_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode *mode, uint32_t *freq);
/*
* Enables instrumentation of GC allocations. This is necessary so that managed
*/
MONO_API void mono_profiler_set_call_instrumentation_filter_callback (MonoProfilerHandle handle, MonoProfilerCallInstrumentationFilterCallback cb);
+#ifdef MONO_PROFILER_UNSTABLE_GC_ROOTS
typedef enum {
/* Upper 2 bytes. */
MONO_PROFILER_GC_ROOT_PINNING = 1 << 8,
MONO_PROFILER_GC_ROOT_TYPEMASK = 0xff,
} MonoProfilerGCRootType;
+#endif
typedef enum {
/* data = MonoMethod *method */
MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING = 9,
} MonoProfilerCodeBufferType;
-// Keep somewhat in sync with libgc/include/gc.h : GC_EventType.
typedef enum {
- MONO_GC_EVENT_START = 0,
- MONO_GC_EVENT_MARK_START = 1,
- MONO_GC_EVENT_MARK_END = 2,
- MONO_GC_EVENT_RECLAIM_START = 3,
- MONO_GC_EVENT_RECLAIM_END = 4,
- MONO_GC_EVENT_END = 5,
MONO_GC_EVENT_PRE_STOP_WORLD = 6,
/* When this event arrives, the GC and suspend locks are acquired. */
MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED = 10,
MONO_GC_EVENT_POST_STOP_WORLD = 7,
+ MONO_GC_EVENT_START = 0,
+ MONO_GC_EVENT_END = 5,
MONO_GC_EVENT_PRE_START_WORLD = 8,
/* When this event arrives, the GC and suspend locks are released. */
MONO_GC_EVENT_POST_START_WORLD_UNLOCKED = 11,
static void G_GNUC_UNUSED
sgen_client_binary_protocol_mark_start (int generation)
{
- MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_MARK_START, generation));
}
static void G_GNUC_UNUSED
sgen_client_binary_protocol_mark_end (int generation)
{
- MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_MARK_END, generation));
}
static void G_GNUC_UNUSED
sgen_client_binary_protocol_reclaim_start (int generation)
{
- MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_RECLAIM_START, generation));
}
static void G_GNUC_UNUSED
sgen_client_binary_protocol_reclaim_end (int generation)
{
- MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_RECLAIM_END, generation));
}
static void
#include <mono/metadata/object.h>
#include <mono/metadata/exception.h>
#include <mono/metadata/debug-helpers.h>
-#include <mono/metadata/profiler.h>
-#include <mono/metadata/profiler-private.h>
#include <mono/metadata/gc-internals.h>
/* This function is redirected to String.CreateString ()
#define WSAEHOSTDOWN 10064
#define WSAEHOSTUNREACH 10065
#define WSASYSCALLFAILURE 10107
+#define WSAENXIO 100001
#endif
mono_w32file_get_disk_free_space (const gunichar2 *path_name, guint64 *free_bytes_avail, guint64 *total_number_of_bytes, guint64 *total_number_of_free_bytes)
{
gboolean result;
- ULARGE_INTEGER *wapi_free_bytes_avail;
- ULARGE_INTEGER *wapi_total_number_of_bytes;
- ULARGE_INTEGER *wapi_total_number_of_free_bytes;
+ ULARGE_INTEGER wapi_free_bytes_avail;
+ ULARGE_INTEGER wapi_total_number_of_bytes;
+ ULARGE_INTEGER wapi_total_number_of_free_bytes;
MONO_ENTER_GC_SAFE;
- result = GetDiskFreeSpaceEx (path_name, wapi_free_bytes_avail, wapi_total_number_of_bytes, wapi_total_number_of_free_bytes);
+ result = GetDiskFreeSpaceEx (path_name, &wapi_free_bytes_avail, &wapi_total_number_of_bytes, &wapi_total_number_of_free_bytes);
MONO_EXIT_GC_SAFE;
if (result) {
if (free_bytes_avail)
- *free_bytes_avail = wapi_free_bytes_avail->QuadPart;
+ *free_bytes_avail = wapi_free_bytes_avail.QuadPart;
if (total_number_of_bytes)
- *total_number_of_bytes = wapi_total_number_of_bytes->QuadPart;
+ *total_number_of_bytes = wapi_total_number_of_bytes.QuadPart;
if (total_number_of_free_bytes)
- *total_number_of_free_bytes = wapi_total_number_of_free_bytes->QuadPart;
+ *total_number_of_free_bytes = wapi_total_number_of_free_bytes.QuadPart;
}
return result;
case ENODEV: return WSAENETDOWN;
#ifdef EPROTOTYPE
case EPROTOTYPE: return WSAEPROTOTYPE;
+#endif
+#ifdef ENXIO
+ case ENXIO: return WSAENXIO;
#endif
default:
g_error ("%s: no translation into winsock error for (%d) \"%s\"", __func__, error, g_strerror (error));
#ifdef ENABLE_LLVM
if (acfg->llvm) {
llvm_acfg = acfg;
- mono_llvm_create_aot_module (acfg->image->assembly, acfg->global_prefix, TRUE, acfg->aot_opts.static_link, acfg->aot_opts.llvm_only);
+ mono_llvm_create_aot_module (acfg->image->assembly, acfg->global_prefix, acfg->nshared_got_entries, TRUE, acfg->aot_opts.static_link, acfg->aot_opts.llvm_only);
}
#endif
#include <mono/metadata/marshal.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/debug-helpers.h>
-#include "mono/metadata/profiler.h"
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/environment.h>
pop
ret
}
+
+ .method public static int32 test_2_fault () cil managed
+ {
+ .maxstack 16
+ .locals init (int32 V_0)
+ IL_0000: ldc.i4.0
+ IL_0001: stloc.0
+ .try
+ {
+ .try
+ {
+ IL_0002: newobj instance void [mscorlib]System.Exception::.ctor()
+ IL_0007: throw
+ leave.s IL_0018
+ } // end .try
+ fault
+ {
+ IL_0009: ldloc.0
+ IL_000a: ldc.i4.1
+ IL_000b: add
+ IL_000c: stloc.0
+ endfinally
+ } // end handler
+ IL_000f: leave.s IL_0018
+
+ } // end .try
+ catch [mscorlib]System.Object
+ {
+ IL_0011: pop
+ IL_0012: ldloc.0
+ IL_0013: ldc.i4.1
+ IL_0014: add
+ IL_0015: stloc.0
+ IL_0016: leave.s IL_0018
+
+ } // end handler
+ IL_0018: ldloc.0
+ ret
+ }
+
+ .method public static int32 test_0_fault_no_exception () cil managed
+ {
+ .maxstack 16
+ .locals init (int32 V_0)
+ IL_0000: ldc.i4.0
+ IL_0001: stloc.0
+ .try
+ {
+ .try
+ {
+ leave.s IL_0018
+ } // end .try
+ fault
+ {
+ IL_0009: ldloc.0
+ IL_000a: ldc.i4.1
+ IL_000b: add
+ IL_000c: stloc.0
+ endfinally
+ } // end handler
+ IL_000f: leave.s IL_0018
+
+ } // end .try
+ catch [mscorlib]System.Object
+ {
+ IL_0011: pop
+ IL_0012: ldloc.0
+ IL_0013: ldc.i4.1
+ IL_0014: add
+ IL_0015: stloc.0
+ IL_0016: leave.s IL_0018
+
+ } // end handler
+ IL_0018: ldloc.0
+ ret
+ }
}
} else {
/* FIXME: maybe save the jit tls in the prolog */
}
- if (cfg->used_int_regs & (1 << AMD64_RBP)) {
+ if (cfg->used_int_regs & (1 << AMD64_RBP))
amd64_mov_reg_membase (code, AMD64_RBP, cfg->frame_reg, lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, rbp), 8);
- }
+ if (cfg->arch.omit_fp)
+ /*
+ * emit_setup_lmf () marks RBP as saved, we have to mark it as same value here before clearing up the stack
+ * since its stack slot will become invalid.
+ */
+ mono_emit_unwind_op_same_value (cfg, code, AMD64_RBP);
}
/* Restore callee saved regs */
if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->arch.saved_iregs & (1 << i))) {
/* Restore only used_int_regs, not arch.saved_iregs */
#if defined(MONO_SUPPORT_TASKLETS)
- int restore_reg=1;
+ int restore_reg = 1;
#else
- int restore_reg=(cfg->used_int_regs & (1 << i));
+ int restore_reg = (cfg->used_int_regs & (1 << i));
#endif
if (restore_reg) {
amd64_mov_reg_membase (code, i, cfg->frame_reg, save_area_offset, 8);
#include <mono/metadata/threads.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/debug-helpers.h>
-#include "mono/metadata/profiler.h"
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/gc-internals.h>
#include <mono/metadata/debug-internals.h>
#include <mono/metadata/mono-debug.h>
-#include <mono/metadata/profiler.h>
+#include <mono/metadata/profiler-private.h>
#include <mono/metadata/mono-endian.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/mono-mlist.h>
void (*cleanup)(void);
void (*emit_method)(MonoCompile *cfg);
void (*emit_call)(MonoCompile *cfg, MonoCallInst *call);
- void (*create_aot_module)(MonoAssembly *assembly, const char *global_prefix, gboolean emit_dwarf, gboolean static_link, gboolean llvm_only);
+ void (*create_aot_module)(MonoAssembly *assembly, const char *global_prefix, int initial_got_size, gboolean emit_dwarf, gboolean static_link, gboolean llvm_only);
void (*emit_aot_module)(const char *filename, const char *cu_name);
void (*check_method_supported)(MonoCompile *cfg);
void (*emit_aot_file_info)(MonoAotFileInfo *info, gboolean has_jitted_code);
}
void
-mono_llvm_create_aot_module (MonoAssembly *assembly, const char *global_prefix, gboolean emit_dwarf, gboolean static_link, gboolean llvm_only)
+mono_llvm_create_aot_module (MonoAssembly *assembly, const char *global_prefix, int initial_got_size, gboolean emit_dwarf, gboolean static_link, gboolean llvm_only)
{
- backend.create_aot_module (assembly, global_prefix, emit_dwarf, static_link, llvm_only);
+ backend.create_aot_module (assembly, global_prefix, initial_got_size, emit_dwarf, static_link, llvm_only);
}
void
clause = get_most_deep_clause (cfg, ctx, bb);
if (clause) {
- g_assert (clause->flags == MONO_EXCEPTION_CLAUSE_NONE || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY);
+ g_assert (clause->flags == MONO_EXCEPTION_CLAUSE_NONE || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY || clause->flags == MONO_EXCEPTION_CLAUSE_FAULT);
/*
* Have to use an invoke instead of a call, branching to the
* handler bblock of the clause containing this bblock.
*/
- g_assert (ec->flags == MONO_EXCEPTION_CLAUSE_NONE || ec->flags == MONO_EXCEPTION_CLAUSE_FINALLY);
+ g_assert (ec->flags == MONO_EXCEPTION_CLAUSE_NONE || ec->flags == MONO_EXCEPTION_CLAUSE_FINALLY || ec->flags == MONO_EXCEPTION_CLAUSE_FAULT);
tblock = cfg->cil_offset_to_bb [ec->handler_offset];
g_assert (tblock);
MonoExceptionClause *group_cursor = group_start;
for (int i = 0; i < group_size; i ++) {
- if (!(group_cursor->flags & MONO_EXCEPTION_CLAUSE_FINALLY))
+ if (!(group_cursor->flags & MONO_EXCEPTION_CLAUSE_FINALLY || group_cursor->flags & MONO_EXCEPTION_CLAUSE_FAULT))
finally_only = FALSE;
group_cursor++;
MonoExceptionClause *clause = &ctx->cfg->header->clauses [clause_index];
// Make exception available to catch blocks
- if (!(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
+ if (!(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY || clause->flags & MONO_EXCEPTION_CLAUSE_FAULT)) {
LLVMValueRef mono_exc = mono_llvm_emit_load_exception_call (ctx, ctx->builder);
g_assert (ctx->ex_var);
LLVMValueRef val, switch_ins, callee;
GSList *bb_list;
BBInfo *info;
+ gboolean is_fault = MONO_REGION_FLAGS (bb->region) == MONO_EXCEPTION_CLAUSE_FAULT;
- handler_bb = (MonoBasicBlock*)g_hash_table_lookup (ctx->region_to_handler, GUINT_TO_POINTER (mono_get_block_region_notry (cfg, bb->region)));
- g_assert (handler_bb);
- info = &bblocks [handler_bb->block_num];
- lhs = info->finally_ind;
- g_assert (lhs);
+ /*
+ * Fault clauses are like finally clauses, but they are only called if an exception is thrown.
+ */
+ if (!is_fault) {
+ handler_bb = (MonoBasicBlock*)g_hash_table_lookup (ctx->region_to_handler, GUINT_TO_POINTER (mono_get_block_region_notry (cfg, bb->region)));
+ g_assert (handler_bb);
+ info = &bblocks [handler_bb->block_num];
+ lhs = info->finally_ind;
+ g_assert (lhs);
- bb_list = info->call_handler_return_bbs;
+ bb_list = info->call_handler_return_bbs;
- resume_bb = gen_bb (ctx, "ENDFINALLY_RESUME_BB");
+ resume_bb = gen_bb (ctx, "ENDFINALLY_RESUME_BB");
- /* Load the finally variable */
- val = LLVMBuildLoad (builder, lhs, "");
+ /* Load the finally variable */
+ val = LLVMBuildLoad (builder, lhs, "");
- /* Reset the variable */
- LLVMBuildStore (builder, LLVMConstInt (LLVMInt32Type (), 0, FALSE), lhs);
+ /* Reset the variable */
+ LLVMBuildStore (builder, LLVMConstInt (LLVMInt32Type (), 0, FALSE), lhs);
- /* Branch to either resume_bb, or to the bblocks in bb_list */
- switch_ins = LLVMBuildSwitch (builder, val, resume_bb, g_slist_length (bb_list));
- /*
- * The other targets are added at the end to handle OP_CALL_HANDLER
- * opcodes processed later.
- */
- info->endfinally_switch_ins_list = g_slist_append_mempool (cfg->mempool, info->endfinally_switch_ins_list, switch_ins);
+ /* Branch to either resume_bb, or to the bblocks in bb_list */
+ switch_ins = LLVMBuildSwitch (builder, val, resume_bb, g_slist_length (bb_list));
+ /*
+ * The other targets are added at the end to handle OP_CALL_HANDLER
+ * opcodes processed later.
+ */
+ info->endfinally_switch_ins_list = g_slist_append_mempool (cfg->mempool, info->endfinally_switch_ins_list, switch_ins);
- builder = ctx->builder = create_builder (ctx);
- LLVMPositionBuilderAtEnd (ctx->builder, resume_bb);
+ builder = ctx->builder = create_builder (ctx);
+ LLVMPositionBuilderAtEnd (ctx->builder, resume_bb);
+ }
if (ctx->llvm_only) {
emit_resume_eh (ctx, bb);
header = cfg->header;
for (i = 0; i < header->num_clauses; ++i) {
clause = &header->clauses [i];
- if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_NONE) {
- set_failure (ctx, "non-finally/catch clause.");
+ if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT && clause->flags != MONO_EXCEPTION_CLAUSE_NONE) {
+ set_failure (ctx, "non-finally/catch/fault clause.");
return;
}
}
}
void
-mono_llvm_create_aot_module (MonoAssembly *assembly, const char *global_prefix, gboolean emit_dwarf, gboolean static_link, gboolean llvm_only)
+mono_llvm_create_aot_module (MonoAssembly *assembly, const char *global_prefix, int initial_got_size, gboolean emit_dwarf, gboolean static_link, gboolean llvm_only)
{
MonoLLVMModule *module = &aot_module;
module->static_link = static_link;
module->llvm_only = llvm_only;
/* The first few entries are reserved */
- module->max_got_offset = 16;
+ module->max_got_offset = initial_got_size;
module->context = LLVMGetGlobalContext ();
if (llvm_only)
void mono_llvm_cleanup (void) MONO_LLVM_INTERNAL;
void mono_llvm_emit_method (MonoCompile *cfg) MONO_LLVM_INTERNAL;
void mono_llvm_emit_call (MonoCompile *cfg, MonoCallInst *call) MONO_LLVM_INTERNAL;
-void mono_llvm_create_aot_module (MonoAssembly *assembly, const char *global_prefix, gboolean emit_dwarf, gboolean static_link, gboolean llvm_only) MONO_LLVM_INTERNAL;
+void mono_llvm_create_aot_module (MonoAssembly *assembly, const char *global_prefix, int initial_got_size, gboolean emit_dwarf, gboolean static_link, gboolean llvm_only) MONO_LLVM_INTERNAL;
void mono_llvm_emit_aot_module (const char *filename, const char *cu_name) MONO_LLVM_INTERNAL;
void mono_llvm_emit_aot_file_info (MonoAotFileInfo *info, gboolean has_jitted_code) MONO_LLVM_INTERNAL;
void mono_llvm_emit_aot_data (const char *symbol, guint8 *data, int data_len) MONO_LLVM_INTERNAL;
#include <mono/metadata/threads.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/debug-helpers.h>
-#include "mono/metadata/profiler.h"
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/environment.h>
mono_profiler_get_sample_mode (NULL, &mode, NULL);
if (mode == MONO_PROFILER_SAMPLE_MODE_NONE) {
- mono_profiler_sampling_thread_sleep ();
+ mono_profiler_sampling_thread_wait ();
+
+ if (!InterlockedRead (&sampling_thread_running))
+ goto done;
+
goto init;
}
clock_init (mode);
for (guint64 sleep = clock_get_time_ns (); InterlockedRead (&sampling_thread_running); clock_sleep_ns_abs (sleep)) {
- uint64_t freq;
+ uint32_t freq;
MonoProfilerSampleMode new_mode;
mono_profiler_get_sample_mode (NULL, &new_mode, &freq);
} FOREACH_THREAD_SAFE_END
}
- InterlockedWrite (&sampling_thread_exiting, 1);
-
clock_cleanup ();
+done:
+ InterlockedWrite (&sampling_thread_exiting, 1);
+
pthread_setschedparam (pthread_self (), old_policy, &old_sched);
mono_thread_info_detach ();
{
InterlockedWrite (&sampling_thread_running, 0);
+ mono_profiler_sampling_thread_post ();
+
#ifndef PLATFORM_MACOSX
/*
* There is a slight problem when we're using CLOCK_PROCESS_CPUTIME_ID: If
#include <mono/metadata/threads.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/debug-helpers.h>
-#include "mono/metadata/profiler.h"
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/threads.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/debug-helpers.h>
-#include "mono/metadata/profiler.h"
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/threads.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/debug-helpers.h>
-#include "mono/metadata/profiler.h"
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/environment.h>
/*
- * mono-profiler-aot.c: Ahead of Time Compiler Profiler for Mono.
+ * aot.c: Ahead of Time Compiler Profiler for Mono.
*
*
* Copyright 2008-2009 Novell, Inc (http://www.novell.com)
/*
- * mono-profiler-iomap.c: IOMAP string profiler for Mono.
+ * iomap.c: IOMAP string profiler for Mono.
*
* Authors:
* Marek Habersack <mhabersack@novell.com>
#include <config.h>
-
+#include <mono/utils/mono-logger-internals.h>
+#include <mono/utils/mono-proclib.h>
#include "log.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-#ifdef HAVE_SCHED_GETAFFINITY
-#include <sched.h>
-
-# ifndef GLIBC_HAS_CPU_COUNT
-static int
-CPU_COUNT(cpu_set_t *set)
-{
- int i, count = 0;
-
- for (int i = 0; i < CPU_SETSIZE; i++)
- if (CPU_ISSET(i, set))
- count++;
- return count;
-}
-# endif
-#endif
-
typedef struct {
const char *event_name;
const int mask;
} NameAndMask;
static NameAndMask event_list[] = {
- { "domain", PROFLOG_DOMAIN_EVENTS },
- { "assembly", PROFLOG_ASSEMBLY_EVENTS },
- { "module", PROFLOG_MODULE_EVENTS },
- { "class", PROFLOG_CLASS_EVENTS },
- { "jit", PROFLOG_JIT_COMPILATION_EVENTS },
{ "exception", PROFLOG_EXCEPTION_EVENTS },
- { "gcalloc", PROFLOG_ALLOCATION_EVENTS },
- { "gc", PROFLOG_GC_EVENTS },
- { "thread", PROFLOG_THREAD_EVENTS },
- { "calls", PROFLOG_CALL_EVENTS },
- //{ "inscov", PROFLOG_INS_COVERAGE_EVENTS }, //this is a profiler API event, but there's no actual event for us to emit here
- //{ "sampling", PROFLOG_SAMPLING_EVENTS }, //it makes no sense to enable/disable this event by itself
{ "monitor", PROFLOG_MONITOR_EVENTS },
- { "gcmove", PROFLOG_GC_MOVES_EVENTS },
+ { "gc", PROFLOG_GC_EVENTS },
+ { "gcalloc", PROFLOG_GC_ALLOCATION_EVENTS },
+ { "gcmove", PROFLOG_GC_MOVE_EVENTS },
{ "gcroot", PROFLOG_GC_ROOT_EVENTS },
- { "context", PROFLOG_CONTEXT_EVENTS },
- { "finalization", PROFLOG_FINALIZATION_EVENTS },
- { "counter", PROFLOG_COUNTER_EVENTS },
{ "gchandle", PROFLOG_GC_HANDLE_EVENTS },
+ { "finalization", PROFLOG_GC_FINALIZATION_EVENTS },
+ { "counter", PROFLOG_COUNTER_EVENTS },
+ { "jit", PROFLOG_JIT_EVENTS },
- { "typesystem", PROFLOG_TYPELOADING_ALIAS },
- { "coverage", PROFLOG_CODECOV_ALIAS },
- //{ "sample", PROFLOG_PERF_SAMPLING_ALIAS }, //takes args, explicitly handles
- { "alloc", PROFLOG_GC_ALLOC_ALIAS },
- //{ "heapshot", PROFLOG_HEAPSHOT_ALIAS }, //takes args, explicitly handled
+ { "alloc", PROFLOG_ALLOC_ALIAS },
{ "legacy", PROFLOG_LEGACY_ALIAS },
};
static void usage (void);
static void set_hsmode (ProfilerConfig *config, const char* val);
static void set_sample_freq (ProfilerConfig *config, const char *val);
-static int mono_cpu_count (void);
-
static gboolean
match_option (const char *arg, const char *opt_name, const char **rval)
config->do_report = TRUE;
} else if (match_option (arg, "debug", NULL)) {
config->do_debug = TRUE;
- } else if (match_option (arg, "debug-coverage", NULL)) {
- config->debug_coverage = TRUE;
- } else if (match_option (arg, "sampling-real", NULL)) {
- config->sampling_mode = MONO_PROFILER_SAMPLE_MODE_REAL;
- } else if (match_option (arg, "sampling-process", NULL)) {
- config->sampling_mode = MONO_PROFILER_SAMPLE_MODE_PROCESS;
} else if (match_option (arg, "heapshot", &val)) {
- config->enable_mask |= PROFLOG_HEAPSHOT_ALIAS;
set_hsmode (config, val);
+ if (config->hs_mode != MONO_PROFILER_HEAPSHOT_NONE)
+ config->enable_mask |= PROFLOG_HEAPSHOT_ALIAS;
+ } else if (match_option (arg, "heapshot-on-shutdown", NULL)) {
+ config->hs_on_shutdown = TRUE;
+ config->enable_mask |= PROFLOG_HEAPSHOT_ALIAS;
} else if (match_option (arg, "sample", &val)) {
set_sample_freq (config, val);
- if (config->sample_freq)
- config->enable_mask |= PROFLOG_PERF_SAMPLING_ALIAS;
+ config->sampling_mode = MONO_PROFILER_SAMPLE_MODE_PROCESS;
+ config->enable_mask |= PROFLOG_SAMPLE_EVENTS;
+ } else if (match_option (arg, "sample-real", &val)) {
+ set_sample_freq (config, val);
+ config->sampling_mode = MONO_PROFILER_SAMPLE_MODE_REAL;
+ config->enable_mask |= PROFLOG_SAMPLE_EVENTS;
+ } else if (match_option (arg, "calls", NULL)) {
+ config->enter_leave = TRUE;
+ } else if (match_option (arg, "coverage", NULL)) {
+ config->collect_coverage = TRUE;
} else if (match_option (arg, "zip", NULL)) {
config->use_zip = TRUE;
} else if (match_option (arg, "output", &val)) {
int num_frames = strtoul (val, &end, 10);
if (num_frames > MAX_FRAMES)
num_frames = MAX_FRAMES;
- config->notraces = num_frames == 0;
config->num_frames = num_frames;
} else if (match_option (arg, "maxsamples", &val)) {
char *end;
break;
}
}
- if (i == G_N_ELEMENTS (event_list)) {
- printf ("Could not parse argument %s\n", arg);
- }
+
+ if (i == G_N_ELEMENTS (event_list))
+ mono_profiler_printf_err ("Could not parse argument: %s", arg);
}
}
//XXX change this to header constants
config->max_allocated_sample_hits = mono_cpu_count () * 1000;
- config->sampling_mode = MONO_PROFILER_SAMPLE_MODE_PROCESS;
+ config->sampling_mode = MONO_PROFILER_SAMPLE_MODE_NONE;
config->sample_freq = 100;
config->max_call_depth = 100;
config->num_frames = MAX_FRAMES;
static void
set_hsmode (ProfilerConfig *config, const char* val)
{
- char *end;
- unsigned int count;
- if (!val)
+ if (!val) {
+ config->hs_mode = MONO_PROFILER_HEAPSHOT_MAJOR;
return;
+ }
+
if (strcmp (val, "ondemand") == 0) {
- config->hs_mode_ondemand = TRUE;
+ config->hs_mode = MONO_PROFILER_HEAPSHOT_ON_DEMAND;
return;
}
- count = strtoul (val, &end, 10);
+ char *end;
+
+ unsigned int count = strtoul (val, &end, 10);
+
if (val == end) {
usage ();
return;
}
- if (strcmp (end, "ms") == 0)
- config->hs_mode_ms = count;
- else if (strcmp (end, "gc") == 0)
- config->hs_mode_gc = count;
- else
+ if (strcmp (end, "ms") == 0) {
+ config->hs_mode = MONO_PROFILER_HEAPSHOT_X_MS;
+ config->hs_freq_ms = count;
+ } else if (strcmp (end, "gc") == 0) {
+ config->hs_mode = MONO_PROFILER_HEAPSHOT_X_GC;
+ config->hs_freq_gc = count;
+ } else
usage ();
}
-/*
-Sampling frequency allows for one undocumented, hidden and ignored argument. The sampling kind.
-Back in the day when this was done using perf, we could specify one of: cycles,instr,cacherefs,cachemiss,branches,branchmiss
-With us moving ot userland sampling, those options are now meaningless.
-*/
static void
set_sample_freq (ProfilerConfig *config, const char *val)
{
if (!val)
return;
- const char *p = val;
-
- // Is it only the frequency (new option style)?
- if (isdigit (*p))
- goto parse;
-
- // Skip the sample type for backwards compatibility.
- while (isalpha (*p))
- p++;
-
- // Skip the forward slash only if we got a sample type.
- if (p != val && *p == '/') {
- p++;
-
- char *end;
-
- parse:
- config->sample_freq = strtoul (p, &end, 10);
+ char *end;
- if (p == end) {
- usage ();
- return;
- }
+ int freq = strtoul (val, &end, 10);
- p = end;
+ if (val == end) {
+ usage ();
+ return;
}
- if (*p)
- usage ();
+ config->sample_freq = freq;
}
static void
usage (void)
{
- printf ("Log profiler version %d.%d (format: %d)\n", LOG_VERSION_MAJOR, LOG_VERSION_MINOR, LOG_DATA_VERSION);
- printf ("Usage: mono --profile=log[:OPTION1[,OPTION2...]] program.exe\n");
- printf ("Options:\n");
- printf ("\thelp show this usage info\n");
- printf ("\t[no]'event' enable/disable a profiling event. Valid values: domain, assembly, module, class, jit, exception, gcalloc, gc, thread, monitor, gcmove, gcroot, context, finalization, counter, gchandle\n");
- printf ("\t[no]typesystem enable/disable typesystem related events such as class and assembly loading\n");
- printf ("\t[no]alloc enable/disable recording allocation info\n");
- printf ("\t[no]calls enable/disable recording enter/leave method events\n");
- printf ("\t[no]legacy enable/disable pre mono 5.4 default profiler events\n");
- printf ("\tsample[=frequency] enable/disable statistical sampling of threads (frequency in Hz, 100 by default)\n");
- printf ("\theapshot[=MODE] record heap shot info (by default at each major collection)\n");
- printf ("\t MODE: every XXms milliseconds, every YYgc collections, ondemand\n");
- printf ("\t[no]coverage enable collection of code coverage data\n");
- printf ("\tcovfilter=ASSEMBLY add an assembly to the code coverage filters\n");
- printf ("\t add a + to include the assembly or a - to exclude it\n");
- printf ("\t covfilter=-mscorlib\n");
- printf ("\tcovfilter-file=FILE use FILE to generate the list of assemblies to be filtered\n");
- printf ("\tmaxframes=NUM collect up to NUM stack frames\n");
- printf ("\tcalldepth=NUM ignore method events for call chain depth bigger than NUM\n");
- printf ("\toutput=FILENAME write the data to file FILENAME (The file is always overwriten)\n");
- printf ("\toutput=+FILENAME write the data to file FILENAME.pid (The file is always overwriten)\n");
- printf ("\toutput=|PROGRAM write the data to the stdin of PROGRAM\n");
- printf ("\t %%t is subtituted with date and time, %%p with the pid\n");
- printf ("\treport create a report instead of writing the raw data to a file\n");
- printf ("\tzip compress the output data\n");
- printf ("\tport=PORTNUM use PORTNUM for the listening command server\n");
-}
-
-static int
-mono_cpu_count (void)
-{
-#ifdef PLATFORM_ANDROID
- /* Android tries really hard to save power by powering off CPUs on SMP phones which
- * means the normal way to query cpu count returns a wrong value with userspace API.
- * Instead we use /sys entries to query the actual hardware CPU count.
- */
- int count = 0;
- char buffer[8] = {'\0'};
- int present = open ("/sys/devices/system/cpu/present", O_RDONLY);
- /* Format of the /sys entry is a cpulist of indexes which in the case
- * of present is always of the form "0-(n-1)" when there is more than
- * 1 core, n being the number of CPU cores in the system. Otherwise
- * the value is simply 0
- */
- if (present != -1 && read (present, (char*)buffer, sizeof (buffer)) > 3)
- count = strtol (((char*)buffer) + 2, NULL, 10);
- if (present != -1)
- close (present);
- if (count > 0)
- return count + 1;
-#endif
-
-#if defined(HOST_ARM) || defined (HOST_ARM64)
-
- /* ARM platforms tries really hard to save power by powering off CPUs on SMP phones which
- * means the normal way to query cpu count returns a wrong value with userspace API. */
-
-#ifdef _SC_NPROCESSORS_CONF
- {
- int count = sysconf (_SC_NPROCESSORS_CONF);
- if (count > 0)
- return count;
- }
-#endif
-
-#else
-
-#ifdef HAVE_SCHED_GETAFFINITY
- {
- cpu_set_t set;
- if (sched_getaffinity (getpid (), sizeof (set), &set) == 0)
- return CPU_COUNT (&set);
- }
-#endif
-#ifdef _SC_NPROCESSORS_ONLN
- {
- int count = sysconf (_SC_NPROCESSORS_ONLN);
- if (count > 0)
- return count;
- }
-#endif
-
-#endif /* defined(HOST_ARM) || defined (HOST_ARM64) */
-
-#ifdef USE_SYSCTL
- {
- int count;
- int mib [2];
- size_t len = sizeof (int);
- mib [0] = CTL_HW;
- mib [1] = HW_NCPU;
- if (sysctl (mib, 2, &count, &len, NULL, 0) == 0)
- return count;
- }
-#endif
-#ifdef HOST_WIN32
- {
- SYSTEM_INFO info;
- GetSystemInfo (&info);
- return info.dwNumberOfProcessors;
- }
-#endif
-
- static gboolean warned;
-
- if (!warned) {
- g_warning ("Don't know how to determine CPU count on this platform; assuming 1");
- warned = TRUE;
- }
-
- return 1;
+ mono_profiler_printf ("Mono log profiler version %d.%d (format: %d)", LOG_VERSION_MAJOR, LOG_VERSION_MINOR, LOG_DATA_VERSION);
+ mono_profiler_printf ("Usage: mono --profile=log[:OPTION1[,OPTION2...]] program.exe\n");
+ mono_profiler_printf ("Options:");
+ mono_profiler_printf ("\thelp show this usage info");
+ mono_profiler_printf ("\t[no]'EVENT' enable/disable an individual profiling event");
+ mono_profiler_printf ("\t valid EVENT values:");
+
+ for (int i = 0; i < G_N_ELEMENTS (event_list); i++)
+ mono_profiler_printf ("\t %s", event_list [i].event_name);
+
+ mono_profiler_printf ("\t[no]alloc enable/disable recording allocation info");
+ mono_profiler_printf ("\t[no]legacy enable/disable pre mono 5.4 default profiler events");
+ mono_profiler_printf ("\tsample[-real][=FREQ] enable/disable statistical sampling of threads");
+ mono_profiler_printf ("\t FREQ in Hz, 100 by default");
+ mono_profiler_printf ("\t the -real variant uses wall clock time instead of process time");
+ mono_profiler_printf ("\theapshot[=MODE] record heapshot info (by default at each major collection)");
+ mono_profiler_printf ("\t MODE: every XXms milliseconds, every YYgc collections, ondemand");
+ mono_profiler_printf ("\theapshot-on-shutdown do a heapshot on runtime shutdown");
+ mono_profiler_printf ("\t this option is independent of the above option");
+ mono_profiler_printf ("\tcalls enable recording enter/leave method events (very heavy)");
+ mono_profiler_printf ("\tcoverage enable collection of code coverage data");
+ mono_profiler_printf ("\tcovfilter=ASSEMBLY add ASSEMBLY to the code coverage filters");
+ mono_profiler_printf ("\t prefix a + to include the assembly or a - to exclude it");
+ mono_profiler_printf ("\t e.g. covfilter=-mscorlib");
+ mono_profiler_printf ("\tcovfilter-file=FILE use FILE to generate the list of assemblies to be filtered");
+ mono_profiler_printf ("\tmaxframes=NUM collect up to NUM stack frames");
+ mono_profiler_printf ("\tcalldepth=NUM ignore method events for call chain depth bigger than NUM");
+ mono_profiler_printf ("\toutput=FILENAME write the data to file FILENAME (the file is always overwritten)");
+ mono_profiler_printf ("\toutput=+FILENAME write the data to file FILENAME.pid (the file is always overwritten)");
+ mono_profiler_printf ("\toutput=|PROGRAM write the data to the stdin of PROGRAM");
+ mono_profiler_printf ("\t %%t is substituted with date and time, %%p with the pid");
+ mono_profiler_printf ("\treport create a report instead of writing the raw data to a file");
+ mono_profiler_printf ("\tzip compress the output data");
+ mono_profiler_printf ("\tport=PORTNUM use PORTNUM for the listening command server");
}
/*
- * mono-profiler-log.c: mono log profiler
+ * log.c: mono log profiler
*
* Authors:
* Paolo Molaro (lupus@ximian.com)
#include <config.h>
#include <mono/metadata/assembly.h>
+#include <mono/metadata/class-internals.h>
#include <mono/metadata/debug-helpers.h>
-#include "../metadata/metadata-internals.h"
+#include <mono/metadata/loader.h>
+#include <mono/metadata/metadata-internals.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/mono-gc.h>
#include <mono/metadata/mono-perfcounters.h>
+#include <mono/metadata/tabledefs.h>
#include <mono/utils/atomic.h>
#include <mono/utils/hazard-pointer.h>
#include <mono/utils/lock-free-alloc.h>
#include <mono/utils/lock-free-queue.h>
#include <mono/utils/mono-conc-hashtable.h>
+#include <mono/utils/mono-coop-mutex.h>
#include <mono/utils/mono-counters.h>
+#include <mono/utils/mono-logger-internals.h>
#include <mono/utils/mono-linked-list-set.h>
#include <mono/utils/mono-membar.h>
#include <mono/utils/mono-mmap.h>
#include <zlib.h>
#endif
-#define BUFFER_SIZE (4096 * 16)
-
-/* Worst-case size in bytes of a 64-bit value encoded with LEB128. */
-#define LEB128_SIZE 10
-
-/* Size of a value encoded as a single byte. */
-#undef BYTE_SIZE // mach/i386/vm_param.h on OS X defines this to 8, but it isn't used for anything.
-#define BYTE_SIZE 1
-
-/* Size in bytes of the event prefix (ID + time). */
-#define EVENT_SIZE (BYTE_SIZE + LEB128_SIZE)
-
-static volatile gint32 runtime_inited;
-static volatile gint32 in_shutdown;
-
-static ProfilerConfig config;
-static int nocalls = 0;
-static int notraces = 0;
-static int use_zip = 0;
-static int do_report = 0;
-static int do_heap_shot = 0;
-static int max_call_depth = 0;
-static int command_port = 0;
-static int heapshot_requested = 0;
-static int do_mono_sample = 0;
-static int do_debug = 0;
-static int do_coverage = 0;
-static gboolean no_counters = FALSE;
-static gboolean debug_coverage = FALSE;
-static int max_allocated_sample_hits;
-
-#define ENABLED(EVT) (config.effective_mask & (EVT))
-
// Statistics for internal profiler data structures.
static gint32 sample_allocations_ctr,
buffer_allocations_ctr;
coverage_classes_ctr,
coverage_assemblies_ctr;
-static MonoLinkedListSet profiler_thread_list;
-
-/*
- * file format:
- * [header] [buffer]*
- *
- * The file is composed by a header followed by 0 or more buffers.
- * Each buffer contains events that happened on a thread: for a given thread
- * buffers that appear later in the file are guaranteed to contain events
- * that happened later in time. Buffers from separate threads could be interleaved,
- * though.
- * Buffers are not required to be aligned.
- *
- * header format:
- * [id: 4 bytes] constant value: LOG_HEADER_ID
- * [major: 1 byte] [minor: 1 byte] major and minor version of the log profiler
- * [format: 1 byte] version of the data format for the rest of the file
- * [ptrsize: 1 byte] size in bytes of a pointer in the profiled program
- * [startup time: 8 bytes] time in milliseconds since the unix epoch when the program started
- * [timer overhead: 4 bytes] approximate overhead in nanoseconds of the timer
- * [flags: 4 bytes] file format flags, should be 0 for now
- * [pid: 4 bytes] pid of the profiled process
- * [port: 2 bytes] tcp port for server if != 0
- * [args size: 4 bytes] size of args
- * [args: string] arguments passed to the profiler
- * [arch size: 4 bytes] size of arch
- * [arch: string] architecture the profiler is running on
- * [os size: 4 bytes] size of os
- * [os: string] operating system the profiler is running on
- *
- * The multiple byte integers are in little-endian format.
- *
- * buffer format:
- * [buffer header] [event]*
- * Buffers have a fixed-size header followed by 0 or more bytes of event data.
- * Timing information and other values in the event data are usually stored
- * as uleb128 or sleb128 integers. To save space, as noted for each item below,
- * some data is represented as a difference between the actual value and
- * either the last value of the same type (like for timing information) or
- * as the difference from a value stored in a buffer header.
- *
- * For timing information the data is stored as uleb128, since timing
- * increases in a monotonic way in each thread: the value is the number of
- * nanoseconds to add to the last seen timing data in a buffer. The first value
- * in a buffer will be calculated from the time_base field in the buffer head.
- *
- * Object or heap sizes are stored as uleb128.
- * Pointer differences are stored as sleb128, instead.
- *
- * If an unexpected value is found, the rest of the buffer should be ignored,
- * as generally the later values need the former to be interpreted correctly.
- *
- * buffer header format:
- * [bufid: 4 bytes] constant value: BUF_ID
- * [len: 4 bytes] size of the data following the buffer header
- * [time_base: 8 bytes] time base in nanoseconds since an unspecified epoch
- * [ptr_base: 8 bytes] base value for pointers
- * [obj_base: 8 bytes] base value for object addresses
- * [thread id: 8 bytes] system-specific thread ID (pthread_t for example)
- * [method_base: 8 bytes] base value for MonoMethod pointers
- *
- * event format:
- * [extended info: upper 4 bits] [type: lower 4 bits]
- * [time diff: uleb128] nanoseconds since last timing
- * [data]*
- * The data that follows depends on type and the extended info.
- * Type is one of the enum values in mono-profiler-log.h: TYPE_ALLOC, TYPE_GC,
- * TYPE_METADATA, TYPE_METHOD, TYPE_EXCEPTION, TYPE_MONITOR, TYPE_HEAP.
- * The extended info bits are interpreted based on type, see
- * each individual event description below.
- * strings are represented as a 0-terminated utf8 sequence.
- *
- * backtrace format:
- * [num: uleb128] number of frames following
- * [frame: sleb128]* mum MonoMethod* as a pointer difference from the last such
- * pointer or the buffer method_base
- *
- * type alloc format:
- * type: TYPE_ALLOC
- * exinfo: zero or TYPE_ALLOC_BT
- * [ptr: sleb128] class as a byte difference from ptr_base
- * [obj: sleb128] object address as a byte difference from obj_base
- * [size: uleb128] size of the object in the heap
- * If exinfo == TYPE_ALLOC_BT, a backtrace follows.
- *
- * type GC format:
- * type: TYPE_GC
- * exinfo: one of TYPE_GC_EVENT, TYPE_GC_RESIZE, TYPE_GC_MOVE, TYPE_GC_HANDLE_CREATED[_BT],
- * TYPE_GC_HANDLE_DESTROYED[_BT], TYPE_GC_FINALIZE_START, TYPE_GC_FINALIZE_END,
- * TYPE_GC_FINALIZE_OBJECT_START, TYPE_GC_FINALIZE_OBJECT_END
- * if exinfo == TYPE_GC_RESIZE
- * [heap_size: uleb128] new heap size
- * if exinfo == TYPE_GC_EVENT
- * [event type: byte] GC event (MONO_GC_EVENT_* from profiler.h)
- * [generation: byte] GC generation event refers to
- * if exinfo == TYPE_GC_MOVE
- * [num_objects: uleb128] number of object moves that follow
- * [objaddr: sleb128]+ num_objects object pointer differences from obj_base
- * num is always an even number: the even items are the old
- * addresses, the odd numbers are the respective new object addresses
- * if exinfo == TYPE_GC_HANDLE_CREATED[_BT]
- * [handle_type: uleb128] MonoGCHandleType enum value
- * upper bits reserved as flags
- * [handle: uleb128] GC handle value
- * [objaddr: sleb128] object pointer differences from obj_base
- * If exinfo == TYPE_GC_HANDLE_CREATED_BT, a backtrace follows.
- * if exinfo == TYPE_GC_HANDLE_DESTROYED[_BT]
- * [handle_type: uleb128] MonoGCHandleType enum value
- * upper bits reserved as flags
- * [handle: uleb128] GC handle value
- * If exinfo == TYPE_GC_HANDLE_DESTROYED_BT, a backtrace follows.
- * if exinfo == TYPE_GC_FINALIZE_OBJECT_{START,END}
- * [object: sleb128] the object as a difference from obj_base
- *
- * type metadata format:
- * type: TYPE_METADATA
- * exinfo: one of: TYPE_END_LOAD, TYPE_END_UNLOAD (optional for TYPE_THREAD and TYPE_DOMAIN,
- * doesn't occur for TYPE_CLASS)
- * [mtype: byte] metadata type, one of: TYPE_CLASS, TYPE_IMAGE, TYPE_ASSEMBLY, TYPE_DOMAIN,
- * TYPE_THREAD, TYPE_CONTEXT
- * [pointer: sleb128] pointer of the metadata type depending on mtype
- * if mtype == TYPE_CLASS
- * [image: sleb128] MonoImage* as a pointer difference from ptr_base
- * [name: string] full class name
- * if mtype == TYPE_IMAGE
- * [name: string] image file name
- * if mtype == TYPE_ASSEMBLY
- * [image: sleb128] MonoImage* as a pointer difference from ptr_base
- * [name: string] assembly name
- * if mtype == TYPE_DOMAIN && exinfo == 0
- * [name: string] domain friendly name
- * if mtype == TYPE_CONTEXT
- * [domain: sleb128] domain id as pointer
- * if mtype == TYPE_THREAD && exinfo == 0
- * [name: string] thread name
- *
- * type method format:
- * type: TYPE_METHOD
- * exinfo: one of: TYPE_LEAVE, TYPE_ENTER, TYPE_EXC_LEAVE, TYPE_JIT
- * [method: sleb128] MonoMethod* as a pointer difference from the last such
- * pointer or the buffer method_base
- * if exinfo == TYPE_JIT
- * [code address: sleb128] pointer to the native code as a diff from ptr_base
- * [code size: uleb128] size of the generated code
- * [name: string] full method name
- *
- * type exception format:
- * type: TYPE_EXCEPTION
- * exinfo: zero, TYPE_CLAUSE, or TYPE_THROW_BT
- * if exinfo == TYPE_CLAUSE
- * [clause type: byte] MonoExceptionEnum enum value
- * [clause index: uleb128] index of the current clause
- * [method: sleb128] MonoMethod* as a pointer difference from the last such
- * pointer or the buffer method_base
- * [object: sleb128] the exception object as a difference from obj_base
- * else
- * [object: sleb128] the exception object as a difference from obj_base
- * If exinfo == TYPE_THROW_BT, a backtrace follows.
- *
- * type runtime format:
- * type: TYPE_RUNTIME
- * exinfo: one of: TYPE_JITHELPER
- * if exinfo == TYPE_JITHELPER
- * [type: byte] MonoProfilerCodeBufferType enum value
- * [buffer address: sleb128] pointer to the native code as a diff from ptr_base
- * [buffer size: uleb128] size of the generated code
- * if type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE
- * [name: string] buffer description name
- *
- * type monitor format:
- * type: TYPE_MONITOR
- * exinfo: zero or TYPE_MONITOR_BT
- * [type: byte] MonoProfilerMonitorEvent enum value
- * [object: sleb128] the lock object as a difference from obj_base
- * If exinfo == TYPE_MONITOR_BT, a backtrace follows.
- *
- * type heap format
- * type: TYPE_HEAP
- * exinfo: one of TYPE_HEAP_START, TYPE_HEAP_END, TYPE_HEAP_OBJECT, TYPE_HEAP_ROOT
- * if exinfo == TYPE_HEAP_OBJECT
- * [object: sleb128] the object as a difference from obj_base
- * [class: sleb128] the object MonoClass* as a difference from ptr_base
- * [size: uleb128] size of the object on the heap
- * [num_refs: uleb128] number of object references
- * each referenced objref is preceded by a uleb128 encoded offset: the
- * first offset is from the object address and each next offset is relative
- * to the previous one
- * [objrefs: sleb128]+ object referenced as a difference from obj_base
- * The same object can appear multiple times, but only the first time
- * with size != 0: in the other cases this data will only be used to
- * provide additional referenced objects.
- * if exinfo == TYPE_HEAP_ROOT
- * [num_roots: uleb128] number of root references
- * [num_gc: uleb128] number of major gcs
- * [object: sleb128] the object as a difference from obj_base
- * [root_type: byte] the root_type: MonoProfileGCRootType (profiler.h)
- * [extra_info: uleb128] the extra_info value
- * object, root_type and extra_info are repeated num_roots times
- *
- * type sample format
- * type: TYPE_SAMPLE
- * exinfo: one of TYPE_SAMPLE_HIT, TYPE_SAMPLE_USYM, TYPE_SAMPLE_UBIN, TYPE_SAMPLE_COUNTERS_DESC, TYPE_SAMPLE_COUNTERS
- * if exinfo == TYPE_SAMPLE_HIT
- * [thread: sleb128] thread id as difference from ptr_base
- * [count: uleb128] number of following instruction addresses
- * [ip: sleb128]* instruction pointer as difference from ptr_base
- * [mbt_count: uleb128] number of managed backtrace frames
- * [method: sleb128]* MonoMethod* as a pointer difference from the last such
- * pointer or the buffer method_base (the first such method can be also indentified by ip, but this is not neccessarily true)
- * if exinfo == TYPE_SAMPLE_USYM
- * [address: sleb128] symbol address as a difference from ptr_base
- * [size: uleb128] symbol size (may be 0 if unknown)
- * [name: string] symbol name
- * if exinfo == TYPE_SAMPLE_UBIN
- * [address: sleb128] address where binary has been loaded as a difference from ptr_base
- * [offset: uleb128] file offset of mapping (the same file can be mapped multiple times)
- * [size: uleb128] memory size
- * [name: string] binary name
- * if exinfo == TYPE_SAMPLE_COUNTERS_DESC
- * [len: uleb128] number of counters
- * for i = 0 to len
- * [section: uleb128] section of counter
- * if section == MONO_COUNTER_PERFCOUNTERS:
- * [section_name: string] section name of counter
- * [name: string] name of counter
- * [type: byte] type of counter
- * [unit: byte] unit of counter
- * [variance: byte] variance of counter
- * [index: uleb128] unique index of counter
- * if exinfo == TYPE_SAMPLE_COUNTERS
- * while true:
- * [index: uleb128] unique index of counter
- * if index == 0:
- * break
- * [type: byte] type of counter value
- * if type == string:
- * if value == null:
- * [0: byte] 0 -> value is null
- * else:
- * [1: byte] 1 -> value is not null
- * [value: string] counter value
- * else:
- * [value: uleb128/sleb128/double] counter value, can be sleb128, uleb128 or double (determined by using type)
- *
- * type coverage format
- * type: TYPE_COVERAGE
- * exinfo: one of TYPE_COVERAGE_METHOD, TYPE_COVERAGE_STATEMENT, TYPE_COVERAGE_ASSEMBLY, TYPE_COVERAGE_CLASS
- * if exinfo == TYPE_COVERAGE_METHOD
- * [assembly: string] name of assembly
- * [class: string] name of the class
- * [name: string] name of the method
- * [signature: string] the signature of the method
- * [filename: string] the file path of the file that contains this method
- * [token: uleb128] the method token
- * [method_id: uleb128] an ID for this data to associate with the buffers of TYPE_COVERAGE_STATEMENTS
- * [len: uleb128] the number of TYPE_COVERAGE_BUFFERS associated with this method
- * if exinfo == TYPE_COVERAGE_STATEMENTS
- * [method_id: uleb128] an the TYPE_COVERAGE_METHOD buffer to associate this with
- * [offset: uleb128] the il offset relative to the previous offset
- * [counter: uleb128] the counter for this instruction
- * [line: uleb128] the line of filename containing this instruction
- * [column: uleb128] the column containing this instruction
- * if exinfo == TYPE_COVERAGE_ASSEMBLY
- * [name: string] assembly name
- * [guid: string] assembly GUID
- * [filename: string] assembly filename
- * [number_of_methods: uleb128] the number of methods in this assembly
- * [fully_covered: uleb128] the number of fully covered methods
- * [partially_covered: uleb128] the number of partially covered methods
- * currently partially_covered will always be 0, and fully_covered is the
- * number of methods that are fully and partially covered.
- * if exinfo == TYPE_COVERAGE_CLASS
- * [name: string] assembly name
- * [class: string] class name
- * [number_of_methods: uleb128] the number of methods in this class
- * [fully_covered: uleb128] the number of fully covered methods
- * [partially_covered: uleb128] the number of partially covered methods
- * currently partially_covered will always be 0, and fully_covered is the
- * number of methods that are fully and partially covered.
- *
- * type meta format:
- * type: TYPE_META
- * exinfo: one of: TYPE_SYNC_POINT
- * if exinfo == TYPE_SYNC_POINT
- * [type: byte] MonoProfilerSyncPointType enum value
- */
-
// Pending data to be written to the log, for a single thread.
// Threads periodically flush their own LogBuffers by calling safe_send
typedef struct _LogBuffer LogBuffer;
typedef struct {
MonoLinkedListSetNode node;
- // Convenience pointer to the profiler structure.
- MonoProfiler *profiler;
-
// Was this thread added to the LLS?
gboolean attached;
#endif
}
-#ifdef __APPLE__
-static mach_timebase_info_data_t timebase_info;
-#elif defined (HOST_WIN32)
-static LARGE_INTEGER pcounter_freq;
-#endif
-
-#define TICKS_PER_SEC 1000000000LL
-
-static uint64_t
-current_time (void)
-{
-#ifdef __APPLE__
- uint64_t time = mach_absolute_time ();
-
- time *= timebase_info.numer;
- time /= timebase_info.denom;
-
- return time;
-#elif defined (HOST_WIN32)
- LARGE_INTEGER value;
-
- QueryPerformanceCounter (&value);
-
- return value.QuadPart * TICKS_PER_SEC / pcounter_freq.QuadPart;
-#elif defined (CLOCK_MONOTONIC)
- struct timespec tspec;
-
- clock_gettime (CLOCK_MONOTONIC, &tspec);
-
- return ((uint64_t) tspec.tv_sec * TICKS_PER_SEC + tspec.tv_nsec);
-#else
- struct timeval tv;
-
- gettimeofday (&tv, NULL);
-
- return ((uint64_t) tv.tv_sec * TICKS_PER_SEC + tv.tv_usec * 1000);
-#endif
-}
-
-static int timer_overhead;
-
-static void
-init_time (void)
-{
-#ifdef __APPLE__
- mach_timebase_info (&timebase_info);
-#elif defined (HOST_WIN32)
- QueryPerformanceFrequency (&pcounter_freq);
-#endif
-
- uint64_t time_start = current_time ();
-
- for (int i = 0; i < 256; ++i)
- current_time ();
-
- uint64_t time_end = current_time ();
-
- timer_overhead = (time_end - time_start) / 256;
-}
+#define ENABLED(EVT) (!!(log_config.effective_mask & (EVT)))
+#define ENABLE(EVT) do { log_config.effective_mask |= (EVT); } while (0)
+#define DISABLE(EVT) do { log_config.effective_mask &= ~(EVT); } while (0)
/*
* These macros should be used when writing an event to a log buffer. They
char *name;
};
-static MonoProfiler *log_profiler;
+typedef struct MonoCounterAgent {
+ MonoCounter *counter;
+ // MonoCounterAgent specific data :
+ void *value;
+ size_t value_size;
+ guint32 index;
+ gboolean emitted;
+ struct MonoCounterAgent *next;
+} MonoCounterAgent;
+
+typedef struct _PerfCounterAgent PerfCounterAgent;
+struct _PerfCounterAgent {
+ PerfCounterAgent *next;
+ guint32 index;
+ char *category_name;
+ char *name;
+ gint64 value;
+ gboolean emitted;
+ gboolean updated;
+ gboolean deleted;
+};
struct _MonoProfiler {
MonoProfilerHandle handle;
+
FILE* file;
#if defined (HAVE_SYS_ZLIB)
gzFile gzfile;
#endif
+
char *args;
uint64_t startup_time;
+ int timer_overhead;
+
+#ifdef __APPLE__
+ mach_timebase_info_data_t timebase_info;
+#elif defined (HOST_WIN32)
+ LARGE_INTEGER pcounter_freq;
+#endif
+
int pipe_output;
int command_port;
int server_socket;
int pipes [2];
+
+ MonoLinkedListSet profiler_thread_list;
+ volatile gint32 buffer_lock_state;
+ volatile gint32 buffer_lock_exclusive_intent;
+
+ volatile gint32 runtime_inited;
+ volatile gint32 in_shutdown;
+
MonoNativeThreadId helper_thread;
+
MonoNativeThreadId writer_thread;
- MonoNativeThreadId dumper_thread;
volatile gint32 run_writer_thread;
- MonoLockFreeAllocSizeClass writer_entry_size_class;
- MonoLockFreeAllocator writer_entry_allocator;
MonoLockFreeQueue writer_queue;
MonoSemType writer_queue_sem;
+
+ MonoLockFreeAllocSizeClass writer_entry_size_class;
+ MonoLockFreeAllocator writer_entry_allocator;
+
MonoConcurrentHashTable *method_table;
mono_mutex_t method_table_mutex;
+
+ MonoNativeThreadId dumper_thread;
volatile gint32 run_dumper_thread;
MonoLockFreeQueue dumper_queue;
MonoSemType dumper_queue_sem;
+
MonoLockFreeAllocSizeClass sample_size_class;
MonoLockFreeAllocator sample_allocator;
MonoLockFreeQueue sample_reuse_queue;
+
BinaryObject *binary_objects;
+
+ volatile gint32 heapshot_requested;
+ guint64 gc_count;
+ guint64 last_hs_time;
+ gboolean do_heap_walk;
+
+ mono_mutex_t counters_mutex;
+ MonoCounterAgent *counters;
+ PerfCounterAgent *perfcounters;
+ guint32 counters_index;
+
+ mono_mutex_t coverage_mutex;
+ GPtrArray *coverage_data;
+
GPtrArray *coverage_filters;
+ MonoConcurrentHashTable *coverage_filtered_classes;
+ MonoConcurrentHashTable *coverage_suppressed_assemblies;
+
+ MonoConcurrentHashTable *coverage_methods;
+ MonoConcurrentHashTable *coverage_assemblies;
+ MonoConcurrentHashTable *coverage_classes;
+
+ MonoConcurrentHashTable *coverage_image_to_methods;
+
+ guint32 coverage_previous_offset;
+ guint32 coverage_method_id;
+
+ MonoCoopMutex api_mutex;
};
+static ProfilerConfig log_config;
+static struct _MonoProfiler log_profiler;
+
typedef struct {
MonoLockFreeQueueNode node;
GPtrArray *methods;
uint64_t time;
} MethodInfo;
+#define TICKS_PER_SEC 1000000000LL
+
+static uint64_t
+current_time (void)
+{
+#ifdef __APPLE__
+ uint64_t time = mach_absolute_time ();
+
+ time *= log_profiler.timebase_info.numer;
+ time /= log_profiler.timebase_info.denom;
+
+ return time;
+#elif defined (HOST_WIN32)
+ LARGE_INTEGER value;
+
+ QueryPerformanceCounter (&value);
+
+ return value.QuadPart * TICKS_PER_SEC / log_profiler.pcounter_freq.QuadPart;
+#elif defined (CLOCK_MONOTONIC)
+ struct timespec tspec;
+
+ clock_gettime (CLOCK_MONOTONIC, &tspec);
+
+ return ((uint64_t) tspec.tv_sec * TICKS_PER_SEC + tspec.tv_nsec);
+#else
+ struct timeval tv;
+
+ gettimeofday (&tv, NULL);
+
+ return ((uint64_t) tv.tv_sec * TICKS_PER_SEC + tv.tv_usec * 1000);
+#endif
+}
+
+static void
+init_time (void)
+{
+#ifdef __APPLE__
+ mach_timebase_info (&log_profiler.timebase_info);
+#elif defined (HOST_WIN32)
+ QueryPerformanceFrequency (&log_profiler.pcounter_freq);
+#endif
+
+ uint64_t time_start = current_time ();
+
+ for (int i = 0; i < 256; ++i)
+ current_time ();
+
+ uint64_t time_end = current_time ();
+
+ log_profiler.timer_overhead = (time_end - time_start) / 256;
+}
+
static char*
pstrdup (const char *s)
{
return p;
}
+#define BUFFER_SIZE (4096 * 16)
+
+/* Worst-case size in bytes of a 64-bit value encoded with LEB128. */
+#define LEB128_SIZE 10
+
+/* Size of a value encoded as a single byte. */
+#undef BYTE_SIZE // mach/i386/vm_param.h on OS X defines this to 8, but it isn't used for anything.
+#define BYTE_SIZE 1
+
+/* Size in bytes of the event prefix (ID + time). */
+#define EVENT_SIZE (BYTE_SIZE + LEB128_SIZE)
+
static void *
alloc_buffer (int size)
{
}
static MonoProfilerThread *
-init_thread (MonoProfiler *prof, gboolean add_to_lls)
+init_thread (gboolean add_to_lls)
{
MonoProfilerThread *thread = PROF_TLS_GET ();
thread = g_malloc (sizeof (MonoProfilerThread));
thread->node.key = thread_id ();
- thread->profiler = prof;
thread->attached = add_to_lls;
thread->call_depth = 0;
thread->busy = 0;
*/
if (add_to_lls) {
MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
- g_assert (mono_lls_insert (&profiler_thread_list, hp, &thread->node) && "Why can't we insert the thread in the LLS?");
+ g_assert (mono_lls_insert (&log_profiler.profiler_thread_list, hp, &thread->node) && "Why can't we insert the thread in the LLS?");
clear_hazard_pointers (hp);
}
static MonoProfilerThread *
get_thread (void)
{
- return init_thread (log_profiler, TRUE);
+ return init_thread (TRUE);
}
// Only valid if init_thread () was called with add_to_lls = FALSE.
*
* The lock does not support recursion.
*/
-static volatile gint32 buffer_lock_state;
-static volatile gint32 buffer_lock_exclusive_intent;
static void
buffer_lock (void)
* the exclusive lock in the gc_event () callback when the world
* is about to stop.
*/
- if (InterlockedRead (&buffer_lock_state) != get_thread ()->small_id << 16) {
+ if (InterlockedRead (&log_profiler.buffer_lock_state) != get_thread ()->small_id << 16) {
MONO_ENTER_GC_SAFE;
gint32 old, new_;
do {
restart:
// Hold off if a thread wants to take the exclusive lock.
- while (InterlockedRead (&buffer_lock_exclusive_intent))
+ while (InterlockedRead (&log_profiler.buffer_lock_exclusive_intent))
mono_thread_info_yield ();
- old = InterlockedRead (&buffer_lock_state);
+ old = InterlockedRead (&log_profiler.buffer_lock_state);
// Is a thread holding the exclusive lock?
if (old >> 16) {
}
new_ = old + 1;
- } while (InterlockedCompareExchange (&buffer_lock_state, new_, old) != old);
+ } while (InterlockedCompareExchange (&log_profiler.buffer_lock_state, new_, old) != old);
MONO_EXIT_GC_SAFE;
}
{
mono_memory_barrier ();
- gint32 state = InterlockedRead (&buffer_lock_state);
+ gint32 state = InterlockedRead (&log_profiler.buffer_lock_state);
// See the comment in buffer_lock ().
if (state == PROF_TLS_GET ()->small_id << 16)
g_assert (state && "Why are we decrementing a zero reader count?");
g_assert (!(state >> 16) && "Why is the exclusive lock held?");
- InterlockedDecrement (&buffer_lock_state);
+ InterlockedDecrement (&log_profiler.buffer_lock_state);
}
static void
{
gint32 new_ = get_thread ()->small_id << 16;
- g_assert (InterlockedRead (&buffer_lock_state) != new_ && "Why are we taking the exclusive lock twice?");
+ g_assert (InterlockedRead (&log_profiler.buffer_lock_state) != new_ && "Why are we taking the exclusive lock twice?");
- InterlockedIncrement (&buffer_lock_exclusive_intent);
+ InterlockedIncrement (&log_profiler.buffer_lock_exclusive_intent);
MONO_ENTER_GC_SAFE;
- while (InterlockedCompareExchange (&buffer_lock_state, new_, 0))
+ while (InterlockedCompareExchange (&log_profiler.buffer_lock_state, new_, 0))
mono_thread_info_yield ();
MONO_EXIT_GC_SAFE;
{
mono_memory_barrier ();
- gint32 state = InterlockedRead (&buffer_lock_state);
+ gint32 state = InterlockedRead (&log_profiler.buffer_lock_state);
gint32 excl = state >> 16;
g_assert (excl && "Why is the exclusive lock not held?");
g_assert (excl == PROF_TLS_GET ()->small_id && "Why does another thread hold the exclusive lock?");
g_assert (!(state & 0xFFFF) && "Why are there readers when the exclusive lock is held?");
- InterlockedWrite (&buffer_lock_state, 0);
- InterlockedDecrement (&buffer_lock_exclusive_intent);
+ InterlockedWrite (&log_profiler.buffer_lock_state, 0);
+ InterlockedDecrement (&log_profiler.buffer_lock_exclusive_intent);
}
static void
{
MonoProfilerThread *thread = get_thread ();
- if (!mono_conc_hashtable_lookup (thread->profiler->method_table, method)) {
+ if (!mono_conc_hashtable_lookup (log_profiler.method_table, method)) {
MethodInfo *info = (MethodInfo *) g_malloc (sizeof (MethodInfo));
info->method = method;
}
static void
-dump_header (MonoProfiler *profiler)
+dump_header (void)
{
- const char *args = profiler->args;
+ const char *args = log_profiler.args;
const char *arch = mono_config_get_cpu ();
const char *os = mono_config_get_os ();
*p++ = LOG_DATA_VERSION;
*p++ = sizeof (void *);
p = write_int64 (p, ((uint64_t) time (NULL)) * 1000);
- p = write_int32 (p, timer_overhead);
+ p = write_int32 (p, log_profiler.timer_overhead);
p = write_int32 (p, 0); /* flags */
p = write_int32 (p, process_id ());
- p = write_int16 (p, profiler->command_port);
+ p = write_int16 (p, log_profiler.command_port);
p = write_header_string (p, args);
p = write_header_string (p, arch);
p = write_header_string (p, os);
#if defined (HAVE_SYS_ZLIB)
- if (profiler->gzfile) {
- gzwrite (profiler->gzfile, hbuf, p - hbuf);
+ if (log_profiler.gzfile) {
+ gzwrite (log_profiler.gzfile, hbuf, p - hbuf);
} else
#endif
{
- fwrite (hbuf, p - hbuf, 1, profiler->file);
- fflush (profiler->file);
+ fwrite (hbuf, p - hbuf, 1, log_profiler.file);
+ fflush (log_profiler.file);
}
g_free (hbuf);
static void
send_buffer (MonoProfilerThread *thread)
{
- WriterQueueEntry *entry = mono_lock_free_alloc (&thread->profiler->writer_entry_allocator);
+ WriterQueueEntry *entry = mono_lock_free_alloc (&log_profiler.writer_entry_allocator);
entry->methods = thread->methods;
entry->buffer = thread->buffer;
mono_lock_free_queue_node_init (&entry->node, FALSE);
- mono_lock_free_queue_enqueue (&thread->profiler->writer_queue, &entry->node);
- mono_os_sem_post (&thread->profiler->writer_queue_sem);
+ mono_lock_free_queue_enqueue (&log_profiler.writer_queue, &entry->node);
+ mono_os_sem_post (&log_profiler.writer_queue_sem);
}
static void
InterlockedIncrement (&thread_ends_ctr);
- if (ENABLED (PROFLOG_THREAD_EVENTS)) {
- LogBuffer *buf = ensure_logbuf_unsafe (thread,
- EVENT_SIZE /* event */ +
- BYTE_SIZE /* type */ +
- LEB128_SIZE /* tid */
- );
+ LogBuffer *buf = ensure_logbuf_unsafe (thread,
+ EVENT_SIZE /* event */ +
+ BYTE_SIZE /* type */ +
+ LEB128_SIZE /* tid */
+ );
- emit_event (buf, TYPE_END_UNLOAD | TYPE_METADATA);
- emit_byte (buf, TYPE_THREAD);
- emit_ptr (buf, (void *) thread->node.key);
- }
+ emit_event (buf, TYPE_END_UNLOAD | TYPE_METADATA);
+ emit_byte (buf, TYPE_THREAD);
+ emit_ptr (buf, (void *) thread->node.key);
}
send_buffer (thread);
{
MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
- if (mono_lls_remove (&profiler_thread_list, hp, &thread->node))
+ if (mono_lls_remove (&log_profiler.profiler_thread_list, hp, &thread->node))
mono_thread_hazardous_try_free (thread, free_thread);
clear_hazard_pointers (hp);
}
static void
-dump_buffer (MonoProfiler *profiler, LogBuffer *buf)
+dump_buffer (LogBuffer *buf)
{
char hbuf [128];
char *p = hbuf;
if (buf->next)
- dump_buffer (profiler, buf->next);
+ dump_buffer (buf->next);
if (buf->cursor - buf->buf) {
p = write_int32 (p, BUF_ID);
p = write_int64 (p, buf->method_base);
#if defined (HAVE_SYS_ZLIB)
- if (profiler->gzfile) {
- gzwrite (profiler->gzfile, hbuf, p - hbuf);
- gzwrite (profiler->gzfile, buf->buf, buf->cursor - buf->buf);
+ if (log_profiler.gzfile) {
+ gzwrite (log_profiler.gzfile, hbuf, p - hbuf);
+ gzwrite (log_profiler.gzfile, buf->buf, buf->cursor - buf->buf);
} else
#endif
{
- fwrite (hbuf, p - hbuf, 1, profiler->file);
- fwrite (buf->buf, buf->cursor - buf->buf, 1, profiler->file);
- fflush (profiler->file);
+ fwrite (hbuf, p - hbuf, 1, log_profiler.file);
+ fwrite (buf->buf, buf->cursor - buf->buf, 1, log_profiler.file);
+ fflush (log_profiler.file);
}
}
}
static void
-dump_buffer_threadless (MonoProfiler *profiler, LogBuffer *buf)
+dump_buffer_threadless (LogBuffer *buf)
{
for (LogBuffer *iter = buf; iter; iter = iter->next)
iter->thread_id = 0;
- dump_buffer (profiler, buf);
+ dump_buffer (buf);
}
// Only valid if init_thread () was called with add_to_lls = FALSE.
static void
sync_point_flush (void)
{
- g_assert (InterlockedRead (&buffer_lock_state) == PROF_TLS_GET ()->small_id << 16 && "Why don't we hold the exclusive lock?");
+ g_assert (InterlockedRead (&log_profiler.buffer_lock_state) == PROF_TLS_GET ()->small_id << 16 && "Why don't we hold the exclusive lock?");
- MONO_LLS_FOREACH_SAFE (&profiler_thread_list, MonoProfilerThread, thread) {
+ MONO_LLS_FOREACH_SAFE (&log_profiler.profiler_thread_list, MonoProfilerThread, thread) {
g_assert (thread->attached && "Why is a thread in the LLS not attached?");
send_buffer (thread);
static void
sync_point_mark (MonoProfilerSyncPointType type)
{
- g_assert (InterlockedRead (&buffer_lock_state) == PROF_TLS_GET ()->small_id << 16 && "Why don't we hold the exclusive lock?");
+ g_assert (InterlockedRead (&log_profiler.buffer_lock_state) == PROF_TLS_GET ()->small_id << 16 && "Why don't we hold the exclusive lock?");
ENTER_LOG (&sync_points_ctr, logbuffer,
EVENT_SIZE /* event */ +
emit_obj (logbuffer, refs [i]);
}
- EXIT_LOG_EXPLICIT (DO_SEND);
+ EXIT_LOG;
return 0;
}
-static unsigned int hs_mode_ms = 0;
-static unsigned int hs_mode_gc = 0;
-static unsigned int hs_mode_ondemand = 0;
-static unsigned int gc_count = 0;
-static uint64_t last_hs_time = 0;
-static gboolean do_heap_walk = FALSE;
-static gboolean ignore_heap_events;
-
static void
gc_roots (MonoProfiler *prof, MonoObject *const *objects, const MonoProfilerGCRootType *root_types, const uintptr_t *extra_info, uint64_t num)
{
- if (ignore_heap_events)
- return;
-
ENTER_LOG (&heap_roots_ctr, logbuffer,
EVENT_SIZE /* event */ +
LEB128_SIZE /* num */ +
emit_value (logbuffer, extra_info [i]);
}
- EXIT_LOG_EXPLICIT (DO_SEND);
+ EXIT_LOG;
}
static void
trigger_on_demand_heapshot (void)
{
- if (heapshot_requested)
+ if (InterlockedRead (&log_profiler.heapshot_requested))
mono_gc_collect (mono_gc_max_generation ());
}
-#define ALL_GC_EVENTS_MASK (PROFLOG_GC_MOVES_EVENTS | PROFLOG_GC_ROOT_EVENTS | PROFLOG_GC_EVENTS | PROFLOG_HEAPSHOT_FEATURE)
+#define ALL_GC_EVENTS_MASK (PROFLOG_GC_EVENTS | PROFLOG_GC_MOVE_EVENTS | PROFLOG_GC_ROOT_EVENTS)
static void
gc_event (MonoProfiler *profiler, MonoProfilerGCEvent ev, uint32_t generation)
{
- if (ev == MONO_GC_EVENT_START) {
- uint64_t now = current_time ();
-
- if (hs_mode_ms && (now - last_hs_time) / 1000 * 1000 >= hs_mode_ms)
- do_heap_walk = TRUE;
- else if (hs_mode_gc && !(gc_count % hs_mode_gc))
- do_heap_walk = TRUE;
- else if (hs_mode_ondemand)
- do_heap_walk = heapshot_requested;
- else if (!hs_mode_ms && !hs_mode_gc && generation == mono_gc_max_generation ())
- do_heap_walk = TRUE;
-
- //If using heapshot, ignore events for collections we don't care
- if (ENABLED (PROFLOG_HEAPSHOT_FEATURE)) {
- // Ignore events generated during the collection itself (IE GC ROOTS)
- ignore_heap_events = !do_heap_walk;
- }
- }
-
-
if (ENABLED (PROFLOG_GC_EVENTS)) {
ENTER_LOG (&gc_events_ctr, logbuffer,
EVENT_SIZE /* event */ +
emit_byte (logbuffer, ev);
emit_byte (logbuffer, generation);
- EXIT_LOG_EXPLICIT (NO_SEND);
+ EXIT_LOG;
}
switch (ev) {
- case MONO_GC_EVENT_START:
- if (generation == mono_gc_max_generation ())
- gc_count++;
-
- break;
case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED:
+ switch (log_config.hs_mode) {
+ case MONO_PROFILER_HEAPSHOT_NONE:
+ log_profiler.do_heap_walk = FALSE;
+ break;
+ case MONO_PROFILER_HEAPSHOT_MAJOR:
+ log_profiler.do_heap_walk = generation == mono_gc_max_generation ();
+ break;
+ case MONO_PROFILER_HEAPSHOT_ON_DEMAND:
+ log_profiler.do_heap_walk = InterlockedRead (&log_profiler.heapshot_requested);
+ break;
+ case MONO_PROFILER_HEAPSHOT_X_GC:
+ log_profiler.do_heap_walk = !(log_profiler.gc_count % log_config.hs_freq_gc);
+ break;
+ case MONO_PROFILER_HEAPSHOT_X_MS:
+ log_profiler.do_heap_walk = (current_time () - log_profiler.last_hs_time) / 1000 * 1000 >= log_config.hs_freq_ms;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ /*
+ * heapshot_requested is set either because on-demand heapshot is
+ * enabled and a heapshot was triggered, or because we're doing a
+ * shutdown heapshot. In the latter case, we won't check it in the
+ * switch above, so check it here and override any decision we made
+ * above.
+ */
+ if (InterlockedRead (&log_profiler.heapshot_requested))
+ log_profiler.do_heap_walk = TRUE;
+
+ if (ENABLED (PROFLOG_GC_ROOT_EVENTS) && log_profiler.do_heap_walk)
+ mono_profiler_set_gc_roots_callback (log_profiler.handle, gc_roots);
+
/*
* Ensure that no thread can be in the middle of writing to
* a buffer when the world stops...
*/
buffer_lock_excl ();
+
break;
case MONO_GC_EVENT_POST_STOP_WORLD:
/*
if (ENABLED (ALL_GC_EVENTS_MASK))
sync_point (SYNC_POINT_WORLD_STOP);
- /*
- * All heap events are surrounded by a HEAP_START and a HEAP_ENV event.
- * Right now, that's the case for GC Moves, GC Roots or heapshots.
- */
- if (ENABLED (PROFLOG_GC_MOVES_EVENTS | PROFLOG_GC_ROOT_EVENTS) || do_heap_walk) {
+ // Surround heapshots with HEAP_START/HEAP_END events.
+ if (log_profiler.do_heap_walk) {
ENTER_LOG (&heap_starts_ctr, logbuffer,
EVENT_SIZE /* event */
);
emit_event (logbuffer, TYPE_HEAP_START | TYPE_HEAP);
- EXIT_LOG_EXPLICIT (DO_SEND);
+ EXIT_LOG;
}
+ break;
+ case MONO_GC_EVENT_START:
+ if (generation == mono_gc_max_generation ())
+ log_profiler.gc_count++;
+
break;
case MONO_GC_EVENT_PRE_START_WORLD:
- if (do_heap_shot && do_heap_walk)
+ mono_profiler_set_gc_roots_callback (log_profiler.handle, NULL);
+
+ if (log_profiler.do_heap_walk) {
mono_gc_walk_heap (0, gc_reference, NULL);
- /* Matching HEAP_END to the HEAP_START from above */
- if (ENABLED (PROFLOG_GC_MOVES_EVENTS | PROFLOG_GC_ROOT_EVENTS) || do_heap_walk) {
ENTER_LOG (&heap_ends_ctr, logbuffer,
EVENT_SIZE /* event */
);
emit_event (logbuffer, TYPE_HEAP_END | TYPE_HEAP);
- EXIT_LOG_EXPLICIT (DO_SEND);
- }
+ EXIT_LOG;
- if (do_heap_shot && do_heap_walk) {
- do_heap_walk = FALSE;
- heapshot_requested = 0;
- last_hs_time = current_time ();
+ log_profiler.do_heap_walk = FALSE;
+ log_profiler.last_hs_time = current_time ();
+
+ InterlockedWrite (&log_profiler.heapshot_requested, 0);
}
/*
*/
if (ENABLED (ALL_GC_EVENTS_MASK))
sync_point_mark (SYNC_POINT_WORLD_START);
+
break;
case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED:
/*
* their buffers again.
*/
buffer_unlock_excl ();
+
break;
default:
break;
emit_event (logbuffer, TYPE_GC_RESIZE | TYPE_GC);
emit_value (logbuffer, new_size);
- EXIT_LOG_EXPLICIT (DO_SEND);
+ EXIT_LOG;
}
typedef struct {
int32_t native_offsets [MAX_FRAMES];
} FrameData;
-static int num_frames = MAX_FRAMES;
-
static mono_bool
walk_stack (MonoMethod *method, int32_t native_offset, int32_t il_offset, mono_bool managed, void* data)
{
FrameData *frame = (FrameData *)data;
- if (method && frame->count < num_frames) {
+ if (method && frame->count < log_config.num_frames) {
frame->il_offsets [frame->count] = il_offset;
frame->native_offsets [frame->count] = native_offset;
frame->methods [frame->count++] = method;
- //printf ("In %d %s at %d (native: %d)\n", frame->count, mono_method_get_name (method), il_offset, native_offset);
}
- return frame->count == num_frames;
+ return frame->count == log_config.num_frames;
}
/*
}
static void
-emit_bt (MonoProfiler *prof, LogBuffer *logbuffer, FrameData *data)
+emit_bt (LogBuffer *logbuffer, FrameData *data)
{
- if (data->count > num_frames)
- printf ("bad num frames: %d\n", data->count);
-
emit_value (logbuffer, data->count);
while (data->count)
static void
gc_alloc (MonoProfiler *prof, MonoObject *obj)
{
- int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces) ? TYPE_ALLOC_BT : 0;
+ int do_bt = (!log_config.enter_leave && InterlockedRead (&log_profiler.runtime_inited) && log_config.num_frames) ? TYPE_ALLOC_BT : 0;
FrameData data;
uintptr_t len = mono_object_get_size (obj);
/* account for object alignment in the heap */
emit_value (logbuffer, len);
if (do_bt)
- emit_bt (prof, logbuffer, &data);
+ emit_bt (logbuffer, &data);
EXIT_LOG;
}
for (int i = 0; i < num; ++i)
emit_obj (logbuffer, objects [i]);
- EXIT_LOG_EXPLICIT (DO_SEND);
+ EXIT_LOG;
}
static void
gc_handle (MonoProfiler *prof, int op, MonoGCHandleType type, uint32_t handle, MonoObject *obj)
{
- int do_bt = nocalls && InterlockedRead (&runtime_inited) && !notraces;
+ int do_bt = !log_config.enter_leave && InterlockedRead (&log_profiler.runtime_inited) && log_config.num_frames;
FrameData data;
if (do_bt)
emit_obj (logbuffer, obj);
if (do_bt)
- emit_bt (prof, logbuffer, &data);
+ emit_bt (logbuffer, &data);
EXIT_LOG;
}
finalize_end (MonoProfiler *prof)
{
trigger_on_demand_heapshot ();
- if (ENABLED (PROFLOG_FINALIZATION_EVENTS)) {
+ if (ENABLED (PROFLOG_GC_FINALIZATION_EVENTS)) {
ENTER_LOG (&finalize_ends_ctr, buf,
EVENT_SIZE /* event */
);
{
char *name;
- if (InterlockedRead (&runtime_inited))
+ if (InterlockedRead (&log_profiler.runtime_inited))
name = mono_type_get_name (mono_class_get_type (klass));
else
name = type_name (klass);
EXIT_LOG;
- if (runtime_inited)
+ if (InterlockedRead (&log_profiler.runtime_inited))
mono_free (name);
else
g_free (name);
static void
method_enter (MonoProfiler *prof, MonoMethod *method)
{
- if (get_thread ()->call_depth++ <= max_call_depth) {
+ if (get_thread ()->call_depth++ <= log_config.max_call_depth) {
ENTER_LOG (&method_entries_ctr, logbuffer,
EVENT_SIZE /* event */ +
LEB128_SIZE /* method */
static void
method_leave (MonoProfiler *prof, MonoMethod *method)
{
- if (--get_thread ()->call_depth <= max_call_depth) {
+ if (--get_thread ()->call_depth <= log_config.max_call_depth) {
ENTER_LOG (&method_exits_ctr, logbuffer,
EVENT_SIZE /* event */ +
LEB128_SIZE /* method */
static void
method_exc_leave (MonoProfiler *prof, MonoMethod *method, MonoObject *exc)
{
- if (!nocalls && --get_thread ()->call_depth <= max_call_depth) {
+ if (--get_thread ()->call_depth <= log_config.max_call_depth) {
ENTER_LOG (&method_exception_exits_ctr, logbuffer,
EVENT_SIZE /* event */ +
LEB128_SIZE /* method */
static void
throw_exc (MonoProfiler *prof, MonoObject *object)
{
- int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces) ? TYPE_THROW_BT : 0;
+ int do_bt = (!log_config.enter_leave && InterlockedRead (&log_profiler.runtime_inited) && log_config.num_frames) ? TYPE_THROW_BT : 0;
FrameData data;
if (do_bt)
emit_obj (logbuffer, object);
if (do_bt)
- emit_bt (prof, logbuffer, &data);
+ emit_bt (logbuffer, &data);
EXIT_LOG;
}
static void
monitor_event (MonoProfiler *profiler, MonoObject *object, MonoProfilerMonitorEvent ev)
{
- int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces) ? TYPE_MONITOR_BT : 0;
+ int do_bt = (!log_config.enter_leave && InterlockedRead (&log_profiler.runtime_inited) && log_config.num_frames) ? TYPE_MONITOR_BT : 0;
FrameData data;
if (do_bt)
emit_obj (logbuffer, object);
if (do_bt)
- emit_bt (profiler, logbuffer, &data);
+ emit_bt (logbuffer, &data);
EXIT_LOG;
}
static void
thread_start (MonoProfiler *prof, uintptr_t tid)
{
- if (ENABLED (PROFLOG_THREAD_EVENTS)) {
- ENTER_LOG (&thread_starts_ctr, logbuffer,
- EVENT_SIZE /* event */ +
- BYTE_SIZE /* type */ +
- LEB128_SIZE /* tid */
- );
+ ENTER_LOG (&thread_starts_ctr, logbuffer,
+ EVENT_SIZE /* event */ +
+ BYTE_SIZE /* type */ +
+ LEB128_SIZE /* tid */
+ );
- emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
- emit_byte (logbuffer, TYPE_THREAD);
- emit_ptr (logbuffer, (void*) tid);
+ emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
+ emit_byte (logbuffer, TYPE_THREAD);
+ emit_ptr (logbuffer, (void*) tid);
- EXIT_LOG;
- }
+ EXIT_LOG;
}
static void
thread_end (MonoProfiler *prof, uintptr_t tid)
{
- if (ENABLED (PROFLOG_THREAD_EVENTS)) {
- ENTER_LOG (&thread_ends_ctr, logbuffer,
- EVENT_SIZE /* event */ +
- BYTE_SIZE /* type */ +
- LEB128_SIZE /* tid */
- );
+ ENTER_LOG (&thread_ends_ctr, logbuffer,
+ EVENT_SIZE /* event */ +
+ BYTE_SIZE /* type */ +
+ LEB128_SIZE /* tid */
+ );
- emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
- emit_byte (logbuffer, TYPE_THREAD);
- emit_ptr (logbuffer, (void*) tid);
+ emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
+ emit_byte (logbuffer, TYPE_THREAD);
+ emit_ptr (logbuffer, (void*) tid);
- EXIT_LOG_EXPLICIT (NO_SEND);
- }
+ EXIT_LOG_EXPLICIT (NO_SEND);
MonoProfilerThread *thread = get_thread ();
{
int len = strlen (name) + 1;
- if (ENABLED (PROFLOG_THREAD_EVENTS)) {
- ENTER_LOG (&thread_names_ctr, logbuffer,
- EVENT_SIZE /* event */ +
- BYTE_SIZE /* type */ +
- LEB128_SIZE /* tid */ +
- len /* name */
- );
+ ENTER_LOG (&thread_names_ctr, logbuffer,
+ EVENT_SIZE /* event */ +
+ BYTE_SIZE /* type */ +
+ LEB128_SIZE /* tid */ +
+ len /* name */
+ );
- emit_event (logbuffer, TYPE_METADATA);
- emit_byte (logbuffer, TYPE_THREAD);
- emit_ptr (logbuffer, (void*)tid);
- memcpy (logbuffer->cursor, name, len);
- logbuffer->cursor += len;
+ emit_event (logbuffer, TYPE_METADATA);
+ emit_byte (logbuffer, TYPE_THREAD);
+ emit_ptr (logbuffer, (void*)tid);
+ memcpy (logbuffer->cursor, name, len);
+ logbuffer->cursor += len;
- EXIT_LOG;
- }
+ EXIT_LOG;
}
static void
typedef struct {
MonoLockFreeQueueNode node;
- MonoProfiler *prof;
uint64_t time;
uintptr_t tid;
const void *ip;
{
SampleHit *sample = (SampleHit *) data;
- if (sample->count < num_frames) {
+ if (sample->count < log_config.num_frames) {
int i = sample->count;
sample->frames [i].method = method;
sample->count++;
}
- return sample->count == num_frames;
+ return sample->count == log_config.num_frames;
}
#define SAMPLE_SLOT_SIZE(FRAMES) (sizeof (SampleHit) + sizeof (AsyncFrameInfo) * (FRAMES - MONO_ZERO_LEN_ARRAY))
SampleHit *sample = p;
mono_lock_free_queue_node_unpoison (&sample->node);
- mono_lock_free_queue_enqueue (&sample->prof->dumper_queue, &sample->node);
- mono_os_sem_post (&sample->prof->dumper_queue_sem);
+ mono_lock_free_queue_enqueue (&log_profiler.dumper_queue, &sample->node);
+ mono_os_sem_post (&log_profiler.dumper_queue_sem);
}
static void
* invoking runtime functions, which is not async-signal-safe.
*/
- if (InterlockedRead (&in_shutdown))
+ if (InterlockedRead (&log_profiler.in_shutdown))
return;
SampleHit *sample = (SampleHit *) mono_lock_free_queue_dequeue (&profiler->sample_reuse_queue);
* If we're out of reusable sample events and we're not allowed to
* allocate more, we have no choice but to drop the event.
*/
- if (InterlockedRead (&sample_allocations_ctr) >= max_allocated_sample_hits)
+ if (InterlockedRead (&sample_allocations_ctr) >= log_config.max_allocated_sample_hits)
return;
sample = mono_lock_free_alloc (&profiler->sample_allocator);
- sample->prof = profiler;
mono_lock_free_queue_node_init (&sample->node, TRUE);
InterlockedIncrement (&sample_allocations_ctr);
if (++i == hsize)
i = 0;
} while (i != start_pos);
- /* should not happen */
- printf ("failed code page store\n");
+ g_assert_not_reached ();
return 0;
}
//#if defined(HAVE_DL_ITERATE_PHDR) && defined(ELFMAG0)
#if 0
static void
-dump_ubin (MonoProfiler *prof, const char *filename, uintptr_t load_addr, uint64_t offset, uintptr_t size)
+dump_ubin (const char *filename, uintptr_t load_addr, uint64_t offset, uintptr_t size)
{
int len = strlen (filename) + 1;
memcpy (logbuffer->cursor, filename, len);
logbuffer->cursor += len;
- EXIT_LOG_EXPLICIT (DO_SEND);
+ EXIT_LOG;
}
#endif
static void
-dump_usym (MonoProfiler *prof, const char *name, uintptr_t value, uintptr_t size)
+dump_usym (const char *name, uintptr_t value, uintptr_t size)
{
int len = strlen (name) + 1;
memcpy (logbuffer->cursor, name, len);
logbuffer->cursor += len;
- EXIT_LOG_EXPLICIT (DO_SEND);
+ EXIT_LOG;
}
/* ELF code crashes on some systems. */
#endif
static void
-dump_elf_symbols (MonoProfiler *prof, ElfW(Sym) *symbols, int num_symbols, const char *strtab, void *load_addr)
+dump_elf_symbols (ElfW(Sym) *symbols, int num_symbols, const char *strtab, void *load_addr)
{
int i;
for (i = 0; i < num_symbols; ++i) {
sym = strtab + symbols [i].st_name;
if (!symbols [i].st_name || !symbols [i].st_size || (symbols [i].st_info & 0xf) != STT_FUNC)
continue;
- //printf ("symbol %s at %d\n", sym, symbols [i].st_value);
dump_usym (sym, (uintptr_t)load_addr + symbols [i].st_value, symbols [i].st_size);
}
}
shstrtabh = (void*)((char*)sheader + (header->e_shentsize * header->e_shstrndx));
strtab = (const char*)data + shstrtabh->sh_offset;
for (i = 0; i < header->e_shnum; ++i) {
- //printf ("section header: %d\n", sheader->sh_type);
if (sheader->sh_type == SHT_SYMTAB) {
symtabh = sheader;
strtabh = (void*)((char*)data + header->e_shoff + sheader->sh_link * header->e_shentsize);
- /*printf ("symtab section header: %d, .strstr: %d\n", i, sheader->sh_link);*/
break;
}
sheader = (void*)((char*)sheader + header->e_shentsize);
static int
elf_dl_callback (struct dl_phdr_info *info, size_t size, void *data)
{
- MonoProfiler *prof = data;
char buf [256];
const char *filename;
BinaryObject *obj;
ElfW(Word) *hash_table = NULL;
ElfW(Ehdr) *header = NULL;
const char* strtab = NULL;
- for (obj = prof->binary_objects; obj; obj = obj->next) {
+ for (obj = log_profiler.binary_objects; obj; obj = obj->next) {
if (obj->addr == a)
return 0;
}
obj = g_calloc (sizeof (BinaryObject), 1);
obj->addr = (void*)info->dlpi_addr;
obj->name = pstrdup (filename);
- obj->next = prof->binary_objects;
- prof->binary_objects = obj;
- //printf ("loaded file: %s at %p, segments: %d\n", filename, (void*)info->dlpi_addr, info->dlpi_phnum);
+ obj->next = log_profiler.binary_objects;
+ log_profiler.binary_objects = obj;
a = NULL;
for (i = 0; i < info->dlpi_phnum; ++i) {
- //printf ("segment type %d file offset: %d, size: %d\n", info->dlpi_phdr[i].p_type, info->dlpi_phdr[i].p_offset, info->dlpi_phdr[i].p_memsz);
if (info->dlpi_phdr[i].p_type == PT_LOAD && !header) {
header = (ElfW(Ehdr)*)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
if (header->e_ident [EI_MAG0] != ELFMAG0 ||
header->e_ident [EI_MAG3] != ELFMAG3 ) {
header = NULL;
}
- dump_ubin (prof, filename, info->dlpi_addr + info->dlpi_phdr[i].p_vaddr, info->dlpi_phdr[i].p_offset, info->dlpi_phdr[i].p_memsz);
+ dump_ubin (filename, info->dlpi_addr + info->dlpi_phdr[i].p_vaddr, info->dlpi_phdr[i].p_offset, info->dlpi_phdr[i].p_memsz);
} else if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) {
dyn = (ElfW(Dyn) *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
}
}
- if (read_elf_symbols (prof, filename, (void*)info->dlpi_addr))
+ if (read_elf_symbols (filename, (void*)info->dlpi_addr))
return 0;
if (!info->dlpi_name || !info->dlpi_name[0])
return 0;
return 0;
for (i = 0; dyn [i].d_tag != DT_NULL; ++i) {
if (dyn [i].d_tag == DT_SYMTAB) {
- if (symtab && do_debug)
- printf ("multiple symtabs: %d\n", i);
symtab = (ElfW(Sym) *)(a + dyn [i].d_un.d_ptr);
} else if (dyn [i].d_tag == DT_HASH) {
hash_table = (ElfW(Word) *)(a + dyn [i].d_un.d_ptr);
if (!hash_table)
return 0;
num_sym = hash_table [1];
- dump_elf_symbols (prof, symtab, num_sym, strtab, (void*)info->dlpi_addr);
+ dump_elf_symbols (symtab, num_sym, strtab, (void*)info->dlpi_addr);
return 0;
}
static int
-load_binaries (MonoProfiler *prof)
+load_binaries (void)
{
- dl_iterate_phdr (elf_dl_callback, prof);
+ dl_iterate_phdr (elf_dl_callback, NULL);
return 1;
}
#else
static int
-load_binaries (MonoProfiler *prof)
+load_binaries (void)
{
return 0;
}
}
static void
-dump_unmanaged_coderefs (MonoProfiler *prof)
+dump_unmanaged_coderefs (void)
{
int i;
const char* last_symbol;
uintptr_t addr, page_end;
- if (load_binaries (prof))
+ if (load_binaries ())
return;
for (i = 0; i < size_code_pages; ++i) {
const char* sym;
last_symbol = sym;
if (!sym)
continue;
- dump_usym (prof, sym, addr, 0); /* let's not guess the size */
- //printf ("found symbol at %p: %s\n", (void*)addr, sym);
+ dump_usym (sym, addr, 0); /* let's not guess the size */
}
}
}
-typedef struct MonoCounterAgent {
- MonoCounter *counter;
- // MonoCounterAgent specific data :
- void *value;
- size_t value_size;
- short index;
- short emitted;
- struct MonoCounterAgent *next;
-} MonoCounterAgent;
-
-static MonoCounterAgent* counters;
-static int counters_index = 1;
-static mono_mutex_t counters_mutex;
-
static void
counters_add_agent (MonoCounter *counter)
{
- if (InterlockedRead (&in_shutdown))
+ if (InterlockedRead (&log_profiler.in_shutdown))
return;
MonoCounterAgent *agent, *item;
- mono_os_mutex_lock (&counters_mutex);
+ mono_os_mutex_lock (&log_profiler.counters_mutex);
- for (agent = counters; agent; agent = agent->next) {
+ for (agent = log_profiler.counters; agent; agent = agent->next) {
if (agent->counter == counter) {
agent->value_size = 0;
if (agent->value) {
agent->counter = counter;
agent->value = NULL;
agent->value_size = 0;
- agent->index = counters_index++;
- agent->emitted = 0;
+ agent->index = log_profiler.counters_index++;
+ agent->emitted = FALSE;
agent->next = NULL;
- if (!counters) {
- counters = agent;
+ if (!log_profiler.counters) {
+ log_profiler.counters = agent;
} else {
- item = counters;
+ item = log_profiler.counters;
while (item->next)
item = item->next;
item->next = agent;
}
done:
- mono_os_mutex_unlock (&counters_mutex);
+ mono_os_mutex_unlock (&log_profiler.counters_mutex);
}
static mono_bool
}
static void
-counters_init (MonoProfiler *profiler)
+counters_init (void)
{
- mono_os_mutex_init (&counters_mutex);
+ mono_os_mutex_init (&log_profiler.counters_mutex);
+
+ log_profiler.counters_index = 1;
mono_counters_on_register (&counters_add_agent);
mono_counters_foreach (counters_init_foreach_callback, NULL);
}
static void
-counters_emit (MonoProfiler *profiler)
+counters_emit (void)
{
MonoCounterAgent *agent;
int len = 0;
LEB128_SIZE /* len */
;
- mono_os_mutex_lock (&counters_mutex);
+ mono_os_mutex_lock (&log_profiler.counters_mutex);
- for (agent = counters; agent; agent = agent->next) {
+ for (agent = log_profiler.counters; agent; agent = agent->next) {
if (agent->emitted)
continue;
emit_event (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE);
emit_value (logbuffer, len);
- for (agent = counters; agent; agent = agent->next) {
+ for (agent = log_profiler.counters; agent; agent = agent->next) {
const char *name;
if (agent->emitted)
emit_byte (logbuffer, mono_counter_get_variance (agent->counter));
emit_value (logbuffer, agent->index);
- agent->emitted = 1;
+ agent->emitted = TRUE;
}
- EXIT_LOG_EXPLICIT (DO_SEND);
+ EXIT_LOG;
done:
- mono_os_mutex_unlock (&counters_mutex);
+ mono_os_mutex_unlock (&log_profiler.counters_mutex);
}
static void
-counters_sample (MonoProfiler *profiler, uint64_t timestamp)
+counters_sample (uint64_t timestamp)
{
MonoCounterAgent *agent;
MonoCounter *counter;
void *buffer;
int size;
- counters_emit (profiler);
+ counters_emit ();
buffer_size = 8;
buffer = g_calloc (1, buffer_size);
- mono_os_mutex_lock (&counters_mutex);
+ mono_os_mutex_lock (&log_profiler.counters_mutex);
size =
EVENT_SIZE /* event */
;
- for (agent = counters; agent; agent = agent->next) {
+ for (agent = log_profiler.counters; agent; agent = agent->next) {
size +=
LEB128_SIZE /* index */ +
BYTE_SIZE /* type */ +
emit_event_time (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE, timestamp);
- for (agent = counters; agent; agent = agent->next) {
+ for (agent = log_profiler.counters; agent; agent = agent->next) {
size_t size;
counter = agent->counter;
emit_value (logbuffer, 0);
- EXIT_LOG_EXPLICIT (DO_SEND);
+ EXIT_LOG;
- mono_os_mutex_unlock (&counters_mutex);
+ mono_os_mutex_unlock (&log_profiler.counters_mutex);
}
-typedef struct _PerfCounterAgent PerfCounterAgent;
-struct _PerfCounterAgent {
- PerfCounterAgent *next;
- int index;
- char *category_name;
- char *name;
- int type;
- gint64 value;
- guint8 emitted;
- guint8 updated;
- guint8 deleted;
-};
-
-static PerfCounterAgent *perfcounters = NULL;
-
static void
-perfcounters_emit (MonoProfiler *profiler)
+perfcounters_emit (void)
{
PerfCounterAgent *pcagent;
int len = 0;
LEB128_SIZE /* len */
;
- for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
+ for (pcagent = log_profiler.perfcounters; pcagent; pcagent = pcagent->next) {
if (pcagent->emitted)
continue;
emit_event (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE);
emit_value (logbuffer, len);
- for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
+ for (pcagent = log_profiler.perfcounters; pcagent; pcagent = pcagent->next) {
if (pcagent->emitted)
continue;
emit_byte (logbuffer, MONO_COUNTER_VARIABLE);
emit_value (logbuffer, pcagent->index);
- pcagent->emitted = 1;
+ pcagent->emitted = TRUE;
}
- EXIT_LOG_EXPLICIT (DO_SEND);
+ EXIT_LOG;
}
static gboolean
{
PerfCounterAgent *pcagent;
- for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
+ for (pcagent = log_profiler.perfcounters; pcagent; pcagent = pcagent->next) {
if (strcmp (pcagent->category_name, category_name) != 0 || strcmp (pcagent->name, name) != 0)
continue;
if (pcagent->value == value)
return TRUE;
pcagent->value = value;
- pcagent->updated = 1;
- pcagent->deleted = 0;
+ pcagent->updated = TRUE;
+ pcagent->deleted = FALSE;
return TRUE;
}
pcagent = g_new0 (PerfCounterAgent, 1);
- pcagent->next = perfcounters;
- pcagent->index = counters_index++;
+ pcagent->next = log_profiler.perfcounters;
+ pcagent->index = log_profiler.counters_index++;
pcagent->category_name = g_strdup (category_name);
pcagent->name = g_strdup (name);
- pcagent->type = (int) type;
pcagent->value = value;
- pcagent->emitted = 0;
- pcagent->updated = 1;
- pcagent->deleted = 0;
+ pcagent->emitted = FALSE;
+ pcagent->updated = TRUE;
+ pcagent->deleted = FALSE;
- perfcounters = pcagent;
+ log_profiler.perfcounters = pcagent;
return TRUE;
}
static void
-perfcounters_sample (MonoProfiler *profiler, uint64_t timestamp)
+perfcounters_sample (uint64_t timestamp)
{
PerfCounterAgent *pcagent;
int len = 0;
int size;
- mono_os_mutex_lock (&counters_mutex);
+ mono_os_mutex_lock (&log_profiler.counters_mutex);
/* mark all perfcounters as deleted, foreach will unmark them as necessary */
- for (pcagent = perfcounters; pcagent; pcagent = pcagent->next)
- pcagent->deleted = 1;
+ for (pcagent = log_profiler.perfcounters; pcagent; pcagent = pcagent->next)
+ pcagent->deleted = TRUE;
- mono_perfcounter_foreach (perfcounters_foreach, perfcounters);
+ mono_perfcounter_foreach (perfcounters_foreach, NULL);
- perfcounters_emit (profiler);
+ perfcounters_emit ();
size =
EVENT_SIZE /* event */
;
- for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
+ for (pcagent = log_profiler.perfcounters; pcagent; pcagent = pcagent->next) {
if (pcagent->deleted || !pcagent->updated)
continue;
emit_event_time (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE, timestamp);
- for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
+ for (pcagent = log_profiler.perfcounters; pcagent; pcagent = pcagent->next) {
if (pcagent->deleted || !pcagent->updated)
continue;
emit_uvalue (logbuffer, pcagent->index);
emit_byte (logbuffer, MONO_COUNTER_LONG);
emit_svalue (logbuffer, pcagent->value);
- pcagent->updated = 0;
+ pcagent->updated = FALSE;
}
emit_value (logbuffer, 0);
- EXIT_LOG_EXPLICIT (DO_SEND);
+ EXIT_LOG;
done:
- mono_os_mutex_unlock (&counters_mutex);
+ mono_os_mutex_unlock (&log_profiler.counters_mutex);
}
static void
-counters_and_perfcounters_sample (MonoProfiler *prof)
+counters_and_perfcounters_sample (void)
{
uint64_t now = current_time ();
- counters_sample (prof, now);
- perfcounters_sample (prof, now);
+ counters_sample (now);
+ perfcounters_sample (now);
}
-#define COVERAGE_DEBUG(x) if (debug_coverage) {x}
-static mono_mutex_t coverage_mutex;
-static MonoConcurrentHashTable *coverage_methods = NULL;
-static MonoConcurrentHashTable *coverage_assemblies = NULL;
-static MonoConcurrentHashTable *coverage_classes = NULL;
-
-static MonoConcurrentHashTable *filtered_classes = NULL;
-static MonoConcurrentHashTable *image_to_methods = NULL;
-static MonoConcurrentHashTable *suppressed_assemblies = NULL;
-static gboolean coverage_initialized = FALSE;
-
-static GPtrArray *coverage_data = NULL;
-static int previous_offset = 0;
-
typedef struct {
MonoLockFreeQueueNode node;
MonoMethod *method;
static void
obtain_coverage_for_method (MonoProfiler *prof, const MonoProfilerCoverageData *entry)
{
- int offset = entry->il_offset - previous_offset;
+ int offset = entry->il_offset - log_profiler.coverage_previous_offset;
CoverageEntry *e = g_new (CoverageEntry, 1);
- previous_offset = entry->il_offset;
+ log_profiler.coverage_previous_offset = entry->il_offset;
e->offset = offset;
e->counter = entry->counter;
e->line = entry->line;
e->column = entry->column;
- g_ptr_array_add (coverage_data, e);
+ g_ptr_array_add (log_profiler.coverage_data, e);
}
static char *
return ret;
}
-static int method_id;
static void
build_method_buffer (gpointer key, gpointer value, gpointer userdata)
{
MonoMethod *method = (MonoMethod *)value;
- MonoProfiler *prof = (MonoProfiler *)userdata;
MonoClass *klass;
MonoImage *image;
char *class_name;
const char *image_name, *method_name, *sig, *first_filename;
guint i;
- previous_offset = 0;
- coverage_data = g_ptr_array_new ();
+ log_profiler.coverage_previous_offset = 0;
+ log_profiler.coverage_data = g_ptr_array_new ();
- mono_profiler_get_coverage_data (prof->handle, method, obtain_coverage_for_method);
+ mono_profiler_get_coverage_data (log_profiler.handle, method, obtain_coverage_for_method);
klass = mono_method_get_class (method);
image = mono_class_get_image (klass);
class_name = parse_generic_type_names (mono_type_get_name (mono_class_get_type (klass)));
method_name = mono_method_get_name (method);
- if (coverage_data->len != 0) {
- CoverageEntry *entry = (CoverageEntry *)coverage_data->pdata[0];
+ if (log_profiler.coverage_data->len != 0) {
+ CoverageEntry *entry = (CoverageEntry *)log_profiler.coverage_data->pdata[0];
first_filename = entry->filename ? entry->filename : "";
} else
first_filename = "";
emit_string (logbuffer, first_filename, strlen (first_filename) + 1);
emit_uvalue (logbuffer, mono_method_get_token (method));
- emit_uvalue (logbuffer, method_id);
- emit_value (logbuffer, coverage_data->len);
+ emit_uvalue (logbuffer, log_profiler.coverage_method_id);
+ emit_value (logbuffer, log_profiler.coverage_data->len);
- EXIT_LOG_EXPLICIT (DO_SEND);
+ EXIT_LOG;
- for (i = 0; i < coverage_data->len; i++) {
- CoverageEntry *entry = (CoverageEntry *)coverage_data->pdata[i];
+ for (i = 0; i < log_profiler.coverage_data->len; i++) {
+ CoverageEntry *entry = (CoverageEntry *)log_profiler.coverage_data->pdata[i];
ENTER_LOG (&coverage_statements_ctr, logbuffer,
EVENT_SIZE /* event */ +
);
emit_event (logbuffer, TYPE_COVERAGE_STATEMENT | TYPE_COVERAGE);
- emit_uvalue (logbuffer, method_id);
+ emit_uvalue (logbuffer, log_profiler.coverage_method_id);
emit_uvalue (logbuffer, entry->offset);
emit_uvalue (logbuffer, entry->counter);
emit_uvalue (logbuffer, entry->line);
emit_uvalue (logbuffer, entry->column);
- EXIT_LOG_EXPLICIT (DO_SEND);
+ EXIT_LOG;
}
- method_id++;
+ log_profiler.coverage_method_id++;
g_free (class_name);
- g_ptr_array_foreach (coverage_data, free_coverage_entry, NULL);
- g_ptr_array_free (coverage_data, TRUE);
- coverage_data = NULL;
+ g_ptr_array_foreach (log_profiler.coverage_data, free_coverage_entry, NULL);
+ g_ptr_array_free (log_profiler.coverage_data, TRUE);
}
/* This empties the queue */
emit_uvalue (logbuffer, fully_covered);
emit_uvalue (logbuffer, partially_covered);
- EXIT_LOG_EXPLICIT (DO_SEND);
+ EXIT_LOG;
g_free (class_name);
}
static void
get_coverage_for_image (MonoImage *image, int *number_of_methods, guint *fully_covered, int *partially_covered)
{
- MonoLockFreeQueue *image_methods = (MonoLockFreeQueue *)mono_conc_hashtable_lookup (image_to_methods, image);
+ MonoLockFreeQueue *image_methods = (MonoLockFreeQueue *)mono_conc_hashtable_lookup (log_profiler.coverage_image_to_methods, image);
*number_of_methods = mono_image_get_table_rows (image, MONO_TABLE_METHOD);
if (image_methods)
emit_uvalue (logbuffer, fully_covered);
emit_uvalue (logbuffer, partially_covered);
- EXIT_LOG_EXPLICIT (DO_SEND);
+ EXIT_LOG;
}
static void
-dump_coverage (MonoProfiler *prof)
+dump_coverage (void)
{
- if (!coverage_initialized)
- return;
-
- COVERAGE_DEBUG(fprintf (stderr, "Coverage: Started dump\n");)
- method_id = 0;
-
- mono_os_mutex_lock (&coverage_mutex);
- mono_conc_hashtable_foreach (coverage_assemblies, build_assembly_buffer, NULL);
- mono_conc_hashtable_foreach (coverage_classes, build_class_buffer, NULL);
- mono_conc_hashtable_foreach (coverage_methods, build_method_buffer, prof);
- mono_os_mutex_unlock (&coverage_mutex);
-
- COVERAGE_DEBUG(fprintf (stderr, "Coverage: Finished dump\n");)
+ mono_os_mutex_lock (&log_profiler.coverage_mutex);
+ mono_conc_hashtable_foreach (log_profiler.coverage_assemblies, build_assembly_buffer, NULL);
+ mono_conc_hashtable_foreach (log_profiler.coverage_classes, build_class_buffer, NULL);
+ mono_conc_hashtable_foreach (log_profiler.coverage_methods, build_method_buffer, NULL);
+ mono_os_mutex_unlock (&log_profiler.coverage_mutex);
}
static MonoLockFreeQueueNode *
MonoLockFreeQueue *image_methods, *class_methods;
MonoLockFreeQueueNode *node;
- g_assert (coverage_initialized && "Why are we being asked for coverage filter info when we're not doing coverage?");
-
- COVERAGE_DEBUG(fprintf (stderr, "Coverage filter for %s\n", mono_method_get_name (method));)
-
flags = mono_method_get_flags (method, &iflags);
- if ((iflags & 0x1000 /*METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL*/) ||
- (flags & 0x2000 /*METHOD_ATTRIBUTE_PINVOKE_IMPL*/)) {
- COVERAGE_DEBUG(fprintf (stderr, " Internal call or pinvoke - ignoring\n");)
+ if ((iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
+ (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
return FALSE;
- }
// Don't need to do anything else if we're already tracking this method
- if (mono_conc_hashtable_lookup (coverage_methods, method)) {
- COVERAGE_DEBUG(fprintf (stderr, " Already tracking\n");)
+ if (mono_conc_hashtable_lookup (log_profiler.coverage_methods, method))
return TRUE;
- }
klass = mono_method_get_class (method);
image = mono_class_get_image (klass);
// Don't handle coverage for the core assemblies
- if (mono_conc_hashtable_lookup (suppressed_assemblies, (gpointer) mono_image_get_name (image)) != NULL)
+ if (mono_conc_hashtable_lookup (log_profiler.coverage_suppressed_assemblies, (gpointer) mono_image_get_name (image)) != NULL)
return FALSE;
if (prof->coverage_filters) {
/* Check already filtered classes first */
- if (mono_conc_hashtable_lookup (filtered_classes, klass)) {
- COVERAGE_DEBUG(fprintf (stderr, " Already filtered\n");)
+ if (mono_conc_hashtable_lookup (log_profiler.coverage_filtered_classes, klass))
return FALSE;
- }
classname = mono_type_get_name (mono_class_get_type (klass));
fqn = g_strdup_printf ("[%s]%s", mono_image_get_name (image), classname);
- COVERAGE_DEBUG(fprintf (stderr, " Looking for %s in filter\n", fqn);)
// Check positive filters first
has_positive = FALSE;
found = FALSE;
if (filter [0] == '+') {
filter = &filter [1];
- COVERAGE_DEBUG(fprintf (stderr, " Checking against +%s ...", filter);)
-
- if (strstr (fqn, filter) != NULL) {
- COVERAGE_DEBUG(fprintf (stderr, "matched\n");)
+ if (strstr (fqn, filter) != NULL)
found = TRUE;
- } else
- COVERAGE_DEBUG(fprintf (stderr, "no match\n");)
has_positive = TRUE;
}
}
if (has_positive && !found) {
- COVERAGE_DEBUG(fprintf (stderr, " Positive match was not found\n");)
-
- mono_os_mutex_lock (&coverage_mutex);
- mono_conc_hashtable_insert (filtered_classes, klass, klass);
- mono_os_mutex_unlock (&coverage_mutex);
+ mono_os_mutex_lock (&log_profiler.coverage_mutex);
+ mono_conc_hashtable_insert (log_profiler.coverage_filtered_classes, klass, klass);
+ mono_os_mutex_unlock (&log_profiler.coverage_mutex);
g_free (fqn);
g_free (classname);
// Skip '-'
filter = &filter [1];
- COVERAGE_DEBUG(fprintf (stderr, " Checking against -%s ...", filter);)
if (strstr (fqn, filter) != NULL) {
- COVERAGE_DEBUG(fprintf (stderr, "matched\n");)
-
- mono_os_mutex_lock (&coverage_mutex);
- mono_conc_hashtable_insert (filtered_classes, klass, klass);
- mono_os_mutex_unlock (&coverage_mutex);
+ mono_os_mutex_lock (&log_profiler.coverage_mutex);
+ mono_conc_hashtable_insert (log_profiler.coverage_filtered_classes, klass, klass);
+ mono_os_mutex_unlock (&log_profiler.coverage_mutex);
g_free (fqn);
g_free (classname);
return FALSE;
- } else
- COVERAGE_DEBUG(fprintf (stderr, "no match\n");)
-
+ }
}
g_free (fqn);
g_free (classname);
}
- COVERAGE_DEBUG(fprintf (stderr, " Handling coverage for %s\n", mono_method_get_name (method));)
header = mono_method_get_header_checked (method, &error);
mono_error_cleanup (&error);
// generated causing a crash. See https://bugzilla.xamarin.com/show_bug.cgi?id=39325
mono_assembly_addref (assembly);
- mono_os_mutex_lock (&coverage_mutex);
- mono_conc_hashtable_insert (coverage_methods, method, method);
- mono_conc_hashtable_insert (coverage_assemblies, assembly, assembly);
- mono_os_mutex_unlock (&coverage_mutex);
+ mono_os_mutex_lock (&log_profiler.coverage_mutex);
+ mono_conc_hashtable_insert (log_profiler.coverage_methods, method, method);
+ mono_conc_hashtable_insert (log_profiler.coverage_assemblies, assembly, assembly);
+ mono_os_mutex_unlock (&log_profiler.coverage_mutex);
- image_methods = (MonoLockFreeQueue *)mono_conc_hashtable_lookup (image_to_methods, image);
+ image_methods = (MonoLockFreeQueue *)mono_conc_hashtable_lookup (log_profiler.coverage_image_to_methods, image);
if (image_methods == NULL) {
image_methods = (MonoLockFreeQueue *) g_malloc (sizeof (MonoLockFreeQueue));
mono_lock_free_queue_init (image_methods);
- mono_os_mutex_lock (&coverage_mutex);
- mono_conc_hashtable_insert (image_to_methods, image, image_methods);
- mono_os_mutex_unlock (&coverage_mutex);
+ mono_os_mutex_lock (&log_profiler.coverage_mutex);
+ mono_conc_hashtable_insert (log_profiler.coverage_image_to_methods, image, image_methods);
+ mono_os_mutex_unlock (&log_profiler.coverage_mutex);
}
node = create_method_node (method);
mono_lock_free_queue_enqueue (image_methods, node);
- class_methods = (MonoLockFreeQueue *)mono_conc_hashtable_lookup (coverage_classes, klass);
+ class_methods = (MonoLockFreeQueue *)mono_conc_hashtable_lookup (log_profiler.coverage_classes, klass);
if (class_methods == NULL) {
class_methods = (MonoLockFreeQueue *) g_malloc (sizeof (MonoLockFreeQueue));
mono_lock_free_queue_init (class_methods);
- mono_os_mutex_lock (&coverage_mutex);
- mono_conc_hashtable_insert (coverage_classes, klass, class_methods);
- mono_os_mutex_unlock (&coverage_mutex);
+ mono_os_mutex_lock (&log_profiler.coverage_mutex);
+ mono_conc_hashtable_insert (log_profiler.coverage_classes, klass, class_methods);
+ mono_os_mutex_unlock (&log_profiler.coverage_mutex);
}
node = create_method_node (method);
char *line;
FILE *sa_file;
- suppressed_assemblies = mono_conc_hashtable_new (g_str_hash, g_str_equal);
+ log_profiler.coverage_suppressed_assemblies = mono_conc_hashtable_new (g_str_hash, g_str_equal);
sa_file = fopen (SUPPRESSION_DIR "/mono-profiler-log.suppression", "r");
if (sa_file == NULL)
return;
/* Don't need to free @content as it is referred to by the lines stored in @suppressed_assemblies */
content = get_file_content (sa_file);
- if (content == NULL) {
- g_error ("mono-profiler-log.suppression is greater than 128kb - aborting\n");
- }
+ if (content == NULL)
+ g_error ("mono-profiler-log.suppression is greater than 128kb - aborting.");
while ((line = get_next_line (content, &content))) {
line = g_strchomp (g_strchug (line));
/* No locking needed as we're doing initialization */
- mono_conc_hashtable_insert (suppressed_assemblies, line, line);
+ mono_conc_hashtable_insert (log_profiler.coverage_suppressed_assemblies, line, line);
}
fclose (sa_file);
static void
parse_cov_filter_file (GPtrArray *filters, const char *file)
{
- FILE *filter_file;
- char *line, *content;
+ FILE *filter_file = fopen (file, "r");
- filter_file = fopen (file, "r");
if (filter_file == NULL) {
- fprintf (stderr, "Unable to open %s\n", file);
+ mono_profiler_printf_err ("Could not open coverage filter file '%s'.", file);
return;
}
/* Don't need to free content as it is referred to by the lines stored in @filters */
- content = get_file_content (filter_file);
+ char *content = get_file_content (filter_file);
+
if (content == NULL)
- fprintf (stderr, "WARNING: %s is greater than 128kb - ignoring\n", file);
+ mono_profiler_printf_err ("Coverage filter file '%s' is larger than 128kb - ignoring.", file);
+
+ char *line;
while ((line = get_next_line (content, &content)))
g_ptr_array_add (filters, g_strchug (g_strchomp (line)));
}
static void
-coverage_init (MonoProfiler *prof)
-{
- g_assert (!coverage_initialized && "Why are we initializing coverage twice?");
-
- COVERAGE_DEBUG(fprintf (stderr, "Coverage initialized\n");)
-
- mono_os_mutex_init (&coverage_mutex);
- coverage_methods = mono_conc_hashtable_new (NULL, NULL);
- coverage_assemblies = mono_conc_hashtable_new (NULL, NULL);
- coverage_classes = mono_conc_hashtable_new (NULL, NULL);
- filtered_classes = mono_conc_hashtable_new (NULL, NULL);
- image_to_methods = mono_conc_hashtable_new (NULL, NULL);
+coverage_init (void)
+{
+ mono_os_mutex_init (&log_profiler.coverage_mutex);
+ log_profiler.coverage_methods = mono_conc_hashtable_new (NULL, NULL);
+ log_profiler.coverage_assemblies = mono_conc_hashtable_new (NULL, NULL);
+ log_profiler.coverage_classes = mono_conc_hashtable_new (NULL, NULL);
+ log_profiler.coverage_filtered_classes = mono_conc_hashtable_new (NULL, NULL);
+ log_profiler.coverage_image_to_methods = mono_conc_hashtable_new (NULL, NULL);
init_suppressed_assemblies ();
-
- coverage_initialized = TRUE;
}
static void
}
static void
-cleanup_reusable_samples (MonoProfiler *prof)
+cleanup_reusable_samples (void)
{
SampleHit *sample;
- while ((sample = (SampleHit *) mono_lock_free_queue_dequeue (&prof->sample_reuse_queue)))
+ while ((sample = (SampleHit *) mono_lock_free_queue_dequeue (&log_profiler.sample_reuse_queue)))
mono_thread_hazardous_try_free (sample, free_sample_hit);
}
+static void
+log_early_shutdown (MonoProfiler *prof)
+{
+ if (log_config.hs_on_shutdown) {
+ InterlockedWrite (&log_profiler.heapshot_requested, 1);
+ mono_gc_collect (mono_gc_max_generation ());
+ }
+}
+
static void
log_shutdown (MonoProfiler *prof)
{
- InterlockedWrite (&in_shutdown, 1);
+ InterlockedWrite (&log_profiler.in_shutdown, 1);
- if (!no_counters)
- counters_and_perfcounters_sample (prof);
+ if (ENABLED (PROFLOG_COUNTER_EVENTS))
+ counters_and_perfcounters_sample ();
- dump_coverage (prof);
+ if (log_config.collect_coverage)
+ dump_coverage ();
char c = 1;
if (write (prof->pipes [1], &c, 1) != 1) {
- fprintf (stderr, "Could not write to pipe: %s\n", strerror (errno));
+ mono_profiler_printf_err ("Could not write to log profiler pipe: %s", g_strerror (errno));
exit (1);
}
mono_native_thread_join (prof->helper_thread);
- mono_os_mutex_destroy (&counters_mutex);
+ mono_os_mutex_destroy (&log_profiler.counters_mutex);
MonoCounterAgent *mc_next;
- for (MonoCounterAgent *cur = counters; cur; cur = mc_next) {
+ for (MonoCounterAgent *cur = log_profiler.counters; cur; cur = mc_next) {
mc_next = cur->next;
g_free (cur);
}
PerfCounterAgent *pc_next;
- for (PerfCounterAgent *cur = perfcounters; cur; cur = pc_next) {
+ for (PerfCounterAgent *cur = log_profiler.perfcounters; cur; cur = pc_next) {
pc_next = cur->next;
g_free (cur);
}
* not immediately removed upon calling mono_lls_remove (), by
* iterating until the head is NULL.
*/
- while (profiler_thread_list.head) {
- MONO_LLS_FOREACH_SAFE (&profiler_thread_list, MonoProfilerThread, thread) {
+ while (log_profiler.profiler_thread_list.head) {
+ MONO_LLS_FOREACH_SAFE (&log_profiler.profiler_thread_list, MonoProfilerThread, thread) {
g_assert (thread->attached && "Why is a thread in the LLS not attached?");
remove_thread (thread);
*/
mono_thread_hazardous_try_free_all ();
- cleanup_reusable_samples (prof);
+ cleanup_reusable_samples ();
/*
* Finally, make sure that all sample hits are freed. This should cover all
*/
mono_thread_hazardous_try_free_all ();
- gint32 state = InterlockedRead (&buffer_lock_state);
+ gint32 state = InterlockedRead (&log_profiler.buffer_lock_state);
g_assert (!(state & 0xFFFF) && "Why is the reader count still non-zero?");
g_assert (!(state >> 16) && "Why is the exclusive lock still held?");
mono_conc_hashtable_destroy (prof->method_table);
mono_os_mutex_destroy (&prof->method_table_mutex);
- if (coverage_initialized) {
- mono_os_mutex_lock (&coverage_mutex);
- mono_conc_hashtable_foreach (coverage_assemblies, unref_coverage_assemblies, prof);
- mono_os_mutex_unlock (&coverage_mutex);
+ if (log_config.collect_coverage) {
+ mono_os_mutex_lock (&log_profiler.coverage_mutex);
+ mono_conc_hashtable_foreach (log_profiler.coverage_assemblies, unref_coverage_assemblies, NULL);
+ mono_os_mutex_unlock (&log_profiler.coverage_mutex);
- mono_conc_hashtable_destroy (coverage_methods);
- mono_conc_hashtable_destroy (coverage_assemblies);
- mono_conc_hashtable_destroy (coverage_classes);
- mono_conc_hashtable_destroy (filtered_classes);
+ mono_conc_hashtable_destroy (log_profiler.coverage_methods);
+ mono_conc_hashtable_destroy (log_profiler.coverage_assemblies);
+ mono_conc_hashtable_destroy (log_profiler.coverage_classes);
+ mono_conc_hashtable_destroy (log_profiler.coverage_filtered_classes);
- mono_conc_hashtable_destroy (image_to_methods);
- mono_conc_hashtable_destroy (suppressed_assemblies);
- mono_os_mutex_destroy (&coverage_mutex);
+ mono_conc_hashtable_destroy (log_profiler.coverage_image_to_methods);
+ mono_conc_hashtable_destroy (log_profiler.coverage_suppressed_assemblies);
+ mono_os_mutex_destroy (&log_profiler.coverage_mutex);
}
+ mono_coop_mutex_destroy (&log_profiler.api_mutex);
+
PROF_TLS_FREE ();
g_free (prof->args);
- g_free (prof);
}
static char*
* error and exiting.
*/
if (fd >= FD_SETSIZE) {
- fprintf (stderr, "File descriptor is out of bounds for fd_set: %d\n", fd);
+ mono_profiler_printf_err ("File descriptor is out of bounds for fd_set: %d", fd);
exit (1);
}
static void *
helper_thread (void *arg)
{
- MonoProfiler *prof = (MonoProfiler *) arg;
-
mono_threads_attach_tools_thread ();
mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler helper");
- MonoProfilerThread *thread = init_thread (prof, FALSE);
+ MonoProfilerThread *thread = init_thread (FALSE);
GArray *command_sockets = g_array_new (FALSE, FALSE, sizeof (int));
FD_ZERO (&rfds);
- add_to_fd_set (&rfds, prof->server_socket, &max_fd);
- add_to_fd_set (&rfds, prof->pipes [0], &max_fd);
+ add_to_fd_set (&rfds, log_profiler.server_socket, &max_fd);
+ add_to_fd_set (&rfds, log_profiler.pipes [0], &max_fd);
for (gint i = 0; i < command_sockets->len; i++)
add_to_fd_set (&rfds, g_array_index (command_sockets, int, i), &max_fd);
if (errno == EINTR)
continue;
- fprintf (stderr, "Error in mono-profiler-log server: %s", strerror (errno));
+ mono_profiler_printf_err ("Could not poll in log profiler helper thread: %s", g_strerror (errno));
exit (1);
}
- if (!no_counters)
- counters_and_perfcounters_sample (prof);
+ if (ENABLED (PROFLOG_COUNTER_EVENTS))
+ counters_and_perfcounters_sample ();
buffer_lock_excl ();
buffer_unlock_excl ();
// Are we shutting down?
- if (FD_ISSET (prof->pipes [0], &rfds)) {
+ if (FD_ISSET (log_profiler.pipes [0], &rfds)) {
char c;
- read (prof->pipes [0], &c, 1);
+ read (log_profiler.pipes [0], &c, 1);
break;
}
buf [len] = 0;
- if (!strcmp (buf, "heapshot\n") && hs_mode_ondemand) {
+ if (log_config.hs_mode == MONO_PROFILER_HEAPSHOT_ON_DEMAND && !strcmp (buf, "heapshot\n")) {
// Rely on the finalization callback triggering a GC.
- heapshot_requested = 1;
+ InterlockedWrite (&log_profiler.heapshot_requested, 1);
mono_gc_finalize_notify ();
}
}
- if (FD_ISSET (prof->server_socket, &rfds)) {
- int fd = accept (prof->server_socket, NULL, NULL);
+ if (FD_ISSET (log_profiler.server_socket, &rfds)) {
+ int fd = accept (log_profiler.server_socket, NULL, NULL);
if (fd != -1) {
if (fd >= FD_SETSIZE)
}
static void
-start_helper_thread (MonoProfiler* prof)
+start_helper_thread (void)
{
- if (pipe (prof->pipes) == -1) {
- fprintf (stderr, "Cannot create pipe: %s\n", strerror (errno));
+ if (pipe (log_profiler.pipes) == -1) {
+ mono_profiler_printf_err ("Could not create log profiler pipe: %s", g_strerror (errno));
exit (1);
}
- prof->server_socket = socket (PF_INET, SOCK_STREAM, 0);
+ log_profiler.server_socket = socket (PF_INET, SOCK_STREAM, 0);
- if (prof->server_socket == -1) {
- fprintf (stderr, "Cannot create server socket: %s\n", strerror (errno));
+ if (log_profiler.server_socket == -1) {
+ mono_profiler_printf_err ("Could not create log profiler server socket: %s", g_strerror (errno));
exit (1);
}
memset (&server_address, 0, sizeof (server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;
- server_address.sin_port = htons (prof->command_port);
+ server_address.sin_port = htons (log_profiler.command_port);
- if (bind (prof->server_socket, (struct sockaddr *) &server_address, sizeof (server_address)) == -1) {
- fprintf (stderr, "Cannot bind server socket on port %d: %s\n", prof->command_port, strerror (errno));
- close (prof->server_socket);
+ if (bind (log_profiler.server_socket, (struct sockaddr *) &server_address, sizeof (server_address)) == -1) {
+ mono_profiler_printf_err ("Could not bind log profiler server socket on port %d: %s", log_profiler.command_port, g_strerror (errno));
+ close (log_profiler.server_socket);
exit (1);
}
- if (listen (prof->server_socket, 1) == -1) {
- fprintf (stderr, "Cannot listen on server socket: %s\n", strerror (errno));
- close (prof->server_socket);
+ if (listen (log_profiler.server_socket, 1) == -1) {
+ mono_profiler_printf_err ("Could not listen on log profiler server socket: %s", g_strerror (errno));
+ close (log_profiler.server_socket);
exit (1);
}
socklen_t slen = sizeof (server_address);
- if (getsockname (prof->server_socket, (struct sockaddr *) &server_address, &slen)) {
- fprintf (stderr, "Could not get assigned port: %s\n", strerror (errno));
- close (prof->server_socket);
+ if (getsockname (log_profiler.server_socket, (struct sockaddr *) &server_address, &slen)) {
+ mono_profiler_printf_err ("Could not retrieve assigned port for log profiler server socket: %s", g_strerror (errno));
+ close (log_profiler.server_socket);
exit (1);
}
- prof->command_port = ntohs (server_address.sin_port);
+ log_profiler.command_port = ntohs (server_address.sin_port);
- if (!mono_native_thread_create (&prof->helper_thread, helper_thread, prof)) {
- fprintf (stderr, "Could not start helper thread\n");
- close (prof->server_socket);
+ if (!mono_native_thread_create (&log_profiler.helper_thread, helper_thread, NULL)) {
+ mono_profiler_printf_err ("Could not start log profiler helper thread");
+ close (log_profiler.server_socket);
exit (1);
}
}
}
static gboolean
-handle_writer_queue_entry (MonoProfiler *prof)
+handle_writer_queue_entry (void)
{
WriterQueueEntry *entry;
- if ((entry = (WriterQueueEntry *) mono_lock_free_queue_dequeue (&prof->writer_queue))) {
+ if ((entry = (WriterQueueEntry *) mono_lock_free_queue_dequeue (&log_profiler.writer_queue))) {
if (!entry->methods)
goto no_methods;
for (guint i = 0; i < entry->methods->len; i++) {
MethodInfo *info = (MethodInfo *) g_ptr_array_index (entry->methods, i);
- if (mono_conc_hashtable_lookup (prof->method_table, info->method))
+ if (mono_conc_hashtable_lookup (log_profiler.method_table, info->method))
goto free_info; // This method already has metadata emitted.
/*
* method lists will just be empty for the rest of the
* app's lifetime.
*/
- mono_os_mutex_lock (&prof->method_table_mutex);
- mono_conc_hashtable_insert (prof->method_table, info->method, info->method);
- mono_os_mutex_unlock (&prof->method_table_mutex);
+ mono_os_mutex_lock (&log_profiler.method_table_mutex);
+ mono_conc_hashtable_insert (log_profiler.method_table, info->method, info->method);
+ mono_os_mutex_unlock (&log_profiler.method_table_mutex);
char *name = mono_method_full_name (info->method, 1);
int nlen = strlen (name) + 1;
if (wrote_methods) {
MonoProfilerThread *thread = PROF_TLS_GET ();
- dump_buffer_threadless (prof, thread->buffer);
+ dump_buffer_threadless (thread->buffer);
init_buffer_state (thread);
}
no_methods:
- dump_buffer (prof, entry->buffer);
+ dump_buffer (entry->buffer);
mono_thread_hazardous_try_free (entry, free_writer_entry);
static void *
writer_thread (void *arg)
{
- MonoProfiler *prof = (MonoProfiler *)arg;
-
mono_threads_attach_tools_thread ();
mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler writer");
- dump_header (prof);
+ dump_header ();
- MonoProfilerThread *thread = init_thread (prof, FALSE);
+ MonoProfilerThread *thread = init_thread (FALSE);
- while (InterlockedRead (&prof->run_writer_thread)) {
- mono_os_sem_wait (&prof->writer_queue_sem, MONO_SEM_FLAGS_NONE);
- handle_writer_queue_entry (prof);
+ while (InterlockedRead (&log_profiler.run_writer_thread)) {
+ mono_os_sem_wait (&log_profiler.writer_queue_sem, MONO_SEM_FLAGS_NONE);
+ handle_writer_queue_entry ();
}
/* Drain any remaining entries on shutdown. */
- while (handle_writer_queue_entry (prof));
+ while (handle_writer_queue_entry ());
free_buffer (thread->buffer, thread->buffer->size);
deinit_thread (thread);
}
static void
-start_writer_thread (MonoProfiler* prof)
+start_writer_thread (void)
{
- InterlockedWrite (&prof->run_writer_thread, 1);
+ InterlockedWrite (&log_profiler.run_writer_thread, 1);
- if (!mono_native_thread_create (&prof->writer_thread, writer_thread, prof)) {
- fprintf (stderr, "Could not start writer thread\n");
+ if (!mono_native_thread_create (&log_profiler.writer_thread, writer_thread, NULL)) {
+ mono_profiler_printf_err ("Could not start log profiler writer thread");
exit (1);
}
}
SampleHit *sample = p;
mono_lock_free_queue_node_unpoison (&sample->node);
- mono_lock_free_queue_enqueue (&sample->prof->sample_reuse_queue, &sample->node);
+ mono_lock_free_queue_enqueue (&log_profiler.sample_reuse_queue, &sample->node);
}
static gboolean
-handle_dumper_queue_entry (MonoProfiler *prof)
+handle_dumper_queue_entry (void)
{
SampleHit *sample;
- if ((sample = (SampleHit *) mono_lock_free_queue_dequeue (&prof->dumper_queue))) {
+ if ((sample = (SampleHit *) mono_lock_free_queue_dequeue (&log_profiler.dumper_queue))) {
for (int i = 0; i < sample->count; ++i) {
MonoMethod *method = sample->frames [i].method;
MonoDomain *domain = sample->frames [i].domain;
ENTER_LOG (&sample_hits_ctr, logbuffer,
EVENT_SIZE /* event */ +
- BYTE_SIZE /* type */ +
LEB128_SIZE /* tid */ +
LEB128_SIZE /* count */ +
1 * (
for (int i = 0; i < sample->count; ++i)
emit_method (logbuffer, sample->frames [i].method);
- EXIT_LOG_EXPLICIT (DO_SEND);
+ EXIT_LOG;
mono_thread_hazardous_try_free (sample, reuse_sample_hit);
- dump_unmanaged_coderefs (prof);
+ dump_unmanaged_coderefs ();
}
return FALSE;
static void *
dumper_thread (void *arg)
{
- MonoProfiler *prof = (MonoProfiler *)arg;
-
mono_threads_attach_tools_thread ();
mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler dumper");
- MonoProfilerThread *thread = init_thread (prof, FALSE);
+ MonoProfilerThread *thread = init_thread (FALSE);
- while (InterlockedRead (&prof->run_dumper_thread)) {
+ while (InterlockedRead (&log_profiler.run_dumper_thread)) {
/*
* Flush samples every second so it doesn't seem like the profiler is
* not working if the program is mostly idle.
*/
- if (mono_os_sem_timedwait (&prof->dumper_queue_sem, 1000, MONO_SEM_FLAGS_NONE) == MONO_SEM_TIMEDWAIT_RET_TIMEDOUT)
+ if (mono_os_sem_timedwait (&log_profiler.dumper_queue_sem, 1000, MONO_SEM_FLAGS_NONE) == MONO_SEM_TIMEDWAIT_RET_TIMEDOUT)
send_log_unsafe (FALSE);
- handle_dumper_queue_entry (prof);
+ handle_dumper_queue_entry ();
}
/* Drain any remaining entries on shutdown. */
- while (handle_dumper_queue_entry (prof));
+ while (handle_dumper_queue_entry ());
send_log_unsafe (FALSE);
deinit_thread (thread);
}
static void
-start_dumper_thread (MonoProfiler* prof)
+start_dumper_thread (void)
{
- InterlockedWrite (&prof->run_dumper_thread, 1);
+ InterlockedWrite (&log_profiler.run_dumper_thread, 1);
- if (!mono_native_thread_create (&prof->dumper_thread, dumper_thread, prof)) {
- fprintf (stderr, "Could not start dumper thread\n");
+ if (!mono_native_thread_create (&log_profiler.dumper_thread, dumper_thread, NULL)) {
+ mono_profiler_printf_err ("Could not start log profiler dumper thread");
exit (1);
}
}
mono_counters_register (name, MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, counter);
}
+ICALL_EXPORT gint32
+proflog_icall_GetMaxStackTraceFrames (void)
+{
+ return MAX_FRAMES;
+}
+
+ICALL_EXPORT gint32
+proflog_icall_GetStackTraceFrames (void)
+{
+ return log_config.num_frames;
+}
+
+ICALL_EXPORT void
+proflog_icall_SetStackTraceFrames (gint32 value)
+{
+ log_config.num_frames = value;
+}
+
+ICALL_EXPORT MonoProfilerHeapshotMode
+proflog_icall_GetHeapshotMode (void)
+{
+ return log_config.hs_mode;
+}
+
+ICALL_EXPORT void
+proflog_icall_SetHeapshotMode (MonoProfilerHeapshotMode value)
+{
+ log_config.hs_mode = value;
+}
+
+ICALL_EXPORT gint32
+proflog_icall_GetHeapshotMillisecondsFrequency (void)
+{
+ return log_config.hs_freq_ms;
+}
+
+ICALL_EXPORT void
+proflog_icall_SetHeapshotMillisecondsFrequency (gint32 value)
+{
+ log_config.hs_freq_ms = value;
+}
+
+ICALL_EXPORT gint32
+proflog_icall_GetHeapshotCollectionsFrequency (void)
+{
+ return log_config.hs_freq_gc;
+}
+
+ICALL_EXPORT void
+proflog_icall_SetHeapshotCollectionsFrequency (gint32 value)
+{
+ log_config.hs_freq_gc = value;
+}
+
+ICALL_EXPORT gint32
+proflog_icall_GetCallDepth (void)
+{
+ return log_config.max_call_depth;
+}
+
+ICALL_EXPORT void
+proflog_icall_SetCallDepth (gint32 value)
+{
+ log_config.max_call_depth = value;
+}
+
+ICALL_EXPORT void
+proflog_icall_GetSampleMode (MonoProfilerSampleMode *mode, gint32 *frequency)
+{
+ uint32_t freq;
+
+ mono_profiler_get_sample_mode (log_profiler.handle, mode, &freq);
+
+ *frequency = freq;
+}
+
+ICALL_EXPORT MonoBoolean
+proflog_icall_SetSampleMode (MonoProfilerSampleMode mode, gint32 frequency)
+{
+ mono_coop_mutex_lock (&log_profiler.api_mutex);
+
+ mono_bool result = mono_profiler_set_sample_mode (log_profiler.handle, mode, frequency);
+
+ if (mode != MONO_PROFILER_SAMPLE_MODE_NONE) {
+ ENABLE (PROFLOG_SAMPLE_EVENTS);
+ mono_profiler_set_sample_hit_callback (log_profiler.handle, mono_sample_hit);
+ } else {
+ DISABLE (PROFLOG_SAMPLE_EVENTS);
+ mono_profiler_set_sample_hit_callback (log_profiler.handle, NULL);
+ }
+
+ mono_coop_mutex_unlock (&log_profiler.api_mutex);
+
+ return result;
+}
+
+ICALL_EXPORT MonoBoolean
+proflog_icall_GetExceptionEvents (void)
+{
+ return ENABLED (PROFLOG_EXCEPTION_EVENTS);
+}
+
+ICALL_EXPORT void
+proflog_icall_SetExceptionEvents (MonoBoolean value)
+{
+ mono_coop_mutex_lock (&log_profiler.api_mutex);
+
+ if (value) {
+ ENABLE (PROFLOG_EXCEPTION_EVENTS);
+ mono_profiler_set_exception_throw_callback (log_profiler.handle, throw_exc);
+ mono_profiler_set_exception_clause_callback (log_profiler.handle, clause_exc);
+ } else {
+ DISABLE (PROFLOG_EXCEPTION_EVENTS);
+ mono_profiler_set_exception_throw_callback (log_profiler.handle, NULL);
+ mono_profiler_set_exception_clause_callback (log_profiler.handle, NULL);
+ }
+
+ mono_coop_mutex_unlock (&log_profiler.api_mutex);
+}
+
+ICALL_EXPORT MonoBoolean
+proflog_icall_GetMonitorEvents (void)
+{
+ return ENABLED (PROFLOG_MONITOR_EVENTS);
+}
+
+ICALL_EXPORT void
+proflog_icall_SetMonitorEvents (MonoBoolean value)
+{
+ mono_coop_mutex_lock (&log_profiler.api_mutex);
+
+ if (value) {
+ ENABLE (PROFLOG_EXCEPTION_EVENTS);
+ mono_profiler_set_monitor_contention_callback (log_profiler.handle, monitor_contention);
+ mono_profiler_set_monitor_acquired_callback (log_profiler.handle, monitor_acquired);
+ mono_profiler_set_monitor_failed_callback (log_profiler.handle, monitor_failed);
+ } else {
+ DISABLE (PROFLOG_EXCEPTION_EVENTS);
+ mono_profiler_set_monitor_contention_callback (log_profiler.handle, NULL);
+ mono_profiler_set_monitor_acquired_callback (log_profiler.handle, NULL);
+ mono_profiler_set_monitor_failed_callback (log_profiler.handle, NULL);
+ }
+
+ mono_coop_mutex_unlock (&log_profiler.api_mutex);
+}
+
+ICALL_EXPORT MonoBoolean
+proflog_icall_GetGCEvents (void)
+{
+ return ENABLED (PROFLOG_GC_EVENTS);
+}
+
+ICALL_EXPORT void
+proflog_icall_SetGCEvents (MonoBoolean value)
+{
+ mono_coop_mutex_lock (&log_profiler.api_mutex);
+
+ if (value)
+ ENABLE (PROFLOG_GC_EVENTS);
+ else
+ DISABLE (PROFLOG_GC_EVENTS);
+
+ mono_coop_mutex_unlock (&log_profiler.api_mutex);
+}
+
+ICALL_EXPORT MonoBoolean
+proflog_icall_GetGCAllocationEvents (void)
+{
+ return ENABLED (PROFLOG_GC_ALLOCATION_EVENTS);
+}
+
+ICALL_EXPORT void
+proflog_icall_SetGCAllocationEvents (MonoBoolean value)
+{
+ mono_coop_mutex_lock (&log_profiler.api_mutex);
+
+ if (value) {
+ ENABLE (PROFLOG_GC_ALLOCATION_EVENTS);
+ mono_profiler_set_gc_allocation_callback (log_profiler.handle, gc_alloc);
+ } else {
+ DISABLE (PROFLOG_GC_ALLOCATION_EVENTS);
+ mono_profiler_set_gc_allocation_callback (log_profiler.handle, NULL);
+ }
+
+ mono_coop_mutex_unlock (&log_profiler.api_mutex);
+}
+
+ICALL_EXPORT MonoBoolean
+proflog_icall_GetGCMoveEvents (void)
+{
+ return ENABLED (PROFLOG_GC_MOVE_EVENTS);
+}
+
+ICALL_EXPORT void
+proflog_icall_SetGCMoveEvents (MonoBoolean value)
+{
+ mono_coop_mutex_lock (&log_profiler.api_mutex);
+
+ if (value) {
+ ENABLE (PROFLOG_GC_MOVE_EVENTS);
+ mono_profiler_set_gc_moves_callback (log_profiler.handle, gc_moves);
+ } else {
+ DISABLE (PROFLOG_GC_MOVE_EVENTS);
+ mono_profiler_set_gc_moves_callback (log_profiler.handle, NULL);
+ }
+
+ mono_coop_mutex_unlock (&log_profiler.api_mutex);
+}
+
+ICALL_EXPORT MonoBoolean
+proflog_icall_GetGCRootEvents (void)
+{
+ return ENABLED (PROFLOG_GC_ROOT_EVENTS);
+}
+
+ICALL_EXPORT void
+proflog_icall_SetGCRootEvents (MonoBoolean value)
+{
+ mono_coop_mutex_lock (&log_profiler.api_mutex);
+
+ if (value)
+ ENABLE (PROFLOG_GC_ROOT_EVENTS);
+ else
+ DISABLE (PROFLOG_GC_ROOT_EVENTS);
+
+ mono_coop_mutex_unlock (&log_profiler.api_mutex);
+}
+
+ICALL_EXPORT MonoBoolean
+proflog_icall_GetGCHandleEvents (void)
+{
+ return ENABLED (PROFLOG_GC_HANDLE_EVENTS);
+}
+
+ICALL_EXPORT void
+proflog_icall_SetGCHandleEvents (MonoBoolean value)
+{
+ mono_coop_mutex_lock (&log_profiler.api_mutex);
+
+ if (value) {
+ ENABLE (PROFLOG_GC_HANDLE_EVENTS);
+ mono_profiler_set_gc_handle_created_callback (log_profiler.handle, gc_handle_created);
+ mono_profiler_set_gc_handle_deleted_callback (log_profiler.handle, gc_handle_deleted);
+ } else {
+ DISABLE (PROFLOG_GC_HANDLE_EVENTS);
+ mono_profiler_set_gc_handle_created_callback (log_profiler.handle, NULL);
+ mono_profiler_set_gc_handle_deleted_callback (log_profiler.handle, NULL);
+ }
+
+ mono_coop_mutex_unlock (&log_profiler.api_mutex);
+}
+
+ICALL_EXPORT MonoBoolean
+proflog_icall_GetGCFinalizationEvents (void)
+{
+ return ENABLED (PROFLOG_GC_FINALIZATION_EVENTS);
+}
+
+ICALL_EXPORT void
+proflog_icall_SetGCFinalizationEvents (MonoBoolean value)
+{
+ mono_coop_mutex_lock (&log_profiler.api_mutex);
+
+ if (value) {
+ ENABLE (PROFLOG_GC_FINALIZATION_EVENTS);
+ mono_profiler_set_gc_finalizing_callback (log_profiler.handle, finalize_begin);
+ mono_profiler_set_gc_finalizing_object_callback (log_profiler.handle, finalize_object_begin);
+ mono_profiler_set_gc_finalized_object_callback (log_profiler.handle, finalize_object_end);
+ } else {
+ DISABLE (PROFLOG_GC_FINALIZATION_EVENTS);
+ mono_profiler_set_gc_finalizing_callback (log_profiler.handle, NULL);
+ mono_profiler_set_gc_finalizing_object_callback (log_profiler.handle, NULL);
+ mono_profiler_set_gc_finalized_object_callback (log_profiler.handle, NULL);
+ }
+
+ mono_coop_mutex_unlock (&log_profiler.api_mutex);
+}
+
+ICALL_EXPORT MonoBoolean
+proflog_icall_GetCounterEvents (void)
+{
+ return ENABLED (PROFLOG_COUNTER_EVENTS);
+}
+
+ICALL_EXPORT void
+proflog_icall_SetCounterEvents (MonoBoolean value)
+{
+ mono_coop_mutex_lock (&log_profiler.api_mutex);
+
+ if (value)
+ ENABLE (PROFLOG_COUNTER_EVENTS);
+ else
+ DISABLE (PROFLOG_COUNTER_EVENTS);
+
+ mono_coop_mutex_unlock (&log_profiler.api_mutex);
+}
+
+ICALL_EXPORT MonoBoolean
+proflog_icall_GetJitEvents (void)
+{
+ return ENABLED (PROFLOG_JIT_EVENTS);
+}
+
+ICALL_EXPORT void
+proflog_icall_SetJitEvents (MonoBoolean value)
+{
+ mono_coop_mutex_lock (&log_profiler.api_mutex);
+
+ if (value) {
+ ENABLE (PROFLOG_JIT_EVENTS);
+ mono_profiler_set_jit_code_buffer_callback (log_profiler.handle, code_buffer_new);
+ } else {
+ DISABLE (PROFLOG_JIT_EVENTS);
+ mono_profiler_set_jit_code_buffer_callback (log_profiler.handle, NULL);
+ }
+
+ mono_coop_mutex_unlock (&log_profiler.api_mutex);
+}
+
static void
runtime_initialized (MonoProfiler *profiler)
{
- InterlockedWrite (&runtime_inited, 1);
+ InterlockedWrite (&log_profiler.runtime_inited, 1);
register_counter ("Sample events allocated", &sample_allocations_ctr);
register_counter ("Log buffers allocated", &buffer_allocations_ctr);
register_counter ("Event: Coverage classes", &coverage_classes_ctr);
register_counter ("Event: Coverage assemblies", &coverage_assemblies_ctr);
- counters_init (profiler);
+ counters_init ();
/*
* We must start the helper thread before the writer thread. This is
* because the helper thread sets up the command port which is written to
* the log header by the writer thread.
*/
- start_helper_thread (profiler);
- start_writer_thread (profiler);
- start_dumper_thread (profiler);
+ start_helper_thread ();
+ start_writer_thread ();
+ start_dumper_thread ();
+
+ mono_coop_mutex_init (&log_profiler.api_mutex);
+
+#define ADD_ICALL(NAME) \
+ mono_add_internal_call ("Mono.Profiler.Log.LogProfiler::" EGLIB_STRINGIFY (NAME), proflog_icall_ ## NAME);
+
+ ADD_ICALL (GetMaxStackTraceFrames);
+ ADD_ICALL (GetStackTraceFrames);
+ ADD_ICALL (SetStackTraceFrames);
+ ADD_ICALL (GetHeapshotMode);
+ ADD_ICALL (SetHeapshotMode);
+ ADD_ICALL (GetHeapshotMillisecondsFrequency);
+ ADD_ICALL (SetHeapshotMillisecondsFrequency);
+ ADD_ICALL (GetHeapshotCollectionsFrequency);
+ ADD_ICALL (SetHeapshotCollectionsFrequency);
+ ADD_ICALL (GetCallDepth);
+ ADD_ICALL (SetCallDepth);
+ ADD_ICALL (GetSampleMode);
+ ADD_ICALL (SetSampleMode);
+ ADD_ICALL (GetExceptionEvents);
+ ADD_ICALL (SetExceptionEvents);
+ ADD_ICALL (GetMonitorEvents);
+ ADD_ICALL (SetMonitorEvents);
+ ADD_ICALL (GetGCEvents);
+ ADD_ICALL (SetGCEvents);
+ ADD_ICALL (GetGCAllocationEvents);
+ ADD_ICALL (SetGCAllocationEvents);
+ ADD_ICALL (GetGCMoveEvents);
+ ADD_ICALL (SetGCMoveEvents);
+ ADD_ICALL (GetGCRootEvents);
+ ADD_ICALL (SetGCRootEvents);
+ ADD_ICALL (GetGCHandleEvents);
+ ADD_ICALL (SetGCHandleEvents);
+ ADD_ICALL (GetGCFinalizationEvents);
+ ADD_ICALL (SetGCFinalizationEvents);
+ ADD_ICALL (GetCounterEvents);
+ ADD_ICALL (SetCounterEvents);
+ ADD_ICALL (GetJitEvents);
+ ADD_ICALL (SetJitEvents);
+
+#undef ADD_ICALL
}
static void
create_profiler (const char *args, const char *filename, GPtrArray *filters)
{
char *nf;
- int force_delete = 0;
- log_profiler = (MonoProfiler *) g_calloc (1, sizeof (MonoProfiler));
- log_profiler->args = pstrdup (args);
- log_profiler->command_port = command_port;
-
- if (filename && *filename == '-') {
- force_delete = 1;
- filename++;
- g_warning ("WARNING: the output:-FILENAME option is deprecated, the profiler now always overrides the output file\n");
- }
+ log_profiler.args = pstrdup (args);
+ log_profiler.command_port = log_config.command_port;
//If filename begin with +, append the pid at the end
if (filename && *filename == '+')
filename = g_strdup_printf ("%s.%d", filename + 1, getpid ());
-
if (!filename) {
- if (do_report)
+ if (log_config.do_report)
filename = "|mprof-report -";
else
filename = "output.mlpd";
nf = (char*)filename;
} else {
nf = new_filename (filename);
- if (do_report) {
+ if (log_config.do_report) {
int s = strlen (nf) + 32;
char *p = (char *) g_malloc (s);
snprintf (p, s, "|mprof-report '--out=%s' -", nf);
}
}
if (*nf == '|') {
- log_profiler->file = popen (nf + 1, "w");
- log_profiler->pipe_output = 1;
+ log_profiler.file = popen (nf + 1, "w");
+ log_profiler.pipe_output = 1;
} else if (*nf == '#') {
int fd = strtol (nf + 1, NULL, 10);
- log_profiler->file = fdopen (fd, "a");
- } else {
- if (force_delete)
- unlink (nf);
- log_profiler->file = fopen (nf, "wb");
- }
- if (!log_profiler->file) {
- fprintf (stderr, "Cannot create profiler output: %s\n", nf);
+ log_profiler.file = fdopen (fd, "a");
+ } else
+ log_profiler.file = fopen (nf, "wb");
+
+ if (!log_profiler.file) {
+ mono_profiler_printf_err ("Could not create log profiler output file '%s'.", nf);
exit (1);
}
#if defined (HAVE_SYS_ZLIB)
- if (use_zip)
- log_profiler->gzfile = gzdopen (fileno (log_profiler->file), "wb");
+ if (log_config.use_zip)
+ log_profiler.gzfile = gzdopen (fileno (log_profiler.file), "wb");
#endif
/*
g_assert (SAMPLE_SLOT_SIZE (MAX_FRAMES) * 2 < LOCK_FREE_ALLOC_SB_USABLE_SIZE (SAMPLE_BLOCK_SIZE));
// FIXME: We should free this stuff too.
- mono_lock_free_allocator_init_size_class (&log_profiler->sample_size_class, SAMPLE_SLOT_SIZE (num_frames), SAMPLE_BLOCK_SIZE);
- mono_lock_free_allocator_init_allocator (&log_profiler->sample_allocator, &log_profiler->sample_size_class, MONO_MEM_ACCOUNT_PROFILER);
+ mono_lock_free_allocator_init_size_class (&log_profiler.sample_size_class, SAMPLE_SLOT_SIZE (log_config.num_frames), SAMPLE_BLOCK_SIZE);
+ mono_lock_free_allocator_init_allocator (&log_profiler.sample_allocator, &log_profiler.sample_size_class, MONO_MEM_ACCOUNT_PROFILER);
- mono_lock_free_queue_init (&log_profiler->sample_reuse_queue);
+ mono_lock_free_queue_init (&log_profiler.sample_reuse_queue);
g_assert (sizeof (WriterQueueEntry) * 2 < LOCK_FREE_ALLOC_SB_USABLE_SIZE (WRITER_ENTRY_BLOCK_SIZE));
// FIXME: We should free this stuff too.
- mono_lock_free_allocator_init_size_class (&log_profiler->writer_entry_size_class, sizeof (WriterQueueEntry), WRITER_ENTRY_BLOCK_SIZE);
- mono_lock_free_allocator_init_allocator (&log_profiler->writer_entry_allocator, &log_profiler->writer_entry_size_class, MONO_MEM_ACCOUNT_PROFILER);
+ mono_lock_free_allocator_init_size_class (&log_profiler.writer_entry_size_class, sizeof (WriterQueueEntry), WRITER_ENTRY_BLOCK_SIZE);
+ mono_lock_free_allocator_init_allocator (&log_profiler.writer_entry_allocator, &log_profiler.writer_entry_size_class, MONO_MEM_ACCOUNT_PROFILER);
+
+ mono_lock_free_queue_init (&log_profiler.writer_queue);
+ mono_os_sem_init (&log_profiler.writer_queue_sem, 0);
- mono_lock_free_queue_init (&log_profiler->writer_queue);
- mono_os_sem_init (&log_profiler->writer_queue_sem, 0);
+ mono_lock_free_queue_init (&log_profiler.dumper_queue);
+ mono_os_sem_init (&log_profiler.dumper_queue_sem, 0);
- mono_lock_free_queue_init (&log_profiler->dumper_queue);
- mono_os_sem_init (&log_profiler->dumper_queue_sem, 0);
+ mono_os_mutex_init (&log_profiler.method_table_mutex);
+ log_profiler.method_table = mono_conc_hashtable_new (NULL, NULL);
- mono_os_mutex_init (&log_profiler->method_table_mutex);
- log_profiler->method_table = mono_conc_hashtable_new (NULL, NULL);
+ if (log_config.collect_coverage)
+ coverage_init ();
- if (do_coverage)
- coverage_init (log_profiler);
- log_profiler->coverage_filters = filters;
+ log_profiler.coverage_filters = filters;
- log_profiler->startup_time = current_time ();
+ log_profiler.startup_time = current_time ();
}
/*
{
GPtrArray *filters = NULL;
- proflog_parse_args (&config, desc [3] == ':' ? desc + 4 : "");
-
- //XXX maybe later cleanup to use config directly
- nocalls = !(config.effective_mask & PROFLOG_CALL_EVENTS);
- no_counters = !(config.effective_mask & PROFLOG_COUNTER_EVENTS);
- do_report = config.do_report;
- do_debug = config.do_debug;
- do_heap_shot = (config.effective_mask & PROFLOG_HEAPSHOT_FEATURE);
- hs_mode_ondemand = config.hs_mode_ondemand;
- hs_mode_ms = config.hs_mode_ms;
- hs_mode_gc = config.hs_mode_gc;
- do_mono_sample = (config.effective_mask & PROFLOG_SAMPLING_FEATURE);
- use_zip = config.use_zip;
- command_port = config.command_port;
- num_frames = config.num_frames;
- notraces = config.notraces;
- max_allocated_sample_hits = config.max_allocated_sample_hits;
- max_call_depth = config.max_call_depth;
- do_coverage = (config.effective_mask & PROFLOG_CODE_COV_FEATURE);
- debug_coverage = config.debug_coverage;
-
- if (config.cov_filter_files) {
+ proflog_parse_args (&log_config, desc [3] == ':' ? desc + 4 : "");
+
+ if (log_config.cov_filter_files) {
filters = g_ptr_array_new ();
int i;
- for (i = 0; i < config.cov_filter_files->len; ++i) {
- const char *name = config.cov_filter_files->pdata [i];
+ for (i = 0; i < log_config.cov_filter_files->len; ++i) {
+ const char *name = log_config.cov_filter_files->pdata [i];
parse_cov_filter_file (filters, name);
}
}
PROF_TLS_INIT ();
- create_profiler (desc, config.output_filename, filters);
+ create_profiler (desc, log_config.output_filename, filters);
- mono_lls_init (&profiler_thread_list, NULL);
+ mono_lls_init (&log_profiler.profiler_thread_list, NULL);
- MonoProfilerHandle handle = log_profiler->handle = mono_profiler_install (log_profiler);
+ MonoProfilerHandle handle = log_profiler.handle = mono_profiler_install (&log_profiler);
- //Required callbacks
+ /*
+ * Required callbacks. These are either necessary for the profiler itself
+ * to function, or provide metadata that's needed if other events (e.g.
+ * allocations, exceptions) are dynamically enabled/disabled.
+ */
+
+ mono_profiler_set_runtime_shutdown_begin_callback (handle, log_early_shutdown);
mono_profiler_set_runtime_shutdown_end_callback (handle, log_shutdown);
mono_profiler_set_runtime_initialized_callback (handle, runtime_initialized);
mono_profiler_set_gc_event_callback (handle, gc_event);
- mono_profiler_set_gc_resize_callback (handle, gc_resize);
+
mono_profiler_set_thread_started_callback (handle, thread_start);
mono_profiler_set_thread_stopped_callback (handle, thread_end);
-
- //It's questionable whether we actually want this to be mandatory, maybe put it behind the actual event?
mono_profiler_set_thread_name_callback (handle, thread_name);
- if (config.effective_mask & PROFLOG_DOMAIN_EVENTS) {
- mono_profiler_set_domain_loaded_callback (handle, domain_loaded);
- mono_profiler_set_domain_unloading_callback (handle, domain_unloaded);
- mono_profiler_set_domain_name_callback (handle, domain_name);
- }
+ mono_profiler_set_domain_loaded_callback (handle, domain_loaded);
+ mono_profiler_set_domain_unloading_callback (handle, domain_unloaded);
+ mono_profiler_set_domain_name_callback (handle, domain_name);
- if (config.effective_mask & PROFLOG_ASSEMBLY_EVENTS) {
- mono_profiler_set_assembly_loaded_callback (handle, assembly_loaded);
- mono_profiler_set_assembly_unloading_callback (handle, assembly_unloaded);
- }
+ mono_profiler_set_context_loaded_callback (handle, context_loaded);
+ mono_profiler_set_context_unloaded_callback (handle, context_unloaded);
- if (config.effective_mask & PROFLOG_MODULE_EVENTS) {
- mono_profiler_set_image_loaded_callback (handle, image_loaded);
- mono_profiler_set_image_unloading_callback (handle, image_unloaded);
- }
+ mono_profiler_set_assembly_loaded_callback (handle, assembly_loaded);
+ mono_profiler_set_assembly_unloading_callback (handle, assembly_unloaded);
- if (config.effective_mask & PROFLOG_CLASS_EVENTS)
- mono_profiler_set_class_loaded_callback (handle, class_loaded);
+ mono_profiler_set_image_loaded_callback (handle, image_loaded);
+ mono_profiler_set_image_unloading_callback (handle, image_unloaded);
- if (config.effective_mask & PROFLOG_JIT_COMPILATION_EVENTS) {
- mono_profiler_set_jit_done_callback (handle, method_jitted);
- mono_profiler_set_jit_code_buffer_callback (handle, code_buffer_new);
- }
+ mono_profiler_set_class_loaded_callback (handle, class_loaded);
- if (config.effective_mask & PROFLOG_EXCEPTION_EVENTS) {
+ mono_profiler_set_jit_done_callback (handle, method_jitted);
+
+ if (ENABLED (PROFLOG_EXCEPTION_EVENTS)) {
mono_profiler_set_exception_throw_callback (handle, throw_exc);
mono_profiler_set_exception_clause_callback (handle, clause_exc);
}
- if (config.effective_mask & PROFLOG_ALLOCATION_EVENTS) {
- mono_profiler_enable_allocations ();
- mono_profiler_set_gc_allocation_callback (handle, gc_alloc);
- }
-
- //PROFLOG_GC_EVENTS is mandatory
- //PROFLOG_THREAD_EVENTS is mandatory
-
- if (config.effective_mask & PROFLOG_CALL_EVENTS) {
- mono_profiler_set_call_instrumentation_filter_callback (handle, method_filter);
- mono_profiler_set_method_enter_callback (handle, method_enter);
- mono_profiler_set_method_leave_callback (handle, method_leave);
- mono_profiler_set_method_exception_leave_callback (handle, method_exc_leave);
- }
-
- if (config.effective_mask & PROFLOG_INS_COVERAGE_EVENTS)
- mono_profiler_set_coverage_filter_callback (handle, coverage_filter);
-
- if (config.effective_mask & PROFLOG_SAMPLING_EVENTS) {
- mono_profiler_enable_sampling (handle);
-
- if (!mono_profiler_set_sample_mode (handle, config.sampling_mode, config.sample_freq))
- g_warning ("Another profiler controls sampling parameters; the log profiler will not be able to modify them");
-
- mono_profiler_set_sample_hit_callback (handle, mono_sample_hit);
- }
-
- if (config.effective_mask & PROFLOG_MONITOR_EVENTS) {
+ if (ENABLED (PROFLOG_MONITOR_EVENTS)) {
mono_profiler_set_monitor_contention_callback (handle, monitor_contention);
mono_profiler_set_monitor_acquired_callback (handle, monitor_acquired);
mono_profiler_set_monitor_failed_callback (handle, monitor_failed);
}
- if (config.effective_mask & PROFLOG_GC_MOVES_EVENTS)
+ if (ENABLED (PROFLOG_GC_EVENTS))
+ mono_profiler_set_gc_resize_callback (handle, gc_resize);
+
+ if (ENABLED (PROFLOG_GC_ALLOCATION_EVENTS))
+ mono_profiler_set_gc_allocation_callback (handle, gc_alloc);
+
+ if (ENABLED (PROFLOG_GC_MOVE_EVENTS))
mono_profiler_set_gc_moves_callback (handle, gc_moves);
- if (config.effective_mask & PROFLOG_GC_ROOT_EVENTS)
+ if (ENABLED (PROFLOG_GC_ROOT_EVENTS))
mono_profiler_set_gc_roots_callback (handle, gc_roots);
- if (config.effective_mask & PROFLOG_CONTEXT_EVENTS) {
- mono_profiler_set_context_loaded_callback (handle, context_loaded);
- mono_profiler_set_context_unloaded_callback (handle, context_unloaded);
+ if (ENABLED (PROFLOG_GC_HANDLE_EVENTS)) {
+ mono_profiler_set_gc_handle_created_callback (handle, gc_handle_created);
+ mono_profiler_set_gc_handle_deleted_callback (handle, gc_handle_deleted);
}
- if (config.effective_mask & PROFLOG_FINALIZATION_EVENTS) {
+ if (ENABLED (PROFLOG_GC_FINALIZATION_EVENTS)) {
mono_profiler_set_gc_finalizing_callback (handle, finalize_begin);
mono_profiler_set_gc_finalized_callback (handle, finalize_end);
mono_profiler_set_gc_finalizing_object_callback (handle, finalize_object_begin);
- mono_profiler_set_gc_finalized_object_callback (handle, finalize_object_end);
- } else if (ENABLED (PROFLOG_HEAPSHOT_FEATURE) && config.hs_mode_ondemand) {
- //On Demand heapshot uses the finalizer thread to force a collection and thus a heapshot
- mono_profiler_set_gc_finalized_callback (handle, finalize_end);
}
- //PROFLOG_COUNTER_EVENTS is a pseudo event controled by the no_counters global var
+ //On Demand heapshot uses the finalizer thread to force a collection and thus a heapshot
+ mono_profiler_set_gc_finalized_callback (handle, finalize_end);
- if (config.effective_mask & PROFLOG_GC_HANDLE_EVENTS) {
- mono_profiler_set_gc_handle_created_callback (handle, gc_handle_created);
- mono_profiler_set_gc_handle_deleted_callback (handle, gc_handle_deleted);
+ if (ENABLED (PROFLOG_SAMPLE_EVENTS))
+ mono_profiler_set_sample_hit_callback (handle, mono_sample_hit);
+
+ if (ENABLED (PROFLOG_JIT_EVENTS))
+ mono_profiler_set_jit_code_buffer_callback (handle, code_buffer_new);
+
+ if (log_config.enter_leave) {
+ mono_profiler_set_call_instrumentation_filter_callback (handle, method_filter);
+ mono_profiler_set_method_enter_callback (handle, method_enter);
+ mono_profiler_set_method_leave_callback (handle, method_leave);
+ mono_profiler_set_method_exception_leave_callback (handle, method_exc_leave);
}
+
+ if (log_config.collect_coverage)
+ mono_profiler_set_coverage_filter_callback (handle, coverage_filter);
+
+ mono_profiler_enable_allocations ();
+ mono_profiler_enable_sampling (handle);
+
+ /*
+ * If no sample option was given by the user, this just leaves the sampling
+ * thread in idle mode. We do this even if no option was given so that we
+ * can warn if another profiler controls sampling parameters.
+ */
+ if (!mono_profiler_set_sample_mode (handle, log_config.sampling_mode, log_config.sample_freq))
+ mono_profiler_printf_err ("Another profiler controls sampling parameters; the log profiler will not be able to modify them.");
}
#define __MONO_PROFLOG_H__
#include <glib.h>
+#define MONO_PROFILER_UNSTABLE_GC_ROOTS
#include <mono/metadata/profiler.h>
#define BUF_ID 0x4D504C01
added an exception object field to TYPE_CLAUSE
class unload events no longer exist (they were never emitted)
removed type field from TYPE_SAMPLE_HIT
+ removed MONO_GC_EVENT_{MARK,RECLAIM}_{START,END}
+ */
+
+/*
+ * file format:
+ * [header] [buffer]*
+ *
+ * The file is composed by a header followed by 0 or more buffers.
+ * Each buffer contains events that happened on a thread: for a given thread
+ * buffers that appear later in the file are guaranteed to contain events
+ * that happened later in time. Buffers from separate threads could be interleaved,
+ * though.
+ * Buffers are not required to be aligned.
+ *
+ * header format:
+ * [id: 4 bytes] constant value: LOG_HEADER_ID
+ * [major: 1 byte] [minor: 1 byte] major and minor version of the log profiler
+ * [format: 1 byte] version of the data format for the rest of the file
+ * [ptrsize: 1 byte] size in bytes of a pointer in the profiled program
+ * [startup time: 8 bytes] time in milliseconds since the unix epoch when the program started
+ * [timer overhead: 4 bytes] approximate overhead in nanoseconds of the timer
+ * [flags: 4 bytes] file format flags, should be 0 for now
+ * [pid: 4 bytes] pid of the profiled process
+ * [port: 2 bytes] tcp port for server if != 0
+ * [args size: 4 bytes] size of args
+ * [args: string] arguments passed to the profiler
+ * [arch size: 4 bytes] size of arch
+ * [arch: string] architecture the profiler is running on
+ * [os size: 4 bytes] size of os
+ * [os: string] operating system the profiler is running on
+ *
+ * The multiple byte integers are in little-endian format.
+ *
+ * buffer format:
+ * [buffer header] [event]*
+ * Buffers have a fixed-size header followed by 0 or more bytes of event data.
+ * Timing information and other values in the event data are usually stored
+ * as uleb128 or sleb128 integers. To save space, as noted for each item below,
+ * some data is represented as a difference between the actual value and
+ * either the last value of the same type (like for timing information) or
+ * as the difference from a value stored in a buffer header.
+ *
+ * For timing information the data is stored as uleb128, since timing
+ * increases in a monotonic way in each thread: the value is the number of
+ * nanoseconds to add to the last seen timing data in a buffer. The first value
+ * in a buffer will be calculated from the time_base field in the buffer head.
+ *
+ * Object or heap sizes are stored as uleb128.
+ * Pointer differences are stored as sleb128, instead.
+ *
+ * If an unexpected value is found, the rest of the buffer should be ignored,
+ * as generally the later values need the former to be interpreted correctly.
+ *
+ * buffer header format:
+ * [bufid: 4 bytes] constant value: BUF_ID
+ * [len: 4 bytes] size of the data following the buffer header
+ * [time_base: 8 bytes] time base in nanoseconds since an unspecified epoch
+ * [ptr_base: 8 bytes] base value for pointers
+ * [obj_base: 8 bytes] base value for object addresses
+ * [thread id: 8 bytes] system-specific thread ID (pthread_t for example)
+ * [method_base: 8 bytes] base value for MonoMethod pointers
+ *
+ * event format:
+ * [extended info: upper 4 bits] [type: lower 4 bits]
+ * [time diff: uleb128] nanoseconds since last timing
+ * [data]*
+ * The data that follows depends on type and the extended info.
+ * Type is one of the enum values in mono-profiler-log.h: TYPE_ALLOC, TYPE_GC,
+ * TYPE_METADATA, TYPE_METHOD, TYPE_EXCEPTION, TYPE_MONITOR, TYPE_HEAP.
+ * The extended info bits are interpreted based on type, see
+ * each individual event description below.
+ * strings are represented as a 0-terminated utf8 sequence.
+ *
+ * backtrace format:
+ * [num: uleb128] number of frames following
+ * [frame: sleb128]* mum MonoMethod* as a pointer difference from the last such
+ * pointer or the buffer method_base
+ *
+ * type alloc format:
+ * type: TYPE_ALLOC
+ * exinfo: zero or TYPE_ALLOC_BT
+ * [ptr: sleb128] class as a byte difference from ptr_base
+ * [obj: sleb128] object address as a byte difference from obj_base
+ * [size: uleb128] size of the object in the heap
+ * If exinfo == TYPE_ALLOC_BT, a backtrace follows.
+ *
+ * type GC format:
+ * type: TYPE_GC
+ * exinfo: one of TYPE_GC_EVENT, TYPE_GC_RESIZE, TYPE_GC_MOVE, TYPE_GC_HANDLE_CREATED[_BT],
+ * TYPE_GC_HANDLE_DESTROYED[_BT], TYPE_GC_FINALIZE_START, TYPE_GC_FINALIZE_END,
+ * TYPE_GC_FINALIZE_OBJECT_START, TYPE_GC_FINALIZE_OBJECT_END
+ * if exinfo == TYPE_GC_RESIZE
+ * [heap_size: uleb128] new heap size
+ * if exinfo == TYPE_GC_EVENT
+ * [event type: byte] GC event (MONO_GC_EVENT_* from profiler.h)
+ * [generation: byte] GC generation event refers to
+ * if exinfo == TYPE_GC_MOVE
+ * [num_objects: uleb128] number of object moves that follow
+ * [objaddr: sleb128]+ num_objects object pointer differences from obj_base
+ * num is always an even number: the even items are the old
+ * addresses, the odd numbers are the respective new object addresses
+ * if exinfo == TYPE_GC_HANDLE_CREATED[_BT]
+ * [handle_type: uleb128] MonoGCHandleType enum value
+ * upper bits reserved as flags
+ * [handle: uleb128] GC handle value
+ * [objaddr: sleb128] object pointer differences from obj_base
+ * If exinfo == TYPE_GC_HANDLE_CREATED_BT, a backtrace follows.
+ * if exinfo == TYPE_GC_HANDLE_DESTROYED[_BT]
+ * [handle_type: uleb128] MonoGCHandleType enum value
+ * upper bits reserved as flags
+ * [handle: uleb128] GC handle value
+ * If exinfo == TYPE_GC_HANDLE_DESTROYED_BT, a backtrace follows.
+ * if exinfo == TYPE_GC_FINALIZE_OBJECT_{START,END}
+ * [object: sleb128] the object as a difference from obj_base
+ *
+ * type metadata format:
+ * type: TYPE_METADATA
+ * exinfo: one of: TYPE_END_LOAD, TYPE_END_UNLOAD (optional for TYPE_THREAD and TYPE_DOMAIN,
+ * doesn't occur for TYPE_CLASS)
+ * [mtype: byte] metadata type, one of: TYPE_CLASS, TYPE_IMAGE, TYPE_ASSEMBLY, TYPE_DOMAIN,
+ * TYPE_THREAD, TYPE_CONTEXT
+ * [pointer: sleb128] pointer of the metadata type depending on mtype
+ * if mtype == TYPE_CLASS
+ * [image: sleb128] MonoImage* as a pointer difference from ptr_base
+ * [name: string] full class name
+ * if mtype == TYPE_IMAGE
+ * [name: string] image file name
+ * if mtype == TYPE_ASSEMBLY
+ * [image: sleb128] MonoImage* as a pointer difference from ptr_base
+ * [name: string] assembly name
+ * if mtype == TYPE_DOMAIN && exinfo == 0
+ * [name: string] domain friendly name
+ * if mtype == TYPE_CONTEXT
+ * [domain: sleb128] domain id as pointer
+ * if mtype == TYPE_THREAD && exinfo == 0
+ * [name: string] thread name
+ *
+ * type method format:
+ * type: TYPE_METHOD
+ * exinfo: one of: TYPE_LEAVE, TYPE_ENTER, TYPE_EXC_LEAVE, TYPE_JIT
+ * [method: sleb128] MonoMethod* as a pointer difference from the last such
+ * pointer or the buffer method_base
+ * if exinfo == TYPE_JIT
+ * [code address: sleb128] pointer to the native code as a diff from ptr_base
+ * [code size: uleb128] size of the generated code
+ * [name: string] full method name
+ *
+ * type exception format:
+ * type: TYPE_EXCEPTION
+ * exinfo: zero, TYPE_CLAUSE, or TYPE_THROW_BT
+ * if exinfo == TYPE_CLAUSE
+ * [clause type: byte] MonoExceptionEnum enum value
+ * [clause index: uleb128] index of the current clause
+ * [method: sleb128] MonoMethod* as a pointer difference from the last such
+ * pointer or the buffer method_base
+ * [object: sleb128] the exception object as a difference from obj_base
+ * else
+ * [object: sleb128] the exception object as a difference from obj_base
+ * If exinfo == TYPE_THROW_BT, a backtrace follows.
+ *
+ * type runtime format:
+ * type: TYPE_RUNTIME
+ * exinfo: one of: TYPE_JITHELPER
+ * if exinfo == TYPE_JITHELPER
+ * [type: byte] MonoProfilerCodeBufferType enum value
+ * [buffer address: sleb128] pointer to the native code as a diff from ptr_base
+ * [buffer size: uleb128] size of the generated code
+ * if type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE
+ * [name: string] buffer description name
+ *
+ * type monitor format:
+ * type: TYPE_MONITOR
+ * exinfo: zero or TYPE_MONITOR_BT
+ * [type: byte] MonoProfilerMonitorEvent enum value
+ * [object: sleb128] the lock object as a difference from obj_base
+ * If exinfo == TYPE_MONITOR_BT, a backtrace follows.
+ *
+ * type heap format
+ * type: TYPE_HEAP
+ * exinfo: one of TYPE_HEAP_START, TYPE_HEAP_END, TYPE_HEAP_OBJECT, TYPE_HEAP_ROOT
+ * if exinfo == TYPE_HEAP_OBJECT
+ * [object: sleb128] the object as a difference from obj_base
+ * [class: sleb128] the object MonoClass* as a difference from ptr_base
+ * [size: uleb128] size of the object on the heap
+ * [num_refs: uleb128] number of object references
+ * each referenced objref is preceded by a uleb128 encoded offset: the
+ * first offset is from the object address and each next offset is relative
+ * to the previous one
+ * [objrefs: sleb128]+ object referenced as a difference from obj_base
+ * The same object can appear multiple times, but only the first time
+ * with size != 0: in the other cases this data will only be used to
+ * provide additional referenced objects.
+ * if exinfo == TYPE_HEAP_ROOT
+ * [num_roots: uleb128] number of root references
+ * [num_gc: uleb128] number of major gcs
+ * [object: sleb128] the object as a difference from obj_base
+ * [root_type: byte] the root_type: MonoProfileGCRootType (profiler.h)
+ * [extra_info: uleb128] the extra_info value
+ * object, root_type and extra_info are repeated num_roots times
+ *
+ * type sample format
+ * type: TYPE_SAMPLE
+ * exinfo: one of TYPE_SAMPLE_HIT, TYPE_SAMPLE_USYM, TYPE_SAMPLE_UBIN, TYPE_SAMPLE_COUNTERS_DESC, TYPE_SAMPLE_COUNTERS
+ * if exinfo == TYPE_SAMPLE_HIT
+ * [thread: sleb128] thread id as difference from ptr_base
+ * [count: uleb128] number of following instruction addresses
+ * [ip: sleb128]* instruction pointer as difference from ptr_base
+ * [mbt_count: uleb128] number of managed backtrace frames
+ * [method: sleb128]* MonoMethod* as a pointer difference from the last such
+ * pointer or the buffer method_base (the first such method can be also indentified by ip, but this is not neccessarily true)
+ * if exinfo == TYPE_SAMPLE_USYM
+ * [address: sleb128] symbol address as a difference from ptr_base
+ * [size: uleb128] symbol size (may be 0 if unknown)
+ * [name: string] symbol name
+ * if exinfo == TYPE_SAMPLE_UBIN
+ * [address: sleb128] address where binary has been loaded as a difference from ptr_base
+ * [offset: uleb128] file offset of mapping (the same file can be mapped multiple times)
+ * [size: uleb128] memory size
+ * [name: string] binary name
+ * if exinfo == TYPE_SAMPLE_COUNTERS_DESC
+ * [len: uleb128] number of counters
+ * for i = 0 to len
+ * [section: uleb128] section of counter
+ * if section == MONO_COUNTER_PERFCOUNTERS:
+ * [section_name: string] section name of counter
+ * [name: string] name of counter
+ * [type: byte] type of counter
+ * [unit: byte] unit of counter
+ * [variance: byte] variance of counter
+ * [index: uleb128] unique index of counter
+ * if exinfo == TYPE_SAMPLE_COUNTERS
+ * while true:
+ * [index: uleb128] unique index of counter
+ * if index == 0:
+ * break
+ * [type: byte] type of counter value
+ * if type == string:
+ * if value == null:
+ * [0: byte] 0 -> value is null
+ * else:
+ * [1: byte] 1 -> value is not null
+ * [value: string] counter value
+ * else:
+ * [value: uleb128/sleb128/double] counter value, can be sleb128, uleb128 or double (determined by using type)
+ *
+ * type coverage format
+ * type: TYPE_COVERAGE
+ * exinfo: one of TYPE_COVERAGE_METHOD, TYPE_COVERAGE_STATEMENT, TYPE_COVERAGE_ASSEMBLY, TYPE_COVERAGE_CLASS
+ * if exinfo == TYPE_COVERAGE_METHOD
+ * [assembly: string] name of assembly
+ * [class: string] name of the class
+ * [name: string] name of the method
+ * [signature: string] the signature of the method
+ * [filename: string] the file path of the file that contains this method
+ * [token: uleb128] the method token
+ * [method_id: uleb128] an ID for this data to associate with the buffers of TYPE_COVERAGE_STATEMENTS
+ * [len: uleb128] the number of TYPE_COVERAGE_BUFFERS associated with this method
+ * if exinfo == TYPE_COVERAGE_STATEMENTS
+ * [method_id: uleb128] an the TYPE_COVERAGE_METHOD buffer to associate this with
+ * [offset: uleb128] the il offset relative to the previous offset
+ * [counter: uleb128] the counter for this instruction
+ * [line: uleb128] the line of filename containing this instruction
+ * [column: uleb128] the column containing this instruction
+ * if exinfo == TYPE_COVERAGE_ASSEMBLY
+ * [name: string] assembly name
+ * [guid: string] assembly GUID
+ * [filename: string] assembly filename
+ * [number_of_methods: uleb128] the number of methods in this assembly
+ * [fully_covered: uleb128] the number of fully covered methods
+ * [partially_covered: uleb128] the number of partially covered methods
+ * currently partially_covered will always be 0, and fully_covered is the
+ * number of methods that are fully and partially covered.
+ * if exinfo == TYPE_COVERAGE_CLASS
+ * [name: string] assembly name
+ * [class: string] class name
+ * [number_of_methods: uleb128] the number of methods in this class
+ * [fully_covered: uleb128] the number of fully covered methods
+ * [partially_covered: uleb128] the number of partially covered methods
+ * currently partially_covered will always be 0, and fully_covered is the
+ * number of methods that are fully and partially covered.
+ *
+ * type meta format:
+ * type: TYPE_META
+ * exinfo: one of: TYPE_SYNC_POINT
+ * if exinfo == TYPE_SYNC_POINT
+ * [type: byte] MonoProfilerSyncPointType enum value
*/
enum {
TYPE_COVERAGE_CLASS = 3 << 4,
/* extended type for TYPE_META */
TYPE_SYNC_POINT = 0 << 4,
- TYPE_END
};
enum {
};
typedef enum {
- SYNC_POINT_PERIODIC,
- SYNC_POINT_WORLD_STOP,
- SYNC_POINT_WORLD_START
+ SYNC_POINT_PERIODIC = 0,
+ SYNC_POINT_WORLD_STOP = 1,
+ SYNC_POINT_WORLD_START = 2,
} MonoProfilerSyncPointType;
typedef enum {
} MonoProfilerMonitorEvent;
enum {
- MONO_PROFILER_GC_HANDLE_CREATED,
- MONO_PROFILER_GC_HANDLE_DESTROYED,
+ MONO_PROFILER_GC_HANDLE_CREATED = 0,
+ MONO_PROFILER_GC_HANDLE_DESTROYED = 1,
};
+typedef enum {
+ MONO_PROFILER_HEAPSHOT_NONE = 0,
+ MONO_PROFILER_HEAPSHOT_MAJOR = 1,
+ MONO_PROFILER_HEAPSHOT_ON_DEMAND = 2,
+ MONO_PROFILER_HEAPSHOT_X_GC = 3,
+ MONO_PROFILER_HEAPSHOT_X_MS = 4,
+} MonoProfilerHeapshotMode;
+
// If you alter MAX_FRAMES, you may need to alter SAMPLE_BLOCK_SIZE too.
#define MAX_FRAMES 32
//The following flags control emitting individual events
-#define PROFLOG_DOMAIN_EVENTS (1 << 0)
-#define PROFLOG_ASSEMBLY_EVENTS (1 << 1)
-#define PROFLOG_MODULE_EVENTS (1 << 2)
-#define PROFLOG_CLASS_EVENTS (1 << 3)
-#define PROFLOG_JIT_COMPILATION_EVENTS (1 << 4)
-#define PROFLOG_EXCEPTION_EVENTS (1 << 5)
-#define PROFLOG_ALLOCATION_EVENTS (1 << 6)
-#define PROFLOG_GC_EVENTS (1 << 7)
-#define PROFLOG_THREAD_EVENTS (1 << 8)
-//This generate enter/leave events
-#define PROFLOG_CALL_EVENTS (1 << 9)
-#define PROFLOG_INS_COVERAGE_EVENTS (1 << 10)
-#define PROFLOG_SAMPLING_EVENTS (1 << 11)
-#define PROFLOG_MONITOR_EVENTS (1 << 12)
-#define PROFLOG_GC_MOVES_EVENTS (1 << 13)
-
-#define PROFLOG_GC_ROOT_EVENTS (1 << 14)
-#define PROFLOG_CONTEXT_EVENTS (1 << 15)
-#define PROFLOG_FINALIZATION_EVENTS (1 << 16)
-#define PROFLOG_COUNTER_EVENTS (1 << 17)
-#define PROFLOG_GC_HANDLE_EVENTS (1 << 18)
-
-//The following flags control whole subsystems
-//Enables code coverage generation
-#define PROFLOG_CODE_COV_FEATURE (1 << 19)
-//This enables sampling to be generated
-#define PROFLOG_SAMPLING_FEATURE (1 << 20)
-//This enable heap dumping during GCs and filter GCRoots and GCHandle events outside of the dumped collections
-#define PROFLOG_HEAPSHOT_FEATURE (1 << 21)
-
-
-
-//The follow flags are the common aliases we want ppl to use
-#define PROFLOG_TYPELOADING_ALIAS (PROFLOG_DOMAIN_EVENTS | PROFLOG_ASSEMBLY_EVENTS | PROFLOG_MODULE_EVENTS | PROFLOG_CLASS_EVENTS)
-#define PROFLOG_CODECOV_ALIAS (PROFLOG_INS_COVERAGE_EVENTS | PROFLOG_CODE_COV_FEATURE)
-#define PROFLOG_PERF_SAMPLING_ALIAS (PROFLOG_TYPELOADING_ALIAS | PROFLOG_THREAD_EVENTS | PROFLOG_SAMPLING_EVENTS | PROFLOG_SAMPLING_FEATURE)
-#define PROFLOG_GC_ALLOC_ALIAS (PROFLOG_TYPELOADING_ALIAS | PROFLOG_THREAD_EVENTS | PROFLOG_GC_EVENTS | PROFLOG_ALLOCATION_EVENTS)
-#define PROFLOG_HEAPSHOT_ALIAS (PROFLOG_TYPELOADING_ALIAS | PROFLOG_THREAD_EVENTS | PROFLOG_GC_EVENTS | PROFLOG_GC_ROOT_EVENTS | PROFLOG_HEAPSHOT_FEATURE)
-#define PROFLOG_LEGACY_ALIAS (PROFLOG_TYPELOADING_ALIAS | PROFLOG_GC_EVENTS | PROFLOG_THREAD_EVENTS | PROFLOG_JIT_COMPILATION_EVENTS | PROFLOG_EXCEPTION_EVENTS | PROFLOG_MONITOR_EVENTS | PROFLOG_GC_ROOT_EVENTS | PROFLOG_CONTEXT_EVENTS | PROFLOG_FINALIZATION_EVENTS | PROFLOG_COUNTER_EVENTS)
-
+#define PROFLOG_EXCEPTION_EVENTS (1 << 0)
+#define PROFLOG_MONITOR_EVENTS (1 << 1)
+#define PROFLOG_GC_EVENTS (1 << 2)
+#define PROFLOG_GC_ALLOCATION_EVENTS (1 << 3)
+#define PROFLOG_GC_MOVE_EVENTS (1 << 4)
+#define PROFLOG_GC_ROOT_EVENTS (1 << 5)
+#define PROFLOG_GC_HANDLE_EVENTS (1 << 6)
+#define PROFLOG_GC_FINALIZATION_EVENTS (1 << 7)
+#define PROFLOG_COUNTER_EVENTS (1 << 8)
+#define PROFLOG_SAMPLE_EVENTS (1 << 9)
+#define PROFLOG_JIT_EVENTS (1 << 10)
+
+#define PROFLOG_ALLOC_ALIAS (PROFLOG_GC_EVENTS | PROFLOG_GC_ALLOCATION_EVENTS | PROFLOG_GC_MOVE_EVENTS)
+#define PROFLOG_HEAPSHOT_ALIAS (PROFLOG_GC_EVENTS | PROFLOG_GC_ROOT_EVENTS)
+#define PROFLOG_LEGACY_ALIAS (PROFLOG_EXCEPTION_EVENTS | PROFLOG_MONITOR_EVENTS | PROFLOG_GC_EVENTS | PROFLOG_GC_MOVE_EVENTS | PROFLOG_GC_ROOT_EVENTS | PROFLOG_GC_HANDLE_EVENTS | PROFLOG_GC_FINALIZATION_EVENTS | PROFLOG_COUNTER_EVENTS)
typedef struct {
//Events explicitly enabled
int enable_mask;
+
//Events explicitly disabled
int disable_mask;
- //Actual mask the profiler should use
+ // Actual mask the profiler should use. Can be changed at runtime.
int effective_mask;
+ // Whether to do method prologue/epilogue instrumentation. Only used at startup.
+ gboolean enter_leave;
+
+ // Whether to collect code coverage by instrumenting basic blocks.
+ gboolean collect_coverage;
+
//Emit a report at the end of execution
gboolean do_report;
//Enable profiler internal debugging
gboolean do_debug;
- //Enable code coverage specific debugging
- gboolean debug_coverage;
-
//Where to compress the output file
gboolean use_zip;
- //If true, don't generate stacktraces
- gboolean notraces;
+ // Heapshot mode (every major, on demand, XXgc, XXms). Can be changed at runtime.
+ MonoProfilerHeapshotMode hs_mode;
- //If true, heapshots are generated on demand only
- gboolean hs_mode_ondemand;
+ // Heapshot frequency in milliseconds (for MONO_HEAPSHOT_X_MS). Can be changed at runtime.
+ unsigned int hs_freq_ms;
- //HeapShort frequency in milliseconds
- unsigned int hs_mode_ms;
+ // Heapshot frequency in number of collections (for MONO_HEAPSHOT_X_GC). Can be changed at runtime.
+ unsigned int hs_freq_gc;
- //HeapShort frequency in number of collections
- unsigned int hs_mode_gc;
+ // Whether to do a heapshot on shutdown.
+ gboolean hs_on_shutdown;
- //Sample frequency in Hertz
+ // Sample frequency in Hertz. Only used at startup.
int sample_freq;
- //Maximum number of frames to collect
+ // Maximum number of frames to collect. Can be changed at runtime.
int num_frames;
- //Max depth to record enter/leave events
+ // Max depth to record enter/leave events. Can be changed at runtime.
int max_call_depth;
//Name of the generated mlpd file
//Filter files used by the code coverage mode
GPtrArray *cov_filter_files;
- //Port to listen for profiling commands
+ // Port to listen for profiling commands (e.g. "heapshot" for on-demand heapshot).
int command_port;
- //Max size of the sample hit buffer, we'll drop frames if it's reached
+ // Maximum number of SampleHit structures. We'll drop samples if this number is not sufficient.
int max_allocated_sample_hits;
+ // Sample mode. Only used at startup.
MonoProfilerSampleMode sampling_mode;
} ProfilerConfig;
SAMPLE_BRANCH_MISSES,
};
+enum {
+ MONO_GC_EVENT_MARK_START = 1,
+ MONO_GC_EVENT_MARK_END = 2,
+ MONO_GC_EVENT_RECLAIM_START = 3,
+ MONO_GC_EVENT_RECLAIM_END = 4,
+};
+
static const char*
sample_type_name (int type)
{
report_errors ();
}
# test heapshot traces
-$report = run_test_sgen ("test-heapshot.exe", "heapshot,output=-traces.mlpd,legacy", "--traces traces.mlpd");
+$report = run_test_sgen ("test-heapshot.exe", "heapshot,output=traces.mlpd,legacy", "--traces traces.mlpd");
if ($report ne "missing binary") {
check_report_basics ($report);
check_report_heapshot ($report, 0, {"T" => 5000});
report_errors ();
}
# test traces
-$report = run_test ("test-traces.exe", "legacy,calls,alloc,output=-traces.mlpd", "--maxframes=7 --traces traces.mlpd");
+$report = run_test ("test-traces.exe", "legacy,calls,alloc,output=traces.mlpd", "--maxframes=7 --traces traces.mlpd");
check_report_basics ($report);
check_call_traces ($report,
"T:level3 (int)" => [2020, "T:Main (string[])"],
);
report_errors ();
# test traces without enter/leave events
-$report = run_test ("test-traces.exe", "legacy,alloc,output=-traces.mlpd", "--traces traces.mlpd");
+$report = run_test ("test-traces.exe", "legacy,alloc,output=traces.mlpd", "--traces traces.mlpd");
check_report_basics ($report);
# this has been broken recently
check_exception_traces ($report,
/*
- * mono-codeanalyst.c: VTune profiler
+ * vtune.c: VTune profiler
*
* Author:
* Virgile Bello (virgile.bello@gmail.com)
PROFILE_MCS_FLAGS = -d:MOBILE,MOBILE_LEGACY
endif
-MCS_NO_LIB = $(TOOLS_RUNTIME) $(CSC) -unsafe -debug:portable \
+MCS_NO_UNSAFE = $(TOOLS_RUNTIME) $(CSC) -debug:portable \
-noconfig -nologo \
-nowarn:0162 -nowarn:0168 -nowarn:0219 -nowarn:0414 -nowarn:0618 \
-nowarn:0169 -nowarn:1690 -nowarn:0649 -nowarn:0612 -nowarn:3021 \
-nowarn:0197 $(PROFILE_MCS_FLAGS)
+MCS_NO_LIB = $(MCS_NO_UNSAFE) -unsafe
MCS = $(MCS_NO_LIB)
libtest_la_SOURCES = libtest.c
libtest_la_LIBADD = $(GLIB_LIBS) $(LIBICONV)
-test-internalsvisibleto: internalsvisibleto-runtimetest.exe internalsvisibleto-compilertest.exe internalsvisibleto-library.dll
- $(Q) $(RUNTIME) internalsvisibleto-runtimetest.exe 1>internalsvisibleto-runtimetest.exe.stdout 2>internalsvisibleto-runtimetest.exe.stderr
- $(Q) $(RUNTIME) internalsvisibleto-compilertest.exe 1>internalsvisibleto-compilertest.exe.stdout 2>internalsvisibleto-compilertest.exe.stderr
-
-internalsvisibleto-runtimetest.exe: internalsvisibleto-runtimetest.cs internalsvisibleto-library.cs
- $(Q) $(MCS) -out:internalsvisibleto-correctcase.dll -target:library -d:CORRECT_CASE -d:PERMISSIVE internalsvisibleto-library.cs
- $(Q) $(MCS) -out:internalsvisibleto-wrongcase.dll -target:library -d:WRONG_CASE -d:PERMISSIVE internalsvisibleto-library.cs
- $(Q) $(MCS) -out:internalsvisibleto-runtimetest.exe -warn:0 -r:internalsvisibleto-correctcase.dll -r:internalsvisibleto-wrongcase.dll internalsvisibleto-runtimetest.cs
- $(Q) $(MCS) -out:internalsvisibleto-correctcase.dll -target:library -d:CORRECT_CASE internalsvisibleto-library.cs
- $(Q) $(MCS) -out:internalsvisibleto-wrongcase.dll -target:library -d:WRONG_CASE internalsvisibleto-library.cs
-
-internalsvisibleto-compilertest.exe: internalsvisibleto-compilertest.cs internalsvisibleto-library.cs
- $(Q) $(MCS) -out:internalsvisibleto-correctcase-2.dll -target:library -d:CORRECT_CASE internalsvisibleto-library.cs
- $(Q) $(MCS) -out:internalsvisibleto-wrongcase-2.dll -target:library -d:WRONG_CASE internalsvisibleto-library.cs
- $(Q) $(MCS) -out:internalsvisibleto-compilertest.exe -warn:0 -r:internalsvisibleto-correctcase-2.dll -r:internalsvisibleto-wrongcase-2.dll internalsvisibleto-compilertest.cs
+INTERNALSVISIBLETO_TEST_SRC = \
+ internalsvisibleto-runtimetest.cs \
+ internalsvisibleto-compilertest.cs
+
+INTERNALSVISIBLETO_TEST_LIB_SRC = \
+ internalsvisibleto-library.cs
+
+INTERNALSVISIBLETO_TEST_LIBS = \
+ internalsvisibleto-correctcase.dll \
+ internalsvisibleto-wrongcase.dll \
+ internalsvisibleto-correctcase-2.dll \
+ internalsvisibleto-wrongcase-2.dll \
+ internalsvisibleto-correctcase-sign2048.dll \
+ internalsvisibleto-wrongcase-sign2048.dll \
+ internalsvisibleto-correctcase-2-sign2048.dll \
+ internalsvisibleto-wrongcase-2-sign2048.dll
+
+
+INTERNALSVISIBLETO_TEST = \
+ $(INTERNALSVISIBLETO_TEST_SRC:.cs=.exe) \
+ $(INTERNALSVISIBLETO_TEST_SRC:.cs=-sign2048.exe)
+
+if FULL_AOT_TESTS
+INTERNALSVISIBLETO_TESTAOT = \
+ $(INTERNALSVISIBLETO_TEST:.exe=.exe$(PLATFORM_AOT_SUFFIX))
+INTERNALSVISIBLETO_TESTAOT_LIBS = \
+ $(INTERNALSVISIBLETO_TEST_LIBS:.dll=.dll$(PLATFORM_AOT_SUFFIX))
+endif
+
+if HYBRID_AOT_TESTS
+INTERNALSVISIBLETO_TESTAOT = \
+ $(INTERNALSVISIBLETO_TEST:.exe=.exe$(PLATFORM_AOT_SUFFIX))
+INTERNALSVISIBLETO_TESTAOT_LIBS = \
+ $(INTERNALSVISIBLETO_TEST_LIBS:.dll=.dll$(PLATFORM_AOT_SUFFIX))
+endif
+
+EXTRA_DIST += $(INTERNALSVISIBLETO_TEST_SRC) $(INTERNALSVISIBLETO_TEST_LIB_SRC)
+
+test-internalsvisibleto: test-runner.exe $(INTERNALSVISIBLETO_TEST) $(INTERNALSVISIBLETO_TESTAOT) $(INTERNALSVISIBLETO_TESTAOT_LIBS)
+ $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ $(INTERNALSVISIBLETO_TEST)
+
+internalsvisibleto-correctcase.dll internalsvisibleto-wrongcase.dll internalsvisibleto-runtimetest.exe: internalsvisibleto-runtimetest.cs internalsvisibleto-library.cs
+ $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-correctcase.dll -target:library -d:CORRECT_CASE -d:PERMISSIVE internalsvisibleto-library.cs
+ $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-wrongcase.dll -target:library -d:WRONG_CASE -d:PERMISSIVE internalsvisibleto-library.cs
+ $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-runtimetest.exe -warn:0 -r:internalsvisibleto-correctcase.dll -r:internalsvisibleto-wrongcase.dll internalsvisibleto-runtimetest.cs
+ $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-correctcase.dll -target:library -d:CORRECT_CASE internalsvisibleto-library.cs
+ $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-wrongcase.dll -target:library -d:WRONG_CASE internalsvisibleto-library.cs
+
+internalsvisibleto-correctcase-2.dll internalsvisibleto-wrongcase-2.dll internalsvisibleto-compilertest.exe: internalsvisibleto-compilertest.cs internalsvisibleto-library.cs
+ $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-correctcase-2.dll -target:library -d:CORRECT_CASE internalsvisibleto-library.cs
+ $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-wrongcase-2.dll -target:library -d:WRONG_CASE internalsvisibleto-library.cs
+ $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-compilertest.exe -warn:0 -r:internalsvisibleto-correctcase-2.dll -r:internalsvisibleto-wrongcase-2.dll internalsvisibleto-compilertest.cs
+
+internalsvisibleto-correctcase-sign2048.dll internalsvisibleto-wrongcase-sign2048.dll internalsvisibleto-runtimetest-sign2048.exe: internalsvisibleto-runtimetest.cs internalsvisibleto-library.cs internalsvisibleto-2048.snk
+ $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-correctcase-sign2048.dll -target:library -d:CORRECT_CASE -d:PERMISSIVE -d:SIGN2048 internalsvisibleto-library.cs
+ $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-wrongcase-sign2048.dll -target:library -d:WRONG_CASE -d:PERMISSIVE -d:SIGN2048 internalsvisibleto-library.cs
+ $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-runtimetest-sign2048.exe -warn:0 -r:internalsvisibleto-correctcase-sign2048.dll -r:internalsvisibleto-wrongcase-sign2048.dll -d:SIGN2048 internalsvisibleto-runtimetest.cs
+ $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-correctcase-sign2048.dll -target:library -d:CORRECT_CASE -d:SIGN2048 internalsvisibleto-library.cs
+ $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-wrongcase-sign2048.dll -target:library -d:WRONG_CASE -d:SIGN2048 internalsvisibleto-library.cs
+
+internalsvisibleto-correctcase-2-sign2048.dll internalsvisibleto-wrongcase-2-sign2048.dll internalsvisibleto-compilertest-sign2048.exe: internalsvisibleto-compilertest.cs internalsvisibleto-library.cs internalsvisibleto-2048.snk
+ $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-correctcase-2-sign2048.dll -target:library -d:CORRECT_CASE -d:SIGN2048 internalsvisibleto-library.cs
+ $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-wrongcase-2-sign2048.dll -target:library -d:WRONG_CASE -d:SIGN2048 internalsvisibleto-library.cs
+ $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-compilertest-sign2048.exe -warn:0 -r:internalsvisibleto-correctcase-2-sign2048.dll -r:internalsvisibleto-wrongcase-2-sign2048.dll -d:SIGN2048 internalsvisibleto-compilertest.cs
+
CLEANFILES = $(TESTS_CS) $(TESTS_IL) $(TESTS_BENCH) $(TESTS_STRESS) $(TESTSAOT_CS) $(TESTSAOT_IL) $(TESTSAOT_BENCH) $(TESTSAOT_STRESS) *.dll *.stdout *.aotlog *.exe stest.dat
using System;
+#if SIGN2048
+using System.Reflection;
+[assembly: AssemblyDelaySign(true)]
+[assembly: AssemblyKeyFile(@"internalsvisibleto-2048.snk")]
+#endif
+
namespace InternalsVisibleTo {
class Program {
static void Main (string[] args) {
Console.WriteLine("-- Correct case --");
+ try {
+ var a = new CorrectCaseFriendAssembly.PublicClass ();
+ a.InternalMethod ();
+ Console.WriteLine ("Access friend internal method: OK");
+ } catch (MemberAccessException) {
+ failCount += 1;
+ Console.WriteLine ("Access friend internal method: Fail");
+ }
+
try {
var a = new CorrectCaseFriendAssembly.InternalClass(@internal: 0);
Console.WriteLine("Access internal class internal ctor: OK");
using System;
using System.Runtime.CompilerServices;
+#if SIGN2048
+using System.Reflection;
+[assembly: AssemblyDelaySign(true)]
+[assembly: AssemblyKeyFile(@"internalsvisibleto-2048.snk")]
+#endif
+
#if CORRECT_CASE
+#if !SIGN2048
[assembly: InternalsVisibleTo("internalsvisibleto-runtimetest")]
[assembly: InternalsVisibleTo("internalsvisibleto-compilertest")]
#else
+[assembly: InternalsVisibleTo("internalsvisibleto-runtimetest-sign2048, PublicKey=00240000048000001401000006020000002400005253413100080000010001002b524ed36058e444d0f2b12aeeeadab6f9a614dae43300d489746d143103a63c0178d0e316cc7a83156637d02b95b617c34bfa6877bc418118ce6d652e73211fdb80e5bc1878c6ef1b488dae12925390e7932dae9b22ada65ec76694a73b8e940db558d03ff5a3bee28017cb4448cd41dc946cc248e3313417f59092b9b62996de506c9446c7dceffed8e854cfa3d42eee30cdccbce934318b64ee20489178c00fa587f4ea666e4421eeae157fddf5ce7cfcf76e3b8b390005297f1b7e502c0f211c8c3f6886012cc4173aeedb4dc915d6d8f3821c19c0f1eedcccec8e839c1443ac96db7231ddebb391a5a92373aa87a6f2b2c8a9d57ad204e61813cc280da3")]
+[assembly: InternalsVisibleTo("internalsvisibleto-compilertest-sign2048, PublicKey=00240000048000001401000006020000002400005253413100080000010001002b524ed36058e444d0f2b12aeeeadab6f9a614dae43300d489746d143103a63c0178d0e316cc7a83156637d02b95b617c34bfa6877bc418118ce6d652e73211fdb80e5bc1878c6ef1b488dae12925390e7932dae9b22ada65ec76694a73b8e940db558d03ff5a3bee28017cb4448cd41dc946cc248e3313417f59092b9b62996de506c9446c7dceffed8e854cfa3d42eee30cdccbce934318b64ee20489178c00fa587f4ea666e4421eeae157fddf5ce7cfcf76e3b8b390005297f1b7e502c0f211c8c3f6886012cc4173aeedb4dc915d6d8f3821c19c0f1eedcccec8e839c1443ac96db7231ddebb391a5a92373aa87a6f2b2c8a9d57ad204e61813cc280da3")]
+#endif // SIGN2048
+#else
+#if !SIGN2048
[assembly: InternalsVisibleTo("iNtErnAlsVisibLETo-RUntimeTesT")]
[assembly: InternalsVisibleTo("iNtErnAlsVisibLETo-COmpilerTesT")]
-#endif
+#else
+[assembly: InternalsVisibleTo("iNtErnAlsVisibLETo-RUntimeTesT-sign2048, PublicKey=00240000048000001401000006020000002400005253413100080000010001002b524ed36058e444d0f2b12aeeeadab6f9a614dae43300d489746d143103a63c0178d0e316cc7a83156637d02b95b617c34bfa6877bc418118ce6d652e73211fdb80e5bc1878c6ef1b488dae12925390e7932dae9b22ada65ec76694a73b8e940db558d03ff5a3bee28017cb4448cd41dc946cc248e3313417f59092b9b62996de506c9446c7dceffed8e854cfa3d42eee30cdccbce934318b64ee20489178c00fa587f4ea666e4421eeae157fddf5ce7cfcf76e3b8b390005297f1b7e502c0f211c8c3f6886012cc4173aeedb4dc915d6d8f3821c19c0f1eedcccec8e839c1443ac96db7231ddebb391a5a92373aa87a6f2b2c8a9d57ad204e61813cc280da3")]
+[assembly: InternalsVisibleTo("iNtErnAlsVisibLETo-COmpilerTesT-sign2048, PublicKey=00240000048000001401000006020000002400005253413100080000010001002b524ed36058e444d0f2b12aeeeadab6f9a614dae43300d489746d143103a63c0178d0e316cc7a83156637d02b95b617c34bfa6877bc418118ce6d652e73211fdb80e5bc1878c6ef1b488dae12925390e7932dae9b22ada65ec76694a73b8e940db558d03ff5a3bee28017cb4448cd41dc946cc248e3313417f59092b9b62996de506c9446c7dceffed8e854cfa3d42eee30cdccbce934318b64ee20489178c00fa587f4ea666e4421eeae157fddf5ce7cfcf76e3b8b390005297f1b7e502c0f211c8c3f6886012cc4173aeedb4dc915d6d8f3821c19c0f1eedcccec8e839c1443ac96db7231ddebb391a5a92373aa87a6f2b2c8a9d57ad204e61813cc280da3")]
+#endif // SIGN2048
+#endif // !CORRECT_CASE
#if CORRECT_CASE
namespace CorrectCaseFriendAssembly {
using System;
+#if SIGN2048
+using System.Reflection;
+[assembly: AssemblyDelaySign(true)]
+[assembly: AssemblyKeyFile(@"internalsvisibleto-2048.snk")]
+#endif
+
namespace InternalsVisibleTo {
class Program {
static void Main (string[] args) {
Console.WriteLine("-- Correct case --");
+ try {
+ var a = new CorrectCaseFriendAssembly.PublicClass ();
+ a.InternalMethod ();
+ Console.WriteLine ("Access friend internal method: OK");
+ } catch (MemberAccessException) {
+ failCount += 1;
+ Console.WriteLine ("Access friend internal method: Fail");
+ }
+
try {
var a = new CorrectCaseFriendAssembly.InternalClass(@private: false);
Console.WriteLine("Access internal class private ctor: OK");
MONO_TRACE_W32HANDLE
} MonoTraceMask;
-extern GLogLevelFlags mono_internal_current_level;
-extern MonoTraceMask mono_internal_current_mask;
+MONO_API extern GLogLevelFlags mono_internal_current_level;
+MONO_API extern MonoTraceMask mono_internal_current_mask;
void
mono_trace_init (void);
void
mono_trace_cleanup (void);
-void
+MONO_API void
mono_tracev_inner (GLogLevelFlags level, MonoTraceMask mask, const char *format, va_list args);
void
#define mono_gc_printf(gc_log_file, format, ...) g_log ("mono-gc", G_LOG_LEVEL_MESSAGE, format, ##__VA_ARGS__)
#define mono_runtime_printf(format, ...) g_log ("mono-rt", G_LOG_LEVEL_MESSAGE, format "\n", ##__VA_ARGS__)
#define mono_runtime_printf_err(format, ...) g_log ("mono-rt", G_LOG_LEVEL_CRITICAL, format "\n", ##__VA_ARGS__)
+#define mono_profiler_printf(format, ...) g_log ("mono-prof", G_LOG_LEVEL_MESSAGE, format "\n", ##__VA_ARGS__)
+#define mono_profiler_printf_err(format, ...) g_log ("mono-prof", G_LOG_LEVEL_CRITICAL, format "\n", ##__VA_ARGS__)
#define mono_runtime_stdout_fflush() do { } while (0)
#else
#define mono_runtime_printf(format, ...) fprintf (stdout, format "\n", ##__VA_ARGS__)
#define mono_runtime_printf_err(format, ...) fprintf (stderr, format "\n", ##__VA_ARGS__)
+#define mono_profiler_printf(format, ...) fprintf (stdout, format "\n", ##__VA_ARGS__)
+#define mono_profiler_printf_err(format, ...) fprintf (stderr, format "\n", ##__VA_ARGS__)
#define mono_runtime_stdout_fflush() do { fflush (stdout); } while (0)
#endif
#include <glib.h>
#include <mono/utils/mono-compiler.h>
+#include <mono/utils/mono-publib.h>
/* never remove or reorder these enums values: they are used in corlib/System */
int mono_process_current_pid (void);
-int mono_cpu_count (void);
+MONO_API int mono_cpu_count (void);
gint64 mono_cpu_get_data (int cpu_id, MonoCpuData data, MonoProcessError *error);
gint32 mono_cpu_usage (MonoCpuUsageState *prev);
<PackAlignmentBoundary>0</PackAlignmentBoundary>
<CallingConvention>0</CallingConvention>
<ErrorReporting>0</ErrorReporting>
- <CommandLineTemplate Condition="'$(Platform)' == 'Win32'">"$(VCInstallDir)bin\ml.exe" /c [AllOptions] [AdditionalOptions] /Ta[Inputs]</CommandLineTemplate>
- <CommandLineTemplate Condition="'$(Platform)' == 'X64'">"$(VCInstallDir)bin\amd64\ml64.exe" /c [AllOptions] [AdditionalOptions] /Ta[Inputs]</CommandLineTemplate>
+ <CommandLineTemplate Condition="'$(Platform)' == 'Win32'">"ml.exe" /c [AllOptions] [AdditionalOptions] /Ta[Inputs]</CommandLineTemplate>
+ <CommandLineTemplate Condition="'$(Platform)' == 'X64'">"ml64.exe" /c [AllOptions] [AdditionalOptions] /Ta[Inputs]</CommandLineTemplate>
<CommandLineTemplate Condition="'$(Platform)' != 'Win32' and '$(Platform)' != 'X64'">echo MASM not supported on this platform</CommandLineTemplate>
<ExecutionDescription>Assembling %(Identity)...</ExecutionDescription>
</MASM>
<MONO_CFG_DIR>$(MONO_DIR)/runtime/etc</MONO_CFG_DIR>
<MONO_NUNIT_RUN_TARGET>net_4_x_System_test.dll</MONO_NUNIT_RUN_TARGET>
<MONO_NUNIT_FIXTURE></MONO_NUNIT_FIXTURE>
- <MONO_NUNIT_ARGS>-noshadow -exclude=NotWorking,ValueAdd,CAS,InetAccess /labels</MONO_NUNIT_ARGS>
+ <MONO_NUNIT_ARGS>-noshadow -exclude=NotWorking,CAS /labels</MONO_NUNIT_ARGS>
<MONO_NUNIT_ARGS Condition="'$(MONO_NUNIT_FIXTURE)'!=''">$(MONO_NUNIT_ARGS) -fixture $(MONO_NUNIT_FIXTURE)</MONO_NUNIT_ARGS>
<MONO_NUNIT_RUN_ADDITIONAL_ARGS>
</MONO_NUNIT_RUN_ADDITIONAL_ARGS>
</BuildMacro>
</ItemGroup>
<ItemDefinitionGroup />
-</Project>
\ No newline at end of file
+</Project>
; file generated by create-windef.pl
LIBRARY mono-profiler-vtune.dll
EXPORTS
-mono_profiler_startup
\ No newline at end of file
+mono_profiler_init
</ProjectReference>\r
</ItemDefinitionGroup>\r
<ItemGroup>\r
- <ClCompile Include="..\mono\profiler\mono-profiler-vtune.c" />\r
+ <ClCompile Include="..\mono\profiler\vtune.c" />\r
</ItemGroup>\r
<ItemGroup>\r
<None Include="mono-profiler-vtune.def" />\r
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
<ImportGroup Label="ExtensionTargets">\r
</ImportGroup>\r
-</Project>
\ No newline at end of file
+</Project>\r
</Filter>\r
</ItemGroup>\r
<ItemGroup>\r
- <ClCompile Include="..\mono\profiler\mono-profiler-vtune.c">\r
+ <ClCompile Include="..\mono\profiler\vtune.c">\r
<Filter>Source Files</Filter>\r
</ClCompile>\r
</ItemGroup>\r
<Filter>Resource Files</Filter>\r
</None>\r
</ItemGroup>\r
-</Project>
\ No newline at end of file
+</Project>\r
class MSBuild (GitHubPackage):
def __init__ (self):
GitHubPackage.__init__ (self, 'mono', 'msbuild', '15.3',
- revision = 'f7dcc3900c808775adad970f047202b4de34e986')
+ revision = '371d25657ed8ff8ca5908de8a221c14eac240fc0')
def build (self):
self.sh ('./cibuild.sh --scope Compile --target Mono --host Mono --config Release')
}
mono_class_init (klass);
if (mono_class_has_failure (klass)) {
- printf ("Error verifying class(0x%08x) %s.%s a type load error happened\n", token, klass->name_space, klass->name);
+ MonoError type_load_error;
+ error_init (&type_load_error);
+ mono_error_set_for_class_failure (&type_load_error, klass);
+ printf ("Could not initialize class(0x%08x) %s.%s due to %s\n", token, klass->name_space, klass->name, mono_error_get_message (&type_load_error));
+ mono_error_cleanup (&type_load_error);
++count;
}
mono_class_setup_vtable (klass);
if (mono_class_has_failure (klass)) {
- printf ("Error verifying class(0x%08x) %s.%s a type load error happened\n", token, klass->name_space, klass->name);
+ MonoError type_load_error;
+ error_init (&type_load_error);
+ mono_error_set_for_class_failure (&type_load_error, klass);
+ printf ("Could not initialize vtable of class(0x%08x) %s.%s due to %s\n", token, klass->name_space, klass->name, mono_error_get_message (&type_load_error));
+ mono_error_cleanup (&type_load_error);
++count;
}
}