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

Split functions within the step folder into .hpp and .cpp files #279

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

ddement
Copy link
Collaborator

@ddement ddement commented Sep 25, 2024

This commit should improve compile times for incremental builds quite significantly, depending on where you're making your changes. Note that it seems to slow down building from scratch by a little bit (about 20-50%).

The functions in this folder mark the transition from a high level "pass around the structs" workflow to actually calling the kernels that do the work, so they are a reasonable place to provide the split to get the most "bang for our buck" with incremental compile time improvements.

@ddement ddement self-assigned this Sep 25, 2024
@ddement ddement marked this pull request as ready for review September 25, 2024 20:29
Copy link
Collaborator

@deslaughter deslaughter left a comment

Choose a reason for hiding this comment

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

I don't think forward declaring the structs in the header files is a good idea. I understand that it allows the headers to be decoupled, but then if you want to actually use those headers you have to track down the origin of each type that has been forward declared. This makes the library harder to use and is likely to frustrate the users. I'd recommend going ahead and referencing the appropriate includes.

We can add more lines to this file depending on how people end up interfacing with the code,
but this is a good starting point.
@ddement ddement force-pushed the compile_step branch 2 times, most recently from a6b5d69 to 5c8ffab Compare October 21, 2024 13:52
@ddement
Copy link
Collaborator Author

ddement commented Oct 21, 2024

I've added the top-level openturbine.hpp for users to include rather than being fine-grained with their includes. I'm open to adding more to this, but I figured this was a good first set of files and the bare minimum for using OpenTurbine.

Let me know if this looks good or if you'd still prefer to include in the lower level headers.

Copy link
Collaborator

Choose a reason for hiding this comment

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

What is the intent for this file?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This file is to provide a convenience header for users to include rather than having to know which ones they really want. For example, if they want our step function and all of the structs that it depends on, they would otherwise have to include 5 different headers. Before this change, they would have gotten them all from including step.hpp, but this is violating the guideline of including what you use and sets them up for breakage if we make any changes.

Internally, we should not use this header and continue including everything we want directly.

Comment on lines +4 to +5
struct Solver;
struct Constraints;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This makes me nervous -- why are we using forward declarations here? I think the risks outweigh the compile-time savings here (e.g. unit testing this -- would there be surprises?). For what it's worth, Google's style guild also discourages it.

https://google.github.io/styleguide/cppguide.html#Forward_Declarations

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Forward declarations are good for decreasing compile times and binary size, but are also for decoupling our code and ensuring that we are doing a good job of managing our dependencies.

an example: in our unit tests, we created and manipulated the Constraints and StepParameters structs. However, we never actually included them, instead getting their code transitively from Step.hpp. A change in our code layout broke our tests and could break user code.

Their cautionary tales against the forward declaration seem to pertain to using a forward declaration within an implementation. I agree that this is bad. I don't think they apply when using forward declarations when defining your interface, which is common practice.

);
}
}
void AssembleConstraintsMatrix(Solver& solver, const Constraints& constraints);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we have a policy on declaring parameter names (which are not primitive) in the headers-only files? For example, would the following be cleaner?

void AssembleConstraintsMatrix(Solver&, const Constraints&);

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think we have a policy for this yet. I don't have a strong opinion about which I prefer.

@faisal-bhuiyan
Copy link
Collaborator

The functions in this folder mark the transition from a high level "pass around the structs" workflow to actually calling the kernels that do the work, so they are a reasonable place to provide the split to get the most "bang for our buck" with incremental compile time improvements.

Just wondering if any other parts of openturbine might benefit from such a split -- what are your thoughts? Is maintaining a mix of header-only files + splitting them out as appropriate the optimal path?

@ddement
Copy link
Collaborator Author

ddement commented Oct 22, 2024

The functions in this folder mark the transition from a high level "pass around the structs" workflow to actually calling the kernels that do the work, so they are a reasonable place to provide the split to get the most "bang for our buck" with incremental compile time improvements.

Just wondering if any other parts of openturbine might benefit from such a split -- what are your thoughts? Is maintaining a mix of header-only files + splitting them out as appropriate the optimal path?

Maybe, but I don't think so. This split already slows down our compile times from scratch significantly. Truth be told, I'm not even sure if this change is a good idea (I put it together hoping it would be a massive, unqualified win). If we ever decide to do any templating on these functions, we'll have to pull them back into header files, for example.

This break location was also chosen because it has the best chance of insulating our users from long compile times (they will mostly use the functions in the step folder). Given our discussions in recent weeks about how we want our users to interact with OpenTurbine, it may make sense to compile to objects at that higher level interface and make most things below it be headers.

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.

3 participants