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
11 changes: 9 additions & 2 deletions .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,21 @@ jobs:

steps:
- uses: actions/checkout@v2

- uses: actions/setup-python@v5
with:
python-version: '3.10'
cache: 'pip'

- name: Install dependencies
run: sudo apt-get install libdw-dev libunwind-dev gfortran
run: |
sudo apt-get install libdw-dev libunwind-dev gfortran
python3 -m pip install pybind11

- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -C ${{github.workspace}}/cmake/hostconfig/github-actions.cmake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -Dpybind11_DIR=$(pybind11-config --cmakedir) -C ${{github.workspace}}/cmake/hostconfig/github-actions.cmake

- name: Build
# Build your program with the given configuration
Expand Down
16 changes: 13 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ option(BUILD_SHARED_LIBS "Build shared libraries" TRUE)
option(CMAKE_INSTALL_RPATH_USE_LINK_PATH "Add rpath for all dependencies" TRUE)

# Optional Fortran
add_caliper_option(WITH_FORTRAN "Install Fortran interface" FALSE)
add_caliper_option(WITH_TOOLS "Build Caliper tools" TRUE)
add_caliper_option(WITH_FORTRAN "Install Fortran interface" FALSE)
add_caliper_option(WITH_PYTHON_BINDINGS "Install Python bindings" FALSE)
add_caliper_option(WITH_TOOLS "Build Caliper tools" TRUE)

add_caliper_option(WITH_NVTX "Enable NVidia nvtx bindings for NVprof and NSight (requires CUDA)" FALSE)
add_caliper_option(WITH_CUPTI "Enable CUPTI service (CUDA performance analysis)" FALSE)
Expand Down Expand Up @@ -421,7 +422,12 @@ if(WITH_TAU)
endif()

# Find Python
find_package(Python COMPONENTS Interpreter REQUIRED)
set(FIND_PYTHON_COMPONENTS "Interpreter")
if (WITH_PYTHON_BINDINGS)
set(FIND_PYTHON_COMPONENTS "Development" ${FIND_PYTHON_COMPONENTS})
endif ()

find_package(Python COMPONENTS ${FIND_PYTHON_COMPONENTS} REQUIRED)
set(CALI_PYTHON_EXECUTABLE Python::Interpreter)

if (WITH_SAMPLER)
Expand Down Expand Up @@ -495,6 +501,10 @@ configure_file(
include_directories(${PROJECT_BINARY_DIR}/include)
include_directories(include)

if (WITH_PYTHON_BINDINGS AND BUILD_TESTING)
set(PYPATH_TESTING "" CACHE INTERNAL "")
endif()

add_subdirectory(ext)
add_subdirectory(src)

Expand Down
14 changes: 14 additions & 0 deletions cmake/get_python_install_paths.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import sys
import sysconfig

if len(sys.argv) != 3 or sys.argv[1] not in ("purelib", "platlib"):
raise RuntimeError(
"Usage: python get_python_install_paths.py <purelib | platlib> <sysconfig_scheme>"
)

install_dir = sysconfig.get_path(sys.argv[1], sys.argv[2], {"userbase": "", "base": ""})

if install_dir.startswith("/"):
install_dir = install_dir[1:]

print(install_dir, end="")
1 change: 1 addition & 0 deletions cmake/hostconfig/github-actions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ set(WITH_NVPROF Off CACHE BOOL "")
set(WITH_PAPI Off CACHE BOOL "")
set(WITH_SAMPLER On CACHE BOOL "")
set(WITH_VTUNE Off CACHE BOOL "")
set(WITH_PYTHON_BINDINGS On CACHE BOOL "")

set(WITH_DOCS Off CACHE BOOL "")
set(BUILD_TESTING On CACHE BOOL "")
48 changes: 48 additions & 0 deletions examples/apps/cali-perfproblem-branch-mispred.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright (c) 2024, Lawrence Livermore National Security, LLC.
# See top-level LICENSE file for details.

from pycaliper.high_level import annotate_function
from pycaliper.annotation import Annotation

import numpy as np

@annotate_function()
def init(arraySize: int, sort: bool) -> np.array:
data = np.random.randint(256, size=arraySize)
if sort:
data = np.sort(data)
return data


@annotate_function()
def work(data: np.array):
data_sum = 0
for _ in range(100):
for val in np.nditer(data):
if val >= 128:
data_sum += val
print("sum =", data_sum)


@annotate_function()
def benchmark(arraySize: int, sort: bool):
sorted_ann = Annotation("sorted")
sorted_ann.set(sort)
print("Intializing benchmark data with sort =", sort)
data = init(arraySize, sort)
print("Calculating sum of values >= 128")
work(data)
print("Done!")
sorted_ann.end()


@annotate_function()
def main():
arraySize = 32768
benchmark(arraySize, True)
benchmark(arraySize, False)


if __name__ == "__main__":
main()

76 changes: 76 additions & 0 deletions examples/apps/py-example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Copyright (c) 2024, Lawrence Livermore National Security, LLC.
# See top-level LICENSE file for details.

from pycaliper.high_level import annotate_function
from pycaliper.config_manager import ConfigManager
from pycaliper.instrumentation import (
set_global_byname,
begin_region,
end_region,
)
from pycaliper.loop import Loop

import argparse
import sys
import time


def get_available_specs_doc(mgr: ConfigManager):
doc = ""
for cfg in mgr.available_config_specs():
doc += mgr.get_documentation_for_spec(cfg)
doc += "\n"
return doc


@annotate_function()
def foo(i: int) -> float:
nsecs = max(i * 500, 100000)
secs = nsecs / 10**9
time.sleep(secs)
return 0.5 * i


def main():
mgr = ConfigManager()

parser = argparse.ArgumentParser()
parser.add_argument("--caliper_config", "-P", type=str, default="",
help="Configuration for Caliper\n{}".format(get_available_specs_doc(mgr)))
parser.add_argument("iterations", type=int, nargs="?", default=4,
help="Number of iterations")
args = parser.parse_args()

mgr.add(args.caliper_config)

if mgr.error():
print("Caliper config error:", mgr, file=sys.stderr)

mgr.start()

set_global_byname("iterations", args.iterations)
set_global_byname("caliper.config", args.caliper_config)

begin_region("main")

begin_region("init")
t = 0
end_region("init")

loop_ann = Loop("mainloop")

for i in range(args.iterations):
loop_ann.start_iteration(i)
t *= foo(i)
loop_ann.end_iteration()

loop_ann.end()

end_region("main")

mgr.flush()


if __name__ == "__main__":
main()

4 changes: 4 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ if (WITH_TOOLS)
add_subdirectory(tools)
endif()

if (WITH_PYTHON_BINDINGS)
add_subdirectory(interface/python)
endif()

install(
TARGETS
caliper
Expand Down
64 changes: 64 additions & 0 deletions src/interface/python/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
set(PYCALIPER_BINDING_SOURCES
annotation.cpp
config_manager.cpp
instrumentation.cpp
loop.cpp
mod.cpp
)

set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)

find_package(pybind11 CONFIG REQUIRED)

set(PYCALIPER_SYSCONFIG_SCHEME "posix_user" CACHE STRING "Scheme used for searching for pycaliper's install path. Valid options can be determined with 'sysconfig.get_scheme_names()'")

execute_process(COMMAND ${Python_EXECUTABLE} ${CMAKE_SOURCE_DIR}/cmake/get_python_install_paths.py purelib ${PYCALIPER_SYSCONFIG_SCHEME} OUTPUT_VARIABLE PYCALIPER_SITELIB)
execute_process(COMMAND ${Python_EXECUTABLE} ${CMAKE_SOURCE_DIR}/cmake/get_python_install_paths.py platlib ${PYCALIPER_SYSCONFIG_SCHEME} OUTPUT_VARIABLE PYCALIPER_SITEARCH)

message(STATUS "Pycaliper sitelib: ${PYCALIPER_SITELIB}")
message(STATUS "Pycaliper sitearch: ${PYCALIPER_SITEARCH}")

set(PYCALIPER_SITELIB "${PYCALIPER_SITELIB}/pycaliper")
set(PYCALIPER_SITEARCH "${PYCALIPER_SITEARCH}/pycaliper")

pybind11_add_module(__pycaliper_impl ${PYCALIPER_BINDING_SOURCES})
target_link_libraries(__pycaliper_impl PUBLIC caliper)
target_compile_features(__pycaliper_impl PUBLIC cxx_std_11)
target_include_directories(__pycaliper_impl PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

add_custom_target(
pycaliper_test ALL # Always build pycaliper_test
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/pycaliper
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/pycaliper ${CMAKE_CURRENT_BINARY_DIR}/pycaliper
COMMENT "Copying pycaliper Python source to ${CMAKE_CURRENT_BINARY_DIR}/pycaliper"
)
add_dependencies(__pycaliper_impl pycaliper_test)

if (BUILD_TESTING)
set(PYPATH_TESTING ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "")
add_custom_target(
pycaliper_symlink_lib_in_build ALL
COMMAND ${CMAKE_COMMAND} -E create_symlink
$<TARGET_FILE:__pycaliper_impl>
${CMAKE_CURRENT_BINARY_DIR}/pycaliper/$<TARGET_FILE_NAME:__pycaliper_impl>
COMMENT "Creating symlink between Python C module and build directory for testing"
DEPENDS __pycaliper_impl
)
message(STATUS "Will add ${PYPATH_TESTING} to PYTHONPATH during test")
endif()

install(
DIRECTORY
pycaliper/
DESTINATION
${PYCALIPER_SITELIB}
)

install(
TARGETS
__pycaliper_impl
ARCHIVE DESTINATION
${PYCALIPER_SITEARCH}
LIBRARY DESTINATION
${PYCALIPER_SITEARCH}
)
Loading