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

Span<T> #5851

Closed
jkotas opened this Issue Jun 17, 2016 · 88 comments

Comments

Projects
None yet
@jkotas
Member

jkotas commented Jun 17, 2016

Turn https://github.com/dotnet/corefxlab/tree/master/src/System.Slices into efficient first class feature.

  • Initial implementation: #7886
  • Design document: https://github.com/dotnet/corefxlab/blob/master/docs/specs/span.md
  • JIT - Correctness – proper GC reporting of the special byref field
    • Re-enable GC layout reporting for Span
      if (pMT == g_TypedReferenceMT) // if (pMT->IsByRefLike()) // TODO-SPAN: Proper GC reporting
      . JIT chokes on it - fragile assumption introduced by recent JIT throughput fix.
    • Intrinsic for reading/writing byrefs
      // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
      , multiple places
  • VM - Correctness
    • proper GC reporting: #8517
    • enforcement of byreflike constrains #8516
    • #9032
  • VM - Stress
    • GC reporting for tailcalls - #9032
    • GC reporting for struct passed in regs on Unix - #9033
  • JIT - Optimizations – apply same sort of optimizations to Span as it does for Strings or Arrays (treat indexers as intrinsics, range check elimination, etc.)
    • Span methods may not inline when called from shared methods #10031
    • Improve aliasing model for implicit-by-ref struct passing #10049
    • Recognize/optimize Span bounds checks more like array bounds checks #10050
    • Better optimization for CORINFO_HELP_RUNTIMEHANDLE_METHOD #10051 [moved to future]
  • Update buildtools with Roslyn that has local byref and locals C# 7 feature
  • Implement the full public surface #5857
  • Add Span<T> to framework contracts
  • Add Span<T> tests
  • Add Span<T> and ReadOnlySpan<T> as yet another ByRef-like type in Roslyn, so that unsupported operations on Span<T> like boxing or creating Span<T>[] are compile errors: https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/span-safety.md
  • Make sure there is a way to pin Span<T> for interop
  • Debugging #8518 / dotnet/corefx#14376
  • Reflection - #17296
  • Performance optimizations
    • Optimize Copy, Clear, Fill - #9161
  • Marshaler support (as with arrays) #14460
  • APIs across corefx that accept spans (dotnet/corefx#21281)
  • APIs for working with specialty spans (dotnet/corefx#21395)

@jkotas jkotas added this to the Future milestone Jun 17, 2016

@stephentoub

This comment has been minimized.

Show comment
Hide comment
@stephentoub

stephentoub Jun 17, 2016

Member
  • Marshaler support (as with arrays)?
Member

stephentoub commented Jun 17, 2016

  • Marshaler support (as with arrays)?
@adamsitnik

This comment has been minimized.

Show comment
Hide comment
@adamsitnik

adamsitnik Jun 17, 2016

Member

I just love it, hope for some up-for-grabs issues!

Member

adamsitnik commented Jun 17, 2016

I just love it, hope for some up-for-grabs issues!

@benaadams

This comment has been minimized.

Show comment
Hide comment
@benaadams

benaadams Jun 17, 2016

Collaborator

Does "Add Span to framework contracts" include items like adding to Stream Read/Write etc? Or is it making Span available as a type? (Assuming latter, and others will be new issues after)

Collaborator

benaadams commented Jun 17, 2016

Does "Add Span to framework contracts" include items like adding to Stream Read/Write etc? Or is it making Span available as a type? (Assuming latter, and others will be new issues after)

@omariom

This comment has been minimized.

Show comment
Hide comment
@omariom

omariom Jun 17, 2016

Contributor

The CoreFxLab's prototype has useful extensions methods for Span<byte> and Span<char> like Read/Write and StartsWith/EndsWith. Will CoreCLR's Span get them?

Contributor

omariom commented Jun 17, 2016

The CoreFxLab's prototype has useful extensions methods for Span<byte> and Span<char> like Read/Write and StartsWith/EndsWith. Will CoreCLR's Span get them?

@dotnetchris

This comment has been minimized.

Show comment
Hide comment
@dotnetchris

dotnetchris Jun 17, 2016

Would there be any sane method to allow Span<> to integrate with List<> that it could operate on the underlying array?

dotnetchris commented Jun 17, 2016

Would there be any sane method to allow Span<> to integrate with List<> that it could operate on the underlying array?

@KrzysztofCwalina

This comment has been minimized.

Show comment
Hide comment
@KrzysztofCwalina

KrzysztofCwalina Jun 17, 2016

Member

@omariom, we need the corfxlab API and the corlcr one to be the same (portable). The reason for it is that I think we need to use the corfxlab implementation for previously shipped runtime/frameworks, e.g. .NET Framework 4.5. Otherwise, the addoption of Span will be very much inhibited by inability to write portable code. Of course, the out-of-band span will be slower, but as long as the API is available in portable code, we should be good.

Member

KrzysztofCwalina commented Jun 17, 2016

@omariom, we need the corfxlab API and the corlcr one to be the same (portable). The reason for it is that I think we need to use the corfxlab implementation for previously shipped runtime/frameworks, e.g. .NET Framework 4.5. Otherwise, the addoption of Span will be very much inhibited by inability to write portable code. Of course, the out-of-band span will be slower, but as long as the API is available in portable code, we should be good.

@KrzysztofCwalina

This comment has been minimized.

Show comment
Hide comment
@KrzysztofCwalina

KrzysztofCwalina Jun 17, 2016

Member

@benaadams, we need some existing APIs, e.g. Stream.Read/Write to accept spans, but I think it's a separate workitem form the one @jkotas listed.

Member

KrzysztofCwalina commented Jun 17, 2016

@benaadams, we need some existing APIs, e.g. Stream.Read/Write to accept spans, but I think it's a separate workitem form the one @jkotas listed.

@KrzysztofCwalina

This comment has been minimized.

Show comment
Hide comment
@KrzysztofCwalina

KrzysztofCwalina Jun 17, 2016

Member

@dotnetchris, what do you consider "sane" in this context? If you mean wrapping Span into List then no (Span is stack only, and does not always have "underlying array").

Member

KrzysztofCwalina commented Jun 17, 2016

@dotnetchris, what do you consider "sane" in this context? If you mean wrapping Span into List then no (Span is stack only, and does not always have "underlying array").

@KrzysztofCwalina

This comment has been minimized.

Show comment
Hide comment
@KrzysztofCwalina

KrzysztofCwalina Jun 17, 2016

Member

@adamsitnik, I am not sure we want completely open up for grabs so early (as there is lots of tricky work here) but you have done lots of good work in corfxlab and so if you (presonally) would like to take #5857, it would be great! Same for @omariom :-)

Member

KrzysztofCwalina commented Jun 17, 2016

@adamsitnik, I am not sure we want completely open up for grabs so early (as there is lots of tricky work here) but you have done lots of good work in corfxlab and so if you (presonally) would like to take #5857, it would be great! Same for @omariom :-)

@adamsitnik

This comment has been minimized.

Show comment
Hide comment
@adamsitnik

adamsitnik Jun 17, 2016

Member

@KrzysztofCwalina Thanks! consider it done ;)

Member

adamsitnik commented Jun 17, 2016

@KrzysztofCwalina Thanks! consider it done ;)

@dotnetchris

This comment has been minimized.

Show comment
Hide comment
@dotnetchris

dotnetchris Jun 17, 2016

@KrzysztofCwalina i meant for Span to access List's internal array

dotnetchris commented Jun 17, 2016

@KrzysztofCwalina i meant for Span to access List's internal array

@KrzysztofCwalina

This comment has been minimized.

Show comment
Hide comment
@KrzysztofCwalina

KrzysztofCwalina Jun 17, 2016

Member

I think we might also need to constrain T to primitive type (i.e. type with no managed object references). Otherwise, it will be possible to create Span over native memory without GC being aware of the roots.

Member

KrzysztofCwalina commented Jun 17, 2016

I think we might also need to constrain T to primitive type (i.e. type with no managed object references). Otherwise, it will be possible to create Span over native memory without GC being aware of the roots.

@omariom

This comment has been minimized.

Show comment
Hide comment
@omariom

omariom Jun 18, 2016

Contributor

@KrzysztofCwalina
Only certain operations seem unsafe in this sense: Cast, BlockEquals and Span<byte>.Read/Write.

Contributor

omariom commented Jun 18, 2016

@KrzysztofCwalina
Only certain operations seem unsafe in this sense: Cast, BlockEquals and Span<byte>.Read/Write.

@KrzysztofCwalina

This comment has been minimized.

Show comment
Hide comment
@KrzysztofCwalina

KrzysztofCwalina Jun 18, 2016

Member

@dotnetchris, yes, it would be great to add List<T>.Slice that returns Span<T>. Same with other slicable types, e.g. String.Slice -> Span<char>.

Member

KrzysztofCwalina commented Jun 18, 2016

@dotnetchris, yes, it would be great to add List<T>.Slice that returns Span<T>. Same with other slicable types, e.g. String.Slice -> Span<char>.

@KrzysztofCwalina

This comment has been minimized.

Show comment
Hide comment
@KrzysztofCwalina

KrzysztofCwalina Jun 18, 2016

Member

@omariom, it seems like accessors and copy operations too, e.g.
var nativeSpan = new Span(nativeMemory, len);
nativeSpan[0] = new object();
// will GC know that the object is rooted? will it change the native memory when the object is rooted and moves?

Similarly when an array backed span of object sis copied to native span.

Member

KrzysztofCwalina commented Jun 18, 2016

@omariom, it seems like accessors and copy operations too, e.g.
var nativeSpan = new Span(nativeMemory, len);
nativeSpan[0] = new object();
// will GC know that the object is rooted? will it change the native memory when the object is rooted and moves?

Similarly when an array backed span of object sis copied to native span.

@omariom

This comment has been minimized.

Show comment
Hide comment
@omariom

omariom Jun 18, 2016

Contributor

@KrzysztofCwalina
Then I think it is worth adding a new constraint to CLR and C# - blittable(or other name). And ability to apply it at members level.
With such constraint we could have Spans of any type but some operations would be only allowed on Spans of types having no references.

Contributor

omariom commented Jun 18, 2016

@KrzysztofCwalina
Then I think it is worth adding a new constraint to CLR and C# - blittable(or other name). And ability to apply it at members level.
With such constraint we could have Spans of any type but some operations would be only allowed on Spans of types having no references.

@jkotas

This comment has been minimized.

Show comment
Hide comment
@jkotas

jkotas Jun 18, 2016

Member

For these kind of operations, I think the blittability should be enforced via a dynamic check if needed, that the JIT can eliminate by treating it as intrinsic; or by Roslyn analyzer. I do not think it makes sense to have first class blittable constrain - it is too much complexity, for the value that it provides.

Also, the casting between different blitable Span types is pretty questionable operation. It has portability problems because of it lets you create misaligned Spans. I do not think it should be in the "safe" Span API set. (Having it in "unsafe" span API set is fine.)

Member

jkotas commented Jun 18, 2016

For these kind of operations, I think the blittability should be enforced via a dynamic check if needed, that the JIT can eliminate by treating it as intrinsic; or by Roslyn analyzer. I do not think it makes sense to have first class blittable constrain - it is too much complexity, for the value that it provides.

Also, the casting between different blitable Span types is pretty questionable operation. It has portability problems because of it lets you create misaligned Spans. I do not think it should be in the "safe" Span API set. (Having it in "unsafe" span API set is fine.)

@jkotas

This comment has been minimized.

Show comment
Hide comment
@jkotas

jkotas Jun 18, 2016

Member
var nativeSpan = new Span(nativeMemory, len);
nativeSpan[0] = new object();
// will GC know that the object is rooted? will it change the native memory when the object is rooted and moves?

When you are doing interop with unmanaged pointers, you have to know what you are doing and you have to get it right. If you do not get it right, your program will crash in a very bad way.

In your example, the GC will not track the native memory and your program will crash in a very bad way. It is no different from if you pass wrong len to Span(void * p, int len) that will crash your program in a very bad way as well.

I know that we have historically tried to prevent some of the bad uses, but I always had mixed feelings about it.

Maybe we should have the dynamic check for blitability in the regular Span(void * p, int len), but also have extension method without any checks in "unsafe" span API set for power-users?

Member

jkotas commented Jun 18, 2016

var nativeSpan = new Span(nativeMemory, len);
nativeSpan[0] = new object();
// will GC know that the object is rooted? will it change the native memory when the object is rooted and moves?

When you are doing interop with unmanaged pointers, you have to know what you are doing and you have to get it right. If you do not get it right, your program will crash in a very bad way.

In your example, the GC will not track the native memory and your program will crash in a very bad way. It is no different from if you pass wrong len to Span(void * p, int len) that will crash your program in a very bad way as well.

I know that we have historically tried to prevent some of the bad uses, but I always had mixed feelings about it.

Maybe we should have the dynamic check for blitability in the regular Span(void * p, int len), but also have extension method without any checks in "unsafe" span API set for power-users?

@nietras

This comment has been minimized.

Show comment
Hide comment
@nietras

nietras Jun 18, 2016

Contributor

I think it would be really good to have a "unsafe" span API set for high perf scenarios. As long as there will be a code path without unnecessary checks in cases where you know what you are doing.

Also I hope it will still be possible to query the span whether it is based on native or managed memory and have access to native pointer or managed array/pinning depending on which memory is used.

Contributor

nietras commented Jun 18, 2016

I think it would be really good to have a "unsafe" span API set for high perf scenarios. As long as there will be a code path without unnecessary checks in cases where you know what you are doing.

Also I hope it will still be possible to query the span whether it is based on native or managed memory and have access to native pointer or managed array/pinning depending on which memory is used.

@omariom

This comment has been minimized.

Show comment
Hide comment
@omariom

omariom Jun 18, 2016

Contributor

@jkotas

If Type had ContainsReferences property treated by JIT as a constant then it would be no-op in the dangerous methods when T is blittable and throw otherwise.

For CoreLab's Span another solution should be found. May be Reflection? Though it will be slow.

Contributor

omariom commented Jun 18, 2016

@jkotas

If Type had ContainsReferences property treated by JIT as a constant then it would be no-op in the dangerous methods when T is blittable and throw otherwise.

For CoreLab's Span another solution should be found. May be Reflection? Though it will be slow.

@nietras

This comment has been minimized.

Show comment
Hide comment
@nietras

nietras Jun 18, 2016

Contributor

For corefx one might use the solution shown here: https://github.com/AndreyAkinshin/BlittableStructs/blob/master/BlittableStructs/BlittableHelper.cs

It is probably pretty slow (haven't benchmarked it) on first call, but should then be fast perhaps even inlineable. The helper is also discussed in a blog post: http://aakinshin.net/en/blog/dotnet/blittable/

Contributor

nietras commented Jun 18, 2016

For corefx one might use the solution shown here: https://github.com/AndreyAkinshin/BlittableStructs/blob/master/BlittableStructs/BlittableHelper.cs

It is probably pretty slow (haven't benchmarked it) on first call, but should then be fast perhaps even inlineable. The helper is also discussed in a blog post: http://aakinshin.net/en/blog/dotnet/blittable/

@nblumhardt

This comment has been minimized.

Show comment
Hide comment
@nblumhardt

nblumhardt Jun 20, 2016

Using ReadOnlySpan<char> as the span type for substrings seems to preclude the addition of a lot of interesting/useful text-specific members (intuitive ToString(), StartsWith(string), etc.). Is there room for a separate StringSpan type for this case?

nblumhardt commented Jun 20, 2016

Using ReadOnlySpan<char> as the span type for substrings seems to preclude the addition of a lot of interesting/useful text-specific members (intuitive ToString(), StartsWith(string), etc.). Is there room for a separate StringSpan type for this case?

@jaredpar

This comment has been minimized.

Show comment
Hide comment
@jaredpar

jaredpar Jun 20, 2016

Member

I do not think it makes sense to have first class blittable constrain - it is too much complexity, for the value that it provides.

The ability to convert from say Span<int> to Span<byte> proved really useful in Midori. It's something I'd love to preserve with CLR as well.

The language already has this exact concept in the spec under the guise unmanaged type. Essentially a struct that transitively contains no reference types. The compiler is already making this check for other scenarios. Why not expose it as a real language feature and generic constraint?

struct Point { int x; int y }
void M<T>() where T : blittable // implies struct
M<Point>() // Okay 
M<object>() // Nope, not blittable 
Member

jaredpar commented Jun 20, 2016

I do not think it makes sense to have first class blittable constrain - it is too much complexity, for the value that it provides.

The ability to convert from say Span<int> to Span<byte> proved really useful in Midori. It's something I'd love to preserve with CLR as well.

The language already has this exact concept in the spec under the guise unmanaged type. Essentially a struct that transitively contains no reference types. The compiler is already making this check for other scenarios. Why not expose it as a real language feature and generic constraint?

struct Point { int x; int y }
void M<T>() where T : blittable // implies struct
M<Point>() // Okay 
M<object>() // Nope, not blittable 
@benaadams

This comment has been minimized.

Show comment
Hide comment
@benaadams

benaadams Jun 21, 2016

Collaborator

The ability to convert from say Span to Span proved really useful in Midori.

Could even have a safe convert where it checks (length * sizeof(T1)) % sizeof(T2) == 0 (might want also an unsafe convert where it doesn't - as may be pre-checking and re-slicing).

You can already have explicit layout overlapping arrays; but the length property gets confused as its based on the instantiation type (which makes sense); but the span approach could have the appropriate length for each sized datatype.

Example use reading from stream/disk/network from byte[] => Vector3[] or saving Vector3[] => byte[]

Collaborator

benaadams commented Jun 21, 2016

The ability to convert from say Span to Span proved really useful in Midori.

Could even have a safe convert where it checks (length * sizeof(T1)) % sizeof(T2) == 0 (might want also an unsafe convert where it doesn't - as may be pre-checking and re-slicing).

You can already have explicit layout overlapping arrays; but the length property gets confused as its based on the instantiation type (which makes sense); but the span approach could have the appropriate length for each sized datatype.

Example use reading from stream/disk/network from byte[] => Vector3[] or saving Vector3[] => byte[]

@KrzysztofCwalina

This comment has been minimized.

Show comment
Hide comment
@KrzysztofCwalina

KrzysztofCwalina Jun 21, 2016

Member

@nblumhardt, the operations you listed could be extension methods over ROS, couldn't they?

Member

KrzysztofCwalina commented Jun 21, 2016

@nblumhardt, the operations you listed could be extension methods over ROS, couldn't they?

@jkotas

This comment has been minimized.

Show comment
Hide comment
@jkotas

jkotas Oct 12, 2017

Member

Updated the milestone to 2.1. We need to go through the list above and make sure that there is nothing major falling through the cracks for Span<T> end-to-end experience for .NET Core 2.1.

cc @ahsonkhan @KrzysztofCwalina @stephentoub @joshfree

Member

jkotas commented Oct 12, 2017

Updated the milestone to 2.1. We need to go through the list above and make sure that there is nothing major falling through the cracks for Span<T> end-to-end experience for .NET Core 2.1.

cc @ahsonkhan @KrzysztofCwalina @stephentoub @joshfree

@joshfree

This comment has been minimized.

Show comment
Hide comment
@joshfree

joshfree Oct 12, 2017

Member

thanks for giving this a nudge @jkotas

Member

joshfree commented Oct 12, 2017

thanks for giving this a nudge @jkotas

@KrzysztofCwalina

This comment has been minimized.

Show comment
Hide comment
@KrzysztofCwalina

KrzysztofCwalina Oct 12, 2017

Member

Besides the VM correctness and stress workitems, I still worry that debug-ability of code using Spans is a pretty big issue. I will turn lots of people off spans.

Member

KrzysztofCwalina commented Oct 12, 2017

Besides the VM correctness and stress workitems, I still worry that debug-ability of code using Spans is a pretty big issue. I will turn lots of people off spans.

@colombod

This comment has been minimized.

Show comment
Hide comment
@colombod

colombod Oct 12, 2017

Member

Why so negative? This api is for scenarios that are not exact everyone’s cup of tea. Don’t see anything bad about the api and design.

Member

colombod commented Oct 12, 2017

Why so negative? This api is for scenarios that are not exact everyone’s cup of tea. Don’t see anything bad about the api and design.

@ahsonkhan

This comment has been minimized.

Show comment
Hide comment
@ahsonkhan

ahsonkhan Oct 17, 2017

Member

Reflection?

Is this work item related to IsReferenceOrContainsReferences?

If so, we already have the implementation of that check in place (here and here). Is there any additional context for this?

Member

ahsonkhan commented Oct 17, 2017

Reflection?

Is this work item related to IsReferenceOrContainsReferences?

If so, we already have the implementation of that check in place (here and here). Is there any additional context for this?

@jkotas

This comment has been minimized.

Show comment
Hide comment
@jkotas

jkotas Oct 17, 2017

Member

It is about calling methods on Span or that take Span arguments via reflection:

  • It is not possible to do it via existing reflection methods. We should have test to verify that e.g. typeof(SpanExtensions).GetMethod("AsReadOnlySpan", new Type[] { typeof(string) }).Invoke(null, new object[] { "Hello" }); fails gracefully.
  • We may want to look into adding new reflection APIs that allow calling these methods via reflection. This does not need to be for 2.1.
Member

jkotas commented Oct 17, 2017

It is about calling methods on Span or that take Span arguments via reflection:

  • It is not possible to do it via existing reflection methods. We should have test to verify that e.g. typeof(SpanExtensions).GetMethod("AsReadOnlySpan", new Type[] { typeof(string) }).Invoke(null, new object[] { "Hello" }); fails gracefully.
  • We may want to look into adding new reflection APIs that allow calling these methods via reflection. This does not need to be for 2.1.
@ahsonkhan

This comment has been minimized.

Show comment
Hide comment
@ahsonkhan

ahsonkhan Mar 4, 2018

Member

Marking "Debugging" and "APIs for working with specialty spans" as complete.

Also "VM - Correctness" and "VM - Stress" are done.

What's left:

  • JIT - Optimizations – apply same sort of optimizations to Span as it does for Strings or Arrays (treat indexers as intrinsics, range check elimination, etc.)
    • Better optimization for CORINFO_HELP_RUNTIMEHANDLE_METHOD #10051
  • Reflection?
  • Marshaler support (as with arrays) #14460
Member

ahsonkhan commented Mar 4, 2018

Marking "Debugging" and "APIs for working with specialty spans" as complete.

Also "VM - Correctness" and "VM - Stress" are done.

What's left:

  • JIT - Optimizations – apply same sort of optimizations to Span as it does for Strings or Arrays (treat indexers as intrinsics, range check elimination, etc.)
    • Better optimization for CORINFO_HELP_RUNTIMEHANDLE_METHOD #10051
  • Reflection?
  • Marshaler support (as with arrays) #14460
@kstewart83

This comment has been minimized.

Show comment
Hide comment
@kstewart83

kstewart83 Mar 4, 2018

What is the possibility of adding a Span/Memory constructor for working with memory mapped files? Currently, it looks like I have to have unsafe code in order to do this:

var dbPath = "test.txt";
var initialSize = 1024;
var mmf = MemoryMappedFile.CreateFromFile(dbPath);
var mma = mmf.CreateViewAccessor(0, initialSize).SafeMemoryMappedViewHandle;
Span<byte> bytes;
unsafe
{
    byte* ptrMemMap = (byte*)0;
    mma.AcquirePointer(ref ptrMemMap);
    bytes = new Span<byte>(ptrMemMap, (int)mma.ByteLength);
}

Also, it seems like I can only create Spans, as there aren't public constructors for Memory that take a pointer (maybe I'm missing the reason for this). But since the view accessors have safe memory handles that implement System.Runtime.InteropServices.SafeBuffer (i.e., they have a pointer and a length)...it seems natural to be able to leverage this for Span/Memory. So what would be nice is something like this:

var dbPath = "test.txt";
var initialSize = 1024;
var mmf = MemoryMappedFile.CreateFromFile(dbPath);
var mma = mmf.CreateViewAccessor(0, initialSize).SafeMemoryMappedViewHandle;
var mem = new Memory(mma);
var span = mem.Span.Slice(0, 512);

I also noticed that the indexer and internal length of Span uses int. With memory mapped files (especially for database scenarios) it is reasonable that the target file will exceed the upper limit for int. I'm not sure about the performance impact of long based indexing or if there is some magic way to have it both ways, but it would be convenient for certain scenarios.

kstewart83 commented Mar 4, 2018

What is the possibility of adding a Span/Memory constructor for working with memory mapped files? Currently, it looks like I have to have unsafe code in order to do this:

var dbPath = "test.txt";
var initialSize = 1024;
var mmf = MemoryMappedFile.CreateFromFile(dbPath);
var mma = mmf.CreateViewAccessor(0, initialSize).SafeMemoryMappedViewHandle;
Span<byte> bytes;
unsafe
{
    byte* ptrMemMap = (byte*)0;
    mma.AcquirePointer(ref ptrMemMap);
    bytes = new Span<byte>(ptrMemMap, (int)mma.ByteLength);
}

Also, it seems like I can only create Spans, as there aren't public constructors for Memory that take a pointer (maybe I'm missing the reason for this). But since the view accessors have safe memory handles that implement System.Runtime.InteropServices.SafeBuffer (i.e., they have a pointer and a length)...it seems natural to be able to leverage this for Span/Memory. So what would be nice is something like this:

var dbPath = "test.txt";
var initialSize = 1024;
var mmf = MemoryMappedFile.CreateFromFile(dbPath);
var mma = mmf.CreateViewAccessor(0, initialSize).SafeMemoryMappedViewHandle;
var mem = new Memory(mma);
var span = mem.Span.Slice(0, 512);

I also noticed that the indexer and internal length of Span uses int. With memory mapped files (especially for database scenarios) it is reasonable that the target file will exceed the upper limit for int. I'm not sure about the performance impact of long based indexing or if there is some magic way to have it both ways, but it would be convenient for certain scenarios.

@jkotas

This comment has been minimized.

Show comment
Hide comment
@jkotas

jkotas Mar 5, 2018

Member

dotnet/corefx#26603 has the discussion about Span & memory mapped files.

Member

jkotas commented Mar 5, 2018

dotnet/corefx#26603 has the discussion about Span & memory mapped files.

@kstewart83

This comment has been minimized.

Show comment
Hide comment
@kstewart83

kstewart83 Mar 5, 2018

Unfortunately, looking at dotnet/corefx#26603 along with the referenced code in the benchmarks didn't clear things up for me. It seems like that particular use case is geared to copying small bits of the memory mapped files into Spans and ReadOnlySegments. It looks like the solution still involves unsafe code with OwnedMemory<T>, which is what I'd like to avoid. I don't have experience with manual memory management in C#, so some of this is a little difficult to grasp. That's what I found appealing about Span/Memory is that I could now access additional performance and reduce/eliminate copying data around without the headache of manual memory management and the issues that come with it. It seems memory mapped files fit into target paradigm of Span/Memory (unifying the APIs around contiguous random access memory), so hopefully some type of integration of memory mapped files and Span/Memory makes it in at some point.

kstewart83 commented Mar 5, 2018

Unfortunately, looking at dotnet/corefx#26603 along with the referenced code in the benchmarks didn't clear things up for me. It seems like that particular use case is geared to copying small bits of the memory mapped files into Spans and ReadOnlySegments. It looks like the solution still involves unsafe code with OwnedMemory<T>, which is what I'd like to avoid. I don't have experience with manual memory management in C#, so some of this is a little difficult to grasp. That's what I found appealing about Span/Memory is that I could now access additional performance and reduce/eliminate copying data around without the headache of manual memory management and the issues that come with it. It seems memory mapped files fit into target paradigm of Span/Memory (unifying the APIs around contiguous random access memory), so hopefully some type of integration of memory mapped files and Span/Memory makes it in at some point.

@davidfowl

This comment has been minimized.

Show comment
Hide comment
@davidfowl

davidfowl Mar 5, 2018

Contributor

@KrzysztofCwalina I think we should create something first class with Memory mapped files and the new buffer primitives (ReadOnlySequence).

@kstewart83 all we have right now are extremely low level primitives that you have to string together to make something work. That specific issue was about the performance gap between using Span directly and using the ReadOnlySequence (the gap has been reduced for that specific scenario).

Dealing with anything bigger than an int you'll need to use ReadOnlySequence<T> which is just a view over a linked list of ReadOnlyMemory<T>.

Contributor

davidfowl commented Mar 5, 2018

@KrzysztofCwalina I think we should create something first class with Memory mapped files and the new buffer primitives (ReadOnlySequence).

@kstewart83 all we have right now are extremely low level primitives that you have to string together to make something work. That specific issue was about the performance gap between using Span directly and using the ReadOnlySequence (the gap has been reduced for that specific scenario).

Dealing with anything bigger than an int you'll need to use ReadOnlySequence<T> which is just a view over a linked list of ReadOnlyMemory<T>.

@ahsonkhan

This comment has been minimized.

Show comment
Hide comment
@ahsonkhan

ahsonkhan Mar 5, 2018

Member

I think we should create something first class with Memory mapped files and the new buffer primitives (ReadOnlySequence).

I have re-opened the dotnet/corefx#26603 issue. Feel free to move the discussion there (See dotnet/corefx#26603 (comment)).

Member

ahsonkhan commented Mar 5, 2018

I think we should create something first class with Memory mapped files and the new buffer primitives (ReadOnlySequence).

I have re-opened the dotnet/corefx#26603 issue. Feel free to move the discussion there (See dotnet/corefx#26603 (comment)).

@RussKeldorph

This comment has been minimized.

Show comment
Hide comment
@RussKeldorph

RussKeldorph Mar 28, 2018

Member

@ahsonkhan Is there more work on this issue for 2.1?

Member

RussKeldorph commented Mar 28, 2018

@ahsonkhan Is there more work on this issue for 2.1?

@ahsonkhan

This comment has been minimized.

Show comment
Hide comment
@ahsonkhan

ahsonkhan Mar 30, 2018

Member

Is there more work on this issue for 2.1?

There is no other work for 2.1.

There are two items left from the original list, but both are marked as future. They can be tracked separately (and outside of 2.1):

  • Marshaler support (as with arrays) #14460
  • Reflection #17296

Closing this issue!

Member

ahsonkhan commented Mar 30, 2018

Is there more work on this issue for 2.1?

There is no other work for 2.1.

There are two items left from the original list, but both are marked as future. They can be tracked separately (and outside of 2.1):

  • Marshaler support (as with arrays) #14460
  • Reflection #17296

Closing this issue!

@ahsonkhan ahsonkhan closed this Mar 30, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment