[latency] New latency visualization tool (#36964)

Adds a build config - latent_see - that configures a module and some macros to allow recording of latency information through the stack and across threads. One can then use tools that understand the chromium event trace format (eg `ui.perfetto.dev`) to visualize the traces.

![image](https://github.com/grpc/grpc/assets/10120821/d936ac0c-7be0-4572-a62b-826b29344421)

Closes #36964

COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/36964 from ctiller:latent-see 2c109f9575
PiperOrigin-RevId: 647455107
pull/37081/head
Craig Tiller 5 months ago committed by Copybara-Service
parent e7727bc223
commit e1b61766fc
  1. 4
      BUILD
  2. 36
      CMakeLists.txt
  3. 1
      Makefile
  4. 2
      Package.swift
  5. 72
      build_autogenerated.yaml
  6. 1
      config.m4
  7. 1
      config.w32
  8. 10
      doc/core/latent_see.md
  9. 2
      gRPC-C++.podspec
  10. 3
      gRPC-Core.podspec
  11. 2
      grpc.gemspec
  12. 2
      package.xml
  13. 21
      src/core/BUILD
  14. 6
      src/core/lib/gprpp/work_serializer.cc
  15. 6
      src/core/lib/promise/activity.h
  16. 3
      src/core/lib/promise/party.cc
  17. 2
      src/core/lib/surface/client_call.cc
  18. 113
      src/core/util/latent_see.cc
  19. 214
      src/core/util/latent_see.h
  20. 1
      src/python/grpcio/grpc_core_dependencies.py
  21. 2
      tools/bazel.rc
  22. 2
      tools/doxygen/Doxyfile.c++.internal
  23. 1
      tools/doxygen/Doxyfile.core
  24. 3
      tools/doxygen/Doxyfile.core.internal

@ -2090,6 +2090,7 @@ grpc_cc_library(
"//src/core:if",
"//src/core:iomgr_fwd",
"//src/core:latch",
"//src/core:latent_see",
"//src/core:loop",
"//src/core:map",
"//src/core:match",
@ -3009,8 +3010,8 @@ grpc_cc_library(
external_deps = [
"absl/base:core_headers",
"absl/container:inlined_vector",
"absl/log",
"absl/log:check",
"absl/log:log",
],
language = "c++",
visibility = ["@grpc:client_channel"],
@ -3023,6 +3024,7 @@ grpc_cc_library(
"orphanable",
"stats",
"//src/core:experiments",
"//src/core:latent_see",
"//src/core:stats_data",
],
)

36
CMakeLists.txt generated

@ -2647,6 +2647,7 @@ add_library(grpc
src/core/util/json/json_reader.cc
src/core/util/json/json_util.cc
src/core/util/json/json_writer.cc
src/core/util/latent_see.cc
src/core/xds/grpc/certificate_provider_store.cc
src/core/xds/grpc/file_watcher_certificate_provider_factory.cc
src/core/xds/grpc/xds_audit_logger_registry.cc
@ -3363,6 +3364,7 @@ add_library(grpc_unsecure
src/core/util/json/json_object_loader.cc
src/core/util/json/json_reader.cc
src/core/util/json/json_writer.cc
src/core/util/latent_see.cc
third_party/upb/upb/mini_descriptor/build_enum.c
third_party/upb/upb/mini_descriptor/decode.c
third_party/upb/upb/mini_descriptor/internal/base92.c
@ -5441,6 +5443,7 @@ add_library(grpc_authorization_provider
src/core/tsi/transport_security_grpc.cc
src/core/util/json/json_reader.cc
src/core/util/json/json_writer.cc
src/core/util/latent_see.cc
third_party/upb/upb/mini_descriptor/build_enum.c
third_party/upb/upb/mini_descriptor/decode.c
third_party/upb/upb/mini_descriptor/internal/base92.c
@ -6376,7 +6379,9 @@ add_executable(activity_test
src/core/lib/debug/trace_flags.cc
src/core/lib/gprpp/dump_args.cc
src/core/lib/gprpp/glob.cc
src/core/lib/gprpp/per_cpu.cc
src/core/lib/promise/activity.cc
src/core/util/latent_see.cc
test/core/promise/activity_test.cc
)
if(WIN32 AND MSVC)
@ -8938,6 +8943,7 @@ add_executable(call_filters_test
src/core/lib/experiments/experiments.cc
src/core/lib/gprpp/dump_args.cc
src/core/lib/gprpp/glob.cc
src/core/lib/gprpp/per_cpu.cc
src/core/lib/gprpp/ref_counted_string.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
@ -8969,6 +8975,7 @@ add_executable(call_filters_test
src/core/lib/transport/parsed_metadata.cc
src/core/lib/transport/status_conversion.cc
src/core/lib/transport/timeout_encoding.cc
src/core/util/latent_see.cc
test/core/transport/call_filters_test.cc
third_party/upb/upb/mini_descriptor/build_enum.c
third_party/upb/upb/mini_descriptor/decode.c
@ -9193,8 +9200,10 @@ add_executable(call_state_test
src/core/lib/debug/trace_flags.cc
src/core/lib/gprpp/dump_args.cc
src/core/lib/gprpp/glob.cc
src/core/lib/gprpp/per_cpu.cc
src/core/lib/promise/activity.cc
src/core/lib/transport/call_state.cc
src/core/util/latent_see.cc
test/core/transport/call_state_test.cc
)
if(WIN32 AND MSVC)
@ -9517,6 +9526,7 @@ add_executable(call_utils_test
src/core/telemetry/stats_data.cc
src/core/tsi/alts/handshaker/transport_security_common_api.cc
src/core/util/json/json_writer.cc
src/core/util/latent_see.cc
test/core/call/call_utils_test.cc
third_party/upb/upb/mini_descriptor/build_enum.c
third_party/upb/upb/mini_descriptor/decode.c
@ -9954,6 +9964,7 @@ add_executable(cancel_callback_test
src/core/lib/experiments/experiments.cc
src/core/lib/gprpp/dump_args.cc
src/core/lib/gprpp/glob.cc
src/core/lib/gprpp/per_cpu.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/iomgr/closure.cc
@ -9972,6 +9983,7 @@ add_executable(cancel_callback_test
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/util/latent_see.cc
test/core/promise/cancel_callback_test.cc
third_party/upb/upb/mini_descriptor/build_enum.c
third_party/upb/upb/mini_descriptor/decode.c
@ -11062,6 +11074,7 @@ add_executable(chunked_vector_test
src/core/lib/experiments/experiments.cc
src/core/lib/gprpp/dump_args.cc
src/core/lib/gprpp/glob.cc
src/core/lib/gprpp/per_cpu.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/iomgr/closure.cc
@ -11080,6 +11093,7 @@ add_executable(chunked_vector_test
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/util/latent_see.cc
test/core/gprpp/chunked_vector_test.cc
third_party/upb/upb/mini_descriptor/build_enum.c
third_party/upb/upb/mini_descriptor/decode.c
@ -14372,6 +14386,7 @@ add_executable(exec_ctx_wakeup_scheduler_test
src/core/lib/experiments/experiments.cc
src/core/lib/gprpp/dump_args.cc
src/core/lib/gprpp/glob.cc
src/core/lib/gprpp/per_cpu.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/iomgr/closure.cc
@ -14384,6 +14399,7 @@ add_executable(exec_ctx_wakeup_scheduler_test
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/util/latent_see.cc
test/core/promise/exec_ctx_wakeup_scheduler_test.cc
third_party/upb/upb/mini_descriptor/build_enum.c
third_party/upb/upb/mini_descriptor/decode.c
@ -15173,6 +15189,7 @@ add_executable(flow_control_test
src/core/lib/experiments/experiments.cc
src/core/lib/gprpp/dump_args.cc
src/core/lib/gprpp/glob.cc
src/core/lib/gprpp/per_cpu.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/iomgr/closure.cc
@ -15192,6 +15209,7 @@ add_executable(flow_control_test
src/core/lib/slice/slice_buffer.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/lib/transport/bdp_estimator.cc
src/core/util/latent_see.cc
test/core/transport/chttp2/flow_control_test.cc
third_party/upb/upb/mini_descriptor/build_enum.c
third_party/upb/upb/mini_descriptor/decode.c
@ -15260,6 +15278,7 @@ add_executable(for_each_test
src/core/lib/experiments/experiments.cc
src/core/lib/gprpp/dump_args.cc
src/core/lib/gprpp/glob.cc
src/core/lib/gprpp/per_cpu.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/iomgr/closure.cc
@ -15278,6 +15297,7 @@ add_executable(for_each_test
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/util/latent_see.cc
test/core/promise/for_each_test.cc
third_party/upb/upb/mini_descriptor/build_enum.c
third_party/upb/upb/mini_descriptor/decode.c
@ -18708,7 +18728,9 @@ add_executable(inter_activity_pipe_test
src/core/lib/debug/trace_flags.cc
src/core/lib/gprpp/dump_args.cc
src/core/lib/gprpp/glob.cc
src/core/lib/gprpp/per_cpu.cc
src/core/lib/promise/activity.cc
src/core/util/latent_see.cc
test/core/promise/inter_activity_pipe_test.cc
)
if(WIN32 AND MSVC)
@ -18805,6 +18827,7 @@ add_executable(interceptor_list_test
src/core/lib/experiments/experiments.cc
src/core/lib/gprpp/dump_args.cc
src/core/lib/gprpp/glob.cc
src/core/lib/gprpp/per_cpu.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/iomgr/closure.cc
@ -18823,6 +18846,7 @@ add_executable(interceptor_list_test
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/util/latent_see.cc
test/core/promise/interceptor_list_test.cc
third_party/upb/upb/mini_descriptor/build_enum.c
third_party/upb/upb/mini_descriptor/decode.c
@ -19598,7 +19622,9 @@ add_executable(latch_test
src/core/lib/debug/trace_flags.cc
src/core/lib/gprpp/dump_args.cc
src/core/lib/gprpp/glob.cc
src/core/lib/gprpp/per_cpu.cc
src/core/lib/promise/activity.cc
src/core/util/latent_see.cc
test/core/promise/latch_test.cc
)
if(WIN32 AND MSVC)
@ -20017,6 +20043,7 @@ add_executable(map_pipe_test
src/core/lib/experiments/experiments.cc
src/core/lib/gprpp/dump_args.cc
src/core/lib/gprpp/glob.cc
src/core/lib/gprpp/per_cpu.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/iomgr/closure.cc
@ -20035,6 +20062,7 @@ add_executable(map_pipe_test
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/util/latent_see.cc
test/core/promise/map_pipe_test.cc
third_party/upb/upb/mini_descriptor/build_enum.c
third_party/upb/upb/mini_descriptor/decode.c
@ -21004,7 +21032,9 @@ add_executable(mpsc_test
src/core/lib/debug/trace_flags.cc
src/core/lib/gprpp/dump_args.cc
src/core/lib/gprpp/glob.cc
src/core/lib/gprpp/per_cpu.cc
src/core/lib/promise/activity.cc
src/core/util/latent_see.cc
test/core/promise/mpsc_test.cc
)
if(WIN32 AND MSVC)
@ -21505,7 +21535,9 @@ add_executable(observable_test
src/core/lib/debug/trace_flags.cc
src/core/lib/gprpp/dump_args.cc
src/core/lib/gprpp/glob.cc
src/core/lib/gprpp/per_cpu.cc
src/core/lib/promise/activity.cc
src/core/util/latent_see.cc
test/core/promise/observable_test.cc
)
if(WIN32 AND MSVC)
@ -23388,7 +23420,9 @@ add_executable(promise_mutex_test
src/core/lib/debug/trace_flags.cc
src/core/lib/gprpp/dump_args.cc
src/core/lib/gprpp/glob.cc
src/core/lib/gprpp/per_cpu.cc
src/core/lib/promise/activity.cc
src/core/util/latent_see.cc
test/core/promise/promise_mutex_test.cc
)
if(WIN32 AND MSVC)
@ -33153,7 +33187,9 @@ add_executable(wait_for_callback_test
src/core/lib/debug/trace_flags.cc
src/core/lib/gprpp/dump_args.cc
src/core/lib/gprpp/glob.cc
src/core/lib/gprpp/per_cpu.cc
src/core/lib/promise/activity.cc
src/core/util/latent_see.cc
test/core/promise/wait_for_callback_test.cc
)
if(WIN32 AND MSVC)

1
Makefile generated

@ -1461,6 +1461,7 @@ LIBGRPC_SRC = \
src/core/util/json/json_reader.cc \
src/core/util/json/json_util.cc \
src/core/util/json/json_writer.cc \
src/core/util/latent_see.cc \
src/core/util/linux/cpu.cc \
src/core/util/linux/log.cc \
src/core/util/log.cc \

2
Package.swift generated

@ -1931,6 +1931,8 @@ let package = Package(
"src/core/util/json/json_util.h",
"src/core/util/json/json_writer.cc",
"src/core/util/json/json_writer.h",
"src/core/util/latent_see.cc",
"src/core/util/latent_see.h",
"src/core/util/linux/cpu.cc",
"src/core/util/linux/log.cc",
"src/core/util/log.cc",

@ -1217,6 +1217,7 @@ libs:
- src/core/util/json/json_reader.h
- src/core/util/json/json_util.h
- src/core/util/json/json_writer.h
- src/core/util/latent_see.h
- src/core/util/spinlock.h
- src/core/util/upb_utils.h
- src/core/xds/grpc/certificate_provider_store.h
@ -2023,6 +2024,7 @@ libs:
- src/core/util/json/json_reader.cc
- src/core/util/json/json_util.cc
- src/core/util/json/json_writer.cc
- src/core/util/latent_see.cc
- src/core/xds/grpc/certificate_provider_store.cc
- src/core/xds/grpc/file_watcher_certificate_provider_factory.cc
- src/core/xds/grpc/xds_audit_logger_registry.cc
@ -2690,6 +2692,7 @@ libs:
- src/core/util/json/json_object_loader.h
- src/core/util/json/json_reader.h
- src/core/util/json/json_writer.h
- src/core/util/latent_see.h
- src/core/util/spinlock.h
- src/core/util/upb_utils.h
- third_party/upb/upb/generated_code_support.h
@ -3105,6 +3108,7 @@ libs:
- src/core/util/json/json_object_loader.cc
- src/core/util/json/json_reader.cc
- src/core/util/json/json_writer.cc
- src/core/util/latent_see.cc
- third_party/upb/upb/mini_descriptor/build_enum.c
- third_party/upb/upb/mini_descriptor/decode.c
- third_party/upb/upb/mini_descriptor/internal/base92.c
@ -4750,6 +4754,7 @@ libs:
- src/core/util/json/json_args.h
- src/core/util/json/json_reader.h
- src/core/util/json/json_writer.h
- src/core/util/latent_see.h
- src/core/util/spinlock.h
- third_party/upb/upb/generated_code_support.h
- third_party/upb/upb/mini_descriptor/build_enum.h
@ -5035,6 +5040,7 @@ libs:
- src/core/tsi/transport_security_grpc.cc
- src/core/util/json/json_reader.cc
- src/core/util/json/json_writer.cc
- src/core/util/latent_see.cc
- third_party/upb/upb/mini_descriptor/build_enum.c
- third_party/upb/upb/mini_descriptor/decode.c
- third_party/upb/upb/mini_descriptor/internal/base92.c
@ -5433,6 +5439,7 @@ targets:
- src/core/lib/gprpp/dump_args.h
- src/core/lib/gprpp/glob.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/per_cpu.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/promise/activity.h
@ -5449,13 +5456,16 @@ targets:
- src/core/lib/promise/promise.h
- src/core/lib/promise/seq.h
- src/core/lib/promise/wait_set.h
- src/core/util/latent_see.h
- test/core/promise/test_wakeup_schedulers.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/debug/trace_flags.cc
- src/core/lib/gprpp/dump_args.cc
- src/core/lib/gprpp/glob.cc
- src/core/lib/gprpp/per_cpu.cc
- src/core/lib/promise/activity.cc
- src/core/util/latent_see.cc
- test/core/promise/activity_test.cc
deps:
- gtest
@ -6614,6 +6624,7 @@ targets:
- src/core/lib/gprpp/manual_constructor.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/packed_table.h
- src/core/lib/gprpp/per_cpu.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/gprpp/ref_counted_string.h
@ -6674,6 +6685,7 @@ targets:
- src/core/lib/transport/simple_slice_based_metadata.h
- src/core/lib/transport/status_conversion.h
- src/core/lib/transport/timeout_encoding.h
- src/core/util/latent_see.h
- src/core/util/spinlock.h
- test/core/promise/poll_matcher.h
- third_party/upb/upb/generated_code_support.h
@ -6707,6 +6719,7 @@ targets:
- src/core/lib/experiments/experiments.cc
- src/core/lib/gprpp/dump_args.cc
- src/core/lib/gprpp/glob.cc
- src/core/lib/gprpp/per_cpu.cc
- src/core/lib/gprpp/ref_counted_string.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
@ -6738,6 +6751,7 @@ targets:
- src/core/lib/transport/parsed_metadata.cc
- src/core/lib/transport/status_conversion.cc
- src/core/lib/transport/timeout_encoding.cc
- src/core/util/latent_see.cc
- test/core/transport/call_filters_test.cc
- third_party/upb/upb/mini_descriptor/build_enum.c
- third_party/upb/upb/mini_descriptor/decode.c
@ -6875,6 +6889,7 @@ targets:
- src/core/lib/gprpp/dump_args.h
- src/core/lib/gprpp/glob.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/per_cpu.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/promise/activity.h
@ -6885,14 +6900,17 @@ targets:
- src/core/lib/promise/poll.h
- src/core/lib/promise/status_flag.h
- src/core/lib/transport/call_state.h
- src/core/util/latent_see.h
- test/core/promise/poll_matcher.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/debug/trace_flags.cc
- src/core/lib/gprpp/dump_args.cc
- src/core/lib/gprpp/glob.cc
- src/core/lib/gprpp/per_cpu.cc
- src/core/lib/promise/activity.cc
- src/core/lib/transport/call_state.cc
- src/core/util/latent_see.cc
- test/core/transport/call_state_test.cc
deps:
- gtest
@ -7227,6 +7245,7 @@ targets:
- src/core/util/json/json.h
- src/core/util/json/json_args.h
- src/core/util/json/json_writer.h
- src/core/util/latent_see.h
- src/core/util/spinlock.h
- third_party/upb/upb/generated_code_support.h
- third_party/upb/upb/mini_descriptor/build_enum.h
@ -7481,6 +7500,7 @@ targets:
- src/core/telemetry/stats_data.cc
- src/core/tsi/alts/handshaker/transport_security_common_api.cc
- src/core/util/json/json_writer.cc
- src/core/util/latent_see.cc
- test/core/call/call_utils_test.cc
- third_party/upb/upb/mini_descriptor/build_enum.c
- third_party/upb/upb/mini_descriptor/decode.c
@ -7870,6 +7890,7 @@ targets:
- src/core/lib/gprpp/glob.h
- src/core/lib/gprpp/manual_constructor.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/per_cpu.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/gprpp/status_helper.h
@ -7905,6 +7926,7 @@ targets:
- src/core/lib/slice/slice_internal.h
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/util/latent_see.h
- src/core/util/spinlock.h
- third_party/upb/upb/generated_code_support.h
- third_party/upb/upb/mini_descriptor/build_enum.h
@ -7934,6 +7956,7 @@ targets:
- src/core/lib/experiments/experiments.cc
- src/core/lib/gprpp/dump_args.cc
- src/core/lib/gprpp/glob.cc
- src/core/lib/gprpp/per_cpu.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/iomgr/closure.cc
@ -7952,6 +7975,7 @@ targets:
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_string_helpers.cc
- src/core/util/latent_see.cc
- test/core/promise/cancel_callback_test.cc
- third_party/upb/upb/mini_descriptor/build_enum.c
- third_party/upb/upb/mini_descriptor/decode.c
@ -8690,6 +8714,7 @@ targets:
- src/core/lib/gprpp/glob.h
- src/core/lib/gprpp/manual_constructor.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/per_cpu.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/gprpp/status_helper.h
@ -8724,6 +8749,7 @@ targets:
- src/core/lib/slice/slice_internal.h
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/util/latent_see.h
- src/core/util/spinlock.h
- third_party/upb/upb/generated_code_support.h
- third_party/upb/upb/mini_descriptor/build_enum.h
@ -8753,6 +8779,7 @@ targets:
- src/core/lib/experiments/experiments.cc
- src/core/lib/gprpp/dump_args.cc
- src/core/lib/gprpp/glob.cc
- src/core/lib/gprpp/per_cpu.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/iomgr/closure.cc
@ -8771,6 +8798,7 @@ targets:
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_string_helpers.cc
- src/core/util/latent_see.cc
- test/core/gprpp/chunked_vector_test.cc
- third_party/upb/upb/mini_descriptor/build_enum.c
- third_party/upb/upb/mini_descriptor/decode.c
@ -10274,6 +10302,7 @@ targets:
- src/core/lib/gprpp/glob.h
- src/core/lib/gprpp/manual_constructor.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/per_cpu.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/gprpp/status_helper.h
@ -10296,6 +10325,7 @@ targets:
- src/core/lib/slice/slice_internal.h
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/util/latent_see.h
- src/core/util/spinlock.h
- third_party/upb/upb/generated_code_support.h
- third_party/upb/upb/mini_descriptor/build_enum.h
@ -10325,6 +10355,7 @@ targets:
- src/core/lib/experiments/experiments.cc
- src/core/lib/gprpp/dump_args.cc
- src/core/lib/gprpp/glob.cc
- src/core/lib/gprpp/per_cpu.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/iomgr/closure.cc
@ -10337,6 +10368,7 @@ targets:
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_string_helpers.cc
- src/core/util/latent_see.cc
- test/core/promise/exec_ctx_wakeup_scheduler_test.cc
- third_party/upb/upb/mini_descriptor/build_enum.c
- third_party/upb/upb/mini_descriptor/decode.c
@ -10834,6 +10866,7 @@ targets:
- src/core/lib/gprpp/glob.h
- src/core/lib/gprpp/manual_constructor.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/per_cpu.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/gprpp/status_helper.h
@ -10870,6 +10903,7 @@ targets:
- src/core/lib/slice/slice_string_helpers.h
- src/core/lib/transport/bdp_estimator.h
- src/core/lib/transport/http2_errors.h
- src/core/util/latent_see.h
- src/core/util/spinlock.h
- third_party/upb/upb/generated_code_support.h
- third_party/upb/upb/mini_descriptor/build_enum.h
@ -10902,6 +10936,7 @@ targets:
- src/core/lib/experiments/experiments.cc
- src/core/lib/gprpp/dump_args.cc
- src/core/lib/gprpp/glob.cc
- src/core/lib/gprpp/per_cpu.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/iomgr/closure.cc
@ -10921,6 +10956,7 @@ targets:
- src/core/lib/slice/slice_buffer.cc
- src/core/lib/slice/slice_string_helpers.cc
- src/core/lib/transport/bdp_estimator.cc
- src/core/util/latent_see.cc
- test/core/transport/chttp2/flow_control_test.cc
- third_party/upb/upb/mini_descriptor/build_enum.c
- third_party/upb/upb/mini_descriptor/decode.c
@ -10967,6 +11003,7 @@ targets:
- src/core/lib/gprpp/glob.h
- src/core/lib/gprpp/manual_constructor.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/per_cpu.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/gprpp/status_helper.h
@ -11010,6 +11047,7 @@ targets:
- src/core/lib/slice/slice_internal.h
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/util/latent_see.h
- src/core/util/spinlock.h
- test/core/promise/test_wakeup_schedulers.h
- third_party/upb/upb/generated_code_support.h
@ -11040,6 +11078,7 @@ targets:
- src/core/lib/experiments/experiments.cc
- src/core/lib/gprpp/dump_args.cc
- src/core/lib/gprpp/glob.cc
- src/core/lib/gprpp/per_cpu.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/iomgr/closure.cc
@ -11058,6 +11097,7 @@ targets:
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_string_helpers.cc
- src/core/util/latent_see.cc
- test/core/promise/for_each_test.cc
- third_party/upb/upb/mini_descriptor/build_enum.c
- third_party/upb/upb/mini_descriptor/decode.c
@ -12606,6 +12646,7 @@ targets:
- src/core/lib/gprpp/dump_args.h
- src/core/lib/gprpp/glob.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/per_cpu.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/promise/activity.h
@ -12618,13 +12659,16 @@ targets:
- src/core/lib/promise/inter_activity_pipe.h
- src/core/lib/promise/poll.h
- src/core/lib/promise/seq.h
- src/core/util/latent_see.h
- test/core/promise/test_wakeup_schedulers.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/debug/trace_flags.cc
- src/core/lib/gprpp/dump_args.cc
- src/core/lib/gprpp/glob.cc
- src/core/lib/gprpp/per_cpu.cc
- src/core/lib/promise/activity.cc
- src/core/util/latent_see.cc
- test/core/promise/inter_activity_pipe_test.cc
deps:
- gtest
@ -12669,6 +12713,7 @@ targets:
- src/core/lib/gprpp/glob.h
- src/core/lib/gprpp/manual_constructor.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/per_cpu.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/gprpp/status_helper.h
@ -12704,6 +12749,7 @@ targets:
- src/core/lib/slice/slice_internal.h
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/util/latent_see.h
- src/core/util/spinlock.h
- test/core/promise/test_context.h
- third_party/upb/upb/generated_code_support.h
@ -12734,6 +12780,7 @@ targets:
- src/core/lib/experiments/experiments.cc
- src/core/lib/gprpp/dump_args.cc
- src/core/lib/gprpp/glob.cc
- src/core/lib/gprpp/per_cpu.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/iomgr/closure.cc
@ -12752,6 +12799,7 @@ targets:
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_string_helpers.cc
- src/core/util/latent_see.cc
- test/core/promise/interceptor_list_test.cc
- third_party/upb/upb/mini_descriptor/build_enum.c
- third_party/upb/upb/mini_descriptor/decode.c
@ -13185,6 +13233,7 @@ targets:
- src/core/lib/gprpp/dump_args.h
- src/core/lib/gprpp/glob.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/per_cpu.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/promise/activity.h
@ -13200,13 +13249,16 @@ targets:
- src/core/lib/promise/map.h
- src/core/lib/promise/poll.h
- src/core/lib/promise/seq.h
- src/core/util/latent_see.h
- test/core/promise/test_wakeup_schedulers.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/debug/trace_flags.cc
- src/core/lib/gprpp/dump_args.cc
- src/core/lib/gprpp/glob.cc
- src/core/lib/gprpp/per_cpu.cc
- src/core/lib/promise/activity.cc
- src/core/util/latent_see.cc
- test/core/promise/latch_test.cc
deps:
- gtest
@ -13375,6 +13427,7 @@ targets:
- src/core/lib/gprpp/glob.h
- src/core/lib/gprpp/manual_constructor.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/per_cpu.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/gprpp/status_helper.h
@ -13418,6 +13471,7 @@ targets:
- src/core/lib/slice/slice_internal.h
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/util/latent_see.h
- src/core/util/spinlock.h
- test/core/promise/test_wakeup_schedulers.h
- third_party/upb/upb/generated_code_support.h
@ -13448,6 +13502,7 @@ targets:
- src/core/lib/experiments/experiments.cc
- src/core/lib/gprpp/dump_args.cc
- src/core/lib/gprpp/glob.cc
- src/core/lib/gprpp/per_cpu.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/iomgr/closure.cc
@ -13466,6 +13521,7 @@ targets:
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_string_helpers.cc
- src/core/util/latent_see.cc
- test/core/promise/map_pipe_test.cc
- third_party/upb/upb/mini_descriptor/build_enum.c
- third_party/upb/upb/mini_descriptor/decode.c
@ -13985,6 +14041,7 @@ targets:
- src/core/lib/gprpp/dump_args.h
- src/core/lib/gprpp/glob.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/per_cpu.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/promise/activity.h
@ -13996,13 +14053,16 @@ targets:
- src/core/lib/promise/poll.h
- src/core/lib/promise/promise.h
- src/core/lib/promise/wait_set.h
- src/core/util/latent_see.h
- test/core/promise/poll_matcher.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/debug/trace_flags.cc
- src/core/lib/gprpp/dump_args.cc
- src/core/lib/gprpp/glob.cc
- src/core/lib/gprpp/per_cpu.cc
- src/core/lib/promise/activity.cc
- src/core/util/latent_see.cc
- test/core/promise/mpsc_test.cc
deps:
- gtest
@ -14294,6 +14354,7 @@ targets:
- src/core/lib/gprpp/glob.h
- src/core/lib/gprpp/notification.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/per_cpu.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/promise/activity.h
@ -14305,13 +14366,16 @@ targets:
- src/core/lib/promise/map.h
- src/core/lib/promise/observable.h
- src/core/lib/promise/poll.h
- src/core/util/latent_see.h
- test/core/promise/poll_matcher.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/debug/trace_flags.cc
- src/core/lib/gprpp/dump_args.cc
- src/core/lib/gprpp/glob.cc
- src/core/lib/gprpp/per_cpu.cc
- src/core/lib/promise/activity.cc
- src/core/util/latent_see.cc
- test/core/promise/observable_test.cc
deps:
- gtest
@ -15228,6 +15292,7 @@ targets:
- src/core/lib/gprpp/dump_args.h
- src/core/lib/gprpp/glob.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/per_cpu.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/promise/activity.h
@ -15244,13 +15309,16 @@ targets:
- src/core/lib/promise/promise.h
- src/core/lib/promise/promise_mutex.h
- src/core/lib/promise/seq.h
- src/core/util/latent_see.h
- test/core/promise/test_wakeup_schedulers.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/debug/trace_flags.cc
- src/core/lib/gprpp/dump_args.cc
- src/core/lib/gprpp/glob.cc
- src/core/lib/gprpp/per_cpu.cc
- src/core/lib/promise/activity.cc
- src/core/util/latent_see.cc
- test/core/promise/promise_mutex_test.cc
deps:
- gtest
@ -21013,6 +21081,7 @@ targets:
- src/core/lib/gprpp/glob.h
- src/core/lib/gprpp/notification.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/per_cpu.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/promise/activity.h
@ -21023,13 +21092,16 @@ targets:
- src/core/lib/promise/map.h
- src/core/lib/promise/poll.h
- src/core/lib/promise/wait_for_callback.h
- src/core/util/latent_see.h
- test/core/promise/test_wakeup_schedulers.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/debug/trace_flags.cc
- src/core/lib/gprpp/dump_args.cc
- src/core/lib/gprpp/glob.cc
- src/core/lib/gprpp/per_cpu.cc
- src/core/lib/promise/activity.cc
- src/core/util/latent_see.cc
- test/core/promise/wait_for_callback_test.cc
deps:
- gtest

1
config.m4 generated

@ -836,6 +836,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/util/json/json_reader.cc \
src/core/util/json/json_util.cc \
src/core/util/json/json_writer.cc \
src/core/util/latent_see.cc \
src/core/util/linux/cpu.cc \
src/core/util/linux/log.cc \
src/core/util/log.cc \

1
config.w32 generated

@ -801,6 +801,7 @@ if (PHP_GRPC != "no") {
"src\\core\\util\\json\\json_reader.cc " +
"src\\core\\util\\json\\json_util.cc " +
"src\\core\\util\\json\\json_writer.cc " +
"src\\core\\util\\latent_see.cc " +
"src\\core\\util\\linux\\cpu.cc " +
"src\\core\\util\\linux\\log.cc " +
"src\\core\\util\\log.cc " +

@ -0,0 +1,10 @@
Latent-see
----------
This is a simple latency profiling tool.
We record various timestamps throughout program execution, and then at exit format json
to a file `latent_see.json` in the chrome event trace format. This format can be
consumed by various tools (eg ui.perfetto.dev).
Recording macros are documented in latent_see.h.

2
gRPC-C++.podspec generated

@ -1321,6 +1321,7 @@ Pod::Spec.new do |s|
'src/core/util/json/json_reader.h',
'src/core/util/json/json_util.h',
'src/core/util/json/json_writer.h',
'src/core/util/latent_see.h',
'src/core/util/spinlock.h',
'src/core/util/string.h',
'src/core/util/time_precise.h',
@ -2596,6 +2597,7 @@ Pod::Spec.new do |s|
'src/core/util/json/json_reader.h',
'src/core/util/json/json_util.h',
'src/core/util/json/json_writer.h',
'src/core/util/latent_see.h',
'src/core/util/spinlock.h',
'src/core/util/string.h',
'src/core/util/time_precise.h',

3
gRPC-Core.podspec generated

@ -2046,6 +2046,8 @@ Pod::Spec.new do |s|
'src/core/util/json/json_util.h',
'src/core/util/json/json_writer.cc',
'src/core/util/json/json_writer.h',
'src/core/util/latent_see.cc',
'src/core/util/latent_see.h',
'src/core/util/linux/cpu.cc',
'src/core/util/linux/log.cc',
'src/core/util/log.cc',
@ -3369,6 +3371,7 @@ Pod::Spec.new do |s|
'src/core/util/json/json_reader.h',
'src/core/util/json/json_util.h',
'src/core/util/json/json_writer.h',
'src/core/util/latent_see.h',
'src/core/util/spinlock.h',
'src/core/util/string.h',
'src/core/util/time_precise.h',

2
grpc.gemspec generated

@ -1933,6 +1933,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/util/json/json_util.h )
s.files += %w( src/core/util/json/json_writer.cc )
s.files += %w( src/core/util/json/json_writer.h )
s.files += %w( src/core/util/latent_see.cc )
s.files += %w( src/core/util/latent_see.h )
s.files += %w( src/core/util/linux/cpu.cc )
s.files += %w( src/core/util/linux/log.cc )
s.files += %w( src/core/util/log.cc )

2
package.xml generated

@ -1915,6 +1915,8 @@
<file baseinstalldir="/" name="src/core/util/json/json_util.h" role="src" />
<file baseinstalldir="/" name="src/core/util/json/json_writer.cc" role="src" />
<file baseinstalldir="/" name="src/core/util/json/json_writer.h" role="src" />
<file baseinstalldir="/" name="src/core/util/latent_see.cc" role="src" />
<file baseinstalldir="/" name="src/core/util/latent_see.h" role="src" />
<file baseinstalldir="/" name="src/core/util/linux/cpu.cc" role="src" />
<file baseinstalldir="/" name="src/core/util/linux/log.cc" role="src" />
<file baseinstalldir="/" name="src/core/util/log.cc" role="src" />

@ -130,6 +130,25 @@ grpc_cc_library(
],
)
grpc_cc_library(
name = "latent_see",
srcs = [
"util/latent_see.cc",
],
hdrs = [
"util/latent_see.h",
],
external_deps = [
"absl/log",
"absl/strings",
"absl/types:optional",
],
deps = [
"per_cpu",
"//:gpr",
],
)
grpc_cc_library(
name = "transport_fwd",
hdrs = [
@ -581,6 +600,7 @@ grpc_cc_library(
"construct_destruct",
"context",
"event_engine_context",
"latent_see",
"poll",
"promise_factory",
"ref_counted",
@ -961,6 +981,7 @@ grpc_cc_library(
"construct_destruct",
"context",
"dump_args",
"latent_see",
"no_destruct",
"poll",
"promise_factory",

@ -43,6 +43,7 @@
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/telemetry/stats.h"
#include "src/core/telemetry/stats_data.h"
#include "src/core/util/latent_see.h"
namespace grpc_core {
@ -377,6 +378,8 @@ class WorkSerializer::DispatchingWorkSerializer final
// rate of mutex acquisitions per work item tends towards 1.
CallbackVector incoming_ ABSL_GUARDED_BY(mu_);
GPR_NO_UNIQUE_ADDRESS latent_see::Flow flow_;
#ifndef NDEBUG
static thread_local DispatchingWorkSerializer* running_work_serializer_;
#endif
@ -428,6 +431,8 @@ void WorkSerializer::DispatchingWorkSerializer::Run(
// Implementation of EventEngine::Closure::Run - our actual work loop
void WorkSerializer::DispatchingWorkSerializer::Run() {
GRPC_LATENT_SEE_PARENT_SCOPE("WorkSerializer::Run");
flow_.End();
// TODO(ctiller): remove these when we can deprecate ExecCtx
ApplicationCallbackExecCtx app_exec_ctx;
ExecCtx exec_ctx;
@ -457,6 +462,7 @@ void WorkSerializer::DispatchingWorkSerializer::Run() {
if (processing_.empty() && !Refill()) return;
// There's still work in processing_, so schedule ourselves again on
// EventEngine.
flow_.Begin(GRPC_LATENT_SEE_METADATA("WorkSerializer::Link"));
event_engine_->Run(this);
}

@ -42,6 +42,7 @@
#include "src/core/lib/promise/detail/promise_factory.h"
#include "src/core/lib/promise/detail/status.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/util/latent_see.h"
namespace grpc_core {
@ -545,6 +546,8 @@ class PromiseActivity final
}
void WakeupAsync(WakeupMask) final {
GRPC_LATENT_SEE_INNER_SCOPE("PromiseActivity::WakeupAsync");
wakeup_flow_.Begin(GRPC_LATENT_SEE_METADATA("Activity::Wakeup"));
if (!wakeup_scheduled_.exchange(true, std::memory_order_acq_rel)) {
// Can't safely run, so ask to run later.
this->ScheduleWakeup();
@ -568,6 +571,8 @@ class PromiseActivity final
// In response to Wakeup, run the Promise state machine again until it
// settles. Then check for completion, and if we have completed, call on_done.
void Step() ABSL_LOCKS_EXCLUDED(mu()) {
GRPC_LATENT_SEE_PARENT_SCOPE("PromiseActivity::Step");
wakeup_flow_.End();
// Poll the promise until things settle out under a lock.
mu()->Lock();
if (done_) {
@ -644,6 +649,7 @@ class PromiseActivity final
GPR_NO_UNIQUE_ADDRESS Promise promise;
};
GPR_NO_UNIQUE_ADDRESS PromiseHolder promise_holder_ ABSL_GUARDED_BY(mu());
GPR_NO_UNIQUE_ADDRESS latent_see::Flow wakeup_flow_;
};
} // namespace promise_detail

@ -27,6 +27,7 @@
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/promise/activity.h"
#include "src/core/util/latent_see.h"
#ifdef GRPC_MAXIMIZE_THREADYNESS
#include "src/core/lib/gprpp/thd.h" // IWYU pragma: keep
@ -214,6 +215,7 @@ void Party::ForceImmediateRepoll(WakeupMask mask) {
}
void Party::RunLocked() {
GRPC_LATENT_SEE_PARENT_SCOPE("Party::RunLocked");
// If there is a party running, then we don't run it immediately
// but instead add it to the end of the list of parties to run.
// This enables a fairly straightforward batching of work from a
@ -269,6 +271,7 @@ bool Party::RunParty() {
}
bool Party::RunOneParticipant(int i) {
GRPC_LATENT_SEE_INNER_SCOPE("Party::RunOneParticipant");
// If the participant is null, skip.
// This allows participants to complete whilst wakers still exist
// somewhere.

@ -59,6 +59,7 @@
#include "src/core/lib/transport/metadata.h"
#include "src/core/telemetry/stats.h"
#include "src/core/telemetry/stats_data.h"
#include "src/core/util/latent_see.h"
namespace grpc_core {
@ -129,6 +130,7 @@ ClientCall::ClientCall(grpc_call*, uint32_t, grpc_completion_queue* cq,
grpc_call_error ClientCall::StartBatch(const grpc_op* ops, size_t nops,
void* notify_tag,
bool is_notify_tag_closure) {
GRPC_LATENT_SEE_PARENT_SCOPE("ClientCall::StartBatch");
if (nops == 0) {
EndOpImmediately(cq_, notify_tag, is_notify_tag_closure);
return GRPC_CALL_OK;

@ -0,0 +1,113 @@
// Copyright 2024 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/core/util/latent_see.h"
#ifdef GRPC_ENABLE_LATENT_SEE
#include <chrono>
#include <cstdint>
#include "absl/strings/str_cat.h"
#include "absl/types/optional.h"
namespace grpc_core {
namespace latent_see {
thread_local std::vector<Log::Event> Log::thread_events_;
thread_local uint64_t Log::thread_id_ = Log::Get().next_thread_id_.fetch_add(1);
std::atomic<uint64_t> Flow::next_flow_id_{1};
std::string Log::GenerateJson() {
std::vector<RecordedEvent> events;
for (auto& fragment : fragments_) {
MutexLock lock(&fragment.mu);
events.insert(events.end(), fragment.events.begin(), fragment.events.end());
}
absl::optional<std::chrono::steady_clock::time_point> start_time;
for (auto& event : events) {
if (!start_time.has_value() || *start_time > event.event.timestamp) {
start_time = event.event.timestamp;
}
}
if (!start_time.has_value()) return "[]";
std::string json = "[\n";
bool first = true;
for (const auto& event : events) {
absl::string_view phase;
bool has_id;
switch (event.event.type) {
case EventType::kBegin:
phase = "B";
has_id = false;
break;
case EventType::kEnd:
phase = "E";
has_id = false;
break;
case EventType::kFlowStart:
phase = "s";
has_id = true;
break;
case EventType::kFlowEnd:
phase = "f";
has_id = true;
break;
case EventType::kMark:
phase = "i";
has_id = false;
break;
}
if (!first) absl::StrAppend(&json, ",\n");
first = false;
absl::StrAppend(&json, "{\"name\": ", event.event.metadata->name,
", \"ph\": \"", phase, "\", \"ts\": ",
std::chrono::duration<double, std::micro>(
event.event.timestamp - *start_time)
.count(),
", \"pid\": 0, \"tid\": ", event.thread_id);
if (has_id) {
absl::StrAppend(&json, ", \"id\": ", event.event.id);
}
if (event.event.type == EventType::kFlowEnd) {
absl::StrAppend(&json, ", \"bp\": \"e\"");
}
absl::StrAppend(&json, ", \"args\": {\"file\": \"",
event.event.metadata->file,
"\", \"line\": ", event.event.metadata->line,
", \"batch\": ", event.batch_id, "}}");
}
absl::StrAppend(&json, "\n]");
return json;
}
void Log::FlushThreadLog() {
auto& thread_events = thread_events_;
if (thread_events.empty()) return;
auto& log = Get();
const auto batch_id =
log.next_batch_id_.fetch_add(1, std::memory_order_relaxed);
auto& fragment = log.fragments_.this_cpu();
const auto thread_id = thread_id_;
{
MutexLock lock(&fragment.mu);
for (auto event : thread_events) {
fragment.events.push_back(RecordedEvent{thread_id, batch_id, event});
}
}
thread_events.clear();
}
} // namespace latent_see
} // namespace grpc_core
#endif

@ -0,0 +1,214 @@
// Copyright 2024 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_SRC_CORE_UTIL_LATENT_SEE_H
#define GRPC_SRC_CORE_UTIL_LATENT_SEE_H
#include <grpc/support/port_platform.h>
#ifdef GRPC_ENABLE_LATENT_SEE
#include <chrono>
#include <cstdint>
#include <utility>
#include <vector>
#include "absl/log/log.h"
#include "src/core/lib/gprpp/per_cpu.h"
#include "src/core/lib/gprpp/sync.h"
namespace grpc_core {
namespace latent_see {
struct Metadata {
const char* file;
int line;
const char* name;
};
enum class EventType : uint8_t { kBegin, kEnd, kFlowStart, kFlowEnd, kMark };
class Log {
public:
static void FlushThreadLog();
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static void Append(
const Metadata* metadata, EventType type, uint64_t id) {
thread_events_.push_back(
Event{metadata, std::chrono::steady_clock::now(), id, type});
}
private:
Log() = default;
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static Log& Get() {
static Log* log = []() {
atexit([] {
LOG(INFO) << "Writing latent_see.json in " << get_current_dir_name();
FILE* f = fopen("latent_see.json", "w");
if (f == nullptr) return;
fprintf(f, "%s", log->GenerateJson().c_str());
fclose(f);
});
return new Log();
}();
return *log;
}
std::string GenerateJson();
struct Event {
const Metadata* metadata;
std::chrono::steady_clock::time_point timestamp;
uint64_t id;
EventType type;
};
struct RecordedEvent {
uint64_t thread_id;
uint64_t batch_id;
Event event;
};
std::atomic<uint64_t> next_thread_id_{1};
std::atomic<uint64_t> next_batch_id_{1};
static thread_local std::vector<Event> thread_events_;
static thread_local uint64_t thread_id_;
struct Fragment {
Mutex mu;
std::vector<RecordedEvent> events ABSL_GUARDED_BY(mu);
};
PerCpu<Fragment> fragments_{PerCpuOptions()};
};
template <bool kFlush>
class Scope {
public:
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION explicit Scope(const Metadata* metadata)
: metadata_(metadata) {
Log::Append(metadata_, EventType::kBegin, 0);
}
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION ~Scope() {
Log::Append(metadata_, EventType::kEnd, 0);
if (kFlush) Log::FlushThreadLog();
}
Scope(const Scope&) = delete;
Scope& operator=(const Scope&) = delete;
private:
const Metadata* const metadata_;
};
using ParentScope = Scope<true>;
using InnerScope = Scope<false>;
class Flow {
public:
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION Flow() : metadata_(nullptr) {}
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION explicit Flow(const Metadata* metadata)
: metadata_(metadata),
id_(next_flow_id_.fetch_add(1, std::memory_order_relaxed)) {
Log::Append(metadata_, EventType::kFlowStart, id_);
}
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION ~Flow() {
if (metadata_ != nullptr) {
Log::Append(metadata_, EventType::kFlowEnd, id_);
}
}
Flow(const Flow&) = delete;
Flow& operator=(const Flow&) = delete;
Flow(Flow&& other) noexcept
: metadata_(std::exchange(other.metadata_, nullptr)), id_(other.id_) {}
Flow& operator=(Flow&& other) noexcept {
if (metadata_ != nullptr) Log::Append(metadata_, EventType::kFlowEnd, id_);
metadata_ = std::exchange(other.metadata_, nullptr);
id_ = other.id_;
return *this;
}
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION bool is_active() const {
return metadata_ != nullptr;
}
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION void End() {
if (metadata_ == nullptr) return;
Log::Append(metadata_, EventType::kFlowEnd, id_);
metadata_ = nullptr;
}
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION void Begin(const Metadata* metadata) {
if (metadata_ != nullptr) Log::Append(metadata_, EventType::kFlowEnd, id_);
metadata_ = metadata;
if (metadata_ == nullptr) return;
id_ = next_flow_id_.fetch_add(1, std::memory_order_relaxed);
Log::Append(metadata_, EventType::kFlowStart, id_);
}
private:
const Metadata* metadata_;
uint64_t id_;
static std::atomic<uint64_t> next_flow_id_;
};
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline void Mark(const Metadata* md) {
Log::Append(md, EventType::kMark, 0);
}
} // namespace latent_see
} // namespace grpc_core
#define GRPC_LATENT_SEE_METADATA(name) \
[]() { \
static grpc_core::latent_see::Metadata metadata = {__FILE__, __LINE__, \
#name}; \
return &metadata; \
}()
// Parent scope: logs a begin and end event, and flushes the thread log on scope
// exit. Because the flush takes some time it's better to place one parent scope
// at the top of the stack, and use lighter weight scopes within it.
#define GRPC_LATENT_SEE_PARENT_SCOPE(name) \
grpc_core::latent_see::ParentScope latent_see_scope##__LINE__( \
GRPC_LATENT_SEE_METADATA(name))
// Inner scope: logs a begin and end event. Lighter weight than parent scope,
// but does not flush the thread state - so should only be enclosed by a parent
// scope.
#define GRPC_LATENT_SEE_INNER_SCOPE(name) \
grpc_core::latent_see::InnerScope latent_see_scope##__LINE__( \
GRPC_LATENT_SEE_METADATA(name))
// Mark: logs a single event.
// This is not flushed automatically, and so should only be used within a parent
// scope.
#define GRPC_LATENT_SEE_MARK(name) \
grpc_core::latent_see::Mark(GRPC_LATENT_SEE_METADATA(name))
#else // !def(GRPC_ENABLE_LATENT_SEE)
namespace grpc_core {
namespace latent_see {
struct Metadata {};
struct Flow {
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION bool is_active() const { return false; }
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION void End() {}
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION void Begin(Metadata*) {}
};
} // namespace latent_see
} // namespace grpc_core
#define GRPC_LATENT_SEE_METADATA(name) nullptr
#define GRPC_LATENT_SEE_PARENT_SCOPE(name) \
do { \
} while (0)
#define GRPC_LATENT_SEE_INNER_SCOPE(name) \
do { \
} while (0)
#define GRPC_LATENT_SEE_MARK(name) \
do { \
} while (0)
#endif // GRPC_ENABLE_LATENT_SEE
#endif // GRPC_SRC_CORE_UTIL_LATENT_SEE_H

@ -810,6 +810,7 @@ CORE_SOURCE_FILES = [
'src/core/util/json/json_reader.cc',
'src/core/util/json/json_util.cc',
'src/core/util/json/json_writer.cc',
'src/core/util/latent_see.cc',
'src/core/util/linux/cpu.cc',
'src/core/util/linux/log.cc',
'src/core/util/log.cc',

@ -35,6 +35,8 @@ build --define=use_fast_cpp_protos=true
build:opt --compilation_mode=opt
build:opt --copt=-Wframe-larger-than=16384
build:latent_see --copt=-DGRPC_ENABLE_LATENT_SEE
build:dbg --compilation_mode=dbg
# Dynamic link cause issues like: `dyld: malformed mach-o: load commands size (59272) > 32768`

@ -2937,6 +2937,8 @@ src/core/util/json/json_util.cc \
src/core/util/json/json_util.h \
src/core/util/json/json_writer.cc \
src/core/util/json/json_writer.h \
src/core/util/latent_see.cc \
src/core/util/latent_see.h \
src/core/util/linux/cpu.cc \
src/core/util/linux/log.cc \
src/core/util/log.cc \

@ -777,6 +777,7 @@ doc/core/epoll-polling-engine.md \
doc/core/grpc-client-server-polling-engine-usage.md \
doc/core/grpc-cq.md \
doc/core/grpc-polling-engines.md \
doc/core/latent_see.md \
doc/core/moving-to-c++.md \
doc/core/pending_api_cleanups.md \
doc/core/transport_explainer.md \

@ -777,6 +777,7 @@ doc/core/epoll-polling-engine.md \
doc/core/grpc-client-server-polling-engine-usage.md \
doc/core/grpc-cq.md \
doc/core/grpc-polling-engines.md \
doc/core/latent_see.md \
doc/core/moving-to-c++.md \
doc/core/pending_api_cleanups.md \
doc/core/transport_explainer.md \
@ -2716,6 +2717,8 @@ src/core/util/json/json_util.cc \
src/core/util/json/json_util.h \
src/core/util/json/json_writer.cc \
src/core/util/json/json_writer.h \
src/core/util/latent_see.cc \
src/core/util/latent_see.h \
src/core/util/linux/cpu.cc \
src/core/util/linux/log.cc \
src/core/util/log.cc \

Loading…
Cancel
Save