Updated Span API : NonPortableCast and AsReadOnlySpan to MemoryMarshal.Cast and AsSpan

One of the interesting changes (not sure why Microsoft changed this) was moving/changing the Span<T> API’s a bit. For example, the Span<T>.NonPortableCast Method was moved as an extension method under MemoryMarshal.

Previous API

Span<byte> byteSpan = BitConverter.GetBytes(originalPrimitiveType);
Span<int> intSpan = byteSpan.NonPortableCast<byte, int>();

Current API

Span<byte> byteSpan = BitConverter.GetBytes(originalPrimitiveType);
Span<int> intSpan = MemoryMarshal.Cast<byte, int>(byteSpan);

Similarly, the string.AsReadonlySpan method has been renamed. The new API is as follows.

Previous API

ReadOnlySpan<char> keyString = "SomeText".AsReadOnlySpan();

Current API

ReadOnlySpan<char> keyString = "SomeText".AsSpan();

The MemoryMarshal extensions can be found under the System.Runtime.InteropServices namespace. Code discussed in my earlier post about Benchmarking Span has been updated in my Github.

Type Casting using Span<T>

In an earlier post, we explored the possibilities of Span and performance benefits of the feature was clearly visible in our benchmark tests. We will continue exploring the Span further in this post, as attempt to cast between types using Span.

The cast functionality is not that hard, thanks to the extension methods that comes along with Span<byte> under the System.MemoryExtensions namespace. The NonPortableCast method converts a Span<byte> to the specified Type.  As seen in the code below, the first step however is to convert the original type to a byte array. The implicit conversion between byte array and Span<byte> would allow you to convert it to Span<byte>.

 

long originalPrimitiveType = 25;
Span byteSpan = BitConverter.GetBytes(originalPrimitiveType);
Span intSpan = byteSpan.NonPortableCast();
int castPrimitiveType = intSpan[0];
The key point to note here is the first 4 bytes of Span<byte> maps to the zeroth element of Span<int>. The code samples described in this post is available in my Github.

Benchmarking Span<T> Performance

Span<T> is yet another addition to C# 7.x and is particularly useful in developing memory intensive applications.  So what is Span all about ?

 

As Microsoft describes it, Span<T> is a new value Type which enables the representation of contiguous regions of arbitrary memory, regardless of whether the memory is associated with a managed object, is provided by native code  or is on the stack, with a performance characteristics like that of an array.

 

It feels like you can use pointers, but without entering ‘unsafe’ code. That definitely is interesting. We will be looking into Span<T> closely in upcoming posts, but for this post, we will compare Span with Strings when parsing sub strings.  We will begin by how sub strings work. We will keep it simple for sake of the example. Consider the following code.
public void DummyMethod(string data) { }

string keyString = "234567";
DummyMethod(keyString.Substring(0, 2));
DummyMethod(keyString.Substring(2, 2));
DummyMethod(keyString.Substring(4, 2));

Remember string is immutable, and each time we are invoking the Substring method, we are allocating a new memory location is allocated with the substring. Now that isn’t a scenario you wouldn’t want to be if you are working on a memory intensive application and you want to parse a really long string. But what is we could parse the string right from the memory location allocated for keyString. That would be extremely efficient right ?

That’s where Span<T> comes in. It would allow us to point to a contiguous region of memory, and allow us to parse through it without needing a different memory allocation. Let’s rewrite the above code using Span<T>.

public void DummyMethod(ReadOnlySpan data) { }

ReadOnlySpan keyString = "234567".AsReadOnlySpan();
DummyMethod(keyString.Slice(0, 2));
DummyMethod(keyString.Slice(2, 2));
DummyMethod(keyString.Slice(4, 2));

Notice that the string has a nice little extension method to create a ReadOnlySpan. We are also using the Slice method (instead of Substring) to access the specific part of memory location. We will do a bit of bench marking to understand the performance implication. Let’s create a BenchmarkDemo Class for our demonstrative purpose. Complete source code is available at my Github.

[Benchmark]
public void UsingSubString()
{
    string keyString = "long string";
    for (int i = 0; i < IterationLimit; i++)
        DummyStringMethod(keyString.Substring(0, i));
}
void DummyStringMethod(string _) { }

[Benchmark]
public void UsingSpan()
{
    ReadOnlySpan keyString = "long string".AsReadOnlySpan();
    for (int i = 0; i < IterationLimit; i++)
        DummySpanMethod(keyString.Slice(0, i));
}

void DummySpanMethod(ReadOnlySpan _) { }

The above code is for demonstrative purpose, hence we are using a dummy string "long string". In the example in Github, you can find the same replaced with lorem ipsum.

Alright, now lets run the Benchmark code and analyse the memory allocation against iteration loops of 10,100, and 400. We are using BenchmarkDotNet for example.

Benchmark Span

As you can see the “UsingSubString” method uses a huge amount of memory as the calls to substring increases. On other hand, Span based method hardly uses any and doesn’t have any different as the number of calls increases.

That’s it for now, we will investigate more on Span<T> in upcoming posts.