Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add posix I/O writer #334

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
16 changes: 16 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ find_package(Sensors)
find_package(Veosinfo)
find_package(Libpfm)
find_package(PkgConfig)
find_package(BpfObject)

if(PkgConfig_FOUND)
pkg_check_modules(Audit audit)
Expand All @@ -129,6 +130,9 @@ CMAKE_DEPENDENT_OPTION(USE_LIBAUDIT "Use libaudit for syscall name resolution" O
add_feature_info("USE_LIBAUDIT" USE_LIBAUDIT "Use libaudit for syscall name resolution.")
CMAKE_DEPENDENT_OPTION(USE_VEOSINFO "Use libveosinfo to sample NEC SX-Aurora Tsubasa cards." ON "Veosinfo_FOUND" OFF)
add_feature_info("USE_VEOSINFO" USE_VEOSINFO "Use libveosinfo to sample NEC SX-Aurora Tsubasa cards.")
CMAKE_DEPENDENT_OPTION(USE_BPF "Use BPF for filename lookup" ON BpfObject_FOUND OFF)
add_feature_info("USE_BPF" USE_BPF "Use BPF for filename lookup")

# system configuration checks
CHECK_INCLUDE_FILES(linux/hw_breakpoint.h HAVE_HW_BREAKPOINT_H)
CHECK_STRUCT_HAS_MEMBER("struct perf_event_attr" clockid linux/perf_event.h HAVE_PERF_EVENT_ATTR_CLOCKID)
Expand Down Expand Up @@ -368,6 +372,18 @@ target_include_directories(lo2s PRIVATE
${CMAKE_CURRENT_BINARY_DIR}/include
)


if (USE_BPF)
if (BpfObject_FOUND)
target_compile_definitions(lo2s PUBLIC HAVE_BPF)
bpf_object(open src/perf/posix_io/open.bpf.c)
add_dependencies(lo2s open_skel)
target_link_libraries(lo2s PRIVATE open_skel)
else()
message(SEND_ERROR "BPF not found but requested.")
endif()
endif()

add_subdirectory(man)

message(STATUS "Linux kernel version: ${LINUX_VERSION}")
Expand Down
189 changes: 189 additions & 0 deletions cmake/FindBpfObject.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause

#[=======================================================================[.rst:
FindBpfObject
--------

Find BpfObject

This module finds if all the dependencies for eBPF Compile-Once-Run-Everywhere
programs are available and where all the components are located.

The caller may set the following variables to disable automatic
search/processing for the associated component:

``BPFOBJECT_BPFTOOL_EXE``
Path to ``bpftool`` binary

``BPFOBJECT_CLANG_EXE``
Path to ``clang`` binary

``LIBBPF_INCLUDE_DIRS``
Path to ``libbpf`` development headers

``LIBBPF_LIBRARIES``
Path to `libbpf` library

``BPFOBJECT_VMLINUX_H``
Path to ``vmlinux.h`` generated by ``bpftool``. If unset, this module will
attempt to automatically generate a copy.

This module sets the following result variables:

::

BpfObject_FOUND = TRUE if all components are found


This module also provides the ``bpf_object()`` macro. This macro generates a
cmake interface library for the BPF object's generated skeleton as well
as the associated dependencies.

.. code-block:: cmake

bpf_object(<name> <source>)

Given an abstract ``<name>`` for a BPF object and the associated ``<source>``
file, generates an interface library target, ``<name>_skel``, that may be
linked against by other cmake targets.

Example Usage:

::

find_package(BpfObject REQUIRED)
bpf_object(myobject myobject.bpf.c)
add_executable(myapp myapp.c)
target_link_libraries(myapp myobject_skel)

#]=======================================================================]

if(NOT BPFOBJECT_BPFTOOL_EXE)
find_program(BPFOBJECT_BPFTOOL_EXE NAMES bpftool DOC "Path to bpftool executable")
endif()

if(NOT BPFOBJECT_CLANG_EXE)
find_program(BPFOBJECT_CLANG_EXE NAMES clang DOC "Path to clang executable")

execute_process(COMMAND ${BPFOBJECT_CLANG_EXE} --version
OUTPUT_VARIABLE CLANG_version_output
ERROR_VARIABLE CLANG_version_error
RESULT_VARIABLE CLANG_version_result
OUTPUT_STRIP_TRAILING_WHITESPACE)

# Check that clang is new enough
if(${CLANG_version_result} EQUAL 0)
if("${CLANG_version_output}" MATCHES "clang version ([^\n]+)\n")
# Transform X.Y.Z into X;Y;Z which can then be interpreted as a list
set(CLANG_VERSION "${CMAKE_MATCH_1}")
string(REPLACE "." ";" CLANG_VERSION_LIST ${CLANG_VERSION})
list(GET CLANG_VERSION_LIST 0 CLANG_VERSION_MAJOR)

# Anything older than clang 10 doesn't really work
string(COMPARE LESS ${CLANG_VERSION_MAJOR} 10 CLANG_VERSION_MAJOR_LT10)
if(${CLANG_VERSION_MAJOR_LT10})
message(FATAL_ERROR "clang ${CLANG_VERSION} is too old for BPF CO-RE")
endif()

message(STATUS "Found clang version: ${CLANG_VERSION}")
else()
message(FATAL_ERROR "Failed to parse clang version string: ${CLANG_version_output}")
endif()
else()
message(FATAL_ERROR "Command \"${BPFOBJECT_CLANG_EXE} --version\" failed with output:\n${CLANG_version_error}")
endif()
endif()

if(NOT LIBBPF_INCLUDE_DIRS OR NOT LIBBPF_LIBRARIES)
find_package(LibBpf)
endif()

if(BPFOBJECT_VMLINUX_H)
get_filename_component(GENERATED_VMLINUX_DIR ${BPFOBJECT_VMLINUX_H} DIRECTORY)
elseif(BPFOBJECT_BPFTOOL_EXE)
# Generate vmlinux.h
set(GENERATED_VMLINUX_DIR ${CMAKE_CURRENT_BINARY_DIR}/include/lo2s)
set(BPFOBJECT_VMLINUX_H "${GENERATED_VMLINUX_DIR}/vmlinux.h")

file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/lo2s")
execute_process(COMMAND ${BPFOBJECT_BPFTOOL_EXE} btf dump file /sys/kernel/btf/vmlinux format c
OUTPUT_FILE ${BPFOBJECT_VMLINUX_H}
ERROR_VARIABLE VMLINUX_error
RESULT_VARIABLE VMLINUX_result)
if(${VMLINUX_result} EQUAL 0)
set(VMLINUX ${BPFOBJECT_VMLINUX_H})
else()
message(FATAL_ERROR "Failed to dump vmlinux.h from BTF: ${VMLINUX_error}")
endif()
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(BpfObject
REQUIRED_VARS
BPFOBJECT_BPFTOOL_EXE
BPFOBJECT_CLANG_EXE
LIBBPF_INCLUDE_DIRS
LIBBPF_LIBRARIES
GENERATED_VMLINUX_DIR)

# Get clang bpf system includes
execute_process(
COMMAND bash -c "${BPFOBJECT_CLANG_EXE} -v -E - < /dev/null 2>&1 |
sed -n '/<...> search starts here:/,/End of search list./{ s| \\(/.*\\)|-idirafter \\1|p }'"
OUTPUT_VARIABLE CLANG_SYSTEM_INCLUDES_output
ERROR_VARIABLE CLANG_SYSTEM_INCLUDES_error
RESULT_VARIABLE CLANG_SYSTEM_INCLUDES_result
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(${CLANG_SYSTEM_INCLUDES_result} EQUAL 0)
separate_arguments(CLANG_SYSTEM_INCLUDES UNIX_COMMAND ${CLANG_SYSTEM_INCLUDES_output})
message(STATUS "BPF system include flags: ${CLANG_SYSTEM_INCLUDES}")
else()
message(FATAL_ERROR "Failed to determine BPF system includes: ${CLANG_SYSTEM_INCLUDES_error}")
endif()

# Get target arch
execute_process(COMMAND uname -m
COMMAND sed -e "s/x86_64/x86/" -e "s/aarch64/arm64/" -e "s/ppc64le/powerpc/" -e "s/mips.*/mips/"
OUTPUT_VARIABLE ARCH_output
ERROR_VARIABLE ARCH_error
RESULT_VARIABLE ARCH_result
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(${ARCH_result} EQUAL 0)
set(ARCH ${ARCH_output})
message(STATUS "BPF target arch: ${ARCH}")
else()
message(FATAL_ERROR "Failed to determine target architecture: ${ARCH_error}")
endif()

# Public macro
macro(bpf_object name input)
set(BPF_C_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${input})
set(BPF_O_FILE ${CMAKE_CURRENT_BINARY_DIR}/${name}.bpf.o)
set(BPF_SKEL_FILE ${CMAKE_CURRENT_BINARY_DIR}/include/lo2s/${name}.skel.h)
message(STATUS ${CMAKE_CURRENT_BINARY_DIR})
set(OUTPUT_TARGET ${name}_skel)

# Build BPF object file
add_custom_command(OUTPUT ${BPF_O_FILE}
COMMAND ${BPFOBJECT_CLANG_EXE} -g -O2 -target bpf -D__TARGET_ARCH_${ARCH}
${CLANG_SYSTEM_INCLUDES} -I${GENERATED_VMLINUX_DIR}
-I${CMAKE_SOURCE_DIR}/include
-isystem ${LIBBPF_INCLUDE_DIRS} -c ${BPF_C_FILE} -o ${BPF_O_FILE}
COMMAND_EXPAND_LISTS
VERBATIM
DEPENDS ${BPF_C_FILE}
COMMENT "[clang] Building BPF object: ${name}")

# Build BPF skeleton header
add_custom_command(OUTPUT ${BPF_SKEL_FILE}
COMMAND bash -c "${BPFOBJECT_BPFTOOL_EXE} gen skeleton ${BPF_O_FILE} > ${BPF_SKEL_FILE}"
VERBATIM
DEPENDS ${BPF_O_FILE}
COMMENT "[skel] Building BPF skeleton: ${name}")

add_library(${OUTPUT_TARGET} INTERFACE)
target_sources(${OUTPUT_TARGET} INTERFACE ${BPF_SKEL_FILE})
target_include_directories(${OUTPUT_TARGET} INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
target_include_directories(${OUTPUT_TARGET} SYSTEM INTERFACE ${LIBBPF_INCLUDE_DIRS})
target_link_libraries(${OUTPUT_TARGET} INTERFACE ${LIBBPF_LIBRARIES} -lelf -lz)
endmacro()
32 changes: 32 additions & 0 deletions cmake/FindLibBpf.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause

find_path(LIBBPF_INCLUDE_DIRS
NAMES
bpf/bpf.h
bpf/btf.h
bpf/libbpf.h
PATHS
/usr/include
/usr/local/include
/opt/local/include
/sw/include
ENV CPATH)

find_library(LIBBPF_LIBRARIES
NAMES
bpf
PATHS
/usr/lib
/usr/local/lib
/opt/local/lib
/sw/lib
ENV LIBRARY_PATH
ENV LD_LIBRARY_PATH)

include (FindPackageHandleStandardArgs)

FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibBpf "Please install the libbpf development package"
LIBBPF_LIBRARIES
LIBBPF_INCLUDE_DIRS)

mark_as_advanced(LIBBPF_INCLUDE_DIRS LIBBPF_LIBRARIES)
2 changes: 2 additions & 0 deletions include/lo2s/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ struct Config
bool use_x86_energy;
// block I/O
bool use_block_io;
// posix I/O
bool use_posix_io;
// syscalls
bool use_syscalls = false;
std::vector<int64_t> syscall_filter;
Expand Down
8 changes: 8 additions & 0 deletions include/lo2s/measurement_scope.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ enum class MeasurementScopeType
NEC_METRIC,
BIO,
SYSCALL,
POSIX_IO,
UNKNOWN
};

Expand Down Expand Up @@ -79,6 +80,11 @@ struct MeasurementScope
return { MeasurementScopeType::SYSCALL, s };
}

static MeasurementScope posix_io(ExecutionScope s)
{
return { MeasurementScopeType::POSIX_IO, s };
}

friend bool operator==(const MeasurementScope& lhs, const MeasurementScope& rhs)
{
return (lhs.scope == rhs.scope) && lhs.type == rhs.type;
Expand Down Expand Up @@ -111,6 +117,8 @@ struct MeasurementScope
return fmt::format("block layer I/O events for {}", scope.name());
case MeasurementScopeType::SYSCALL:
return fmt::format("syscall events for {}", scope.name());
case MeasurementScopeType::POSIX_IO:
return fmt::format("POSIX I/O events for {}", scope.name());
default:
throw new std::runtime_error("Unknown ExecutionScopeType!");
}
Expand Down
Empty file.
2 changes: 1 addition & 1 deletion include/lo2s/monitor/poll_monitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@

void add_fd(int fd);

virtual void monitor([[maybe_unused]] int fd){};
virtual void monitor([[maybe_unused]] int fd) {};

Check failure on line 58 in include/lo2s/monitor/poll_monitor.hpp

View check run for this annotation

Code Style Turtle / Code Formatting Test

include/lo2s/monitor/poll_monitor.hpp#L58

- virtual void monitor([[maybe_unused]] int fd) {}; + virtual void monitor([[maybe_unused]] int fd){};

struct pollfd& stop_pfd()
{
Expand Down
Loading
Loading