diff --git a/CHANGELOG b/CHANGELOG index dd1c46371f3..edcf3ba2a18 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -37,7 +37,9 @@ Unreleased: * Added "Expand all" and "Collapse all" to the track menu to expand or collapse a track group and all of its descendants. SDK: - * + * Fixed MSVC hanging while compiling a scoped TRACE_EVENT used inside a + lambda when the legacy lambda processor is in use (C++17 without + /permissive-). See https://github.com/google/perfetto/issues/7591. Misc: * Added the `perfetto_cxx_standard` GN arg (default "c++17") to allow standalone builds to use a newer C++ standard (e.g. "c++20"). diff --git a/include/perfetto/tracing/internal/track_event_data_source.h b/include/perfetto/tracing/internal/track_event_data_source.h index c13f26ac722..09edb22a1f3 100644 --- a/include/perfetto/tracing/internal/track_event_data_source.h +++ b/include/perfetto/tracing/internal/track_event_data_source.h @@ -490,6 +490,24 @@ class TrackEvent { DecayArgType(args)...); } + // Used by PERFETTO_INTERNAL_SCOPED_TRACK_EVENT_END. + static void TraceScopedEventEnd(size_t category_index) + PERFETTO_ALWAYS_INLINE { + CallIfCategoryEnabled(category_index, [category_index](uint32_t instances) { + TraceForCategory(instances, category_index, /*name=*/nullptr, + protos::pbzero::TrackEvent::TYPE_SLICE_END); + }); + } + + template + static void TraceScopedEventEndForDynamicCategory( + const CategoryType& category) PERFETTO_ALWAYS_INLINE { + CallIfEnabled([&category](uint32_t instances) { + TraceForCategory(instances, category, /*name=*/nullptr, + protos::pbzero::TrackEvent::TYPE_SLICE_END); + }); + } + // TraceState overloads template < typename CategoryType, diff --git a/include/perfetto/tracing/internal/track_event_macros.h b/include/perfetto/tracing/internal/track_event_macros.h index 1c0b059889d..14febf30362 100644 --- a/include/perfetto/tracing/internal/track_event_macros.h +++ b/include/perfetto/tracing/internal/track_event_macros.h @@ -160,6 +160,25 @@ } \ } while (false) +// Like TRACE_EVENT_END(category), but without lambdas. A lambda in the scoped +// event finalizer's destructor makes MSVC hang when TRACE_EVENT is used inside +// a lambda (without /permissive-). See +// https://github.com/google/perfetto/issues/7591. +#define PERFETTO_INTERNAL_SCOPED_TRACK_EVENT_END(category) \ + do { \ + namespace tns = PERFETTO_TRACK_EVENT_NAMESPACE; \ + PERFETTO_INTERNAL_STATIC_FOR_MSVC constexpr size_t PERFETTO_UID( \ + kCatIndex_ADD_TO_PERFETTO_DEFINE_CATEGORIES_IF_FAILS_) = \ + PERFETTO_GET_CATEGORY_INDEX(category); \ + if (::PERFETTO_TRACK_EVENT_NAMESPACE::internal::IsDynamicCategory( \ + category)) { \ + tns::TrackEvent::TraceScopedEventEndForDynamicCategory(category); \ + } else { \ + tns::TrackEvent::TraceScopedEventEnd(PERFETTO_UID( \ + kCatIndex_ADD_TO_PERFETTO_DEFINE_CATEGORIES_IF_FAILS_)); \ + } \ + } while (false) + // C++17 doesn't like a move constructor being defined for the EventFinalizer // class but C++11 and MSVC doesn't compile without it being defined so support // both. @@ -181,7 +200,7 @@ /* scope if used in a single line if statement. */ \ EventFinalizer(...) {} \ ~EventFinalizer() { \ - TRACE_EVENT_END(category); \ + PERFETTO_INTERNAL_SCOPED_TRACK_EVENT_END(category); \ } \ \ EventFinalizer(const EventFinalizer&) = delete; \ diff --git a/src/tracing/test/api_integrationtest.cc b/src/tracing/test/api_integrationtest.cc index 0e46ca97532..b958c3877e1 100644 --- a/src/tracing/test/api_integrationtest.cc +++ b/src/tracing/test/api_integrationtest.cc @@ -3852,6 +3852,29 @@ TEST_P(PerfettoApiTest, TrackEventScoped) { "E", "B:test.TestEvent", "B:test.AnotherEvent", "E", "E")); } +// Regression test for https://github.com/google/perfetto/issues/7591. +TEST_P(PerfettoApiTest, TrackEventScopedInsideLambda) { + auto* tracing_session = NewTraceWithCategories({"test"}); + tracing_session->get()->StartBlocking(); + + auto simple = []() { TRACE_EVENT("test", "InLambda"); }; + simple(); + + auto with_args = [](uint64_t arg) { + TRACE_EVENT("test", "InLambdaWithArgs", [&](perfetto::EventContext ctx) { + ctx.event()->set_log_message()->set_body_iid(arg); + }); + }; + with_args(123); + + auto disabled = []() { TRACE_EVENT("foo", "DisabledEvent"); }; + disabled(); + + auto slices = StopSessionAndReadSlicesFromTrace(tracing_session); + EXPECT_THAT(slices, ElementsAre("B:test.InLambda", "E", + "B:test.InLambdaWithArgs", "E")); +} + // A class similar to what Protozero generates for extended message. class TestTrackEvent : public perfetto::protos::pbzero::TrackEvent { public: