-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Change OwnedMemory to MemoryManager and add an IMemoryOwner. #17340
Conversation
Guidance & documentation should be coming online over the next few hours. I'll send links once I've finished the docs. These docs will also justify the API changes and should answer questions anybody might have regarding this. |
Is there any way this could be done in stages or nah? |
We would have to only add APIs (leaving all the old APIs as is), wait for it to propagate, update all the calls, and then remove the old APIs. The propagation time across all repos is too large for us to wait for the round-trip. Also, this change is a bit more complex, so doing it in stages is a lot more difficult in general. |
Given the goal of having this done Friday, I think the best way is to get this merged tonight and get it properly consumed in corefx tomorrow AM. |
/// <summary> | ||
/// The number of items in the Memory<typeparamref name="T"/>. | ||
/// </summary> | ||
public virtual int Length => GetSpan().Length; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this change; any reason for this to be virtual?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably to avoid the GetSpan()
call?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could have done
public int Length { get; }
protected MemoryManager(int length)
{
Length = length;
}
public Memory<T> Memory => new Memory<T>(this, 0, Length);
Unless its valid that derived classes of MemoryManager
can change in length on the go?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@benaadams There are scenarios where this can change; e.g., if the factory pools and reuses these instances. We can provide a default implementation of this logic via reading the value from GetSpan()
, but as a perf optimization implementations may want to provide the value in a more direct manner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would it change in case of a pool? We usually don't return exact size requested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@benaadams @GrabYourPitchforks just made me aware of the fact that this type will rarely be used directly because the MemoryPool returns IMemoryOwner<T>
, so really none of this matters. Though as an implementer of MemoryManager<T>
, I think it's confusing to expose length. So lets try to come up with something concrete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
K so Memory
won't inline due to the interface.
However as the implementer you will have to get a Length
somewhere and possibly an Offset
, so can stick it on the type and have everything else inline and have a good performance implementation with no additional virtuals or the need to implement the two methods?
public abstract class MemoryManager<T> : IMemoryOwner<T>, IPinnable
{
protected int Offset { get; set; }
protected int Length { get; set; }
protected MemoryManager()
{
}
protected MemoryManager(int length)
{
Length = length;
}
protected MemoryManager(int offset, int length)
{
Offset = offset;
Length = length;
}
public Memory<T> Memory => new Memory<T>(this, Offset, Length);
// Rest as now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or kill Length
and force the implementation
public abstract class MemoryManager<T> : IMemoryOwner<T>, IPinnable
{
public abstract Memory<T> Memory { get; }
// Rest as now
Passing off the validation of offset and length to derived class
public class MyMemory : MemoryManager<byte>
{
private int Offset { get; set; }
private int Length { get; set; }
public MyMemory(...)
{
// ...
}
public override Memory<T> Memory => new Memory<T>(this, Offset, Length);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@GrabYourPitchforks making it abstract?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the feedback. In the interest of time, I am going to merge the change as is and we can consider changing this separately.
FYI, https://gist.github.com/GrabYourPitchforks/4c3e1935fd4d9fa2831dbfcab35dffc6 is the latest draft of the The document detailing |
OSX10.12 x64 Checked Innerloop Build and Test — Triggered. (93/134 on osx-10.12||OSX.1012.Amd6.Open) |
@ahsonkhan don't block on the mac leg; https://github.com/dotnet/core-eng/issues/3064 |
And here's the doc detailing the relationship between |
@ahsonkhan you're free to merge this given the infra issue blocking the last 2 legs from actually executing and the minimal risk of a macos or arm specific issue in this PR. |
UpcomingPR on the corefx side: dotnet/corefx#28640cc @joshfree, @GrabYourPitchforks, @KrzysztofCwalina, @pakrym, @davidfowl, @jkotas, @stephentoub
cc @Anipik, @safern - many of these changes will need to be mirrored