Skip to content

Turn On Cross-Module Incremental Builds! #34196

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

Merged
merged 6 commits into from
Oct 7, 2020
Merged

Conversation

CodaFi
Copy link
Contributor

@CodaFi CodaFi commented Oct 6, 2020

Cross-Module incremental dependencies are a new experimental mode of the Swift driver and frontend. Through a tight partnership between the two, we enable the driver to have far greater visibility into the dependency structure of a Swift module.

Rather than invent a new model, we have chosen to extend the existing incremental compilation model that works for a single module to multiple modules. To do this, we need the frontend to emit Swift dependencies in a form the driver can consume. We could emit these metadata in the form of an extra supplementary output that summarizes the contents of a generated module. However, this approach comes with a number of downsides:

  • It requires additional integration with the build system
  • It assumes swiftmodule files will be consumed directly from the build directory; they are not
  • It incorrectly assumes a swiftmodule has but one interface. Taken in aggregate, a swiftmodule directory has one interface per triple

Given this, the approach we take here is to encode these dependencies directly into the swiftmodule file itself. When frontends load these souped-up incremental swiftmodule files, they record in their own swiftdeps files that they depend on an incremental swiftmodule. Upon the next build, the driver is then able to read that module file, extract the swiftdeps information from it, and use it to influence the way it schedules jobs.

The sum total is that we neatly extend the intra-module case of incremental builds to the inter-module case by treating swiftmodule inputs not as opaque entities, but as "big ol' flat Swift files" that just export an interface like any other Swift file within the module. As a further optimization, and because clients literally cannot observe this aspect of the incremental build, we only serialize the provides (the "defs" side of a "use-def" edge) when emitting swiftdeps metadata into swiftmodule files.

To build a module with cross-module incremental metadata, the unstable flag -enable-experimental-cross-module-incremental-build must be provided to all driver invocations of the relevant targets. Any swiftmodule files without incremental metadata sections present are treated according to the status quo.

rdar://69595010

CodaFi added 3 commits October 5, 2020 18:40
llvm-bcanalyzer does *not* like it when there are multiple block info metadata blocks in the same bitstream file. This patch will skip the emission of that and just jump straight to the metadata block when we're not reading a "standalone" incremental dependency file. While I'm here, also add the right block abbreviation info so we can get a decent dump from llvm-bcanalyzer
…pendencies

Register the module the external dependencies ride in with the pseudo-job in the Driver. This is a hack.
Cross-Module incremental dependencies are a new experimental mode of the Swift driver and frontend. Through a tight partnership between the two, we enable the driver to have far greater visibility into the dependency structure of a Swift module.

Rather than invent a new model, we have chosen to extend the existing incremental compilation model that works for a single module to multiple modules. To do this, we need the frontend to emit Swift dependencies in a form the driver can consume. We could emit these metadata in the form of an extra supplementary output that summarizes the contents of a generated module. However, this approach comes with a number of downsides:

- It requires additional integration with the build system
- It assumes swiftmodule files will be consumed directly from the build directory; they are not
- It incorrectly assumes a swiftmodule has but one interface. Taken in aggregate, a swiftmodule directory has one interface *per triple*

Given this, the approach we take here is to encode these dependencies directly into the swiftmodule file itself. When frontends load these souped-up incremental swiftmodule files, they record in their own swiftdeps files that they depend on an incremental swiftmodule. Upon the next build, the driver is then able to read that module file, extract the swiftdeps information from it, and use it to influence the way it schedules jobs.

The sum total is that we neatly extend the intra-module case of incremental builds to the inter-module case by treating swiftmodule inputs not as opaque entities, but as "big ol' flat Swift files" that just export an interface like any other Swift file within the module. As a further optimization, and because clients literally cannot observe this aspect of the incremental build, we only serialize the provides (the "defs" side of a "use-def" edge) when emitting swiftdeps metadata into swiftmodule files.

rdar://69595010
@CodaFi CodaFi requested a review from davidungar October 6, 2020 02:02
@CodaFi
Copy link
Contributor Author

CodaFi commented Oct 6, 2020

@swift-ci test

Copy link
Contributor

@davidungar davidungar left a comment

Choose a reason for hiding this comment

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

Fantastic to turn this on! Everything I wrote is a nit, with the possible exception of the "why not track cached...".

Comment on lines -281 to -282
assert(getSwiftDeps(iter->second) == swiftDeps.getValue() &&
"jobsBySwiftDeps should be inverse of getSwiftDeps.");
Copy link
Contributor

Choose a reason for hiding this comment

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

I bet you have a good argument for dispensing with this assertion. What is it?

Comment on lines +993 to +1004

if (dependencyTracker && file) {
auto DepPath = file->getFilename();
// Don't record cached artifacts as dependencies.
if (!isCached(DepPath)) {
if (M->hasIncrementalInfo()) {
dependencyTracker->addIncrementalDependency(DepPath);
} else {
dependencyTracker->addDependency(DepPath, /*isSystem=*/false);
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

my own style would be to factor these lines out into a function, "trackDependency" or some such.
Also, it would be helpful to add a "why" to the comment on 996. (Why not record cached artifacts?)

@swift-ci
Copy link
Contributor

swift-ci commented Oct 6, 2020

Build failed
Swift Test Linux Platform
Git Sha - ea444de031e532cd4313d0a3ec8de0d054a24167

@tschuett
Copy link
Contributor

tschuett commented Oct 6, 2020

Is there going to be a file in the docs directory about Cross-Module Incremental Builds?

@CodaFi
Copy link
Contributor Author

CodaFi commented Oct 6, 2020

@tschuett We're hoping to eventually just scrap this flag and turn this on for every incremental build after this gets battle tested. It should be completely seamless from an end-user's perspective. From an implementation perspective, I could write some words into DriverInternals.md about the presence of swiftdeps info in swiftmodule files being a thing you can't rely on. Was that what you had in mind?

It doesn't seem to like the output file maps I've written here.
@CodaFi
Copy link
Contributor Author

CodaFi commented Oct 6, 2020

@swift-ci test

@CodaFi
Copy link
Contributor Author

CodaFi commented Oct 6, 2020

@swift-ci test Windows

@tschuett
Copy link
Contributor

tschuett commented Oct 6, 2020

Anything is fine, but all the documentation is in the commit message, which nobody will ever find.

I don't care about the flag. The feature/implementation seems to be interesting.

@swift-ci
Copy link
Contributor

swift-ci commented Oct 6, 2020

Build failed
Swift Test OS X Platform
Git Sha - 00d8e3c

@swift-ci
Copy link
Contributor

swift-ci commented Oct 6, 2020

Build failed
Swift Test Linux Platform
Git Sha - 00d8e3c

@swift-ci
Copy link
Contributor

swift-ci commented Oct 7, 2020

Build failed
Swift Test OS X Platform
Git Sha - 00d8e3c

@CodaFi CodaFi merged commit 245ace3 into swiftlang:main Oct 7, 2020
@CodaFi CodaFi deleted the crossbeam branch October 7, 2020 06:04
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.

4 participants