diff options
author | David Mason <davmason@microsoft.com> | 2019-06-07 13:49:15 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-07 13:49:15 -0700 |
commit | b314ed86b11756834b0936e56c3d841e7407f81d (patch) | |
tree | 4895cca7eef7e36f683a291bec0183b2163dc8fb | |
parent | b614f4f5529296cac834e54f2fa4bc540a61a04d (diff) | |
download | coreclr-b314ed86b11756834b0936e56c3d841e7407f81d.tar.gz coreclr-b314ed86b11756834b0936e56c3d841e7407f81d.tar.bz2 coreclr-b314ed86b11756834b0936e56c3d841e7407f81d.zip |
Add docs for rejit on attach and the new profiler attach mechanism (#24868)
5 files changed, 104 insertions, 1 deletions
diff --git a/Documentation/Profiling/Profiler Attach on CoreCLR.md b/Documentation/Profiling/Profiler Attach on CoreCLR.md new file mode 100644 index 0000000000..1e494a79f3 --- /dev/null +++ b/Documentation/Profiling/Profiler Attach on CoreCLR.md @@ -0,0 +1,28 @@ + +# Profiler Attach on CoreCLR + +Starting with .Net Core 3 preview6 there is a new profiler attach mechanism for CoreCLR. The desktop .Net Framework has had profiler attach since v4, but we have not had profiler attach on .Net Core. The desktop implementation was very Windows-centric and we did not have a good way to offer a cross platform profiler attach mechanism. The recent diagnostics port work means there is now a cross platform communication channel for external processes to communicate with a running CoreCLR process, and this allowed us to finally offer profiler attach for CoreCLR. + +## How do you attach a profiler to a running CoreCLR process? + +***Disclaimer: the code in the dotnet/diagnostics repo referred to below is in prelease and is under active development. You should expect things to change before the official release.*** + +Attaching a profiler to a running CoreCLR process involves sending a message from an external process (the trigger process) on the diagnostics port telling the runtime which profiler to attach. We have a premade managed implementation over at the [Diagnostics repo](https://github.com/dotnet/diagnostics). The attach method is `DiagnosticHelpers.AttachProfiler` in the `Microsoft.Diagnostics.Tools.RuntimeClient` library, which will be shipped on NuGet once it is released. It takes five arguments: + +1) `int processId` - (Required) The process ID to attach to. +2) `uint attachTimeout` - (Required) A timeout that informs the runtime how long to wait while attempting to attach. This does not impact the timeout of trying to send the attach message. +3) `Guid profilerGuid` - (Required) The profiler's GUID to use when initializing. +4) `string profilerPath` - (Required) The path to the profiler on disk. +5) `byte[] additionalData` - (Optional) A data blob that will be passed to `ICorProfilerCallback3::InitializeForAttach` as `pvClientData`. + +This method returns a status HR following the usual convention, 0 (S_OK) means a profiler was successfully attached and any other value is an error indicating what went wrong. + +## What if you can't run managed code in your trigger process? + +If you are unable to run managed code as part of your trigger process, it is still possible to request a profiler attach. The spec for the diagnostics port is located [here](https://github.com/dotnet/diagnostics/blob/master/documentation/design-docs/ipc-protocol.md). + +You will have to do the following (according to the above spec): +1) Open the appropriate channel - domain socket on Linux and a named pipe on Windows +2) Construct the payload with the appropriate command (Profiler) and command ID (AttachProfiler), plus all of the arguments listed above +3) Send the payload over the channel +4) Parse the response diff --git a/Documentation/Profiling/Profiler Breaking Changes.md b/Documentation/Profiling/Profiler Breaking Changes.md index f63b22764e..8f693a4650 100644 --- a/Documentation/Profiling/Profiler Breaking Changes.md +++ b/Documentation/Profiling/Profiler Breaking Changes.md @@ -3,4 +3,5 @@ Over time we will need to modify the Profiler APIs, this document will serve as a record of any breaking changes. 1. Code Versioning introduced changes documented [here](../design-docs/code-versioning-profiler-breaking-changes.md) -2. The work to allow adding new types and methods after module load means ICorProfilerInfo7::ApplyMetadata will now potentially trigger a GC, and will not be callable in situations where a GC can not happen (for example ICorProfilerCallback::RootReferences).
\ No newline at end of file +2. The work to allow adding new types and methods after module load means ICorProfilerInfo7::ApplyMetadata will now potentially trigger a GC, and will not be callable in situations where a GC can not happen (for example ICorProfilerCallback::RootReferences). +3. As part of the work to allow ReJIT on attach ReJITted methods will no longer be inlined (ever). Since the inlining is blocked there won't be a `ICorProfilerCallback::JITInlining` callback.
\ No newline at end of file diff --git a/Documentation/Profiling/ReJIT on Attach.md b/Documentation/Profiling/ReJIT on Attach.md new file mode 100644 index 0000000000..f45116a6c5 --- /dev/null +++ b/Documentation/Profiling/ReJIT on Attach.md @@ -0,0 +1,71 @@ +# ReJIT on Attach + +A longstanding feature request we've had from profiler authors is the ability to ReJIT a method after attach. There are non-trivial technical reasons this was never an option in desktop .Net, but CoreCLR has had some changes that made it more feasible to attain. As of .Net Core 3 preview5 profiler authors now have the ability to ReJIT methods after attach. + +## The new API + +To enable ReJIT on attach there is a new API `ICorProfilerInfo10::RequestReJITWithInliners`. Here is the signature: + +``` + HRESULT RequestReJITWithInliners( + [in] DWORD dwRejitFlags, + [in] ULONG cFunctions, + [in, size_is(cFunctions)] ModuleID moduleIds[], + [in, size_is(cFunctions)] mdMethodDef methodIds[]); +``` + +Conceptually this works the same as `ICorProfilerInfo4::RequestReJIT` except it will automatically ReJIT any methods that have inlined the target method(s) in the past. The arguments are the same except for the additon of `dwRejitFlags` as the first parameter. The valid values for this argument come from this enum: + +``` +typedef enum +{ + // ReJITted methods will be prevented from being inlined + COR_PRF_REJIT_BLOCK_INLINING = 0x1, + + // This flag controls whether the runtime will call GetReJITParameters + // on methods that are ReJITted because they inline a method that was requested + // for ReJIT + COR_PRF_REJIT_INLINING_CALLBACKS = 0x2 +} COR_PRF_REJIT_FLAGS; +``` + +Any callers of this API must set `COR_PRF_REJIT_BLOCK_INLINING`. Although it is possible that in the future this restriction will be lifted, the current implementation blocks ReJITted methods from being inlined (ever). + +The other value `COR_PRF_REJIT_INLINING_CALLBACKS` controls whether you get a `ICorProfilerCallback4::GetReJITParameters` callback for any methods that are ReJITted as inliners of the requested method. The default is to not receive callbacks for these methods. You will always receive a `GetReJITParameters` callback for any methods that are explictly requested. + + +## Inner workings/Limitations + +With this API you are no longer required to monitor JIT callbacks to manually block inlining from occurring. To acheive that the runtime now globally blocks a ReJITted method from being inlined (even if it was ReJITted with `ICorProfilerInfo4::RequestReJIT` and not the new API). Once a method is reverted with `ICorProfilerInfo4::RequestRevert` inlining will occur again for any future jittings. + +It is important to mention here how `RequestRevert` works. When you revert a ReJITted method, the original native code is activated. This means there are potential pitfalls for calling `RequestRevert`. Consider an app where method A inlines method B and the profiler wants to ReJIT both A and B. Once A and B are both ReJITted, the application will behave as expected. However, if later on the profiler decides to revert method A but intends to leave method B ReJITted, it might be surprising to find that once the original native code for A is activated this includes the inlined non-ReJIT IL for method B. Effectively any calls to B through A will be calling the original, unmodified IL. + +To revert a method without having to reason about the inline sequence, we suggest calling RequestReJIT again on the method but providing the original IL in GetReJITParameters. + +The limitation of collectible and dynamic methods has not been lifted. It is not currently possible to ReJIT these types of methods, although we would like to lift that restriction in the future. Even if you never intend to call RequestReJIT directly on a collectible or dynamic method, this may still affect you when doing ReJIT on attach if the method you would like to ReJIT has been inlined in a collectible or dynamic method. I.e. if you would like to ReJIT method A which has been inlined in collectible method B, there is currently no way to make method B call the updated method A. + +## Metadata Changes on Attach + +Usually profiler authors do not want to trivially change the IL for ReJITted methods, but rather inject new types/methods and call those new types/methods. Previously our guidance has been to do any metadata rewriting during the `ICorProfilerCallback::ModuleLoadFinished` callback. This advice presents a challenge if the profiler is not attached during module load and still wants to modify metadata. + +To work around this a set of metadata changes is now legal to make at any point as long as you call `ICorProfilerInfo7::ApplyMetadata` afterwards: +* `DefineUserString` +* `DefineTypeRefByName` +* `DefineMemberRef` +* `DefineTypeDef` +* `DefineMethod` - methods on new types, or non-virtual methods on existing types +* `DefineNestedType` - only on new types +* `DefineCustomAttribute` +* `DefinePinvokeMap` +* `DefineModuleRef` +* `DefineField` - only on new types +* `DefineEvent` +* `DefineMethodImpl` - only on new types +* `DefineMethodSpec` + + +There are still some metadata changes that are definitely illegal and will almost certainly never become legal due to restrictions/assumptions existing in the runtime: +* Adding a virtual method to an existing type +* Adding a field to an existing type + +Anything not listed as either legal or illegal is untested and should not be assumed to work.
\ No newline at end of file diff --git a/Documentation/Profiling/davbr-blog-archive/Attach.md b/Documentation/Profiling/davbr-blog-archive/Attach.md index 25da0486fe..e4874ba9cd 100644 --- a/Documentation/Profiling/davbr-blog-archive/Attach.md +++ b/Documentation/Profiling/davbr-blog-archive/Attach.md @@ -1,5 +1,7 @@ *This blog post originally appeared on David Broman's blog on 11/4/2009* +***[Update 5/30/19]: The archived content below refers to an Attach mechanism that only worked on desktop, not on .Net Core. Please see [Profiler Attach on CoreCLR](../Profiler Attach on Coreclr.md) for profiler attach on CoreCLR*** + Profiler attach is a feature that allows you to attach a profiler to an already running process. The usefulness of this is fairly obvious to anyone who's ever attached a debugger to a running-process: It's helpful when diagnosing hard-to-reproduce problems, and particularly useful when encountering issues in production. diff --git a/Documentation/Profiling/davbr-blog-archive/Attach2.md b/Documentation/Profiling/davbr-blog-archive/Attach2.md index 2f41733f7c..d2db6ca613 100644 --- a/Documentation/Profiling/davbr-blog-archive/Attach2.md +++ b/Documentation/Profiling/davbr-blog-archive/Attach2.md @@ -1,5 +1,6 @@ *This blog post originally appeared on David Broman's blog on 1/18/2010* +***[Update 5/30/19]: The archived content below refers to an Attach mechanism that only worked on desktop, not on .Net Core. Please see [Profiler Attach on CoreCLR](../Profiler Attach on Coreclr.md) for profiler attach on CoreCLR*** In a previous [post](Attach.md), I outlined to all you profiler writers how to modify your profiler so it can attach to running processes, and what sorts of limitations your profiler will have when it attaches. In this post, I answer the question, “My profiler is attached. What should it do next?” |