Skip to content

Commit acda84e

Browse files
authored
Merge pull request #10844 from NREL/10842_PluginHangs
Fix #10842 - When using pyenergyplus to run (via run_energyplus), PythonPlugin initializations errors lead to hang
2 parents 3659604 + 397c580 commit acda84e

File tree

5 files changed

+257
-11
lines changed

5 files changed

+257
-11
lines changed

Diff for: src/EnergyPlus/CMakeLists.txt

+11
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,17 @@ if(BUILD_TESTING)
11471147
COMMAND energyplus -D -d "${CLI_TEST_DIR}/PythonPlugin.FromOutside/out-${NON_ASCII_DIRNAME}" ${NON_ASCII_DIRNAME}/${TEST_CASE}.idf
11481148
WORKING_DIRECTORY "${CLI_TEST_DIR}"
11491149
)
1150+
1151+
set(TEST_DIR "${PROJECT_BINARY_DIR}/tst/api/TestRuntimeReleasesTheGIL")
1152+
file(MAKE_DIRECTORY ${TEST_DIR})
1153+
add_test(NAME "API.Runtime.PythonPlugin.TestRuntimeReleasesTheGIL"
1154+
COMMAND "${Python_EXECUTABLE}" "${PROJECT_SOURCE_DIR}/tst/EnergyPlus/api/TestRuntimeReleasesTheGIL.py" -d "${TEST_DIR}" -w "${EPW_FILE}" -D "${PROJECT_SOURCE_DIR}/tst/EnergyPlus/api/TestRuntimeReleasesTheGIL/mcve_gil.idf"
1155+
)
1156+
set_tests_properties("API.Runtime.PythonPlugin.TestRuntimeReleasesTheGIL"
1157+
PROPERTIES
1158+
ENVIRONMENT PYTHONPATH=${DIR_WITH_PY_ENERGYPLUS}
1159+
TIMEOUT 10 # This used to timeout! and we expect it NOT to
1160+
)
11501161
endif()
11511162
endif()
11521163

Diff for: src/EnergyPlus/PluginManager.cc

+22-11
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,22 @@ void initPython(EnergyPlusData &state, fs::path const &pathToPythonPackages)
461461
// Py_Initialize();
462462
Py_InitializeFromConfig(&config);
463463
}
464+
465+
// GilGrabber is an RAII helper that will ensure we release the GIL (including if we end up throwing)
466+
struct GilGrabber
467+
{
468+
GilGrabber()
469+
{
470+
gil = PyGILState_Ensure();
471+
}
472+
~GilGrabber()
473+
{
474+
PyGILState_Release(gil);
475+
}
476+
477+
PyGILState_STATE gil;
478+
};
479+
464480
#endif // LINK_WITH_PYTHON
465481

466482
PluginManager::PluginManager(EnergyPlusData &state) : eplusRunningViaPythonAPI(state.dataPluginManager->eplusRunningViaPythonAPI)
@@ -484,8 +500,8 @@ PluginManager::PluginManager(EnergyPlusData &state) : eplusRunningViaPythonAPI(s
484500

485501
initPython(state, pathToPythonPackages);
486502

487-
// Take control of the global interpreter lock while we are here, make sure to release it...
488-
PyGILState_STATE gil = PyGILState_Ensure();
503+
// Take control of the global interpreter lock, which will be released via RAII
504+
GilGrabber gil_grabber;
489505

490506
// call this once to allow us to add to, and report, sys.path later as needed
491507
PyRun_SimpleString("import sys"); // allows us to report sys.path later
@@ -679,8 +695,8 @@ PluginManager::PluginManager(EnergyPlusData &state) : eplusRunningViaPythonAPI(s
679695
}
680696
}
681697

682-
// Release the global interpreter lock
683-
PyGILState_Release(gil);
698+
// Release the global interpreter lock is done via RAII
699+
684700
// setting up output variables deferred until later in the simulation setup process
685701
#else
686702
// need to alert only if a plugin instance is found
@@ -1103,8 +1119,8 @@ bool PluginInstance::run(EnergyPlusData &state, EMSManager::EMSCallFrom iCalledF
11031119
return false;
11041120
}
11051121

1106-
// Get control of the global interpreter lock
1107-
PyGILState_STATE gil = PyGILState_Ensure();
1122+
// Take control of the global interpreter lock, which will be released via RAII
1123+
GilGrabber gil_grabber;
11081124

11091125
// then call the main function
11101126
// static const PyObject oneArgObjFormat = Py_BuildValue)("O");
@@ -1119,20 +1135,17 @@ bool PluginInstance::run(EnergyPlusData &state, EMSManager::EMSCallFrom iCalledF
11191135
} else {
11201136
ShowContinueError(state, "This could happen for any number of reasons, check the plugin code.");
11211137
}
1122-
PyGILState_Release(gil);
11231138
ShowFatalError(state, format("Program terminates after call to {}() on {} failed!", functionNameAsString, this->stringIdentifier));
11241139
}
11251140
if (PyLong_Check(pFunctionResponse)) { // NOLINT(hicpp-signed-bitwise)
11261141
long exitCode = PyLong_AsLong(pFunctionResponse);
11271142
if (exitCode == 0) {
11281143
// success
11291144
} else if (exitCode == 1) {
1130-
PyGILState_Release(gil);
11311145
ShowFatalError(state, format("Python Plugin \"{}\" returned 1 to indicate EnergyPlus should abort", this->stringIdentifier));
11321146
}
11331147
} else {
11341148
std::string const functionNameAsString(functionName); // only convert to string if an error occurs
1135-
PyGILState_Release(gil);
11361149
ShowFatalError(
11371150
state,
11381151
format("Invalid return from {}() on class \"{}, make sure it returns an integer exit code, either zero (success) or one (failure)",
@@ -1141,10 +1154,8 @@ bool PluginInstance::run(EnergyPlusData &state, EMSManager::EMSCallFrom iCalledF
11411154
}
11421155
Py_DECREF(pFunctionResponse); // PyObject_CallFunction returns new reference, decrement
11431156
if (state.dataPluginManager->apiErrorFlag) {
1144-
PyGILState_Release(gil);
11451157
ShowFatalError(state, "API problems encountered while running plugin cause program termination.");
11461158
}
1147-
PyGILState_Release(gil);
11481159
return true;
11491160
}
11501161
#else

Diff for: tst/EnergyPlus/api/TestRuntimeReleasesTheGIL.py

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University
2+
# of Illinois, The Regents of the University of California, through Lawrence
3+
# Berkeley National Laboratory (subject to receipt of any required approvals
4+
# from the U.S. Dept. of Energy), Oak Ridge National Laboratory, managed by UT-
5+
# Battelle, Alliance for Sustainable Energy, LLC, and other contributors. All
6+
# rights reserved.
7+
#
8+
# NOTICE: This Software was developed under funding from the U.S. Department of
9+
# Energy and the U.S. Government consequently retains certain rights. As such,
10+
# the U.S. Government has been granted for itself and others acting on its
11+
# behalf a paid-up, nonexclusive, irrevocable, worldwide license in the
12+
# Software to reproduce, distribute copies to the public, prepare derivative
13+
# works, and perform publicly and display publicly, and to permit others to do
14+
# so.
15+
#
16+
# Redistribution and use in source and binary forms, with or without
17+
# modification, are permitted provided that the following conditions are met:
18+
#
19+
# (1) Redistributions of source code must retain the above copyright notice,
20+
# this list of conditions and the following disclaimer.
21+
#
22+
# (2) Redistributions in binary form must reproduce the above copyright notice,
23+
# this list of conditions and the following disclaimer in the documentation
24+
# and/or other materials provided with the distribution.
25+
#
26+
# (3) Neither the name of the University of California, Lawrence Berkeley
27+
# National Laboratory, the University of Illinois, U.S. Dept. of Energy nor
28+
# the names of its contributors may be used to endorse or promote products
29+
# derived from this software without specific prior written permission.
30+
#
31+
# (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in
32+
# stand-alone form without changes from the version obtained under this
33+
# License, or (ii) Licensee makes a reference solely to the software
34+
# portion of its product, Licensee must refer to the software as
35+
# "EnergyPlus version X" software, where "X" is the version number Licensee
36+
# obtained under this License and may not use a different name for the
37+
# software. Except as specifically required in this Section (4), Licensee
38+
# shall not use in a company name, a product name, in advertising,
39+
# publicity, or other promotional activities any name, trade name,
40+
# trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or
41+
# confusingly similar designation, without the U.S. Department of Energy's
42+
# prior written consent.
43+
#
44+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
45+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
48+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
50+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
54+
# POSSIBILITY OF SUCH DAMAGE.
55+
56+
import sys
57+
58+
from pyenergyplus.api import EnergyPlusAPI
59+
60+
api = EnergyPlusAPI()
61+
state = api.state_manager.new_state()
62+
exit_code = api.runtime.run_energyplus(state, sys.argv[1:])
63+
64+
if exit_code == 0:
65+
print("Expected EnergyPlus to return an error to the broken python plugin. Task Succeeded Unsuccessfully!")
66+
sys.exit(1)
+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
! The PythonPlugin referenced here has a broken import
2+
! This is a test for #10842
3+
4+
Timestep,6;
5+
6+
SimulationControl,
7+
No, !- Do Zone Sizing Calculation
8+
No, !- Do System Sizing Calculation
9+
No, !- Do Plant Sizing Calculation
10+
Yes, !- Run Simulation for Sizing Periods
11+
No, !- Run Simulation for Weather File Run Periods
12+
No, !- Do HVAC Sizing Simulation for Sizing Periods
13+
1; !- Maximum Number of HVAC Sizing Simulation Passes
14+
15+
GlobalGeometryRules,
16+
UpperLeftCorner, !- Starting Vertex Position
17+
Counterclockwise, !- Vertex Entry Direction
18+
Relative, !- Coordinate System
19+
Relative; !- Daylighting Reference Point Coordinate System
20+
21+
Building,
22+
Building, !- Name
23+
0.0000, !- North Axis {deg}
24+
City, !- Terrain
25+
0.0400, !- Loads Convergence Tolerance Value {W}
26+
0.2000, !- Temperature Convergence Tolerance Value {deltaC}
27+
FullInteriorAndExterior, !- Solar Distribution
28+
25, !- Maximum Number of Warmup Days
29+
6; !- Minimum Number of Warmup Days
30+
31+
Site:Location,
32+
CHICAGO_IL_USA TMY2-94846, !- Name
33+
41.78000, !- Latitude {deg}
34+
-87.75000, !- Longitude {deg}
35+
-6.000000, !- Time Zone {hr}
36+
190.0000; !- Elevation {m}
37+
38+
! CHICAGO_IL_USA Annual Heating 99.6%, MaxDB=-20.6°C
39+
40+
SizingPeriod:DesignDay,
41+
CHICAGO Ann Htg 99.6% Condns DB, !- Name
42+
1, !- Month
43+
21, !- Day of Month
44+
WinterDesignDay, !- Day Type
45+
-20.6, !- Maximum Dry-Bulb Temperature {C}
46+
0.0, !- Daily Dry-Bulb Temperature Range {deltaC}
47+
, !- Dry-Bulb Temperature Range Modifier Type
48+
, !- Dry-Bulb Temperature Range Modifier Day Schedule Name
49+
Wetbulb, !- Humidity Condition Type
50+
-20.6, !- Wetbulb or DewPoint at Maximum Dry-Bulb {C}
51+
, !- Humidity Condition Day Schedule Name
52+
, !- Humidity Ratio at Maximum Dry-Bulb {kgWater/kgDryAir}
53+
, !- Enthalpy at Maximum Dry-Bulb {J/kg}
54+
, !- Daily Wet-Bulb Temperature Range {deltaC}
55+
99063., !- Barometric Pressure {Pa}
56+
4.9, !- Wind Speed {m/s}
57+
270, !- Wind Direction {deg}
58+
No, !- Rain Indicator
59+
No, !- Snow Indicator
60+
No, !- Daylight Saving Time Indicator
61+
ASHRAEClearSky, !- Solar Model Indicator
62+
, !- Beam Solar Day Schedule Name
63+
, !- Diffuse Solar Day Schedule Name
64+
, !- ASHRAE Clear Sky Optical Depth for Beam Irradiance (taub) {dimensionless}
65+
, !- ASHRAE Clear Sky Optical Depth for Diffuse Irradiance (taud) {dimensionless}
66+
0.00; !- Sky Clearness
67+
68+
! CHICAGO_IL_USA Annual Cooling (DB=>MWB) .4%, MaxDB=33.2°C MWB=23.8°C
69+
70+
SizingPeriod:DesignDay,
71+
CHICAGO Ann Clg .4% Condns DB=>MWB, !- Name
72+
7, !- Month
73+
21, !- Day of Month
74+
SummerDesignDay, !- Day Type
75+
33.2, !- Maximum Dry-Bulb Temperature {C}
76+
10.7, !- Daily Dry-Bulb Temperature Range {deltaC}
77+
, !- Dry-Bulb Temperature Range Modifier Type
78+
, !- Dry-Bulb Temperature Range Modifier Day Schedule Name
79+
Wetbulb, !- Humidity Condition Type
80+
23.8, !- Wetbulb or DewPoint at Maximum Dry-Bulb {C}
81+
, !- Humidity Condition Day Schedule Name
82+
, !- Humidity Ratio at Maximum Dry-Bulb {kgWater/kgDryAir}
83+
, !- Enthalpy at Maximum Dry-Bulb {J/kg}
84+
, !- Daily Wet-Bulb Temperature Range {deltaC}
85+
99063., !- Barometric Pressure {Pa}
86+
5.3, !- Wind Speed {m/s}
87+
230, !- Wind Direction {deg}
88+
No, !- Rain Indicator
89+
No, !- Snow Indicator
90+
No, !- Daylight Saving Time Indicator
91+
ASHRAEClearSky, !- Solar Model Indicator
92+
, !- Beam Solar Day Schedule Name
93+
, !- Diffuse Solar Day Schedule Name
94+
, !- ASHRAE Clear Sky Optical Depth for Beam Irradiance (taub) {dimensionless}
95+
, !- ASHRAE Clear Sky Optical Depth for Diffuse Irradiance (taud) {dimensionless}
96+
1.00; !- Sky Clearness
97+
98+
PythonPlugin:Instance,
99+
Heating Setpoint Override, !- Name
100+
Yes, !- Run During Warmup Days
101+
mcve_gil, !- Python Module Name
102+
HeatingSetPoint; !- Plugin Class Name
+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University
2+
# of Illinois, The Regents of the University of California, through Lawrence
3+
# Berkeley National Laboratory (subject to receipt of any required approvals
4+
# from the U.S. Dept. of Energy), Oak Ridge National Laboratory, managed by UT-
5+
# Battelle, Alliance for Sustainable Energy, LLC, and other contributors. All
6+
# rights reserved.
7+
#
8+
# NOTICE: This Software was developed under funding from the U.S. Department of
9+
# Energy and the U.S. Government consequently retains certain rights. As such,
10+
# the U.S. Government has been granted for itself and others acting on its
11+
# behalf a paid-up, nonexclusive, irrevocable, worldwide license in the
12+
# Software to reproduce, distribute copies to the public, prepare derivative
13+
# works, and perform publicly and display publicly, and to permit others to do
14+
# so.
15+
#
16+
# Redistribution and use in source and binary forms, with or without
17+
# modification, are permitted provided that the following conditions are met:
18+
#
19+
# (1) Redistributions of source code must retain the above copyright notice,
20+
# this list of conditions and the following disclaimer.
21+
#
22+
# (2) Redistributions in binary form must reproduce the above copyright notice,
23+
# this list of conditions and the following disclaimer in the documentation
24+
# and/or other materials provided with the distribution.
25+
#
26+
# (3) Neither the name of the University of California, Lawrence Berkeley
27+
# National Laboratory, the University of Illinois, U.S. Dept. of Energy nor
28+
# the names of its contributors may be used to endorse or promote products
29+
# derived from this software without specific prior written permission.
30+
#
31+
# (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in
32+
# stand-alone form without changes from the version obtained under this
33+
# License, or (ii) Licensee makes a reference solely to the software
34+
# portion of its product, Licensee must refer to the software as
35+
# "EnergyPlus version X" software, where "X" is the version number Licensee
36+
# obtained under this License and may not use a different name for the
37+
# software. Except as specifically required in this Section (4), Licensee
38+
# shall not use in a company name, a product name, in advertising,
39+
# publicity, or other promotional activities any name, trade name,
40+
# trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or
41+
# confusingly similar designation, without the U.S. Department of Energy's
42+
# prior written consent.
43+
#
44+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
45+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
48+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
50+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
54+
# POSSIBILITY OF SUCH DAMAGE.
55+
56+
from this_does_not_exist.hello_world import garbage

0 commit comments

Comments
 (0)