diff --git a/.github/workflows/containers.yml b/.github/workflows/containers.yml index 52f465b227..66e795a447 100644 --- a/.github/workflows/containers.yml +++ b/.github/workflows/containers.yml @@ -4,7 +4,7 @@ run-name: ci-containers # nightly build on: schedule: - - cron: 0 1 * * * + - cron: 0 5 * * * concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/opensuse.yml b/.github/workflows/opensuse.yml index d3ea4c8fda..d2a465ef30 100644 --- a/.github/workflows/opensuse.yml +++ b/.github/workflows/opensuse.yml @@ -11,20 +11,21 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -env: - BUILD_TYPE: Release - OMNITRACE_VERBOSE: 1 - OMNITRACE_CI: ON - jobs: opensuse: runs-on: ubuntu-20.04 container: image: jrmadsen/omnitrace:ci-base-opensuse-${{ matrix.os-release }} strategy: + fail-fast: false matrix: compiler: ['g++'] os-release: [ '15.2', '15.3' ] + build-type: ['Release'] + + env: + OMNITRACE_VERBOSE: 1 + OMNITRACE_CI: ON steps: - uses: actions/checkout@v3 @@ -42,11 +43,16 @@ jobs: echo "LD_LIBRARY_PATH=/opt/omnitrace/lib:${LD_LIBRARY_PATH}" >> $GITHUB_ENV - name: Configure CMake - timeout-minutes: 10 + timeout-minutes: 115 + shell: bash run: git config --global --add safe.directory ${PWD} && cmake --version && - cmake -B build + ./scripts/run-ci.sh -B build + --name opensuse-${{ matrix.os-release }}-${{ matrix.compiler }}-nompi-python + --build-jobs 2 + --site GitHub + --cmake-args -DCMAKE_C_COMPILER=$(echo '${{ matrix.compiler }}' | sed 's/+/c/g') -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} @@ -61,25 +67,11 @@ jobs: -DOMNITRACE_CI_MPI_RUN_AS_ROOT=ON -DOMNITRACE_MAX_THREADS=32 - - name: Build - timeout-minutes: 60 - run: - cmake --build build --target all --parallel 2 -- VERBOSE=1 - - name: Install timeout-minutes: 10 run: cmake --build build --target install --parallel 2 - - name: Test - timeout-minutes: 45 - run: - cd build && - ldd ./bin/omnitrace && - ./bin/omnitrace --help && - ctest -V -N -O omnitrace-ctest-${{ github.job }}-commands.log && - ctest -V --output-log omnitrace-ctest-${{ github.job }}.log --stop-on-failure - - name: Test Install timeout-minutes: 10 run: | diff --git a/.github/workflows/ubuntu-bionic.yml b/.github/workflows/ubuntu-bionic.yml index 3fdb2d722c..05d1e71713 100644 --- a/.github/workflows/ubuntu-bionic.yml +++ b/.github/workflows/ubuntu-bionic.yml @@ -24,9 +24,10 @@ jobs: container: image: jrmadsen/omnitrace:ci-base-ubuntu-18.04 strategy: + fail-fast: false matrix: compiler: ['g++-7', 'g++-8'] - mpi: [ '', 'libmpich-dev mpich' ] + mpi: [ 'nompi', 'mpich' ] steps: - name: Patch Git @@ -48,7 +49,9 @@ jobs: run: apt-get update && apt-get upgrade -y && - apt-get install -y build-essential m4 autoconf libtool python3-pip ${{ matrix.compiler }} ${{ matrix.mpi }} && + apt-get install -y build-essential m4 autoconf libtool python3-pip ${{ matrix.compiler }} && + if [ "${{ matrix.mpi }}" = "mpich" ]; then apt-get install -y libmpich-dev mpich; fi && + if [ "${{ matrix.mpi }}" = "openmpi" ]; then apt-get install -y libopenmpi-dev openmpi-bin libfabric-dev; fi && python3 -m pip install --upgrade pip && python3 -m pip install numpy && python3 -m pip install perfetto && @@ -71,12 +74,18 @@ jobs: echo "/opt/omnitrace/bin:${HOME}/.local/bin" >> $GITHUB_PATH && echo "LD_LIBRARY_PATH=/opt/omnitrace/lib:${LD_LIBRARY_PATH}" >> $GITHUB_ENV - - name: Configure CMake - timeout-minutes: 10 + - name: Configure, Build, and Test + timeout-minutes: 115 + shell: bash run: cmake --version && - if [ -z "${{ matrix.mpi }}" ]; then USE_MPI=OFF; else USE_MPI=ON; fi && - cmake -B build + if [ "${{ matrix.mpi }}" = "nompi" ]; then USE_MPI=OFF; else USE_MPI=ON; fi && + append-tagname() { if [ "${1}" == "ON" ]; then TAG="${TAG}-${2}"; fi; } && + ./scripts/run-ci.sh -B build + --name ubuntu-bionic-${{ matrix.compiler }}-${{ matrix.mpi }}-python + --build-jobs 2 + --site GitHub + --cmake-args -DCMAKE_C_COMPILER=$(echo '${{ matrix.compiler }}' | sed 's/+/c/g') -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} @@ -91,24 +100,10 @@ jobs: -DLULESH_BUILD_KOKKOS=OFF -DOMNITRACE_MAX_THREADS=32 - - name: Build - timeout-minutes: 60 - run: - cmake --build build --target all --parallel 2 -- VERBOSE=1 - - name: Install run: cmake --build build --target install --parallel 2 - - name: Test - timeout-minutes: 45 - run: - cd build && - ldd ./bin/omnitrace && - ./bin/omnitrace --help && - ctest -V -N -O omnitrace-ctest-${{ github.job }}-commands.log && - ctest -V --output-log omnitrace-ctest-${{ github.job }}.log --stop-on-failure - - name: Test Install timeout-minutes: 10 run: | diff --git a/.github/workflows/ubuntu-focal.yml b/.github/workflows/ubuntu-focal.yml index d47265d8e6..9aa62374f2 100644 --- a/.github/workflows/ubuntu-focal.yml +++ b/.github/workflows/ubuntu-focal.yml @@ -21,6 +21,7 @@ jobs: container: image: jrmadsen/omnitrace:ci-base-ubuntu-20.04 strategy: + fail-fast: false matrix: compiler: ['g++-7', 'g++-8'] lto: ['OFF'] @@ -87,12 +88,25 @@ jobs: echo "CC=$(echo '${{ matrix.compiler }}' | sed 's/+/c/g')" >> $GITHUB_ENV && echo "CXX=${{ matrix.compiler }}" >> $GITHUB_ENV - - name: Configure CMake - timeout-minutes: 10 + - name: Configure, Build, and Test + timeout-minutes: 115 + shell: bash run: git config --global --add safe.directory ${PWD} && + TAG="" && + append-tagname() { if [ "${1}" == "ON" ]; then TAG="${TAG}-${2}"; fi; } && + append-tagname ${{ matrix.lto }} lto && + append-tagname ${{ matrix.strip }} strip && + append-tagname ${{ matrix.python }} python && + append-tagname ${{ matrix.mpi-headers }} mpip && + append-tagname ${{ matrix.static-libgcc }} libgcc && + append-tagname ${{ matrix.static-libstdcxx }} libstdcxx && cmake --version && - cmake -B build + ./scripts/run-ci.sh -B build + --name ubuntu-focal-${{ matrix.compiler }}${TAG} + --build-jobs 2 + --site GitHub + --cmake-args -DCMAKE_C_COMPILER=$(echo '${{ matrix.compiler }}' | sed 's/+/c/g') -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} @@ -112,17 +126,7 @@ jobs: -DOMNITRACE_PYTHON_ENVS="py3.6;py3.7;py3.8;py3.9;py3.10" -DOMNITRACE_MAX_THREADS=32 - - name: Build - timeout-minutes: 60 - run: - cmake --build build --target all --parallel 2 -- VERBOSE=1 - - - name: Install - timeout-minutes: 10 - run: - cmake --build build --target install --parallel 2 - - - name: Test + - name: Test Build-Tree Module timeout-minutes: 45 shell: bash run: | @@ -134,8 +138,25 @@ jobs: echo $(which omnitrace) ldd $(which omnitrace) omnitrace --help - ctest -V -N -O omnitrace-ctest-${{ github.job }}-commands.log - ctest -V --output-log omnitrace-ctest-${{ github.job }}.log --stop-on-failure + omnitrace-avail --help + omnitrace-sample --help + + - name: Test Build-Tree Source Script + timeout-minutes: 45 + shell: bash + run: | + cd build + source ./share/omnitrace/setup-env.sh + echo $(which omnitrace) + ldd $(which omnitrace) + omnitrace --help + omnitrace-avail --help + omnitrace-sample --help + + - name: Install + timeout-minutes: 10 + run: + cmake --build build --target install --parallel 2 - name: Test Install timeout-minutes: 15 @@ -184,19 +205,20 @@ jobs: container: image: jrmadsen/omnitrace:ci-base-ubuntu-20.04 strategy: + fail-fast: false matrix: compiler: ['g++'] - rocm_version: ['4.3', '4.5', '5.0'] - mpi_headers: ['OFF'] - build_jobs: ['4'] - ctest_exclude: ['-LE "mpi-example|transpose"'] + rocm-version: ['4.3', '4.5', '5.0'] + mpi-headers: ['OFF'] + build-jobs: ['4'] + ctest-exclude: ['-LE "mpi-example|transpose"'] perfetto-tools: ['ON'] include: - compiler: 'g++' - rocm_version: 'debian' - mpi_headers: 'ON' - build_jobs: '2' - ctest_exclude: '-LE transpose' + rocm-version: 'debian' + mpi-headers: 'ON' + build-jobs: '2' + ctest-exclude: '-LE transpose' perfetto-tools: 'OFF' env: @@ -213,7 +235,7 @@ jobs: apt-get update && apt-get install -y software-properties-common wget gnupg2 && wget -q -O - https://repo.radeon.com/rocm/rocm.gpg.key | apt-key add - && - echo "deb [arch=amd64] https://repo.radeon.com/rocm/apt/${{ matrix.rocm_version }}/ ubuntu main" | tee /etc/apt/sources.list.d/rocm.list && + echo "deb [arch=amd64] https://repo.radeon.com/rocm/apt/${{ matrix.rocm-version }}/ ubuntu main" | tee /etc/apt/sources.list.d/rocm.list && apt-get update && apt-get install -y build-essential m4 autoconf libtool python3-pip clang libomp-dev ${{ matrix.compiler }} libudev1 libnuma1 rocm-dev rocm-utils rocm-smi-lib roctracer-dev rocprofiler-dev hip-base hsa-amd-aqlprofile hsa-rocr-dev hsakmt-roct-dev libpapi-dev curl libopenmpi-dev openmpi-bin libfabric-dev && python3 -m pip install --upgrade pip && @@ -221,7 +243,7 @@ jobs: for i in 6 7 8 9 10; do /opt/conda/envs/py3.${i}/bin/python -m pip install numpy perfetto dataclasses; done - name: Install RCCL - if: ${{ matrix.rocm_version != '4.3' }} + if: ${{ matrix.rocm-version != '4.3' }} timeout-minutes: 10 run: apt-get install -y rccl-dev @@ -251,12 +273,19 @@ jobs: realpath test-install.cfg cat test-install.cfg - - name: Configure CMake - timeout-minutes: 10 + - name: Configure, Build, and Test + timeout-minutes: 115 + shell: bash run: git config --global --add safe.directory ${PWD} && cmake --version && - cmake -B build + TAG="-rocm-${{ matrix.rocm-version }}" && + TAG="$(echo ${TAG} | sed 's/debian/latest/g')" && + ./scripts/run-ci.sh -B build + --name ubuntu-focal-rocm-${{ matrix.compiler }}${TAG} + --build-jobs 2 + --site GitHub + --cmake-args -DCMAKE_C_COMPILER=$(echo '${{ matrix.compiler }}' | sed 's/+/c/g') -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} @@ -271,32 +300,20 @@ jobs: -DOMNITRACE_USE_PAPI=OFF -DOMNITRACE_USE_OMPT=OFF -DOMNITRACE_USE_PYTHON=ON - -DOMNITRACE_USE_MPI_HEADERS=${{ matrix.mpi_headers }} + -DOMNITRACE_USE_MPI_HEADERS=${{ matrix.mpi-headers }} -DOMNITRACE_USE_SANITIZER=OFF -DOMNITRACE_INSTALL_PERFETTO_TOOLS=${{ matrix.perfetto-tools }} -DOMNITRACE_PYTHON_PREFIX=/opt/conda/envs -DOMNITRACE_PYTHON_ENVS="py3.6;py3.7;py3.8;py3.9;py3.10" - -DOMNITRACE_CI_MPI_RUN_AS_ROOT=${{ matrix.mpi_headers }} + -DOMNITRACE_CI_MPI_RUN_AS_ROOT=${{ matrix.mpi-headers }} -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=OFF - - - name: Build - timeout-minutes: 60 - run: - cmake --build build --target all --parallel ${{ matrix.build_jobs }} -- VERBOSE=1 + --ctest-args + ${{ matrix.ctest-exclude }} - name: Install run: cmake --build build --target install --parallel 2 - - name: Test - timeout-minutes: 45 - run: - cd build && - ldd ./bin/omnitrace && - ./bin/omnitrace --help && - ctest -V ${{ matrix.ctest_exclude }} -N -O omnitrace-ctest-${{ github.job }}-commands.log && - ctest -V ${{ matrix.ctest_exclude }} --output-log omnitrace-ctest-${{ github.job }}.log --stop-on-failure - - name: Test Install timeout-minutes: 15 shell: bash @@ -340,9 +357,10 @@ jobs: ubuntu-focal: runs-on: ubuntu-20.04 strategy: + fail-fast: false matrix: compiler: ['g++'] - mpi: [ '', 'libmpich-dev mpich', 'libopenmpi-dev openmpi-bin libfabric-dev' ] + mpi: [ 'nompi', 'mpich', 'openmpi' ] boost: ['OFF'] tbb: ['OFF'] build-type: ['Release'] @@ -352,7 +370,7 @@ jobs: deps: ['libtbb-dev libboost-{atomic,system,thread,date-time,filesystem,timer}-dev'] include: - compiler: 'g++' - mpi: '' + mpi: 'nompi' boost: 'ON' tbb: 'ON' build-type: 'Release' @@ -373,7 +391,9 @@ jobs: timeout-minutes: 10 run: sudo apt-get update && - sudo apt-get install -y build-essential m4 autoconf libtool python3-pip clang libomp-dev environment-modules ${{ matrix.deps }} ${{ matrix.compiler }} ${{ matrix.mpi }} && + sudo apt-get install -y build-essential m4 autoconf libtool python3-pip clang libomp-dev environment-modules ${{ matrix.deps }} ${{ matrix.compiler }} && + if [ "${{ matrix.mpi }}" = "mpich" ]; then sudo apt-get install -y libmpich-dev mpich; fi && + if [ "${{ matrix.mpi }}" = "openmpi" ]; then sudo apt-get install -y libopenmpi-dev openmpi-bin libfabric-dev; fi && python3 -m pip install --upgrade pip && python3 -m pip install numpy && python3 -m pip install perfetto && @@ -392,12 +412,18 @@ jobs: echo "CXX=${{ matrix.compiler }}" >> $GITHUB_ENV && echo "${HOME}/.local/bin" >> $GITHUB_PATH - - name: Configure CMake - timeout-minutes: 10 + - name: Configure, Build, and Test + timeout-minutes: 115 + shell: bash run: cmake --version && - if [ -z "${{ matrix.mpi }}" ]; then USE_MPI=OFF; else USE_MPI=ON; fi && - cmake -B ${{ github.workspace }}/build + if [ "${{ matrix.mpi }}" = "nompi" ]; then USE_MPI=OFF; else USE_MPI=ON; fi && + if [ -z "${{ matrix.deps }}" ]; then TAG=""; else TAG="-external-deps"; fi && + ./scripts/run-ci.sh -B ${{ github.workspace }}/build + --name ubuntu-focal-${{ matrix.compiler }}-${{ matrix.mpi }}${TAG} + --build-jobs 2 + --site GitHub + --cmake-args -DCMAKE_C_COMPILER=$(echo '${{ matrix.compiler }}' | sed 's/+/c/g') -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} @@ -433,18 +459,6 @@ jobs: source ${{ github.workspace }}/build/share/omnitrace/setup-env.sh env - - name: Build - timeout-minutes: 60 - run: - cmake --build ${{ github.workspace }}/build --target all --parallel 2 -- VERBOSE=1 - - - name: Test - timeout-minutes: 45 - working-directory: ${{ github.workspace }}/build - run: - ctest -V -N -O ${{ github.workspace }}/build/omnitrace-ctest-${{ github.job }}-commands.log && - ctest -V --output-log ${{ github.workspace }}/build/omnitrace-ctest-${{ github.job }}.log --stop-on-failure - - name: Install working-directory: ${{ github.workspace }}/build run: | @@ -499,3 +513,56 @@ jobs: set +e RUNNING_PROCS=$(pgrep trace_processor_shell) if [ -n "${RUNNING_PROCS}" ]; then kill -s 9 ${RUNNING_PROCS}; fi + + ubuntu-focal-codecov: + runs-on: ubuntu-20.04 + + container: + image: jrmadsen/omnitrace:ci-base-ubuntu-20.04 + + env: + OMNITRACE_VERBOSE: 2 + + steps: + - uses: actions/checkout@v3 + + - name: Install Packages + timeout-minutes: 10 + run: + apt-get update && + apt-get install -y build-essential m4 autoconf libtool python3-pip clang libomp-dev environment-modules gcc g++ mpich libmpich-dev && + python3 -m pip install --upgrade pip && + python3 -m pip install numpy && + python3 -m pip install perfetto && + python3 -m pip install 'cmake==3.24.1' && + for i in 6 7 8 9 10; do /opt/conda/envs/py3.${i}/bin/python -m pip install numpy perfetto dataclasses; done + + - name: Configure Env + run: + echo "CC=$(echo '${{ matrix.compiler }}' | sed 's/+/c/g')" >> $GITHUB_ENV && + echo "CXX=${{ matrix.compiler }}" >> $GITHUB_ENV && + echo "${HOME}/.local/bin" >> $GITHUB_PATH + + - name: Configure, Build, and Test + timeout-minutes: 115 + shell: bash + run: + git config --global --add safe.directory ${PWD} && + cmake --version && + ./scripts/run-ci.sh -B build + --name ubuntu-focal-codecov-mpi-python-ompt-papi + --build-jobs 2 + --site GitHub + --coverage + --cmake-args + -DCMAKE_INSTALL_PREFIX=/opt/omnitrace + -DOMNITRACE_BUILD_CI=OFF + -DOMNITRACE_BUILD_TESTING=ON + -DOMNITRACE_BUILD_DYNINST=OFF + -DOMNITRACE_USE_MPI=ON + -DOMNITRACE_USE_PYTHON=ON + -DOMNITRACE_USE_OMPT=ON + -DOMNITRACE_USE_PAPI=ON + -DOMNITRACE_USE_HIP=OFF + -DOMNITRACE_USE_RCCL=ON + -DOMNITRACE_MAX_THREADS=32 diff --git a/.github/workflows/ubuntu-jammy.yml b/.github/workflows/ubuntu-jammy.yml index 80cc7225fe..78b6420dee 100644 --- a/.github/workflows/ubuntu-jammy.yml +++ b/.github/workflows/ubuntu-jammy.yml @@ -102,12 +102,31 @@ jobs: echo "CC=$(echo '${{ matrix.compiler }}' | sed 's/+/c/g')" >> $GITHUB_ENV echo "CXX=${{ matrix.compiler }}" >> $GITHUB_ENV - - name: Configure CMake - timeout-minutes: 10 + - name: Configure, Build, and Test + timeout-minutes: 115 + shell: bash run: git config --global --add safe.directory ${PWD} && cmake --version && - cmake -B build + TAG="" && + append-tagname() { if [ "${1}" == "ON" ]; then TAG="${TAG}-${2}"; fi; } && + append-tagname ${{ matrix.hip }} rocm-${{ matrix.rocm-version }} && + append-tagname ${{ matrix.mpi }} mpi && + append-tagname ${{ matrix.ompt }} ompt && + append-tagname ${{ matrix.papi }} papi && + append-tagname ${{ matrix.python }} python && + append-tagname ${{ matrix.mpi-headers }} mpip && + append-tagname ${{ matrix.build-dyninst }} internal-dyninst && + append-tagname ${{ matrix.lto }} lto && + append-tagname ${{ matrix.strip }} strip && + append-tagname ${{ matrix.hidden }} hidden-viz && + append-tagname ${{ matrix.static-libgcc }} libgcc && + append-tagname ${{ matrix.static-libstdcxx }} libstdcxx && + ./scripts/run-ci.sh -B build + --name ubuntu-jammy-${{ matrix.compiler }}${TAG} + --build-jobs 2 + --site GitHub + --cmake-args -DCMAKE_C_COMPILER=$(echo '${{ matrix.compiler }}' | sed 's/+/c/g') -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} @@ -125,27 +144,16 @@ jobs: -DOMNITRACE_BUILD_STATIC_LIBGCC=${{ matrix.static-libgcc }} -DOMNITRACE_BUILD_STATIC_LIBSTDCXX=${{ matrix.static-libstdcxx }} -DOMNITRACE_PYTHON_PREFIX=/opt/conda/envs - -DOMNITRACE_PYTHON_ENVS="py3.6;py3.7;py3.8;py3.9;py3.10" + -DOMNITRACE_PYTHON_ENVS="py3.7;py3.8;py3.9;py3.10" -DOMNITRACE_STRIP_LIBRARIES=${{ matrix.strip }} + -DOMNITRACE_MAX_THREADS=32 -DUSE_CLANG_OMP=OFF - - name: Build - timeout-minutes: 60 - run: - cmake --build build --target all --parallel 2 -- VERBOSE=1 - - name: Install timeout-minutes: 10 run: cmake --build build --target install --parallel 2 - - name: Test - timeout-minutes: 45 - run: - cd build && - ctest -V -N -O omnitrace-ctest-${{ github.job }}-commands.log && - ctest -V --output-log omnitrace-ctest-${{ github.job }}.log - - name: CPack and Install run: | cd build diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a5d35ee6c..c5d46a040d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -173,6 +173,7 @@ omnitrace_add_option(OMNITRACE_USE_OMPT "Enable OpenMP tools support" ON) omnitrace_add_option(OMNITRACE_USE_PYTHON "Enable Python support" OFF) omnitrace_add_option(OMNITRACE_BUILD_DYNINST "Build dyninst from submodule" OFF) omnitrace_add_option(OMNITRACE_BUILD_LIBUNWIND "Build libunwind from submodule" ON) +omnitrace_add_option(OMNITRACE_BUILD_CODECOV "Build for code coverage" OFF) omnitrace_add_option(OMNITRACE_INSTALL_PERFETTO_TOOLS "Install perfetto tools (i.e. traced, perfetto, etc.)" OFF) @@ -269,8 +270,8 @@ if(OMNITRACE_BUILD_HIDDEN_VISIBILITY) endif() if(OMNITRACE_BUILD_TESTING OR "$ENV{OMNITRACE_CI}" MATCHES "[1-9]+|ON|on|y|yes") - include(CTest) enable_testing() + include(CTest) endif() # ------------------------------------------------------------------------------# @@ -281,8 +282,38 @@ endif() set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME core) +if(OMNITRACE_BUILD_CODECOV) + omnitrace_save_variables(CODECOV_FLAGS VARIABLES CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + foreach(_BUILD_TYPE DEBUG MINSIZEREL RELWITHDEBINFO RELEASE) + omnitrace_save_variables(CODECOV_FLAGS VARIABLES CMAKE_C_FLAGS_${_BUILD_TYPE} + CMAKE_CXX_FLAGS_${_BUILD_TYPE}) + endforeach() + + foreach(_BUILD_TYPE DEBUG MINSIZEREL RELWITHDEBINFO RELEASE) + set(CMAKE_C_FLAGS_${_BUILD_TYPE} + "-Og -g3 -fno-omit-frame-pointer -fprofile-abs-path -fprofile-arcs -ftest-coverage" + ) + set(CMAKE_CXX_FLAGS_${_BUILD_TYPE} + "-Og -g3 -fno-omit-frame-pointer -fprofile-abs-path -fprofile-arcs -ftest-coverage" + ) + endforeach() + + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") +endif() + add_subdirectory(source) +if(OMNITRACE_BUILD_CODECOV) + omnitrace_restore_variables(CODECOV_FLAGS VARIABLES CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + + foreach(_BUILD_TYPE DEBUG MINSIZEREL RELWITHDEBINFO RELEASE) + omnitrace_restore_variables( + CODECOV_FLAGS VARIABLES CMAKE_C_FLAGS_${_BUILD_TYPE} + CMAKE_CXX_FLAGS_${_BUILD_TYPE}) + endforeach() +endif() + # ------------------------------------------------------------------------------# # # miscellaneous installs diff --git a/cmake/Formatting.cmake b/cmake/Formatting.cmake index ace9046053..d4a6700bf2 100644 --- a/cmake/Formatting.cmake +++ b/cmake/Formatting.cmake @@ -61,7 +61,7 @@ if(OMNITRACE_CLANG_FORMAT_EXE ${PROJECT_SOURCE_DIR}/source/*.hpp.in ${PROJECT_SOURCE_DIR}/source/*.h ${PROJECT_SOURCE_DIR}/source/*.h.in) file(GLOB_RECURSE examples ${PROJECT_SOURCE_DIR}/examples/*.cpp - ${PROJECT_SOURCE_DIR}/examples/*.hpp) + ${PROJECT_SOURCE_DIR}/examples/*.c ${PROJECT_SOURCE_DIR}/examples/*.hpp) file(GLOB_RECURSE external ${PROJECT_SOURCE_DIR}/examples/lulesh/external/kokkos/*) file( GLOB_RECURSE diff --git a/docker/Dockerfile.opensuse.ci b/docker/Dockerfile.opensuse.ci index 16b90a2b5c..6c89739a0c 100644 --- a/docker/Dockerfile.opensuse.ci +++ b/docker/Dockerfile.opensuse.ci @@ -26,7 +26,7 @@ RUN zypper update -y && \ COPY ./dyninst-source /tmp/dyninst RUN cd /tmp/dyninst && \ - cmake -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_BOOST=ON -DBUILD_TBB=ON -DBUILD_ELFUTILS=ON -DBUILD_LIBIBERTY=ON && \ + cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_BOOST=ON -DBUILD_TBB=ON -DBUILD_ELFUTILS=ON -DBUILD_LIBIBERTY=ON && \ cmake --build build --target all --parallel ${NJOBS} && \ cmake --build build --target install --parallel ${NJOBS} && \ cd /tmp && \ diff --git a/docker/Dockerfile.ubuntu.ci b/docker/Dockerfile.ubuntu.ci index 2096d0604a..47e5909a63 100644 --- a/docker/Dockerfile.ubuntu.ci +++ b/docker/Dockerfile.ubuntu.ci @@ -32,7 +32,7 @@ RUN apt-get update && \ apt-get autoclean && \ locale -a && \ cd /tmp/dyninst && \ - cmake -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_BOOST=ON -DBUILD_TBB=ON -DBUILD_ELFUTILS=ON -DBUILD_LIBIBERTY=ON -DELFUTILS_DOWNLOAD_VERSION=${ELFUTILS_DOWNLOAD_VERSION} -DBOOST_DOWNLOAD_VERSION=${BOOST_DOWNLOAD_VERSION} && \ + cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_BOOST=ON -DBUILD_TBB=ON -DBUILD_ELFUTILS=ON -DBUILD_LIBIBERTY=ON -DELFUTILS_DOWNLOAD_VERSION=${ELFUTILS_DOWNLOAD_VERSION} -DBOOST_DOWNLOAD_VERSION=${BOOST_DOWNLOAD_VERSION} && \ cmake --build build --target all --parallel ${NJOBS} && \ cmake --build build --target install --parallel ${NJOBS} && \ wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh && \ diff --git a/examples/code-coverage/CMakeLists.txt b/examples/code-coverage/CMakeLists.txt index c02261255b..b18f119938 100644 --- a/examples/code-coverage/CMakeLists.txt +++ b/examples/code-coverage/CMakeLists.txt @@ -16,3 +16,23 @@ if(OMNITRACE_INSTALL_EXAMPLES) DESTINATION bin COMPONENT omnitrace-examples) endif() + +set(PYTHON_FILES code-coverage.py) + +find_package(Python3 COMPONENTS Interpreter) + +if(Python3_FOUND) + set(PYTHON_EXECUTABLE "${Python3_EXECUTABLE}") + + foreach(_FILE ${PYTHON_FILES}) + configure_file(${PROJECT_SOURCE_DIR}/${_FILE} ${PROJECT_BINARY_DIR}/${_FILE} + @ONLY) + + if(OMNITRACE_INSTALL_EXAMPLES) + install( + PROGRAMS ${PROJECT_BINARY_DIR}/${_FILE} + DESTINATION bin + COMPONENT omnitrace-examples) + endif() + endforeach() +endif() diff --git a/examples/code-coverage/code-coverage.py b/examples/code-coverage/code-coverage.py new file mode 100644 index 0000000000..efd2f2da9e --- /dev/null +++ b/examples/code-coverage/code-coverage.py @@ -0,0 +1,54 @@ +#!@PYTHON_EXECUTABLE@ + +import omnitrace +import argparse + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + + parser.add_argument( + "-i", + "--input", + type=str, + nargs="+", + help="Input code coverage", + default=None, + required=True, + ) + parser.add_argument( + "-o", + "--output", + type=str, + help="Output code coverage", + default=None, + required=True, + ) + + args = parser.parse_args() + + data = None + for itr in args.input: + _summary, _details = omnitrace.coverage.load(itr) + if data is None: + data = _details + else: + data = omnitrace.coverage.concat(data, _details) + + summary = omnitrace.coverage.get_summary(data) + top = omnitrace.coverage.get_top(data) + bottom = omnitrace.coverage.get_bottom(data) + + print("Top code coverage:") + for itr in top: + print( + f" {itr.count} | {itr.function} | {itr.module}:{itr.line} | {itr.source}" + ) + + print("Bottom code coverage:") + for itr in bottom: + print( + f" {itr.count} | {itr.function} | {itr.module}:{itr.line} | {itr.source}" + ) + + print("\nSaving code coverage") + omnitrace.coverage.save(summary, data, args.output) diff --git a/examples/lulesh/lulesh.cc b/examples/lulesh/lulesh.cc index e62747cedc..f1b65b1120 100644 --- a/examples/lulesh/lulesh.cc +++ b/examples/lulesh/lulesh.cc @@ -751,7 +751,7 @@ CalcHourglassControlForElems(Domain& domain, Real_t determ[], Real_t hgcoef) int error = 0; Kokkos::parallel_reduce( - numElem, + "CalcHourglassControlForElems", numElem, KOKKOS_LAMBDA(const int i, int& err) { Real_t x1[8], y1[8], z1[8]; @@ -813,7 +813,7 @@ CalcVolumeForceForElems(Domain& domain) // check for negative element volume int error = 0; Kokkos::parallel_reduce( - numElem, + "CalcVolumeForceForElems", numElem, KOKKOS_LAMBDA(const int k, int& err) { if(determ[k] <= Real_t(0.0)) { @@ -1221,7 +1221,7 @@ CalcLagrangeElements(Domain& domain) int error = 0; Kokkos::parallel_reduce( - numElem, + "CalcLagrangeElements", numElem, KOKKOS_LAMBDA(const int k, int& err) { Real_t vdov = domain.dxx(k) + domain.dyy(k) + domain.dzz(k); Real_t vdovthird = vdov / Real_t(3.0); @@ -1607,7 +1607,7 @@ CalcQForElems(Domain& domain) Index_t idx = 0; Kokkos::parallel_reduce( - numElem, + "CalcQForElems", numElem, KOKKOS_LAMBDA(const Index_t& i, Index_t& count) { if(domain.q(i) > domain.qstop()) { @@ -1931,7 +1931,7 @@ ApplyMaterialPropertiesForElems(Domain& domain) int error = 0; Kokkos::parallel_reduce( - numElem, + "ApplyMaterialPropertiesForElems", numElem, KOKKOS_LAMBDA(const int i, int& err) { Real_t vc = domain.v(i); if(eosvmin != Real_t(0.)) @@ -1949,7 +1949,7 @@ ApplyMaterialPropertiesForElems(Domain& domain) }, error); - if(error) + if(error != 0) #if USE_MPI MPI_Abort(MPI_COMM_WORLD, VolumeError); #else @@ -2015,7 +2015,7 @@ CalcCourantConstraintForElems(Domain& domain, Index_t length, Index_t r, Real_t MinFinder result; Kokkos::parallel_reduce( - length, + "CalcCourantConstraintForElems", length, KOKKOS_LAMBDA(const int i, MinFinder& minf) { Index_t indx = domain.regElemlist(r, i); Real_t dtf = domain.ss(indx) * domain.ss(indx); @@ -2065,7 +2065,7 @@ CalcHydroConstraintForElems(Domain& domain, Index_t length, Index_t r, Real_t dv MinFinder result; Kokkos::parallel_reduce( - length, + "CalcHydroConstraintForElems", length, KOKKOS_LAMBDA(const int i, MinFinder& minf) { Index_t indx = domain.regElemlist(r, i); @@ -2167,8 +2167,9 @@ main(int argc, char* argv[]) myRank = 0; #endif - Kokkos::initialize(); + Kokkos::initialize(argc, argv); { + Kokkos::Tools::pushRegion("initialization"); opts.its = 9999999; opts.nx = 30; opts.numReg = 11; @@ -2223,24 +2224,41 @@ main(int argc, char* argv[]) MPI_Barrier(MPI_COMM_WORLD); #endif + Kokkos::Tools::popRegion(); + #if USE_MPI double start = MPI_Wtime(); #else timeval start; - gettimeofday(&start, NULL); + gettimeofday(&start, nullptr); #endif + + uint32_t _time_incrp = 0; + uint32_t _leap_frogp = 0; + Kokkos::Tools::createProfileSection("TimeIncr", &_time_incrp); + Kokkos::Tools::createProfileSection("LeapFrog", &_leap_frogp); + while((locDom.time() < locDom.stoptime()) && (locDom.cycle() < opts.its)) { + Kokkos::Tools::startSection(_time_incrp); TimeIncrement(locDom); + Kokkos::Tools::stopSection(_time_incrp); + + Kokkos::Tools::startSection(_leap_frogp); LagrangeLeapFrog(locDom); + Kokkos::Tools::stopSection(_leap_frogp); if((opts.showProg != 0) && (opts.quiet == 0) && (myRank == 0)) { printf("cycle = %d, time = %e, dt=%e\n", locDom.cycle(), double(locDom.time()), double(locDom.deltatime())); } + Kokkos::Tools::markEvent("completed_timestep"); } + Kokkos::Tools::destroyProfileSection(_time_incrp); + Kokkos::Tools::destroyProfileSection(_leap_frogp); + double elapsed_time; #if USE_MPI elapsed_time = MPI_Wtime() - start; @@ -2258,6 +2276,7 @@ main(int argc, char* argv[]) elapsed_timeG = elapsed_time; #endif + Kokkos::Tools::pushRegion("finalization"); if(opts.viz) { DumpToVisit(locDom, opts.numFiles, myRank, numRanks); @@ -2267,6 +2286,7 @@ main(int argc, char* argv[]) { VerifyAndWriteFinalOutput(elapsed_timeG, locDom, opts.nx, numRanks); } + Kokkos::Tools::popRegion(); buffer = Kokkos::View(); } diff --git a/examples/mpi/CMakeLists.txt b/examples/mpi/CMakeLists.txt index 281148521f..be8040ee43 100644 --- a/examples/mpi/CMakeLists.txt +++ b/examples/mpi/CMakeLists.txt @@ -1,8 +1,6 @@ cmake_minimum_required(VERSION 3.16 FATAL_ERROR) -project(omnitrace-mpi-example LANGUAGES CXX) - -set(CMAKE_BUILD_TYPE "Release") +project(omnitrace-mpi-examples LANGUAGES C CXX) find_package(MPI) if(NOT MPI_FOUND) @@ -12,15 +10,51 @@ endif() find_package(Threads REQUIRED) -add_executable(mpi-example mpi.cpp) +set(CMAKE_BUILD_TYPE "RelWithDebInfo") +add_library(mpi-c-interface-library INTERFACE) target_link_libraries( - mpi-example PRIVATE MPI::MPI_CXX Threads::Threads - $) + mpi-c-interface-library + INTERFACE Threads::Threads MPI::MPI_C + $) +target_compile_options(mpi-c-interface-library INTERFACE -Wno-double-promotion) + +add_executable(mpi-allgather allgather.c) +target_link_libraries(mpi-allgather PRIVATE mpi-c-interface-library) + +add_executable(mpi-bcast bcast.c) +target_link_libraries(mpi-bcast PRIVATE mpi-c-interface-library) + +add_executable(mpi-all2all all2all.c) +target_link_libraries(mpi-all2all PRIVATE mpi-c-interface-library) + +add_executable(mpi-reduce reduce.c) +target_link_libraries(mpi-reduce PRIVATE mpi-c-interface-library) + +add_executable(mpi-scatter-gather scatter-gather.c) +target_link_libraries(mpi-scatter-gather PRIVATE mpi-c-interface-library) + +add_executable(mpi-send-recv send-recv.c) +target_link_libraries(mpi-send-recv PRIVATE mpi-c-interface-library) + +add_executable(mpi-allreduce allreduce.c) +target_link_libraries(mpi-allreduce PRIVATE mpi-c-interface-library m) + +set(CMAKE_BUILD_TYPE "Release") + +add_library(mpi-cxx-interface-library INTERFACE) +target_link_libraries( + mpi-cxx-interface-library + INTERFACE Threads::Threads MPI::MPI_CXX + $) + +add_executable(mpi-example mpi.cpp) +target_link_libraries(mpi-example PRIVATE mpi-cxx-interface-library) if(OMNITRACE_INSTALL_EXAMPLES) install( - TARGETS mpi-example + TARGETS mpi-example mpi-allgather mpi-bcast mpi-all2all mpi-reduce + mpi-scatter-gather mpi-send-recv DESTINATION bin COMPONENT omnitrace-examples) endif() diff --git a/examples/mpi/all2all.c b/examples/mpi/all2all.c new file mode 100644 index 0000000000..ab698e02dd --- /dev/null +++ b/examples/mpi/all2all.c @@ -0,0 +1,244 @@ +// Author: Wes Kendall +// Copyright 2014 www.mpitutorial.com +// This code is provided freely with the tutorials on mpitutorial.com. Feel +// free to modify it for your own use. Any distribution of the code must +// either provide a link to www.mpitutorial.com or keep this header intact. +// +// A program that bins random numbers using MPI_Alltoallv. +// +#include +#include +#include +#include +#include + +// Creates an array of random numbers for binning. Note that the numbers are +// between [0, 1) +float* +create_random_numbers(int numbers_per_proc) +{ + float* random_numbers = (float*) malloc(sizeof(float) * numbers_per_proc); + int i; + for(i = 0; i < numbers_per_proc; i++) + { + int r = rand(); + // Make sure that the random number is never exactly one. + if(r == RAND_MAX) + { + r--; + } + random_numbers[i] = rand() / (float) (RAND_MAX); + } + return random_numbers; +} + +// Given a number, determine which process owns it. Since numbers are from [0, 1), +// simply multiple the number by the size of the MPI world to figure out which +// process owns it +int +which_process_owns_this_number(float rand_num, int world_size) +{ + return (int) (rand_num * world_size); +} + +// Gets the starting value for a process's bin +float +get_bin_start(int world_rank, int world_size) +{ + return (float) world_rank / world_size; +} + +// Gets the ending value for a process's bin +float +get_bin_end(int world_rank, int world_size) +{ + return get_bin_start(world_rank + 1, world_size); +} + +// This function returns the amount of numbers that will be sent to each +// process given the array of random numbers. +int* +get_send_amounts_per_proc(float* rand_nums, int numbers_per_proc, int world_size) +{ + int* send_amounts_per_proc = (int*) malloc(sizeof(int) * world_size); + // Initialize the amount of numbers per process to zero + memset(send_amounts_per_proc, 0, sizeof(int) * world_size); + + // For each random number, determine which process owns it and increment + // the amount of numbers for that process. + int i; + for(i = 0; i < numbers_per_proc; i++) + { + int owning_rank = which_process_owns_this_number(rand_nums[i], world_size); + send_amounts_per_proc[owning_rank]++; + } + + return send_amounts_per_proc; +} + +// Given how many numbers each process is sending to the other processes, find +// out how many numbers you are receiving from each process. This function +// returns an array of counts indexed on the rank of the process from which it +// will receive the numbers. +int* +get_recv_amounts_per_proc(int* send_amounts_per_proc, int world_size) +{ + int* recv_amounts_per_proc = (int*) malloc(sizeof(int) * world_size); + + // Perform an Alltoall for the send counts. This will send the send counts + // from each process and place them in the recv_amounts_per_proc array of + // the receiving processes to let them know how many numbers they will + // receive when binning occurs. + MPI_Alltoall(send_amounts_per_proc, 1, MPI_INT, recv_amounts_per_proc, 1, MPI_INT, + MPI_COMM_WORLD); + return recv_amounts_per_proc; +} + +// Given an array (of size "size") of counts, return the prefix sum of the +// counts. +int* +prefix_sum(const int* counts, int size) +{ + int* prefix_sum_result = (int*) malloc(sizeof(int) * size); + prefix_sum_result[0] = 0; + int i; + for(i = 1; i < size; i++) + { + prefix_sum_result[i] = prefix_sum_result[i - 1] + counts[i - 1]; + } + return prefix_sum_result; +} + +// Returns the sum of an array +int +sum(const int* arr, int size) +{ + int sum_result = 0; + int i; + for(i = 0; i < size; i++) + { + sum_result += arr[i]; + } + return sum_result; +} + +// Used for sorting floating point numbers +int +compare_float(const void* a, const void* b) +{ + if(*(float*) a < *(float*) b) + { + return -1; + } + else if(*(float*) a > *(float*) b) + { + return 1; + } + else + { + return 0; + } +} + +// Verifies that the binned numbers belong to the process. +void +verify_bin_nums(float* binned_nums, int num_count, int world_rank, int world_size) +{ + int i; + float bin_start = get_bin_start(world_rank, world_size); + float bin_end = get_bin_end(world_rank, world_size); + for(i = 0; i < num_count; i++) + { + if(binned_nums[i] >= bin_end || binned_nums[i] < bin_start) + { + fprintf( + stderr, + "Error: Binned number %f exceeds bin range [%f - %f) for process %d\n", + binned_nums[i], bin_start, bin_end, world_rank); + } + } +} + +int +main(int argc, char** argv) +{ + if(argc != 2) + { + fprintf(stderr, "Usage: bin numbers_per_proc\n"); + exit(1); + } + + // Get the amount of random numbers to create per process + int numbers_per_proc = atoi(argv[1]); + + MPI_Init(NULL, NULL); + + int world_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); + int world_size; + MPI_Comm_size(MPI_COMM_WORLD, &world_size); + + // Seed the random number generator to get different results each time + srand(time(NULL) * world_rank); + + // Create the random numbers on this process. Note that all numbers + // will be between 0 and 1 + float* rand_nums = create_random_numbers(numbers_per_proc); + + // Given the array of random numbers, determine how many will be sent + // to each process (based on the which process owns the number). + // The return value from this function is an array of counts + // for each rank in the communicator. + // The count represents how many numbers each process will receive + // when they are binned from this process. + int* send_amounts_per_proc = + get_send_amounts_per_proc(rand_nums, numbers_per_proc, world_size); + + // Determine how many numbers you will receive from each process. This + // information is needed to set up the binning call. + int* recv_amounts_per_proc = + get_recv_amounts_per_proc(send_amounts_per_proc, world_size); + + // Do a prefix sum for the send/recv amounts to get the send/recv offsets for + // the MPI_Alltoallv call (the binning call). + int* send_offsets_per_proc = prefix_sum(send_amounts_per_proc, world_size); + int* recv_offsets_per_proc = prefix_sum(recv_amounts_per_proc, world_size); + + // Allocate an array to hold the binned numbers for this process based on the total + // amount of numbers this process will receive from others. + int total_recv_amount = sum(recv_amounts_per_proc, world_size); + float* binned_nums = (float*) malloc(sizeof(float) * total_recv_amount); + + // The final step before binning - arrange all of the random numbers so that they + // are ordered by bin. For simplicity, we are simply going to sort the random + // numbers, however, this could be optimized since the numbers don't need to be + // fully sorted. + qsort(rand_nums, numbers_per_proc, sizeof(float), &compare_float); + + // Perform the binning step with MPI_Alltoallv. This will send all of the numbers in + // the rand_nums array to their proper bin. Each process will only contain numbers + // belonging to its bin after this step. For example, if there are 4 processes, + // process 0 will contain numbers in the [0, .25) range. + MPI_Alltoallv(rand_nums, send_amounts_per_proc, send_offsets_per_proc, MPI_FLOAT, + binned_nums, recv_amounts_per_proc, recv_offsets_per_proc, MPI_FLOAT, + MPI_COMM_WORLD); + + // Print results + printf("Process %d received %d numbers in bin [%f - %f)\n", world_rank, + total_recv_amount, get_bin_start(world_rank, world_size), + get_bin_end(world_rank, world_size)); + + // Check that the bin numbers are correct + verify_bin_nums(binned_nums, total_recv_amount, world_rank, world_size); + + MPI_Barrier(MPI_COMM_WORLD); + MPI_Finalize(); + + // Clean up + free(rand_nums); + free(send_amounts_per_proc); + free(recv_amounts_per_proc); + free(send_offsets_per_proc); + free(recv_offsets_per_proc); + free(binned_nums); +} diff --git a/examples/mpi/allgather.c b/examples/mpi/allgather.c new file mode 100644 index 0000000000..4400896918 --- /dev/null +++ b/examples/mpi/allgather.c @@ -0,0 +1,107 @@ +// Author: Wes Kendall +// Copyright 2012 www.mpitutorial.com +// This code is provided freely with the tutorials on mpitutorial.com. Feel +// free to modify it for your own use. Any distribution of the code must +// either provide a link to www.mpitutorial.com or keep this header intact. +// +// Program that computes the average of an array of elements in parallel using +// MPI_Scatter and MPI_Allgather +// +#include +#include +#include +#include +#include + +// Creates an array of random numbers. Each number has a value from 0 - 1 +float* +create_rand_nums(int num_elements) +{ + float* rand_nums = (float*) malloc(sizeof(float) * num_elements); + assert(rand_nums != NULL); + int i; + for(i = 0; i < num_elements; i++) + { + rand_nums[i] = (rand() / (float) RAND_MAX); + } + return rand_nums; +} + +// Computes the average of an array of numbers +float +compute_avg(float* array, int num_elements) +{ + float sum = 0.f; + int i; + for(i = 0; i < num_elements; i++) + { + sum += array[i]; + } + return sum / num_elements; +} + +int +main(int argc, char** argv) +{ + if(argc != 2) + { + fprintf(stderr, "Usage: avg num_elements_per_proc\n"); + exit(1); + } + + int num_elements_per_proc = atoi(argv[1]); + // Seed the random number generator to get different results each time + srand(time(NULL)); + + MPI_Init(NULL, NULL); + + int world_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); + int world_size; + MPI_Comm_size(MPI_COMM_WORLD, &world_size); + + // Create a random array of elements on the root process. Its total + // size will be the number of elements per process times the number + // of processes + float* rand_nums = NULL; + if(world_rank == 0) + { + rand_nums = create_rand_nums(num_elements_per_proc * world_size); + } + + // For each process, create a buffer that will hold a subset of the entire + // array + float* sub_rand_nums = (float*) malloc(sizeof(float) * num_elements_per_proc); + assert(sub_rand_nums != NULL); + + // Scatter the random numbers from the root process to all processes in + // the MPI world + MPI_Scatter(rand_nums, num_elements_per_proc, MPI_FLOAT, sub_rand_nums, + num_elements_per_proc, MPI_FLOAT, 0, MPI_COMM_WORLD); + + // Compute the average of your subset + float sub_avg = compute_avg(sub_rand_nums, num_elements_per_proc); + + // Gather all partial averages down to all the processes + float* sub_avgs = (float*) malloc(sizeof(float) * world_size); + assert(sub_avgs != NULL); + MPI_Allgather(&sub_avg, 1, MPI_FLOAT, sub_avgs, 1, MPI_FLOAT, MPI_COMM_WORLD); + + // Now that we have all of the partial averages, compute the + // total average of all numbers. Since we are assuming each process computed + // an average across an equal amount of elements, this computation will + // produce the correct answer. + float avg = compute_avg(sub_avgs, world_size); + printf("Avg of all elements from proc %d is %f\n", world_rank, avg); + + // Clean up + if(world_rank == 0) + { + free(rand_nums); + } + free(sub_avgs); + free(sub_rand_nums); + + MPI_Barrier(MPI_COMM_WORLD); + MPI_Finalize(); +} diff --git a/examples/mpi/allreduce.c b/examples/mpi/allreduce.c new file mode 100644 index 0000000000..ca252c2729 --- /dev/null +++ b/examples/mpi/allreduce.c @@ -0,0 +1,94 @@ +// Author: Wes Kendall +// Copyright 2013 www.mpitutorial.com +// This code is provided freely with the tutorials on mpitutorial.com. Feel +// free to modify it for your own use. Any distribution of the code must +// either provide a link to www.mpitutorial.com or keep this header intact. +// +// Program that computes the standard deviation of an array of elements in parallel using +// MPI_Reduce. +// +#include +#include +#include +#include +#include +#include + +// Creates an array of random numbers. Each number has a value from 0 - 1 +float* +create_rand_nums(int num_elements) +{ + float* rand_nums = (float*) malloc(sizeof(float) * num_elements); + assert(rand_nums != NULL); + int i; + for(i = 0; i < num_elements; i++) + { + rand_nums[i] = (rand() / (float) RAND_MAX); + } + return rand_nums; +} + +int +main(int argc, char** argv) +{ + if(argc != 2) + { + fprintf(stderr, "Usage: avg num_elements_per_proc\n"); + exit(1); + } + + int num_elements_per_proc = atoi(argv[1]); + + MPI_Init(NULL, NULL); + + int world_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); + int world_size; + MPI_Comm_size(MPI_COMM_WORLD, &world_size); + + // Create a random array of elements on all processes. + srand(time(NULL) * + world_rank); // Seed the random number generator of processes uniquely + float* rand_nums = NULL; + rand_nums = create_rand_nums(num_elements_per_proc); + + // Sum the numbers locally + float local_sum = 0; + int i; + for(i = 0; i < num_elements_per_proc; i++) + { + local_sum += rand_nums[i]; + } + + // Reduce all of the local sums into the global sum in order to + // calculate the mean + float global_sum; + MPI_Allreduce(&local_sum, &global_sum, 1, MPI_FLOAT, MPI_SUM, MPI_COMM_WORLD); + float mean = global_sum / (num_elements_per_proc * world_size); + + // Compute the local sum of the squared differences from the mean + float local_sq_diff = 0; + for(i = 0; i < num_elements_per_proc; i++) + { + local_sq_diff += (rand_nums[i] - mean) * (rand_nums[i] - mean); + } + + // Reduce the global sum of the squared differences to the root process + // and print off the answer + float global_sq_diff; + MPI_Reduce(&local_sq_diff, &global_sq_diff, 1, MPI_FLOAT, MPI_SUM, 0, MPI_COMM_WORLD); + + // The standard deviation is the square root of the mean of the squared + // differences. + if(world_rank == 0) + { + float stddev = sqrt(global_sq_diff / (num_elements_per_proc * world_size)); + printf("Mean - %f, Standard deviation = %f\n", mean, stddev); + } + + // Clean up + free(rand_nums); + + MPI_Barrier(MPI_COMM_WORLD); + MPI_Finalize(); +} diff --git a/examples/mpi/bcast.c b/examples/mpi/bcast.c new file mode 100644 index 0000000000..038359b3cf --- /dev/null +++ b/examples/mpi/bcast.c @@ -0,0 +1,134 @@ +// Author: Wes Kendall +// Copyright 2011 www.mpitutorial.com +// This code is provided freely with the tutorials on mpitutorial.com. Feel +// free to modify it for your own use. Any distribution of the code must +// either provide a link to www.mpitutorial.com or keep this header intact. +// +// Comparison of MPI_Bcast with the my_bcast function +// +#include +#include +#include +#include + +void +my_bcast(void* data, int count, MPI_Datatype datatype, int root, MPI_Comm communicator) +{ + int world_rank; + MPI_Comm_rank(communicator, &world_rank); + int world_size; + MPI_Comm_size(communicator, &world_size); + + if(world_rank == root) + { + // If we are the root process, send our data to everyone + int i; + for(i = 0; i < world_size; i++) + { + if(i != world_rank) + { + MPI_Send(data, count, datatype, i, 0, communicator); + } + } + } + else + { + // If we are a receiver process, receive the data from the root + MPI_Recv(data, count, datatype, root, 0, communicator, MPI_STATUS_IGNORE); + } +} + +void +my_ibcast(void* data, int count, MPI_Datatype datatype, int root, MPI_Comm communicator) +{ + int world_rank; + MPI_Comm_rank(communicator, &world_rank); + int world_size; + MPI_Comm_size(communicator, &world_size); + MPI_Request request = MPI_REQUEST_NULL; + + if(world_rank == root) + { + // If we are the root process, send our data to everyone + int i; + for(i = 0; i < world_size; i++) + { + if(i != world_rank) + { + MPI_Isend(data, count, datatype, i, 0, communicator, &request); + } + } + } + else + { + // If we are a receiver process, receive the data from the root + MPI_Irecv(data, count, datatype, root, 0, communicator, &request); + } + + MPI_Status status; + // bloks and waits for destination process to receive data + MPI_Wait(&request, &status); +} + +int +main(int argc, char** argv) +{ + int num_elements = 30; + int num_trials = 50; + + if(argc != 3) fprintf(stderr, "Usage: compare_bcast [num_elements] [num_trials]\n"); + + if(argc > 1) num_elements = atoi(argv[1]); + if(argc > 2) num_trials = atoi(argv[2]); + + MPI_Init(NULL, NULL); + + int world_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); + + double total_my_bcast_time = 0.0; + double total_my_ibcast_time = 0.0; + double total_mpi_bcast_time = 0.0; + int i; + int* data = (int*) malloc(sizeof(int) * num_elements); + assert(data != NULL); + + for(i = 0; i < num_trials; i++) + { + // Time my_bcast + // Synchronize before starting timing + MPI_Barrier(MPI_COMM_WORLD); + total_my_bcast_time -= MPI_Wtime(); + my_bcast(data, num_elements, MPI_INT, 0, MPI_COMM_WORLD); + // Synchronize again before obtaining final time + MPI_Barrier(MPI_COMM_WORLD); + total_my_bcast_time += MPI_Wtime(); + + MPI_Barrier(MPI_COMM_WORLD); + total_my_ibcast_time -= MPI_Wtime(); + my_ibcast(data, num_elements, MPI_INT, 0, MPI_COMM_WORLD); + // Synchronize again before obtaining final time + MPI_Barrier(MPI_COMM_WORLD); + total_my_ibcast_time += MPI_Wtime(); + + // Time MPI_Bcast + MPI_Barrier(MPI_COMM_WORLD); + total_mpi_bcast_time -= MPI_Wtime(); + MPI_Bcast(data, num_elements, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Barrier(MPI_COMM_WORLD); + total_mpi_bcast_time += MPI_Wtime(); + } + + // Print off timing information + if(world_rank == 0) + { + printf("Data size = %d, Trials = %d\n", num_elements * (int) sizeof(int), + num_trials); + printf("Avg my_bcast time = %lf\n", total_my_bcast_time / num_trials); + printf("Avg my_ibcast time = %lf\n", total_my_ibcast_time / num_trials); + printf("Avg MPI_Bcast time = %lf\n", total_mpi_bcast_time / num_trials); + } + + free(data); + MPI_Finalize(); +} diff --git a/examples/mpi/reduce.c b/examples/mpi/reduce.c new file mode 100644 index 0000000000..6d82cc9be8 --- /dev/null +++ b/examples/mpi/reduce.c @@ -0,0 +1,82 @@ +// Author: Wes Kendall +// Copyright 2013 www.mpitutorial.com +// This code is provided freely with the tutorials on mpitutorial.com. Feel +// free to modify it for your own use. Any distribution of the code must +// either provide a link to www.mpitutorial.com or keep this header intact. +// +// Program that computes the average of an array of elements in parallel using +// MPI_Reduce. +// +#include +#include +#include +#include +#include + +// Creates an array of random numbers. Each number has a value from 0 - 1 +float* +create_rand_nums(int num_elements) +{ + float* rand_nums = (float*) malloc(sizeof(float) * num_elements); + assert(rand_nums != NULL); + int i; + for(i = 0; i < num_elements; i++) + { + rand_nums[i] = (rand() / (float) RAND_MAX); + } + return rand_nums; +} + +int +main(int argc, char** argv) +{ + if(argc != 2) + { + fprintf(stderr, "Usage: avg num_elements_per_proc\n"); + exit(1); + } + + int num_elements_per_proc = atoi(argv[1]); + + MPI_Init(NULL, NULL); + + int world_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); + int world_size; + MPI_Comm_size(MPI_COMM_WORLD, &world_size); + + // Create a random array of elements on all processes. + srand(time(NULL) * world_rank); // Seed the random number generator to get different + // results each time for each processor + float* rand_nums = NULL; + rand_nums = create_rand_nums(num_elements_per_proc); + + // Sum the numbers locally + float local_sum = 0; + int i; + for(i = 0; i < num_elements_per_proc; i++) + { + local_sum += rand_nums[i]; + } + + // Print the random numbers on each process + printf("Local sum for process %d - %f, avg = %f\n", world_rank, local_sum, + local_sum / num_elements_per_proc); + + // Reduce all of the local sums into the global sum + float global_sum; + MPI_Reduce(&local_sum, &global_sum, 1, MPI_FLOAT, MPI_SUM, 0, MPI_COMM_WORLD); + + // Print the result + if(world_rank == 0) + { + printf("Total sum = %f, avg = %f\n", global_sum, + global_sum / (world_size * num_elements_per_proc)); + } + + // Clean up + free(rand_nums); + + MPI_Barrier(MPI_COMM_WORLD); + MPI_Finalize(); +} diff --git a/examples/mpi/scatter-gather.c b/examples/mpi/scatter-gather.c new file mode 100644 index 0000000000..c9af42cb53 --- /dev/null +++ b/examples/mpi/scatter-gather.c @@ -0,0 +1,118 @@ +// Author: Wes Kendall +// Copyright 2012 www.mpitutorial.com +// This code is provided freely with the tutorials on mpitutorial.com. Feel +// free to modify it for your own use. Any distribution of the code must +// either provide a link to www.mpitutorial.com or keep this header intact. +// +// Program that computes the average of an array of elements in parallel using +// MPI_Scatter and MPI_Gather +// +#include +#include +#include +#include +#include + +// Creates an array of random numbers. Each number has a value from 0 - 1 +float* +create_rand_nums(int num_elements) +{ + float* rand_nums = (float*) malloc(sizeof(float) * num_elements); + assert(rand_nums != NULL); + int i; + for(i = 0; i < num_elements; i++) + { + rand_nums[i] = (rand() / (float) RAND_MAX); + } + return rand_nums; +} + +// Computes the average of an array of numbers +float +compute_avg(float* array, int num_elements) +{ + float sum = 0.f; + int i; + for(i = 0; i < num_elements; i++) + { + sum += array[i]; + } + return sum / num_elements; +} + +int +main(int argc, char** argv) +{ + if(argc != 2) + { + fprintf(stderr, "Usage: avg num_elements_per_proc\n"); + exit(1); + } + + int num_elements_per_proc = atoi(argv[1]); + // Seed the random number generator to get different results each time + srand(time(NULL)); + + MPI_Init(NULL, NULL); + + int world_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); + int world_size; + MPI_Comm_size(MPI_COMM_WORLD, &world_size); + + // Create a random array of elements on the root process. Its total + // size will be the number of elements per process times the number + // of processes + float* rand_nums = NULL; + if(world_rank == 0) + { + rand_nums = create_rand_nums(num_elements_per_proc * world_size); + } + + // For each process, create a buffer that will hold a subset of the entire + // array + float* sub_rand_nums = (float*) malloc(sizeof(float) * num_elements_per_proc); + assert(sub_rand_nums != NULL); + + // Scatter the random numbers from the root process to all processes in + // the MPI world + MPI_Scatter(rand_nums, num_elements_per_proc, MPI_FLOAT, sub_rand_nums, + num_elements_per_proc, MPI_FLOAT, 0, MPI_COMM_WORLD); + + // Compute the average of your subset + float sub_avg = compute_avg(sub_rand_nums, num_elements_per_proc); + + // Gather all partial averages down to the root process + float* sub_avgs = NULL; + if(world_rank == 0) + { + sub_avgs = (float*) malloc(sizeof(float) * world_size); + assert(sub_avgs != NULL); + } + MPI_Gather(&sub_avg, 1, MPI_FLOAT, sub_avgs, 1, MPI_FLOAT, 0, MPI_COMM_WORLD); + + // Now that we have all of the partial averages on the root, compute the + // total average of all numbers. Since we are assuming each process computed + // an average across an equal amount of elements, this computation will + // produce the correct answer. + if(world_rank == 0) + { + float avg = compute_avg(sub_avgs, world_size); + printf("Avg of all elements is %f\n", avg); + // Compute the average across the original data for comparison + float original_data_avg = + compute_avg(rand_nums, num_elements_per_proc * world_size); + printf("Avg computed across original data is %f\n", original_data_avg); + } + + // Clean up + if(world_rank == 0) + { + free(rand_nums); + free(sub_avgs); + } + free(sub_rand_nums); + + MPI_Barrier(MPI_COMM_WORLD); + MPI_Finalize(); +} diff --git a/examples/mpi/send-recv.c b/examples/mpi/send-recv.c new file mode 100644 index 0000000000..7ac673972c --- /dev/null +++ b/examples/mpi/send-recv.c @@ -0,0 +1,55 @@ +// Author: Wes Kendall +// Copyright 2011 www.mpitutorial.com +// This code is provided freely with the tutorials on mpitutorial.com. Feel +// free to modify it for your own use. Any distribution of the code must +// either provide a link to www.mpitutorial.com or keep this header intact. +// +// Ping pong example with MPI_Send and MPI_Recv. Two processes ping pong a +// number back and forth, incrementing it until it reaches a given value. +// +#include +#include +#include + +int +main(int argc, char** argv) +{ + const int PING_PONG_LIMIT = 10; + + // Initialize the MPI environment + MPI_Init(NULL, NULL); + // Find out rank, size + int world_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); + int world_size; + MPI_Comm_size(MPI_COMM_WORLD, &world_size); + + // We are assuming 2 processes for this task + if(world_size != 2) + { + fprintf(stderr, "World size must be two for %s\n", argv[0]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + + int ping_pong_count = 0; + int partner_rank = (world_rank + 1) % 2; + while(ping_pong_count < PING_PONG_LIMIT) + { + if(world_rank == ping_pong_count % 2) + { + // Increment the ping pong count before you send it + ping_pong_count++; + MPI_Send(&ping_pong_count, 1, MPI_INT, partner_rank, 0, MPI_COMM_WORLD); + printf("%d sent and incremented ping_pong_count %d to %d\n", world_rank, + ping_pong_count, partner_rank); + } + else + { + MPI_Recv(&ping_pong_count, 1, MPI_INT, partner_rank, 0, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + printf("%d received ping_pong_count %d from %d\n", world_rank, + ping_pong_count, partner_rank); + } + } + MPI_Finalize(); +} diff --git a/external/dyninst b/external/dyninst index 280f39610e..65c34d95ea 160000 --- a/external/dyninst +++ b/external/dyninst @@ -1 +1 @@ -Subproject commit 280f39610e25dfcf364091571b292fcb8fed8be2 +Subproject commit 65c34d95ea4ce9cb563eca0ecc6e11fa17b99221 diff --git a/scripts/run-ci.sh b/scripts/run-ci.sh new file mode 100755 index 0000000000..17a6ddb902 --- /dev/null +++ b/scripts/run-ci.sh @@ -0,0 +1,252 @@ +#!/bin/bash -e + +SCRIPT_DIR=$(realpath $(dirname ${BASH_SOURCE[0]})) +cd $(dirname ${SCRIPT_DIR}) + +tolower() +{ + echo "$@" | awk -F '\|~\|' '{print tolower($1)}'; +} + +toupper() +{ + echo "$@" | awk -F '\|~\|' '{print toupper($1)}'; +} + +: ${CMAKE_BUILD_PARALLEL_LEVEL:=$(nproc)} +: ${DASHBOARD_MODE:="Continuous"} +: ${DASHBOARD_STAGES:="Start Update Configure Build Test MemCheck Coverage Submit"} +: ${SOURCE_DIR:=${PWD}} +: ${BINARY_DIR:=${PWD}/build} +: ${SITE:=$(hostname)} +: ${NAME:=""} +: ${SUBMIT_URL:="my.cdash.org/submit.php?project=Omnitrace"} +: ${CODECOV:=0} + +usage() +{ + print_option() { printf " --%-20s %-24s %s\n" "${1}" "${2}" "${3}"; } + print_default_option() { printf " --%-20s %-24s %s (default: %s)\n" "${1}" "${2}" "${3}" "$(tolower ${4})"; } + + echo "Options:" + print_option "help -h" "" "This message" + + echo "" + print_option "coverage -c" "" "Enable code coverage" + print_default_option "name -n" "" "Job name" "" + print_default_option "site -s" "" "Site name" "${SITE}" + print_default_option "source-dir -S" "" "Source directory" "${SOURCE_DIR}" + print_default_option "binary-dir -B" "" "Build directory" "${BINARY_DIR}" + print_default_option "build-jobs -j" "" "Number of build jobs" "${CMAKE_BUILD_PARALLEL_LEVEL}" + print_default_option cmake-args "" "CMake configuration args" "none" + print_default_option ctest-args "" "CTest command args" "none" + print_default_option cdash-mode "" "CDash mode" "${DASHBOARD_MODE}" + print_default_option cdash-stages "" "CDash stages" "${DASHBOARD_STAGES}" + print_default_option submit-url "" "CDash submission URL" "${SUBMIT_URL}" + #print_default_option lto "[on|off]" "Enable LTO" "${LTO}" +} + +send-error() +{ + usage + echo -e "\nError: ${@}" + exit 1 +} + +verbose-run() +{ + echo -e "\n### Executing \"${@}\"... ###\n" + eval "${@}" +} + +reset-last() +{ + last() { send-error "Unsupported argument :: \"${1}\""; } +} + +reset-last + +n=0 +while [[ $# -gt 0 ]] +do + case "${1}" in + -h|--help) + usage + exit 0 + ;; + -c|--coverage) + CODECOV=1 + reset-last + ;; + -n|--name) + shift + NAME=$(echo ${1} | sed 's/g++/gcc/g') + reset-last + ;; + -s|--site) + shift + SITE=${1} + reset-last + ;; + -S|--source-dir) + shift + SOURCE_DIR=${1} + reset-last + ;; + -B|--binary-dir) + shift + BINARY_DIR=${1} + reset-last + ;; + -j|--build-jobs) + shift + CMAKE_BUILD_PARALLEL_LEVEL=${1} + reset-last + ;; + --cmake-args) + if [ -n "${2}" ]; then + shift + CMAKE_ARGS=${1} + fi + last() { CMAKE_ARGS="${CMAKE_ARGS} ${1}"; } + ;; + --ctest-args) + if [ -n "${2}" ]; then + shift + CTEST_ARGS=${1} + fi + last() { CTEST_ARGS="${CTEST_ARGS} \"${1}\""; } + ;; + --cdash-mode) + shift + DASHBOARD_MODE=${1} + reset-last + ;; + --cdash-stages) + shift + DASHBOARD_STAGES=${1} + last() { DASHBOARD_STAGES="${DASHBOARD_STAGES} ${1}"; } + ;; + --submit-url) + shift + SUBMIT_URL=${1} + reset-last + ;; + --*) + send-error "Unsupported argument at position $((${n} + 1)) :: \"${1}\"" + ;; + *) + last ${1} + ;; + esac + n=$((${n} + 1)) + shift +done + +if [ -z "${NAME}" ]; then send-error "--name option required"; fi + +CDASH_ARGS="" +for i in ${DASHBOARD_STAGES} +do + if [ -z "${CDASH_ARGS}" ]; then + CDASH_ARGS="-D ${DASHBOARD_MODE}${i}" + else + CDASH_ARGS="${CDASH_ARGS} -D ${DASHBOARD_MODE}${i}" + fi +done + +export CMAKE_BUILD_PARALLEL_LEVEL + +if [ "${CODECOV}" -gt 0 ]; then + GCOV_CMD=$(which gcov) + CMAKE_ARGS="${CMAKE_ARGS} -DOMNITRACE_BUILD_CODECOV=ON -DOMNITRACE_STRIP_LIBRARIES=OFF" +fi + +GIT_CMD=$(which git) +CMAKE_CMD=$(which cmake) +CTEST_CMD=$(which ctest) +SOURCE_DIR=$(realpath ${SOURCE_DIR}) +BINARY_DIR=$(realpath ${BINARY_DIR}) + +verbose-run mkdir -p ${BINARY_DIR} + +cat << EOF > ${BINARY_DIR}/CTestCustom.cmake + +set(CTEST_PROJECT_NAME "Omnitrace") +set(CTEST_NIGHTLY_START_TIME "05:00:00 UTC") + +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE_CDASH TRUE) +set(CTEST_SUBMIT_URL "https://${SUBMIT_URL}") + +set(CTEST_UPDATE_TYPE git) +set(CTEST_UPDATE_VERSION_ONLY TRUE) +set(CTEST_GIT_INIT_SUBMODULES TRUE) + +set(CTEST_OUTPUT_ON_FAILURE TRUE) +set(CTEST_USE_LAUNCHERS TRUE) +set(CMAKE_CTEST_ARGUMENTS --output-on-failure ${CTEST_ARGS}) + +set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS "100") +set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS "100") +set(CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE "51200") +set(CTEST_CUSTOM_COVERAGE_EXCLUDE "/usr/.*;.*external/.*;.*examples/.*") + +set(CTEST_SITE "${SITE}") +set(CTEST_BUILD_NAME "${NAME}") + +set(CTEST_SOURCE_DIRECTORY ${SOURCE_DIR}) +set(CTEST_BINARY_DIRECTORY ${BINARY_DIR}) + +set(CTEST_UPDATE_COMMAND ${GIT_CMD}) +set(CTEST_CONFIGURE_COMMAND "${CMAKE_CMD} -B ${BINARY_DIR} ${SOURCE_DIR} -DOMNITRACE_BUILD_CI=ON ${CMAKE_ARGS}") +set(CTEST_BUILD_COMMAND "${CMAKE_CMD} --build ${BINARY_DIR} --target all") +set(CTEST_COVERAGE_COMMAND ${GCOV_CMD}) +EOF + +verbose-run cd ${BINARY_DIR} + +cat << EOF > dashboard.cmake + +include("\${CMAKE_CURRENT_LIST_DIR}/CTestCustom.cmake") + +macro(handle_error _message _ret) + if(NOT \${\${_ret}} EQUAL 0) + ctest_submit(PARTS Done RETURN_VALUE _submit_ret) + message(FATAL_ERROR "\${_message} failed: \${\${_ret}}") + endif() +endmacro() + +ctest_start(${DASHBOARD_MODE}) +ctest_update(SOURCE "${SOURCE_DIR}") +ctest_submit(PARTS Start Update RETURN_VALUE _submit_ret) + +ctest_configure(BUILD "${BINARY_DIR}" RETURN_VALUE _configure_ret) +ctest_submit(PARTS Configure RETURN_VALUE _submit_ret) + +handle_error("Configure" _configure_ret) + +ctest_build(BUILD "${BINARY_DIR}" RETURN_VALUE _build_ret) +ctest_submit(PARTS Build RETURN_VALUE _submit_ret) + +handle_error("Build" _build_ret) + +ctest_test(BUILD "${BINARY_DIR}" RETURN_VALUE _test_ret) +ctest_submit(PARTS Test RETURN_VALUE _submit_ret) + +if("${CODECOV}" GREATER 0) + ctest_coverage( + BUILD "${BINARY_DIR}" + RETURN_VALUE _coverage_ret + CAPTURE_CMAKE_ERROR _coverage_err) + ctest_submit(PARTS Coverage RETURN_VALUE _submit_ret) +endif() + +handle_error("Testing" _test_ret) + +ctest_submit(PARTS Done RETURN_VALUE _submit_ret) +EOF + +verbose-run cat CTestCustom.cmake +verbose-run cat dashboard.cmake +verbose-run ctest ${CDASH_ARGS} -S dashboard.cmake --output-on-failure ${CTEST_ARGS} diff --git a/source/bin/omnitrace-critical-trace/critical-trace.cpp b/source/bin/omnitrace-critical-trace/critical-trace.cpp index 546005cee8..bb33992142 100644 --- a/source/bin/omnitrace-critical-trace/critical-trace.cpp +++ b/source/bin/omnitrace-critical-trace/critical-trace.cpp @@ -24,6 +24,7 @@ #include "api.hpp" #include "library/config.hpp" +#include "library/debug.hpp" #include "library/perfetto.hpp" #include @@ -57,6 +58,8 @@ main(int argc, char** argv) config::set_setting_value("OMNITRACE_THREAD_POOL_SIZE", std::thread::hardware_concurrency()); config::set_setting_value("OMNITRACE_CRITICAL_TRACE_SERIALIZE_NAMES", true); + config::set_setting_value("OMNITRACE_USE_PID", false); + config::set_setting_value("OMNITRACE_TIME_OUTPUT", false); if(config::get_verbose() >= 0) { @@ -70,8 +73,12 @@ main(int argc, char** argv) { critical_trace::complete_call_chain = {}; OMNITRACE_BASIC_PRINT_F("Loading call-chain %s...\n", argv[i]); - critical_trace::load_call_chain(argv[i], "call_chain", - critical_trace::complete_call_chain); + if(!critical_trace::load_call_chain(argv[i], "call_chain", + critical_trace::complete_call_chain)) + { + OMNITRACE_THROW("Error loading '%s'. Data size: %zu\n", argv[i], + critical_trace::complete_call_chain.size()); + } for(const auto& itr : *tim::get_hash_ids()) critical_trace::complete_hash_ids.emplace(itr.second); OMNITRACE_BASIC_PRINT_F("Computing critical trace for %s...\n", argv[i]); @@ -369,22 +376,28 @@ save_call_chain_json(const std::string& _fname, const std::string& _label, } } -void +bool load_call_chain(const std::string& _fname, const std::string& _label, call_chain& _call_chain) { + namespace cereal = tim::cereal; + std::ifstream ifs{}; ifs.open(_fname); - if(ifs && ifs.is_open()) - { - namespace cereal = tim::cereal; - auto ar = tim::policy::input_archive::get(ifs); - ar->setNextName("omnitrace"); - ar->startNode(); - (*ar)(cereal::make_nvp(_label.c_str(), _call_chain)); - ar->finishNode(); - } + OMNITRACE_CONDITIONAL_THROW(!ifs || !ifs.is_open(), + "Error! call-chain file '%s' could not be opened", + _fname.c_str()); + + auto ar = tim::policy::input_archive::get(ifs); + auto _val = call_chain{}; + ar->setNextName("omnitrace"); + ar->startNode(); + (*ar)(cereal::make_nvp(_label.c_str(), _val)); + ar->finishNode(); + auto _success = (_val.empty() == false); + if(_success) std::swap(_call_chain, _val); + return _success; } auto @@ -484,6 +497,7 @@ find_children(PTL::ThreadPool& _tp, call_graph_t& _graph, const call_chain& _cha return !_data.empty(); }; + OMNITRACE_CT_DEBUG_F("Checking index at -1...\n"); if(!_indexed.at(-1).empty()) { OMNITRACE_CT_DEBUG_F("Setting root (line %i)...\n", __LINE__); @@ -856,7 +870,7 @@ compute_critical_trace() OMNITRACE_BASIC_PRINT("\n"); - try + // try { PTL::ThreadPool _tp{ get_thread_pool_size(), []() { copy_hash_ids(); }, []() {} }; _tp.set_verbose(-1); @@ -970,11 +984,11 @@ compute_critical_trace() _tg.join(); _tp.destroy_threadpool(); - } catch(std::exception& e) + } // catch(std::exception& e) { - OMNITRACE_BASIC_PRINT("Thread exited '%s' with exception: %s\n", __FUNCTION__, - e.what()); - TIMEMORY_CONDITIONAL_DEMANGLED_BACKTRACE(true, 32); + // OMNITRACE_BASIC_PRINT("Thread exited '%s' with exception: %s\n", __FUNCTION__, + // e.what()); + // TIMEMORY_CONDITIONAL_DEMANGLED_BACKTRACE(true, 32); } _report_perf(_ct_perf, __FUNCTION__, "critical trace computation"); diff --git a/source/bin/omnitrace-critical-trace/critical-trace.hpp b/source/bin/omnitrace-critical-trace/critical-trace.hpp index ece704bfb8..1230636453 100644 --- a/source/bin/omnitrace-critical-trace/critical-trace.hpp +++ b/source/bin/omnitrace-critical-trace/critical-trace.hpp @@ -65,7 +65,7 @@ std::mutex complete_call_mutex{}; void update_critical_path(call_chain _chain, int64_t _tid); -void +bool load_call_chain(const std::string& _fname, const std::string& _label, call_chain& _call_chain); diff --git a/source/lib/omnitrace/library.cpp b/source/lib/omnitrace/library.cpp index 30cf2fa919..246e5f85a0 100644 --- a/source/lib/omnitrace/library.cpp +++ b/source/lib/omnitrace/library.cpp @@ -818,7 +818,6 @@ omnitrace_finalize_hidden(void) if(get_use_critical_trace() || (get_use_rocm_smi() && get_use_roctracer())) { OMNITRACE_VERBOSE_F(1, "Generating the critical trace...\n"); - for(size_t i = 0; i < max_supported_threads; ++i) { using critical_trace_hash_data = @@ -856,10 +855,10 @@ omnitrace_finalize_hidden(void) if(get_use_critical_trace()) { // launch compute task - OMNITRACE_VERBOSE_F(1, "launching critical trace compute task...\n"); + OMNITRACE_VERBOSE_F(1, "Launching critical trace compute task...\n"); critical_trace::compute(); - OMNITRACE_VERBOSE_F(1, "Waiting on critical trace tasks...\n"); + OMNITRACE_VERBOSE_F(1, "Waiting on critical trace computation...\n"); tasking::join(); } @@ -980,7 +979,8 @@ omnitrace_finalize_hidden(void) for(auto& itr : _maps) { auto&& _path = itr.pathname; - if(!_path.empty() && _path.at(0) != '[') _libs.emplace(_path); + if(!_path.empty() && _path.at(0) != '[' && filepath::exists(_path)) + _libs.emplace(_path); } ar(tim::cereal::make_nvp("memory_maps_files", _libs), tim::cereal::make_nvp("memory_maps", _maps)); diff --git a/source/lib/omnitrace/library/config.cpp b/source/lib/omnitrace/library/config.cpp index 1618f8b99d..bd31d4d31d 100644 --- a/source/lib/omnitrace/library/config.cpp +++ b/source/lib/omnitrace/library/config.cpp @@ -941,6 +941,38 @@ configure_mode_settings() } } +namespace +{ +using signal_settings = tim::signals::signal_settings; +using sys_signal = tim::signals::sys_signal; + +void +omnitrace_exit_action(int nsig) +{ + tim::signals::block_signals(get_sampling_signals(), + tim::signals::sigmask_scope::process); + OMNITRACE_BASIC_PRINT("Finalizing afer signal %i :: %s\n", nsig, + signal_settings::str(static_cast(nsig)).c_str()); + if(get_state() == State::Active) omnitrace_finalize(); + kill(process::get_id(), nsig); +} + +void +omnitrace_trampoline_handler(int _v) +{ + if(get_verbose_env() >= 1) + { + ::omnitrace::debug::flush(); + ::omnitrace::debug::lock _debug_lk{}; + OMNITRACE_FPRINTF_STDERR_COLOR(warning); + fprintf(::omnitrace::debug::get_file(), + "signal %i ignored (OMNITRACE_IGNORE_DYNINST_TRAMPOLINE=ON)\n", _v); + ::omnitrace::debug::flush(); + timemory_print_demangled_backtrace<64>(); + } +} +} // namespace + void configure_signal_handler() { @@ -953,19 +985,8 @@ configure_signal_handler() if(_config->get_enable_signal_handler()) { - using signal_settings = tim::signals::signal_settings; - using sys_signal = tim::signals::sys_signal; tim::signals::disable_signal_detection(); - auto _exit_action = [](int nsig) { - tim::signals::block_signals(get_sampling_signals(), - tim::signals::sigmask_scope::process); - OMNITRACE_BASIC_PRINT( - "Finalizing afer signal %i :: %s\n", nsig, - signal_settings::str(static_cast(nsig)).c_str()); - if(get_state() == State::Active) omnitrace_finalize(); - kill(process::get_id(), nsig); - }; - signal_settings::set_exit_action(_exit_action); + signal_settings::set_exit_action(omnitrace_exit_action); signal_settings::check_environment(); auto default_signals = signal_settings::get_default(); for(const auto& itr : default_signals) @@ -978,22 +999,11 @@ configure_signal_handler() if(_ignore_dyninst_trampoline) { - using signal_handler_t = void (*)(int); - static auto _trampoline_handler = [](int _v) { - if(get_verbose_env() >= 2) - { - ::omnitrace::debug::flush(); - ::omnitrace::debug::lock _debug_lk{}; - OMNITRACE_FPRINTF_STDERR_COLOR(warning); - fprintf(::omnitrace::debug::get_file(), - "signal %i ignored (OMNITRACE_IGNORE_DYNINST_TRAMPOLINE=ON)\n", - _v); - ::omnitrace::debug::flush(); - timemory_print_demangled_backtrace<64>(); - } - }; - ::signal(_dyninst_trampoline_signal, - static_cast(_trampoline_handler)); + struct sigaction _action; + sigemptyset(&_action.sa_mask); + _action.sa_flags = {}; + _action.sa_handler = omnitrace_trampoline_handler; + sigaction(_dyninst_trampoline_signal, &_action, nullptr); } } diff --git a/source/lib/omnitrace/library/critical_trace.cpp b/source/lib/omnitrace/library/critical_trace.cpp index d94009bbad..3388c9e72a 100644 --- a/source/lib/omnitrace/library/critical_trace.cpp +++ b/source/lib/omnitrace/library/critical_trace.cpp @@ -904,6 +904,7 @@ std::vector> get_entries(const std::function& _eval) { OMNITRACE_SCOPED_THREAD_STATE(ThreadState::Internal); + tasking::join(); copy_hash_ids(); squash_critical_path(complete_call_chain); std::sort(complete_call_chain.begin(), complete_call_chain.end()); diff --git a/source/lib/omnitrace/library/dynamic_library.cpp b/source/lib/omnitrace/library/dynamic_library.cpp index ce84c35583..66680e2c8d 100644 --- a/source/lib/omnitrace/library/dynamic_library.cpp +++ b/source/lib/omnitrace/library/dynamic_library.cpp @@ -28,12 +28,15 @@ #include #include #include +#include #include #include namespace omnitrace { +namespace procfs = ::tim::procfs; + std::string find_library_path(const std::string& _name, const std::vector& _env_vars, const std::vector& _hints, @@ -41,6 +44,13 @@ find_library_path(const std::string& _name, const std::vector& _env { if(_name.find('/') == 0) return _name; + for(const auto& itr : procfs::get_maps(process::get_id(), true)) + { + auto&& _path = itr.pathname; + if(_path.find(_name) != std::string::npos && filepath::exists(_path)) + return _path; + } + auto _paths = std::vector{}; for(const std::string& itr : _env_vars) { @@ -74,6 +84,9 @@ dynamic_library::dynamic_library(std::string _env, std::string _fname, int _flag , filename{ std::move(_fname) } , flags{ _flags } { + // check the memory maps + filename = find_library_path(filename, {}, {}); + if(_query_env) { auto _env_val = get_env(envname, std::string{}, _store); diff --git a/source/lib/omnitrace/library/kokkosp.cpp b/source/lib/omnitrace/library/kokkosp.cpp index fd389f93d9..537ee0f154 100644 --- a/source/lib/omnitrace/library/kokkosp.cpp +++ b/source/lib/omnitrace/library/kokkosp.cpp @@ -161,7 +161,9 @@ extern "C" for(auto& itr : _maps) { auto&& _path = itr.pathname; - if(!_path.empty() && _path.at(0) != '[') _libs.emplace(_path); + if(!_path.empty() && _path.at(0) != '[' && + omnitrace::filepath::exists(_path)) + _libs.emplace(_path); } for(const auto& itr : _libs) { diff --git a/source/lib/omnitrace/library/ptl.cpp b/source/lib/omnitrace/library/ptl.cpp index 04f4cc7de4..0785526ee7 100644 --- a/source/lib/omnitrace/library/ptl.cpp +++ b/source/lib/omnitrace/library/ptl.cpp @@ -137,6 +137,10 @@ join() for(size_t i = 0; i < max_supported_threads; ++i) roctracer::get_task_group(i).join(); } + else + { + OMNITRACE_DEBUG_F("roctracer thread-pool is not active...\n"); + } if(critical_trace::get_thread_pool_state() == State::Active) { @@ -144,6 +148,10 @@ join() for(size_t i = 0; i < max_supported_threads; ++i) critical_trace::get_task_group(i).join(); } + else + { + OMNITRACE_DEBUG_F("critical-trace thread-pool is not active...\n"); + } } void @@ -160,6 +168,10 @@ shutdown() } roctracer::get_thread_pool_state() = State::Finalized; } + else + { + OMNITRACE_DEBUG_F("roctracer thread-pool is not active...\n"); + } if(critical_trace::get_thread_pool_state() == State::Active) { @@ -172,6 +184,10 @@ shutdown() } critical_trace::get_thread_pool_state() = State::Finalized; } + else + { + OMNITRACE_DEBUG_F("critical-trace thread-pool is not active...\n"); + } if(get_thread_pool_state() == State::Active) { @@ -179,6 +195,10 @@ shutdown() get_thread_pool().destroy_threadpool(); get_thread_pool_state() = State::Finalized; } + else + { + OMNITRACE_DEBUG_F("thread-pool is not active...\n"); + } } size_t @@ -194,7 +214,8 @@ roctracer::get_task_group(int64_t _tid) {}; using thread_data_t = thread_data, local>; static auto& _v = - thread_data_t::instances(construct_on_init{}, &tasking::get_thread_pool()); + (roctracer::get_thread_pool_state() = State::Active, + thread_data_t::instances(construct_on_init{}, &tasking::get_thread_pool())); return *_v.at(_tid); } @@ -205,7 +226,8 @@ critical_trace::get_task_group(int64_t _tid) {}; using thread_data_t = thread_data, local>; static auto& _v = - thread_data_t::instances(construct_on_init{}, &tasking::get_thread_pool()); + (critical_trace::get_thread_pool_state() = State::Active, + thread_data_t::instances(construct_on_init{}, &tasking::get_thread_pool())); return *_v.at(_tid); } } // namespace tasking diff --git a/source/lib/omnitrace/library/rcclp.cpp b/source/lib/omnitrace/library/rcclp.cpp index 648b8570bc..100d7d6542 100644 --- a/source/lib/omnitrace/library/rcclp.cpp +++ b/source/lib/omnitrace/library/rcclp.cpp @@ -26,6 +26,7 @@ #include "library/components/category_region.hpp" #include "library/components/fwd.hpp" #include "library/defines.hpp" +#include "library/dynamic_library.hpp" #include "library/timemory.hpp" #include @@ -42,8 +43,10 @@ #include #include -static uint64_t global_id = std::numeric_limits::max(); -static void* librccl_handle = nullptr; +namespace +{ +uint64_t global_id = std::numeric_limits::max(); +} namespace omnitrace { @@ -59,10 +62,9 @@ setup() configure(); // make sure the symbols are loaded to be wrapped - auto libpath = tim::get_env("OMNITRACE_RCCL_LIBRARY", "librccl.so"); - librccl_handle = dlopen(libpath.c_str(), RTLD_NOW | RTLD_GLOBAL); - if(!librccl_handle) fprintf(stderr, "%s\n", dlerror()); - dlerror(); // Clear any existing error + dynamic_library _librccl{ + "OMNITRACE_RCCL_LIBRARY", "librccl.so", RTLD_NOW | RTLD_GLOBAL, true, true, true + }; auto _use_data = tim::get_env("OMNITRACE_RCCLP_COMM_DATA", get_use_timemory()); if(!get_use_timemory()) @@ -78,7 +80,6 @@ setup() component::configure_rcclp(); global_id = component::activate_rcclp(); - if(librccl_handle) dlclose(librccl_handle); } void diff --git a/source/lib/omnitrace/library/sampling.cpp b/source/lib/omnitrace/library/sampling.cpp index fbbd60f1ba..4e747c1698 100644 --- a/source/lib/omnitrace/library/sampling.cpp +++ b/source/lib/omnitrace/library/sampling.cpp @@ -421,7 +421,7 @@ configure(bool _setup, int64_t _tid) auto _freq = std::max(get_sampling_cpu_freq(), get_sampling_real_freq()); auto _period = (1.0 / _freq) * units::sec; - _period = std::max(_period, 1.0e9); // max of 1 second + _period = std::min(_period, 1.0e9); // max of 1 second std::this_thread::sleep_for( std::chrono::nanoseconds{ static_cast(_period) }); diff --git a/source/python/libpyomnitrace.cpp b/source/python/libpyomnitrace.cpp index f179e4e400..8e8bfc8e73 100644 --- a/source/python/libpyomnitrace.cpp +++ b/source/python/libpyomnitrace.cpp @@ -136,26 +136,6 @@ PYBIND11_MODULE(libpyomnitrace, omni) }, "Initialize omnitrace"); - omni.def( - "initialize", - [](const std::string& _v) { - if(_is_initialized) - throw std::runtime_error("Error! omnitrace is already initialized"); - _is_initialized = true; - bool _use_mpi = false; - try - { - py::module::import("mpi4py"); - _use_mpi = true; - } catch(py::error_already_set& _exc) - { - if(!_exc.matches(PyExc_ImportError)) throw; - } - omnitrace_set_mpi(_use_mpi, false); - omnitrace_init("trace", false, _v.c_str()); - }, - "Initialize omnitrace"); - omni.def( "finalize", []() { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 11b733c588..1cec467f71 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -66,6 +66,20 @@ set(_lock_environment "OMNITRACE_TIMELINE_PROFILE=OFF" "${_test_library_path}") +set(_critical_trace_environment + "OMNITRACE_VERBOSE=2" + "OMNITRACE_USE_SAMPLING=OFF" + "OMNITRACE_USE_PROCESS_SAMPLING=OFF" + "OMNITRACE_CRITICAL_TRACE=ON" + "OMNITRACE_CRITICAL_TRACE_DEBUG=ON" + "OMNITRACE_TRACE_THREAD_LOCKS=ON" + "OMNITRACE_TRACE_THREAD_SPIN_LOCKS=ON" + "OMNITRACE_TRACE_THREAD_RW_LOCKS=ON" + "OMNITRACE_COUT_OUTPUT=ON" + "OMNITRACE_TIME_OUTPUT=OFF" + "OMNITRACE_TIMELINE_PROFILE=OFF" + "${_test_library_path}") + set(_ompt_environment "OMNITRACE_USE_PERFETTO=ON" "OMNITRACE_USE_TIMEMORY=ON" @@ -396,12 +410,15 @@ function(OMNITRACE_ADD_TEST) baseline preload binary-rewrite binary-rewrite-run binary-rewrite-sampling binary-rewrite-sampling-run runtime-instrument runtime-instrument-sampling) string(REGEX REPLACE "-run(-|/)" "\\1" _prefix "${TEST_NAME}-${_TEST}/") - set(_labels "${TEST_LABELS}" "${_TEST}") + set(_labels "${_TEST}") string(REPLACE "-run" "" _labels "${_TEST}") string(REPLACE "-sampling" ";sampling" _labels "${_labels}") if(TEST_TARGET) list(APPEND _labels "${TEST_TARGET}") endif() + if(TEST_LABELS) + list(APPEND _labels "${TEST_LABELS}") + endif() set(_environ "OMNITRACE_DEFAULT_MIN_INSTRUCTIONS=64" "${TEST_ENVIRONMENT}" @@ -840,6 +857,35 @@ if(OMNITRACE_USE_MPI OR OMNITRACE_USE_MPI_HEADERS) REWRITE_RUN_PASS_REGEX ">>> main(.*\n.*)>>> MPI_Init_thread(.*\n.*)>>> pthread_create(.*\n.*)>>> MPI_Comm_size(.*\n.*)>>> MPI_Comm_rank(.*\n.*)>>> MPI_Barrier(.*\n.*)>>> MPI_Alltoall" ) + + set(_mpip_environment + "OMNITRACE_USE_PERFETTO=ON" + "OMNITRACE_USE_TIMEMORY=ON" + "OMNITRACE_USE_SAMPLING=OFF" + "OMNITRACE_USE_PROCESS_SAMPLING=OFF" + "OMNITRACE_TIME_OUTPUT=OFF" + "OMNITRACE_FILE_OUTPUT=ON" + "OMNITRACE_USE_MPIP=ON" + "OMNITRACE_DEBUG=ON" + "OMNITRACE_VERBOSE=3" + "OMNITRACE_DL_VERBOSE=3" + "OMNITRACE_SAMPLING_DELAY=1" + "OMNITRACE_SAMPLING_FREQ=0.001" + "${_test_openmp_env}" + "${_test_library_path}") + + foreach(_EXAMPLE all2all allgather allreduce bcast reduce scatter-gather send-recv) + omnitrace_add_test( + SKIP_RUNTIME SKIP_SAMPLING + NAME "mpi-${_EXAMPLE}" + TARGET mpi-${_EXAMPLE} + MPI ON + NUM_PROCS 2 + LABELS "mpip" + REWRITE_ARGS -e -v 2 --label file line --min-instructions 0 + RUN_ARGS 30 + ENVIRONMENT "${_mpip_environment}") + endforeach() endif() omnitrace_add_test( @@ -1039,7 +1085,7 @@ omnitrace_add_test( PRELOAD_PASS_REGEX "${_ompt_preload_samp_regex}(.*)${_ompt_preload_file_regex}") omnitrace_add_test( - SKIP_BASELINE SKIP_SAMPLING + SKIP_BASELINE SKIP_SAMPLING SKIP_PRELOAD NAME code-coverage TARGET code-coverage REWRITE_ARGS @@ -1078,7 +1124,7 @@ omnitrace_add_test( REWRITE_RUN_PASS_REGEX "(\\\[[0-9]+\\\]) code coverage :: 66.67%") omnitrace_add_test( - SKIP_BASELINE SKIP_SAMPLING + SKIP_BASELINE SKIP_SAMPLING SKIP_PRELOAD NAME code-coverage-hybrid TARGET code-coverage REWRITE_ARGS -e -v 2 --min-instructions=4 -E ^std:: --coverage function @@ -1105,7 +1151,7 @@ omnitrace_add_test( REWRITE_RUN_PASS_REGEX "(\\\[[0-9]+\\\]) code coverage :: 66.67%") omnitrace_add_test( - SKIP_BASELINE SKIP_SAMPLING + SKIP_BASELINE SKIP_SAMPLING SKIP_PRELOAD NAME code-coverage-basic-blocks TARGET code-coverage REWRITE_ARGS @@ -1144,7 +1190,7 @@ omnitrace_add_test( REWRITE_RUN_PASS_REGEX "(\\\[[0-9]+\\\]) function coverage :: 66.67%") omnitrace_add_test( - SKIP_BASELINE SKIP_SAMPLING + SKIP_BASELINE SKIP_SAMPLING SKIP_PRELOAD NAME code-coverage-basic-blocks-hybrid TARGET code-coverage REWRITE_ARGS -e -v 2 --min-instructions=4 -E ^std:: --coverage basic_block @@ -1170,6 +1216,60 @@ omnitrace_add_test( RUNTIME_PASS_REGEX "(\\\[[0-9]+\\\]) function coverage :: 66.67%" REWRITE_RUN_PASS_REGEX "(\\\[[0-9]+\\\]) function coverage :: 66.67%") +# -------------------------------------------------------------------------------------- # +# +# critical-trace tests +# +# -------------------------------------------------------------------------------------- # + +omnitrace_add_test( + SKIP_BASELINE SKIP_RUNTIME SKIP_SAMPLING SKIP_PRELOAD + NAME parallel-overhead-critical-trace + TARGET parallel-overhead + LABELS "critical-trace" + REWRITE_ARGS + -e + -i + 8 + -E + "^fib" + -v + 2 + --print-instrumented + functions + RUN_ARGS 10 4 100 + ENVIRONMENT "${_critical_trace_environment}") + +add_test( + NAME parallel-overhead-process-critical-trace + COMMAND + $ + ${PROJECT_BINARY_DIR}/omnitrace-tests-output/parallel-overhead-critical-trace-binary-rewrite/call-chain.json + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) + +set(_parallel_overhead_critical_trace_environ + "OMNITRACE_OUTPUT_PATH=omnitrace-tests-output" + "OMNITRACE_OUTPUT_PREFIX=parallel-overhead-critical-trace/" + "OMNITRACE_CRITICAL_TRACE_DEBUG=ON" + "OMNITRACE_VERBOSE=4" + "OMNITRACE_DEBUG=ON" + "OMNITRACE_USE_PID=OFF" + "OMNITRACE_TIME_OUTPUT=OFF") + +set_tests_properties( + parallel-overhead-process-critical-trace + PROPERTIES + ENVIRONMENT + "${_parallel_overhead_critical_trace_environ}" + TIMEOUT + 300 + LABELS + "parallel-overhead;critical-trace" + PASS_REGULAR_EXPRESSION + "Outputting.*(critical-trace-cpu.json).*Outputting.*(critical-trace-any.json)" + DEPENDS + parallel-overhead-critical-trace-binary-rewrite-run) + # -------------------------------------------------------------------------------------- # # # attach tests @@ -1341,6 +1441,24 @@ foreach(_VERSION ${OMNITRACE_PYTHON_VERSIONS}) RUN_ARGS -v 5 -n 5 -s 3 ENVIRONMENT "${_python_environment}") + omnitrace_add_python_test( + STANDALONE + NAME python-code-coverage + PYTHON_EXECUTABLE ${_PYTHON_EXECUTABLE} + PYTHON_VERSION ${_VERSION} + FILE ${CMAKE_SOURCE_DIR}/examples/code-coverage/code-coverage.py + RUN_ARGS + -i + ${PROJECT_BINARY_DIR}/omnitrace-tests-output/code-coverage-basic-blocks-binary-rewrite/coverage.json + ${PROJECT_BINARY_DIR}/omnitrace-tests-output/code-coverage-basic-blocks-hybrid-runtime-instrument/coverage.json + -o + ${PROJECT_BINARY_DIR}/omnitrace-tests-output/code-coverage-basic-blocks-summary/coverage.json + DEPENDS code-coverage-basic-blocks-binary-rewrite + code-coverage-basic-blocks-binary-rewrite-run + code-coverage-basic-blocks-hybrid-runtime-instrument + LABELS "code-coverage" + ENVIRONMENT "${_python_environment}") + # ---------------------------------------------------------------------------------- # # python output tests # ---------------------------------------------------------------------------------- #