diff --git a/Dockerfile.ci b/Dockerfile.ci index d33745b841..10316f6cb2 100644 --- a/Dockerfile.ci +++ b/Dockerfile.ci @@ -1,13 +1,56 @@ -FROM ubuntu:24.04 +FROM debian:trixie-slim -# Base + g++ + git for perf_tests -RUN DEBIAN_FRONTEND=noninteractive && apt-get update && apt-get install -y gpg wget gcc g++ libunwind-dev jq bash nodejs npm bzip2 \ - git autoconf make iproute2 jq curl ca-certificates libtool pkg-config cmake lcov && \ - echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main" | tee /etc/apt/sources.list.d/archive_uri-http_apt_llvm_org_jammy_-jammy.list && \ - wget -qO - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - && \ - apt-get update && apt-get install -y clang-format-19 clang-tidy-19 && \ - ln -s /usr/lib/llvm-19/bin/clang-tidy /usr/bin/clang-tidy && \ - ln -s /usr/lib/llvm-19/bin/clang-format /usr/bin/clang-format +# Align with Deckhouse module (debian-trixie) and libunwind+lzma static link expectations. +# LLVM 21 from apt.llvm.org (trixie toolchain). +# binutils-gold: needed only on linux/arm64 because every currently released Go +# (1.25.x with x<=9 and 1.26.x with x<=2) unconditionally forces `-fuse-ld=gold` +# for cgo dynamic/PIE links and aborts with "ARM64 external linker must be gold" +# otherwise (see https://github.com/golang/go/issues/15696 and +# https://github.com/golang/go/issues/22040). The underlying GNU bfd bug was +# fixed in binutils 2.36 (we ship 2.44), but Go itself only learned to detect +# that and fall back to bfd in CL 740480; the backports landed in +# release-branch.go1.{25,26} on 2026-04-17, *after* the cut of go1.26.2 +# (2026-04-15), so the fix will first ship in Go 1.25.10 / Go 1.26.3. +# Once GO_VERSION below is bumped to >=1.25.10 or >=1.26.3, this package can +# be dropped (see https://github.com/golang/go/issues/78405). +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + curl \ + wget \ + gnupg \ + gcc-14 \ + g++-14 \ + binutils-gold \ + libunwind-dev \ + liblzma-dev \ + libstdc++-14-dev \ + jq \ + bash \ + nodejs \ + npm \ + bzip2 \ + git \ + autoconf \ + make \ + iproute2 \ + libtool \ + pkg-config \ + cmake \ + lcov; \ + wget -qO /tmp/llvm-snapshot.gpg.key https://apt.llvm.org/llvm-snapshot.gpg.key; \ + gpg --dearmor -o /usr/share/keyrings/apt-llvm-org.gpg /tmp/llvm-snapshot.gpg.key; \ + rm -f /tmp/llvm-snapshot.gpg.key; \ + echo "deb [signed-by=/usr/share/keyrings/apt-llvm-org.gpg] http://apt.llvm.org/trixie/ llvm-toolchain-trixie-21 main" > /etc/apt/sources.list.d/llvm.list; \ + apt-get update; \ + apt-get install -y --no-install-recommends clang-format-21 clang-tidy-21; \ + ln -sf /usr/lib/llvm-21/bin/clang-tidy /usr/bin/clang-tidy; \ + ln -sf /usr/lib/llvm-21/bin/clang-format /usr/bin/clang-format; \ + update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100; \ + update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 100; \ + update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-14 100; \ + rm -rf /var/lib/apt/lists/* # Bazel ARG BAZEL_VERSION=7.4.1 @@ -16,7 +59,11 @@ RUN wget -qO "/usr/local/bin/bazel" https://github.com/bazelbuild/bazel/releases chmod +x "/usr/local/bin/bazel" # Go + go-tools (GOPATH under /opt so FIRST_GOPATH/bin/goyacc is found when /root is volume-mounted) -ARG GO_VERSION=1.25.9 +# TODO: when bumping GO_VERSION to >=1.25.10 or >=1.26.3, drop the +# `binutils-gold` package above — those Go releases no longer require gold on +# linux/arm64 when GNU ld is 2.36+. See the comment near `binutils-gold` and +# https://github.com/golang/go/issues/22040 (issue #78405 for the 1.25 backport). +ARG GO_VERSION=1.26.2 ARG GO_ARCH RUN cd /tmp && curl -LOs https://go.dev/dl/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz && tar -C /usr/local -xzf go${GO_VERSION}.linux-${GO_ARCH}.tar.gz ENV GOPATH="/opt/go" @@ -28,5 +75,4 @@ ARG GOYACC_VERSION=v0.6.0 RUN go install golang.org/x/tools/cmd/goyacc@${GOYACC_VERSION} # minio for getting perf test data -RUN wget -O /usr/local/bin/mcli https://dl.min.io/client/mc/release/linux-amd64/mc -RUN chmod +x /usr/local/bin/mcli +RUN wget -O /usr/local/bin/mcli "https://dl.min.io/client/mc/release/linux-${GO_ARCH}/mc" && chmod +x /usr/local/bin/mcli diff --git a/pp/MODULE.bazel b/pp/MODULE.bazel index 7dd2143c93..c97519dbfe 100644 --- a/pp/MODULE.bazel +++ b/pp/MODULE.bazel @@ -5,8 +5,8 @@ # For more details, please check https://github.com/bazelbuild/bazel/issues/18958 ############################################################################### register_toolchains( - "//bazel/toolchain:cc_toolchain_for_g++-13_toolchain_aarch64", - "//bazel/toolchain:cc_toolchain_for_g++-13_toolchain_x86_64", + "//bazel/toolchain:cc_toolchain_for_g++-14_toolchain_aarch64", + "//bazel/toolchain:cc_toolchain_for_g++-14_toolchain_x86_64", ) # Hedron's Compile Commands Extractor for Bazel diff --git a/pp/bare_bones/bitset.h b/pp/bare_bones/bitset.h index 8730295606..5fb455788c 100644 --- a/pp/bare_bones/bitset.h +++ b/pp/bare_bones/bitset.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "bit.h" #include "concepts.h" @@ -263,3 +264,12 @@ template struct IsZeroInitializable> : std::true_type {}; } // namespace BareBones + +// GenericBitset::size() is the allocated bit width, not ranges::distance(begin, end) (set-bit +// count). GCC 14+ libstdc++ uses sized-range fast paths in std::ranges::equal; disable them. +namespace std::ranges { + +template +inline constexpr bool disable_sized_range> = true; + +} // namespace std::ranges diff --git a/pp/bazel/toolchain/BUILD b/pp/bazel/toolchain/BUILD index c1a4745949..eb723a3368 100644 --- a/pp/bazel/toolchain/BUILD +++ b/pp/bazel/toolchain/BUILD @@ -44,41 +44,15 @@ string_flag( ) cc_toolchain_suite( - name = "g++-13", + name = "g++-14", toolchains = { - "k8": ":g++-13_toolchain_x86_64", - "aarch64": ":g++-13_toolchain_aarch64", + "k8": ":g++-14_toolchain_x86_64", + "aarch64": ":g++-14_toolchain_aarch64", }, ) filegroup(name = "empty") -cc_toolchain( - name = "g++-13_toolchain_x86_64", - all_files = ":empty", - compiler_files = ":empty", - dwp_files = ":empty", - linker_files = ":empty", - objcopy_files = ":empty", - strip_files = ":empty", - supports_param_files = 0, - toolchain_config = ":g++-13_toolchain_config_x86_64", - toolchain_identifier = "g++-13_toolchain", -) - -cc_toolchain( - name = "g++-13_toolchain_aarch64", - all_files = ":empty", - compiler_files = ":empty", - dwp_files = ":empty", - linker_files = ":empty", - objcopy_files = ":empty", - strip_files = ":empty", - supports_param_files = 0, - toolchain_config = ":g++-13_toolchain_config_aarch64", - toolchain_identifier = "g++-13_toolchain", -) - cc_toolchain( name = "g++-14_toolchain_x86_64", all_files = ":empty", @@ -105,34 +79,6 @@ cc_toolchain( toolchain_identifier = "g++-14_toolchain", ) -toolchain( - name = "cc_toolchain_for_g++-13_toolchain_x86_64", - toolchain = ":g++-13_toolchain_x86_64", - toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", - exec_compatible_with = [ - "@platforms//cpu:x86_64", - "@platforms//os:linux", - ], - target_compatible_with = [ - "@platforms//cpu:x86_64", - "@platforms//os:linux", - ], -) - -toolchain( - name = "cc_toolchain_for_g++-13_toolchain_aarch64", - toolchain = ":g++-13_toolchain_aarch64", - toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", - exec_compatible_with = [ - "@platforms//cpu:aarch64", - "@platforms//os:linux", - ], - target_compatible_with = [ - "@platforms//cpu:aarch64", - "@platforms//os:linux", - ], -) - toolchain( name = "cc_toolchain_for_g++-14_toolchain_x86_64", toolchain = ":g++-14_toolchain_x86_64", @@ -161,34 +107,6 @@ toolchain( ], ) -cc_toolchain_config( - name = "g++-13_toolchain_config_x86_64", - builtin_include_directories = [ - "/usr/lib/gcc/x86_64-alpine-linux-musl", - "/usr/lib/gcc/x86_64-linux-gnu/13", - "/usr/include", - "/usr/lib/linux", - ], - march = ":march", - with_asan = ":asan", - with_profiling = ":profiling", - profiling_opts = ":profiling_opts", -) - -cc_toolchain_config( - name = "g++-13_toolchain_config_aarch64", - builtin_include_directories = [ - "/usr/lib/gcc/aarch64-alpine-linux-musl/13.2.1/include/", - "/usr/lib/gcc/aarch64-linux-gnu/13", - "/usr/include", - "/usr/lib/linux", - ], - march = ":march", - with_asan = ":asan", - with_profiling = ":profiling", - profiling_opts = ":profiling_opts", -) - cc_toolchain_config( name = "g++-14_toolchain_config_x86_64", builtin_include_directories = [ diff --git a/pp/bazel/toolchain/cc_toolchain_config.bzl b/pp/bazel/toolchain/cc_toolchain_config.bzl index 82da70b7f8..39a6958fb7 100644 --- a/pp/bazel/toolchain/cc_toolchain_config.bzl +++ b/pp/bazel/toolchain/cc_toolchain_config.bzl @@ -204,10 +204,10 @@ def _impl(ctx): flags = [ "-static-libgcc", "-static-libstdc++", - "-l:libstdc++.a", + "-lstdc++", "-lm", "-lunwind", - "-lstdc++_libbacktrace" + "-lstdc++exp" ], ), ]), diff --git a/pp/entrypoint/metrics.cpp b/pp/entrypoint/metrics.cpp index ffb5b4c26a..208f8e6556 100644 --- a/pp/entrypoint/metrics.cpp +++ b/pp/entrypoint/metrics.cpp @@ -11,7 +11,9 @@ using PromPP::Primitives::Go::String; extern "C" void prompp_metrics_register() { [[maybe_unused]] static auto _ = [] { +#if JEMALLOC_AVAILABLE metrics::CreateMetricsPage(); +#endif return 0; }(); } diff --git a/pp/go/cppbridge/entrypoint.go b/pp/go/cppbridge/entrypoint.go index 0124ed2a5a..fc01c76aa3 100644 --- a/pp/go/cppbridge/entrypoint.go +++ b/pp/go/cppbridge/entrypoint.go @@ -12,8 +12,8 @@ package cppbridge // #cgo amd64,!asan,dbg LDFLAGS: -l:amd64_entrypoint_init_aio_dbg.a -l:amd64_k8_entrypoint_aio_prefixed_dbg.a -l:amd64_nehalem_entrypoint_aio_prefixed_dbg.a -l:amd64_haswell_entrypoint_aio_prefixed_dbg.a // #cgo amd64,asan,!dbg LDFLAGS: -l:amd64_entrypoint_init_aio_opt_asan.a -l:amd64_k8_entrypoint_aio_prefixed_opt_asan.a -l:amd64_nehalem_entrypoint_aio_prefixed_opt_asan.a -l:amd64_haswell_entrypoint_aio_prefixed_opt_asan.a // #cgo amd64,asan,dbg LDFLAGS: -l:amd64_entrypoint_init_aio_dbg_asan.a -l:amd64_k8_entrypoint_aio_prefixed_dbg_asan.a -l:amd64_nehalem_entrypoint_aio_prefixed_dbg_asan.a -l:amd64_haswell_entrypoint_aio_prefixed_dbg_asan.a -// #cgo !static LDFLAGS: -lstdc++ -lm -lgcc_eh -l:libunwind.a -llzma -lstdc++_libbacktrace -// #cgo static LDFLAGS: -static -static-libgcc -static-libstdc++ -l:libstdc++.a -l:libm.a -l:libgcc_eh.a -l:libunwind.a -l:liblzma.a -l:libstdc++_libbacktrace.a +// #cgo !static LDFLAGS: -lstdc++ -lm -lgcc_eh -l:libunwind.a -llzma -lstdc++exp +// #cgo static LDFLAGS: -static -static-libgcc -static-libstdc++ -l:libstdc++.a -l:libm.a -l:libgcc_eh.a -l:libunwind.a -l:liblzma.a -l:libstdc++exp.a // #include "entrypoint.h" import "C" //nolint:gocritic // because otherwise it won't work import ( diff --git a/pp/go/cppbridge/metrics_test.go b/pp/go/cppbridge/metrics_test.go index 78a9fa98aa..e215a590c6 100644 --- a/pp/go/cppbridge/metrics_test.go +++ b/pp/go/cppbridge/metrics_test.go @@ -1,6 +1,7 @@ package cppbridge import ( + "strings" "testing" "github.com/stretchr/testify/suite" @@ -14,9 +15,17 @@ func TestCppMetricsSuite(t *testing.T) { suite.Run(t, new(CppMetricsSuite)) } +// jemallocMetricDescPrefix matches the global jemalloc arena pool metrics that +// are registered in init() via prompp_metrics_register. They are unrelated to +// per-test metric pages and are filtered out of the suite's view of CppMetrics. +const jemallocMetricDescPrefix = `Desc{fqName: "prompp_common_jemalloc_` + func (s *CppMetricsSuite) getMetrics() []*CppMetric { metrics := []*CppMetric(nil) for metric := range CppMetrics { + if strings.HasPrefix(metric.descriptor.String(), jemallocMetricDescPrefix) { + continue + } metrics = append(metrics, metric) } diff --git a/pp/metrics/jemalloc_metrics.h b/pp/metrics/jemalloc_metrics.h index d037c9aed3..1a809f1630 100644 --- a/pp/metrics/jemalloc_metrics.h +++ b/pp/metrics/jemalloc_metrics.h @@ -3,6 +3,8 @@ #include "bare_bones/jemalloc.h" #include "metrics_page.h" +#if JEMALLOC_AVAILABLE + namespace metrics { struct JemallocMetrics final : MetricsPage { @@ -17,3 +19,5 @@ struct JemallocMetrics final : MetricsPage { }; } // namespace metrics + +#endif // JEMALLOC_AVAILABLE diff --git a/pp/primitives/go_metric.h b/pp/primitives/go_metric.h index 63104c6980..d327f94473 100644 --- a/pp/primitives/go_metric.h +++ b/pp/primitives/go_metric.h @@ -96,7 +96,7 @@ struct MetricDescriptor { for (const auto& label_pair : labels) { const_label_pairs.emplace_back(&label_pair); } - std::ranges::sort(const_label_pairs, [](const LabelPair* a, const LabelPair* b) { return a->name < b->name; }); + std::ranges::sort(const_label_pairs, [](const LabelPair* a, const LabelPair* b) { return *a->name < *b->name; }); } [[nodiscard]] PROMPP_ALWAYS_INLINE uint64_t calculate_id() const noexcept { diff --git a/pp/scripts/test_coredump.sh b/pp/scripts/test_coredump.sh index d1377b4777..7e7082eb8b 100755 --- a/pp/scripts/test_coredump.sh +++ b/pp/scripts/test_coredump.sh @@ -33,7 +33,7 @@ OLD_COREDUMP_USE_PID=0 SAVE_COREDUMP=1 SKIP_BUILD_TEST=0 TEST_TARGET_NAME=bare_bones_coredump_test -TEST_BUILD_COMMAND="bazel build --config=g++-13 $TEST_TARGET_NAME" +TEST_BUILD_COMMAND="bazel build --config=g++-14 $TEST_TARGET_NAME" TEST_BINARY=./bazel-bin/$TEST_TARGET_NAME eval set -- "${options}" diff --git a/pp/third_party/patches/quasis_crypto/0001-md5.hh.patch b/pp/third_party/patches/quasis_crypto/0001-md5.hh.patch index 043bec7310..d26b5c774c 100644 --- a/pp/third_party/patches/quasis_crypto/0001-md5.hh.patch +++ b/pp/third_party/patches/quasis_crypto/0001-md5.hh.patch @@ -1,17 +1,45 @@ --- a/md5.hh +++ b/md5.hh -@@ -36,6 +36,10 @@ +@@ -36,6 +36,11 @@ * Copyright 2022 Quasis - The MIT License */ +#pragma once + +#include ++#include + namespace crypto { template -@@ -180,7 +184,7 @@ namespace crypto { +@@ -154,22 +159,22 @@ + } + + template constexpr MD5& +- update(const input_type *input, size_type count) noexcept requires (__is_trivially_copyable(input_type)) { ++ update(const input_type *input, size_type count) noexcept requires (std::is_trivially_copyable_v) { + return update(reinterpret_cast(input), sizeof(input_type) * count); + } + + template constexpr MD5& +- update(const input_type (&input)[count]) noexcept requires (__is_trivially_copyable(input_type)) { ++ update(const input_type (&input)[count]) noexcept requires (std::is_trivially_copyable_v) { + return update(reinterpret_cast(input), sizeof(input_type) * count); + } + + template constexpr MD5& +- update(const input_type *begin, const input_type *end) noexcept requires (__is_trivially_copyable(input_type)) { ++ update(const input_type *begin, const input_type *end) noexcept requires (std::is_trivially_copyable_v) { + return update(reinterpret_cast(begin), sizeof(input_type) * (end - begin)); + } + + template constexpr MD5& +- update(const input_type &input) noexcept requires (__is_trivially_copyable(input_type)) { ++ update(const input_type &input) noexcept requires (std::is_trivially_copyable_v) { + return update(reinterpret_cast(&input), sizeof(input_type)); + } + +@@ -180,7 +185,7 @@ template constexpr MD5& update(const size_type count, input_type &&input) noexcept { @@ -20,7 +48,18 @@ } constexpr output_type -@@ -207,7 +211,7 @@ namespace crypto { +@@ -194,7 +199,10 @@ + auto factor = (length + sizeof(block_type) - 1) / sizeof(block_type); + + hasher.update(factor * sizeof(block_type) - length, uint8_type{0x00}); ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" + hasher.update(m_count << 3); ++#pragma GCC diagnostic pop + + return *reinterpret_cast(&hasher.m_state); + } +@@ -207,7 +215,7 @@ static constexpr uint32_type rotl(uint32_type value, int count) noexcept { @@ -29,7 +68,7 @@ } static constexpr word_type -@@ -323,35 +327,3 @@ namespace crypto { +@@ -323,35 +331,3 @@ return MD5().update(static_cast(input)...).digest(); } }