Skip to content

Conversation

@omajid
Copy link
Member

@omajid omajid commented Jul 29, 2025

When writing out the .deps.json file through DependencyContextCreator, sort as much information as possible to ensure a stable order of the file contents. This helps make application builds deterministic.

Contribute to dotnet/source-build#4963

@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Jul 29, 2025
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Jul 29, 2025
{
jsonWriter.WriteStartObject(DependencyContextStrings.RuntimesPropertyName);
foreach (RuntimeFallbacks runtimeFallback in context.RuntimeGraph)
foreach (RuntimeFallbacks runtimeFallback in context.RuntimeGraph.OrderBy(r => r.Runtime, StringComparer.Ordinal))
Copy link
Member Author

Choose a reason for hiding this comment

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

Is there a risk of this breaking how the runtime fallback is computed/used?

Copy link
Member

Choose a reason for hiding this comment

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

@ericstj / @ViktorHofer Can one of you weigh in on if this can affect behavior adversely?

Copy link
Member

Choose a reason for hiding this comment

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

The host implements runtime lookup. @elinor-fung I would expect that nothing here is order dependent since the host should be probing in the order defined in the runtimes section of the shared-framework's deps file.

Copy link
Member

Choose a reason for hiding this comment

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

The order does matter for RID fallbacks, as the host uses the order of the fallbacks as defined in the .deps.json. This can be a shared framework's deps file or that for the app itself (for example, self-contained) - both should be created by this writer.

The order of the RuntimeFallbacks objects shouldn't matter (this line), but the order of the fallbacks array (line 65) definitely does. That is, a fallback array of [ "linux", "unix-x64", "unix", "any", "base" ] needs to stay in that order and should not become [ "any", "base", "linux", "unix", "unix-x64" ].


private static void AddResourceAssemblies(IReadOnlyList<ResourceAssembly> resourceAssemblies, Utf8JsonWriter jsonWriter)
{
resourceAssemblies = resourceAssemblies.OrderBy(r => r.Path, StringComparer.Ordinal).ToList();
Copy link
Member Author

Choose a reason for hiding this comment

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

This was one of the biggest culprits, leading to unpredictable order of resource dlls in deps.json files.

Copy link
Member

Choose a reason for hiding this comment

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

What made the earlier part of the build non-deterministic in how it passed these in? Typically the order of things in the file, the order in which the filesystem enumerates, etc is deterministic. It's when folks do things like shove them into a dictionary/hashtable then dump that back out that the order becomes non-deterministic.

I'm not too familiar with how much we resign to sorting to solve determinism problems vs rooting out unintentional disorder. Sorting is certainly a more stable solution, but it does burn cycles. I would be interested in hearing from @dsplaisted about this.

Copy link
Member

Choose a reason for hiding this comment

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

the order in which the filesystem enumerates

this is not guaranteed though

from Linux readdir

The order in which filenames are read by successive calls to readdir() depends on the filesystem implementation; it is unlikely that the names will be sorted in any fashion.

and on Windows FindNextFileA:

The order in which this function returns the file names is dependent on the file system type. With the NTFS file system and CDFS file systems, the names are usually returned in alphabetical order. With FAT file systems, the names are usually returned in the order the files were written to the disk, which may or may not be in alphabetical order. However, as stated previously, these behaviors are not guaranteed.

Copy link
Member

Choose a reason for hiding this comment

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

And MSBuild doesn't ensure it either? Is everything that consumes items in the build meant to sort them in order to be deterministic? @rainersigwald

I'm just imagining that we all do less work if the inputs are stable and no one needs to sort than if we all assume inputs are not stable and everyone must sort. I'd prefer a world where every component just preserves input derived order and doesn't apply its own sorting.

Copy link
Member

Choose a reason for hiding this comment

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

I'd prefer a world where every component just preserves input derived order and doesn't apply its own sorting.

This is mostly what MSBuild does--for globs we just preserve filesystem order, and other item operations are order-preserving.

Copy link
Member

Choose a reason for hiding this comment

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

So presumably that can be done here instead of adding all this sorting. @omajid - do you have a couple example binlogs that show where the ordering gets mixed up? (Bonus if we find and fix a determinism bug that is impacting multiple components instead of just this one).

When writing out the .deps.json file through DependencyContextCreator,
sort as much information as possible to ensure a stable order of the
file contents. This helps make application builds deterministic.

Contributes to: dotnet/source-build#4963
@omajid omajid force-pushed the deps-json-stable-order branch from a0a2f74 to beaf7ff Compare August 7, 2025 22:28
@vcsjones vcsjones added area-DependencyModel and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Aug 15, 2025
@dotnet-policy-service
Copy link
Contributor

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

@ericstj
Copy link
Member

ericstj commented Sep 2, 2025

It would be good to measure if this will impact performance of SDK builds. cc @dsplaisted
You can have a look at the time spent in GenerateDepsFile for a sufficiently complex application with and without this change to see if will be noticeable.

@ericstj
Copy link
Member

ericstj commented Sep 16, 2025

@omajid pinging on this one - conclusion was we should root out the source of disorder on a single machine in the build rather than forcing sorting. I'd be happy to work with you on this. I think we should find a case where reordering happens and then look at binlog before/after.

@ericstj ericstj added the needs-author-action An issue or pull request that requires more info or actions from the author. label Sep 16, 2025
@dotnet-policy-service
Copy link
Contributor

This pull request has been automatically marked no-recent-activity because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will remove no-recent-activity.

@dotnet-policy-service
Copy link
Contributor

This pull request will now be closed since it had been marked no-recent-activity but received no further activity in the past 14 days. It is still possible to reopen or comment on the pull request, but please note that it will be locked if it remains inactive for another 30 days.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-DependencyModel community-contribution Indicates that the PR has been added by a community member needs-author-action An issue or pull request that requires more info or actions from the author. no-recent-activity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants