Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cDAC] Implement ReJIT portion of SOSDacImpl::GetMethodDescData #109936

Merged
merged 11 commits into from
Dec 4, 2024

Conversation

max-charlamb
Copy link
Contributor

@max-charlamb max-charlamb commented Nov 18, 2024

Adds ReJIT support to SOSDacImpl::GetMethodDescData.

Modifies ICodeVersions contract

interface ICodeVersions
{
    /* adds */ ILCodeVersionHandle GetActiveILCodeVersion(TargetPointer methodDesc);
    /* adds */ ILCodeVersionHandle GetILCodeVersion(NativeCodeVersionHandle codeVersionHandle);
    /* adds */ IEnumerable<ILCodeVersionHandle> GetILCodeVersions(TargetPointer methodDesc);
    /* adds */ NativeCodeVersionHandle GetActiveNativeCodeVersionForILCodeVersion(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle);

    /* removes */ NativeCodeVersionHandle GetActiveNativeCodeVersion(TargetPointer methodDesc);
}

static class ICodeVersionsExtensions
{
    /* adds */ static NativeCodeVersionHandle GetActiveNativeCodeVersion(this ICodeVersions cv, TargetPointer methodDesc);
}

GetActiveNativeCodeVersion can be implemented in terms of existing ICodeVersions methods GetActiveILCodeVersion and GetActiveNativeCodeVersionForILCodeVersion. With the goal of keeping the contract surface area as small as possible, I think it would be best to remove this method and implement as an extension method on ICodeVersions. Since it only relies on the existing contract APIs, the extension method does not need to be versioned.

Adds to IReJIT contract

interface IReJIT
{
    /* adds */ RejitState GetRejitState(ILCodeVersionHandle codeVersionHandle);

    /* adds */ TargetNUInt GetRejitId(ILCodeVersionHandle codeVersionHandle);
}

static class IReJITExtensions
{
    /* adds */ static IEnumerable<TargetNUInt> GetRejitIds(this IReJIT rejit, Target target, TargetPointer methodDesc);
}

Adds fields to existing cDAC Data Types

  • Adds FirstVersionNode pointer to ILCodeVersioningState. This is used to iterate the linked list of explicit ILCodeVersionNodes`.
  • Adds Next pointer to ILCodeVersionNode to iterate the linked list of explicit nodes.
  • Adds RejitState uint to ILCodeVersionNode`

Testing

Tested manually using the ReJIT tooling in the coreclr rejit test. I ran the test in WinDBG and debugged WinDBG in VS to verify the SOS calls had the expected behavior.

Contributes to #109426

Copy link
Contributor

Tagging subscribers to this area: @tommcdon
See info in area-owners.md if you want to be subscribed.

@@ -7,10 +7,20 @@ namespace Microsoft.Diagnostics.DataContractReader;


[DebuggerDisplay("{Hex}")]
public readonly struct TargetNUInt
public readonly struct TargetNUInt : IEquatable<TargetNUInt>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adds IEquatable to make comparing TargetNUInts less verbose.


kSuppressParams = 0x80000000
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debated making this part of the data type, but didn't want to tie it in case the values change. Hiding them in the ReJIT implementation means we need a second copy for testing.

@max-charlamb max-charlamb marked this pull request as ready for review November 22, 2024 20:37
bool IsEnabled() => throw new NotImplementedException();

RejitState GetRejitState(ILCodeVersionHandle codeVersionHandle) => throw new NotImplementedException();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the cdac I feel like we should either make an effort to make the data structures and algorithms match the runtime directly or make a conscious effort to have a higher level API that abstracts away some of the details. Putting GetRejitState and GetRejitId here doesn't feel like it accomplishes either of those tasks. In the runtime they are part of ILCodeVersion and in the cdac they are now part of a different conceptual contract, but we don't change the abstraction level.

Curious to know what other people's thoughts are here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know, we do need contract methods to get this metadata (id/state) as the cDAC is setup to not allow users to access the marshalled data structures directly. Enforcing the use of contract methods allows for versioning independent of runtime changes.

Another option would be to put these methods on the ICodeVersions contract. However, I believe separating the ICodeVersions contract from the IReJIT contract is beneficial as it allows us to separate the logic determining what code version is active from associated metadata which ReJIT/TieredCompilation add to code versions. In case this metadata structure changes in the future it will be simple to change just the relevant contract implementation without modifying the larger code versioning logic.

When TieredCompilation SOS APIs are implemented, I think we should create an ITieredCompilation contract that allows us to get the optimization tier metadata off of NativeCodeVersions.

Since FEATURE_REJIT can be enabled/disabled separately from FEATURE_CODE_VERSIONING, I think this also gives us a path to adapt to toggleable runtime features through contract versions. If for example ReJIT is disabled in a target, the ReJIT contract can be different and let cDAC users know ReJIT is disabled.

I am also curious if other people have suggestions on better ways to implement the ReJIT cDAC functionality.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there might be two levels we are talking about here

  • data structures and algorithms match the runtime: this seems like what we want for the data descriptors and the contract implementations in the cDAC reader. They are not directly exposed to consumers (for example, the ISOSDacInterface implementation in SOSDacImpl.cs).
  • higher level API: this should be the contracts and the methods on those contracts

I do view the CodeVersions and ReJIT as separate at a higher level - one depends on the other, but I think that is a natural/expected part of these contracts. With the IL/NativeCodeVersionHandle providing the opaque common link, separate CodeVersions and ReJIT contracts (and eventually TieredCompilation) makes sense to me.

docs/design/datacontracts/ReJIT.md Outdated Show resolved Hide resolved
Comment on lines 10 to 26
internal readonly TargetPointer Module;
internal readonly uint MethodDefinition;
internal readonly TargetPointer ILCodeVersionNode;
internal ILCodeVersionHandle(TargetPointer module, uint methodDef, TargetPointer ilCodeVersionNodeAddress)
{
if (module != TargetPointer.Null && ilCodeVersionNodeAddress != TargetPointer.Null)
throw new ArgumentException("Both MethodDesc and ILCodeVersionNode cannot be non-null");

if (module != TargetPointer.Null && methodDef == 0)
throw new ArgumentException("MethodDefinition must be non-zero if Module is non-null");

Module = module;
MethodDefinition = methodDef;
ILCodeVersionNode = ilCodeVersionNodeAddress;
}
public static ILCodeVersionHandle Invalid => new ILCodeVersionHandle(TargetPointer.Null, 0, TargetPointer.Null);
public bool IsValid => Module != TargetPointer.Null || ILCodeVersionNode != TargetPointer.Null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on removing these details from the *CodeVersionHandle in the contract doc? I see them more as opaque handles that get returned from / passed to different contracts, with the module / method definiton / node on them being implementation details that aren't part of the contract.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I think we should have only the publicly usable parts of the handle. I'll make that change.

src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs Outdated Show resolved Hide resolved
src/native/managed/cdacreader/tests/CodeVersionsTests.cs Outdated Show resolved Hide resolved
src/native/managed/cdacreader/tests/CodeVersionsTests.cs Outdated Show resolved Hide resolved
src/native/managed/cdacreader/tests/ReJITTests.cs Outdated Show resolved Hide resolved
@max-charlamb
Copy link
Contributor Author

/ba-g Build analysis blocked by #110395

@max-charlamb max-charlamb merged commit 1fc8222 into dotnet:main Dec 4, 2024
144 of 150 checks passed
eduardo-vp pushed a commit to eduardo-vp/runtime that referenced this pull request Dec 5, 2024
…et#109936)

* Modifies CodeVersions contract
* Adds to ReJIT contract
* Adds contract extension methods as helpers for when functionality can be implemented in terms of versioned APIs.
mikelle-rogers pushed a commit to mikelle-rogers/runtime that referenced this pull request Dec 10, 2024
…et#109936)

* Modifies CodeVersions contract
* Adds to ReJIT contract
* Adds contract extension methods as helpers for when functionality can be implemented in terms of versioned APIs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants