Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.NET 10 P1 -- Runtime and Libraries changes #9715

Open
wants to merge 25 commits into
base: dotnet10p1
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b18f5e8
Create runtime branch
richlander Feb 4, 2025
4040fcf
Merge branch 'main' into dotnet10p1-runtime
richlander Feb 6, 2025
04e0f86
Merge branch 'dotnet10p1' into dotnet10p1-runtime
richlander Feb 6, 2025
b6c4ce8
Add cryptography notes
bartonjs Feb 7, 2025
79c8c43
Fix typo
bartonjs Feb 7, 2025
d786189
Add ISOWeek overloads for DateOnly type
tarekgh Feb 11, 2025
4e7b77c
ZipArchive
carlossanlop Feb 11, 2025
698c410
Merge remote-tracking branch 'dotnet/dotnet10p1-runtime' into dotnet1…
carlossanlop Feb 11, 2025
f8c767f
Remove duplicate ISOWeek method overloads section
tarekgh Feb 11, 2025
8f04470
Add String Normalization APIs for Span<char>
tarekgh Feb 11, 2025
9ddd00b
Fix formatting in String Normalization APIs section
tarekgh Feb 11, 2025
b2242a5
Fix formatting for String Normalization APIs section
tarekgh Feb 11, 2025
6acfe1e
Fix formatting for String Normalization APIs section
tarekgh Feb 11, 2025
92a540e
Update String Normalization APIs section
tarekgh Feb 11, 2025
d4bb520
Update String Normalization APIs section
tarekgh Feb 11, 2025
54c1c1e
Doc formatting fix
tarekgh Feb 11, 2025
f06b822
Adding TimeSpan note
tarekgh Feb 11, 2025
70109c4
Add JIT notes
amanasifkhalid Feb 13, 2025
817e7f4
Convert tabs to spaces
amanasifkhalid Feb 13, 2025
f75f7d3
Better ZipArchive stats
carlossanlop Feb 13, 2025
dff2971
Fix stack allocation description
amanasifkhalid Feb 13, 2025
dbf79fc
Feedback
amanasifkhalid Feb 14, 2025
c0c45cc
Add AVX10.2 experimental note, and feedback
amanasifkhalid Feb 14, 2025
d88ecba
"C-style" -> "typical"
amanasifkhalid Feb 14, 2025
633c8b7
Add stack allocation example
amanasifkhalid Feb 14, 2025
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
170 changes: 168 additions & 2 deletions release-notes/10.0/preview/preview1/libraries.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,173 @@

- [What's new in .NET 10](https://learn.microsoft.com/dotnet/core/whats-new/dotnet-10/overview) documentation

## Finding Certificates By Thumbprints Other Than SHA-1

## Feature
Finding certificates uniquely by thumbprint is a fairly common operation,
but the `X509Certificate2Collection.Find` method (for the `FindByThumbprint` mode) only searches for the SHA-1 Thumbprint value.

Since SHA-2-256 ("SHA256") and SHA-3-256 have the same lengths,
we decided that it wasn't pure goodness to let the Find method find any vaguely matching thumbprints.
Copy link
Member Author

Choose a reason for hiding this comment

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

I think some folks may miss was "pure goodness" means.

Suggested change
we decided that it wasn't pure goodness to let the Find method find any vaguely matching thumbprints.
we decided that it wasn't correct to let the Find method find any vaguely matching thumbprints.

Instead, we introduced a new method that accepts the name of the hash algorithm that you want to use for matching.

```C#
X509Certificate2Collection coll = store.Certificates.FindByThumbprint(HashAlgorithmName.SHA256, thumbprint);
Debug.Assert(coll.Count < 2, "Collection has too many matches, has SHA-2 been broken?");
return coll.SingleOrDefault();
```

## Finding PEM-encoded Data in ASCII/UTF-8

The PEM encoding (originally "Privacy Enhanced Mail", but now used widely outside of email) is defined for "text",
which means that the `PemEncoding` class was designed to run on `System.String` and `ReadOnlySpan<char>`.
Copy link
Member Author

Choose a reason for hiding this comment

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

which means that the PemEncoding class was designed to run

I'm not seeing the obvious conclusion that A leads to B.

But, it's quite common (especially on Linux) to have something like a certificate written in a file that uses the ASCII (string) encoding.
Historically, that meant you needed to open the file, convert the bytes to chars (or a string), and then you can use PemEncoding.

Taking advantage of the fact that PEM is only defined for 7-bit ASCII characters, and that 7-bit ASCII has a perfect overlap with single-byte UTF-8 values,
you can now skip the UTF-8/ASCII to char conversion and read the file directly.

```diff
byte[] fileContents = File.ReadAllBytes(path);
-char[] text = Encoding.ASCII.GetString(fileContents);
-PemFields pemFields = PemEncoding.Find(text);
+PemFields pemFields = PemEncoding.FindUtf8(fileContents);

-byte[] contents = Base64.DecodeFromChars(text.AsSpan()[pemFields.Base64Data]);
+byte[] contents = Base64.DecodeFromUtf8(fileContents.AsSpan()[pemFields.Base64Data]);
```

## New Method Overloads in ISOWeek for DateOnly Type

The ISOWeek class was originally designed to work exclusively with DateTime, as it was introduced before the DateOnly type existed. Now that DateOnly is available, it makes sense for ISOWeek to support it as well.

```C#
public static class ISOWeek
{
// New overloads
public static int GetWeekOfYear(DateOnly date);
public static int GetYear(DateOnly date);
public static DateOnly ToDateOnly(int year, int week, DayOfWeek dayOfWeek);
}
```

## String Normalization APIs to Work with Span of Characters

Unicode string normalization has been supported for a long time, but existing APIs have only worked with the string type. This means that callers with data stored in different forms, such as character arrays or spans, must allocate a new string to use these APIs.
Additionally, APIs that return a normalized string always allocate a new string to represent the normalized output.

The change introduces new APIs that work with spans of characters, reducing the restriction to string types and helping to avoid unnecessary allocations.
Copy link
Member Author

@richlander richlander Feb 14, 2025

Choose a reason for hiding this comment

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

Best to word as a positive when we can.

Suggested change
The change introduces new APIs that work with spans of characters, reducing the restriction to string types and helping to avoid unnecessary allocations.
The change introduces new APIs that work with spans of characters, expanding normalization beyond string types and helping to avoid unnecessary allocations.


```C#
public static class StringNormalizationExtensions
{
public static int GetNormalizedLength(this ReadOnlySpan<char> source, NormalizationForm normalizationForm = NormalizationForm.FormC);
public static bool IsNormalized(this ReadOnlySpan<char> source, NormalizationForm normalizationForm = NormalizationForm.FormC);
public static bool TryNormalize(this ReadOnlySpan<char> source, Span<char> destination, out int charsWritten, NormalizationForm normalizationForm = NormalizationForm.FormC);
}
```

## Adding TimeSpan.FromMilliseconds Overload with a Single Parameter

Previously, we introduced the following method without adding an overload that takes a single parameter:

```C#
public static TimeSpan FromMilliseconds(long milliseconds, long microseconds = 0);
```

Although this works since the second parameter is optional, it causes a compilation error when used in a LINQ expression like:

```C#
Expression<Action> a = () => TimeSpan.FromMilliseconds(1000);
```

The issue arises because LINQ expressions cannot handle optional parameters. To address this, we are introducing an overload that takes a single parameter and modifying the existing method to make the second parameter mandatory:

```C#
public readonly struct TimeSpan
{
public static TimeSpan FromMilliseconds(long milliseconds, long microseconds); // Second parameter is no longer optional
public static TimeSpan FromMilliseconds(long milliseconds); // New overload
}
```

## ZipArchive performance and memory improvements
carlossanlop marked this conversation as resolved.
Show resolved Hide resolved

Two significant PRs have been made by contributor @edwardneal in .NET 10 Preview 1 to improve the performance and memory usage of `ZipArchive`:

- [#102704](https://github.com/dotnet/runtime/pull/102704) - This PR optimizes the way entries are written to a `ZipArchive` when in `Update` mode. Previously, all `ZipArchiveEntries` would be loaded into memory and rewritten, which could lead to high memory usage and performance bottlenecks. The optimization reduces memory usage and improves performance by avoiding the need to load all entries into memory.
Copy link
Member Author

@richlander richlander Feb 14, 2025

Choose a reason for hiding this comment

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

I prefer this format. The repo is (largely) implied in this file but not across the body of release notes. We should be explicit. We've also use the longer form in past years.
 

Suggested change
- [#102704](https://github.com/dotnet/runtime/pull/102704) - This PR optimizes the way entries are written to a `ZipArchive` when in `Update` mode. Previously, all `ZipArchiveEntries` would be loaded into memory and rewritten, which could lead to high memory usage and performance bottlenecks. The optimization reduces memory usage and improves performance by avoiding the need to load all entries into memory.
- [dotnet/runtime #102704](https://github.com/dotnet/runtime/pull/102704) optimizes the way entries are written to a `ZipArchive` when in `Update` mode. Previously, all `ZipArchiveEntries` would be loaded into memory and rewritten, which could lead to high memory usage and performance bottlenecks. The optimization reduces memory usage and improves performance by avoiding the need to load all entries into memory.


Adding a 2GB zip file to an existing archive showed:

- A 99.8% reduction in execution time.
- A 99.9996% reduction in memory usage.

Benchmarks:

| Method | Job | Runtime | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Gen2 | Allocated | Alloc Ratio |
|---------- |--------- |---------- |-------------:|-----------:|------------:|------:|--------:|----------:|----------:|----------:|-----------:|------------:|
| Benchmark | Baseline | .NET 9.0 | 4.187 s | 83.3751 ms | 177.6792 ms | 1.002 | 0.06 | 1000.0000 | 1000.0000 | 1000.0000 | 2 GB | 1.000 |
| Benchmark | CoreRun | .NET 10.0 | 9.452 ms | 0.1583 ms | 0.1322 ms | 0.002 | 0.00 | - | - | - | 7.01 KB | 0.000 |

Additional details provided [in the PR description](https://github.com/dotnet/runtime/pull/102704#issue-2317941700).
Copy link
Member Author

Choose a reason for hiding this comment

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

Suggested change
Additional details provided [in the PR description](https://github.com/dotnet/runtime/pull/102704#issue-2317941700).
Additional details are provided in [dotnet/runtime #102704](https://github.com/dotnet/runtime/pull/102704#issue-2317941700).


- [#103153](https://github.com/dotnet/runtime/pull/103153) - This PR enhances the performance of `ZipArchive` by parallelizing the extraction of entries and optimizing internal data structures for better memory usage. These improvements address issues related to performance bottlenecks and high memory usage, making `ZipArchive` more efficient and faster, especially when dealing with large archives.
Copy link
Member Author

@richlander richlander Feb 14, 2025

Choose a reason for hiding this comment

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

Suggested change
- [#103153](https://github.com/dotnet/runtime/pull/103153) - This PR enhances the performance of `ZipArchive` by parallelizing the extraction of entries and optimizing internal data structures for better memory usage. These improvements address issues related to performance bottlenecks and high memory usage, making `ZipArchive` more efficient and faster, especially when dealing with large archives.
- [dotnet/runtime #103153](https://github.com/dotnet/runtime/pull/103153) enhances the performance of `ZipArchive` by parallelizing the extraction of entries and optimizing internal data structures for better memory usage. These improvements address issues related to performance bottlenecks and high memory usage, making `ZipArchive` more efficient and faster, especially when dealing with large archives.


Reading a zip archive showed:

- An 18% reduction in execution time.
- An 18% reduction in memory usage.

Benchmarks:

| Method | Job | Runtime | NumberOfFiles | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Gen2 | Allocated | Alloc Ratio |
|---------- |--------- |---------- |-------------- |----------------:|--------------:|--------------:|------:|--------:|----------:|---------:|---------:|-----------:|------------:|
| Benchmark | Baseline | .NET 9.0 | 2 | 1,178.6 ns | 23.23 ns | 22.81 ns | 1.00 | 0.03 | 0.3700 | - | - | 1.52 KB | 1.00 |
| Benchmark | CoreRun | .NET 10.0 | 2 | 821.6 ns | 12.45 ns | 11.65 ns | 0.70 | 0.02 | 0.2899 | - | - | 1.19 KB | 0.78 |
| | | | | | | | | | | | | | |
| Benchmark | Baseline | .NET 9.0 | 10 | 4,205.5 ns | 62.41 ns | 55.33 ns | 1.00 | 0.02 | 1.4954 | - | - | 6.13 KB | 1.00 |
| Benchmark | CoreRun | .NET 10.0 | 10 | 3,467.5 ns | 67.25 ns | 66.05 ns | 0.82 | 0.02 | 1.2054 | - | - | 4.93 KB | 0.80 |
| | | | | | | | | | | | | | |
| Benchmark | Baseline | .NET 9.0 | 25 | 10,201.5 ns | 190.59 ns | 187.18 ns | 1.00 | 0.02 | 3.5095 | - | - | 14.38 KB | 1.00 |
| Benchmark | CoreRun | .NET 10.0 | 25 | 8,210.2 ns | 152.35 ns | 142.51 ns | 0.81 | 0.02 | 2.8229 | - | - | 11.54 KB | 0.80 |
| | | | | | | | | | | | | | |
| Benchmark | Baseline | .NET 9.0 | 50 | 20,152.7 ns | 333.29 ns | 311.76 ns | 1.00 | 0.02 | 7.0496 | - | - | 28.91 KB | 1.00 |
| Benchmark | CoreRun | .NET 10.0 | 50 | 20,109.1 ns | 517.18 ns | 1,500.43 ns | 1.00 | 0.08 | 5.7068 | - | - | 23.34 KB | 0.81 |
| | | | | | | | | | | | | | |
| Benchmark | Baseline | .NET 9.0 | 100 | 46,986.2 ns | 923.08 ns | 1,906.33 ns | 1.00 | 0.06 | 14.2822 | 0.1221 | - | 58.42 KB | 1.00 |
| Benchmark | CoreRun | .NET 10.0 | 100 | 37,767.2 ns | 752.51 ns | 1,554.06 ns | 0.81 | 0.05 | 11.5967 | 0.0610 | - | 47.38 KB | 0.81 |
| | | | | | | | | | | | | | |
| Benchmark | Baseline | .NET 9.0 | 250 | 115,159.8 ns | 2,211.52 ns | 2,271.07 ns | 1.00 | 0.03 | 34.5459 | 0.1221 | - | 141.42 KB | 1.00 |
| Benchmark | CoreRun | .NET 10.0 | 250 | 94,148.7 ns | 1,842.33 ns | 3,414.87 ns | 0.82 | 0.03 | 27.8320 | 0.3662 | - | 113.97 KB | 0.81 |
| | | | | | | | | | | | | | |
| Benchmark | Baseline | .NET 9.0 | 500 | 241,338.5 ns | 4,726.33 ns | 7,896.64 ns | 1.00 | 0.05 | 69.8242 | 0.4883 | - | 285.86 KB | 1.00 |
| Benchmark | CoreRun | .NET 10.0 | 500 | 184,869.9 ns | 2,969.04 ns | 4,162.18 ns | 0.77 | 0.03 | 56.1523 | 0.7324 | - | 231.06 KB | 0.81 |
| | | | | | | | | | | | | | |
| Benchmark | Baseline | .NET 9.0 | 1000 | 510,114.6 ns | 10,092.12 ns | 20,386.57 ns | 1.00 | 0.05 | 114.2578 | 72.2656 | - | 577.2 KB | 1.00 |
| Benchmark | CoreRun | .NET 10.0 | 1000 | 404,349.3 ns | 7,289.88 ns | 16,153.88 ns | 0.79 | 0.04 | 93.2617 | 52.7344 | - | 467.72 KB | 0.81 |
| | | | | | | | | | | | | | |
| Benchmark | Baseline | .NET 9.0 | 10000 | 13,950,239.9 ns | 273,372.39 ns | 345,728.57 ns | 1.00 | 0.03 | 1000.0000 | 687.5000 | 218.7500 | 5786.24 KB | 1.00 |
| Benchmark | CoreRun | .NET 10.0 | 10000 | 10,911,298.0 ns | 204,013.47 ns | 226,760.43 ns | 0.78 | 0.02 | 843.7500 | 609.3750 | 250.0000 | 4692.19 KB | 0.81 |

Creating an archive showed:

- A 23-35% reduction in execution time.
- A 2% reduction in memory usage.

Benchmarks:

| Method | Job | Runtime | NumberOfFiles | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen0 | Gen1 | Allocated | Alloc Ratio |
|---------- |--------- |---------- |-------------- |----------:|----------:|-----------:|----------:|------:|--------:|--------:|--------:|----------:|------------:|
| Benchmark | Baseline | .NET 9.0 | 2 | 2.729 μs | 0.0538 μs | 0.0449 μs | 2.706 μs | 1.00 | 0.02 | 2.2697 | - | 9.28 KB | 1.00 |
| Benchmark | CoreRun | .NET 10.0 | 2 | 1.665 μs | 0.0256 μs | 0.0239 μs | 1.659 μs | 0.61 | 0.01 | 2.2259 | - | 9.1 KB | 0.98 |
| | | | | | | | | | | | | | |
| Benchmark | Baseline | .NET 9.0 | 10 | 10.341 μs | 0.1988 μs | 0.2289 μs | 10.266 μs | 1.00 | 0.03 | 9.7046 | - | 39.76 KB | 1.00 |
| Benchmark | CoreRun | .NET 10.0 | 10 | 7.937 μs | 0.1514 μs | 0.2487 μs | 7.831 μs | 0.77 | 0.03 | 9.5215 | - | 39.02 KB | 0.98 |
| | | | | | | | | | | | | | |
| Benchmark | Baseline | .NET 9.0 | 25 | 24.677 μs | 0.4903 μs | 0.8842 μs | 24.563 μs | 1.00 | 0.05 | 20.1721 | 3.3569 | 82.92 KB | 1.00 |
| Benchmark | CoreRun | .NET 10.0 | 25 | 18.247 μs | 0.3474 μs | 0.3412 μs | 18.192 μs | 0.74 | 0.03 | 19.7754 | 3.2654 | 81.13 KB | 0.98 |
| | | | | | | | | | | | | | |
| Benchmark | Baseline | .NET 9.0 | 50 | 67.420 μs | 5.7447 μs | 16.9384 μs | 57.185 μs | 1.05 | 0.35 | 40.5273 | 13.4888 | 166.71 KB | 1.00 |
| Benchmark | CoreRun | .NET 10.0 | 50 | 41.443 μs | 0.7212 μs | 0.8306 μs | 41.493 μs | 0.65 | 0.13 | 39.6729 | 0.0610 | 163.16 KB | 0.98 |

Additional benchmarking details provided [in the PR description](https://github.com/dotnet/runtime/pull/103153#issue-2339713028).

This is something about the feature
Loading