From 6bc348bbb8cf654fea2f2878e59476c87c7facab Mon Sep 17 00:00:00 2001 From: Federico Di Pierro Date: Wed, 20 Nov 2024 10:08:09 +0100 Subject: [PATCH 1/6] new(cmake,ci): added support for using jemalloc allocator instead of glibc one. The jemalloc allocator is enabled by default for published packages. Signed-off-by: Federico Di Pierro --- .../workflows/reusable_build_packages.yaml | 1 + CMakeLists.txt | 5 ++ cmake/modules/jemalloc.cmake | 64 +++++++++++++++++++ userspace/falco/CMakeLists.txt | 7 +- 4 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 cmake/modules/jemalloc.cmake diff --git a/.github/workflows/reusable_build_packages.yaml b/.github/workflows/reusable_build_packages.yaml index 650e4317bae..d42ee16ddbd 100644 --- a/.github/workflows/reusable_build_packages.yaml +++ b/.github/workflows/reusable_build_packages.yaml @@ -84,6 +84,7 @@ jobs: -DBUILD_DRIVER=Off \ -DBUILD_BPF=Off \ -DUSE_ASAN=${{ (inputs.sanitizers == true && inputs.arch == 'x86_64' && 'ON') || 'OFF' }} \ + -DUSE_JEMALLOC=On \ -DFALCO_VERSION=${{ inputs.version }} - name: Build project diff --git a/CMakeLists.txt b/CMakeLists.txt index 51f9e71ff51..d42c0e92915 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ option(BUILD_FALCO_UNIT_TESTS "Build falco unit tests" OFF) option(USE_ASAN "Build with AddressSanitizer" OFF) option(USE_UBSAN "Build with UndefinedBehaviorSanitizer" OFF) option(UBSAN_HALT_ON_ERROR "Halt on error when building with UBSan" ON) +option(USE_JEMALLOC "Use jemalloc allocator" OFF) if(WIN32) if(POLICY CMP0091) @@ -141,6 +142,10 @@ set(CMD_MAKE make) include(ExternalProject) +if(USE_JEMALLOC) + include(jemalloc) +endif() + # libs include(falcosecurity-libs) diff --git a/cmake/modules/jemalloc.cmake b/cmake/modules/jemalloc.cmake new file mode 100644 index 00000000000..647c3bf5bf1 --- /dev/null +++ b/cmake/modules/jemalloc.cmake @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (C) 2024 The Falco Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under the License +# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +# or implied. See the License for the specific language governing permissions and limitations under +# the License. +# + +option(USE_BUNDLED_JEMALLOC "Use bundled jemalloc allocator" ${USE_BUNDLED_DEPS}) + +if(JEMALLOC_LIB) + # we already have JEMALLOC +elseif(NOT USE_BUNDLED_JEMALLOC) + if(BUILD_SHARED_LIBS) + set(JEMALLOC_LIB_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) + else() + set(JEMALLOC_LIB_SUFFIX ${CMAKE_STATIC_LIBRARY_SUFFIX}) + endif() + find_library(JEMALLOC_LIB NAMES jemalloc${JEMALLOC_LIB_SUFFIX}) + if(JEMALLOC_LIB) + message(STATUS "Found JEMALLOC: lib: ${JEMALLOC_LIB}") + else() + message(FATAL_ERROR "Couldn't find system jemalloc") + endif() +else() + if(BUILD_SHARED_LIBS) + set(JEMALLOC_LIB_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) + else() + set(JEMALLOC_LIB_SUFFIX ${CMAKE_STATIC_LIBRARY_SUFFIX}) + endif() + set(JEMALLOC_SRC "${PROJECT_BINARY_DIR}/jemalloc-prefix/src") + set(JEMALLOC_LIB "${JEMALLOC_SRC}/jemalloc/lib/libjemalloc${JEMALLOC_LIB_SUFFIX}") + ExternalProject_Add( + jemalloc + PREFIX "${PROJECT_BINARY_DIR}/jemalloc-prefix" + URL "https://github.com/jemalloc/jemalloc/archive/refs/tags/5.3.0.tar.gz" + URL_HASH "SHA256=ef6f74fd45e95ee4ef7f9e19ebe5b075ca6b7fbe0140612b2a161abafb7ee179" + CONFIGURE_COMMAND ./autogen.sh --enable-prof --disable-libdl + BUILD_IN_SOURCE 1 + BUILD_COMMAND make build_lib_static + INSTALL_COMMAND "" + UPDATE_COMMAND "" + BUILD_BYPRODUCTS ${JEMALLOC_LIB} + ) + message(STATUS "Using bundled jemalloc: lib: ${JEMALLOC_LIB}") + install( + FILES "${JEMALLOC_LIB}" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/${LIBS_PACKAGE_NAME}" + COMPONENT "libs-deps" + ) +endif() + +# We add a custom target, in this way we can always depend on `jemalloc` without distinguishing +# between "bundled" and "not-bundled" case +if(NOT TARGET jemalloc) + add_custom_target(jemalloc) +endif() diff --git a/userspace/falco/CMakeLists.txt b/userspace/falco/CMakeLists.txt index 13849e6fe9a..d6c399059e1 100644 --- a/userspace/falco/CMakeLists.txt +++ b/userspace/falco/CMakeLists.txt @@ -68,9 +68,13 @@ set(FALCO_INCLUDE_DIRECTORIES ) set(FALCO_DEPENDENCIES cxxopts) - set(FALCO_LIBRARIES falco_engine sinsp yaml-cpp) +if(USE_JEMALLOC) + list(APPEND FALCO_DEPENDENCIES jemalloc) + list(APPEND FALCO_LIBRARIES ${JEMALLOC_LIB}) +endif() + if(NOT WIN32) target_sources(falco_application PRIVATE outputs_program.cpp outputs_syslog.cpp) endif() @@ -96,6 +100,7 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD) list( APPEND FALCO_INCLUDE_DIRECTORIES + FALCO_INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}" "${GRPC_INCLUDE}" "${GRPCPP_INCLUDE}" From f93e696ca4bccd8a1b49f6abf82a15699501e3a6 Mon Sep 17 00:00:00 2001 From: Federico Di Pierro Date: Wed, 20 Nov 2024 12:10:47 +0100 Subject: [PATCH 2/6] new(cmake,userspace): expose jemalloc stats in stats writer and prometheus metircs. Signed-off-by: Federico Di Pierro --- cmake/modules/jemalloc.cmake | 9 ++++-- falco.yaml | 1 + userspace/falco/config_json_schema.h | 3 ++ userspace/falco/configuration.cpp | 3 ++ userspace/falco/configuration.h | 3 ++ userspace/falco/falco_metrics.cpp | 36 ++++++++++++++++++++++++ userspace/falco/stats_writer.cpp | 41 ++++++++++++++++++++++++++++ 7 files changed, 94 insertions(+), 2 deletions(-) diff --git a/cmake/modules/jemalloc.cmake b/cmake/modules/jemalloc.cmake index 647c3bf5bf1..3f80ac7556f 100644 --- a/cmake/modules/jemalloc.cmake +++ b/cmake/modules/jemalloc.cmake @@ -15,9 +15,10 @@ option(USE_BUNDLED_JEMALLOC "Use bundled jemalloc allocator" ${USE_BUNDLED_DEPS}) -if(JEMALLOC_LIB) +if(JEMALLOC_INCLUDE) # we already have JEMALLOC elseif(NOT USE_BUNDLED_JEMALLOC) + find_path(JEMALLOC_INCLUDE jemalloc/jemalloc.h) if(BUILD_SHARED_LIBS) set(JEMALLOC_LIB_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) else() @@ -37,6 +38,7 @@ else() endif() set(JEMALLOC_SRC "${PROJECT_BINARY_DIR}/jemalloc-prefix/src") set(JEMALLOC_LIB "${JEMALLOC_SRC}/jemalloc/lib/libjemalloc${JEMALLOC_LIB_SUFFIX}") + set(JEMALLOC_INCLUDE "${JEMALLOC_SRC}/jemalloc/include/jemalloc") ExternalProject_Add( jemalloc PREFIX "${PROJECT_BINARY_DIR}/jemalloc-prefix" @@ -49,7 +51,7 @@ else() UPDATE_COMMAND "" BUILD_BYPRODUCTS ${JEMALLOC_LIB} ) - message(STATUS "Using bundled jemalloc: lib: ${JEMALLOC_LIB}") + message(STATUS "Using bundled jemalloc: include: ${JEMALLOC_INCLUDE}, lib: ${JEMALLOC_LIB}") install( FILES "${JEMALLOC_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/${LIBS_PACKAGE_NAME}" @@ -62,3 +64,6 @@ endif() if(NOT TARGET jemalloc) add_custom_target(jemalloc) endif() + +include_directories(${JEMALLOC_INCLUDE}) +add_compile_definitions(HAS_JEMALLOC) diff --git a/falco.yaml b/falco.yaml index 80d7926b22c..332b9757e80 100644 --- a/falco.yaml +++ b/falco.yaml @@ -1124,6 +1124,7 @@ metrics: kernel_event_counters_per_cpu_enabled: false libbpf_stats_enabled: true plugins_metrics_enabled: true + jemalloc_stats_enabled: false convert_memory_to_mb: true include_empty_values: false diff --git a/userspace/falco/config_json_schema.h b/userspace/falco/config_json_schema.h index 92ae04fe109..02006f6e37d 100644 --- a/userspace/falco/config_json_schema.h +++ b/userspace/falco/config_json_schema.h @@ -569,6 +569,9 @@ const char config_schema_string[] = LONG_STRING_CONST( }, "include_empty_values": { "type": "boolean" + }, + "jemalloc_stats_enabled": { + "type": "boolean" } }, "minProperties": 1, diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index b2359ed1da4..574fcd79535 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -610,6 +610,9 @@ void falco_configuration::load_yaml(const std::string &config_name) { if(m_config.get_scalar("metrics.plugins_metrics_enabled", true)) { m_metrics_flags |= METRICS_V2_PLUGINS; } + if(m_config.get_scalar("metrics.jemalloc_stats_enabled", true)) { + m_metrics_flags |= METRICS_V2_JEMALLOC_STATS; + } m_metrics_convert_memory_to_mb = m_config.get_scalar("metrics.convert_memory_to_mb", true); diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index ba6eb201e01..3a5f3a5ac9d 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -37,6 +37,9 @@ limitations under the License. #include "event_drops.h" #include "falco_outputs.h" +// Falco only metric +#define METRICS_V2_JEMALLOC_STATS 1 << 31 + enum class engine_kind_t : uint8_t { KMOD, EBPF, MODERN_EBPF, REPLAY, GVISOR, NODRIVER }; // Map that holds { config filename | validation status } for each loaded config file. diff --git a/userspace/falco/falco_metrics.cpp b/userspace/falco/falco_metrics.cpp index 8d58338de44..aca5e8fd24c 100644 --- a/userspace/falco/falco_metrics.cpp +++ b/userspace/falco/falco_metrics.cpp @@ -23,6 +23,10 @@ limitations under the License. #include +#ifdef HAS_JEMALLOC +#include +#endif + namespace fs = std::filesystem; /*! @@ -249,6 +253,38 @@ std::string falco_metrics::to_text(const falco::app::state& state) { } } } +#ifdef HAS_JEMALLOC + if(state.config->m_metrics_flags & METRICS_V2_JEMALLOC_STATS) { + nlohmann::json j; + malloc_stats_print( + [](void* to, const char* from) { + nlohmann::json* j = (nlohmann::json*)to; + *j = nlohmann::json::parse(from); + }, + &j, + "Jmdablxeg"); + const auto& j_stats = j["jemalloc"]["stats"]; + for(auto it = j_stats.begin(); it != j_stats.end(); ++it) { + if(it.value().is_number_unsigned()) { + std::uint64_t val = it.value().template get(); + std::string key = "jemalloc." + it.key(); + auto metric = libs::metrics::libsinsp_metrics::new_metric( + key.c_str(), + METRICS_V2_JEMALLOC_STATS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_MEMORY_BYTES, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, + val); + prometheus_metrics_converter.convert_metric_to_unit_convention(metric); + prometheus_text += + prometheus_metrics_converter.convert_metric_to_text_prometheus( + metric, + "falcosecurity", + "falco"); + } + } + } +#endif } // Libs metrics categories diff --git a/userspace/falco/stats_writer.cpp b/userspace/falco/stats_writer.cpp index c5af9698e74..eac9e784be0 100644 --- a/userspace/falco/stats_writer.cpp +++ b/userspace/falco/stats_writer.cpp @@ -32,6 +32,10 @@ limitations under the License. #include #include +#ifdef HAS_JEMALLOC +#include +#endif + namespace fs = std::filesystem; // note: ticker_t is an uint16_t, which is enough because we don't care about @@ -434,6 +438,43 @@ void stats_writer::collector::get_metrics_output_fields_additional( } } +#ifdef HAS_JEMALLOC + if(m_writer->m_config->m_metrics_flags & METRICS_V2_JEMALLOC_STATS) { + nlohmann::json j; + malloc_stats_print( + [](void* to, const char* from) { + nlohmann::json* j = (nlohmann::json*)to; + *j = nlohmann::json::parse(from); + }, + &j, + "Jmdablxeg"); + const auto& j_stats = j["jemalloc"]["stats"]; + for(auto it = j_stats.begin(); it != j_stats.end(); ++it) { + if(it.value().is_number_unsigned()) { + std::uint64_t val = it.value().template get(); + if(m_writer->m_config->m_metrics_include_empty_values || val != 0) { + std::string key = "falco.jemalloc." + it.key() + "_bytes"; + auto metric = libs::metrics::libsinsp_metrics::new_metric( + key.c_str(), + METRICS_V2_JEMALLOC_STATS, + METRIC_VALUE_TYPE_U64, + METRIC_VALUE_UNIT_MEMORY_BYTES, + METRIC_VALUE_METRIC_TYPE_MONOTONIC, + val); + if(m_writer->m_config->m_metrics_convert_memory_to_mb && + m_writer->m_output_rule_metrics_converter) { + m_writer->m_output_rule_metrics_converter + ->convert_metric_to_unit_convention(metric); + output_fields[metric.name] = metric.value.d; + } else { + output_fields[metric.name] = metric.value.u64; + } + } + } + } + } +#endif + #if defined(__linux__) and !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__) if(m_writer->m_libs_metrics_collector && m_writer->m_output_rule_metrics_converter) { // Libs metrics categories From 17098393b2512e7794bddabf969e702c0e258def Mon Sep 17 00:00:00 2001 From: Federico Di Pierro Date: Thu, 21 Nov 2024 10:42:22 +0100 Subject: [PATCH 3/6] fix(cmake): fixed jemalloc from system. Signed-off-by: Federico Di Pierro --- cmake/modules/jemalloc.cmake | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmake/modules/jemalloc.cmake b/cmake/modules/jemalloc.cmake index 3f80ac7556f..bd9d1b11bf7 100644 --- a/cmake/modules/jemalloc.cmake +++ b/cmake/modules/jemalloc.cmake @@ -19,14 +19,15 @@ if(JEMALLOC_INCLUDE) # we already have JEMALLOC elseif(NOT USE_BUNDLED_JEMALLOC) find_path(JEMALLOC_INCLUDE jemalloc/jemalloc.h) + set(JEMALLOC_INCLUDE ${JEMALLOC_INCLUDE}/jemalloc) if(BUILD_SHARED_LIBS) set(JEMALLOC_LIB_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) else() set(JEMALLOC_LIB_SUFFIX ${CMAKE_STATIC_LIBRARY_SUFFIX}) endif() - find_library(JEMALLOC_LIB NAMES jemalloc${JEMALLOC_LIB_SUFFIX}) + find_library(JEMALLOC_LIB NAMES libjemalloc${JEMALLOC_LIB_SUFFIX}) if(JEMALLOC_LIB) - message(STATUS "Found JEMALLOC: lib: ${JEMALLOC_LIB}") + message(STATUS "Found JEMALLOC: include: ${JEMALLOC_INCLUDE}, lib: ${JEMALLOC_LIB}") else() message(FATAL_ERROR "Couldn't find system jemalloc") endif() From e250e84ce665e5f1febbbcc4d5622833ba5c47db Mon Sep 17 00:00:00 2001 From: Federico Di Pierro Date: Fri, 22 Nov 2024 09:27:33 +0100 Subject: [PATCH 4/6] chore(ci): drop jemalloc from ASAN builds. Signed-off-by: Federico Di Pierro --- .github/workflows/reusable_build_packages.yaml | 3 ++- falco.yaml | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable_build_packages.yaml b/.github/workflows/reusable_build_packages.yaml index d42ee16ddbd..ac648412fb7 100644 --- a/.github/workflows/reusable_build_packages.yaml +++ b/.github/workflows/reusable_build_packages.yaml @@ -75,6 +75,7 @@ jobs: uses: falcosecurity/libs/.github/actions/install-zig@master - name: Prepare project + # Jemalloc and ASAN don't play very well together. run: | cmake -B build -S . \ -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} \ @@ -84,7 +85,7 @@ jobs: -DBUILD_DRIVER=Off \ -DBUILD_BPF=Off \ -DUSE_ASAN=${{ (inputs.sanitizers == true && inputs.arch == 'x86_64' && 'ON') || 'OFF' }} \ - -DUSE_JEMALLOC=On \ + -DUSE_JEMALLOC=${{ (inputs.sanitizers == true && inputs.arch == 'x86_64' && 'OFF') || 'ON' }} \ -DFALCO_VERSION=${{ inputs.version }} - name: Build project diff --git a/falco.yaml b/falco.yaml index 332b9757e80..4f3ab655360 100644 --- a/falco.yaml +++ b/falco.yaml @@ -1103,6 +1103,8 @@ syscall_event_drops: # there will be no metrics available. In other words, there are no default or # generic plugin metrics at this time. This may be subject to change. # +# `jemalloc_stats_enabled`: Falco can now expose jemalloc related stats. +# # If metrics are enabled, the web server can be configured to activate the # corresponding Prometheus endpoint using `webserver.prometheus_metrics_enabled`. # Prometheus output can be used in combination with the other output options. From 7fe39a3fdc958b027eb7258187f9eae21f473d74 Mon Sep 17 00:00:00 2001 From: Federico Di Pierro Date: Fri, 6 Dec 2024 13:10:13 +0100 Subject: [PATCH 5/6] chore(cmake): add a warning when using both jemalloc and asan. Signed-off-by: Federico Di Pierro Co-authored-by: Samuel Gaist --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d42c0e92915..5aafd3bb4a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -143,6 +143,9 @@ set(CMD_MAKE make) include(ExternalProject) if(USE_JEMALLOC) + if(USE_ASAN) + message(WARNING "Jemalloc and ASAN do not play well together") + endif() include(jemalloc) endif() From b8db7e5e740103b4edb964cc31bea7998e491f6a Mon Sep 17 00:00:00 2001 From: Federico Di Pierro Date: Fri, 6 Dec 2024 14:50:21 +0100 Subject: [PATCH 6/6] update(cmake): bump jemalloc asan warning message Co-authored-by: Samuel Gaist Signed-off-by: Federico Di Pierro --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5aafd3bb4a7..a28d0b62a3e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,7 +144,7 @@ include(ExternalProject) if(USE_JEMALLOC) if(USE_ASAN) - message(WARNING "Jemalloc and ASAN do not play well together") + message(WARNING "Jemalloc and ASAN are known to have issues when combined") endif() include(jemalloc) endif()