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

new(cmake,ci): added support for using jemalloc allocator instead of glibc one #3406

Merged
merged 6 commits into from
Dec 10, 2024
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
2 changes: 2 additions & 0 deletions .github/workflows/reusable_build_packages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }} \
Expand All @@ -84,6 +85,7 @@ jobs:
-DBUILD_DRIVER=Off \
-DBUILD_BPF=Off \
-DUSE_ASAN=${{ (inputs.sanitizers == true && inputs.arch == 'x86_64' && 'ON') || 'OFF' }} \
-DUSE_JEMALLOC=${{ (inputs.sanitizers == true && inputs.arch == 'x86_64' && 'OFF') || 'ON' }} \
-DFALCO_VERSION=${{ inputs.version }}

- name: Build project
Expand Down
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -141,6 +142,13 @@ set(CMD_MAKE make)

include(ExternalProject)

if(USE_JEMALLOC)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeing the comment about jemalloc and ASAN above, shouldn't there be a check done here that fails the configuration if both are enabled ? Otherwise we will likely have users that will get problematic builds.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, i'll just add a warning!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed!

if(USE_ASAN)
message(WARNING "Jemalloc and ASAN are known to have issues when combined")
endif()
include(jemalloc)
endif()

# libs
include(falcosecurity-libs)

Expand Down
70 changes: 70 additions & 0 deletions cmake/modules/jemalloc.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# 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_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 libjemalloc${JEMALLOC_LIB_SUFFIX})
if(JEMALLOC_LIB)
message(STATUS "Found JEMALLOC: include: ${JEMALLOC_INCLUDE}, 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}")
set(JEMALLOC_INCLUDE "${JEMALLOC_SRC}/jemalloc/include/jemalloc")
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: include: ${JEMALLOC_INCLUDE}, 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()

include_directories(${JEMALLOC_INCLUDE})
add_compile_definitions(HAS_JEMALLOC)
3 changes: 3 additions & 0 deletions falco.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -1124,6 +1126,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

Expand Down
7 changes: 6 additions & 1 deletion userspace/falco/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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}"
Expand Down
3 changes: 3 additions & 0 deletions userspace/falco/config_json_schema.h
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,9 @@ const char config_schema_string[] = LONG_STRING_CONST(
},
"include_empty_values": {
"type": "boolean"
},
"jemalloc_stats_enabled": {
"type": "boolean"
}
},
"minProperties": 1,
Expand Down
3 changes: 3 additions & 0 deletions userspace/falco/configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,9 @@ void falco_configuration::load_yaml(const std::string &config_name) {
if(m_config.get_scalar<bool>("metrics.plugins_metrics_enabled", true)) {
m_metrics_flags |= METRICS_V2_PLUGINS;
}
if(m_config.get_scalar<bool>("metrics.jemalloc_stats_enabled", true)) {
m_metrics_flags |= METRICS_V2_JEMALLOC_STATS;
}

m_metrics_convert_memory_to_mb =
m_config.get_scalar<bool>("metrics.convert_memory_to_mb", true);
Expand Down
3 changes: 3 additions & 0 deletions userspace/falco/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All other METRICS_V2_... defines live in libs; give this a big number to avoid conflicts.


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.
Expand Down
36 changes: 36 additions & 0 deletions userspace/falco/falco_metrics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ limitations under the License.

#include <libsinsp/sinsp.h>

#ifdef HAS_JEMALLOC
#include <jemalloc.h>
#endif

namespace fs = std::filesystem;

/*!
Expand Down Expand Up @@ -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::uint64_t>();
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
Expand Down
41 changes: 41 additions & 0 deletions userspace/falco/stats_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ limitations under the License.
#include <libscap/strl.h>
#include <libscap/scap_vtable.h>

#ifdef HAS_JEMALLOC
#include <jemalloc.h>
#endif

namespace fs = std::filesystem;

// note: ticker_t is an uint16_t, which is enough because we don't care about
Expand Down Expand Up @@ -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<std::uint64_t>();
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
Expand Down
Loading