dotnet / dotnet/msbuild

Node assignments pessimized in multitargeted->multitargeted refs with `BuildProjectReferences=false`

Open
#8,563 1 comment 1 reaction 0 assignees View on GitHub
Area: Engine backlog needs-design Priority:2 triaged
Dominant language
C#
Stars
5.5k
Forks
1.5k
Avg merge
1d 6h
Merged PRs (30d)
139

Description

Given a project that itself multitargets and references several multitargeted projects, like [pessimized_node_assignments.zip](https://github.com/dotnet/msbuild/files/10969331/pessimized_node_assignments.zip), the scheduler does a terrible job spreading the work around among nodes when the referencing project (here `Aggregate\Aggregate.csproj`) is built with `-p:BuildProjectReferences=false -m:3 -nr:false`.

The true optimal node count and scheduling for such a system may not be knowable, but `number_of_nodes = number_of_TargetFrameworks` seems like a very reasonable guess.

From my debugging, what's going wrong is that we have these dependencies (filtered to a single reference):

```mermaid
graph TD
subgraph Aggregate
Aggregate_outer
Aggregate_net5
Aggregate_net6
Aggregate_net7
end
subgraph Lib1
Lib1_outer
Lib1_net5
Lib1_net6
Lib1_net7
end
Aggregate_outer -->|Build| Aggregate_net5
Aggregate_outer -->|Build| Aggregate_net6
Aggregate_outer -->|Build| Aggregate_net7
Aggregate_net5 -->|GetTargetFrameworks| Lib1_outer
Aggregate_net6 -->|GetTargetFrameworks| Lib1_outer
Aggregate_net7 -->|GetTargetFrameworks| Lib1_outer

Lib1_outer -->|GetTargetFrameworksWithPlatformForSingleTargetFramework| Lib1_net5
Lib1_outer -->|GetTargetFrameworksWithPlatformForSingleTargetFramework| Lib1_net6
Lib1_outer -->|GetTargetFrameworksWithPlatformForSingleTargetFramework| Lib1_net7

Aggregate_net5 -->|GetTargetPath| Lib1_net5
Aggregate_net6 -->|GetTargetPath| Lib1_net6
Aggregate_net7 -->|GetTargetPath| Lib1_net7
```

Unfortunately, the calls to `GetTargetFrameworksWithPlatformForSingleTargetFramework` are all getting assigned to `node 1`, locking the inner builds for all referenced projects to that node. That node is also used to do actual build work for one of the inner builds of `Aggregate`, which blocks work that should be able to run in parallel for the other inner builds:

![image](https://user-images.githubusercontent.com/3347530/225066388-eb950826-5a05-482e-a5b3-59f7a266b179.png)

@dfederm has observed worse cascading where all of the inner builds were serialized on real-world projects.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.