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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ define run_cmake =
-DCMAKE_INSTALL_PREFIX=$(abspath $(INSTALL_PREFIX)) \
-DCMAKE_EXPORT_COMPILE_COMMANDS=1 \
-DCMAKE_PREFIX_PATH=$(CURDIR)/infra/cmake \
-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES="./cmake/use-fetch-content.cmake" \
-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES="./cmake/use-fetch-content.cmake;infra/cmake/bemancmakeinstrumentation.cmake" \
$(_cmake_args) \
$(CURDIR)
endef
Expand Down Expand Up @@ -85,10 +85,10 @@ clean-install:
realclean: clean-install

ctest: $(_build_path)/CMakeCache.txt ## Run CTest on current build
cd $(_build_path) && ctest --output-on-failure -C $(CONFIG)
cd $(_build_path) && ctest --parallel --output-on-failure -C $(CONFIG)

ctest_ : compile
cd $(_build_path) && ctest --output-on-failure -C $(CONFIG)
cd $(_build_path) && ctest --parallel --output-on-failure -C $(CONFIG)

test: ctest_ ## Rebuild and run tests

Expand Down
18 changes: 18 additions & 0 deletions infra/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,21 @@ Some options for the project and target will also be supported:
* `BEMAN_INSTALL_CONFIG_FILE_PACKAGES` - a list of package names (e.g., `beman.something`) for which to install the config file
(default: all packages)
* `<BEMAN_NAME>_INSTALL_CONFIG_FILE_PACKAGE` - a per-project option to enable/disable config file installation (default: `ON` if the project is top-level, `OFF` otherwise). For instance for `beman.something`, the option would be `BEMAN_SOMETHING_INSTALL_CONFIG_FILE_PACKAGE`.

#### `beman_cmake_instrumentation`

The cmake modules in this library are intended to provide access to CMake instrumentation data in Google Trace format which is visualizable with chrome://tracing and https://ui.perfetto.dev.

Instrumentation may be enabled either by adding to the CMAKE_PROJECT_TOP_LEVEL_INCLUDES
```sh
-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=infra/cmake/bemancmakeinstrumentation.cmake
```
or by calling explicitly within the CMakeList.txt file.
```cmake
find_package(BemanCMakeInstrumentation)
configure_beman_cmake_instrumentation()
```

In either form, CMake will call `instrumentation.sh` which will copy the trace data in json format into a `.trace` subdirectory within the build directory.

Multiple calls to `configure_beman_cmake_instrumentation` will only configure the callback hooks once, so it is safe to include multiple times, including by TOP_LEVEL_INCLUDE.
29 changes: 29 additions & 0 deletions infra/cmake/bemancmakeinstrumentation-config.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
include_guard(GLOBAL)

cmake_minimum_required (VERSION 4.2)

set(BEMAN_CMAKE_INSTRUMENTATION_DIR ${CMAKE_CURRENT_LIST_DIR})

function(configure_beman_cmake_instrumentation)
if(NOT BEMAN_CMAKE_INSTRUMENTATION_CONFIGURATION)
message(WARNING "Configuring Beman CMake Instrumentation")

# Enable experimental feature!!
set(CMAKE_EXPERIMENTAL_INSTRUMENTATION ec7aa2dc-b87f-45a3-8022-fe01c5f59984)

# Instrumentation query
cmake_instrumentation(
API_VERSION 1
DATA_VERSION 1

OPTIONS staticSystemInformation dynamicSystemInformation trace
HOOKS postGenerate preBuild postBuild preCMakeBuild postCMakeBuild postCMakeInstall postCTest
CALLBACK ${BEMAN_CMAKE_INSTRUMENTATION_DIR}/instrumentation.sh
)
message(WARNING "using callback script ${BB_CMAKE_INSTRUMENTATION_DIR}/instrumentation.sh")

# Mark task as done in cache
set(BEMAN_CMAKE_INSTRUMENTATION_CONFIGURATION TRUE CACHE INTERNAL "Flag to ensure CMake Instrumentation configured only once")
endif()

endfunction(configure_beman_cmake_instrumentation)
6 changes: 6 additions & 0 deletions infra/cmake/bemancmakeinstrumentation.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
include_guard(GLOBAL)

cmake_minimum_required (VERSION 4.2)

find_package(BemanCMakeInstrumentation)
configure_beman_cmake_instrumentation()
115 changes: 115 additions & 0 deletions infra/cmake/instrumentation.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/usr/bin/env bash

set -o nounset
set -o errexit
trap 'echo "Aborting due to errexit on line $LINENO. Exit code: $?" >&2' ERR
set -o errtrace
set -o pipefail
IFS=$'\n\t'

###############################################################################
# Environment
###############################################################################

# $_ME
#
# This program's basename.
_ME="$(basename "${0}")"

###############################################################################
# Help
###############################################################################

# _print_help()
#
# Usage:
# _print_help
#
# Print the program help information.
_print_help() {
cat <<HEREDOC

Callback script to process CMake Instrumentation data
https://cmake.org/cmake/help/latest/command/cmake_instrumentation.html

Usage:
${_ME} [<arguments>]
${_ME} -h | --help

Options:
-h --help Show this screen.
HEREDOC
}

###############################################################################
# Program Functions
###############################################################################
_debug_print() {
if [[ -n "${DEBUG:-}" ]]; then
printf "[DEBUG] $(date +'%H:%M:%S'): %s \n" "$1" >&2
fi
}

_check_file_exists() {
local file="$1"
if [[ ! -f "${file}" ]]; then
echo "Error: File not found: ${file}" >&2
exit 1 # Exit the entire script with a non-zero status
fi
}

_process_index() {
indexFile=${1:-}
_check_file_exists "${indexFile}"
_debug_print "$(cat "${indexFile}")"

local buildDir
buildDir=$(jq -r '.buildDir' "${1:-}")
_debug_print "$(printf "buildDir is |%q|" "${buildDir}")"

local dataDir
dataDir=$(jq -r '.dataDir' "${1:-}")
_debug_print "$(printf "dataDir is |%q|" "${dataDir}")"

local hook
hook=$(jq -r '.hook' "${1:-}")
_debug_print "$(printf "hook is |%q|" "${hook}")"

local trace
trace=$(jq -r '.trace' "${1:-}")
_debug_print "$(printf "trace is |%q|" "${trace}")"

local outputDir
outputDir="${buildDir}/.trace"
_debug_print "$(printf "Copy trace to |%q|" "${outputDir}")"
mkdir -p "${outputDir}"

local traceDestFile
traceDestFile="${outputDir}/${hook}-$(basename "${trace}")"
_debug_print "$(printf "traceDestFile: |%q|" "${traceDestFile}")"
cp "${dataDir}/${trace}" "${outputDir}/${hook}-$(basename "${trace}")"
}

###############################################################################
# Main
###############################################################################

# _main()
#
# Usage:
# _main [<options>] [<arguments>]
#
# Description:
# Entry point for the program, handling basic option parsing and dispatching.
_main() {
# Avoid complex option parsing when only one program option is expected.
if [[ "${1:-}" =~ ^-h|--help$ ]]
then
_print_help
else
_process_index "$@"
fi
}

# Call `_main` after everything has been defined.
_main "$@"