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][tests] Make it easier to set up a unit test #108288

Merged
merged 14 commits into from
Sep 26, 2024

Conversation

lambdageek
Copy link
Member

  1. We used to stackalloc a lot of data because the Target callback had to be an UnmanagedCallersOnly function pointer. But now it's just a delegate. So we can heap allocate the mock memory space and get rid of a bunch of incidental fixed statements
  2. We used to spell out the JSON contract descriptor in every test case. We dont' need to do that - most tests are not testing parsing. Hide all that stuff in MockMemorySpace.Builder

Now that Target's reader callback is just a normal managed delegate, we don't have a lot of reason to make the testing ReadContext a ref struct.  So simplify our resource usage and just store the descriptors and json as heap allocated arrays
The ReadContext for the  tests keeps a copy of the json payload, we don't need to use unmanaged pointers
we don't hold pointers to span data anymore
most of our tests that use a valid contract descriptor don't need to repeat the boilerplat to fill it in
We previously did the wrong thing with TargetTestHelpers.MakeGlobalJson:
it always filled in direct values.  So technically filling in the
pointer data in all the other tests is unnecessary.

Add a second SetGlobals overload for the builder that takes
a 4-tuple (either ulong? Value or uint IndirectIndex) and a second
collection of actual values for the indices.
everything is using high level construction now
@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Sep 26, 2024
@lambdageek lambdageek added area-Diagnostics-coreclr and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Sep 26, 2024
Copy link
Contributor

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

if (_heapFragments.Count > 0)
Span<byte> descriptor = stackalloc byte[_targetTestHelpers.ContractDescriptorSize];
_targetTestHelpers.ContractDescriptorFill(descriptor, jsonLength, pointerDataCount);
const ulong ContractDescriptorAddr = 0xaaaaaaaa;
Copy link
Member

Choose a reason for hiding this comment

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

Is this an important value? The address is also only 32-bits and we are assigning to a 64-bit value. Perhaps a comment to clarify what this is used for?

Copy link
Member Author

Choose a reason for hiding this comment

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

Moved it to the top of the file and added a comment that it's arbitrary but mustn't overlap any of the other arbitrary addresses that the tests use.

Right now in the interest of not doing too much magic and keeping the tests reproducible all the "allocation" in the mock memory space is done by hand - by picking an address that doesn't overlap anything and allocating a fragment there (the builder will tell you if you mathed wrong). I think in the longer term it will be easier to write bigger tests if we had some kind of mock malloc, but I'm worried that debugging a failed test will be too difficult, or the tests might become non-deterministic or something. But on the other hand, I'm hoping after the contract refactoring we won't have to write massive tests. So we'll see.

throw new InvalidOperationException("Context already created");
GCHandle fragmentReaderHandle = default; ;
if (_heapFragments.Count > 0)
Span<byte> descriptor = stackalloc byte[_targetTestHelpers.ContractDescriptorSize];
Copy link
Member

Choose a reason for hiding this comment

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

This seems odd. Why not just allocate the array and then assign it below. Both the stackalloc and the array seem unnecessary.

Copy link
Member Author

Choose a reason for hiding this comment

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

yea I missed these while copy/pasting. They're leftover from the earlier unsafe pointer based approach.

I checked, there aren't any more stackalloc in the tests

if (_indirectValues != null)
{
int pointerSize = _targetTestHelpers.PointerSize;
Span<byte> pointerDataBytes = stackalloc byte[_indirectValues.Count * pointerSize];
Copy link
Member

Choose a reason for hiding this comment

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

Another stackalloc and array question.

@lambdageek lambdageek merged commit fdc9e54 into dotnet:main Sep 26, 2024
148 of 150 checks passed
sirntar pushed a commit to sirntar/runtime that referenced this pull request Sep 30, 2024
We used to stackalloc a lot of data because the Target callback had to be an UnmanagedCallersOnly function pointer. But now it's just a delegate. So we can heap allocate the mock memory space and get rid of a bunch of incidental fixed statements
We used to spell out the JSON contract descriptor in every test case. We dont' need to do that - most tests are not testing parsing. Hide all that stuff in MockMemorySpace.Builder

* make MockMemorySpace.ReadContext a class

   Now that Target's reader callback is just a normal managed delegate, we don't have a lot of reason to make the testing ReadContext a ref struct.  So simplify our resource usage and just store the descriptors and json as heap allocated arrays

* remove uses of fixed in tests

   The ReadContext for the  tests keeps a copy of the json payload, we don't need to use unmanaged pointers

* make the MockMemorySpace.Builder a normal class

   we don't hold pointers to span data anymore

* make MockMemorySpace.ReadContext private

* begin hiding ContractDescriptorFill

   most of our tests that use a valid contract descriptor don't need to repeat the boilerplate to fill it in

* start removing json and pointer data boilerplate

* Don't fill the pointer data when there isn't any

   We previously did the wrong thing with TargetTestHelpers.MakeGlobalJson: it always filled in direct values.  So technically filling in the pointer data in all the other tests is unnecessary.

   Add a second SetGlobals overload for the builder that takes a 4-tuple (either ulong? Value or uint IndirectIndex) and a second collection of actual values for the indices.

* remove unused MockMemorySpace.Builder functions

   everything is using high level construction now

* remove unneeded stackalloc

* describe test addresses
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.

2 participants