From: Radoslaw Zarzynski Date: Fri, 14 Mar 2025 01:55:58 +0000 (+0000) Subject: common: optimize assert_data_ctx passing in ceph_assert() X-Git-Tag: v20.3.0~189^2~2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=d00fe7ad5ece878da5089907c8990356fd377d52;p=ceph.git common: optimize assert_data_ctx passing in ceph_assert() \### After ``` 0000000000e58600 : e58600: 48 83 ec 18 sub $0x18,%rsp e58604: 48 83 bf e0 00 00 00 cmpq $0x0,0xe0(%rdi) e5860b: 00 e5860c: 0f 84 fc 0f b0 ff je 95960e e58612: 80 bf 40 01 00 00 00 cmpb $0x0,0x140(%rdi) e58619: 0f 84 db 0f b0 ff je 9595fa e5861f: 80 bf 18 01 00 00 00 cmpb $0x0,0x118(%rdi) e58626: 75 08 jne e58630 e58628: 48 83 c4 18 add $0x18,%rsp e5862c: c3 retq e5862d: 0f 1f 00 nopl (%rax) e58630: c6 87 18 01 00 00 00 movb $0x0,0x118(%rdi) e58637: 48 8b bf f8 00 00 00 mov 0xf8(%rdi),%rdi e5863e: 48 83 c4 18 add $0x18,%rsp e58642: e9 89 bc ff ff jmpq e542d0 , std::allocator > > >, std::_Select1st, std::allocator > > > >, std::less, std::allocator, std::allocator > > > > >::_M_erase(std::_Rb_tree_node, std::allocator > > > >*) [clone .isra.0]> e58647: 90 nop e58648: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1) e5864f: 00 ``` \### Vanilla main Loading of `assert_data_ctx` was `unlikely` bot not `cold`: ``` 0000000000e3cf90 : e3cf90: 48 83 ec 08 sub $0x8,%rsp e3cf94: 48 83 bf e0 00 00 00 cmpq $0x0,0xe0(%rdi) e3cf9b: 00 e3cf9c: 74 3d je e3cfdb e3cf9e: 80 bf 40 01 00 00 00 cmpb $0x0,0x140(%rdi) e3cfa5: 74 28 je e3cfcf e3cfa7: 80 bf 18 01 00 00 00 cmpb $0x0,0x118(%rdi) e3cfae: 75 08 jne e3cfb8 e3cfb0: 48 83 c4 08 add $0x8,%rsp e3cfb4: c3 retq e3cfb5: 0f 1f 00 nopl (%rax) e3cfb8: c6 87 18 01 00 00 00 movb $0x0,0x118(%rdi) e3cfbf: 48 8b bf f8 00 00 00 mov 0xf8(%rdi),%rdi e3cfc6: 48 83 c4 08 add $0x8,%rsp e3cfca: e9 01 bd ff ff jmpq e38cd0 , std::allocator > > >, std::_Select1st, std::allocator > > > >, std::less, std::allocator, std::allocator > > > > >::_M_erase(std::_Rb_tree_node, std::allocator > > > >*) [clone .isra.0]> e3cfcf: 48 8d 3d aa 0b 29 01 lea 0x1290baa(%rip),%rdi # 20cdb80 e3cfd6: e8 64 6c b6 ff callq 9a3c3f e3cfdb: 48 8d 3d be 0b 29 01 lea 0x1290bbe(%rip),%rdi # 20cdba0 e3cfe2: e8 58 6c b6 ff callq 9a3c3f e3cfe7: 90 nop e3cfe8: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1) e3cfef: 00 ``` Fixes: https://tracker.ceph.com/issues/70476 Signed-off-by: Radoslaw Zarzynski --- diff --git a/src/include/ceph_assert.h b/src/include/ceph_assert.h index f9dca86d9ff1..f0e87073946b 100644 --- a/src/include/ceph_assert.h +++ b/src/include/ceph_assert.h @@ -52,6 +52,10 @@ struct assert_data { extern void __ceph_assert_fail(const char *assertion, const char *file, int line, const char *function); extern void __ceph_assert_fail(const assert_data &ctx); +template +[[gnu::noinline, gnu::cold]] static void __ceph_assert_fail() { + __ceph_assert_fail(*AssertCtxV); +} extern void __ceph_assertf_fail(const char *assertion, const char *file, int line, const char *function, const char* msg, ...); extern void __ceph_assert_warn(const char *assertion, const char *file, int line, const char *function); @@ -98,11 +102,14 @@ using namespace ceph; } while (false) #else #define ceph_assert(expr) \ - do { static const ceph::assert_data assert_data_ctx = \ - {__STRING(expr), __FILE__, __LINE__, __CEPH_ASSERT_FUNCTION}; \ - ((expr) \ - ? _CEPH_ASSERT_VOID_CAST (0) \ - : ::ceph::__ceph_assert_fail(assert_data_ctx)); } while(false) + do { \ + static const auto func_name = __CEPH_ASSERT_FUNCTION; \ + [] (const bool eval) { \ + static const ceph::assert_data assert_data_ctx = \ + {__STRING(expr), __FILE__, __LINE__, func_name}; \ + ((eval) \ + ? _CEPH_ASSERT_VOID_CAST (0) \ + : ::ceph::__ceph_assert_fail<&assert_data_ctx>()); }((bool)(expr)); } while(false) #endif // this variant will *never* get compiled out to NDEBUG in the future. @@ -116,11 +123,14 @@ using namespace ceph; } while(false) #else #define ceph_assert_always(expr) \ - do { static const ceph::assert_data assert_data_ctx = \ - {__STRING(expr), __FILE__, __LINE__, __CEPH_ASSERT_FUNCTION}; \ - ((expr) \ - ? _CEPH_ASSERT_VOID_CAST (0) \ - : ::ceph::__ceph_assert_fail(assert_data_ctx)); } while(false) + do { \ + static const auto func_name = __CEPH_ASSERT_FUNCTION; \ + [] (const bool eval) { \ + static const ceph::assert_data assert_data_ctx = \ + {__STRING(expr), __FILE__, __LINE__, func_name}; \ + ((eval) \ + ? _CEPH_ASSERT_VOID_CAST (0) \ + : ::ceph::__ceph_assert_fail<&assert_data_ctx>()); }((bool)(expr)); } while(false) #endif // Named by analogy with printf. Along with an expression, takes a format