Closed akamsteeg closed 4 years ago
Old:
Method | Job | Toolchain | breachMode | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
IsPwnedPasswordAsync | Job-TEGKPY | .NET Core 2.1 | ? | 71.118 μs | 1.4146 μs | 3.3893 μs | 71.100 μs | 1.23 | 0.05 | 25.6348 | - | - | 118.14 KB |
IsPwnedPasswordAsync | Job-GJVZXI | .NET Core 3.1 | ? | 55.144 μs | 1.0935 μs | 1.1701 μs | 55.018 μs | 1.00 | 0.00 | 25.2686 | 4.2114 | - | 116.58 KB |
IsPwnedPasswordAsync | Job-VWBFQF | net48 | ? | 103.477 μs | 1.9824 μs | 2.2829 μs | 102.961 μs | 1.88 | 0.05 | 26.6113 | 3.5400 | - | 123.41 KB |
New:
Method | Job | Toolchain | breachMode | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
IsPwnedPasswordAsync | Job-VQTSNE | .NET Core 2.1 | ? | 65.549 μs | 1.2758 μs | 1.1934 μs | 64.890 μs | 1.38 | 0.03 | 14.1602 | 0.9766 | - | 65.59 KB |
IsPwnedPasswordAsync | Job-BHPDQD | .NET Core 3.1 | ? | 47.402 μs | 0.6711 μs | 0.5949 μs | 47.286 μs | 1.00 | 0.00 | 14.1602 | 0.9766 | - | 65.49 KB |
IsPwnedPasswordAsync | Job-MCEJQP | net48 | ? | 151.673 μs | 2.4148 μs | 2.2588 μs | 152.235 μs | 3.20 | 0.07 | 20.7520 | - | - | 96.95 KB |
The performance increase (time) is negligable, but the memory usage on the .NET Core TFMs is only ~60% of what is was. Profit! 🎉
In HaveIBeenPwnedClient.IsPwnedPasswordAsync(), or actually HaveIBeenPwnedClient.IsPwnedPasswordInternalAsync(), we use an excessive amount of memory. We create a
StreamReader
to read the response stream fully into a new string, and then do aContains()
on that.https://github.com/akamsteeg/AtleX.HaveIBeenPwned/blob/e6a9126f745c8776a1afb04b1f48ca02770e2e1b/src/AtleX.HaveIBeenPwned/HaveIBeenPwnedClient.cs#L350..L355
This requires around 110KB of memory for every request.
Suggestion: Skip the stream and
StreamReader
. Just useReadAsStringAsync()
on the response to read directly to a string.