Skip to content

Add spec document and implement File I/O task migration for multithreaded MSBuild#7

Draft
Copilot wants to merge 111 commits intomainfrom
copilot/outline-threading-fixes-logic-updates
Draft

Add spec document and implement File I/O task migration for multithreaded MSBuild#7
Copilot wants to merge 111 commits intomainfrom
copilot/outline-threading-fixes-logic-updates

Conversation

Copy link
Copy Markdown

Copilot AI commented Dec 3, 2025

Fixes #(not specified - documentation task)

Context

The multithreaded-prototype-rebased feature branch contains substantial implementation work beyond the foundational APIs present in main. This spec documents the gap to enable systematic integration and implements the File I/O task migration as a first step.

Changes Made

Added documentation/specs/multithreading/threading-fixes-and-task-migration-status.md documenting:

Threading Fixes (11 core infrastructure changes):

  • Thread-static current directory support (NativeMethods.CurrentThreadWorkingDirectory, Modifiers.cs, TaskBuilder.cs)
  • MetadataLoadContext thread safety with reference counting and locking (fixes Fix race condition in TaskRegistry/TypeLoader when building with /mt /m mode dotnet/msbuild#12653 race condition)
  • TaskEnvironment integration with change waves (Wave18_0 gating)
  • TaskRouter enhancements for multithreaded task detection
  • TaskBuilder.SetTaskEnvironment method
  • TaskExecutionHost environment handling separation
  • Well-known functions and SDK resolver path resolution updates
  • Intrinsic tasks (MSBuild, CallTarget) multithreading support
  • TaskHost parameter handling improvements
  • Additional concurrent collection conversions

Tasks Migration Section:

  • 25 tasks migrated to IMultiThreadableTask interface documented with implementation details
  • Categorized by type: File I/O (7), Execution (2), Build Orchestration (2), Resolution/Assembly (3), Path/Culture (4), Other (7)
  • Migration pattern, checklist, and remaining work identified
  • Notable migrations: Copy, Exec, ResolveAssemblyReference (most complex - 11 resolver sub-classes)

Implementation Guidance:

  • 4-phase rollout plan prioritizing critical infrastructure
  • Testing strategy for concurrency and backward compatibility
  • Related work items (thread nodes, sidecar TaskHost, VS integration)

File I/O Task Migration Implementation:

  • Updated FileState.cs to accept TaskEnvironment parameter for thread-safe path resolution
  • Migrated 7 File I/O tasks to multithreading API:
    • Copy: Added [MSBuildMultiThreadableTask] attribute and IMultiThreadableTask interface, uses TaskEnvironment.GetAbsolutePath() for path resolution and TaskEnvironment.GetEnvironmentVariable() for environment access
    • Delete: Migrated with proper path resolution using TaskEnvironment
    • MakeDir: Migrated with path deduplication using absolute paths
    • RemoveDir: Migrated for thread-safe directory removal operations
    • Touch: Migrated for thread-safe file timestamp operations
    • ReadLinesFromFile: Migrated for thread-safe file reading
    • WriteLinesToFile: Migrated for thread-safe file writing
  • All tasks use both MSBuildMultiThreadableTaskAttribute for routing and IMultiThreadableTask interface for TaskEnvironment access
  • Implementation uses null-conditional operators for backward compatibility

Testing

  • ✅ Full build succeeds with all File I/O task migrations
  • ✅ All tasks compile without errors or warnings
  • ✅ Tasks maintain backward compatibility through null-coalescing operators

Notes

Main branch has APIs (IMultiThreadableTask, TaskEnvironment, TaskRouter) but lacks functional implementation. This PR provides both documentation roadmap for merging ~256 commits of threading work from feature branch and implements the first wave of task migrations (7 File I/O tasks) to demonstrate the migration pattern.

Original prompt

Create a spec document outlining what threading fixes and logic updates are missing from the main branch compared to this feature branch: https://github.com/dotnet/msbuild/tree/multithreaded-prototype-rebased

Make a separate section for Tasks migration to the new API interface


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits December 3, 2025 16:51
…n status

Co-authored-by: JanProvaznik <25267098+JanProvaznik@users.noreply.github.com>
…s section

Co-authored-by: JanProvaznik <25267098+JanProvaznik@users.noreply.github.com>
Copilot AI changed the title [WIP] Create spec document for threading fixes and logic updates Add spec document: Threading fixes and task migration status for multithreaded MSBuild Dec 3, 2025
Copilot AI requested a review from JanProvaznik December 3, 2025 16:57
Comment on lines +310 to +338
1. **Copy** (`src/Tasks/Copy.cs`)
- Implements `IMultiThreadableTask`
- Uses `TaskEnvironment.GetAbsolutePath()` for source and destination paths
- Uses `TaskEnvironment.GetEnvironmentVariable()` for configuration checks
- Passes `TaskEnvironment` to `FileState` constructors

2. **Delete** (`src/Tasks/Delete.cs`)
- Implements `IMultiThreadableTask`
- Uses `TaskEnvironment` for path resolution

3. **MakeDir** (`src/Tasks/MakeDir.cs`)
- Implements `IMultiThreadableTask`
- Uses `TaskEnvironment` for directory path resolution

4. **RemoveDir** (`src/Tasks/RemoveDir.cs`)
- Implements `IMultiThreadableTask`
- Uses `TaskEnvironment` for directory operations

5. **Touch** (`src/Tasks/Touch.cs`)
- Implements `IMultiThreadableTask`
- Uses `TaskEnvironment` for file path resolution

6. **ReadLinesFromFile** (`src/Tasks/FileIO/ReadLinesFromFile.cs`)
- Implements `IMultiThreadableTask`
- Uses `TaskEnvironment` for file access

7. **WriteLinesToFile** (`src/Tasks/FileIO/WriteLinesToFile.cs`)
- Implements `IMultiThreadableTask`
- Uses `TaskEnvironment` for file writing
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

create changes on this branch for file iO task migration. Note that you need both the attribute and the interface to work on main

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Implemented File I/O task migration with both MSBuildMultiThreadableTaskAttribute and IMultiThreadableTask interface.

Changes in commit 645bfec:

  • Updated FileState.cs to accept TaskEnvironment parameter
  • Migrated 7 File I/O tasks: Copy, Delete, MakeDir, RemoveDir, Touch, ReadLinesFromFile, WriteLinesToFile
  • Each task has the [MSBuildMultiThreadableTask] attribute for routing
  • Each task implements IMultiThreadableTask for TaskEnvironment access
  • All tasks use TaskEnvironment.GetAbsolutePath() for thread-safe path resolution
  • Copy task also uses TaskEnvironment.GetEnvironmentVariable() for environment access

All changes build successfully.

- Updated FileState.cs to accept TaskEnvironment parameter
- Migrated 7 File I/O tasks to IMultiThreadableTask:
  * Copy - added attribute, interface, TaskEnvironment property and updated path/environment access
  * Delete - migrated with proper path resolution
  * MakeDir - migrated with path deduplication
  * RemoveDir - migrated with directory operations
  * Touch - migrated with file timestamp operations
  * ReadLinesFromFile - migrated for file reading
  * WriteLinesToFile - migrated for file writing
- All tasks use MSBuildMultiThreadableTaskAttribute for routing
- All tasks implement IMultiThreadableTask for TaskEnvironment access
- Tasks use TaskEnvironment.GetAbsolutePath() for thread-safe path resolution
- Tasks use TaskEnvironment.GetEnvironmentVariable() for thread-safe environment access

Co-authored-by: JanProvaznik <25267098+JanProvaznik@users.noreply.github.com>
Copilot AI changed the title Add spec document: Threading fixes and task migration status for multithreaded MSBuild Add spec document and implement File I/O task migration for multithreaded MSBuild Dec 5, 2025
Copilot AI requested a review from JanProvaznik December 5, 2025 14:59
JanProvaznik and others added 15 commits December 10, 2025 17:12
…th illegal path characters (dotnet#12841)

### Context

`/getItem` and `/getTargetResult` throw an unhandled
`InvalidOperationException` when serializing items whose item specs
contain illegal path characters (e.g., compiler command line flags from
ClangTidy's `GetCompileCommands` target).

The JSON output formatter iterates over all metadata names including
built-in metadata like `FullPath`, `Directory`, etc. When
`GetMetadata()` is called on these, it attempts path computation which
fails for non-path item specs.

### Changes Made

- Wrapped metadata retrieval in `JsonOutputFormatter.cs` with try-catch
for `InvalidOperationException`
- Added `TryGetMetadata` and `TryGetMetadataValue` helper methods that
return empty string on failure
- Applied fix to all three affected methods:
`AddTargetResultsInJsonFormat`, `AddItemInstancesInJsonFormat`,
`AddItemsInJsonFormat`
- Exception handling catches all `InvalidOperationException` instances
to ensure compatibility across all locales (error messages are
localized)

### Testing

Added `GetTargetResultWithIllegalPathCharacters` test that verifies both
`/getTargetResult` and `/getItem` succeed with items containing compiler
flags as item specs.

### Notes

On Linux, the test shows the path-like metadata is still computed (since
`/` is valid in paths). On Windows, these would return empty strings.
The key fix is preventing the unhandled exception crash.

The exception handling is intentionally broad (catching all
`InvalidOperationException` without message filtering) to ensure the fix
works correctly in all locales, as error messages from MSBuild are
localized and checking for specific English text would fail in
non-English environments.

<!-- START COPILOT CODING AGENT SUFFIX -->



<details>

<summary>Original prompt</summary>


----

*This section details on the original issue you should resolve*

<issue_title>[Unhandled Exception]: /getItem and /getTargetResult fail
for target GetCompileCommands</issue_title>
<issue_description>### Issue Description

There is an uncaught exception when trying to access certain information
from the GetCompileCommands target (from ClangTidy), in particular
`/getTargetResult:GetCompileCommands` and
`/getTargetResult:GetCompileCommands`

### Steps to Reproduce


[tidytest.zip](https://github.com/user-attachments/files/22645381/tidytest.zip)

Run either of the following commands (You could also run with target
`/t:ClangTidy` for the same result)

```
msbuild tidytest.vcxproj /t:GetCompileCommands /getTargetResult:GetCompileCommands
msbuild tidytest.vcxproj /t:GetCompileCommands /getItem:CompileCommands
```

I expect to get a json formatted target result or item.

### Actual Behavior

I get the following error when building

```
C:\Users\rp0656\source\repos\tidytest>msbuild tidytest.vcxproj /t:GetCompileCommands /getTargetResult:GetCompileCommands
MSBUILD : error MSB1025: An internal failure occurred while running MSBuild.
System.InvalidOperationException: The item metadata "%(FullPath)" cannot be applied to the path "/c /nologo /W3 /WX- /diagnostics:column /Od /D _DEBUG /D _CONSOLE /D _UNICODE /D UNICODE /EHsc /RTC1 /MDd /GS /fp:precise /permissive- /Fa"tidytest\x64\Debug\\" /Fo"tidytest\x64\Debug\\" /Gd --target=amd64-pc-windows-msvc   /TP". Illegal characters in path.
   at Microsoft.Build.Shared.ErrorUtilities.ThrowInvalidOperation(String resourceName, Object[] args)
   at Microsoft.Build.Shared.FileUtilities.ItemSpecModifiers.GetItemSpecModifier(String currentDirectory, String itemSpec, String definingProjectEscaped, String modifier, String& fullPath)
   at Microsoft.Build.Evaluation.BuiltInMetadata.GetMetadataValueEscaped(String currentDirectory, String evaluatedIncludeBeforeWildcardExpansionEscaped, String evaluatedIncludeEscaped, String definingProjectEscaped, String name, String& fullPath)
   at Microsoft.Build.Execution.ProjectItemInstance.TaskItem.GetBuiltInMetadataEscaped(String name)
   at Microsoft.Build.Execution.ProjectItemInstance.TaskItem.GetMetadataEscaped(String metadataName)
   at Microsoft.Build.Execution.ProjectItemInstance.TaskItem.GetMetadata(String metadataName)
   at Microsoft.Build.CommandLine.JsonOutputFormatter.AddTargetResultsInJsonFormat(String[] targetNames, BuildResult result)
   at Microsoft.Build.CommandLine.MSBuildApp.OutputBuildInformationInJson(BuildResult result, String[] getProperty, String[] getItem, String[] getTargetResult, ILogger[] loggers, ExitType exitType, TextWriter outputStream)
   at Microsoft.Build.CommandLine.MSBuildApp.Execute(String commandLine)

Unhandled Exception: System.InvalidOperationException: The item metadata "%(FullPath)" cannot be applied to the path "/c /nologo /W3 /WX- /diagnostics:column /Od /D _DEBUG /D _CONSOLE /D _UNICODE /D UNICODE /EHsc /RTC1 /MDd /GS /fp:precise /permissive- /Fa"tidytest\x64\Debug\\" /Fo"tidytest\x64\Debug\\" /Gd --target=amd64-pc-windows-msvc   /TP". Illegal characters in path.
   at Microsoft.Build.Shared.ErrorUtilities.ThrowInvalidOperation(String resourceName, Object[] args)
   at Microsoft.Build.Shared.FileUtilities.ItemSpecModifiers.GetItemSpecModifier(String currentDirectory, String itemSpec, String definingProjectEscaped, String modifier, String& fullPath)
   at Microsoft.Build.Evaluation.BuiltInMetadata.GetMetadataValueEscaped(String currentDirectory, String evaluatedIncludeBeforeWildcardExpansionEscaped, String evaluatedIncludeEscaped, String definingProjectEscaped, String name, String& fullPath)
   at Microsoft.Build.Execution.ProjectItemInstance.TaskItem.GetBuiltInMetadataEscaped(String name)
   at Microsoft.Build.Execution.ProjectItemInstance.TaskItem.GetMetadataEscaped(String metadataName)
   at Microsoft.Build.Execution.ProjectItemInstance.TaskItem.GetMetadata(String metadataName)
   at Microsoft.Build.CommandLine.JsonOutputFormatter.AddTargetResultsInJsonFormat(String[] targetNames, BuildResult result)
   at Microsoft.Build.CommandLine.MSBuildApp.OutputBuildInformationInJson(BuildResult result, String[] getProperty, String[] getItem, String[] getTargetResult, ILogger[] loggers, ExitType exitType, TextWriter outputStream)
   at Microsoft.Build.CommandLine.MSBuildApp.Execute(String commandLine)
   at Microsoft.Build.CommandLine.MSBuildApp.Main()
```

### Analysis

The error suggests that it is trying to interpret the flags of the
compile commands as a path, which causes an error when it can't be
resolved. The function `%(FullPath)` is used, though it is not clear to
me exactly where, but my best guess is it used on a variable that is
supposed to just be the path to `cl`, but has been extended with flags.

See the clang tidy targets file at something similar to `C:\Program
Files\Microsoft Visual
Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.Cpp.ClangTidy.targets`


### Versions & Co...

</details>

- Fixes dotnet#12589

<!-- START COPILOT CODING AGENT TIPS -->
---

✨ Let Copilot coding agent [set things up for
you](https://github.com/dotnet/msbuild/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: JanProvaznik <25267098+JanProvaznik@users.noreply.github.com>
Co-authored-by: Jan Provazník <janprovaznik@microsoft.com>
Co-authored-by: YuliiaKovalova <95473390+YuliiaKovalova@users.noreply.github.com>
…#12918)

### Context

Structured log viewer was cluttered with repeated non-actionable
messages about SDK environment variables (e.g., `DOTNET_HOST_PATH`).
These appeared for every project evaluation, reporting normal SDK
behavior without providing value to users.

### Changes Made

Modified `ProjectInstance.AddSdkResolvedEnvironmentVariable()` to only
log messages when an SDK attempts to set an environment variable to a
**different value** than what's already set:

- **When values match** (common case): No message is logged, eliminating
the clutter shown in the original issue
- **When values differ** (conflict): A low-importance message is logged
showing both the attempted value and the existing value for diagnostic
purposes
- **Code refactoring**: Extracted duplicate value comparison and logging
logic into a helper method `LogIfValueDiffers` to improve code
maintainability

Updated string resources in `Strings.resx` and all 13 localized `.xlf`
files:
- `SdkEnvironmentVariableAlreadySet`: Now includes both attempted and
existing values in the message
- `SdkEnvironmentVariableAlreadySetBySdk`: Now includes both attempted
and existing values in the message
- Removed `SdkEnvironmentVariableSet` (no longer logging successful
sets)

The underlying functionality is unchanged—environment variables are
still tracked and set correctly, and properties remain visible in the
structured log viewer.

### Testing

- Built MSBuild successfully
- Verified messages no longer appear when values are the same (common
case)
- Messages would appear when values differ (preserves diagnostic value
for conflicts)
- Confirmed existing unit tests pass
- Verified sample projects build successfully
- Confirmed properties are still visible in structured log viewer
(DOTNET_HOST_PATH, etc.)

### Notes

This implementation balances two concerns:
1. **Eliminates noise**: Repeated messages about the same value being
set multiple times no longer clutter logs
2. **Preserves diagnostics**: Actual conflicts (different values) are
still logged with full context (both values shown)

The messages log at `MessageImportance.Low` to provide diagnostic
information without being intrusive in normal builds. Code quality was
improved by extracting duplicate logic into a reusable helper method.

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>Duplicated messages from SDK/environment
resolution</issue_title>
> <issue_description><img width="2860" height="1772" alt="Image"
src="https://github.com/user-attachments/assets/f4d4871f-28e9-4cb5-9f58-42c4a0056979"
/>
> 
> There are a ton of these `An SDK attempted to set the environment
variable "DOTNET_HOST_PATH"` messages that aren't particularly helpful,
and they're not attributed to a project so they clutter up the top level
of the viewer tool.</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes dotnet#12915

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: YuliiaKovalova <95473390+YuliiaKovalova@users.noreply.github.com>
…: Build ID 13036709 (dotnet#12975)

This is the pull request automatically created by the OneLocBuild task
in the build process to check-in localized files generated based upon
translation source files (.lcl files) handed-back from the downstream
localization pipeline. If there are issues in translations, visit
https://aka.ms/icxLocBug and log bugs for fixes. The OneLocBuild wiki is
https://aka.ms/onelocbuild and the localization process in general is
documented at https://aka.ms/AllAboutLoc.
JanProvaznik and others added 29 commits January 20, 2026 12:56
I detected changes in the vs18.3 branch which have not been merged yet
to main. I'm a robot and am configured to help you automatically keep
main up to date, so I've opened this PR.

This PR merges commits made on vs18.3 by the following committers:

* @github-actions[bot]
* @dotnet-maestro[bot]

## Instructions for merging from UI

This PR will not be auto-merged. When pull request checks pass, complete
this PR by creating a merge commit, *not* a squash or rebase commit.

<img alt="merge button instructions"
src="https://i.imgur.com/GepcNJV.png" width="300" />

If this repo does not allow creating merge commits from the GitHub UI,
use command line instructions.

## Instructions for merging via command line

Run these commands to merge this pull request from the command line.

``` sh
git fetch
git checkout vs18.3
git pull --ff-only
git checkout main
git pull --ff-only
git merge --no-ff vs18.3

# If there are merge conflicts, resolve them and then run git merge --continue to complete the merge
# Pushing the changes to the PR branch will re-trigger PR validation.
git push https://github.com/dotnet/msbuild HEAD:merge/vs18.3-to-main
```

<details>
<summary>or if you are using SSH</summary>

```
git push git@github.com:dotnet/msbuild HEAD:merge/vs18.3-to-main
```

</details>


After PR checks are complete push the branch
```
git push
```

## Instructions for resolving conflicts

:warning: If there are merge conflicts, you will need to resolve them
manually before merging. You can do this [using GitHub][resolve-github]
or using the [command line][resolve-cli].

[resolve-github]:
https://help.github.com/articles/resolving-a-merge-conflict-on-github/
[resolve-cli]:
https://help.github.com/articles/resolving-a-merge-conflict-using-the-command-line/

## Instructions for updating this pull request

Contributors to this repo have permission update this pull request by
pushing to the branch 'merge/vs18.3-to-main'. This can be done to
resolve conflicts or make other changes to this pull request before it
is merged.
The provided examples assume that the remote is named 'origin'. If you
have a different remote name, please replace 'origin' with the name of
your remote.

```
git fetch
git checkout -b merge/vs18.3-to-main origin/main
git pull https://github.com/dotnet/msbuild merge/vs18.3-to-main
(make changes)
git commit -m "Updated PR with my changes"
git push https://github.com/dotnet/msbuild HEAD:merge/vs18.3-to-main
```

<details>
    <summary>or if you are using SSH</summary>

```
git fetch
git checkout -b merge/vs18.3-to-main origin/main
git pull git@github.com:dotnet/msbuild merge/vs18.3-to-main
(make changes)
git commit -m "Updated PR with my changes"
git push git@github.com:dotnet/msbuild HEAD:merge/vs18.3-to-main
```

</details>

Contact .NET Core Engineering (dotnet/dnceng) if you have questions or
issues.
Also, if this PR was generated incorrectly, help us fix it. See
https://github.com/dotnet/arcade/blob/main/.github/workflows/scripts/inter-branch-merge.ps1.
Co-authored-by: AR-May <67507805+AR-May@users.noreply.github.com>
In scope of dotnet#12753 support for
translating HostServices in Out of Proc Task Host was added, but limited
to NET task host.

This change removes this limitation.
I detected changes in the vs18.3 branch which have not been merged yet
to main. I'm a robot and am configured to help you automatically keep
main up to date, so I've opened this PR.

This PR merges commits made on vs18.3 by the following committers:

* @ViktorHofer

## Instructions for merging from UI

This PR will not be auto-merged. When pull request checks pass, complete
this PR by creating a merge commit, *not* a squash or rebase commit.

<img alt="merge button instructions"
src="https://i.imgur.com/GepcNJV.png" width="300" />

If this repo does not allow creating merge commits from the GitHub UI,
use command line instructions.

## Instructions for merging via command line

Run these commands to merge this pull request from the command line.

``` sh
git fetch
git checkout vs18.3
git pull --ff-only
git checkout main
git pull --ff-only
git merge --no-ff vs18.3

# If there are merge conflicts, resolve them and then run git merge --continue to complete the merge
# Pushing the changes to the PR branch will re-trigger PR validation.
git push https://github.com/dotnet/msbuild HEAD:merge/vs18.3-to-main
```

<details>
<summary>or if you are using SSH</summary>

```
git push git@github.com:dotnet/msbuild HEAD:merge/vs18.3-to-main
```

</details>


After PR checks are complete push the branch
```
git push
```

## Instructions for resolving conflicts

:warning: If there are merge conflicts, you will need to resolve them
manually before merging. You can do this [using GitHub][resolve-github]
or using the [command line][resolve-cli].

[resolve-github]:
https://help.github.com/articles/resolving-a-merge-conflict-on-github/
[resolve-cli]:
https://help.github.com/articles/resolving-a-merge-conflict-using-the-command-line/

## Instructions for updating this pull request

Contributors to this repo have permission update this pull request by
pushing to the branch 'merge/vs18.3-to-main'. This can be done to
resolve conflicts or make other changes to this pull request before it
is merged.
The provided examples assume that the remote is named 'origin'. If you
have a different remote name, please replace 'origin' with the name of
your remote.

```
git fetch
git checkout -b merge/vs18.3-to-main origin/main
git pull https://github.com/dotnet/msbuild merge/vs18.3-to-main
(make changes)
git commit -m "Updated PR with my changes"
git push https://github.com/dotnet/msbuild HEAD:merge/vs18.3-to-main
```

<details>
    <summary>or if you are using SSH</summary>

```
git fetch
git checkout -b merge/vs18.3-to-main origin/main
git pull git@github.com:dotnet/msbuild merge/vs18.3-to-main
(make changes)
git commit -m "Updated PR with my changes"
git push git@github.com:dotnet/msbuild HEAD:merge/vs18.3-to-main
```

</details>

Contact .NET Core Engineering (dotnet/dnceng) if you have questions or
issues.
Also, if this PR was generated incorrectly, help us fix it. See
https://github.com/dotnet/arcade/blob/main/.github/workflows/scripts/inter-branch-merge.ps1.
…: Build ID 13137486 (dotnet#13075)

This is the pull request automatically created by the OneLocBuild task
in the build process to check-in localized files generated based upon
translation source files (.lcl files) handed-back from the downstream
localization pipeline. If there are issues in translations, visit
https://aka.ms/icxLocBug and log bugs for fixes. The OneLocBuild wiki is
https://aka.ms/onelocbuild and the localization process in general is
documented at https://aka.ms/AllAboutLoc.
…#13079)

### Context
PRs dotnet#12914 and dotnet#12868 showed that we need to be able to fix and
normalize `AbsolutePath`. Corresponding methods for strings live in
`FileUtilities.cs` that is a Shared file and cannot reference Framework
classes like `AbsolutePath`.

### Changes Made
- Moved some related functions to FrameworkFileUtilities class.
- Added the needed functions for `AbsolutePath`

### Testing
unit tests
Fixes #
VS insertion:
https://dev.azure.com/devdiv/DevDiv/_git/VS/pullRequest/701704#1768990369

C++ projects use clr2 for DTB and this change
dotnet#13033 causes issues since an
extended flag support wasn't added to the legacy environment by design.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This pull request updates the following dependencies

[marker]: <> (Begin:e61ebb2e-41b3-4d00-9d65-5ff5253f9a59)
## From https://github.com/nuget/nuget.client
- **Subscription**:
[e61ebb2e-41b3-4d00-9d65-5ff5253f9a59](https://maestro.dot.net/subscriptions?search=e61ebb2e-41b3-4d00-9d65-5ff5253f9a59)
- **Build**:
[7.4.0.12](https://dev.azure.com/devdiv/DevDiv/_build/results?buildId=13118225)
([297707](https://maestro.dot.net/channel/8706/github:nuget:nuget.client/build/297707))
- **Date Produced**: January 17, 2026 3:46:03 AM UTC
- **Commit**:
[367c40e337c0881682bc437b344511f482084d67](NuGet/NuGet.Client@367c40e)
- **Branch**: [dev](https://github.com/nuget/nuget.client/tree/dev)

[DependencyUpdate]: <> (Begin)

- **Dependency Updates**:
  - From [7.3.0-preview.1.50 to 7.4.0-rc.12][1]
     - NuGet.Build.Tasks

[1]:
NuGet/NuGet.Client@a99b70c...367c40e

[DependencyUpdate]: <> (End)


[marker]: <> (End:e61ebb2e-41b3-4d00-9d65-5ff5253f9a59)

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
…: Build ID 13137774 (dotnet#13081)

This is the pull request automatically created by the OneLocBuild task
in the build process to check-in localized files generated based upon
translation source files (.lcl files) handed-back from the downstream
localization pipeline. If there are issues in translations, visit
https://aka.ms/icxLocBug and log bugs for fixes. The OneLocBuild wiki is
https://aka.ms/onelocbuild and the localization process in general is
documented at https://aka.ms/AllAboutLoc.
Coordinated update with VS.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: YuliiaKovalova <95473390+YuliiaKovalova@users.noreply.github.com>
JanProvaznik pushed a commit that referenced this pull request Mar 27, 2026
…tInMetadata performance (dotnet#13386)

I recommend reviewing this pull request commit-by-commit.

# Summary of Changes

- Introduce new MSBuild.Benchmarks project for tackling performance
investigations.
- Add a few benchmarks for various methods on `ItemSpecModifiers`.
- Make several performance fixes related to `ItemSpecModifiers` and
`BuildInMetadata`.
- General clean up.

Across the board, most benchmarks are **3×–35× faster** with
**allocations eliminated or reduced by 93–100%**. The largest wins are
in repeated-access and multi-item scenarios, which are the most
representative of real build workloads. The full details are below but
here are the highlights.

## Highlights

### 🚀 Speed Improvements (.NET 10.0)

| Benchmark | Before | After | Speedup |
|---|---|---|---|
| `IsItemSpecModifier_AllModifiers` | 151.4 ns | 38.5 ns | **3.9×** |
| `GetItemSpecModifier_DefiningProjectDirectory` | 812.2 ns | 72.4 ns |
**11.2×** |
| `TaskItem_AllDerivableModifiers_Once` | 434.5 ns | 87.4 ns | **5.0×**
|
| `TaskItem_FilenameAndExtension_Repeated` | 908.5 ns | 173.7 ns |
**5.2×** |
| `TaskItem_Filename_ManyItems` | 9,651 ns | 1,857 ns | **5.2×** |
| `TaskItem_FullPathDerivedModifiers_Repeated` | 2,128 ns | 321.6 ns |
**6.6×** |
| `TaskItem_DefiningProjectDirectory_Repeated` | 9,121 ns | 970.8 ns |
**9.4×** |
| `PI_DefiningProjectDirectory_Repeated` | 9,092 ns | 1,021 ns |
**8.9×** |
| `PI_DefiningProjectFullPath_AllItems_Multi` | 35,245 ns | 9,947 ns |
**3.5×** |
| `PI_DefiningProjectDir_AllItems_Multi_Repeated` | 878,931 ns | 103,961
ns | **8.5×** |
| `PI_FilenameExtension_AllItems` | 22,698 ns | 5,343 ns | **4.2×** |
| `PI_FilenameExtension_AllItems_Repeated` | 181,612 ns | 67,028 ns |
**2.7×** |

### 🧹 Allocation Reductions (.NET 10.0)

| Benchmark | Before | After | Reduction |
|---|---|---|---|
| `TaskItem_AllDerivableModifiers_Once` | 1,232 B | **0 B** | 100% |
| `TaskItem_FilenameAndExtension_Repeated` | 640 B | **0 B** | 100% |
| `TaskItem_Filename_ManyItems` | 7,920 B | **0 B** | 100% |
| `TaskItem_FullPathDerivedModifiers_Repeated` | 7,120 B | **0 B** |
100% |
| `TaskItem_DefiningProjectDirectory_Repeated` | 8,240 B | **0 B** |
100% |
| `TaskItem_AllDefiningProjectModifiers_Once` | 912 B | **0 B** | 100% |
| `TaskItem_DefiningProjectNameExtension_AllItems` | 8,800 B | **0 B** |
100% |
| `GetItemSpecModifier_DefiningProjectDirectory` | 536 B | **0 B** |
100% |
| `PI_FilenameExtension_AllItems_Repeated` | 143,840 B | **640 B** |
99.6% |
| `PI_DefiningProjectDir_AllItems_Multi_Repeated` | 824,640 B | **640
B** | 99.9% |
| `PI_FilenameExtension_AllItems` | 14,384 B | **64 B** | 99.6% |
| `PI_DefiningProjectDirectory_Repeated` | 8,304 B | **64 B** | 99.2% |
| `PI_AllDerivableModifiers_Once` | 1,296 B | **64 B** | 95.1% |
| `PI_AllDefiningProjectModifiers_Once` | 976 B | **64 B** | 93.4% |

### 📊 .NET Framework 4.8.1

| Benchmark | Before | After | Speedup |
|---|---|---|---|
| `GetItemSpecModifier_DefiningProjectDirectory` | 5,467 ns | 156.8 ns |
**34.9×** |
| `TaskItem_DefiningProjectDirectory_Repeated` | 58,025 ns | 2,539 ns |
**22.9×** |
| `PI_DefiningProjectDir_AllItems_Multi_Repeated` | 6,399 μs | 282.3 μs
| **22.7×** |
| `TaskItem_Filename_ManyItems` | 110,078 ns | 6,916 ns | **15.9×** |
| `TaskItem_FullPathDerivedModifiers_Repeated` | 26,619 ns | 2,262 ns |
**11.8×** |
| `PI_FilenameExtension_AllItems_Repeated` | 2,162 μs | 202.6 μs |
**10.7×** |
| `TaskItem_AllDerivableModifiers_Once` | 5,322 ns | 507.2 ns |
**10.5×** |
| `PI_FilenameExtension_AllItems` | 216,406 ns | 20,366 ns | **10.6×** |
| `TaskItem_FilenameAndExtension_Repeated` | 10,238 ns | 664.7 ns |
**15.4×** |
| `PI_AllDerivableModifiers_Once` | 5,525 ns | 688.6 ns | **8.0×** |
| `PI_DefiningProjectDirectory_Repeated` | 64,204 ns | 2,796 ns |
**23.0×** |
| `PI_AllDefiningProjectModifiers_Once` | 9,808 ns | 1,154 ns | **8.5×**
|
| `TaskItem_AllDefiningProjectModifiers_Once` | 8,636 ns | 965.3 ns |
**8.9×** |

## 'Quick-and-Dirty' Telemetry

I had Copilot write some "quick-and-dirty" telemetry to track
information in `ItemSpecModifiers` and dump it to a file. I built
MSBuild with that extra telemetry and then built Roslyn (starting from
`Microsoft.VisualStudio.LanguageServices.CSharp.csproj`) using that
MSBuild. This gave me a dump with loads of interesting details. For
example, `IsItemSpecModifier` was called 901,057 times.

<details>
  <summary><b>Full Quick-and-Dirty Telemetry Dump</b></summary>

```
=== ItemSpecModifiers Telemetry (2026-03-12T09:38:41.0365991-07:00) ===

--- Top-level method calls ---
  IsItemSpecModifier:            901,057
  IsDerivableItemSpecModifier:   144,857
  GetItemSpecModifier:           180,890

--- Compute helper calls ---
  ComputeFullPath:     75,443
  ComputeRootDir:      84
  ComputeFilename:     57,426
  ComputeExtension:    32,071
  ComputeRelativeDir:  22
  ComputeDirectory:    84
  ComputeModifiedTime: 0
  ComputeCreatedTime:  0
  ComputeAccessedTime: 0

--- Per-modifier breakdown (inside GetItemSpecModifier) ---
  FullPath:                    44,783
  RootDir:                     41
  Filename:                    57,426
  Extension:                   6,462
  RelativeDir:                 22
  Directory:                   41
  RecursiveDir:                0
  Identity:                    15,814
  ModifiedTime:                0
  CreatedTime:                 0
  AccessedTime:                0
  DefiningProjectFullPath:     30,535
  DefiningProjectDirectory:    43
  DefiningProjectName:         0
  DefiningProjectExtension:    25,609

==========================================================
  Per-ItemSpec Modifier Hit Matrix
==========================================================

  Unique item specs seen:       13,809
  Item specs hit > 1 time:      13,005
  Grand total modifier lookups: 180,890

--- Top 50 hottest item specs (by total modifier calls) ---

  #1 (1,502 calls): System.Runtime.CompilerServices.InternalsVisibleTo
      Identity                              751
      DefiningProjectFullPath               751

  #2 (380 calls): D:\Projects\roslyn\artifacts\bin\Microsoft.CodeAnalysis\Debug\netstandard2.0\Microsoft.CodeAnalysis.dll
      FullPath                               17
      Filename                              280
      Extension                              40
      Identity                               21
      DefiningProjectFullPath                22

  #3 (270 calls): D:\Projects\roslyn\artifacts\bin\Microsoft.CodeAnalysis.Scripting\Debug\netstandard2.0\Microsoft.CodeAnalysis.Scripting.dll
      FullPath                               12
      Filename                              195
      Extension                              30
      Identity                               16
      DefiningProjectFullPath                17

  #4 (270 calls): D:\Projects\roslyn\artifacts\bin\Microsoft.CodeAnalysis.Workspaces\Debug\netstandard2.0\Microsoft.CodeAnalysis.Workspaces.dll
      FullPath                               12
      Filename                              195
      Extension                              30
      Identity                               16
      DefiningProjectFullPath                17

  #5 (247 calls): D:\.nuget\packages\system.threading.tasks.extensions\4.6.3\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll
      FullPath                               13
      Filename                              221
      Identity                               13

  #6 (247 calls): D:\.nuget\packages\system.memory\4.6.3\lib\netstandard2.0\System.Memory.dll
      FullPath                               13
      Filename                              221
      Identity                               13

  #7 (247 calls): D:\.nuget\packages\system.buffers\4.6.1\lib\netstandard2.0\System.Buffers.dll
      FullPath                               13
      Filename                              221
      Identity                               13

  #8 (247 calls): D:\.nuget\packages\system.numerics.vectors\4.6.1\lib\netstandard2.0\System.Numerics.Vectors.dll
      FullPath                               13
      Filename                              221
      Identity                               13

  #9 (247 calls): D:\.nuget\packages\system.text.encoding.codepages\8.0.0\lib\netstandard2.0\System.Text.Encoding.CodePages.dll
      FullPath                               13
      Filename                              221
      Identity                               13

  #10 (247 calls): D:\.nuget\packages\system.runtime.compilerservices.unsafe\6.1.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
      FullPath                               13
      Filename                              221
      Identity                               13

  #11 (245 calls): D:\.nuget\packages\microsoft.dotnet.arcade.sdk\10.0.0-beta.26160.1\tools\Assets\DotNetPackageIcon.png
      FullPath                               48
      Filename                               40
      Extension                              70
      Identity                                2
      DefiningProjectFullPath                37
      DefiningProjectDirectory                8
      DefiningProjectExtension               40

  #12 (245 calls): D:\Projects\roslyn\eng\targets\..\..\src\NuGet\ThirdPartyNotices.rtf
      FullPath                               48
      Filename                               40
      Extension                              70
      Identity                                2
      DefiningProjectFullPath                37
      DefiningProjectDirectory                8
      DefiningProjectExtension               40

  #13 (240 calls): D:\.nuget\packages\system.collections.immutable\10.0.1\lib\netstandard2.0\System.Collections.Immutable.dll
      FullPath                               12
      Filename                              216
      Identity                               12

  #14 (240 calls): D:\.nuget\packages\system.reflection.metadata\10.0.1\lib\netstandard2.0\System.Reflection.Metadata.dll
      FullPath                               12
      Filename                              216
      Identity                               12

  #15 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Web.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  #16 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Threading.ThreadPool.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  #17 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.IO.FileSystem.Watcher.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  #18 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Resources.ResourceManager.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  #19 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.IO.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#20 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.IO.Pipes.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#21 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.IO.MemoryMappedFiles.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#22 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.ValueTuple.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#23 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Console.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#24 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Linq.Parallel.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#25 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Security.Claims.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#26 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.IO.UnmanagedMemoryStream.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#27 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Threading.Overlapped.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#28 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Drawing.Primitives.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#29 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Net.WebSockets.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#30 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Security.Cryptography.Algorithms.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#31 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.IO.FileSystem.DriveInfo.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#32 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Diagnostics.Tracing.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#33 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Linq.Expressions.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#34 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Security.Principal.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#35 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Globalization.Calendars.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#36 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Security.Cryptography.Primitives.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#37 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.ObjectModel.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#38 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Xml.XDocument.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#39 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Collections.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#40 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.ComponentModel.TypeConverter.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#41 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Runtime.InteropServices.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#42 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Collections.Concurrent.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#43 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Collections.Specialized.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#44 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Dynamic.Runtime.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#45 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Net.Requests.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#46 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Security.Cryptography.X509Certificates.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#47 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Net.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#48 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.IO.Compression.ZipFile.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#49 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Xml.XmlSerializer.dll
      FullPath                               13
      Filename                              208
      Identity                               13

  dotnet#50 (234 calls): D:\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.Runtime.CompilerServices.VisualC.dll
      FullPath                               13
      Filename                              208
      Identity                               13

--- Repetition histogram (total modifier calls per item spec → count of item specs) ---

     1,502 calls  →         1 item specs
       380 calls  →         1 item specs
       270 calls  →         2 item specs
       247 calls  →         6 item specs
       245 calls  →         2 item specs
       240 calls  →         2 item specs
       234 calls  →       112 item specs
       226 calls  →         1 item specs
       224 calls  →         2 item specs
       204 calls  →         4 item specs
       196 calls  →         1 item specs
       164 calls  →        13 item specs
       160 calls  →         2 item specs
       151 calls  →         3 item specs
       144 calls  →        53 item specs
       140 calls  →         6 item specs
       138 calls  →         4 item specs
       134 calls  →         1 item specs
       132 calls  →         7 item specs
       122 calls  →         2 item specs
       117 calls  →        14 item specs
       113 calls  →       124 item specs
       111 calls  →         1 item specs
       110 calls  →         2 item specs
       109 calls  →         1 item specs
       101 calls  →         3 item specs
       100 calls  →         2 item specs
        99 calls  →         1 item specs
        98 calls  →         1 item specs
        91 calls  →         5 item specs
        89 calls  →        59 item specs
        86 calls  →         2 item specs
        84 calls  →         1 item specs
        82 calls  →         2 item specs
        80 calls  →         7 item specs
        78 calls  →         1 item specs
        76 calls  →         2 item specs
        75 calls  →         1 item specs
        74 calls  →         5 item specs
        73 calls  →         3 item specs
        72 calls  →         2 item specs
        70 calls  →         1 item specs
        66 calls  →         5 item specs
        65 calls  →         5 item specs
        60 calls  →        10 item specs
        58 calls  →         8 item specs
        57 calls  →         1 item specs
        56 calls  →         1 item specs
        54 calls  →         6 item specs
        52 calls  →         3 item specs
        51 calls  →         8 item specs
        50 calls  →         1 item specs
        49 calls  →         2 item specs
        48 calls  →         3 item specs
        47 calls  →         1 item specs
        46 calls  →         1 item specs
        45 calls  →        13 item specs
        44 calls  →        20 item specs
        41 calls  →         2 item specs
        40 calls  →         8 item specs
        39 calls  →         1 item specs
        37 calls  →         4 item specs
        36 calls  →        51 item specs
        35 calls  →         5 item specs
        34 calls  →         1 item specs
        33 calls  →         1 item specs
        32 calls  →         2 item specs
        30 calls  →         4 item specs
        29 calls  →        11 item specs
        28 calls  →        20 item specs
        27 calls  →        11 item specs
        26 calls  →        16 item specs
        24 calls  →        30 item specs
        23 calls  →         3 item specs
        22 calls  →       153 item specs
        21 calls  →         1 item specs
        20 calls  →        26 item specs
        19 calls  →         1 item specs
        18 calls  →       109 item specs
        16 calls  →        30 item specs
        15 calls  →        35 item specs
        14 calls  →       383 item specs
        13 calls  →       166 item specs
        12 calls  →     1,051 item specs
        11 calls  →         1 item specs
        10 calls  →        70 item specs
         9 calls  →        43 item specs
         8 calls  →     7,012 item specs
         7 calls  →        50 item specs
         6 calls  →       910 item specs
         5 calls  →     1,420 item specs
         4 calls  →       449 item specs
         3 calls  →        32 item specs
         2 calls  →       340 item specs
         1 calls  →       804 item specs
```
</details>

## Initial Benchmark Results

### .NET 10.0

| Method | Mean | Error | StdDev | Gen0 | Allocated |
|---------------------------------------------
|--------------:|------------:|------------:|-------:|----------:|
| IsItemSpecModifier_AllModifiers | 151.425 ns | 0.1309 ns | 0.1161 ns |
- | - |
| IsDerivableItemSpecModifier_RecursiveDir | 2.522 ns | 0.0028 ns |
0.0025 ns | - | - |
| GetItemSpecModifier_FullPath | 267.552 ns | 0.3441 ns | 0.3050 ns | -
| - |
| GetItemSpecModifier_Directory | 359.023 ns | 0.7603 ns | 0.6740 ns |
0.0224 | 376 B |
| GetItemSpecModifier_ModifiedTime | 28,544.061 ns | 237.0185 ns |
221.7073 ns | - | 176 B |
| GetItemSpecModifier_DefiningProjectDirectory | 812.229 ns | 3.3636 ns
| 2.9817 ns | 0.0315 | 536 B |
| TaskItem_AllDerivableModifiers_Once | 434.5 ns | 4.36 ns | 4.08 ns |
0.0734 | 1232 B |
| TaskItem_FilenameAndExtension_Repeated | 908.5 ns | 1.13 ns | 1.00 ns
| 0.0381 | 640 B |
| TaskItem_Filename_ManyItems | 9,651.3 ns | 29.02 ns | 25.72 ns |
0.4730 | 7920 B |
| TaskItem_FullPathDerivedModifiers_Repeated | 2,127.6 ns | 7.45 ns |
6.60 ns | 0.4234 | 7120 B |
| ProjectItemInstance_AllDerivableModifiers_Once | 513.4 ns | 2.93 ns |
2.74 ns | 0.0772 | 1296 B |
| ProjectItemInstance_FilenameExtension_AllItems | 22,697.6 ns | 68.62
ns | 64.19 ns | 0.8545 | 14384 B |
| ProjectItemInstance_FilenameExtension_AllItems_Repeated | 181,612.2 ns
| 1,125.69 ns | 940.00 ns | 8.5449 | 143840 B |
| ProjectItemInstance_AllDefiningProjectModifiers_Once | 1.559 μs |
0.0047 μs | 0.0040 μs | 0.0572 | 976 B |
| ProjectItemInstance_DefiningProjectDirectory_Repeated | 9.092 μs |
0.0654 μs | 0.0580 μs | 0.4883 | 8304 B |
|
ProjectItemInstance_DefiningProjectNameExtension_AllItems_SingleProject
| 12.515 μs | 0.0297 μs | 0.0263 μs | 0.5188 | 8864 B |
| ProjectItemInstance_DefiningProjectFullPath_AllItems_MultiProject |
35.245 μs | 0.0405 μs | 0.0379 μs | - | 64 B |
|
ProjectItemInstance_DefiningProjectDirectory_AllItems_MultiProject_Repeated
| 878.931 μs | 3.1495 μs | 2.7919 μs | 48.8281 | 824640 B |
| TaskItem_AllDefiningProjectModifiers_Once | 1.430 μs | 0.0027 μs |
0.0023 μs | 0.0534 | 912 B |
| TaskItem_DefiningProjectNameExtension_AllItems | 11.628 μs | 0.0289 μs
| 0.0241 μs | 0.5188 | 8800 B |
| TaskItem_DefiningProjectDirectory_Repeated | 9.121 μs | 0.0192 μs |
0.0170 μs | 0.4883 | 8240 B |

### .NET Framework 4.8.1

| Method | Mean | Error | StdDev | Gen0 | Allocated |
|---------------------------------------------
|-------------:|-----------:|----------:|-------:|----------:|
| IsItemSpecModifier_AllModifiers | 227.45 ns | 0.297 ns | 0.264 ns | -
| - |
| IsDerivableItemSpecModifier_RecursiveDir | 10.49 ns | 0.019 ns | 0.018
ns | - | - |
| GetItemSpecModifier_FullPath | 1,267.45 ns | 0.844 ns | 0.705 ns | - |
- |
| GetItemSpecModifier_Directory | 2,433.43 ns | 7.400 ns | 6.560 ns |
0.0954 | 517 B |
| GetItemSpecModifier_ModifiedTime | 41,881.06 ns | 111.954 ns | 93.487
ns | 0.1221 | 878 B |
| GetItemSpecModifier_DefiningProjectDirectory | 5,467.24 ns | 8.295 ns
| 6.926 ns | 0.1602 | 857 B |
| TaskItem_AllDerivableModifiers_Once | 5.322 μs | 0.0354 μs | 0.0331 μs
| 0.3662 | 1923 B |
| TaskItem_FilenameAndExtension_Repeated | 10.238 μs | 0.0108 μs |
0.0101 μs | 0.1373 | 761 B |
| TaskItem_Filename_ManyItems | 110.078 μs | 0.1367 μs | 0.1212 μs |
2.3193 | 12379 B |
| TaskItem_FullPathDerivedModifiers_Repeated | 26.619 μs | 0.1695 μs |
0.1585 μs | 2.1973 | 11578 B |
| ProjectItemInstance_AllDerivableModifiers_Once | 5.525 μs | 0.0311 μs
| 0.0276 μs | 0.3662 | 1959 B |
| ProjectItemInstance_FilenameExtension_AllItems | 216.406 μs | 0.2767
μs | 0.2160 μs | 2.9297 | 16422 B |
| ProjectItemInstance_FilenameExtension_AllItems_Repeated | 2,161.623 μs
| 10.4073 μs | 9.2258 μs | 31.2500 | 164225 B |
| ProjectItemInstance_AllDefiningProjectModifiers_Once | 9.808 μs |
0.0177 μs | 0.0165 μs | 0.2594 | 1418 B |
| ProjectItemInstance_DefiningProjectDirectory_Repeated | 64.204 μs |
0.3983 μs | 0.3726 μs | 2.3193 | 12616 B |
|
ProjectItemInstance_DefiningProjectNameExtension_AllItems_SingleProject
| 131.504 μs | 0.3383 μs | 0.3165 μs | 2.1973 | 12456 B |
| ProjectItemInstance_DefiningProjectFullPath_AllItems_MultiProject |
173.171 μs | 0.7242 μs | 0.5654 μs | - | 38 B |
|
ProjectItemInstance_DefiningProjectDirectory_AllItems_MultiProject_Repeated
| 6,399.063 μs | 71.6927 μs | 67.0614 μs | 234.3750 | 1242225 B |
| TaskItem_AllDefiningProjectModifiers_Once | 8.636 μs | 0.0177 μs |
0.0147 μs | 0.2594 | 1382 B |
| TaskItem_DefiningProjectNameExtension_AllItems | 126.982 μs | 0.2250
μs | 0.2104 μs | 2.1973 | 12420 B |
| TaskItem_DefiningProjectDirectory_Repeated | 58.025 μs | 0.1388 μs |
0.1299 μs | 2.3804 | 12579 B |

## Final Benchmark Results

### .NET 10.0

| Method | Mean | Error | StdDev | Gen0 | Allocated |
|---------------------------------------------
|--------------:|------------:|------------:|-------:|----------:|
| IsItemSpecModifier_AllModifiers | 38.4923 ns | 0.5501 ns | 0.5145 ns |
- | - |
| IsDerivableItemSpecModifier_RecursiveDir | 0.0000 ns | 0.0000 ns |
0.0000 ns | - | - |
| GetItemSpecModifier_FullPath | 260.1019 ns | 0.3623 ns | 0.3212 ns | -
| - |
| GetItemSpecModifier_Directory | 413.2121 ns | 1.9441 ns | 1.8185 ns |
0.0224 | 376 B |
| GetItemSpecModifier_ModifiedTime | 30,272.3116 ns | 408.0450 ns |
381.6855 ns | - | 176 B |
| GetItemSpecModifier_DefiningProjectDirectory | 72.3691 ns | 0.0289 ns
| 0.0270 ns | - | - |
| TaskItem_AllDerivableModifiers_Once | 87.41 ns | 0.226 ns | 0.200 ns |
- | - |
| TaskItem_FilenameAndExtension_Repeated | 173.68 ns | 1.812 ns | 1.695
ns | - | - |
| TaskItem_Filename_ManyItems | 1,856.79 ns | 1.128 ns | 0.942 ns | - |
- |
| TaskItem_FullPathDerivedModifiers_Repeated | 321.57 ns | 0.301 ns |
0.267 ns | - | - |
| ProjectItemInstance_AllDerivableModifiers_Once | 143.78 ns | 0.493 ns
| 0.462 ns | 0.0038 | 64 B |
| ProjectItemInstance_FilenameExtension_AllItems | 5,343.30 ns | 4.955
ns | 4.138 ns | - | 64 B |
| ProjectItemInstance_FilenameExtension_AllItems_Repeated | 67,028.30 ns
| 252.985 ns | 224.264 ns | - | 640 B |
| ProjectItemInstance_AllDefiningProjectModifiers_Once | 459.4 ns | 0.34
ns | 0.31 ns | 0.0038 | 64 B |
| ProjectItemInstance_DefiningProjectDirectory_Repeated | 1,020.5 ns |
0.56 ns | 0.47 ns | 0.0038 | 64 B |
|
ProjectItemInstance_DefiningProjectNameExtension_AllItems_SingleProject
| 20,091.0 ns | 17.96 ns | 16.80 ns | - | 64 B |
| ProjectItemInstance_DefiningProjectFullPath_AllItems_MultiProject |
9,946.7 ns | 5.28 ns | 4.68 ns | - | 64 B |
|
ProjectItemInstance_DefiningProjectDirectory_AllItems_MultiProject_Repeated
| 103,960.5 ns | 57.74 ns | 48.21 ns | - | 640 B |
| TaskItem_AllDefiningProjectModifiers_Once | 400.5 ns | 0.15 ns | 0.12
ns | - | - |
| TaskItem_DefiningProjectNameExtension_AllItems | 19,150.3 ns | 11.55
ns | 10.24 ns | - | - |
| TaskItem_DefiningProjectDirectory_Repeated | 970.8 ns | 0.62 ns | 0.55
ns | - | - |

### .NET Framework 4.8.1

| Method | Mean | Error | StdDev | Gen0 | Allocated |
|---------------------------------------------
|-------------:|-----------:|----------:|-------:|----------:|
| IsItemSpecModifier_AllModifiers | 106.532 ns | 0.4289 ns | 0.4012 ns |
- | - |
| IsDerivableItemSpecModifier_RecursiveDir | 5.067 ns | 0.0031 ns |
0.0024 ns | - | - |
| GetItemSpecModifier_FullPath | 1,331.138 ns | 1.4666 ns | 1.3001 ns |
- | - |
| GetItemSpecModifier_Directory | 2,471.887 ns | 4.2333 ns | 3.7527 ns |
0.0954 | 517 B |
| GetItemSpecModifier_ModifiedTime | 44,773.794 ns | 405.2647 ns |
359.2566 ns | 0.1221 | 878 B |
| GetItemSpecModifier_DefiningProjectDirectory | 156.840 ns | 0.2242 ns
| 0.1987 ns | - | - |
| TaskItem_AllDerivableModifiers_Once | 507.2 ns | 1.19 ns | 1.11 ns | -
| - |
| TaskItem_FilenameAndExtension_Repeated | 664.7 ns | 0.39 ns | 0.35 ns
| - | - |
| TaskItem_Filename_ManyItems | 6,916.2 ns | 4.03 ns | 3.77 ns | - | - |
| TaskItem_FullPathDerivedModifiers_Repeated | 2,261.6 ns | 3.34 ns |
2.96 ns | - | - |
| ProjectItemInstance_AllDerivableModifiers_Once | 688.6 ns | 1.01 ns |
0.94 ns | 0.0067 | 36 B |
| ProjectItemInstance_FilenameExtension_AllItems | 20,366.3 ns | 11.28
ns | 10.56 ns | - | 36 B |
| ProjectItemInstance_FilenameExtension_AllItems_Repeated | 202,570.4 ns
| 271.12 ns | 240.34 ns | - | 362 B |
| ProjectItemInstance_AllDefiningProjectModifiers_Once | 1,153.5 ns |
13.83 ns | 12.26 ns | 0.0057 | 36 B |
| ProjectItemInstance_DefiningProjectDirectory_Repeated | 2,795.7 ns |
17.33 ns | 16.21 ns | 0.0038 | 36 B |
|
ProjectItemInstance_DefiningProjectNameExtension_AllItems_SingleProject
| 46,236.9 ns | 105.16 ns | 93.22 ns | - | 36 B |
| ProjectItemInstance_DefiningProjectFullPath_AllItems_MultiProject |
28,362.1 ns | 34.50 ns | 30.58 ns | - | 36 B |
|
ProjectItemInstance_DefiningProjectDirectory_AllItems_MultiProject_Repeated
| 282,316.9 ns | 1,944.00 ns | 1,818.42 ns | - | 364 B |
| TaskItem_AllDefiningProjectModifiers_Once | 965.3 ns | 5.43 ns | 4.53
ns | - | - |
| TaskItem_DefiningProjectNameExtension_AllItems | 42,707.8 ns | 179.84
ns | 168.23 ns | - | - |
| TaskItem_DefiningProjectDirectory_Repeated | 2,539.1 ns | 9.64 ns |
8.05 ns | - | - |
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.