-
Notifications
You must be signed in to change notification settings - Fork 396
MCCF: Make the Common Case Fast
One of the mantras of high-performance programming is "Make the Common Case Fast" or for short MCCF. Like pretty much every other program, EnergyPlus has a core set of features that are used in pretty much every model and others that are used much less frequently. The idea behind MCCF is to remove the handling of rarely-used features from the main loops of the code to help keep those the handling of commonly used features tight and highly optimized.
Even checking for the existence of a rarely-used feature takes time. If the feature is not used during the particular run, the branch associated with the check will be correctly predicted and will not result in a dynamic penalty (see this page to learn about data-dependent branches and branch penalties). However, the mere presence of the branch interferes with compiler optimizations like vectorization.
Let's look a historical (i.e., has already been fixed) example from EnergyPlus. The rarely-used feature is movable insulation. This feature is not commonly used in buildings and as a result it is not commonly used in models either. InitSurfaceHeatBalance is the EnergyPlus function that is called to initialize surface heat balance data structures at the beginning of every time step. This function used to check every surface for the presence of Movable Insulation.
// main InitSurfaceHeatBalanceLoop
for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
...
if (state.dataSurface->SurfSchedMovInsulExt(SurfNum)) { // This is how you tell whether a surface has Movable Insulation
... // Movable Insulation specific code
}
...
}
To MCCF, you want move the handling of Movable Insulation code to a separate loop that is guarded by a condition that there is any Movable Insulation in the model.
// main InitSurfaceHeatBalanceLoop
for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
...
...
}
// dedicated loop for handling Movable Insulation surfaces
if (state.dataSurface->AnyMovableInsulation) {
for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
if (state.dataSurface->SurfSchedMovInsulExt(SurfNum)) {
... // Movable Insulation specific code
}
}
This accomplishes 90% (or maybe 99%) of what we want to do, which is cleaning up the main InitSurfaceHeatBalance
loop and making the handling of common surface types fast in all models.
If we want to go the last mile (or the last foot maybe) we could make the handling of surfaces with Movable Insulation itself faster by not requiring that code to traverse all surfaces in order to identify those surfaces with Movable Insulation. You can do this by creating a separate list that keeps track of all surfaces that have Movable Insulation attached to them and using that list in the dedicated Movable Insulation loop. This code itself can now be better optimized because the conditional has been removed from it. It also executes many fewer iterations.
// dedicated loop for handling Movable Insulation surfaces
if (state.dataSurface->AnyMovableInsulation) {
for (int SurfNum : dataSurface->SurfaceMovInsulIndexList) {
... // Movable Insulation specific code
}
}