Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

TrayanZapryanov
Copy link
Contributor

Do not allocate byte[] if Encoding.GetMaxByteCount for the string parameter is less than 512 characters.
In this case just encode in stackalloc array.

@ghost ghost added the area-System.Net label May 29, 2024
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label May 29, 2024
Copy link
Contributor

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

@TrayanZapryanov
Copy link
Contributor Author

Benchmark:

[MemoryDiagnoser]
public class HttpUtilityBenchmarks
{
	[Benchmark(Baseline = true)]
	public byte[] UrlEncodeToBytes() => HttpUtility.UrlEncodeToBytes("http://127.0.0.1:8080/app%%Dir/page.aspx?foo=b%%r");

	[Benchmark]
	public byte[] UrlEncodeToBytes_PR() => MyHttpUtility.UrlEncodeToBytes("http://127.0.0.1:8080/app%%Dir/page.aspx?foo=b%%r");
}

Result:

Method Mean Error StdDev Ratio Gen0 Allocated Alloc Ratio
UrlEncodeToBytes 212.1 ns 1.93 ns 1.61 ns 1.00 0.0219 184 B 1.00
UrlEncodeToBytes_PR 206.4 ns 1.68 ns 1.58 ns 0.97 0.0124 104 B 0.57

@EgorBo
Copy link
Member

EgorBo commented May 29, 2024

Please, ignore me, I am just testing my bot 🙂

@EgorBot -arm64 -amd -profiler

using System.Web;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

BenchmarkRunner.Run<HttpUtilityBenchmarks>(args: args);

public class HttpUtilityBenchmarks
{
    [Benchmark(Baseline = true)]
    public byte[] UrlEncodeToBytes() => 
        HttpUtility.UrlEncodeToBytes("http://127.0.0.1:8080/app%%Dir/page.aspx?foo=b%%r");
}

@EgorBot
Copy link

EgorBot commented May 29, 2024

BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
AMD EPYC 7763, 1 CPU, 16 logical and 8 physical cores
  Job-DKBAVF : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX2
  Job-OUKBYD : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX2
Method Toolchain Mean Error Ratio
UrlEncodeToBytes Main 349.5 ns 4.33 ns 1.00
UrlEncodeToBytes PR 294.4 ns 4.77 ns 0.84

BDN_Artifacts.zip

Profiler🔥

Flame graphs: Main vs PR 🔥
Hot asm: Main vs PR
Hot functions: Main vs PR

For clean perf results, make sure you have just one [Benchmark] in your app.

@EgorBot
Copy link

EgorBot commented May 29, 2024

BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Unknown processor
  Job-QWEGHO : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
  Job-AUNLAU : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
Method Toolchain Mean Error Ratio
UrlEncodeToBytes Main 411.6 ns 2.59 ns 1.00
UrlEncodeToBytes PR 358.4 ns 0.62 ns 0.87

BDN_Artifacts.zip

Profiler🔥

Flame graphs: Main vs PR 🔥
Hot asm: Main vs PR
Hot functions: Main vs PR

For clean perf results, make sure you have just one [Benchmark] in your app.

@TrayanZapryanov TrayanZapryanov force-pushed the optimize_httputility_urlencodetobytes branch from d550e79 to da876e9 Compare May 31, 2024 08:16
@TrayanZapryanov
Copy link
Contributor Author

Final benchmark results:

Method Mean Error StdDev Ratio Gen0 Allocated Alloc Ratio
UrlEncodeToBytes 209.05 ns 1.128 ns 0.942 ns 1.00 0.0219 184 B 1.00
UrlEncodeToBytes_PR 86.31 ns 1.668 ns 1.638 ns 0.41 0.0124 104 B 0.57

@TrayanZapryanov
Copy link
Contributor Author

@EgorBot -arm64 -amd -profiler

@EgorBot
Copy link

EgorBot commented May 31, 2024

EgorBot manual
Usage: @EgorBot [-%target%] [-profiler] [raw args for BDN] `C# snippet surrounded with triple ticks`
-%target%:       Can be -arm64, -amd or -intel. Or multiple at once, e.g. '-amd -intel'
                 -intel is used when none of the targets are specified.
-profiler:       Use 'perf record' to collect a flamegraph/hot asm - shouldn't be used 
                 when the given benchmark snippet contains more than one [Benchmark]
                 Disabled by default.
-mono:           Use Mono runtime instead of CoreCLR for all targets. Should be possible to use
                 Mono interp too (LLVM is not supported yet).
                 Mono doesn't support -profiler (at least JIT)
                 To use mono-interp, use BDN args, e.g. --envvars MONO_ENV_OPTIONS:"--interpreter"
                 Disabled by default.
-[args for BDN]: Args directly passed to BDN e.g. '--disasm', see
                 https://github.com/dotnet/BenchmarkDotNet/blob/master/docs/articles/guides/console-args.md

All targets are Linux-only at the moment.
NOTE: BenchmarkRunner.Run or BenchmarkSwitcher.From* can be omitted (snippet without an entrypoint)
Although, if they're presented then Program's args must be be forwarded to Run(args: args)

NOTE: [DisassemblyDiagnoser] may cause unexpected crashes in BDN on Linux (at least on x64)

Usage example: link

@TrayanZapryanov
Copy link
Contributor Author

@EgorBot -arm64 -amd

@EgorBot
Copy link

EgorBot commented May 31, 2024

EgorBot manual
Usage: @EgorBot [-%target%] [-profiler] [raw args for BDN] `C# snippet surrounded with triple ticks`
-%target%:       Can be -arm64, -amd or -intel. Or multiple at once, e.g. '-amd -intel'
                 -intel is used when none of the targets are specified.
-profiler:       Use 'perf record' to collect a flamegraph/hot asm - shouldn't be used 
                 when the given benchmark snippet contains more than one [Benchmark]
                 Disabled by default.
-mono:           Use Mono runtime instead of CoreCLR for all targets. Should be possible to use
                 Mono interp too (LLVM is not supported yet).
                 Mono doesn't support -profiler (at least JIT)
                 To use mono-interp, use BDN args, e.g. --envvars MONO_ENV_OPTIONS:"--interpreter"
                 Disabled by default.
-[args for BDN]: Args directly passed to BDN e.g. '--disasm', see
                 https://github.com/dotnet/BenchmarkDotNet/blob/master/docs/articles/guides/console-args.md

All targets are Linux-only at the moment.
NOTE: BenchmarkRunner.Run or BenchmarkSwitcher.From* can be omitted (snippet without an entrypoint)
Although, if they're presented then Program's args must be be forwarded to Run(args: args)

NOTE: [DisassemblyDiagnoser] may cause unexpected crashes in BDN on Linux (at least on x64)

Usage example: link

@TrayanZapryanov
Copy link
Contributor Author

@EgorBot -arm64 -amd -profiler

using System.Web;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

BenchmarkRunner.Run(args: args);

public class HttpUtilityBenchmarks
{
[Benchmark(Baseline = true)]
public byte[] UrlEncodeToBytes() =>
HttpUtility.UrlEncodeToBytes("http://127.0.0.1:8080/app%%Dir/page.aspx?foo=b%%r");
}

@EgorBot
Copy link

EgorBot commented May 31, 2024

EgorBot manual
Usage: @EgorBot [-%target%] [-profiler] [raw args for BDN] `C# snippet surrounded with triple ticks`
-%target%:       Can be -arm64, -amd or -intel. Or multiple at once, e.g. '-amd -intel'
                 -intel is used when none of the targets are specified.
-profiler:       Use 'perf record' to collect a flamegraph/hot asm - shouldn't be used 
                 when the given benchmark snippet contains more than one [Benchmark]
                 Disabled by default.
-mono:           Use Mono runtime instead of CoreCLR for all targets. Should be possible to use
                 Mono interp too (LLVM is not supported yet).
                 Mono doesn't support -profiler (at least JIT)
                 To use mono-interp, use BDN args, e.g. --envvars MONO_ENV_OPTIONS:"--interpreter"
                 Disabled by default.
-[args for BDN]: Args directly passed to BDN e.g. '--disasm', see
                 https://github.com/dotnet/BenchmarkDotNet/blob/master/docs/articles/guides/console-args.md

All targets are Linux-only at the moment.
NOTE: BenchmarkRunner.Run or BenchmarkSwitcher.From* can be omitted (snippet without an entrypoint)
Although, if they're presented then Program's args must be be forwarded to Run(args: args)

NOTE: [DisassemblyDiagnoser] may cause unexpected crashes in BDN on Linux (at least on x64)

Usage example: link

@TrayanZapryanov
Copy link
Contributor Author

@EgorBot -arm64 -amd -profiler

using System.Web;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

BenchmarkRunner.Run<HttpUtilityBenchmarks>(args: args);

public class HttpUtilityBenchmarks
{
    [Benchmark(Baseline = true)]
    public byte[] UrlEncodeToBytes() => 
        HttpUtility.UrlEncodeToBytes("http://127.0.0.1:8080/app%%Dir/page.aspx?foo=b%%r");
}

@EgorBot
Copy link

EgorBot commented May 31, 2024

Benchmark results on Amd
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
AMD EPYC 7763, 1 CPU, 8 logical and 4 physical cores
  Job-CUYSUK : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX2
  Job-JSZBQA : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX2
Method Toolchain Mean Error Ratio
UrlEncodeToBytes Main 340.1 ns 1.08 ns 1.00
UrlEncodeToBytes PR 132.4 ns 0.41 ns 0.39

BDN_Artifacts.zip

Flame graphs: Main vs PR 🔥
Hot asm: Main vs PR
Hot functions: Main vs PR

For clean perf results, make sure you have just one [Benchmark] in your app.

@EgorBot
Copy link

EgorBot commented May 31, 2024

Benchmark results on Arm64
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Unknown processor
  Job-VMBDUG : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
  Job-YJLOWM : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
Method Toolchain Mean Error Ratio
UrlEncodeToBytes Main 415.5 ns 0.60 ns 1.00
UrlEncodeToBytes PR 218.0 ns 0.41 ns 0.52

BDN_Artifacts.zip

Flame graphs: Main vs PR 🔥
Hot asm: Main vs PR
Hot functions: Main vs PR

For clean perf results, make sure you have just one [Benchmark] in your app.

Copy link
Member

@MihaZupan MihaZupan left a comment

Choose a reason for hiding this comment

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

Thanks

@MihaZupan MihaZupan added this to the 9.0.0 milestone May 31, 2024
@MihaZupan MihaZupan merged commit e730d83 into dotnet:main Jun 3, 2024
@TrayanZapryanov TrayanZapryanov deleted the optimize_httputility_urlencodetobytes branch June 4, 2024 11:38
@github-actions github-actions bot locked and limited conversation to collaborators Jul 5, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Net community-contribution Indicates that the PR has been added by a community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants