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

Reduce Optional_string usage #9232

Merged
merged 14 commits into from
Jan 19, 2022
Merged

Reduce Optional_string usage #9232

merged 14 commits into from
Jan 19, 2022

Conversation

jasondegraw
Copy link
Member

Pull request overview

Reduce the usage of the various forms of string optional arguments by about 50%. In many cases, the optional can be replaced with a std::string_view and the presence of the string can be checked with the empty method. Most of the remaining cases either require a deeper refactor or are too tied up with other ongoing refactors that there's not a good way to get at changing just the optional argument. In a few situations, overloading has been used to shift run-time choices of behavior to compile-time choices of behavior, so there may be a (very) small performance benefit from this PR.

Pull Request Author

Add to this list or remove from it as applicable. This is a simple templated set of guidelines.

  • Title of PR should be user-synopsis style (clearly understandable in a standalone changelog context)
  • Label the PR with at least one of: Defect, Refactoring, NewFeature, Performance, and/or DoNoPublish
  • Author should provide a "walkthrough" of relevant code changes using a GitHub code review comment process
  • If changes fix a defect, the fix should be demonstrated in plots and descriptions

Reviewer

This will not be exhaustively relevant to every PR.

  • Perform a Code Review on GitHub
  • If branch is behind develop, merge develop and build locally to check for side effects of the merge
  • If defect, verify by running develop branch and reproducing defect, then running PR and reproducing fix
  • If feature, test running new feature, try creative ways to break it
  • CI status: all green or justified
  • Check that performance is not impacted (CI Linux results include performance check)
  • Run Unit Test(s) locally
  • Check any new function arguments for performance impacts
  • Verify IDF naming conventions and styles, memos and notes and defaults
  • If new idf included, locally check the err file and other outputs

@jasondegraw jasondegraw added the Refactoring Includes code changes that don't change the functionality of the program, just perform refactoring label Jan 12, 2022
@@ -15687,8 +15687,8 @@ void GetDXCoilIndex(EnergyPlusData &state,
std::string const &DXCoilName,
int &DXCoilIndex,
bool &ErrorsFound,
Optional_string_const ThisObjectType,
Optional_bool_const SuppressWarning)
std::string_view const ThisObjectType,
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 one is a good example of the easier changes. The argument is only used for errors, so the argument type is changed first.

} else {
if (present(ThisObjectType)) {
ShowSevereError(state, ThisObjectType + ", GetDXCoilIndex: DX Coil not found=" + DXCoilName);
if (!ThisObjectType.empty()) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Then the call to present is changed to use the empty method.

if (present(ThisObjectType)) {
ShowSevereError(state, ThisObjectType + ", GetDXCoilIndex: DX Coil not found=" + DXCoilName);
if (!ThisObjectType.empty()) {
ShowSevereError(state, fmt::format("{}, GetDXCoilIndex: DX Coil not found={}", ThisObjectType, DXCoilName));
Copy link
Member Author

Choose a reason for hiding this comment

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

And finally the string handling is changed to something compatible with string_view.

bool &ErrorsFound,
Optional_string_const CheckName,
Optional_int_const CheckNumber,
Optional_string_const ObjectName)
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 function was checking for uniqueness of an optional name or optional number based on the string in CheckType... which appears to always be one of two literal strings... so known at runtime. Replace that with two functions, one that checks for name and one that checks for number.

@@ -15720,7 +15719,7 @@ void GetDXCoilIndex(EnergyPlusData &state,
}

std::string
GetDXCoilName(EnergyPlusData &state, int &DXCoilIndex, bool &ErrorsFound, Optional_string_const ThisObjectType, Optional_bool_const SuppressWarning)
GetDXCoilName(EnergyPlusData &state, int &DXCoilIndex, bool &ErrorsFound, std::string_view const ThisObjectType, bool const SuppressWarning)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Functions like this should not be necessary. This should just be state.dataDXCoils->DXCoils(DXCoilNum).Name. The error checking and defaulting should not be necessary. You should not need to call a function to grab a field of an object whose index is known. I understand that this has nothing to do with this PR, but this is as good a place as any for me to hang this comment.

Copy link
Member Author

Choose a reason for hiding this comment

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

These functions should hopefully only get called during the input phase, but (a) good point and (b) I agree.


std::string GetDXCoilName(
EnergyPlusData &state, int &DXCoilIndex, bool &ErrorsFound, Optional_string_const ThisObjectType, Optional_bool_const SuppressWarning);
EnergyPlusData &state, int &DXCoilIndex, bool &ErrorsFound, std::string_view const ThisObjectType = {}, bool const SuppressWarning = false);

Real64 GetCoilCapacity(EnergyPlusData &state,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same thing.

@@ -92,7 +92,7 @@ namespace DataSurfaceColors {
std::string const &ColorType // for now, must be DXF
);

void SetUpSchemeColors(EnergyPlusData &state, std::string const &SchemeName, Optional_string_const ColorType = _);
void SetUpSchemeColors(EnergyPlusData &state, std::string const &SchemeName, std::string const &ColorType);
Copy link
Collaborator

Choose a reason for hiding this comment

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

std::string_view

@@ -1249,17 +1249,87 @@ int InputProcessor::getObjectItemNum(EnergyPlusData &state,
return getIDFObjNum(state, ObjType, object_item_num); // if incoming input is idf, then return idf object order
}

void InputProcessor::lowerRangeCheck(EnergyPlusData &state,
Copy link
Collaborator

Choose a reason for hiding this comment

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

General comment about functions like these. You are passing 9 parameters to this function, 8 of which are only needed in the case of an error, which is presumably rare. This is MCCS (Make the Common Case Slow) 101. If you want to make a function out of the error message code itself, okay. But do the range check at the call site and only call that function if there is an actual error.

Copy link
Member Author

Choose a reason for hiding this comment

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

I went ahead and refactored the function that got split into this one and the other one below, but this only gets used in WeatherManager regardless of whether it was intended to be a general use function. That's another argument for it to go.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah. More important than this specific function, however, is the general lesson and pattern. One of the tenets of high-performance (or at least not terrible-performance) programming is "Make the Common Case Fast". Setting up parameters takes time. Don't take that time if those parameters will only be used infrequently, e.g., in the case of an error. Another example I see quite a bit of is functions that have many options that tweak their behavior in different ways. Yes, you are "reusing code" and that's good, but even good things can be taken too far. If those options are rarely used, then you're slowing down the more frequent instances of the function.

These "rules of thumb" are obvious once someone points them out to you. And they are invaluable. I learned this one in my second year graduate computer architecture class. MCCF is the rule of thumb for computer hardware design, and it applies to software just as well.

}
}
}

void InputProcessor::rangeCheck(EnergyPlusData &state,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same comment as above. Understand that this is not part of this PR, but if I see something I'm going to say something.

Optional_string_const MaxString // Maximum indicator ('<', ',=')
int const ScheduleIndex, // Which Day Schedule being tested
Real64 const Minimum, // Minimum desired value
bool const exclusiveMin, // Minimum indicator ('>', '>=')
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

_,
_,
state.dataEnvrn->WeatherFileLocationTitle);
state.dataInputProcessing->inputProcessor->lowerRangeCheck(state,
Copy link
Collaborator

Choose a reason for hiding this comment

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

See comment above about rangeCheck function.

@Myoldmopar
Copy link
Member

@jasondegraw the last PR just caused a conflict in one file. I'm happy to resolve if you want me to just let me know.

@jasondegraw
Copy link
Member Author

@Myoldmopar Yes, that would be great if you could do that. This should be ready for review, when I last checked it was all good but it may have fallen behind develop a bit.

@Myoldmopar
Copy link
Member

Conflicts resolved, everything builds and passes fine. Carry on...

@jasondegraw
Copy link
Member Author

@Myoldmopar I think we want to get this in now and get out of the way of some of the other work that is going on, who should do review of this PR?

Copy link
Collaborator

@mitchute mitchute left a comment

Choose a reason for hiding this comment

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

Great to have these cleaned up and some of the messiness that came along with these optionals gone.

This all looks OK to me. Nothing is jumping out as controversial, just a nice set of cleanup changes. I think this can merge right away if CI comes back green.

Copy link
Member

@Myoldmopar Myoldmopar left a comment

Choose a reason for hiding this comment

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

Yeah, this looks awesome. I have no issues with this.

@Myoldmopar
Copy link
Member

I'm not sure why Windows didn't come back yet, but I'm not going to hold it up. It was clean ahead of the merge from develop. Merging now, thanks @jasondegraw

@Myoldmopar Myoldmopar merged commit 2f3618a into develop Jan 19, 2022
@Myoldmopar Myoldmopar deleted the optional-string branch January 19, 2022 15:41
yujiex pushed a commit that referenced this pull request Jan 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Refactoring Includes code changes that don't change the functionality of the program, just perform refactoring
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants