Commit 8487c78f authored by Ramon Nou's avatar Ramon Nou
Browse files

Enable coverage information generation and tracking

This MR enables the generation of code coverage reports for the source code. More specifically, it introduces the following changes:

- Adds the `gkfs-code-coverage.cmake` CMake script under `{PROJECT_ROOT}/CMake/` and includes it in the project's main `CMakeLists.txt`. This script defines the `GKFS_ENABLE_CODE_COVERAGE` option to control whether code coverage should be enabled when building, as well as the `target_code_coverage()` function to ensure that the appropriate flags are added to a CMake target.
- Adds `gcovr` to GekkoFS docker build image.
- Adds a `coverage.sh` script under `{PROJECT_ROOT}/scripts/ci` that provides both a `capture` and a `merge` work modes. This script abstracts away the direct usage of `gcovr` and allows the appropriate generation of coverage reports when running tests **in parallel** in the CI. The script relies on a `.coverage-exclusions` file (also under `{PROJECT_ROOT}/scripts/ci`) to control which paths should be excluded from coverage reporting (e.g. `/usr/include/.*`).
- Adds a new `report` stage in the CI pipeline that upon completion generates artifacts both for a Cobertura XML and a HTML code coverage reports.

See merge request !77
parents 460cabe0 2c750281
Loading
Loading
Loading
Loading
+54 −9
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ stages:
  - build deps
  - build
  - test
  - report

variables:
  DEPS_SRC_PATH:                "${CI_PROJECT_DIR}/deps/src"
@@ -60,6 +61,7 @@ compile GekkoFS:
      -Wdev
      -Wdeprecate
      -DCMAKE_BUILD_TYPE=Debug
      -DGKFS_ENABLE_CODE_COVERAGE:BOOL=ON
      -DGKFS_BUILD_TESTS:BOOL=ON
      -DGKFS_INSTALL_TESTS:BOOL=ON
      -DGKFS_ENABLE_FORWARDING:BOOL=ON
@@ -68,13 +70,18 @@ compile GekkoFS:
      -DCMAKE_INSTALL_PREFIX=${INSTALL_PATH}
      ${CI_PROJECT_DIR}
    - make -j$(nproc) install
    # the following commands are intended to reduce artifact size
    - rm -rf ${BUILD_PATH}/_deps
    - find ${BUILD_PATH} -name "*.o" -delete
    # cleanup nlohmann_json: it includes around 500MiB of test data
    - rm -rf ${BUILD_PATH}/_deps/nlohmann_json-src/test/data
    - rm -rf ${BUILD_PATH}/_deps/nlohmann_json-src/benchmarks/data
    - rm -rf ${BUILD_PATH}/_deps/nlohmann_json-src/.git
  artifacts:
    paths:
      - ${BUILD_PATH}
      - ${INSTALL_PATH}
    exclude:
      # remove object files
      - ${BUILD_PATH}/**/*.o

compile tests:
  stage: build
@@ -91,23 +98,39 @@ compile tests:
integration tests:
  stage: test
  script:
    - mkdir -p ${INTEGRATION_TESTS_RUN_PATH}
    - cd ${INTEGRATION_TESTS_BIN_PATH} 
    - TMPDIR=${INTEGRATION_TESTS_RUN_PATH} unbuffer ${PYTEST} -v | tee ${INTEGRATION_TESTS_RUN_PATH}/session.log
    ## run tests
    - cd ${BUILD_PATH}/tests/integration
    - unbuffer ${PYTEST} -v | tee session.log
    ## capture coverage information
    - cd ${BUILD_PATH}
    - ${CI_PROJECT_DIR}/scripts/ci/coverage.sh
          --capture integration
          --root-dir ${CI_PROJECT_DIR}
          --build-dir ${BUILD_PATH}
          --exclusions "${CI_PROJECT_DIR}/scripts/ci/.coverage-exclusions"
  artifacts:
    when: on_failure
    #    when: on_failure
    paths:
      - "${INTEGRATION_TESTS_RUN_PATH}"
      #      - "${INTEGRATION_TESTS_RUN_PATH}"
      - ${BUILD_PATH}

unit:
  stage: test
  script:
    ## run actual tests
    - cd ${BUILD_PATH}
    - ctest -j $(nproc) -L unit::all
    ## capture coverage information
    - ${CI_PROJECT_DIR}/scripts/ci/coverage.sh
          --capture unit
          --root-dir ${CI_PROJECT_DIR}
          --build-dir ${BUILD_PATH}
          --exclusions "${CI_PROJECT_DIR}/scripts/ci/.coverage-exclusions"
  artifacts:
    when: on_failure
    #    when: on_failure
    paths:
      - Testing
      - ${BUILD_PATH}
        #      - Testing

test wr:
  stage: test
@@ -156,3 +179,25 @@ test lseek:
    when: on_failure
    paths:
     - "${LOG_PATH}"


################################################################################
## Generation of code coverage reports
################################################################################

coverage:
  stage: report
  image: gekkofs/coverage
  script:
    - cd ${BUILD_PATH}
    ## merge the partial coverage files from each test in the pipeline
    - ${CI_PROJECT_DIR}/scripts/ci/coverage.sh
          --merge
          --root-dir ${CI_PROJECT_DIR}
          --build-dir ${BUILD_PATH}
  artifacts:
    reports:
      cobertura: ${BUILD_PATH}/.coverage/coverage-cobertura.xml
    paths:
      - ${BUILD_PATH}/.coverage
    expire_in: 2 weeks
+82 −0
Original line number Diff line number Diff line
# Variables
option(GKFS_ENABLE_CODE_COVERAGE
  "Builds GekkoFS targets with code coverage instrumentation."
  OFF
  )

# Common initialization/checks
if(GKFS_ENABLE_CODE_COVERAGE AND NOT GKFS_CODE_COVERAGE_ADDED)

  set(GKFS_CODE_COVERAGE_ADDED ON)

  if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang"
     OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang")

    message(STATUS "[gekkofs] Building with LLVM Code Coverage Tools")

  elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES
                                              "GNU")

    message(STATUS "[gekkofs] Building with GCC Code Coverage Tools")

    if(CMAKE_BUILD_TYPE)
      string(TOUPPER ${CMAKE_BUILD_TYPE} upper_build_type)
      if(NOT ${upper_build_type} STREQUAL "DEBUG")
        message(
          WARNING
            "Code coverage results with an optimized (non-Debug) build may be misleading"
        )
      endif()
    else()
      message(
        WARNING
          "Code coverage results with an optimized (non-Debug) build may be misleading"
      )
    endif()
  else()
    message(FATAL_ERROR "Code coverage requires Clang or GCC. Aborting.")
  endif()
endif()

# Adds code coverage instrumentation to libraries and executable targets.
# ~~~
# Required:
# TARGET_NAME - Name of the target to generate code coverage for.
# Optional:
# PUBLIC   - Sets the visibility for added compile options to targets to PUBLIC
#            instead of the default of PRIVATE.
# PRIVATE - Sets the visibility for added compile options to targets to
#           INTERFACE instead of the default of PRIVATE.
# ~~~
function(target_code_coverage TARGET_NAME)
  # Argument parsing
  set(options PUBLIC INTERFACE)
  cmake_parse_arguments(target_code_coverage "${options}" "" "" ${ARGN})

  # Set the visibility of target functions to PUBLIC, INTERFACE or default to
  # PRIVATE.
  if(target_code_coverage_PUBLIC)
    set(TARGET_VISIBILITY PUBLIC)
  elseif(target_code_coverage_INTERFACE)
    set(TARGET_VISIBILITY INTERFACE)
  else()
    set(TARGET_VISIBILITY PRIVATE)
  endif()

  if(GKFS_ENABLE_CODE_COVERAGE)

    # Add code coverage instrumentation to the target's linker command
    if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang"
       OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang")
      target_compile_options(${TARGET_NAME} ${TARGET_VISIBILITY}
                             -fprofile-instr-generate -fcoverage-mapping)
      target_link_options(${TARGET_NAME} ${TARGET_VISIBILITY}
                          -fprofile-instr-generate -fcoverage-mapping)
    elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES
                                                "GNU")
      target_compile_options(${TARGET_NAME} ${TARGET_VISIBILITY} -fprofile-arcs
        -ftest-coverage)
      target_link_libraries(${TARGET_NAME} ${TARGET_VISIBILITY} gcov)
    endif()
  endif()
endfunction()
+10 −0
Original line number Diff line number Diff line
@@ -74,6 +74,16 @@ configure_file(include/version.hpp.in include/version.hpp)

set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH})


################################################################################
## Coverage generation support:
## ============================
## 
## The `gkfs-code-coverage' module enables the GKFS_ENABLE_CODE_COVERAGE option
## as well as the target_code_coverage() function.
################################################################################
include(gkfs-code-coverage)

set(CMAKE_EXPORT_COMPILE_COMMANDS 0)

# Rocksdb dependencies
+1 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@

[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![pipeline status](https://storage.bsc.es/gitlab/hpc/gekkofs/badges/master/pipeline.svg)](https://storage.bsc.es/gitlab/hpc/gekkofs/commits/master)
[![coverage report](https://storage.bsc.es/gitlab/hpc/gekkofs/badges/master/coverage.svg)](https://storage.bsc.es/gitlab/hpc/gekkofs/-/commits/master)

GekkoFS is a file system capable of aggregating the local I/O capacity and performance of each compute node
in a HPC cluster to produce a high-performance storage space that can be accessed in a distributed manner.
+16 −9
Original line number Diff line number Diff line
@@ -8,7 +8,8 @@ ENV SCRIPTS_PATH ${GKFS_PATH}/scripts
ENV DEPS_SRC_PATH	${GKFS_PATH}/deps_src
ENV INSTALL_PATH	${GKFS_PATH}/build_deps

RUN apt-get update && apt-get install -y --no-install-recommends \
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
		git \
		curl \
		ca-certificates \
@@ -38,8 +39,10 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
		valgrind \
		uuid-dev \
		python3 \
		python3-pip \
		python3-dev \
		python3-venv \
		python3-setuptools \
		expect \
		# clang 10 deps
		lsb-release \
@@ -47,13 +50,17 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
		software-properties-common \
		gnupg2 \
    # add clang-10 repos
&& wget https://apt.llvm.org/llvm.sh -P /tmp && chmod +x /tmp/llvm.sh && /tmp/llvm.sh 10 \
    wget https://apt.llvm.org/llvm.sh -P /tmp && chmod +x /tmp/llvm.sh && /tmp/llvm.sh 10 && \
    # install clang-format
&& apt-get update && apt-get install -y --no-install-recommends clang-format-10 \
    apt-get update && apt-get install -y --no-install-recommends clang-format-10 && \
    # install gcovr
    # (required for partial coverage reports in parallel runs)
    python3 -m pip install --upgrade pip && \
    pip3 install gcovr && \
    # Clean apt cache to reduce image layer size
&& rm -rf /var/lib/apt/lists/* && rm /tmp/llvm.sh \
    rm -rf /var/lib/apt/lists/* && rm /tmp/llvm.sh && \
    # Clean apt caches of packages
&& apt-get clean && apt-get autoclean
    apt-get clean && apt-get autoclean

## COPY scripts/dl_dep.sh		$SCRIPTS_PATH/
## COPY scripts/compile_dep.sh $SCRIPTS_PATH/
Loading