Perf - enumerate with struct

Conflicts:
	src/Microsoft.AspNet.Server.Kestrel/project.json
This commit is contained in:
Louis DeJardin 2015-07-16 21:57:33 -07:00 committed by Stephen Halter
parent ad089be477
commit 96b03ee212
7 changed files with 7024 additions and 57 deletions

View File

@ -10,9 +10,9 @@ namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode
// To enable this option, right-click on the project and select the Properties menu item. In the Build tab select "Produce outputs on build". // To enable this option, right-click on the project and select the Properties menu item. In the Build tab select "Produce outputs on build".
public class KnownHeaders : ICompileModule public class KnownHeaders : ICompileModule
{ {
string Each<T>(IEnumerable<T> values, Func<T, string> formatter) static string Each<T>(IEnumerable<T> values, Func<T, string> formatter)
{ {
return values.Select(formatter).Aggregate((a, b) => a + b + "\r\n"); return values.Select(formatter).Aggregate((a, b) => a + b);
} }
class KnownHeader class KnownHeader
@ -26,6 +26,12 @@ namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode
} }
public virtual void BeforeCompile(BeforeCompileContext context) public virtual void BeforeCompile(BeforeCompileContext context)
{
var syntaxTree = Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(GeneratedFile());
context.Compilation = context.Compilation.AddSyntaxTrees(syntaxTree);
}
public static string GeneratedFile()
{ {
var commonHeaders = new[] var commonHeaders = new[]
{ {
@ -71,7 +77,7 @@ namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode
"Referer", "Referer",
"Range", "Range",
"TE", "TE",
"Translage", "Translate",
"User-Agent", "User-Agent",
}).Select((header, index) => new KnownHeader }).Select((header, index) => new KnownHeader
{ {
@ -113,7 +119,7 @@ namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode
} }
}; };
var syntaxTree = Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText($@" return $@"
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -122,11 +128,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
public partial class {loop.ClassName} public partial class {loop.ClassName}
{{ {{
long _bits = 0; long _bits = 0;
{Each(loop.Headers, header => "string[] _" + header.Identifier + ";")} {Each(loop.Headers, header => @"
string[] _" + header.Identifier + ";")}
protected override int GetCountFast() protected override int GetCountFast()
{{ {{
var count = Unknown.Count; var count = MaybeUnknown?.Count ?? 0;
{Each(loop.Headers, header => $@" {Each(loop.Headers, header => $@"
if ({header.TestBit()}) if ({header.TestBit()})
{{ {{
@ -142,7 +149,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{{{Each(loop.HeadersByLength, byLength => $@" {{{Each(loop.HeadersByLength, byLength => $@"
case {byLength.Key}: case {byLength.Key}:
{{{Each(byLength, header => $@" {{{Each(byLength, header => $@"
if (0 == StringComparer.OrdinalIgnoreCase.Compare(key, ""{header.Name}"")) if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase))
{{ {{
if ({header.TestBit()}) if ({header.TestBit()})
{{ {{
@ -156,7 +163,11 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
")}}} ")}}}
break; break;
")}}} ")}}}
return Unknown[key]; if (MaybeUnknown == null)
{{
throw new System.Collections.Generic.KeyNotFoundException();
}}
return MaybeUnknown[key];
}} }}
protected override bool TryGetValueFast(string key, out string[] value) protected override bool TryGetValueFast(string key, out string[] value)
@ -165,7 +176,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{{{Each(loop.HeadersByLength, byLength => $@" {{{Each(loop.HeadersByLength, byLength => $@"
case {byLength.Key}: case {byLength.Key}:
{{{Each(byLength, header => $@" {{{Each(byLength, header => $@"
if (0 == StringComparer.OrdinalIgnoreCase.Compare(key, ""{header.Name}"")) if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase))
{{ {{
if ({header.TestBit()}) if ({header.TestBit()})
{{ {{
@ -181,7 +192,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
")}}} ")}}}
break; break;
")}}} ")}}}
return Unknown.TryGetValue(key, out value); value = null;
return MaybeUnknown?.TryGetValue(key, out value) ?? false;
}} }}
protected override void SetValueFast(string key, string[] value) protected override void SetValueFast(string key, string[] value)
@ -190,7 +202,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{{{Each(loop.HeadersByLength, byLength => $@" {{{Each(loop.HeadersByLength, byLength => $@"
case {byLength.Key}: case {byLength.Key}:
{{{Each(byLength, header => $@" {{{Each(byLength, header => $@"
if (0 == StringComparer.OrdinalIgnoreCase.Compare(key, ""{header.Name}"")) if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase))
{{ {{
{header.SetBit()}; {header.SetBit()};
_{header.Identifier} = value; _{header.Identifier} = value;
@ -208,7 +220,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{{{Each(loop.HeadersByLength, byLength => $@" {{{Each(loop.HeadersByLength, byLength => $@"
case {byLength.Key}: case {byLength.Key}:
{{{Each(byLength, header => $@" {{{Each(byLength, header => $@"
if (0 == StringComparer.OrdinalIgnoreCase.Compare(key, ""{header.Name}"")) if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase))
{{ {{
if ({header.TestBit()}) if ({header.TestBit()})
{{ {{
@ -230,7 +242,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{{{Each(loop.HeadersByLength, byLength => $@" {{{Each(loop.HeadersByLength, byLength => $@"
case {byLength.Key}: case {byLength.Key}:
{{{Each(byLength, header => $@" {{{Each(byLength, header => $@"
if (0 == StringComparer.OrdinalIgnoreCase.Compare(key, ""{header.Name}"")) if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase))
{{ {{
if ({header.TestBit()}) if ({header.TestBit()})
{{ {{
@ -245,13 +257,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
")}}} ")}}}
break; break;
")}}} ")}}}
return Unknown.Remove(key); return MaybeUnknown?.Remove(key) ?? false;
}} }}
protected override void ClearFast() protected override void ClearFast()
{{ {{
_bits = 0; _bits = 0;
Unknown.Clear(); MaybeUnknown?.Clear();
}} }}
protected override void CopyToFast(KeyValuePair<string, string[]>[] array, int arrayIndex) protected override void CopyToFast(KeyValuePair<string, string[]>[] array, int arrayIndex)
@ -273,27 +285,44 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
++arrayIndex; ++arrayIndex;
}} }}
")} ")}
((ICollection<KeyValuePair<string, string[]>>)Unknown).CopyTo(array, arrayIndex); ((ICollection<KeyValuePair<string, string[]>>)MaybeUnknown)?.CopyTo(array, arrayIndex);
}} }}
protected override IEnumerable<KeyValuePair<string, string[]>> EnumerateFast() public partial struct Enumerator
{{ {{
{Each(loop.Headers, header => $@" public bool MoveNext()
if ({header.TestBit()})
{{
yield return new KeyValuePair<string, string[]>(""{header.Name}"", _{header.Identifier});
}}
")}
foreach(var kv in Unknown)
{{ {{
yield return kv; switch (_state)
{{
{Each(loop.Headers, header => $@"
case {header.Index}:
goto state{header.Index};
")}
default:
goto state_default;
}}
{Each(loop.Headers, header => $@"
state{header.Index}:
if ({header.TestBit()})
{{
_current = new KeyValuePair<string, string[]>(""{header.Name}"", _collection._{header.Identifier});
_state = {header.Index + 1};
return true;
}}
")}
state_default:
if (!_hasUnknown || !_unknownEnumerator.MoveNext())
{{
_current = default(KeyValuePair<string, string[]>);
return false;
}}
_current = _unknownEnumerator.Current;
return true;
}} }}
}} }}
}} }}
")}}} ")}}}
"); ";
context.Compilation = context.Compilation.AddSyntaxTrees(syntaxTree);
} }
public virtual void AfterCompile(AfterCompileContext context) public virtual void AfterCompile(AfterCompileContext context)

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode
{
public class Program
{
public int Main(string[] args)
{
var text = KnownHeaders.GeneratedFile();
if (args.Length == 1)
{
var existing = File.Exists(args[0]) ? File.ReadAllText(args[0]) : "";
if (!string.Equals(text, existing))
{
File.WriteAllText(args[0], text);
}
}
else
{
Console.WriteLine(text);
}
return 0;
}
}
}

View File

@ -27,6 +27,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
private bool _resultStarted; private bool _resultStarted;
private bool _responseStarted; private bool _responseStarted;
private bool _keepAlive; private bool _keepAlive;
private readonly FrameRequestHeaders _requestHeaders = new FrameRequestHeaders();
private readonly FrameResponseHeaders _responseHeaders = new FrameResponseHeaders();
/* /*
//IDictionary<string, object> _environment; //IDictionary<string, object> _environment;
@ -43,8 +45,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
FrameControl = this; FrameControl = this;
StatusCode = 200; StatusCode = 200;
RequestHeaders = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase); RequestHeaders = _requestHeaders;
ResponseHeaders = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase); ResponseHeaders = _responseHeaders;
} }
public string Method { get; set; } public string Method { get; set; }

File diff suppressed because it is too large Load Diff

View File

@ -5,17 +5,11 @@ using System.Linq;
namespace Microsoft.AspNet.Server.Kestrel.Http namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
public partial class FrameRequestHeaders : FrameHeaders
{
}
public partial class FrameResponseHeaders : FrameHeaders
{
}
public abstract class FrameHeaders : IDictionary<string, string[]> public abstract class FrameHeaders : IDictionary<string, string[]>
{ {
protected Dictionary<string, string[]> Unknown = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase); protected Dictionary<string, string[]> MaybeUnknown;
protected Dictionary<string, string[]> Unknown => MaybeUnknown ?? (MaybeUnknown = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase));
protected virtual int GetCountFast() protected virtual int GetCountFast()
{ throw new NotImplementedException(); } { throw new NotImplementedException(); }
@ -41,7 +35,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
protected virtual void CopyToFast(KeyValuePair<string, string[]>[] array, int arrayIndex) protected virtual void CopyToFast(KeyValuePair<string, string[]>[] array, int arrayIndex)
{ throw new NotImplementedException(); } { throw new NotImplementedException(); }
protected virtual IEnumerable<KeyValuePair<string, string[]>> EnumerateFast() protected virtual IEnumerator<KeyValuePair<string, string[]>> GetEnumeratorFast()
{ throw new NotImplementedException(); } { throw new NotImplementedException(); }
@ -62,9 +56,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
bool ICollection<KeyValuePair<string, string[]>>.IsReadOnly => false; bool ICollection<KeyValuePair<string, string[]>>.IsReadOnly => false;
ICollection<string> IDictionary<string, string[]>.Keys => EnumerateFast().Select(x => x.Key).ToList(); ICollection<string> IDictionary<string, string[]>.Keys => ((IDictionary<string,string[]>)this).Select(x => x.Key).ToList();
ICollection<string[]> IDictionary<string, string[]>.Values => EnumerateFast().Select(x => x.Value).ToList(); ICollection<string[]> IDictionary<string, string[]>.Values => ((IDictionary<string, string[]>)this).Select(x => x.Value).ToList();
void ICollection<KeyValuePair<string, string[]>>.Add(KeyValuePair<string, string[]> item) void ICollection<KeyValuePair<string, string[]>>.Add(KeyValuePair<string, string[]> item)
{ {
@ -102,12 +96,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator()
{ {
return EnumerateFast().GetEnumerator(); return GetEnumeratorFast();
} }
IEnumerator<KeyValuePair<string, string[]>> IEnumerable<KeyValuePair<string, string[]>>.GetEnumerator() IEnumerator<KeyValuePair<string, string[]>> IEnumerable<KeyValuePair<string, string[]>>.GetEnumerator()
{ {
return EnumerateFast().GetEnumerator(); return GetEnumeratorFast();
} }
bool ICollection<KeyValuePair<string, string[]>>.Remove(KeyValuePair<string, string[]> item) bool ICollection<KeyValuePair<string, string[]>>.Remove(KeyValuePair<string, string[]> item)
@ -129,4 +123,100 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
return TryGetValueFast(key, out value); return TryGetValueFast(key, out value);
} }
} }
public partial class FrameRequestHeaders : FrameHeaders
{
public Enumerator GetEnumerator()
{
return new Enumerator(this);
}
protected override IEnumerator<KeyValuePair<string, string[]>> GetEnumeratorFast()
{
return GetEnumerator();
}
public partial struct Enumerator : IEnumerator<KeyValuePair<string, string[]>>
{
FrameRequestHeaders _collection;
long _bits;
int _state;
KeyValuePair<string, string[]> _current;
bool _hasUnknown;
Dictionary<string, string[]>.Enumerator _unknownEnumerator;
internal Enumerator(FrameRequestHeaders collection)
{
_collection = collection;
_bits = collection._bits;
_state = 0;
_current = default(KeyValuePair<string, string[]>);
_hasUnknown = collection.MaybeUnknown != null;
_unknownEnumerator = _hasUnknown
? collection.MaybeUnknown.GetEnumerator()
: default(Dictionary<string, string[]>.Enumerator);
}
public KeyValuePair<string, string[]> Current => _current;
object IEnumerator.Current => _current;
public void Dispose()
{
}
public void Reset()
{
_state = 0;
}
}
}
public partial class FrameResponseHeaders : FrameHeaders
{
public Enumerator GetEnumerator()
{
return new Enumerator(this);
}
protected override IEnumerator<KeyValuePair<string, string[]>> GetEnumeratorFast()
{
return GetEnumerator();
}
public partial struct Enumerator : IEnumerator<KeyValuePair<string, string[]>>
{
FrameResponseHeaders _collection;
long _bits;
int _state;
KeyValuePair<string, string[]> _current;
bool _hasUnknown;
Dictionary<string, string[]>.Enumerator _unknownEnumerator;
internal Enumerator(FrameResponseHeaders collection)
{
_collection = collection;
_bits = collection._bits;
_state = 0;
_current = default(KeyValuePair<string, string[]>);
_hasUnknown = collection.MaybeUnknown != null;
_unknownEnumerator = _hasUnknown
? collection.MaybeUnknown.GetEnumerator()
: default(Dictionary<string, string[]>.Enumerator);
}
public KeyValuePair<string, string[]> Current => _current;
object IEnumerator.Current => _current;
public void Dispose()
{
}
public void Reset()
{
_state = 0;
}
}
}
} }

View File

@ -1,11 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Server.Kestrel
{
public class KnownHeaders : Microsoft.AspNet.Server.Kestrel.GeneratedCode.KnownHeaders
{
}
}

View File

@ -6,8 +6,7 @@
"url": "git://github.com/aspnet/kestrelhttpserver" "url": "git://github.com/aspnet/kestrelhttpserver"
}, },
"dependencies": { "dependencies": {
"Microsoft.Dnx.Runtime.Abstractions": "1.0.0-beta7-*", "Microsoft.Dnx.Runtime.Abstractions": "1.0.0-beta7-*"
"Microsoft.AspNet.Server.Kestrel.GeneratedCode": { "version": "1.0.0-*", "type": "build" }
}, },
"frameworks": { "frameworks": {
"dnx451": { }, "dnx451": { },
@ -33,5 +32,8 @@
}, },
"compilationOptions": { "compilationOptions": {
"allowUnsafe": true "allowUnsafe": true
},
"scripts": {
"prepare": "dnx ../Microsoft.AspNet.Server.Kestrel.GeneratedCode run Http/FrameHeaders.Generated.cs"
} }
} }