From 022e79cf172acda54b0b712527414d6152d677a8 Mon Sep 17 00:00:00 2001 From: BrennanConroy Date: Thu, 11 Apr 2019 22:29:23 -0700 Subject: [PATCH] Improve HeaderSplit perf (#9309) --- .../src/Internal/ParsingHelpers.cs | 10 +-- src/Http/perf/Microbenchmarks/AssemblyInfo.cs | 1 + .../GetHeaderSplitBenchmark.cs | 63 +++++++++++++++++++ ...oft.AspNetCore.Http.Microbenchmarks.csproj | 14 +++++ 4 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 src/Http/perf/Microbenchmarks/AssemblyInfo.cs create mode 100644 src/Http/perf/Microbenchmarks/GetHeaderSplitBenchmark.cs create mode 100644 src/Http/perf/Microbenchmarks/Microsoft.AspNetCore.Http.Microbenchmarks.csproj diff --git a/src/Http/Http.Abstractions/src/Internal/ParsingHelpers.cs b/src/Http/Http.Abstractions/src/Internal/ParsingHelpers.cs index 971447fa44..60c3197e3c 100644 --- a/src/Http/Http.Abstractions/src/Internal/ParsingHelpers.cs +++ b/src/Http/Http.Abstractions/src/Internal/ParsingHelpers.cs @@ -19,11 +19,9 @@ namespace Microsoft.AspNetCore.Http.Internal public static StringValues GetHeaderSplit(IHeaderDictionary headers, string key) { var values = GetHeaderUnmodified(headers, key); - return new StringValues(GetHeaderSplitImplementation(values).ToArray()); - } - private static IEnumerable GetHeaderSplitImplementation(StringValues values) - { + StringValues result = default; + foreach (var segment in new HeaderSegmentCollection(values)) { if (!StringSegment.IsNullOrEmpty(segment.Data)) @@ -31,10 +29,12 @@ namespace Microsoft.AspNetCore.Http.Internal var value = DeQuote(segment.Data.Value); if (!string.IsNullOrEmpty(value)) { - yield return value; + result = StringValues.Concat(in result, value); } } } + + return result; } public static StringValues GetHeaderUnmodified(IHeaderDictionary headers, string key) diff --git a/src/Http/perf/Microbenchmarks/AssemblyInfo.cs b/src/Http/perf/Microbenchmarks/AssemblyInfo.cs new file mode 100644 index 0000000000..32248e0d1b --- /dev/null +++ b/src/Http/perf/Microbenchmarks/AssemblyInfo.cs @@ -0,0 +1 @@ +[assembly: BenchmarkDotNet.Attributes.AspNetCoreBenchmark] diff --git a/src/Http/perf/Microbenchmarks/GetHeaderSplitBenchmark.cs b/src/Http/perf/Microbenchmarks/GetHeaderSplitBenchmark.cs new file mode 100644 index 0000000000..9105b5c448 --- /dev/null +++ b/src/Http/perf/Microbenchmarks/GetHeaderSplitBenchmark.cs @@ -0,0 +1,63 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Configs; +using Microsoft.AspNetCore.Http.Internal; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; + +namespace Microsoft.AspNetCore.Http.Abstractions.Microbenchmarks +{ + public class GetHeaderSplitBenchmark + { + HeaderDictionary _dictionary; + + [GlobalSetup] + public void GlobalSetup() + { + var dict = new Dictionary() + { + { "singleValue", new StringValues("single") }, + { "singleValueQuoted", new StringValues("\"single\"") }, + { "doubleValue", new StringValues(new [] { "first", "second" }) }, + { "manyValue", new StringValues(new [] { "first", "second", "third", "fourth", "fifth", "sixth" }) } + }; + _dictionary = new HeaderDictionary(dict); + } + + [Benchmark] + public void SplitSingleHeader() + { + var values = ParsingHelpers.GetHeaderSplit(_dictionary, "singleValue"); + if (values.Count != 1) + throw new Exception(); + } + + [Benchmark] + public void SplitSingleQuotedHeader() + { + var values = ParsingHelpers.GetHeaderSplit(_dictionary, "singleValueQuoted"); + if (values.Count != 1) + throw new Exception(); + } + + [Benchmark] + public void SplitDoubleHeader() + { + var values = ParsingHelpers.GetHeaderSplit(_dictionary, "doubleValue"); + if (values.Count != 2) + throw new Exception(); + } + + [Benchmark] + public void SplitManyHeaders() + { + var values = ParsingHelpers.GetHeaderSplit(_dictionary, "manyValue"); + if (values.Count != 6) + throw new Exception(); + } + } +} diff --git a/src/Http/perf/Microbenchmarks/Microsoft.AspNetCore.Http.Microbenchmarks.csproj b/src/Http/perf/Microbenchmarks/Microsoft.AspNetCore.Http.Microbenchmarks.csproj new file mode 100644 index 0000000000..7a31f1da5b --- /dev/null +++ b/src/Http/perf/Microbenchmarks/Microsoft.AspNetCore.Http.Microbenchmarks.csproj @@ -0,0 +1,14 @@ + + + + Exe + netcoreapp3.0 + + + + + + + + +