From 816e907b6d490506d789ed38620b1eac5f7a2d2f Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Wed, 6 May 2026 21:15:45 -0600 Subject: [PATCH 1/3] try decent-ci style testing on each branch on self-hosted runner --- .github/workflows/self_hosted_decent_ci.yml | 127 ++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 .github/workflows/self_hosted_decent_ci.yml diff --git a/.github/workflows/self_hosted_decent_ci.yml b/.github/workflows/self_hosted_decent_ci.yml new file mode 100644 index 00000000000..f4eb2bc596b --- /dev/null +++ b/.github/workflows/self_hosted_decent_ci.yml @@ -0,0 +1,127 @@ +name: Self-Hosted Decent CI + +on: + pull_request: + branches: [ develop ] + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + +env: + BUILD_DIR: build-decent-ci + Python_REQUIRED_VERSION: "3.12.2" + +jobs: + build_and_test: + name: GCC 13.3 build and split tests + if: >- + ${{ + github.event.pull_request.head.repo.full_name == github.repository && + github.event.pull_request.head.repo.fork == false + }} + runs-on: [ self-hosted, linux, x64, ubuntu-24.04 ] + + steps: + - name: Checkout EnergyPlus + uses: actions/checkout@v6 + with: + ref: ${{ github.event.pull_request.head.sha }} + persist-credentials: false + + - name: Setup runner + id: setup-runner + uses: ./.github/actions/setup-runner + with: + python-version: ${{ env.Python_REQUIRED_VERSION }} + python-arch: x64 + + - name: Select GCC 13.3 toolchain + shell: bash + run: | + sudo apt-get -qq update + sudo apt-get -qq install -y gcc-13 g++-13 gfortran-13 + + gcc_version="$(gcc-13 -dumpfullversion -dumpversion)" + case "$gcc_version" in + 13.3*) ;; + *) + echo "::error::Expected GCC 13.3.x, found ${gcc_version}" + exit 1 + ;; + esac + + { + echo "CC=$(command -v gcc-13)" + echo "CXX=$(command -v g++-13)" + echo "FC=$(command -v gfortran-13)" + } >> "$GITHUB_ENV" + gcc-13 --version + g++-13 --version + gfortran-13 --version + + - name: Configure build + shell: bash + run: | + cmake -S . -B "$BUILD_DIR" \ + -G Ninja \ + -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo \ + -DCMAKE_C_COMPILER:FILEPATH="$CC" \ + -DCMAKE_CXX_COMPILER:FILEPATH="$CXX" \ + -DCMAKE_Fortran_COMPILER:FILEPATH="$FC" \ + -DLINK_WITH_PYTHON:BOOL=ON \ + -DPYTHON_CLI:BOOL=OFF \ + -DPython_REQUIRED_VERSION:STRING="$Python_REQUIRED_VERSION" \ + -DPython_ROOT_DIR:PATH="${{ steps.setup-runner.outputs.python-root-dir }}" \ + -DPython_EXECUTABLE:FILEPATH="${{ steps.setup-runner.outputs.python-executable }}" \ + -DBUILD_FORTRAN:BOOL=ON \ + -DBUILD_TESTING:BOOL=ON \ + -DENABLE_REGRESSION_TESTING:BOOL=OFF \ + -DCOMMIT_SHA:STRING="${{ github.event.pull_request.head.sha }}" \ + -DENABLE_GTEST_DEBUG_MODE:BOOL=OFF \ + -DENABLE_PCH:BOOL=OFF \ + -DFORCE_DEBUG_ARITHM_GCC_OR_CLANG:BOOL=ON \ + -DBUILD_PACKAGE:BOOL=OFF \ + -DDOCUMENTATION_BUILD:STRING=DoNotBuild + + - name: Build + shell: bash + run: | + echo "::add-matcher::./.github/workflows/cpp-problem-matcher.json" + cmake --build "$BUILD_DIR" -j "${NPROC:-$(nproc)}" + echo "::remove-matcher owner=gcc-problem-matcher::" + + - name: Run unit tests + working-directory: ${{ env.BUILD_DIR }} + shell: bash + run: | + begin_group() { echo -e "::group::\033[93m$1\033[0m"; } + + begin_group "Running non-integration CTests" + if ctest -j "${NPROC:-$(nproc)}" --output-on-failure -E "integration.*"; then + echo "::endgroup::" + else + echo "::endgroup::" + begin_group "Re-running failed non-integration tests verbosely" + ctest --rerun-failed -VV + echo "::endgroup::" + fi + + - name: Run integration tests + working-directory: ${{ env.BUILD_DIR }} + shell: bash + run: | + begin_group() { echo -e "::group::\033[93m$1\033[0m"; } + + begin_group "Running integration CTests" + if ctest -j "${NPROC:-$(nproc)}" --output-on-failure -R "integration.*"; then + echo "::endgroup::" + else + echo "::endgroup::" + begin_group "Re-running failed integration tests verbosely" + ctest --rerun-failed -VV + echo "::endgroup::" + fi From f3759093a7f0717cf133cbd4674837b6eeb2a718 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Thu, 7 May 2026 08:28:26 -0600 Subject: [PATCH 2/3] try adding ccache --- .github/workflows/self_hosted_decent_ci.yml | 44 +++++++++++++++++++++ .github/workflows/test_develop_commits.yml | 2 +- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/.github/workflows/self_hosted_decent_ci.yml b/.github/workflows/self_hosted_decent_ci.yml index f4eb2bc596b..55c6bce9b2f 100644 --- a/.github/workflows/self_hosted_decent_ci.yml +++ b/.github/workflows/self_hosted_decent_ci.yml @@ -40,6 +40,7 @@ jobs: python-arch: x64 - name: Select GCC 13.3 toolchain + id: compiler shell: bash run: | sudo apt-get -qq update @@ -59,10 +60,39 @@ jobs: echo "CXX=$(command -v g++-13)" echo "FC=$(command -v gfortran-13)" } >> "$GITHUB_ENV" + echo "compiler-id=gcc-${gcc_version}" >> "$GITHUB_OUTPUT" gcc-13 --version g++-13 --version gfortran-13 --version + - name: Restore ccache + id: cacheccache-restore + uses: actions/cache/restore@v5 + with: + path: | + ${{ steps.setup-runner.outputs.ccache-dir }} + key: ccache-self-hosted-decent-ci-${{ runner.os }}-${{ steps.compiler.outputs.compiler-id }}-pr-${{ github.event.pull_request.number }} + + - name: Show restored ccache state + shell: bash + run: | + begin_group() { echo -e "::group::\033[93m$1\033[0m"; } + + if [ "${{ steps.cacheccache-restore.outputs.cache-hit }}" = "true" ]; then + echo "CCache primary key was hit" + else + echo "No exact ccache hit" + fi + + begin_group "Existing ccache stats" + ccache --show-stats -vv || ccache --show-stats + echo "::endgroup::" + + ccache --zero-stats + begin_group "CCache config" + ccache -p + echo "::endgroup::" + - name: Configure build shell: bash run: | @@ -94,6 +124,20 @@ jobs: cmake --build "$BUILD_DIR" -j "${NPROC:-$(nproc)}" echo "::remove-matcher owner=gcc-problem-matcher::" + - name: Show build ccache stats + if: always() + shell: bash + run: | + ccache --show-stats -vv || ccache --show-stats + + - name: Save ccache + if: always() && steps.cacheccache-restore.outputs.cache-hit != 'true' + uses: actions/cache/save@v5 + with: + path: | + ${{ steps.setup-runner.outputs.ccache-dir }} + key: ${{ steps.cacheccache-restore.outputs.cache-primary-key }} + - name: Run unit tests working-directory: ${{ env.BUILD_DIR }} shell: bash diff --git a/.github/workflows/test_develop_commits.yml b/.github/workflows/test_develop_commits.yml index 41e1f343f32..c23eb8f1973 100644 --- a/.github/workflows/test_develop_commits.yml +++ b/.github/workflows/test_develop_commits.yml @@ -30,7 +30,7 @@ jobs: # pretty: "Standard Build on Mac x64" # alternate: false - os: macos-14 - macos_dev_target: 13.0 + macos_dev_target: 14.0 arch: arm64 python-arch: arm64 generator: "Unix Makefiles" From 19126b779dbb4fba77ebf09df196b574b712798d Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Thu, 7 May 2026 10:16:53 -0600 Subject: [PATCH 3/3] try to patch test --- .../workflows/self_hosted_build_and_test.yml | 2 +- src/EnergyPlus/api/datatransfer.cc | 32 +++++++++++-------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index 23830d94ffd..9dfdafcaf17 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -1,7 +1,7 @@ name: Self-Hosted Build and Test on: - push: + pull_request: branches: [ develop ] workflow_dispatch: inputs: diff --git a/src/EnergyPlus/api/datatransfer.cc b/src/EnergyPlus/api/datatransfer.cc index 2a1e6f94bb0..31332dd1e84 100644 --- a/src/EnergyPlus/api/datatransfer.cc +++ b/src/EnergyPlus/api/datatransfer.cc @@ -46,6 +46,8 @@ // POSSIBILITY OF SUCH DAMAGE. #include +#include +#include #include #include @@ -69,6 +71,20 @@ using namespace EnergyPlus; +namespace { + +char *copyStringForAPI(std::string const &value) +{ + auto *result = static_cast(std::malloc(value.size() + 1)); + if (result == nullptr) { + return nullptr; + } + std::memcpy(result, value.c_str(), value.size() + 1); + return result; +} + +} // namespace + APIDataEntry *getAPIData(EnergyPlusState state, unsigned int *resultingSize) { struct LocalAPIDataEntry @@ -215,13 +231,7 @@ char *listAllAPIDataCSV(EnergyPlusState state) ? variable->unitNameCustomEMS : EnergyPlus::Constant::unitNames[(int)variable->units])); } - // note that we cannot just return a c_str to the local string, as the string will be destructed upon leaving - // this function, and undefined behavior will occur. - // instead make a deep copy, and the user must manage the new char * pointer - // strcpy copies including the null-terminator, strlen doesn't include it - char *p = new char[std::strlen(output.c_str()) + 1]; - std::strcpy(p, output.c_str()); - return p; + return copyStringForAPI(output); } int apiDataFullyReady(EnergyPlusState state) @@ -252,18 +262,14 @@ char *inputFilePath(EnergyPlusState state) { const auto *thisState = static_cast(state); std::string const path_utf8 = EnergyPlus::FileSystem::toGenericString(thisState->dataStrGlobals->inputFilePath); - char *p = new char[std::strlen(path_utf8.c_str()) + 1]; - std::strcpy(p, path_utf8.c_str()); - return p; + return copyStringForAPI(path_utf8); } char *epwFilePath(EnergyPlusState state) { const auto *thisState = static_cast(state); std::string const path_utf8 = EnergyPlus::FileSystem::toGenericString(thisState->files.inputWeatherFilePath.filePath); - char *p = new char[std::strlen(path_utf8.c_str()) + 1]; - std::strcpy(p, path_utf8.c_str()); - return p; + return copyStringForAPI(path_utf8); } char **getObjectNames(EnergyPlusState state, const char *objectType, unsigned int *resultingSize)