diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index 5e67a65..83fd607 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel
@@ -699,8 +699,9 @@ ], ) -cc_test( +cc_binary( name = "thread_identity_benchmark", + testonly = True, srcs = ["internal/thread_identity_benchmark.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, @@ -710,7 +711,6 @@ ":base", "//absl/synchronization", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], )
diff --git a/absl/base/internal/thread_identity_benchmark.cc b/absl/base/internal/thread_identity_benchmark.cc index 0ae10f2..419e82d 100644 --- a/absl/base/internal/thread_identity_benchmark.cc +++ b/absl/base/internal/thread_identity_benchmark.cc
@@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "benchmark/benchmark.h" #include "absl/base/internal/thread_identity.h" #include "absl/synchronization/internal/create_thread_identity.h" #include "absl/synchronization/internal/per_thread_sem.h" +#include "benchmark/benchmark.h" namespace {
diff --git a/absl/base/nullability.h b/absl/base/nullability.h index 37e910a..d11da57 100644 --- a/absl/base/nullability.h +++ b/absl/base/nullability.h
@@ -220,7 +220,8 @@ // No-op except for being a human readable signal. #define ABSL_POINTERS_DEFAULT_NONNULL -#if defined(__clang__) && !defined(__OBJC__) +#if defined(__clang__) && !defined(__OBJC__) && \ + ABSL_HAVE_FEATURE(nullability_on_classes) // absl_nonnull (default with `ABSL_POINTERS_DEFAULT_NONNULL`) // // The indicated pointer is never null. It is the responsibility of the provider
diff --git a/absl/base/nullability_test.cc b/absl/base/nullability_test.cc index 028ea6c..b4a22e8 100644 --- a/absl/base/nullability_test.cc +++ b/absl/base/nullability_test.cc
@@ -16,15 +16,85 @@ #include <cassert> #include <memory> +#include <type_traits> #include <utility> #include "gtest/gtest.h" -#include "absl/base/attributes.h" namespace { +namespace macro_annotations { +void funcWithNonnullArg(int* absl_nonnull /*arg*/) {} +template <typename T> +void funcWithDeducedNonnullArg(T* absl_nonnull /*arg*/) {} + +TEST(NonnullTest, NonnullArgument) { + int var = 0; + funcWithNonnullArg(&var); + funcWithDeducedNonnullArg(&var); +} + +int* absl_nonnull funcWithNonnullReturn() { + static int var = 0; + return &var; +} + +TEST(NonnullTest, NonnullReturn) { + auto var = funcWithNonnullReturn(); + (void)var; +} + +TEST(PassThroughTest, PassesThroughRawPointerToInt) { + EXPECT_TRUE((std::is_same<int* absl_nonnull, int*>::value)); + EXPECT_TRUE((std::is_same<int* absl_nullable, int*>::value)); + EXPECT_TRUE((std::is_same<int* absl_nullability_unknown, int*>::value)); +} + +TEST(PassThroughTest, PassesThroughRawPointerToVoid) { + EXPECT_TRUE((std::is_same<void* absl_nonnull, void*>::value)); + EXPECT_TRUE((std::is_same<void* absl_nullable, void*>::value)); + EXPECT_TRUE((std::is_same<void* absl_nullability_unknown, void*>::value)); +} + +TEST(PassThroughTest, PassesThroughUniquePointerToInt) { + using T = std::unique_ptr<int>; + EXPECT_TRUE((std::is_same<absl_nonnull T, T>::value)); + EXPECT_TRUE((std::is_same<absl_nullable T, T>::value)); + EXPECT_TRUE((std::is_same<absl_nullability_unknown T, T>::value)); +} + +TEST(PassThroughTest, PassesThroughSharedPointerToInt) { + using T = std::shared_ptr<int>; + EXPECT_TRUE((std::is_same<absl_nonnull T, T>::value)); + EXPECT_TRUE((std::is_same<absl_nullable T, T>::value)); + EXPECT_TRUE((std::is_same<absl_nullability_unknown T, T>::value)); +} + +TEST(PassThroughTest, PassesThroughSharedPointerToVoid) { + using T = std::shared_ptr<void>; + EXPECT_TRUE((std::is_same<absl_nonnull T, T>::value)); + EXPECT_TRUE((std::is_same<absl_nullable T, T>::value)); + EXPECT_TRUE((std::is_same<absl_nullability_unknown T, T>::value)); +} + +TEST(PassThroughTest, PassesThroughPointerToMemberObject) { + using T = decltype(&std::pair<int, int>::first); + EXPECT_TRUE((std::is_same<absl_nonnull T, T>::value)); + EXPECT_TRUE((std::is_same<absl_nullable T, T>::value)); + EXPECT_TRUE((std::is_same<absl_nullability_unknown T, T>::value)); +} + +TEST(PassThroughTest, PassesThroughPointerToMemberFunction) { + using T = decltype(&std::unique_ptr<int>::reset); + EXPECT_TRUE((std::is_same<absl_nonnull T, T>::value)); + EXPECT_TRUE((std::is_same<absl_nullable T, T>::value)); + EXPECT_TRUE((std::is_same<absl_nullability_unknown T, T>::value)); +} +} // namespace macro_annotations + using ::absl::Nonnull; using ::absl::NullabilityUnknown; using ::absl::Nullable; +namespace type_alias_annotations { void funcWithNonnullArg(Nonnull<int*> /*arg*/) {} template <typename T> @@ -93,6 +163,7 @@ EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value)); } +} // namespace type_alias_annotations } // namespace // Nullable ADL lookup test
diff --git a/absl/cleanup/internal/cleanup.h b/absl/cleanup/internal/cleanup.h index 967513a..4dd6f91 100644 --- a/absl/cleanup/internal/cleanup.h +++ b/absl/cleanup/internal/cleanup.h
@@ -88,7 +88,7 @@ private: bool is_callback_engaged_; - alignas(Callback) char callback_buffer_[sizeof(Callback)]; + alignas(Callback) unsigned char callback_buffer_[sizeof(Callback)]; }; } // namespace cleanup_internal
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel index 37b5f2a..ccaed1c 100644 --- a/absl/container/BUILD.bazel +++ b/absl/container/BUILD.bazel
@@ -1148,6 +1148,5 @@ "//absl/strings:str_format", "//absl/time", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], )
diff --git a/absl/container/btree_benchmark.cc b/absl/container/btree_benchmark.cc index b1525bd..ee4efbd 100644 --- a/absl/container/btree_benchmark.cc +++ b/absl/container/btree_benchmark.cc
@@ -26,7 +26,6 @@ #include <unordered_set> #include <vector> -#include "benchmark/benchmark.h" #include "absl/algorithm/container.h" #include "absl/base/internal/raw_logging.h" #include "absl/container/btree_map.h" @@ -42,6 +41,7 @@ #include "absl/strings/cord.h" #include "absl/strings/str_format.h" #include "absl/time/time.h" +#include "benchmark/benchmark.h" namespace absl { ABSL_NAMESPACE_BEGIN
diff --git a/absl/container/fixed_array.h b/absl/container/fixed_array.h index b213eb1..8bf8e6c 100644 --- a/absl/container/fixed_array.h +++ b/absl/container/fixed_array.h
@@ -447,7 +447,8 @@ private: ABSL_ADDRESS_SANITIZER_REDZONE(redzone_begin_); - alignas(StorageElement) char buff_[sizeof(StorageElement[inline_elements])]; + alignas(StorageElement) unsigned char buff_[sizeof( + StorageElement[inline_elements])]; ABSL_ADDRESS_SANITIZER_REDZONE(redzone_end_); };
diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h index a3b14a2..b0d3f07 100644 --- a/absl/container/internal/inlined_vector.h +++ b/absl/container/internal/inlined_vector.h
@@ -543,7 +543,7 @@ (std::max)(N, sizeof(Allocated) / sizeof(ValueType<A>)); struct Inlined { - alignas(ValueType<A>) char inlined_data[sizeof( + alignas(ValueType<A>) unsigned char inlined_data[sizeof( ValueType<A>[kOptimalInlinedSize])]; };
diff --git a/absl/crc/crc32c_benchmark.cc b/absl/crc/crc32c_benchmark.cc index 3b46ef3..d7cecc3 100644 --- a/absl/crc/crc32c_benchmark.cc +++ b/absl/crc/crc32c_benchmark.cc
@@ -40,7 +40,13 @@ benchmark::DoNotOptimize(crc); } } -BENCHMARK(BM_Calculate)->Arg(0)->Arg(1)->Arg(100)->Arg(10000)->Arg(500000); +BENCHMARK(BM_Calculate) + ->Arg(0) + ->Arg(1) + ->Arg(100) + ->Arg(2048) + ->Arg(10000) + ->Arg(500000); void BM_Extend(benchmark::State& state) { int len = state.range(0); @@ -53,8 +59,14 @@ benchmark::DoNotOptimize(crc); } } -BENCHMARK(BM_Extend)->Arg(0)->Arg(1)->Arg(100)->Arg(10000)->Arg(500000)->Arg( - 100 * 1000 * 1000); +BENCHMARK(BM_Extend) + ->Arg(0) + ->Arg(1) + ->Arg(100) + ->Arg(2048) + ->Arg(10000) + ->Arg(500000) + ->Arg(100 * 1000 * 1000); // Make working set >> CPU cache size to benchmark prefetches better void BM_ExtendCacheMiss(benchmark::State& state) { @@ -147,7 +159,8 @@ state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * state.range(0)); } -BENCHMARK(BM_Memcpy)->Arg(0)->Arg(1)->Arg(100)->Arg(10000)->Arg(500000); +BENCHMARK(BM_Memcpy)->Arg(0)->Arg(1)->Arg(100)->Arg(2048)->Arg(10000)->Arg( + 500000); void BM_RemoveSuffix(benchmark::State& state) { int full_string_len = state.range(0);
diff --git a/absl/crc/internal/crc32_x86_arm_combined_simd.h b/absl/crc/internal/crc32_x86_arm_combined_simd.h index 0f6e347..5a9b61a 100644 --- a/absl/crc/internal/crc32_x86_arm_combined_simd.h +++ b/absl/crc/internal/crc32_x86_arm_combined_simd.h
@@ -99,19 +99,12 @@ // Produces a XOR operation of |l| and |r|. V128 V128_Xor(const V128 l, const V128 r); -// Produces an AND operation of |l| and |r|. -V128 V128_And(const V128 l, const V128 r); - // Sets the lower half of a 128 bit register to the given 64-bit value and // zeroes the upper half. // dst[63:0] := |r| // dst[127:64] := |0| V128 V128_From64WithZeroFill(const uint64_t r); -// Shift |l| right by |imm| bytes while shifting in zeros. -template <int imm> -V128 V128_ShiftRight(const V128 l); - // Extracts a 32-bit integer from |l|, selected with |imm|. template <int imm> int V128_Extract32(const V128 l); @@ -170,18 +163,11 @@ inline V128 V128_Xor(const V128 l, const V128 r) { return _mm_xor_si128(l, r); } -inline V128 V128_And(const V128 l, const V128 r) { return _mm_and_si128(l, r); } - inline V128 V128_From64WithZeroFill(const uint64_t r) { return _mm_set_epi64x(static_cast<int64_t>(0), static_cast<int64_t>(r)); } template <int imm> -inline V128 V128_ShiftRight(const V128 l) { - return _mm_srli_si128(l, imm); -} - -template <int imm> inline int V128_Extract32(const V128 l) { return _mm_extract_epi32(l, imm); } @@ -261,8 +247,6 @@ inline V128 V128_Xor(const V128 l, const V128 r) { return veorq_u64(l, r); } -inline V128 V128_And(const V128 l, const V128 r) { return vandq_u64(l, r); } - inline V128 V128_From64WithZeroFill(const uint64_t r){ constexpr uint64x2_t kZero = {0, 0}; return vsetq_lane_u64(r, kZero, 0); @@ -270,12 +254,6 @@ template <int imm> -inline V128 V128_ShiftRight(const V128 l) { - return vreinterpretq_u64_s8( - vextq_s8(vreinterpretq_s8_u64(l), vdupq_n_s8(0), imm)); -} - -template <int imm> inline int V128_Extract32(const V128 l) { return vgetq_lane_s32(vreinterpretq_s32_u64(l), imm); }
diff --git a/absl/crc/internal/crc_x86_arm_combined.cc b/absl/crc/internal/crc_x86_arm_combined.cc index 9817c73..3194bec 100644 --- a/absl/crc/internal/crc_x86_arm_combined.cc +++ b/absl/crc/internal/crc_x86_arm_combined.cc
@@ -221,7 +221,8 @@ // We are applying it to CRC32C polynomial. ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesPclmul( const uint8_t* p, V128* partialCRC) const { - V128 loopMultiplicands = V128_Load(reinterpret_cast<const V128*>(k1k2)); + V128 loopMultiplicands = + V128_Load(reinterpret_cast<const V128*>(kFoldAcross512Bits)); V128 partialCRC1 = partialCRC[0]; V128 partialCRC2 = partialCRC[1]; @@ -265,53 +266,33 @@ // Combine 4 vectors of partial crc into a single vector. V128 reductionMultiplicands = - V128_Load(reinterpret_cast<const V128*>(k5k6)); + V128_Load(reinterpret_cast<const V128*>(kFoldAcross256Bits)); V128 low = V128_PMulLow(reductionMultiplicands, partialCRC1); V128 high = V128_PMulHi(reductionMultiplicands, partialCRC1); partialCRC1 = V128_Xor(low, high); - partialCRC1 = V128_Xor(partialCRC1, partialCRC2); + partialCRC1 = V128_Xor(partialCRC1, partialCRC3); - low = V128_PMulLow(reductionMultiplicands, partialCRC3); - high = V128_PMulHi(reductionMultiplicands, partialCRC3); + low = V128_PMulLow(reductionMultiplicands, partialCRC2); + high = V128_PMulHi(reductionMultiplicands, partialCRC2); - partialCRC3 = V128_Xor(low, high); - partialCRC3 = V128_Xor(partialCRC3, partialCRC4); + partialCRC2 = V128_Xor(low, high); + partialCRC2 = V128_Xor(partialCRC2, partialCRC4); - reductionMultiplicands = V128_Load(reinterpret_cast<const V128*>(k3k4)); + reductionMultiplicands = + V128_Load(reinterpret_cast<const V128*>(kFoldAcross128Bits)); low = V128_PMulLow(reductionMultiplicands, partialCRC1); high = V128_PMulHi(reductionMultiplicands, partialCRC1); V128 fullCRC = V128_Xor(low, high); - fullCRC = V128_Xor(fullCRC, partialCRC3); + fullCRC = V128_Xor(fullCRC, partialCRC2); // Reduce fullCRC into scalar value. - reductionMultiplicands = V128_Load(reinterpret_cast<const V128*>(k5k6)); - - V128 mask = V128_Load(reinterpret_cast<const V128*>(kMask)); - - V128 tmp = V128_PMul01(reductionMultiplicands, fullCRC); - fullCRC = V128_ShiftRight<8>(fullCRC); - fullCRC = V128_Xor(fullCRC, tmp); - - reductionMultiplicands = V128_Load(reinterpret_cast<const V128*>(k7k0)); - - tmp = V128_ShiftRight<4>(fullCRC); - fullCRC = V128_And(fullCRC, mask); - fullCRC = V128_PMulLow(reductionMultiplicands, fullCRC); - fullCRC = V128_Xor(tmp, fullCRC); - - reductionMultiplicands = V128_Load(reinterpret_cast<const V128*>(kPoly)); - - tmp = V128_And(fullCRC, mask); - tmp = V128_PMul01(reductionMultiplicands, tmp); - tmp = V128_And(tmp, mask); - tmp = V128_PMulLow(reductionMultiplicands, tmp); - - fullCRC = V128_Xor(tmp, fullCRC); - - return static_cast<uint64_t>(V128_Extract32<1>(fullCRC)); + uint32_t crc = 0; + crc = CRC32_u64(crc, V128_Extract64<0>(fullCRC)); + crc = CRC32_u64(crc, V128_Extract64<1>(fullCRC)); + return crc; } // Update crc with 64 bytes of data from p. @@ -325,15 +306,23 @@ return crc; } - // Generated by crc32c_x86_test --crc32c_generate_constants=true - // and verified against constants in linux kernel for S390: - // https://github.com/torvalds/linux/blob/master/arch/s390/crypto/crc32le-vx.S - alignas(16) static constexpr uint64_t k1k2[2] = {0x0740eef02, 0x09e4addf8}; - alignas(16) static constexpr uint64_t k3k4[2] = {0x1384aa63a, 0x0ba4fc28e}; - alignas(16) static constexpr uint64_t k5k6[2] = {0x0f20c0dfe, 0x14cd00bd6}; - alignas(16) static constexpr uint64_t k7k0[2] = {0x0dd45aab8, 0x000000000}; - alignas(16) static constexpr uint64_t kPoly[2] = {0x105ec76f0, 0x0dea713f1}; - alignas(16) static constexpr uint32_t kMask[4] = {~0u, 0u, ~0u, 0u}; + // Constants generated by './scripts/gen-crc-consts.py x86_pclmul + // crc32_lsb_0x82f63b78' from the Linux kernel. + alignas(16) static constexpr uint64_t kFoldAcross512Bits[2] = { + // (x^543 mod G) * x^32 + 0x00000000740eef02, + // (x^479 mod G) * x^32 + 0x000000009e4addf8}; + alignas(16) static constexpr uint64_t kFoldAcross256Bits[2] = { + // (x^287 mod G) * x^32 + 0x000000003da6d0cb, + // (x^223 mod G) * x^32 + 0x00000000ba4fc28e}; + alignas(16) static constexpr uint64_t kFoldAcross128Bits[2] = { + // (x^159 mod G) * x^32 + 0x00000000f20c0dfe, + // (x^95 mod G) * x^32 + 0x00000000493c7d27}; // Medium runs of bytes are broken into groups of kGroupsSmall blocks of same // size. Each group is CRCed in parallel then combined at the end of the
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel index 01d3230..cd0f1de 100644 --- a/absl/debugging/BUILD.bazel +++ b/absl/debugging/BUILD.bazel
@@ -66,7 +66,9 @@ linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":stacktrace", + "//absl/base:config", "//absl/base:core_headers", + "//absl/types:span", "@googletest//:gtest", "@googletest//:gtest_main", ],
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt index 30eeb5b..60b138a 100644 --- a/absl/debugging/CMakeLists.txt +++ b/absl/debugging/CMakeLists.txt
@@ -55,7 +55,9 @@ ${ABSL_TEST_COPTS} DEPS absl::stacktrace + absl::config absl::core_headers + absl::span GTest::gmock_main )
diff --git a/absl/debugging/internal/addresses.h b/absl/debugging/internal/addresses.h index e40c54e..504fd6f 100644 --- a/absl/debugging/internal/addresses.h +++ b/absl/debugging/internal/addresses.h
@@ -25,14 +25,14 @@ // Removes any metadata (tag bits) from the given pointer, converting it into a // user-readable address. -inline uintptr_t StripPointerMetadata(void* ptr) { +inline uintptr_t StripPointerMetadata(uintptr_t ptr) { #if defined(__aarch64__) // When PAC-RET (-mbranch-protection=pac-ret) is enabled, return addresses // stored on the stack will be signed, which means that pointer bits outside // of the virtual address range are potentially set. Since the stacktrace code // is expected to return normal code pointers, this function clears those // bits. - register uintptr_t x30 __asm__("x30") = reinterpret_cast<uintptr_t>(ptr); + register uintptr_t x30 __asm__("x30") = ptr; // The normal instruction for clearing PAC bits is XPACI, but for // compatibility with ARM platforms that do not support pointer // authentication, we use the hint space instruction XPACLRI instead. Hint @@ -42,10 +42,14 @@ #undef ABSL_XPACLRI_HINT return x30; #else - return reinterpret_cast<uintptr_t>(ptr); + return ptr; #endif } +inline uintptr_t StripPointerMetadata(void* ptr) { + return StripPointerMetadata(reinterpret_cast<uintptr_t>(ptr)); +} + } // namespace debugging_internal ABSL_NAMESPACE_END } // namespace absl
diff --git a/absl/debugging/internal/stacktrace_aarch64-inl.inc b/absl/debugging/internal/stacktrace_aarch64-inl.inc index baea9a8..d1f67f1 100644 --- a/absl/debugging/internal/stacktrace_aarch64-inl.inc +++ b/absl/debugging/internal/stacktrace_aarch64-inl.inc
@@ -185,8 +185,9 @@ ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. -static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, - const void *ucp, int *min_dropped_frames) { +static int UnwindImpl(void **result, uintptr_t *frames, int *sizes, + int max_depth, int skip_count, const void *ucp, + int *min_dropped_frames) { #ifdef __GNUC__ void **frame_pointer = reinterpret_cast<void**>(__builtin_frame_address(0)); #else @@ -223,8 +224,15 @@ result[n] = reinterpret_cast<void *>( absl::debugging_internal::StripPointerMetadata(prev_return_address)); if (IS_STACK_FRAMES) { - sizes[n] = static_cast<int>( - ComputeStackFrameSize(prev_frame_pointer, frame_pointer)); + if (frames != nullptr) { + frames[n] = absl::debugging_internal::StripPointerMetadata( + prev_frame_pointer) + + 2 * sizeof(void *) /* go past the return address */; + } + if (sizes != nullptr) { + sizes[n] = static_cast<int>( + ComputeStackFrameSize(prev_frame_pointer, frame_pointer)); + } } n++; }
diff --git a/absl/debugging/internal/stacktrace_arm-inl.inc b/absl/debugging/internal/stacktrace_arm-inl.inc index 102a2a1..3feb521 100644 --- a/absl/debugging/internal/stacktrace_arm-inl.inc +++ b/absl/debugging/internal/stacktrace_arm-inl.inc
@@ -19,6 +19,7 @@ #include <cstdint> +#include "absl/debugging/internal/addresses.h" #include "absl/debugging/stacktrace.h" // WARNING: @@ -67,8 +68,9 @@ #endif template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> -static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, - const void * /* ucp */, int *min_dropped_frames) { +static int UnwindImpl(void **result, uintptr_t *frames, int *sizes, + int max_depth, int skip_count, const void * /* ucp */, + int *min_dropped_frames) { #ifdef __GNUC__ void **sp = reinterpret_cast<void**>(__builtin_frame_address(0)); #else @@ -97,11 +99,18 @@ result[n] = *sp; if (IS_STACK_FRAMES) { - if (next_sp > sp) { - sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp; - } else { - // A frame-size of 0 is used to indicate unknown frame size. - sizes[n] = 0; + if (frames != nullptr) { + frames[n] = absl::debugging_internal::StripPointerMetadata(sp) + + 1 * sizeof(void *) /* go past the return address */; + } + if (sizes != nullptr) { + if (next_sp > sp) { + sizes[n] = absl::debugging_internal::StripPointerMetadata(next_sp) - + absl::debugging_internal::StripPointerMetadata(sp); + } else { + // A frame-size of 0 is used to indicate unknown frame size. + sizes[n] = 0; + } } } n++;
diff --git a/absl/debugging/internal/stacktrace_emscripten-inl.inc b/absl/debugging/internal/stacktrace_emscripten-inl.inc index 0f44451..6689300 100644 --- a/absl/debugging/internal/stacktrace_emscripten-inl.inc +++ b/absl/debugging/internal/stacktrace_emscripten-inl.inc
@@ -21,6 +21,7 @@ #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_EMSCRIPTEN_INL_H_ #include <emscripten.h> +#include <stdint.h> #include <atomic> #include <cstring> @@ -62,8 +63,9 @@ }(); template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> -static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, - const void *ucp, int *min_dropped_frames) { +static int UnwindImpl(void **result, uintptr_t *frames, int *sizes, + int max_depth, int skip_count, const void *ucp, + int *min_dropped_frames) { if (recursive || disable_stacktraces.load(std::memory_order_relaxed)) { return 0; } @@ -83,8 +85,13 @@ for (int i = 0; i < result_count; i++) result[i] = stack[i + skip_count]; if (IS_STACK_FRAMES) { - // No implementation for finding out the stack frame sizes yet. - memset(sizes, 0, sizeof(*sizes) * result_count); + // No implementation for finding out the stack frames yet. + if (frames != nullptr) { + memset(frames, 0, sizeof(*frames) * result_count); + } + if (sizes != nullptr) { + memset(sizes, 0, sizeof(*sizes) * result_count); + } } if (min_dropped_frames != nullptr) { if (size - skip_count - max_depth > 0) {
diff --git a/absl/debugging/internal/stacktrace_generic-inl.inc b/absl/debugging/internal/stacktrace_generic-inl.inc index 5fa169a..e7a11fc 100644 --- a/absl/debugging/internal/stacktrace_generic-inl.inc +++ b/absl/debugging/internal/stacktrace_generic-inl.inc
@@ -56,8 +56,9 @@ }(); template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> -static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, - const void *ucp, int *min_dropped_frames) { +static int UnwindImpl(void** result, uintptr_t* frames, int* sizes, + int max_depth, int skip_count, const void* ucp, + int* min_dropped_frames) { if (recursive || disable_stacktraces.load(std::memory_order_relaxed)) { return 0; } @@ -79,8 +80,13 @@ result[i] = stack[i + skip_count]; if (IS_STACK_FRAMES) { - // No implementation for finding out the stack frame sizes yet. - memset(sizes, 0, sizeof(*sizes) * static_cast<size_t>(result_count)); + // No implementation for finding out the stack frames yet. + if (frames != nullptr) { + memset(frames, 0, sizeof(*frames) * static_cast<size_t>(result_count)); + } + if (sizes != nullptr) { + memset(sizes, 0, sizeof(*sizes) * static_cast<size_t>(result_count)); + } } if (min_dropped_frames != nullptr) { if (size - skip_count - max_depth > 0) {
diff --git a/absl/debugging/internal/stacktrace_powerpc-inl.inc b/absl/debugging/internal/stacktrace_powerpc-inl.inc index a49ed2f..b84782b 100644 --- a/absl/debugging/internal/stacktrace_powerpc-inl.inc +++ b/absl/debugging/internal/stacktrace_powerpc-inl.inc
@@ -21,6 +21,7 @@ #ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_ #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_ +#include "absl/debugging/internal/addresses.h" #if defined(__linux__) #include <asm/ptrace.h> // for PT_NIP. #include <ucontext.h> // for ucontext_t @@ -40,22 +41,22 @@ // Given a stack pointer, return the saved link register value. // Note that this is the link register for a callee. -static inline void *StacktracePowerPCGetLR(void **sp) { +static inline void **StacktracePowerPCGetLRPtr(void **sp) { // PowerPC has 3 main ABIs, which say where in the stack the // Link Register is. For DARWIN and AIX (used by apple and // linux ppc64), it's in sp[2]. For SYSV (used by linux ppc), // it's in sp[1]. #if defined(_CALL_AIX) || defined(_CALL_DARWIN) - return *(sp+2); + return (sp + 2); #elif defined(_CALL_SYSV) - return *(sp+1); + return (sp + 1); #elif defined(__APPLE__) || defined(__FreeBSD__) || \ (defined(__linux__) && defined(__PPC64__)) // This check is in case the compiler doesn't define _CALL_AIX/etc. - return *(sp+2); + return (sp + 2); #elif defined(__linux) // This check is in case the compiler doesn't define _CALL_SYSV. - return *(sp+1); + return (sp + 1); #else #error Need to specify the PPC ABI for your architecture. #endif @@ -125,9 +126,8 @@ } } - if (new_sp != nullptr && - kernel_symbol_status == kAddressValid && - StacktracePowerPCGetLR(new_sp) == kernel_sigtramp_rt64_address) { + if (new_sp != nullptr && kernel_symbol_status == kAddressValid && + *StacktracePowerPCGetLRPtr(new_sp) == kernel_sigtramp_rt64_address) { const ucontext_t* signal_context = reinterpret_cast<const ucontext_t*>(uc); void **const sp_before_signal = @@ -164,8 +164,9 @@ template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. -static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, - const void *ucp, int *min_dropped_frames) { +static int UnwindImpl(void **result, uintptr_t *frames, int *sizes, + int max_depth, int skip_count, const void *ucp, + int *min_dropped_frames) { void **sp; // Apple macOS uses an old version of gnu as -- both Darwin 7.9.0 (Panther) // and Darwin 8.8.1 (Tiger) use as 1.38. This means we have to use a @@ -211,13 +212,21 @@ if (skip_count > 0) { skip_count--; } else { - result[n] = StacktracePowerPCGetLR(sp); + void **lr = StacktracePowerPCGetLRPtr(sp); + result[n] = *lr; if (IS_STACK_FRAMES) { - if (next_sp > sp) { - sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp; - } else { - // A frame-size of 0 is used to indicate unknown frame size. - sizes[n] = 0; + if (frames != nullptr) { + frames[n] = absl::debugging_internal::StripPointerMetadata(lr) + + 1 * sizeof(void *) /* go past the return address */; + } + if (sizes != nullptr) { + if (next_sp > sp) { + sizes[n] = absl::debugging_internal::StripPointerMetadata(next_sp) - + absl::debugging_internal::StripPointerMetadata(sp); + } else { + // A frame-size of 0 is used to indicate unknown frame size. + sizes[n] = 0; + } } } n++;
diff --git a/absl/debugging/internal/stacktrace_riscv-inl.inc b/absl/debugging/internal/stacktrace_riscv-inl.inc index 3f9e124..59f2913 100644 --- a/absl/debugging/internal/stacktrace_riscv-inl.inc +++ b/absl/debugging/internal/stacktrace_riscv-inl.inc
@@ -20,6 +20,7 @@ #include <sys/ucontext.h> #include "absl/base/config.h" +#include "absl/debugging/internal/addresses.h" #if defined(__linux__) #include <sys/mman.h> #include <ucontext.h> @@ -117,8 +118,9 @@ template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. -static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, - const void *ucp, int *min_dropped_frames) { +static int UnwindImpl(void **result, uintptr_t *frames, int *sizes, + int max_depth, int skip_count, const void *ucp, + int *min_dropped_frames) { // The `frame_pointer` that is computed here points to the top of the frame. // The two words preceding the address are the return address and the previous // frame pointer. @@ -153,8 +155,13 @@ result[n] = return_address; if (IS_STACK_FRAMES) { // NextStackFrame() has already checked that frame size fits to int - sizes[n] = static_cast<int>(ComputeStackFrameSize(frame_pointer, - next_frame_pointer)); + if (frames != nullptr) { + frames[n] = + absl::debugging_internal::StripPointerMetadata(frame_pointer); + } + if (sizes != nullptr) { + sizes[n] = ComputeStackFrameSize(frame_pointer, next_frame_pointer); + } } n++; }
diff --git a/absl/debugging/internal/stacktrace_unimplemented-inl.inc b/absl/debugging/internal/stacktrace_unimplemented-inl.inc index 5b8fb19..ec63940 100644 --- a/absl/debugging/internal/stacktrace_unimplemented-inl.inc +++ b/absl/debugging/internal/stacktrace_unimplemented-inl.inc
@@ -2,9 +2,10 @@ #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_UNIMPLEMENTED_INL_H_ template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> -static int UnwindImpl(void** /* result */, int* /* sizes */, - int /* max_depth */, int /* skip_count */, - const void* /* ucp */, int *min_dropped_frames) { +static int UnwindImpl(void** /* result */, uintptr_t* /* frames */, + int* /* sizes */, int /* max_depth */, + int /* skip_count */, const void* /* ucp */, + int* min_dropped_frames) { if (min_dropped_frames != nullptr) { *min_dropped_frames = 0; }
diff --git a/absl/debugging/internal/stacktrace_win32-inl.inc b/absl/debugging/internal/stacktrace_win32-inl.inc index ef2b973..513a392 100644 --- a/absl/debugging/internal/stacktrace_win32-inl.inc +++ b/absl/debugging/internal/stacktrace_win32-inl.inc
@@ -61,8 +61,9 @@ #endif // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> -static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, - const void*, int* min_dropped_frames) { +static int UnwindImpl(void** result, uintptr_t* frames, int* sizes, + int max_depth, int skip_count, const void*, + int* min_dropped_frames) { USHORT n = 0; if (!RtlCaptureStackBackTrace_fn || skip_count < 0 || max_depth < 0) { // can't get a stacktrace with no function/invalid args @@ -71,8 +72,13 @@ static_cast<ULONG>(max_depth), result, 0); } if (IS_STACK_FRAMES) { - // No implementation for finding out the stack frame sizes yet. - memset(sizes, 0, sizeof(*sizes) * n); + // No implementation for finding out the stack frames yet. + if (frames != nullptr) { + memset(frames, 0, sizeof(*frames) * n); + } + if (sizes != nullptr) { + memset(sizes, 0, sizeof(*sizes) * n); + } } if (min_dropped_frames != nullptr) { // Not implemented.
diff --git a/absl/debugging/internal/stacktrace_x86-inl.inc b/absl/debugging/internal/stacktrace_x86-inl.inc index 1975ba7..2662dab 100644 --- a/absl/debugging/internal/stacktrace_x86-inl.inc +++ b/absl/debugging/internal/stacktrace_x86-inl.inc
@@ -33,6 +33,7 @@ #include "absl/base/macros.h" #include "absl/base/port.h" #include "absl/debugging/internal/address_is_readable.h" +#include "absl/debugging/internal/addresses.h" #include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems #include "absl/debugging/stacktrace.h" @@ -327,8 +328,9 @@ ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. ABSL_ATTRIBUTE_NOINLINE -static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, - const void *ucp, int *min_dropped_frames) { +static int UnwindImpl(void **result, uintptr_t *frames, int *sizes, + int max_depth, int skip_count, const void *ucp, + int *min_dropped_frames) { int n = 0; void **fp = reinterpret_cast<void **>(__builtin_frame_address(0)); @@ -349,13 +351,19 @@ } else { result[n] = *(fp + 1); if (IS_STACK_FRAMES) { - if (next_fp > fp) { - sizes[n] = static_cast<int>( - reinterpret_cast<uintptr_t>(next_fp) - - reinterpret_cast<uintptr_t>(fp)); - } else { - // A frame-size of 0 is used to indicate unknown frame size. - sizes[n] = 0; + if (frames) { + frames[n] = absl::debugging_internal::StripPointerMetadata(fp) + + 2 * sizeof(void *) /* go past the return address */; + } + if (sizes) { + if (next_fp > fp) { + sizes[n] = static_cast<int>( + absl::debugging_internal::StripPointerMetadata(next_fp) - + absl::debugging_internal::StripPointerMetadata(fp)); + } else { + // A frame-size of 0 is used to indicate unknown frame size. + sizes[n] = 0; + } } } n++;
diff --git a/absl/debugging/stacktrace.cc b/absl/debugging/stacktrace.cc index ff8069f..d8ad0e6 100644 --- a/absl/debugging/stacktrace.cc +++ b/absl/debugging/stacktrace.cc
@@ -36,9 +36,14 @@ #include "absl/debugging/stacktrace.h" +#include <stdint.h> + +#include <algorithm> #include <atomic> #include "absl/base/attributes.h" +#include "absl/base/config.h" +#include "absl/base/optimization.h" #include "absl/base/port.h" #include "absl/debugging/internal/stacktrace_config.h" @@ -66,59 +71,68 @@ std::atomic<Unwinder> custom; template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> -ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, int* sizes, - int max_depth, int skip_count, - const void* uc, +ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, uintptr_t* frames, + int* sizes, int max_depth, + int skip_count, const void* uc, int* min_dropped_frames) { - Unwinder f = &UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>; Unwinder g = custom.load(std::memory_order_acquire); - if (g != nullptr) f = g; - + int size; // Add 1 to skip count for the unwinder function itself - int size = (*f)(result, sizes, max_depth, skip_count + 1, uc, - min_dropped_frames); - // To disable tail call to (*f)(...) + ++skip_count; + if (g != nullptr) { + size = (*g)(result, sizes, max_depth, skip_count, uc, min_dropped_frames); + // Frame pointers aren't returned by existing hooks, so clear them. + if (frames != nullptr) { + std::fill(frames, frames + size, uintptr_t()); + } + } else { + size = UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>( + result, frames, sizes, max_depth, skip_count, uc, min_dropped_frames); + } ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); return size; } } // anonymous namespace -ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackFrames( - void** result, int* sizes, int max_depth, int skip_count) { - return Unwind<true, false>(result, sizes, max_depth, skip_count, nullptr, - nullptr); +ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int +internal_stacktrace::GetStackFrames(void** result, uintptr_t* frames, + int* sizes, int max_depth, int skip_count) { + return Unwind<true, false>(result, frames, sizes, max_depth, skip_count, + nullptr, nullptr); } ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int -GetStackFramesWithContext(void** result, int* sizes, int max_depth, - int skip_count, const void* uc, - int* min_dropped_frames) { - return Unwind<true, true>(result, sizes, max_depth, skip_count, uc, +internal_stacktrace::GetStackFramesWithContext(void** result, uintptr_t* frames, + int* sizes, int max_depth, + int skip_count, const void* uc, + int* min_dropped_frames) { + return Unwind<true, true>(result, frames, sizes, max_depth, skip_count, uc, min_dropped_frames); } ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackTrace( void** result, int max_depth, int skip_count) { - return Unwind<false, false>(result, nullptr, max_depth, skip_count, nullptr, - nullptr); + return Unwind<false, false>(result, nullptr, nullptr, max_depth, skip_count, + nullptr, nullptr); } ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackTraceWithContext(void** result, int max_depth, int skip_count, const void* uc, int* min_dropped_frames) { - return Unwind<false, true>(result, nullptr, max_depth, skip_count, uc, - min_dropped_frames); + return Unwind<false, true>(result, nullptr, nullptr, max_depth, skip_count, + uc, min_dropped_frames); } void SetStackUnwinder(Unwinder w) { custom.store(w, std::memory_order_release); } -int DefaultStackUnwinder(void** pcs, int* sizes, int depth, int skip, - const void* uc, int* min_dropped_frames) { +ABSL_ATTRIBUTE_ALWAYS_INLINE static inline int DefaultStackUnwinderImpl( + void** pcs, uintptr_t* frames, int* sizes, int depth, int skip, + const void* uc, int* min_dropped_frames) { skip++; // For this function - Unwinder f = nullptr; + decltype(&UnwindImpl<false, false>) f; if (sizes == nullptr) { if (uc == nullptr) { f = &UnwindImpl<false, false>; @@ -132,9 +146,26 @@ f = &UnwindImpl<true, true>; } } - volatile int x = 0; - int n = (*f)(pcs, sizes, depth, skip, uc, min_dropped_frames); - x = 1; (void) x; // To disable tail call to (*f)(...) + return (*f)(pcs, frames, sizes, depth, skip, uc, min_dropped_frames); +} + +ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int +internal_stacktrace::DefaultStackUnwinder(void** pcs, uintptr_t* frames, + int* sizes, int depth, int skip, + const void* uc, + int* min_dropped_frames) { + int n = DefaultStackUnwinderImpl(pcs, frames, sizes, depth, skip, uc, + min_dropped_frames); + ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); + return n; +} + +ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int DefaultStackUnwinder( + void** pcs, int* sizes, int depth, int skip, const void* uc, + int* min_dropped_frames) { + int n = DefaultStackUnwinderImpl(pcs, nullptr, sizes, depth, skip, uc, + min_dropped_frames); + ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); return n; }
diff --git a/absl/debugging/stacktrace.h b/absl/debugging/stacktrace.h index 0ec0ffd..b55babb 100644 --- a/absl/debugging/stacktrace.h +++ b/absl/debugging/stacktrace.h
@@ -31,11 +31,52 @@ #ifndef ABSL_DEBUGGING_STACKTRACE_H_ #define ABSL_DEBUGGING_STACKTRACE_H_ +#include <stdint.h> + +#include "absl/base/attributes.h" #include "absl/base/config.h" namespace absl { ABSL_NAMESPACE_BEGIN +namespace internal_stacktrace { + +// Same as `absl::GetStackFrames`, but with an optional `frames` parameter to +// allow callers to receive the raw stack frame addresses. +// This is internal for now; use `absl::GetStackFrames()` instead. +extern int GetStackFrames(void** result, uintptr_t* frames, int* sizes, + int max_depth, int skip_count); + +// Same as `absl::GetStackFramesWithContext`, but with an optional `frames` +// parameter to allow callers to receive a start address for each stack frame. +// The address may be zero in cases where it cannot be computed. +// +// DO NOT use this function without consulting the owners of absl/debuggging. +// There is NO GUARANTEE on the precise frame addresses returned on any given +// platform. It is only intended to provide sufficient non-overlapping bounds on +// the local variables of a stack frame when used in conjunction with the +// returned frame sizes. The actual pointers may be ABI-dependent, may vary at +// run time, and are subject to breakage without notice. +// +// Implementation note: +// Currently, we *attempt* to return the Canonical Frame Address (CFA) in DWARF +// on most platforms. This is the value of the stack pointer just before the +// 'call' instruction is executed in the caller. +// Not all platforms and toolchains support this exact address, so this should +// not be relied on for correctness. +extern int GetStackFramesWithContext(void** result, uintptr_t* frames, + int* sizes, int max_depth, int skip_count, + const void* uc, int* min_dropped_frames); + +// Same as `absl::DefaultStackUnwinder`, but with an optional `frames` parameter +// to allow callers to receive the raw stack frame addresses. +// This is internal for now; do not depend on this externally. +extern int DefaultStackUnwinder(void** pcs, uintptr_t* frames, int* sizes, + int max_depth, int skip_count, const void* uc, + int* min_dropped_frames); + +} // namespace internal_stacktrace + // GetStackFrames() // // Records program counter values for up to `max_depth` frames, skipping the @@ -78,8 +119,13 @@ // // This routine may return fewer stack frame entries than are // available. Also note that `result` and `sizes` must both be non-null. -extern int GetStackFrames(void** result, int* sizes, int max_depth, - int skip_count); +ABSL_ATTRIBUTE_ALWAYS_INLINE inline int GetStackFrames(void** result, + int* sizes, + int max_depth, + int skip_count) { + return internal_stacktrace::GetStackFrames(result, nullptr, sizes, max_depth, + skip_count); +} // GetStackFramesWithContext() // @@ -102,9 +148,12 @@ // or other reasons. (This value will be set to `0` if no frames were dropped.) // The number of total stack frames is guaranteed to be >= skip_count + // max_depth + *min_dropped_frames. -extern int GetStackFramesWithContext(void** result, int* sizes, int max_depth, - int skip_count, const void* uc, - int* min_dropped_frames); +ABSL_ATTRIBUTE_ALWAYS_INLINE inline int GetStackFramesWithContext( + void** result, int* sizes, int max_depth, int skip_count, const void* uc, + int* min_dropped_frames) { + return internal_stacktrace::GetStackFramesWithContext( + result, nullptr, sizes, max_depth, skip_count, uc, min_dropped_frames); +} // GetStackTrace() //
diff --git a/absl/debugging/stacktrace_test.cc b/absl/debugging/stacktrace_test.cc index 31f7723..f31f624 100644 --- a/absl/debugging/stacktrace_test.cc +++ b/absl/debugging/stacktrace_test.cc
@@ -14,12 +14,30 @@ #include "absl/debugging/stacktrace.h" +#include <stddef.h> +#include <stdint.h> + +#include <algorithm> + +#include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/macros.h" +#include "absl/base/attributes.h" +#include "absl/base/config.h" #include "absl/base/optimization.h" +#include "absl/types/span.h" namespace { +using ::testing::Contains; + +struct StackTrace { + static constexpr int kStackCount = 64; + int depth; + void* result[kStackCount]; + uintptr_t frames[kStackCount]; + int sizes[kStackCount]; +}; + // This test is currently only known to pass on Linux x86_64/aarch64. #if defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__)) ABSL_ATTRIBUTE_NOINLINE void Unwind(void* p) { @@ -44,4 +62,84 @@ } #endif +#if ABSL_HAVE_BUILTIN(__builtin_frame_address) +struct FrameInfo { + const void* return_address; + uintptr_t frame_address; +}; + +// Returns the canonical frame address and return address for the current stack +// frame, while capturing the stack trace at the same time. +// This performs any platform-specific adjustments necessary to convert from the +// compiler built-ins to the expected API outputs. +ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. + ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. + ABSL_ATTRIBUTE_NOINLINE static FrameInfo + CaptureBacktraceNoInline(StackTrace& backtrace) { + FrameInfo result; + result.return_address = __builtin_return_address(0); + // Large enough to cover all realistic slots the return address could be in + const int kMaxReturnAddressIndex = 5; + void* const* bfa = static_cast<void* const*>(__builtin_frame_address(0)); + backtrace.depth = absl::internal_stacktrace::GetStackFramesWithContext( + backtrace.result, backtrace.frames, backtrace.sizes, + StackTrace::kStackCount, /*skip_count=*/0, + /*uc=*/nullptr, /*min_dropped_frames=*/nullptr); + // Make sure the return address is at a reasonable location in the frame + ptrdiff_t i; + for (i = 0; i < kMaxReturnAddressIndex; ++i) { + // Avoid std::find() here, since it lacks no-sanitize attributes. + if (bfa[i] == result.return_address) { + break; + } + } + result.frame_address = + i < kMaxReturnAddressIndex + ? reinterpret_cast<uintptr_t>( + bfa + i + 1 /* get the Canonical Frame Address (CFA) */) + : 0; + return result; +} + +TEST(StackTrace, CanonicalFrameAddresses) { + // Now capture a stack trace and verify that the return addresses and frame + // addresses line up for one frame. + StackTrace backtrace; + const auto [return_address, frame_address] = + CaptureBacktraceNoInline(backtrace); + auto return_addresses = absl::MakeSpan(backtrace.result) + .subspan(0, static_cast<size_t>(backtrace.depth)); + auto frame_addresses = absl::MakeSpan(backtrace.frames) + .subspan(0, static_cast<size_t>(backtrace.depth)); + + // Many platforms don't support this by default. + bool support_is_expected = false; + + if (support_is_expected) { + // If all zeros were returned, that is valid per the function's contract. + // It just means we don't support returning frame addresses on this + // platform. + bool supported = static_cast<size_t>(std::count(frame_addresses.begin(), + frame_addresses.end(), 0)) < + frame_addresses.size(); + EXPECT_TRUE(supported); + if (supported) { + ASSERT_TRUE(frame_address) + << "unable to obtain frame address corresponding to return address"; + EXPECT_THAT(return_addresses, Contains(return_address).Times(1)); + EXPECT_THAT(frame_addresses, Contains(frame_address).Times(1)); + ptrdiff_t ifound = std::find(return_addresses.begin(), + return_addresses.end(), return_address) - + return_addresses.begin(); + // Make sure we found the frame in the first place. + ASSERT_LT(ifound, backtrace.depth); + // Make sure the frame address actually corresponds to the return + // address. + EXPECT_EQ(frame_addresses[static_cast<size_t>(ifound)], frame_address); + // Make sure the addresses only appear once. + } + } +} +#endif + } // namespace
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index d9a3034..5e9bec4 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel
@@ -245,6 +245,7 @@ ":reflection", "//absl/base:config", "//absl/base:core_headers", + "//absl/base:nullability", "//absl/strings", ], )
diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt index 5430429..f995957 100644 --- a/absl/flags/CMakeLists.txt +++ b/absl/flags/CMakeLists.txt
@@ -218,6 +218,7 @@ absl::flags_internal absl::flags_reflection absl::core_headers + absl::nullability absl::strings )
diff --git a/absl/flags/flag.h b/absl/flags/flag.h index 81b47ee..e052d5f 100644 --- a/absl/flags/flag.h +++ b/absl/flags/flag.h
@@ -35,6 +35,7 @@ #include "absl/base/attributes.h" #include "absl/base/config.h" +#include "absl/base/nullability.h" #include "absl/base/optimization.h" #include "absl/flags/commandlineflag.h" #include "absl/flags/config.h" @@ -106,7 +107,7 @@ // thread-safe, but is potentially expensive. Avoid setting flags in general, // but especially within performance-critical code. template <typename T> -void SetFlag(absl::Flag<T>* flag, const T& v) { +void SetFlag(absl::Flag<T>* absl_nonnull flag, const T& v) { flags_internal::FlagImplPeer::InvokeSet(*flag, v); } @@ -114,7 +115,7 @@ // convertible to `T`. E.g., use this overload to pass a "const char*" when `T` // is `std::string`. template <typename T, typename V> -void SetFlag(absl::Flag<T>* flag, const V& v) { +void SetFlag(absl::Flag<T>* absl_nonnull flag, const V& v) { T value(v); flags_internal::FlagImplPeer::InvokeSet(*flag, value); }
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h index a243b79..ef739e7 100644 --- a/absl/flags/internal/flag.h +++ b/absl/flags/internal/flag.h
@@ -783,7 +783,7 @@ // heap allocation during initialization, which is both slows program startup // and can fail. Using reserved space + placement new allows us to avoid both // problems. - alignas(absl::Mutex) mutable char data_guard_[sizeof(absl::Mutex)]; + alignas(absl::Mutex) mutable unsigned char data_guard_[sizeof(absl::Mutex)]; }; #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop @@ -876,7 +876,8 @@ template <typename T> void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3) { struct AlignedSpace { - alignas(MaskedPointer::RequiredAlignment()) alignas(T) char buf[sizeof(T)]; + alignas(MaskedPointer::RequiredAlignment()) alignas( + T) unsigned char buf[sizeof(T)]; }; using Allocator = std::allocator<AlignedSpace>; switch (op) {
diff --git a/absl/flags/internal/registry.h b/absl/flags/internal/registry.h index 4b68c85..a57ba3c 100644 --- a/absl/flags/internal/registry.h +++ b/absl/flags/internal/registry.h
@@ -73,7 +73,7 @@ // // Retire flag with name "name" and type indicated by ops. -void Retire(const char* name, FlagFastTypeId type_id, char* buf); +void Retire(const char* name, FlagFastTypeId type_id, unsigned char* buf); constexpr size_t kRetiredFlagObjSize = 3 * sizeof(void*); constexpr size_t kRetiredFlagObjAlignment = alignof(void*); @@ -87,7 +87,7 @@ } private: - alignas(kRetiredFlagObjAlignment) char buf_[kRetiredFlagObjSize]; + alignas(kRetiredFlagObjAlignment) unsigned char buf_[kRetiredFlagObjSize]; }; } // namespace flags_internal
diff --git a/absl/flags/reflection.cc b/absl/flags/reflection.cc index ea856ff..b8b4a2e 100644 --- a/absl/flags/reflection.cc +++ b/absl/flags/reflection.cc
@@ -289,11 +289,10 @@ } // namespace -void Retire(const char* name, FlagFastTypeId type_id, char* buf) { +void Retire(const char* name, FlagFastTypeId type_id, unsigned char* buf) { static_assert(sizeof(RetiredFlagObj) == kRetiredFlagObjSize, ""); static_assert(alignof(RetiredFlagObj) == kRetiredFlagObjAlignment, ""); - auto* flag = ::new (static_cast<void*>(buf)) - flags_internal::RetiredFlagObj(name, type_id); + auto* flag = ::new (buf) flags_internal::RetiredFlagObj(name, type_id); FlagRegistry::GlobalRegistry().RegisterFlag(*flag, nullptr); }
diff --git a/absl/functional/BUILD.bazel b/absl/functional/BUILD.bazel index 8296f14..aeed3b6 100644 --- a/absl/functional/BUILD.bazel +++ b/absl/functional/BUILD.bazel
@@ -146,8 +146,9 @@ ], ) -cc_test( +cc_binary( name = "function_type_benchmark", + testonly = True, srcs = [ "function_type_benchmark.cc", ], @@ -159,6 +160,5 @@ ":function_ref", "//absl/base:core_headers", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], )
diff --git a/absl/functional/function_type_benchmark.cc b/absl/functional/function_type_benchmark.cc index 03dc31d..513233b 100644 --- a/absl/functional/function_type_benchmark.cc +++ b/absl/functional/function_type_benchmark.cc
@@ -16,10 +16,10 @@ #include <memory> #include <string> -#include "benchmark/benchmark.h" #include "absl/base/attributes.h" #include "absl/functional/any_invocable.h" #include "absl/functional/function_ref.h" +#include "benchmark/benchmark.h" namespace absl { ABSL_NAMESPACE_BEGIN
diff --git a/absl/functional/internal/any_invocable.h b/absl/functional/internal/any_invocable.h index 6bfc4d1..167d947 100644 --- a/absl/functional/internal/any_invocable.h +++ b/absl/functional/internal/any_invocable.h
@@ -174,7 +174,7 @@ } remote; // Local-storage for the type-erased object when small and trivial enough - alignas(kAlignment) char storage[kStorageSize]; + alignas(kAlignment) unsigned char storage[kStorageSize]; }; // A typed accessor for the object in `TypeErasedState` storage
diff --git a/absl/log/CMakeLists.txt b/absl/log/CMakeLists.txt index 949d442..6aae05d 100644 --- a/absl/log/CMakeLists.txt +++ b/absl/log/CMakeLists.txt
@@ -747,6 +747,7 @@ absl::log_internal_fnmatch absl::memory absl::no_destructor + absl::nullability absl::strings absl::synchronization absl::optional
diff --git a/absl/log/internal/BUILD.bazel b/absl/log/internal/BUILD.bazel index d3f4a8f..5d54b6f 100644 --- a/absl/log/internal/BUILD.bazel +++ b/absl/log/internal/BUILD.bazel
@@ -462,11 +462,12 @@ "//absl/log:__subpackages__", ], deps = [ + ":fnmatch", "//absl/base", "//absl/base:config", "//absl/base:core_headers", "//absl/base:no_destructor", - "//absl/log/internal:fnmatch", + "//absl/base:nullability", "//absl/memory", "//absl/strings", "//absl/synchronization",
diff --git a/absl/log/internal/conditions.h b/absl/log/internal/conditions.h index 97edf65..6fb74b1 100644 --- a/absl/log/internal/conditions.h +++ b/absl/log/internal/conditions.h
@@ -118,6 +118,8 @@ ABSL_LOG_INTERNAL_##type##_CONDITION( \ (condition) && ::absl::LogSeverity::kError >= \ static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL)) +#define ABSL_LOG_INTERNAL_CONDITION_DO_NOT_SUBMIT(type, condition) \ + ABSL_LOG_INTERNAL_CONDITION_ERROR(type, condition) // NOTE: Use ternary operators instead of short-circuiting to mitigate // https://bugs.llvm.org/show_bug.cgi?id=51928. #define ABSL_LOG_INTERNAL_CONDITION_FATAL(type, condition) \ @@ -169,6 +171,8 @@ ABSL_LOG_INTERNAL_##type##_CONDITION(condition) #define ABSL_LOG_INTERNAL_CONDITION_ERROR(type, condition) \ ABSL_LOG_INTERNAL_##type##_CONDITION(condition) +#define ABSL_LOG_INTERNAL_CONDITION_DO_NOT_SUBMIT(type, condition) \ + ABSL_LOG_INTERNAL_CONDITION_ERROR(type, condition) #define ABSL_LOG_INTERNAL_CONDITION_FATAL(type, condition) \ ABSL_LOG_INTERNAL_##type##_CONDITION(condition) #define ABSL_LOG_INTERNAL_CONDITION_QFATAL(type, condition) \
diff --git a/absl/log/internal/fnmatch_test.cc b/absl/log/internal/fnmatch_test.cc index e16a64e..614c7d3 100644 --- a/absl/log/internal/fnmatch_test.cc +++ b/absl/log/internal/fnmatch_test.cc
@@ -27,6 +27,7 @@ EXPECT_THAT(FNMatch("foo", "bar"), IsFalse()); EXPECT_THAT(FNMatch("foo", "fo"), IsFalse()); EXPECT_THAT(FNMatch("foo", "foo2"), IsFalse()); + EXPECT_THAT(FNMatch("foo/*", "foo/1/2/3/4"), IsTrue()); EXPECT_THAT(FNMatch("bar/foo.ext", "bar/foo.ext"), IsTrue()); EXPECT_THAT(FNMatch("*ba*r/fo*o.ext*", "bar/foo.ext"), IsTrue()); EXPECT_THAT(FNMatch("bar/foo.ext", "bar/baz.ext"), IsFalse());
diff --git a/absl/log/internal/strip.h b/absl/log/internal/strip.h index 4846427..60ef878 100644 --- a/absl/log/internal/strip.h +++ b/absl/log/internal/strip.h
@@ -15,7 +15,8 @@ // ----------------------------------------------------------------------------- // File: log/internal/strip.h // ----------------------------------------------------------------------------- -// + +// SKIP_ABSL_INLINE_NAMESPACE_CHECK #ifndef ABSL_LOG_INTERNAL_STRIP_H_ #define ABSL_LOG_INTERNAL_STRIP_H_ @@ -94,4 +95,6 @@ #define ABSL_LOGGING_INTERNAL_DLOG_DFATAL ABSL_LOGGING_INTERNAL_LOG_DFATAL #define ABSL_LOGGING_INTERNAL_DLOG_LEVEL ABSL_LOGGING_INTERNAL_LOG_LEVEL +#define ABSL_LOGGING_INTERNAL_LOG_DO_NOT_SUBMIT ABSL_LOGGING_INTERNAL_LOG_ERROR + #endif // ABSL_LOG_INTERNAL_STRIP_H_
diff --git a/absl/log/internal/vlog_config.h b/absl/log/internal/vlog_config.h index b6e322c..c6543a2 100644 --- a/absl/log/internal/vlog_config.h +++ b/absl/log/internal/vlog_config.h
@@ -34,6 +34,7 @@ #include "absl/base/attributes.h" #include "absl/base/config.h" +#include "absl/base/nullability.h" #include "absl/base/optimization.h" #include "absl/base/thread_annotations.h" #include "absl/strings/string_view.h" @@ -60,7 +61,7 @@ class VLogSite final { public: // `f` must not be destroyed until the program exits. - explicit constexpr VLogSite(const char* f) + explicit constexpr VLogSite(const char* absl_nonnull f) : file_(f), v_(kUninitialized), next_(nullptr) {} VLogSite(const VLogSite&) = delete; VLogSite& operator=(const VLogSite&) = delete; @@ -116,7 +117,7 @@ ABSL_ATTRIBUTE_NOINLINE bool SlowIsEnabled5(int stale_v); // This object is too size-sensitive to use absl::string_view. - const char* const file_; + const char* absl_nonnull const file_; std::atomic<int> v_; std::atomic<VLogSite*> next_; };
diff --git a/absl/log/log.h b/absl/log/log.h index 4a4e038..f1cab9d 100644 --- a/absl/log/log.h +++ b/absl/log/log.h
@@ -34,6 +34,13 @@ // running registered error handlers. // * The `DFATAL` pseudo-severity level is defined as `FATAL` in debug mode and // as `ERROR` otherwise. +// * The `DO_NOT_SUBMIT` pseudo-severity level is an alias for `ERROR`, and is +// intended for debugging statements that won't be submitted. The name is +// chosen to be easy to spot in review and with tools in order to ensure that +// such statements aren't inadvertently checked in. +// The contract is that **it may not be checked in**, meaning that no +// in-contract uses will be affected if we decide in the future to remove it +// or change what it does. // Some preprocessor shenanigans are used to ensure that e.g. `LOG(INFO)` has // the same meaning even if a local symbol or preprocessor macro named `INFO` is // defined. To specify a severity level using an expression instead of a @@ -194,6 +201,8 @@ // LOG(INFO) << std::hex << 0xdeadbeef; // logs "0xdeadbeef" // LOG(INFO) << 0xdeadbeef; // logs "3735928559" +// SKIP_ABSL_INLINE_NAMESPACE_CHECK + #ifndef ABSL_LOG_LOG_H_ #define ABSL_LOG_LOG_H_
diff --git a/absl/log/log_basic_test_impl.inc b/absl/log/log_basic_test_impl.inc index 2c84b45..c4b4e24 100644 --- a/absl/log/log_basic_test_impl.inc +++ b/absl/log/log_basic_test_impl.inc
@@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// SKIP_ABSL_INLINE_NAMESPACE_CHECK + // The testcases in this file are expected to pass or be skipped with any value // of ABSL_MIN_LOG_LEVEL @@ -181,6 +183,37 @@ do_log(); } +TEST_P(BasicLogTest, DoNotSubmit) { + absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam()); + + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + const int log_line = __LINE__ + 1; + auto do_log = [] { ABSL_TEST_LOG(DO_NOT_SUBMIT) << "hello world"; }; + + if (LoggingEnabledAt(absl::LogSeverity::kError)) { + EXPECT_CALL( + test_sink, + Send(AllOf( + SourceFilename(Eq(__FILE__)), + SourceBasename(Eq("log_basic_test_impl.inc")), + SourceLine(Eq(log_line)), Prefix(IsTrue()), + LogSeverity(Eq(absl::LogSeverity::kError)), + Timestamp(InMatchWindow()), + ThreadID(Eq(absl::base_internal::GetTID())), + TextMessage(Eq("hello world")), + Verbosity(Eq(absl::LogEntry::kNoVerbosityLevel)), + ENCODED_MESSAGE(MatchesEvent( + Eq(__FILE__), Eq(log_line), InMatchWindow(), + Eq(logging::proto::ERROR), Eq(absl::base_internal::GetTID()), + ElementsAre(ValueWithLiteral(Eq("hello world"))))), + Stacktrace(IsEmpty())))); + } + + test_sink.StartCapturingLogs(); + do_log(); +} + #if GTEST_HAS_DEATH_TEST using BasicLogDeathTest = BasicLogTest;
diff --git a/absl/numeric/BUILD.bazel b/absl/numeric/BUILD.bazel index 4503a15..3c7a02f 100644 --- a/absl/numeric/BUILD.bazel +++ b/absl/numeric/BUILD.bazel
@@ -56,7 +56,6 @@ "//absl/base:core_headers", "//absl/random", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], ) @@ -115,8 +114,9 @@ ], ) -cc_test( +cc_binary( name = "int128_benchmark", + testonly = True, srcs = ["int128_benchmark.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, @@ -125,7 +125,6 @@ ":int128", "//absl/base:config", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], )
diff --git a/absl/numeric/bits_benchmark.cc b/absl/numeric/bits_benchmark.cc index 2c89afd..429b4ca 100644 --- a/absl/numeric/bits_benchmark.cc +++ b/absl/numeric/bits_benchmark.cc
@@ -15,10 +15,10 @@ #include <cstdint> #include <vector> -#include "benchmark/benchmark.h" #include "absl/base/optimization.h" #include "absl/numeric/bits.h" #include "absl/random/random.h" +#include "benchmark/benchmark.h" namespace absl { namespace {
diff --git a/absl/numeric/int128_benchmark.cc b/absl/numeric/int128_benchmark.cc index eab1515..e2e2de5 100644 --- a/absl/numeric/int128_benchmark.cc +++ b/absl/numeric/int128_benchmark.cc
@@ -18,9 +18,9 @@ #include <random> #include <vector> -#include "benchmark/benchmark.h" #include "absl/base/config.h" #include "absl/numeric/int128.h" +#include "benchmark/benchmark.h" namespace {
diff --git a/absl/status/BUILD.bazel b/absl/status/BUILD.bazel index b0eb27a..b61abeb 100644 --- a/absl/status/BUILD.bazel +++ b/absl/status/BUILD.bazel
@@ -86,6 +86,17 @@ ], ) +cc_binary( + name = "status_benchmark", + testonly = True, + srcs = ["status_benchmark.cc"], + tags = ["benchmark"], + deps = [ + ":status", + "@google_benchmark//:benchmark_main", + ], +) + cc_library( name = "statusor", srcs = [ @@ -132,6 +143,18 @@ ], ) +cc_binary( + name = "statusor_benchmark", + testonly = True, + srcs = ["statusor_benchmark.cc"], + tags = ["benchmark"], + deps = [ + ":status", + ":statusor", + "@google_benchmark//:benchmark_main", + ], +) + cc_library( name = "status_matchers", testonly = 1,
diff --git a/absl/status/status_benchmark.cc b/absl/status/status_benchmark.cc new file mode 100644 index 0000000..a9146fb --- /dev/null +++ b/absl/status/status_benchmark.cc
@@ -0,0 +1,37 @@ +// Copyright 2025 The Abseil 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 +// +// https://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. + +#include <utility> +#include "absl/status/status.h" +#include "benchmark/benchmark.h" + +namespace { + +void BM_CreateOk(benchmark::State& state) { + for (auto _ : state) { + absl::Status s; // ok. + benchmark::DoNotOptimize(s); + } +} +BENCHMARK(BM_CreateOk); + +void BM_CreateBad(benchmark::State& state) { + for (auto _ : state) { + absl::Status s(absl::StatusCode::kInvalidArgument, "message"); + benchmark::DoNotOptimize(s); + } +} +BENCHMARK(BM_CreateBad); + +} // namespace
diff --git a/absl/status/statusor.h b/absl/status/statusor.h index b1da45e..322d448 100644 --- a/absl/status/statusor.h +++ b/absl/status/statusor.h
@@ -464,7 +464,7 @@ // Returns a reference to the current `absl::Status` contained within the // `absl::StatusOr<T>`. If `absl::StatusOr<T>` contains a `T`, then this // function returns `absl::OkStatus()`. - const Status& status() const&; + ABSL_MUST_USE_RESULT const Status& status() const&; Status status() &&; // StatusOr<T>::value()
diff --git a/absl/status/statusor_benchmark.cc b/absl/status/statusor_benchmark.cc new file mode 100644 index 0000000..bb99547 --- /dev/null +++ b/absl/status/statusor_benchmark.cc
@@ -0,0 +1,480 @@ +// Copyright 2025 The Abseil 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 +// +// https://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. + +#include <string> + +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "benchmark/benchmark.h" + +namespace { + +void BM_StatusOrInt_CtorStatus(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<int> status(absl::CancelledError()); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrInt_CtorStatus); + +void BM_StatusOrInt_CtorStatusWithMessage(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<int> status( + absl::UnknownError("This string is 28 characters")); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrInt_CtorStatusWithMessage); + +void BM_StatusOrInt_CopyCtor_Error(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<int> original( + absl::UnknownError("This string is 28 characters")); + benchmark::DoNotOptimize(original); + absl::StatusOr<int> status(original); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrInt_CopyCtor_Error); + +void BM_StatusOrInt_CopyCtor_Ok(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<int> original(42); + benchmark::DoNotOptimize(original); + absl::StatusOr<int> status(original); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrInt_CopyCtor_Ok); + +void BM_StatusOrInt_MoveCtor_Error(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<int> original( + absl::UnknownError("This string is 28 characters")); + benchmark::DoNotOptimize(original); + absl::StatusOr<int> status(std::move(original)); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrInt_MoveCtor_Error); + +void BM_StatusOrInt_MoveCtor_Ok(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<int> original(42); + benchmark::DoNotOptimize(original); + absl::StatusOr<int> status(std::move(original)); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrInt_MoveCtor_Ok); + +void BM_StatusOrInt_CopyAssign_Error(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<int> original( + absl::UnknownError("This string is 28 characters")); + benchmark::DoNotOptimize(original); + absl::StatusOr<int> status(42); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(status = original); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrInt_CopyAssign_Error); + +void BM_StatusOrInt_CopyAssign_Ok(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<int> original(42); + benchmark::DoNotOptimize(original); + absl::StatusOr<int> status(42); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(status = original); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrInt_CopyAssign_Ok); + +void BM_StatusOrInt_MoveAssign_Error(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<int> original( + absl::UnknownError("This string is 28 characters")); + benchmark::DoNotOptimize(original); + absl::StatusOr<int> status(42); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(status = std::move(original)); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrInt_MoveAssign_Error); + +void BM_StatusOrInt_MoveAssign_Ok(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<int> original(42); + benchmark::DoNotOptimize(original); + absl::StatusOr<int> status(42); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(status = std::move(original)); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrInt_MoveAssign_Ok); + +void BM_StatusOrInt_OkMethod_Error(benchmark::State& state) { + absl::StatusOr<int> status( + absl::UnknownError("This string is 28 characters")); + for (auto _ : state) { + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(status.ok()); + } +} +BENCHMARK(BM_StatusOrInt_OkMethod_Error); + +void BM_StatusOrInt_OkMethod_Ok(benchmark::State& state) { + absl::StatusOr<int> status(42); + for (auto _ : state) { + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(status.ok()); + } +} +BENCHMARK(BM_StatusOrInt_OkMethod_Ok); + +void BM_StatusOrInt_StatusMethod_Error(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<int> status( + absl::UnknownError("This string is 28 characters")); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(status.status().ok()); + } +} +BENCHMARK(BM_StatusOrInt_StatusMethod_Error); + +void BM_StatusOrInt_StatusMethod_Ok(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<int> status(42); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(std::move(status).status().ok()); + } +} +BENCHMARK(BM_StatusOrInt_StatusMethod_Ok); + +void BM_StatusOrInt_StatusMethodRvalue_Error(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<int> status( + absl::UnknownError("This string is 28 characters")); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(std::move(status).status().ok()); + } +} +BENCHMARK(BM_StatusOrInt_StatusMethodRvalue_Error); + +void BM_StatusOrInt_StatusMethodRvalue_Ok(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<int> status(42); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(std::move(status).status()); + } +} +BENCHMARK(BM_StatusOrInt_StatusMethodRvalue_Ok); + +void BM_StatusOrString_CtorStatus(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<std::string> status(absl::CancelledError()); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrString_CtorStatus); + +void BM_StatusOrString_CtorStatusWithMessage(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<std::string> status( + absl::UnknownError("This string is 28 characters")); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrString_CtorStatusWithMessage); + +void BM_StatusOrString_CopyCtor_Error(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<std::string> original( + absl::UnknownError("This string is 28 characters")); + benchmark::DoNotOptimize(original); + absl::StatusOr<std::string> status(original); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrString_CopyCtor_Error); + +void BM_StatusOrString_CopyCtor_Ok(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<std::string> original("This string is 28 characters"); + benchmark::DoNotOptimize(original); + absl::StatusOr<std::string> status(original); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrString_CopyCtor_Ok); + +void BM_StatusOrString_MoveCtor_Error(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<std::string> original( + absl::UnknownError("This string is 28 characters")); + benchmark::DoNotOptimize(original); + absl::StatusOr<std::string> status(std::move(original)); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrString_MoveCtor_Error); + +void BM_StatusOrString_MoveCtor_Ok(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<std::string> original("This string is 28 characters"); + benchmark::DoNotOptimize(original); + absl::StatusOr<std::string> status(std::move(original)); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrString_MoveCtor_Ok); + +void BM_StatusOrString_CopyAssign_Error(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<std::string> original( + absl::UnknownError("This string is 28 characters")); + benchmark::DoNotOptimize(original); + absl::StatusOr<std::string> status("This string is 28 characters"); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(status = original); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrString_CopyAssign_Error); + +void BM_StatusOrString_CopyAssign_Ok(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<std::string> original("This string is 28 characters"); + benchmark::DoNotOptimize(original); + absl::StatusOr<std::string> status("This string is 28 characters"); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(status = original); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrString_CopyAssign_Ok); + +void BM_StatusOrString_MoveAssign_Error(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<std::string> original( + absl::UnknownError("This string is 28 characters")); + benchmark::DoNotOptimize(original); + absl::StatusOr<std::string> status("This string is 28 characters"); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(status = std::move(original)); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrString_MoveAssign_Error); + +void BM_StatusOrString_MoveAssign_Ok(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<std::string> original("This string is 28 characters"); + benchmark::DoNotOptimize(original); + absl::StatusOr<std::string> status("This string is 28 characters"); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(status = std::move(original)); + benchmark::DoNotOptimize(status); + } +} +BENCHMARK(BM_StatusOrString_MoveAssign_Ok); + +void BM_StatusOrString_OkMethod_Error(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<std::string> status( + absl::UnknownError("This string is 28 characters")); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(status.ok()); + } +} +BENCHMARK(BM_StatusOrString_OkMethod_Error); + +void BM_StatusOrString_OkMethod_Ok(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<std::string> status("This string is 28 characters"); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(status.ok()); + } +} +BENCHMARK(BM_StatusOrString_OkMethod_Ok); + +void BM_StatusOrString_StatusMethod_Error(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<std::string> status( + absl::UnknownError("This string is 28 characters")); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(status.status().ok()); + } +} +BENCHMARK(BM_StatusOrString_StatusMethod_Error); + +void BM_StatusOrString_StatusMethod_Ok(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<std::string> status("This string is 28 characters"); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(status.status().ok()); + } +} +BENCHMARK(BM_StatusOrString_StatusMethod_Ok); + +void BM_StatusOrString_StatusMethodRvalue_Error(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<std::string> status( + absl::UnknownError("This string is 28 characters")); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(std::move(status).status()); + } +} +BENCHMARK(BM_StatusOrString_StatusMethodRvalue_Error); + +void BM_StatusOrString_StatusMethodRvalue_Ok(benchmark::State& state) { + for (auto _ : state) { + absl::StatusOr<std::string> status("This string is 28 characters"); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(std::move(status).status()); + } +} +BENCHMARK(BM_StatusOrString_StatusMethodRvalue_Ok); + +// Benchmarks comparing a few alternative ways of structuring an interface +// for returning an int64 on success or an error. See (a), (b), (c), (d) +// below for the variants. +bool bm_cond = true; + +bool SimpleIntInterface(int64_t* v) ABSL_ATTRIBUTE_NOINLINE; +bool SimpleIntInterfaceWithErrorMessage(int64_t* v, std::string* msg) + ABSL_ATTRIBUTE_NOINLINE; +absl::Status SimpleIntInterfaceWithErrorStatus(int64_t* v) + ABSL_ATTRIBUTE_NOINLINE; +absl::StatusOr<int64_t> SimpleIntStatusOrInterface() ABSL_ATTRIBUTE_NOINLINE; + +// (a): Just a boolean return value with an out int64* parameter +bool SimpleIntInterface(int64_t* v) { + benchmark::DoNotOptimize(bm_cond); + if (bm_cond) { + *v = 42; + return true; + } else { + return false; + } +} + +// (b): A boolean return value and a string error message filled in on failure +// and an out int64* parameter filled on success +bool SimpleIntInterfaceWithErrorMessage(int64_t* v, std::string* msg) { + benchmark::DoNotOptimize(bm_cond); + if (bm_cond) { + *v = 42; + return true; + } else { + *msg = "This is an error message"; + return false; + } +} + +// (c): A Status return value with an out int64* parameter on success +absl::Status SimpleIntInterfaceWithErrorStatus(int64_t* v) { + benchmark::DoNotOptimize(bm_cond); + if (bm_cond) { + *v = 42; + return absl::OkStatus(); + } else { + return absl::UnknownError("This is an error message"); + } +} + +// (d): A StatusOr<int64> return value +absl::StatusOr<int64_t> SimpleIntStatusOrInterface() { + benchmark::DoNotOptimize(bm_cond); + if (bm_cond) { + return 42; + } else { + return absl::StatusOr<int64_t>( + absl::UnknownError("This is an error message")); + } +} + +void SetCondition(benchmark::State& state) { + bm_cond = (state.range(0) == 0); + state.SetLabel(bm_cond ? "Success" : "Failure"); +} + +void BM_SimpleIntInterface(benchmark::State& state) { + SetCondition(state); + int64_t sum = 0; + for (auto s : state) { + int64_t v; + if (SimpleIntInterface(&v)) { + sum += v; + } + benchmark::DoNotOptimize(sum); + } +} + +void BM_SimpleIntInterfaceMsg(benchmark::State& state) { + SetCondition(state); + int64_t sum = 0; + std::string msg; + for (auto s : state) { + int64_t v; + if (SimpleIntInterfaceWithErrorMessage(&v, &msg)) { + sum += v; + } + benchmark::DoNotOptimize(sum); + benchmark::DoNotOptimize(msg); + } +} + +void BM_SimpleIntInterfaceStatus(benchmark::State& state) { + SetCondition(state); + int64_t sum = 0; + for (auto s : state) { + int64_t v; + auto result = SimpleIntInterfaceWithErrorStatus(&v); + if (result.ok()) { + sum += v; + } + benchmark::DoNotOptimize(sum); + } +} + +void BM_SimpleIntStatusOrInterface(benchmark::State& state) { + SetCondition(state); + int64_t sum = 0; + for (auto s : state) { + auto v_s = SimpleIntStatusOrInterface(); + if (v_s.ok()) { + sum += *v_s; + } + benchmark::DoNotOptimize(sum); + } +} + +// Ordered like this so all the success path benchmarks (Arg(0)) show up, +// then all the failure benchmarks (Arg(1)) +BENCHMARK(BM_SimpleIntInterface)->Arg(0); +BENCHMARK(BM_SimpleIntInterfaceMsg)->Arg(0); +BENCHMARK(BM_SimpleIntInterfaceStatus)->Arg(0); +BENCHMARK(BM_SimpleIntStatusOrInterface)->Arg(0); +BENCHMARK(BM_SimpleIntInterface)->Arg(1); +BENCHMARK(BM_SimpleIntInterfaceMsg)->Arg(1); +BENCHMARK(BM_SimpleIntInterfaceStatus)->Arg(1); +BENCHMARK(BM_SimpleIntStatusOrInterface)->Arg(1); + +} // namespace
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index cb8d900..ddc115d 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel
@@ -172,8 +172,9 @@ ], ) -cc_test( +cc_binary( name = "escaping_benchmark", + testonly = True, srcs = [ "escaping_benchmark.cc", "internal/escaping_test_common.h", @@ -185,7 +186,6 @@ ":strings", "//absl/base:raw_logging_internal", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], ) @@ -241,8 +241,9 @@ ], ) -cc_test( +cc_binary( name = "ascii_benchmark", + testonly = True, srcs = ["ascii_benchmark.cc"], copts = ABSL_TEST_COPTS, tags = ["benchmark"], @@ -250,7 +251,6 @@ deps = [ ":strings", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], ) @@ -268,8 +268,25 @@ ], ) -cc_test( +cc_binary( + name = "damerau_levenshtein_distance_benchmark", + testonly = True, + srcs = [ + "internal/damerau_levenshtein_distance_benchmark.cc", + ], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + tags = ["benchmark"], + visibility = ["//visibility:private"], + deps = [ + ":strings", + "@google_benchmark//:benchmark_main", + ], +) + +cc_binary( name = "memutil_benchmark", + testonly = True, srcs = [ "internal/memutil.h", "internal/memutil_benchmark.cc", @@ -281,7 +298,6 @@ ":strings", "//absl/base:core_headers", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], ) @@ -332,8 +348,9 @@ ], ) -cc_test( +cc_binary( name = "string_view_benchmark", + testonly = True, srcs = ["string_view_benchmark.cc"], copts = ABSL_TEST_COPTS, tags = ["benchmark"], @@ -344,7 +361,6 @@ "//absl/base:core_headers", "//absl/base:raw_logging_internal", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], ) @@ -365,9 +381,9 @@ ], ) -cc_test( +cc_binary( name = "charset_benchmark", - size = "small", + testonly = True, srcs = [ "charset_benchmark.cc", ], @@ -380,7 +396,6 @@ ":charset", "//absl/log:check", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], ) @@ -928,7 +943,6 @@ srcs = ["cordz_test.cc"], copts = ABSL_TEST_COPTS, tags = [ - "benchmark", "no_test_android_arm", "no_test_android_arm64", "no_test_android_x86", @@ -970,8 +984,25 @@ ], ) -cc_test( +cc_binary( + name = "substitute_benchmark", + testonly = True, + srcs = ["substitute_benchmark.cc"], + copts = ABSL_TEST_COPTS, + tags = [ + "benchmark", + ], + visibility = ["//visibility:private"], + deps = [ + ":strings", + "//absl/base:core_headers", + "@google_benchmark//:benchmark_main", + ], +) + +cc_binary( name = "str_replace_benchmark", + testonly = True, srcs = ["str_replace_benchmark.cc"], copts = ABSL_TEST_COPTS, tags = ["benchmark"], @@ -980,7 +1011,6 @@ ":strings", "//absl/base:raw_logging_internal", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], ) @@ -1014,8 +1044,9 @@ ], ) -cc_test( +cc_binary( name = "str_split_benchmark", + testonly = True, srcs = ["str_split_benchmark.cc"], copts = ABSL_TEST_COPTS, tags = ["benchmark"], @@ -1024,7 +1055,6 @@ ":strings", "//absl/base:raw_logging_internal", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], ) @@ -1041,8 +1071,9 @@ ], ) -cc_test( +cc_binary( name = "ostringstream_benchmark", + testonly = True, srcs = ["internal/ostringstream_benchmark.cc"], copts = ABSL_TEST_COPTS, tags = ["benchmark"], @@ -1050,7 +1081,6 @@ deps = [ ":internal", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], ) @@ -1086,8 +1116,9 @@ ], ) -cc_test( +cc_binary( name = "str_join_benchmark", + testonly = True, srcs = ["str_join_benchmark.cc"], copts = ABSL_TEST_COPTS, tags = ["benchmark"], @@ -1095,7 +1126,6 @@ deps = [ ":strings", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], ) @@ -1114,18 +1144,19 @@ ], ) -cc_test( +cc_binary( name = "str_cat_benchmark", + testonly = True, srcs = ["str_cat_benchmark.cc"], copts = ABSL_TEST_COPTS, tags = ["benchmark"], visibility = ["//visibility:private"], deps = [ + ":str_format", ":strings", "//absl/random", "//absl/random:distributions", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], ) @@ -1152,8 +1183,9 @@ ], ) -cc_test( +cc_binary( name = "numbers_benchmark", + testonly = True, srcs = ["numbers_benchmark.cc"], copts = ABSL_TEST_COPTS, tags = ["benchmark"], @@ -1164,7 +1196,6 @@ "//absl/random", "//absl/random:distributions", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], ) @@ -1226,8 +1257,9 @@ ], ) -cc_test( +cc_binary( name = "charconv_benchmark", + testonly = True, srcs = [ "charconv_benchmark.cc", ], @@ -1237,7 +1269,6 @@ deps = [ ":strings", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], )
diff --git a/absl/strings/ascii_benchmark.cc b/absl/strings/ascii_benchmark.cc index e4d0196..a839019 100644 --- a/absl/strings/ascii_benchmark.cc +++ b/absl/strings/ascii_benchmark.cc
@@ -12,15 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/strings/ascii.h" - #include <algorithm> +#include <array> #include <cctype> #include <cstddef> -#include <string> -#include <array> #include <random> +#include <string> +#include "absl/strings/ascii.h" #include "benchmark/benchmark.h" namespace {
diff --git a/absl/strings/charconv_benchmark.cc b/absl/strings/charconv_benchmark.cc index e8c7371..0ee9363 100644 --- a/absl/strings/charconv_benchmark.cc +++ b/absl/strings/charconv_benchmark.cc
@@ -12,12 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/strings/charconv.h" - #include <cstdlib> #include <cstring> #include <string> +#include "absl/strings/charconv.h" #include "benchmark/benchmark.h" namespace {
diff --git a/absl/strings/charset_benchmark.cc b/absl/strings/charset_benchmark.cc index bf7ae56..7133985 100644 --- a/absl/strings/charset_benchmark.cc +++ b/absl/strings/charset_benchmark.cc
@@ -14,9 +14,9 @@ #include <cstdint> -#include "benchmark/benchmark.h" #include "absl/log/check.h" #include "absl/strings/charset.h" +#include "benchmark/benchmark.h" namespace {
diff --git a/absl/strings/escaping_benchmark.cc b/absl/strings/escaping_benchmark.cc index 342fd14..32b8f6e 100644 --- a/absl/strings/escaping_benchmark.cc +++ b/absl/strings/escaping_benchmark.cc
@@ -12,18 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/strings/escaping.h" - #include <cstdint> #include <memory> #include <random> #include <string> -#include "benchmark/benchmark.h" #include "absl/base/internal/raw_logging.h" +#include "absl/strings/escaping.h" #include "absl/strings/internal/escaping_test_common.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" +#include "benchmark/benchmark.h" namespace {
diff --git a/absl/strings/internal/damerau_levenshtein_distance_benchmark.cc b/absl/strings/internal/damerau_levenshtein_distance_benchmark.cc new file mode 100644 index 0000000..76d6db4 --- /dev/null +++ b/absl/strings/internal/damerau_levenshtein_distance_benchmark.cc
@@ -0,0 +1,56 @@ +// Copyright 2022 The Abseil 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 +// +// https://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. + +#include <string> + +#include "absl/strings/internal/damerau_levenshtein_distance.h" +#include "benchmark/benchmark.h" + +namespace { + +std::string MakeTestString(int desired_length, int num_edits) { + std::string test(desired_length, 'x'); + for (int i = 0; (i < num_edits) && (i * 8 < desired_length); ++i) { + test[i * 8] = 'y'; + } + return test; +} + +void BenchmarkArgs(benchmark::internal::Benchmark* benchmark) { + // Each column is 8 bytes. + const auto string_size = {1, 8, 64, 100}; + const auto num_edits = {1, 2, 16, 16, 64, 80}; + const auto distance_cap = {1, 2, 3, 16, 64, 80}; + for (const int s : string_size) { + for (const int n : num_edits) { + for (const int d : distance_cap) { + if (n > s) continue; + benchmark->Args({s, n, d}); + } + } + } +} + +using absl::strings_internal::CappedDamerauLevenshteinDistance; +void BM_Distance(benchmark::State& state) { + std::string s1 = MakeTestString(state.range(0), 0); + std::string s2 = MakeTestString(state.range(0), state.range(1)); + const size_t cap = state.range(2); + for (auto _ : state) { + CappedDamerauLevenshteinDistance(s1, s2, cap); + } +} +BENCHMARK(BM_Distance)->Apply(BenchmarkArgs); + +} // namespace
diff --git a/absl/strings/internal/memutil_benchmark.cc b/absl/strings/internal/memutil_benchmark.cc index 61e323a..1186752 100644 --- a/absl/strings/internal/memutil_benchmark.cc +++ b/absl/strings/internal/memutil_benchmark.cc
@@ -12,13 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/strings/internal/memutil.h" - #include <algorithm> #include <cstdlib> -#include "benchmark/benchmark.h" #include "absl/strings/ascii.h" +#include "absl/strings/internal/memutil.h" +#include "benchmark/benchmark.h" // We fill the haystack with aaaaaaaaaaaaaaaaaa...aaaab. // That gives us:
diff --git a/absl/strings/internal/ostringstream_benchmark.cc b/absl/strings/internal/ostringstream_benchmark.cc index 5979f18..a95cf4d 100644 --- a/absl/strings/internal/ostringstream_benchmark.cc +++ b/absl/strings/internal/ostringstream_benchmark.cc
@@ -12,11 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/strings/internal/ostringstream.h" - #include <sstream> #include <string> +#include "absl/strings/internal/ostringstream.h" #include "benchmark/benchmark.h" namespace {
diff --git a/absl/strings/numbers_benchmark.cc b/absl/strings/numbers_benchmark.cc index e7cb60a..c58f861 100644 --- a/absl/strings/numbers_benchmark.cc +++ b/absl/strings/numbers_benchmark.cc
@@ -19,12 +19,12 @@ #include <type_traits> #include <vector> -#include "benchmark/benchmark.h" #include "absl/base/internal/raw_logging.h" #include "absl/random/distributions.h" #include "absl/random/random.h" #include "absl/strings/numbers.h" #include "absl/strings/string_view.h" +#include "benchmark/benchmark.h" namespace {
diff --git a/absl/strings/str_cat_benchmark.cc b/absl/strings/str_cat_benchmark.cc index 0a851e7..7695e8f 100644 --- a/absl/strings/str_cat_benchmark.cc +++ b/absl/strings/str_cat_benchmark.cc
@@ -21,12 +21,13 @@ #include <tuple> #include <utility> -#include "benchmark/benchmark.h" #include "absl/random/log_uniform_int_distribution.h" #include "absl/random/random.h" #include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "absl/strings/substitute.h" +#include "benchmark/benchmark.h" namespace { @@ -111,6 +112,17 @@ } BENCHMARK(BM_HexCat_By_StrCat); +void BM_HexCat_By_StrFormat(benchmark::State& state) { + int i = 0; + for (auto _ : state) { + std::string result = + absl::StrFormat("%s %x", kStringOne, int64_t{i} + 0x10000000); + benchmark::DoNotOptimize(result); + i = IncrementAlternatingSign(i); + } +} +BENCHMARK(BM_HexCat_By_StrFormat); + void BM_HexCat_By_Substitute(benchmark::State& state) { int i = 0; for (auto _ : state) { @@ -145,6 +157,18 @@ } BENCHMARK(BM_DoubleToString_By_SixDigits); +void BM_FloatToString_By_StrFormat(benchmark::State& state) { + int i = 0; + float foo = 0.0f; + for (auto _ : state) { + std::string result = + absl::StrFormat("%f != %lld", foo += 1.001f, int64_t{i}); + benchmark::DoNotOptimize(result); + i = IncrementAlternatingSign(i); + } +} +BENCHMARK(BM_FloatToString_By_StrFormat); + template <typename Table, size_t... Index> void BM_StrAppendImpl(benchmark::State& state, Table table, size_t total_bytes, std::index_sequence<Index...>) {
diff --git a/absl/strings/str_join_benchmark.cc b/absl/strings/str_join_benchmark.cc index be7a725..ffe6696 100644 --- a/absl/strings/str_join_benchmark.cc +++ b/absl/strings/str_join_benchmark.cc
@@ -13,13 +13,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/strings/str_join.h" - #include <string> #include <tuple> -#include <vector> #include <utility> +#include <vector> +#include "absl/strings/str_join.h" #include "benchmark/benchmark.h" namespace {
diff --git a/absl/strings/str_replace_benchmark.cc b/absl/strings/str_replace_benchmark.cc index 01331da..cbe7572 100644 --- a/absl/strings/str_replace_benchmark.cc +++ b/absl/strings/str_replace_benchmark.cc
@@ -12,13 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/strings/str_replace.h" - #include <cstring> #include <string> -#include "benchmark/benchmark.h" #include "absl/base/internal/raw_logging.h" +#include "absl/strings/str_replace.h" +#include "benchmark/benchmark.h" namespace {
diff --git a/absl/strings/str_split_benchmark.cc b/absl/strings/str_split_benchmark.cc index 003a66b..5a2e953 100644 --- a/absl/strings/str_split_benchmark.cc +++ b/absl/strings/str_split_benchmark.cc
@@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/strings/str_split.h" - #include <cstddef> #include <iterator> #include <string> @@ -21,9 +19,10 @@ #include <unordered_set> #include <vector> -#include "benchmark/benchmark.h" #include "absl/base/internal/raw_logging.h" +#include "absl/strings/str_split.h" #include "absl/strings/string_view.h" +#include "benchmark/benchmark.h" namespace {
diff --git a/absl/strings/string_view_benchmark.cc b/absl/strings/string_view_benchmark.cc index 98f747c..4e36687 100644 --- a/absl/strings/string_view_benchmark.cc +++ b/absl/strings/string_view_benchmark.cc
@@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/strings/string_view.h" - #include <algorithm> #include <cstddef> #include <cstdint> @@ -23,11 +21,12 @@ #include <unordered_set> #include <vector> -#include "benchmark/benchmark.h" #include "absl/base/attributes.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/macros.h" #include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" +#include "benchmark/benchmark.h" namespace {
diff --git a/absl/strings/substitute_benchmark.cc b/absl/strings/substitute_benchmark.cc new file mode 100644 index 0000000..e58ec86 --- /dev/null +++ b/absl/strings/substitute_benchmark.cc
@@ -0,0 +1,158 @@ +// Copyright 2020 The Abseil 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 +// +// https://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. + +#include <cstddef> +#include <cstdint> +#include <string> + +#include "absl/strings/str_cat.h" +#include "absl/strings/substitute.h" +#include "benchmark/benchmark.h" + +namespace { + +void BM_Substitute(benchmark::State& state) { + std::string s(state.range(0), 'x'); + int64_t bytes = 0; + for (auto _ : state) { + std::string result = absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $$", s, + s, s, s, s, s, s, s, s, s); + bytes += result.size(); + } + state.SetBytesProcessed(bytes); +} +BENCHMARK(BM_Substitute)->Range(0, 1024); + +// Like BM_Substitute, but use char* strings (which must then be copied +// to STL strings) for all parameters. This demonstrates that it is faster +// to use absl::Substitute() even if your inputs are char* strings. +void BM_SubstituteCstr(benchmark::State& state) { + std::string s(state.range(0), 'x'); + int64_t bytes = 0; + for (auto _ : state) { + std::string result = + absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $$", s.c_str(), + s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), + s.c_str(), s.c_str(), s.c_str(), s.c_str()); + bytes += result.size(); + } + state.SetBytesProcessed(bytes); +} +BENCHMARK(BM_SubstituteCstr)->Range(0, 1024); + +// For comparison with BM_Substitute. +void BM_StringPrintf(benchmark::State& state) { + std::string s(state.range(0), 'x'); + int64_t bytes = 0; + for (auto _ : state) { + std::string result = absl::StrCat(s, " ", s, " ", s, " ", s, " ", s, " ", s, + " ", s, " ", s, " ", s, " ", s); + bytes += result.size(); + } + state.SetBytesProcessed(bytes); +} +BENCHMARK(BM_StringPrintf)->Range(0, 1024); + +// Benchmark using absl::Substitute() together with SimpleItoa() to print +// numbers. This demonstrates that absl::Substitute() is faster than +// StringPrintf() even when the inputs are numbers. +void BM_SubstituteNumber(benchmark::State& state) { + const int n = state.range(0); + int64_t bytes = 0; + for (auto _ : state) { + std::string result = + absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $$", n, n + 1, n + 2, + n + 3, n + 4, n + 5, n + 6, n + 7, n + 8, n + 9); + bytes += result.size(); + } + state.SetBytesProcessed(bytes); +} +BENCHMARK(BM_SubstituteNumber)->Arg(0)->Arg(1 << 20); + +// For comparison with BM_SubstituteNumber. +void BM_StrCatNumber(benchmark::State& state) { + const int n = state.range(0); + int64_t bytes = 0; + for (auto _ : state) { + std::string result = + absl::StrCat(n, " ", n + 1, " ", n + 2, " ", n + 3, " ", n + 4, " ", + n + 5, " ", n + 6, " ", n + 7, " ", n + 8, " ", n + 9); + bytes += result.size(); + } + state.SetBytesProcessed(bytes); +} +BENCHMARK(BM_StrCatNumber)->Arg(0)->Arg(1 << 20); + +// Benchmark using absl::Substitute() with a single substitution, to test the +// speed at which it copies simple text. Even in this case, it's faster +// that StringPrintf(). +void BM_SubstituteSimpleText(benchmark::State& state) { + std::string s(state.range(0), 'x'); + int64_t bytes = 0; + for (auto _ : state) { + std::string result = absl::Substitute("$0", s.c_str()); + bytes += result.size(); + } + state.SetBytesProcessed(bytes); +} +BENCHMARK(BM_SubstituteSimpleText)->Range(0, 1024); + +// For comparison with BM_SubstituteSimpleText. +void BM_StrCatSimpleText(benchmark::State& state) { + std::string s(state.range(0), 'x'); + int64_t bytes = 0; + for (auto _ : state) { + std::string result = absl::StrCat("", s); + bytes += result.size(); + } + state.SetBytesProcessed(bytes); +} +BENCHMARK(BM_StrCatSimpleText)->Range(0, 1024); + +std::string MakeFormatByDensity(int density, bool subs_mode) { + std::string format((2 + density) * 10, 'x'); + for (size_t i = 0; i < 10; ++i) { + format[density * i] = subs_mode ? '$' : '%'; + format[density * i + 1] = subs_mode ? ('0' + i) : 's'; + } + return format; +} + +void BM_SubstituteDensity(benchmark::State& state) { + const std::string s(10, 'x'); + const std::string format = MakeFormatByDensity(state.range(0), true); + int64_t bytes = 0; + for (auto _ : state) { + std::string result = absl::Substitute(format, s, s, s, s, s, s, s, s, s, s); + bytes += result.size(); + } + state.SetBytesProcessed(bytes); +} +BENCHMARK(BM_SubstituteDensity)->Range(0, 256); + +void BM_StrCatDensity(benchmark::State& state) { + const std::string s(10, 'x'); + const std::string format(state.range(0), 'x'); + int64_t bytes = 0; + for (auto _ : state) { + std::string result = + absl::StrCat(s, format, s, format, s, format, s, format, s, format, s, + format, s, format, s, format, s, format, s, format); + bytes += result.size(); + } + state.SetBytesProcessed(bytes); +} +BENCHMARK(BM_StrCatDensity)->Range(0, 256); + +} // namespace
diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel index 867e986..c3c271e 100644 --- a/absl/synchronization/BUILD.bazel +++ b/absl/synchronization/BUILD.bazel
@@ -140,6 +140,7 @@ "//absl/base:core_headers", "//absl/base:dynamic_annotations", "//absl/base:malloc_internal", + "//absl/base:nullability", "//absl/base:raw_logging_internal", "//absl/base:tracing_internal", "//absl/debugging:stacktrace", @@ -230,7 +231,6 @@ ":graphcycles_internal", "//absl/base:raw_logging_internal", "@google_benchmark//:benchmark_main", - "@googletest//:gtest", ], )
diff --git a/absl/synchronization/CMakeLists.txt b/absl/synchronization/CMakeLists.txt index a745574..4d21067 100644 --- a/absl/synchronization/CMakeLists.txt +++ b/absl/synchronization/CMakeLists.txt
@@ -109,6 +109,7 @@ absl::core_headers absl::dynamic_annotations absl::malloc_internal + absl::nullability absl::raw_logging_internal absl::stacktrace absl::symbolize
diff --git a/absl/synchronization/internal/graphcycles_benchmark.cc b/absl/synchronization/internal/graphcycles_benchmark.cc index 54823e0..9012801 100644 --- a/absl/synchronization/internal/graphcycles_benchmark.cc +++ b/absl/synchronization/internal/graphcycles_benchmark.cc
@@ -12,14 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/synchronization/internal/graphcycles.h" - #include <algorithm> #include <cstdint> #include <vector> -#include "benchmark/benchmark.h" #include "absl/base/internal/raw_logging.h" +#include "absl/synchronization/internal/graphcycles.h" +#include "benchmark/benchmark.h" namespace {
diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h index 9143688..77422a0 100644 --- a/absl/synchronization/mutex.h +++ b/absl/synchronization/mutex.h
@@ -70,6 +70,7 @@ #include "absl/base/internal/low_level_alloc.h" #include "absl/base/internal/thread_identity.h" #include "absl/base/internal/tsan_mutex_interface.h" +#include "absl/base/nullability.h" #include "absl/base/port.h" #include "absl/base/thread_annotations.h" #include "absl/synchronization/internal/kernel_timeout.h" @@ -580,14 +581,15 @@ // Calls `mu->Lock()` and returns when that call returns. That is, `*mu` is // guaranteed to be locked when this object is constructed. Requires that // `mu` be dereferenceable. - explicit MutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) { + explicit MutexLock(Mutex* absl_nonnull mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) + : mu_(mu) { this->mu_->Lock(); } // Like above, but calls `mu->LockWhen(cond)` instead. That is, in addition to // the above, the condition given by `cond` is also guaranteed to hold when // this object is constructed. - explicit MutexLock(Mutex* mu, const Condition& cond) + explicit MutexLock(Mutex* absl_nonnull mu, const Condition& cond) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) { this->mu_->LockWhen(cond); @@ -601,7 +603,7 @@ ~MutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->Unlock(); } private: - Mutex* const mu_; + Mutex* absl_nonnull const mu_; }; // ReaderMutexLock @@ -610,11 +612,12 @@ // releases a shared lock on a `Mutex` via RAII. class ABSL_SCOPED_LOCKABLE ReaderMutexLock { public: - explicit ReaderMutexLock(Mutex* mu) ABSL_SHARED_LOCK_FUNCTION(mu) : mu_(mu) { + explicit ReaderMutexLock(Mutex* absl_nonnull mu) ABSL_SHARED_LOCK_FUNCTION(mu) + : mu_(mu) { mu->ReaderLock(); } - explicit ReaderMutexLock(Mutex* mu, const Condition& cond) + explicit ReaderMutexLock(Mutex* absl_nonnull mu, const Condition& cond) ABSL_SHARED_LOCK_FUNCTION(mu) : mu_(mu) { mu->ReaderLockWhen(cond); @@ -628,7 +631,7 @@ ~ReaderMutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->ReaderUnlock(); } private: - Mutex* const mu_; + Mutex* absl_nonnull const mu_; }; // WriterMutexLock
diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc index 2dc4d73..d8c4fdf 100644 --- a/absl/synchronization/mutex_test.cc +++ b/absl/synchronization/mutex_test.cc
@@ -1725,7 +1725,7 @@ TEST(Mutex, LoggingAddressReuse) { // Repeatedly re-create a Mutex with debug logging at the same address. ScopedInvariantDebugging scoped_debugging; - alignas(absl::Mutex) char storage[sizeof(absl::Mutex)]; + alignas(absl::Mutex) unsigned char storage[sizeof(absl::Mutex)]; auto invariant = +[](void *alive) { EXPECT_TRUE(*static_cast<bool *>(alive)); }; constexpr size_t kIters = 10;
diff --git a/absl/time/BUILD.bazel b/absl/time/BUILD.bazel index b577d92..445bdcc 100644 --- a/absl/time/BUILD.bazel +++ b/absl/time/BUILD.bazel
@@ -131,8 +131,9 @@ ], ) -cc_test( +cc_binary( name = "time_benchmark", + testonly = True, srcs = [ "civil_time_benchmark.cc", "clock_benchmark.cc",