Skip to content
This repository was archived by the owner on Aug 2, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions samples/LowAllocationWebServer/Shared/SampleServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ static void WriteResponseForGetJson(HttpRequest request, ReadOnlySequence<byte>
response.AppendEoh();

// write response JSON
var jsonWriter = new JsonWriter(response, true, prettyPrint: false);
JsonWriterUtf8 jsonWriter = JsonWriter.CreateUtf8(response, prettyPrint: false);
jsonWriter.WriteObjectStart();
jsonWriter.WriteArrayStart("values");
for (int i = 0; i < 5; i++)
Expand Down Expand Up @@ -94,7 +94,7 @@ static void WriteResponseForPostJson(HttpRequest request, ReadOnlySequence<byte>
response.AppendEoh();

// write response JSON
var jsonWriter = new JsonWriter(response, true, prettyPrint: false);
JsonWriterUtf8 jsonWriter = JsonWriter.CreateUtf8(response, prettyPrint: false);
jsonWriter.WriteObjectStart();
jsonWriter.WriteArrayStart("values");
for (int i = 0; i < requestedCount; i++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Buffers.Reader
{
[StructLayout(LayoutKind.Auto)]
public ref struct BufferReader
{
private SequencePosition _currentSequencePosition;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

using System.Buffers.Text;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Buffers.Writer
{
[StructLayout(LayoutKind.Auto)]
public ref partial struct BufferWriter
{
private Span<byte> _buffer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,29 @@
// See the LICENSE file in the project root for more information.

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;

namespace System.Buffers.Writer
{
[StructLayout(LayoutKind.Auto)]
public ref partial struct BufferWriter<T> where T : IBufferWriter<byte>
{
private T _output;
private Span<byte> _span;
private int _buffered;

private static readonly byte[] s_newLine = new byte[] { (byte)'\r', (byte)'\n' };
private static readonly byte[] s_newLine = Encoding.UTF8.GetBytes(Environment.NewLine);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferWriter(T output)
{
_buffered = 0;
_output = output;
_span = output.GetSpan();
NewLine = s_newLine;
}

public ReadOnlySpan<byte> NewLine { get; set; }
private static ReadOnlySpan<byte> NewLine => new ReadOnlySpan<byte>(s_newLine);

public Span<byte> Buffer => _span;

Expand Down Expand Up @@ -56,12 +59,7 @@ public void Ensure(int count = 1)
[MethodImpl(MethodImplOptions.NoInlining)]
private void EnsureMore(int count = 0)
{
var buffered = _buffered;
if (buffered > 0)
{
_buffered = 0;
_output.Advance(buffered);
}
Flush();
_span = _output.GetSpan(count);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ public void WriteLine(string value)
Write(NewLine);
}

public void WriteLine(string value, ReadOnlySpan<byte> newLine)
{
Write(value);
Write(newLine);
}

//public void WriteLine(string value, TransformationFormat format);

public void Write(Utf8String value) => Write(value.Bytes);
Expand All @@ -56,6 +62,12 @@ public void WriteLine(Utf8String value)
Write(NewLine);
}

public void WriteLine(Utf8String value, ReadOnlySpan<byte> newLine)
{
Write(value.Bytes);
Write(newLine);
}

//public void WriteLine(Utf8String value, TransformationFormat format);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

using System.Buffers.Operations;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Buffers.Writer
{
[StructLayout(LayoutKind.Auto)]
public readonly struct TransformationFormat
{
private readonly IBufferTransformation _first;
Expand Down
3 changes: 3 additions & 0 deletions src/System.Text.JsonLab/System.Text.JsonLab.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
<PackageTags>.NET json non-allocating corefxlab</PackageTags>
<PackageIconUrl>http://go.microsoft.com/fwlink/?linkid=833199</PackageIconUrl>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<DebugType>pdbonly</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<Compile Include="System\**\*.cs" Exclude="experiments\**\*.cs;bin\**;obj\**;**\*.xproj;packages\**" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\System.Text.Formatting\System.Text.Formatting.csproj" />
<ProjectReference Include="..\System.Buffers.ReaderWriter\System.Buffers.ReaderWriter.csproj" />
</ItemGroup>
</Project>
2 changes: 2 additions & 0 deletions src/System.Text.JsonLab/System/Text/Json/JsonParseObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
using System.Buffers;
using System.Buffers.Text;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text.Utf8;

using static System.Buffers.Binary.BinaryPrimitives;
using static System.Runtime.InteropServices.MemoryMarshal;

namespace System.Text.JsonLab
{
[StructLayout(LayoutKind.Auto)]
public ref struct JsonObject
{
private MemoryPool<byte> _pool;
Expand Down
2 changes: 2 additions & 0 deletions src/System.Text.JsonLab/System/Text/Json/JsonParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ static DbRow()
}
}

[StructLayout(LayoutKind.Auto)]
internal ref struct TwoStacks
{
Span<byte> _span;
Expand Down Expand Up @@ -112,6 +113,7 @@ internal void Resize(Span<byte> newStackMemory)
}
}

[StructLayout(LayoutKind.Auto)]
internal ref struct JsonParser
{
private Span<byte> _db;
Expand Down
2 changes: 2 additions & 0 deletions src/System.Text.JsonLab/System/Text/Json/JsonReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

namespace System.Text.JsonLab
{

[StructLayout(LayoutKind.Auto)]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What is the benefit of adding this attribute?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Rearranges and packs the fields in the most efficient layout; rather than the order you define them (except child structs, which are on pointer boundaries).

I'd always assumed it was the default layout as it is for classes; and you had to specify [StructLayout(LayoutKind.Sequential)] if you wanted that but seem to not always be the case https://blogs.msdn.microsoft.com/seteplia/2017/09/21/managed-object-internals-part-4-fields-layout/

Not sure it would make much difference; due to the object reference (forces Auto); but was trying to find where the drop was (think its now the issue I opened)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I haven't observed any difference in benchmarks when marking the struct layout as auto versus leaving it as default.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah, from the article it seems if there is a GC ref then it will switch to auto; and I think a Span or ArrayFormatter will count as that, so it shouldn't make any difference. Was just hoping...

public ref struct JsonReader
{
// We are using a ulong to represent our nested state, so we can only go 64 levels deep.
Expand Down
11 changes: 11 additions & 0 deletions src/System.Text.JsonLab/System/Text/Json/JsonThrowHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ private static ArgumentException GetArgumentException(string message)
return new ArgumentException(message);
}

public static void ThrowArgumentExceptionInvalidUtf8String()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why is this beneficial? Isn't ThrowArgumentException(string message) good enough?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The il and asm are larger as it has to load the string reference before calling the Throw helper

Via String

G_M53912_IG05:
       48B9683016EFC1010000 mov      rcx, 0x1C1EF163068
       488B09               mov      rcx, gword ptr [rcx]
       E81FFCFFFF           call     JsonThrowHelper:ThrowArgumentException(ref)
       CC                   int3   

Via Enum is smaller as its just passing a numeric const

G_M12337_IG05:
       33C9                 xor      ecx, ecx
       E8F2FBFFFF           call     JsonThrowHelper:ThrowArgumentException(int)
       CC                   int3     

No Params is just a call

G_M36770_IG05:
       E8D4FBFFFF           call     JsonThrowHelper:ThrowArgumentExceptionInvalidUtf8String()
       CC                   int3   

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

e.g. if you are inlining it all over the place, or duplicating it due to generics, better to be smaller

{
throw GetArgumentExceptionInvalidUtf8String();
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static ArgumentException GetArgumentExceptionInvalidUtf8String()
{
return new ArgumentException("Invalid or incomplete UTF-8 string");
}

public static void ThrowFormatException()
{
throw GetFormatException();
Expand Down
Loading