Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Patches are applied with git apply, which requires LF line endings, so make sure that they are always checked out with
# LF line endings, whatever the platform (e.g., git on Windows checks out text files with CRLF line endings by default).

*.patch text eol=lf
109 changes: 109 additions & 0 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
name: x86-64-v3 benchmark

# Compare the speed of our simulations when libOpenCOR and SUNDIALS are built for x86-64 (i.e. SSE2) and for x86-64-v3
# (i.e. AVX2, FMA, etc.; see X86_64_V3_COMPILER_FLAGS in src/CMakeLists.txt).
# Note #1: both versions are built and benchmarked in the same job, so that they are run on the same CPU.
# Note #2: SUNDIALS is built from source for both versions, so that only the compiler flags differ between them.
# Note #3: the x86-64 version is built by emptying X86_64_V3_COMPILER_FLAGS in src/CMakeLists.txt, which is why we build
# the x86-64-v3 version first (CMake would otherwise reconfigure it).

on:
workflow_dispatch:

jobs:
benchmark:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- name: 'Windows (Intel)'
os: windows-2022
- name: 'Linux (Intel)'
os: ubuntu-24.04
- name: 'macOS (Intel)'
os: macos-15-intel
steps:
- name: Check out libOpenCOR
uses: actions/checkout@v4
- name: Install Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install CMake and Ninja
uses: lukka/get-cmake@latest
- name: Configure MSVC
if: ${{ runner.os == 'Windows' }}
uses: ilammy/msvc-dev-cmd@v1
with:
arch: amd64
- name: Install GCC 16
if: ${{ runner.os == 'Linux' }}
run: |
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install -y gcc-16 g++-16
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-16 100
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-16 100
echo "CC=gcc-16" >> "$GITHUB_ENV"
echo "CXX=g++-16" >> "$GITHUB_ENV"
- name: Report the CPU
shell: bash
run: |
if [ '${{ runner.os }}' == 'Linux' ]; then lscpu | grep 'Model name'; fi
if [ '${{ runner.os }}' == 'macOS' ]; then sysctl -n machdep.cpu.brand_string; fi
if [ '${{ runner.os }}' == 'Windows' ]; then powershell -Command "(Get-CimInstance Win32_Processor).Name"; fi
- name: Build the x86-64-v3 version
shell: bash
run: |
cmake -G Ninja -S . -B build-x86-64-v3 -DBUILD_TYPE=Release -DCOMPILER_CACHING=OFF -DDOCUMENTATION=OFF -DJAVASCRIPT_BINDINGS=OFF -DPREBUILT_SUNDIALS=OFF -DPYTHON_BINDINGS=OFF -DSHARED_LIBS=OFF -DUNIT_TESTING=ON
cmake --build build-x86-64-v3 --target benchmark_executable
- name: Build the x86-64 version
shell: bash
run: |
sed -i.bak -E 's/set\(X86_64_V3_COMPILER_FLAGS "[^"]*"\)/set(X86_64_V3_COMPILER_FLAGS "")/' src/CMakeLists.txt
grep -n 'set(X86_64_V3_COMPILER_FLAGS' src/CMakeLists.txt
cmake -G Ninja -S . -B build-x86-64 -DBUILD_TYPE=Release -DCOMPILER_CACHING=OFF -DDOCUMENTATION=OFF -DJAVASCRIPT_BINDINGS=OFF -DPREBUILT_SUNDIALS=OFF -DPYTHON_BINDINGS=OFF -DSHARED_LIBS=OFF -DUNIT_TESTING=ON
cmake --build build-x86-64 --target benchmark_executable
- name: Run the benchmarks
shell: bash
run: |
for RUN in 1 2 3; do
for VERSION in x86-64 x86-64-v3; do
build-$VERSION/tests/benchmark_executable | tee benchmark-$VERSION-$RUN.txt
done
done
- name: Compare the benchmarks
shell: bash
run: |
python - <<'EOF' | tee -a "$GITHUB_STEP_SUMMARY"
import collections
import glob

# Keep, for each benchmark and version, the best median time over our different runs.

medians = collections.defaultdict(list)
names = []

for version in ('x86-64', 'x86-64-v3'):
for file_name in sorted(glob.glob(f'benchmark-{version}-*.txt')):
for line in open(file_name).readlines()[2:]:
fields = [field.strip() for field in line.split('|')]

if len(fields) >= 5:
medians[(fields[0], version)].append(float(fields[4]))

if fields[0] not in names:
names.append(fields[0])

print('## ${{ matrix.name }}\n')
print('| Benchmark | x86-64 (ms) | x86-64-v3 (ms) | Difference |')
print('|---|---:|---:|---:|')

for name in names:
x86_64 = min(medians[(name, 'x86-64')])
x86_64_v3 = min(medians[(name, 'x86-64-v3')])

print(f'| {name} | {x86_64:.1f} | {x86_64_v3:.1f} | {100.0 * (x86_64_v3 - x86_64) / x86_64:+.1f}% |')
EOF
4 changes: 0 additions & 4 deletions .github/workflows/buildThirdPartyLibrary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,6 @@ jobs:
uses: opencor/buildcache-action@v1
with:
cache_key: webassembly
- name: Install LLVM
run: |
brew install llvm
echo "$(brew --prefix llvm)/bin" >> $GITHUB_PATH
- name: Install Emscripten
run: brew install emscripten
- name: Configure libOpenCOR (for a specific third-party library)
Expand Down
2 changes: 1 addition & 1 deletion VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.20260803.0
1.20260911.1
19 changes: 19 additions & 0 deletions cmake/common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,25 @@ function(replace_compiler_flag OLD NEW)
endforeach()
endfunction()

function(add_cache_flags VARIABLE FLAGS DOCSTRING)
# Add the given flags to the given cache variable, but only if they are not already there.
# Note: the variable may already have them since our JavaScript bindings target passes them to the Emscripten build
# that it kicks off (see src/bindings/javascript/CMakeLists.txt). And, because we must force the cache entry,
# they would otherwise be added once more on every single reconfiguration, making the variable grow without
# bound and, with BUILDCACHE_ACCURACY set to STRICT, invalidating our compiler cache each time.

string(FIND "${${VARIABLE}}" "${FLAGS}" INDEX)

if(NOT INDEX EQUAL -1)
return()
endif()

string(STRIP "${${VARIABLE}} ${FLAGS}" NEW_FLAGS)

set(${VARIABLE} "${NEW_FLAGS}" CACHE STRING "${DOCSTRING}" FORCE)
set(${VARIABLE} "${NEW_FLAGS}" PARENT_SCOPE)
endfunction()

function(suppress_target_warnings TARGET)
target_compile_options(${TARGET} PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/W0>
Expand Down
29 changes: 8 additions & 21 deletions cmake/environmentchecks.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,19 @@
# Make sure that we are using a supported compiler.

if(WIN32)
if( "${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC"
AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"
AND MSVC_TOOLSET_VERSION EQUAL 143)
if(MSVC AND NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(BUILDING_USING_MSVC TRUE)
else()
message(FATAL_ERROR "${CMAKE_PROJECT_NAME} can only be built using MSVC 2022 on Windows.")
message(FATAL_ERROR "${CMAKE_PROJECT_NAME} can only be built using MSVC on Windows.")
endif()
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(BUILDING_USING_CLANG TRUE)
elseif(APPLE)
if( ( "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang"
AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
OR ( "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang"
AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang"))
set(BUILDING_USING_CLANG TRUE)
else()
message(FATAL_ERROR "${CMAKE_PROJECT_NAME} can only be built using (Apple) Clang on macOS.")
endif()
message(FATAL_ERROR "${CMAKE_PROJECT_NAME} can only be built using (Apple) Clang on macOS.")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(BUILDING_USING_GNU TRUE)
else()
if( "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU"
AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(BUILDING_USING_GNU TRUE)
elseif( "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang"
AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(BUILDING_USING_CLANG TRUE)
else()
message(FATAL_ERROR "${CMAKE_PROJECT_NAME} can only be built using GNU or Clang on Linux.")
endif()
message(FATAL_ERROR "${CMAKE_PROJECT_NAME} can only be built using GNU or Clang on Linux.")
endif()

# Make sure that we are building libOpenCOR in 64-bit mode.
Expand Down
18 changes: 16 additions & 2 deletions cmake/packages.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,22 @@ set(PREBUILT_DIR "${PREBUILT_DIR}" CACHE INTERNAL "Prebuilt directory.")
include(ExternalProject)

if(NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN)
set(CMAKE_C_FLAGS_ARGS -DCMAKE_C_FLAGS=-fPIC)
set(CMAKE_CXX_FLAGS_ARGS -DCMAKE_CXX_FLAGS=-fPIC)
set(THIRD_PARTY_C_FLAGS -fPIC)
set(THIRD_PARTY_CXX_FLAGS -fPIC)
endif()

# Build our third-party libraries for x86-64-v3 on Intel (see X86_64_V3_COMPILER_FLAGS in src/CMakeLists.txt).
# Note: setting CMAKE_C_FLAGS/CMAKE_CXX_FLAGS replaces the default flags that CMake would otherwise use (e.g., /EHsc for
# MSVC), so we start from those default flags.

if(X86_64_V3_COMPILER_FLAGS)
string(STRIP "${CMAKE_C_FLAGS_INIT} ${THIRD_PARTY_C_FLAGS} ${X86_64_V3_COMPILER_FLAGS}" THIRD_PARTY_C_FLAGS)
string(STRIP "${CMAKE_CXX_FLAGS_INIT} ${THIRD_PARTY_CXX_FLAGS} ${X86_64_V3_COMPILER_FLAGS}" THIRD_PARTY_CXX_FLAGS)
endif()

if(THIRD_PARTY_C_FLAGS)
set(CMAKE_C_FLAGS_ARGS -DCMAKE_C_FLAGS=${THIRD_PARTY_C_FLAGS})
set(CMAKE_CXX_FLAGS_ARGS -DCMAKE_CXX_FLAGS=${THIRD_PARTY_CXX_FLAGS})
endif()

set(CMAKE_ARGS
Expand Down
Loading
Loading