diff --git a/.gitmodules b/.gitmodules index a0a57f3d..fab3f678 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "vcpkg"] path = vcpkg url = https://github.com/microsoft/vcpkg.git +[submodule "ext/perfetto"] + path = ext/perfetto + url = https://github.com/google/perfetto.git diff --git a/build-linux.sh b/build-linux.sh index c1bd1d5b..18dc067b 100755 --- a/build-linux.sh +++ b/build-linux.sh @@ -6,7 +6,7 @@ show_help() { echo "Usage:" echo " $0 [-n ] [-a ] [-t ] [-g ] [-o ] [-c ] [-l ] [-d] [-s]" echo "Where:" - echo " -p - Specify the predefined provile to build. Defaults to " + echo " -p - Specify the predefined profile to build. Defaults to " echo " 'native-gcc' if not specified. Must be one of " echo " 'native-gcc', 'native-clang', 'arm-glibc', 'arm-musl', " echo " 'arm64-glibc' or 'arm64-musl'." diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 059c4045..febc22cc 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -5,7 +5,7 @@ OPTION(ENABLE_VCPKG "Pull in dependencies using vcpkg" ON) IF(ENABLE_VCPKG) SET(VCPKG_OVERLAY_TRIPLETS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/triplets" CACHE STRING "") - SET(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/../vcpkg/scripts/buildsystems/vcpkg.cmake" CACHE STRING "") + SET(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/../vcpkg/scripts/buildsystems/vcpkg.cmake" CACHE STRING "") ENDIF() PROJECT(gatord C CXX) @@ -13,17 +13,17 @@ PROJECT(gatord C CXX) SET(CMAKE_CXX_STANDARD 17) SET(CMAKE_CXX_STANDARD_REQUIRED ON) -#### -# Generate compile_commands.json for clang-tidy et al -#### +# ### +# Generate compile_commands.json for clang-tidy et al +# ### SET(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Configuration options -OPTION(GATORD_WERROR "Build with -Werror set" ON) -OPTION(CLANG_TIDY_FIX "Enable --fix with clang-tidy" OFF) -OPTION(CONFIG_SUPPORT_PROC_POLLING "Support polling of /proc" ON) -OPTION(CONFIG_PREFER_SYSTEM_WIDE_MODE "Enable system-wide capture by default" ON) -OPTION(CONFIG_ASSUME_PERF_HIGH_PARANOIA "Assume perf_event_paranoid is 2 if it cannot be read" ON) +OPTION(GATORD_WERROR "Build with -Werror set" ON) +OPTION(CLANG_TIDY_FIX "Enable --fix with clang-tidy" OFF) +OPTION(CONFIG_SUPPORT_PROC_POLLING "Support polling of /proc" ON) +OPTION(CONFIG_PREFER_SYSTEM_WIDE_MODE "Enable system-wide capture by default" ON) +OPTION(CONFIG_ASSUME_PERF_HIGH_PARANOIA "Assume perf_event_paranoid is 2 if it cannot be read" ON) # Include the target detection code INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/build-target.cmake) @@ -38,27 +38,39 @@ INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/split-strip.cmake) INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/escape.cmake) # Configure target flags -SET(GATORD_C_CXX_FLAGS "-fvisibility=hidden") +IF(("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") AND(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "7.4.0")) + SET(GATORD_C_CXX_FLAGS "-fvisibility=default") +ELSE() + SET(GATORD_C_CXX_FLAGS "-fvisibility=hidden") +ENDIF() + IF(GATORD_WERROR) - SET(GATORD_C_CXX_FLAGS "${GATORD_C_CXX_FLAGS} -Werror") + SET(GATORD_C_CXX_FLAGS "${GATORD_C_CXX_FLAGS} -Werror") ENDIF() + IF(GATORD_BUILD_STATIC) - SET(GATORD_C_CXX_FLAGS "${GATORD_C_CXX_FLAGS} -static") - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") + SET(GATORD_C_CXX_FLAGS "${GATORD_C_CXX_FLAGS} -static") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") ENDIF() -IF(GATORD_BUILD_ID) - SET(GATORD_C_CXX_FLAGS "${GATORD_C_CXX_FLAGS} -DGATORD_BUILD_ID=\"${GATORD_BUILD_ID}\"") - MESSAGE(STATUS "GATORD_BUILD_ID = ${GATORD_BUILD_ID}") + +IF(NOT DEFINED GATORD_BUILD_ID) + SET(GATORD_BUILD_ID "oss") ENDIF() -IF (NOT CONFIG_SUPPORT_PROC_POLLING) -SET(GATORD_C_CXX_FLAGS "${GATORD_C_CXX_FLAGS} -DCONFIG_SUPPORT_PROC_POLLING=0") + +MESSAGE(STATUS "GATORD_BUILD_ID = ${GATORD_BUILD_ID}") + +IF(NOT CONFIG_SUPPORT_PROC_POLLING) + SET(GATORD_C_CXX_FLAGS "${GATORD_C_CXX_FLAGS} -DCONFIG_SUPPORT_PROC_POLLING=0") ENDIF() -IF (NOT CONFIG_PREFER_SYSTEM_WIDE_MODE) -SET(GATORD_C_CXX_FLAGS "${GATORD_C_CXX_FLAGS} -DCONFIG_PREFER_SYSTEM_WIDE_MODE=0") + +IF(NOT CONFIG_PREFER_SYSTEM_WIDE_MODE) + SET(GATORD_C_CXX_FLAGS "${GATORD_C_CXX_FLAGS} -DCONFIG_PREFER_SYSTEM_WIDE_MODE=0") ENDIF() -IF (NOT CONFIG_ASSUME_PERF_HIGH_PARANOIA) -SET(GATORD_C_CXX_FLAGS "${GATORD_C_CXX_FLAGS} -DCONFIG_ASSUME_PERF_HIGH_PARANOIA=0") + +IF(NOT CONFIG_ASSUME_PERF_HIGH_PARANOIA) + SET(GATORD_C_CXX_FLAGS "${GATORD_C_CXX_FLAGS} -DCONFIG_ASSUME_PERF_HIGH_PARANOIA=0") ENDIF() + INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/compiler-flags.cmake) ADD_SUBDIRECTORY(ipc/proto) @@ -72,614 +84,598 @@ FIND_PACKAGE(Boost 1.75 REQUIRED COMPONENTS ) ADD_DEFINITIONS(-DBOOST_FILESYSTEM_NO_DEPRECATED) - ADD_DEFINITIONS(-DETCDIR="/etc") INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/libsensors + ${CMAKE_CURRENT_SOURCE_DIR}/../ext ${CMAKE_CURRENT_BINARY_DIR}) # This file is generated and contains a hash of the source files -SET(GENERATED_MD5_SOURCE ${CMAKE_CURRENT_BINARY_DIR}/SrcMd5.cpp) -SET(GENERATED_MD5_FILE ${CMAKE_CURRENT_BINARY_DIR}/SrcMd5.md5) +SET(GENERATED_MD5_SOURCE ${CMAKE_CURRENT_BINARY_DIR}/SrcMd5.cpp) +SET(GENERATED_MD5_FILE ${CMAKE_CURRENT_BINARY_DIR}/SrcMd5.md5) # The source files to build SET(GATORD_3RD_PARTY_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/k/perf_event.h - ${CMAKE_CURRENT_SOURCE_DIR}/libsensors/access.c - ${CMAKE_CURRENT_SOURCE_DIR}/libsensors/conf-lex.c - ${CMAKE_CURRENT_SOURCE_DIR}/libsensors/conf-parse.c - ${CMAKE_CURRENT_SOURCE_DIR}/libsensors/data.c - ${CMAKE_CURRENT_SOURCE_DIR}/libsensors/error.c - ${CMAKE_CURRENT_SOURCE_DIR}/libsensors/general.c - ${CMAKE_CURRENT_SOURCE_DIR}/libsensors/init.c - ${CMAKE_CURRENT_SOURCE_DIR}/libsensors/sysfs.c) + ${CMAKE_CURRENT_SOURCE_DIR}/libsensors/access.c + ${CMAKE_CURRENT_SOURCE_DIR}/libsensors/conf-lex.c + ${CMAKE_CURRENT_SOURCE_DIR}/libsensors/conf-parse.c + ${CMAKE_CURRENT_SOURCE_DIR}/libsensors/data.c + ${CMAKE_CURRENT_SOURCE_DIR}/libsensors/error.c + ${CMAKE_CURRENT_SOURCE_DIR}/libsensors/general.c + ${CMAKE_CURRENT_SOURCE_DIR}/libsensors/init.c + ${CMAKE_CURRENT_SOURCE_DIR}/libsensors/sysfs.c) SET_SOURCE_FILES_PROPERTIES(${GATORD_3RD_PARTY_SOURCES} - COMPILE_FLAGS -w) - -SET(GATORD_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/AnnotateListener.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/AnnotateListener.h - ${CMAKE_CURRENT_SOURCE_DIR}/AtraceDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/AtraceDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/BlockCounterFrameBuilder.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/BlockCounterFrameBuilder.h - ${CMAKE_CURRENT_SOURCE_DIR}/BlockCounterMessageConsumer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/BlockCounterMessageConsumer.h - ${CMAKE_CURRENT_SOURCE_DIR}/Buffer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Buffer.h - ${CMAKE_CURRENT_SOURCE_DIR}/BufferUtils.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/BufferUtils.h - ${CMAKE_CURRENT_SOURCE_DIR}/CapturedSpe.h - ${CMAKE_CURRENT_SOURCE_DIR}/CapturedXML.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/CapturedXML.h - ${CMAKE_CURRENT_SOURCE_DIR}/CCNDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/CCNDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/Child.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Child.h - ${CMAKE_CURRENT_SOURCE_DIR}/CommitTimeChecker.h - ${CMAKE_CURRENT_SOURCE_DIR}/Config.h - ${CMAKE_CURRENT_SOURCE_DIR}/Configuration.h - ${CMAKE_CURRENT_SOURCE_DIR}/ConfigurationXML.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/ConfigurationXML.h - ${CMAKE_CURRENT_SOURCE_DIR}/ConfigurationXMLParser.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/ConfigurationXMLParser.h - ${CMAKE_CURRENT_SOURCE_DIR}/Constant.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Constant.h - ${CMAKE_CURRENT_SOURCE_DIR}/ConstantMode.h - ${CMAKE_CURRENT_SOURCE_DIR}/Counter.h - ${CMAKE_CURRENT_SOURCE_DIR}/CounterXML.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/CounterXML.h - ${CMAKE_CURRENT_SOURCE_DIR}/CpuUtils.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/CpuUtils.h - ${CMAKE_CURRENT_SOURCE_DIR}/CpuUtils_Topology.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/CpuUtils_Topology.h - ${CMAKE_CURRENT_SOURCE_DIR}/DiskIODriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/DiskIODriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/DriverCounter.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/DriverCounter.h - ${CMAKE_CURRENT_SOURCE_DIR}/Driver.h - ${CMAKE_CURRENT_SOURCE_DIR}/Drivers.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Drivers.h - ${CMAKE_CURRENT_SOURCE_DIR}/DynBuf.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/DynBuf.h - ${CMAKE_CURRENT_SOURCE_DIR}/EventCode.h - ${CMAKE_CURRENT_SOURCE_DIR}/Events.h - ${CMAKE_CURRENT_SOURCE_DIR}/ExitStatus.h - ${CMAKE_CURRENT_SOURCE_DIR}/ExternalDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/ExternalDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/ExternalSource.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/ExternalSource.h - ${CMAKE_CURRENT_SOURCE_DIR}/Fifo.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Fifo.h - ${CMAKE_CURRENT_SOURCE_DIR}/FSDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/FSDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/FtraceDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/FtraceDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/GatorCLIFlags.h - ${CMAKE_CURRENT_SOURCE_DIR}/GatorCLIParser.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/GatorCLIParser.h - ${CMAKE_CURRENT_SOURCE_DIR}/GatorException.h - ${CMAKE_CURRENT_SOURCE_DIR}/GatorMain.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/GatorMain.h - ${CMAKE_CURRENT_SOURCE_DIR}/GetEventKey.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/GetEventKey.h - ${CMAKE_CURRENT_SOURCE_DIR}/HwmonDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/HwmonDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/IBlockCounterFrameBuilder.h - ${CMAKE_CURRENT_SOURCE_DIR}/IBlockCounterMessageConsumer.h - ${CMAKE_CURRENT_SOURCE_DIR}/IBufferControl.h - ${CMAKE_CURRENT_SOURCE_DIR}/ICpuInfo.h - ${CMAKE_CURRENT_SOURCE_DIR}/IMonitor.h - ${CMAKE_CURRENT_SOURCE_DIR}/IRawFrameBuilder.h - ${CMAKE_CURRENT_SOURCE_DIR}/ISender.h - ${CMAKE_CURRENT_SOURCE_DIR}/ISummaryConsumer.h - ${CMAKE_CURRENT_SOURCE_DIR}/LocalCapture.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/LocalCapture.h - ${CMAKE_CURRENT_SOURCE_DIR}/Logging.h - ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/MemInfoDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/MemInfoDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/MidgardDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/MidgardDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/Monitor.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Monitor.h - ${CMAKE_CURRENT_SOURCE_DIR}/NetDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/NetDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/OlySocket.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/OlySocket.h - ${CMAKE_CURRENT_SOURCE_DIR}/OlyUtility.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/OlyUtility.h - ${CMAKE_CURRENT_SOURCE_DIR}/ParserResult.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/ParserResult.h - ${CMAKE_CURRENT_SOURCE_DIR}/pmus_xml.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/PolledDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/PolledDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/PrimarySourceProvider.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/PrimarySourceProvider.h - ${CMAKE_CURRENT_SOURCE_DIR}/Proc.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Proc.h - ${CMAKE_CURRENT_SOURCE_DIR}/Protocol.h - ${CMAKE_CURRENT_SOURCE_DIR}/ProtocolVersion.h - ${CMAKE_CURRENT_SOURCE_DIR}/Sender.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Sender.h - ${CMAKE_CURRENT_SOURCE_DIR}/SessionData.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/SessionData.h - ${CMAKE_CURRENT_SOURCE_DIR}/SessionXML.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/SessionXML.h - ${CMAKE_CURRENT_SOURCE_DIR}/SimpleDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/SimpleDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/Source.h - ${CMAKE_CURRENT_SOURCE_DIR}/StreamlineSetup.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/StreamlineSetup.h - ${CMAKE_CURRENT_SOURCE_DIR}/StreamlineSetupLoop.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/StreamlineSetupLoop.h - ${CMAKE_CURRENT_SOURCE_DIR}/SummaryBuffer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/SummaryBuffer.h - ${CMAKE_CURRENT_SOURCE_DIR}/Time.h - ${CMAKE_CURRENT_SOURCE_DIR}/TtraceDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/TtraceDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/UEvent.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/UEvent.h - ${CMAKE_CURRENT_SOURCE_DIR}/UserSpaceSource.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/UserSpaceSource.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/agent_environment.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/agent_environment.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/agent_worker_base.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/agent_worker.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/agent_workers_process.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/common/coalescing_cpu_monitor.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/common/nl_cpu_monitor.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/common/polling_cpu_monitor.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/common/socket_listener.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/common/socket_reference.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/common/socket_worker.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/ext_source/ext_source_agent.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/ext_source/ext_source_agent_main.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/ext_source/ext_source_agent_main.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/ext_source/ext_source_agent_worker.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/ext_source/ipc_sink_wrapper.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/async_buffer_builder.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/async_perf_ringbuffer_monitor.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/capture_configuration.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/capture_configuration.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/cpufreq_counter.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/cpufreq_counter.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/cpu_info.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/event_binding_manager.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/event_bindings.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/event_configuration.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/perf_activator.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/perf_activator.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/perf_event_utils.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/perf_event_utils.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/perf_ringbuffer_mmap.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/types.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_agent.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_agent_main.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_agent_main.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_agent_worker.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_buffer_consumer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_buffer_consumer.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_capture_cpu_monitor.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_capture.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_capture_helper.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_driver_summary.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_driver_summary.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_frame_packer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_frame_packer.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/record_types.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/source_adapter.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/source_adapter.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/sync_generator.h - ${CMAKE_CURRENT_SOURCE_DIR}/agents/spawn_agent.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/agents/spawn_agent.h - ${CMAKE_CURRENT_SOURCE_DIR}/android/AndroidActivityManager.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/android/AndroidActivityManager.h - ${CMAKE_CURRENT_SOURCE_DIR}/android/AppGatorRunner.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/android/AppGatorRunner.h - ${CMAKE_CURRENT_SOURCE_DIR}/android/GatorAndroidSetupHandler.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/android/GatorAndroidSetupHandler.h - ${CMAKE_CURRENT_SOURCE_DIR}/android/IAppGatorRunner.h - ${CMAKE_CURRENT_SOURCE_DIR}/android/PropertyUtils.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/android/PropertyUtils.h - ${CMAKE_CURRENT_SOURCE_DIR}/android/Spawn.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/android/Spawn.h - ${CMAKE_CURRENT_SOURCE_DIR}/android/ThermalDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/android/ThermalDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/android/Utils.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/android/Utils.h - ${CMAKE_CURRENT_SOURCE_DIR}/apc/misc_apc_frame_ipc_sender.h - ${CMAKE_CURRENT_SOURCE_DIR}/apc/perf_apc_frame_utils.h - ${CMAKE_CURRENT_SOURCE_DIR}/apc/perf_counter.h - ${CMAKE_CURRENT_SOURCE_DIR}/apc/summary_apc_frame_utils.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ArmNNDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ArmNNDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ArmNNSource.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ArmNNSource.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ByteOrder.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/CaptureMode.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/CounterDirectoryDecoder.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/CounterDirectoryDecoder.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/CounterDirectoryStateUtils.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/CounterDirectoryStateUtils.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/DecoderUtility.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/DecoderUtility.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/DriverSourceIpc.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/DriverSourceIpc.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/FrameBuilderFactory.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/FrameBuilderFactory.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/GlobalState.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/GlobalState.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IAcceptor.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ICaptureController.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ICounterConsumer.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ICounterDirectoryConsumer.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IEncoder.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IFrameBuilderFactory.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IGlobalState.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IPacketConsumer.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IPacketDecoder.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IPeriodicCounterCaptureConsumer.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IPeriodicCounterSelectionConsumer.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IPerJobCounterCaptureConsumer.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IPerJobCounterSelectionConsumer.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ISender.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ISession.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ISessionPacketSender.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IStartStopHandler.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketDecoder.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketDecoderEncoderFactory.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketDecoderEncoderFactory.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketDecoder.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketEncoder.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketEncoder.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketUtility.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketUtility.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketUtilityModels.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SenderQueue.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SenderQueue.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SenderThread.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SenderThread.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/Session.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/Session.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SessionPacketSender.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SessionPacketSender.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SessionStateTracker.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SessionStateTracker.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SocketAcceptor.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SocketAcceptor.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SocketIO.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SocketIO.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ThreadManagementServer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ThreadManagementServer.h - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/TimestampCorrector.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/armnn/TimestampCorrector.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/asio_traits.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/async_line_reader.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/async/completion_handler.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/async_initiate.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/continuation.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/continuation_of.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/continuation_traits.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/cont_if.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/cont_if_state.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/continuation_factory.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/do_if.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/do_if_state.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/initiation_chain.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/loop.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/loop_state.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/map_error.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/map_error_state.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/on_executor.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/on_executor_state.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/polymorphic_state.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/predicate.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/predicate_state.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/start_state.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/state_chain.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/then.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/then_state.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/trace.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/unpack_tuple.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/unpack_tuple_state.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/unpack_variant.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/unpack_variant_state.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/use_continuation_state.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/nop_receiver.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/operations.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/stored_continuation.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/use_continuation.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/netlink/nl_protocol.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/netlink/uevents.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_exec.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_exec.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_process.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_process.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_proc_poller.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_proc_poller.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_read_proc_maps.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_read_proc_sys_dependencies.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_wait_for_process.h - ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/process_monitor.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/process_monitor.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/process_state.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/process_state_tracker.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/wait.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/capture/CaptureProcess.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/capture/CaptureProcess.h - ${CMAKE_CURRENT_SOURCE_DIR}/capture/Environment.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/capture/Environment.h - ${CMAKE_CURRENT_SOURCE_DIR}/capture/internal/UdpListener.h - ${CMAKE_CURRENT_SOURCE_DIR}/ipc/async_streamline_sender.h - ${CMAKE_CURRENT_SOURCE_DIR}/ipc/codec.h - ${CMAKE_CURRENT_SOURCE_DIR}/ipc/message_key.h - ${CMAKE_CURRENT_SOURCE_DIR}/ipc/messages.h - ${CMAKE_CURRENT_SOURCE_DIR}/ipc/message_traits.h - ${CMAKE_CURRENT_SOURCE_DIR}/ipc/raw_ipc_channel_sink.h - ${CMAKE_CURRENT_SOURCE_DIR}/ipc/raw_ipc_channel_source.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Assert.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Assert.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/AutoClosingFd.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/EnumUtils.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/error_code_or.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/lib/exception.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/File.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/lib/FileDescriptor.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/lib/FileDescriptor.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/File.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/forked_process.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/lib/forked_process.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/forked_process_utils.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/lib/forked_process_utils.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Format.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/FsEntry.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/lib/FsEntry.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/FsUtils.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/GenericTimer.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Istream.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Memory.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/PmuCommonEvents.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Popen.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Popen.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Process.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Process.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Resource.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Resource.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/SharedMemory.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/source_location.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Span.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/StaticVector.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/String.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Syscall.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Syscall.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Throw.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Time.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/TimestampSource.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/lib/TimestampSource.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Utils.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Utils.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/Waiter.h - ${CMAKE_CURRENT_SOURCE_DIR}/lib/WaitForProcessPoller.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/lib/WaitForProcessPoller.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/CoreOnliner.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/CoreOnliner.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/PerCoreIdentificationThread.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/PerCoreIdentificationThread.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/attr_to_key_mapping_tracker.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/IPerfAttrsConsumer.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/IPerfGroups.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfAttrsBuffer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfAttrsBuffer.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfConfig.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfDriverConfiguration.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfDriverConfiguration.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfDriverCreateSource.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfEventGroup.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfEventGroup.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfEventGroupIdentifier.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfEventGroupIdentifier.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfGroups.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfGroups.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfSyncThread.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfSyncThread.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfUtils.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcessChildren.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcessChildren.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcessPollerBase.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcessPollerBase.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcLoadAvgFileRecord.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcLoadAvgFileRecord.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcPidStatFileRecord.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcPidStatFileRecord.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcPidStatmFileRecord.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcPidStatmFileRecord.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcStatFileRecord.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcStatFileRecord.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/SysfsSummaryInformation.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/SysfsSummaryInformation.h - ${CMAKE_CURRENT_SOURCE_DIR}/linux/Tracepoints.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/linux/Tracepoints.h - ${CMAKE_CURRENT_SOURCE_DIR}/logging/agent_log.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/logging/agent_log.h - ${CMAKE_CURRENT_SOURCE_DIR}/logging/global_log.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/logging/global_log.h - ${CMAKE_CURRENT_SOURCE_DIR}/logging/logging.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/logging/suppliers.h - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/IMaliHwCntrReader.h - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliDeviceApi.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliDeviceApi_DdkDefines.h - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliDeviceApi.h - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliDevice.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliDevice.h - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliGPUClockPolledDriverCounter.h - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliGPUClockPolledDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliGPUClockPolledDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntr.h - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrNames.h - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrNamesBifrost.h - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrReader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrReader.h - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrSource.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrSource.h - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrTask.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrTask.h - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliInstanceLocator.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliInstanceLocator.h - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/CounterHelpers.h - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/GlobalCounter.h - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/GlobalPoller.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/GlobalPoller.h - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/GlobalStateChangeHandler.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/GlobalStateChangeHandler.h - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/GlobalStatsTracker.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/GlobalStatsTracker.h - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/MixedFrameBuffer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/MixedFrameBuffer.h - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/NonRootCounter.h - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/NonRootDriver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/NonRootDriver.h - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/NonRootSource.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/NonRootSource.h - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/PerCoreMixedFrameBuffer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/PerCoreMixedFrameBuffer.h - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessCounter.h - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessPoller.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessPoller.h - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessStateChangeHandler.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessStateChangeHandler.h - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessStateTracker.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessStateTracker.h - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessStatsTracker.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessStatsTracker.h - ${CMAKE_CURRENT_SOURCE_DIR}/xml/CurrentConfigXML.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/xml/CurrentConfigXML.h - ${CMAKE_CURRENT_SOURCE_DIR}/xml/EventsXML.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/xml/EventsXML.h - ${CMAKE_CURRENT_SOURCE_DIR}/xml/EventsXMLProcessor.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/xml/EventsXMLProcessor.h - ${CMAKE_CURRENT_SOURCE_DIR}/xml/MxmlUtils.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/xml/MxmlUtils.h - ${CMAKE_CURRENT_SOURCE_DIR}/xml/PmuXML.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/xml/PmuXML.h - ${CMAKE_CURRENT_SOURCE_DIR}/xml/PmuXMLParser.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/xml/PmuXMLParser.h + COMPILE_FLAGS -w) + +SET(GATORD_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/AnnotateListener.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/AnnotateListener.h + ${CMAKE_CURRENT_SOURCE_DIR}/AtraceDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/AtraceDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/BlockCounterFrameBuilder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/BlockCounterFrameBuilder.h + ${CMAKE_CURRENT_SOURCE_DIR}/BlockCounterMessageConsumer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/BlockCounterMessageConsumer.h + ${CMAKE_CURRENT_SOURCE_DIR}/Buffer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Buffer.h + ${CMAKE_CURRENT_SOURCE_DIR}/BufferUtils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/BufferUtils.h + ${CMAKE_CURRENT_SOURCE_DIR}/CapturedSpe.h + ${CMAKE_CURRENT_SOURCE_DIR}/CapturedXML.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/CapturedXML.h + ${CMAKE_CURRENT_SOURCE_DIR}/CCNDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/CCNDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/Child.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Child.h + ${CMAKE_CURRENT_SOURCE_DIR}/CommitTimeChecker.h + ${CMAKE_CURRENT_SOURCE_DIR}/Config.h + ${CMAKE_CURRENT_SOURCE_DIR}/Configuration.h + ${CMAKE_CURRENT_SOURCE_DIR}/ConfigurationXML.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ConfigurationXML.h + ${CMAKE_CURRENT_SOURCE_DIR}/ConfigurationXMLParser.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ConfigurationXMLParser.h + ${CMAKE_CURRENT_SOURCE_DIR}/Constant.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Constant.h + ${CMAKE_CURRENT_SOURCE_DIR}/ConstantMode.h + ${CMAKE_CURRENT_SOURCE_DIR}/Counter.h + ${CMAKE_CURRENT_SOURCE_DIR}/CounterXML.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/CounterXML.h + ${CMAKE_CURRENT_SOURCE_DIR}/CpuUtils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/CpuUtils.h + ${CMAKE_CURRENT_SOURCE_DIR}/CpuUtils_Topology.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/CpuUtils_Topology.h + ${CMAKE_CURRENT_SOURCE_DIR}/DiskIODriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/DiskIODriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/DriverCounter.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/DriverCounter.h + ${CMAKE_CURRENT_SOURCE_DIR}/Driver.h + ${CMAKE_CURRENT_SOURCE_DIR}/Drivers.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Drivers.h + ${CMAKE_CURRENT_SOURCE_DIR}/DynBuf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/DynBuf.h + ${CMAKE_CURRENT_SOURCE_DIR}/EventCode.h + ${CMAKE_CURRENT_SOURCE_DIR}/Events.h + ${CMAKE_CURRENT_SOURCE_DIR}/ExitStatus.h + ${CMAKE_CURRENT_SOURCE_DIR}/ExternalDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ExternalDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/ExternalSource.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ExternalSource.h + ${CMAKE_CURRENT_SOURCE_DIR}/Fifo.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Fifo.h + ${CMAKE_CURRENT_SOURCE_DIR}/FSDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/FSDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/FtraceDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/FtraceDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/GatorCLIFlags.h + ${CMAKE_CURRENT_SOURCE_DIR}/GatorCLIParser.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/GatorCLIParser.h + ${CMAKE_CURRENT_SOURCE_DIR}/GatorException.h + ${CMAKE_CURRENT_SOURCE_DIR}/GatorMain.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/GatorMain.h + ${CMAKE_CURRENT_SOURCE_DIR}/GetEventKey.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/GetEventKey.h + ${CMAKE_CURRENT_SOURCE_DIR}/HwmonDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/HwmonDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/IBlockCounterFrameBuilder.h + ${CMAKE_CURRENT_SOURCE_DIR}/IBlockCounterMessageConsumer.h + ${CMAKE_CURRENT_SOURCE_DIR}/IBufferControl.h + ${CMAKE_CURRENT_SOURCE_DIR}/ICpuInfo.h + ${CMAKE_CURRENT_SOURCE_DIR}/IMonitor.h + ${CMAKE_CURRENT_SOURCE_DIR}/IRawFrameBuilder.h + ${CMAKE_CURRENT_SOURCE_DIR}/ISender.h + ${CMAKE_CURRENT_SOURCE_DIR}/ISummaryConsumer.h + ${CMAKE_CURRENT_SOURCE_DIR}/LocalCapture.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/LocalCapture.h + ${CMAKE_CURRENT_SOURCE_DIR}/Logging.h + ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/MemInfoDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/MemInfoDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/MidgardDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/MidgardDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/Monitor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Monitor.h + ${CMAKE_CURRENT_SOURCE_DIR}/NetDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/NetDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/OlySocket.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/OlySocket.h + ${CMAKE_CURRENT_SOURCE_DIR}/OlyUtility.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/OlyUtility.h + ${CMAKE_CURRENT_SOURCE_DIR}/ParserResult.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ParserResult.h + ${CMAKE_CURRENT_SOURCE_DIR}/pmus_xml.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/PolledDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/PolledDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/PrimarySourceProvider.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/PrimarySourceProvider.h + ${CMAKE_CURRENT_SOURCE_DIR}/Proc.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Proc.h + ${CMAKE_CURRENT_SOURCE_DIR}/Protocol.h + ${CMAKE_CURRENT_SOURCE_DIR}/ProtocolVersion.h + ${CMAKE_CURRENT_SOURCE_DIR}/Sender.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Sender.h + ${CMAKE_CURRENT_SOURCE_DIR}/SessionData.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/SessionData.h + ${CMAKE_CURRENT_SOURCE_DIR}/SessionXML.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/SessionXML.h + ${CMAKE_CURRENT_SOURCE_DIR}/SimpleDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/SimpleDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/Source.h + ${CMAKE_CURRENT_SOURCE_DIR}/StreamlineSetup.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/StreamlineSetup.h + ${CMAKE_CURRENT_SOURCE_DIR}/StreamlineSetupLoop.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/StreamlineSetupLoop.h + ${CMAKE_CURRENT_SOURCE_DIR}/SummaryBuffer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/SummaryBuffer.h + ${CMAKE_CURRENT_SOURCE_DIR}/Time.h + ${CMAKE_CURRENT_SOURCE_DIR}/TtraceDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/TtraceDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/UEvent.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/UEvent.h + ${CMAKE_CURRENT_SOURCE_DIR}/UserSpaceSource.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/UserSpaceSource.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/agent_environment.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/agent_environment.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/agent_worker_base.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/agent_worker.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/agent_workers_process.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/common/coalescing_cpu_monitor.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/common/nl_cpu_monitor.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/common/polling_cpu_monitor.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/common/socket_listener.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/common/socket_reference.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/common/socket_worker.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/ext_source/ext_source_agent.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/ext_source/ext_source_agent_main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/ext_source/ext_source_agent_main.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/ext_source/ext_source_agent_worker.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/ext_source/ipc_sink_wrapper.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/async_buffer_builder.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/async_perf_ringbuffer_monitor.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/capture_configuration.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/capture_configuration.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/cpufreq_counter.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/cpufreq_counter.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/cpu_info.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/event_binding_manager.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/event_bindings.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/event_configuration.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/perf_activator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/perf_activator.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/perf_event_utils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/perf_event_utils.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/perf_ringbuffer_mmap.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/events/types.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_agent.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_agent_main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_agent_main.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_agent_worker.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_buffer_consumer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_buffer_consumer.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_capture_cpu_monitor.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_capture.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_capture_helper.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_driver_summary.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_driver_summary.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_frame_packer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/perf_frame_packer.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/record_types.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/source_adapter.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/source_adapter.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perf/sync_generator.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perfetto/perfetto_driver.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perfetto/perfetto_driver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/spawn_agent.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/spawn_agent.h + ${CMAKE_CURRENT_SOURCE_DIR}/android/AndroidActivityManager.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/android/AndroidActivityManager.h + ${CMAKE_CURRENT_SOURCE_DIR}/android/AppGatorRunner.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/android/AppGatorRunner.h + ${CMAKE_CURRENT_SOURCE_DIR}/android/GatorAndroidSetupHandler.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/android/GatorAndroidSetupHandler.h + ${CMAKE_CURRENT_SOURCE_DIR}/android/IAppGatorRunner.h + ${CMAKE_CURRENT_SOURCE_DIR}/android/PropertyUtils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/android/PropertyUtils.h + ${CMAKE_CURRENT_SOURCE_DIR}/android/Spawn.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/android/Spawn.h + ${CMAKE_CURRENT_SOURCE_DIR}/android/ThermalDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/android/ThermalDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/android/Utils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/android/Utils.h + ${CMAKE_CURRENT_SOURCE_DIR}/apc/misc_apc_frame_ipc_sender.h + ${CMAKE_CURRENT_SOURCE_DIR}/apc/perf_apc_frame_utils.h + ${CMAKE_CURRENT_SOURCE_DIR}/apc/perf_counter.h + ${CMAKE_CURRENT_SOURCE_DIR}/apc/summary_apc_frame_utils.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ArmNNDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ArmNNDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ArmNNSource.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ArmNNSource.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ByteOrder.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/CaptureMode.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/CounterDirectoryDecoder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/CounterDirectoryDecoder.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/CounterDirectoryStateUtils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/CounterDirectoryStateUtils.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/DecoderUtility.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/DecoderUtility.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/DriverSourceIpc.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/DriverSourceIpc.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/FrameBuilderFactory.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/FrameBuilderFactory.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/GlobalState.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/GlobalState.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IAcceptor.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ICaptureController.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ICounterConsumer.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ICounterDirectoryConsumer.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IEncoder.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IFrameBuilderFactory.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IGlobalState.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IPacketConsumer.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IPacketDecoder.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IPeriodicCounterCaptureConsumer.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IPeriodicCounterSelectionConsumer.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IPerJobCounterCaptureConsumer.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IPerJobCounterSelectionConsumer.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ISender.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ISession.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ISessionPacketSender.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/IStartStopHandler.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketDecoder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketDecoderEncoderFactory.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketDecoderEncoderFactory.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketDecoder.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketEncoder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketEncoder.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketUtility.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketUtility.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/PacketUtilityModels.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SenderQueue.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SenderQueue.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SenderThread.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SenderThread.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/Session.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/Session.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SessionPacketSender.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SessionPacketSender.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SessionStateTracker.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SessionStateTracker.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SocketAcceptor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SocketAcceptor.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SocketIO.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/SocketIO.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ThreadManagementServer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/ThreadManagementServer.h + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/TimestampCorrector.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/armnn/TimestampCorrector.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/asio_traits.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/async_line_reader.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/async/completion_handler.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/async_initiate.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/continuation.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/continuation_of.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/continuation_traits.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/cont_if.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/cont_if_state.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/continuation_factory.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/do_if.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/do_if_state.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/initiation_chain.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/loop.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/loop_state.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/map_error.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/map_error_state.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/on_executor.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/on_executor_state.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/polymorphic_state.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/predicate.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/predicate_state.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/start_state.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/state_chain.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/then.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/then_state.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/trace.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/unpack_tuple.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/unpack_tuple_state.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/unpack_variant.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/unpack_variant_state.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/detail/use_continuation_state.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/nop_receiver.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/operations.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/stored_continuation.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/continuations/use_continuation.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/netlink/nl_protocol.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/netlink/uevents.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_exec.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_exec.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_process.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_process.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_proc_poller.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_proc_poller.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_read_proc_maps.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_read_proc_sys_dependencies.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/async_wait_for_process.h + ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/process_monitor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/process_monitor.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/process_state.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/process_state_tracker.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/async/proc/wait.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/capture/CaptureProcess.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/capture/CaptureProcess.h + ${CMAKE_CURRENT_SOURCE_DIR}/capture/Environment.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/capture/Environment.h + ${CMAKE_CURRENT_SOURCE_DIR}/capture/internal/UdpListener.h + ${CMAKE_CURRENT_SOURCE_DIR}/ipc/async_streamline_sender.h + ${CMAKE_CURRENT_SOURCE_DIR}/ipc/codec.h + ${CMAKE_CURRENT_SOURCE_DIR}/ipc/message_key.h + ${CMAKE_CURRENT_SOURCE_DIR}/ipc/messages.h + ${CMAKE_CURRENT_SOURCE_DIR}/ipc/message_traits.h + ${CMAKE_CURRENT_SOURCE_DIR}/ipc/raw_ipc_channel_sink.h + ${CMAKE_CURRENT_SOURCE_DIR}/ipc/raw_ipc_channel_source.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Assert.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Assert.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/AutoClosingFd.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/EnumUtils.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/error_code_or.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/lib/exception.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/File.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/lib/FileDescriptor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/lib/FileDescriptor.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/File.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/forked_process.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/lib/forked_process.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/forked_process_utils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/lib/forked_process_utils.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Format.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/FsEntry.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/lib/FsEntry.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/FsUtils.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/GenericTimer.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Memory.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/perfetto_utils.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/PmuCommonEvents.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Popen.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Popen.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Process.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Process.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Resource.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Resource.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/SharedMemory.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/source_location.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Span.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/StaticVector.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/String.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Syscall.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Syscall.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Throw.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Time.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/TimestampSource.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/lib/TimestampSource.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Utils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Utils.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Waiter.h + ${CMAKE_CURRENT_SOURCE_DIR}/lib/WaitForProcessPoller.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/lib/WaitForProcessPoller.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/CoreOnliner.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/CoreOnliner.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/PerCoreIdentificationThread.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/PerCoreIdentificationThread.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/attr_to_key_mapping_tracker.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/IPerfAttrsConsumer.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/IPerfGroups.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfAttrsBuffer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfAttrsBuffer.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfConfig.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfDriverConfiguration.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfDriverConfiguration.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfDriverCreateSource.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfEventGroup.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfEventGroup.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfEventGroupIdentifier.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfEventGroupIdentifier.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfGroups.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfGroups.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfSyncThread.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfSyncThread.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/perf/PerfUtils.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcessChildren.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcessChildren.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcessPollerBase.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcessPollerBase.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcLoadAvgFileRecord.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcLoadAvgFileRecord.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcPidStatFileRecord.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcPidStatFileRecord.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcPidStatmFileRecord.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcPidStatmFileRecord.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcStatFileRecord.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/proc/ProcStatFileRecord.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/SysfsSummaryInformation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/SysfsSummaryInformation.h + ${CMAKE_CURRENT_SOURCE_DIR}/linux/Tracepoints.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/Tracepoints.h + ${CMAKE_CURRENT_SOURCE_DIR}/logging/agent_log.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/logging/agent_log.h + ${CMAKE_CURRENT_SOURCE_DIR}/logging/global_log.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/logging/global_log.h + ${CMAKE_CURRENT_SOURCE_DIR}/logging/logging.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/logging/suppliers.h + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/IMaliHwCntrReader.h + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliDeviceApi.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliDeviceApi_DdkDefines.h + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliDeviceApi.h + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliDevice.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliDevice.h + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliGPUClockPolledDriverCounter.h + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliGPUClockPolledDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliGPUClockPolledDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntr.h + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrNames.h + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrNamesBifrost.h + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrReader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrReader.h + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrSource.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrSource.h + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrTask.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliHwCntrTask.h + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliInstanceLocator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mali_userspace/MaliInstanceLocator.h + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/CounterHelpers.h + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/GlobalCounter.h + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/GlobalPoller.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/GlobalPoller.h + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/GlobalStateChangeHandler.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/GlobalStateChangeHandler.h + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/GlobalStatsTracker.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/GlobalStatsTracker.h + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/MixedFrameBuffer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/MixedFrameBuffer.h + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/NonRootCounter.h + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/NonRootDriver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/NonRootDriver.h + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/NonRootSource.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/NonRootSource.h + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/PerCoreMixedFrameBuffer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/PerCoreMixedFrameBuffer.h + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessCounter.h + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessPoller.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessPoller.h + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessStateChangeHandler.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessStateChangeHandler.h + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessStateTracker.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessStateTracker.h + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessStatsTracker.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/non_root/ProcessStatsTracker.h + ${CMAKE_CURRENT_SOURCE_DIR}/xml/CurrentConfigXML.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/xml/CurrentConfigXML.h + ${CMAKE_CURRENT_SOURCE_DIR}/xml/EventsXML.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/xml/EventsXML.h + ${CMAKE_CURRENT_SOURCE_DIR}/xml/EventsXMLProcessor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/xml/EventsXMLProcessor.h + ${CMAKE_CURRENT_SOURCE_DIR}/xml/MxmlUtils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/xml/MxmlUtils.h + ${CMAKE_CURRENT_SOURCE_DIR}/xml/PmuXML.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/xml/PmuXML.h + ${CMAKE_CURRENT_SOURCE_DIR}/xml/PmuXMLParser.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/xml/PmuXMLParser.h ) -SET(GATORD_SOURCES ${GATORD_SRC_FILES} - ${GATORD_3RD_PARTY_SOURCES} - ${GENERATED_MD5_SOURCE} - ${CMAKE_CURRENT_BINARY_DIR}/defaults_xml.h - ${CMAKE_CURRENT_BINARY_DIR}/events_xml.h - ${CMAKE_CURRENT_BINARY_DIR}/pmus_xml.h) +if(ANDROID) + SET(GATORD_SRC_FILES ${GATORD_SRC_FILES} + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perfetto/perfetto_agent.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perfetto/perfetto_agent_main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perfetto/perfetto_agent_main.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perfetto/perfetto_sdk_helper.h + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perfetto/perfetto_sdk_helper.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/agents/perfetto/perfetto_agent_worker.h) + SET(GATORD_3RD_PARTY_SOURCES ${GATORD_3RD_PARTY_SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/../ext/perfetto/sdk/perfetto.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../ext/perfetto/sdk/perfetto.h) +endif() # Create a list of files to hash for the generated hash file -SET(GLOB FILES_TO_HASH - ${CMAKE_CURRENT_SOURCE_DIR}/events-*.xml) -SET(FILES_TO_HASH ${FILES_TO_HASH} - ${GATORD_SRC_FILES} - ${GATORD_3RD_PARTY_SOURCES} - ${CMAKE_CURRENT_SOURCE_DIR}/events_header.xml - ${CMAKE_CURRENT_SOURCE_DIR}/events_footer.xml - ${CMAKE_CURRENT_SOURCE_DIR}/pmus.xml - ${CMAKE_CURRENT_SOURCE_DIR}/defaults.xml) -LIST(FILTER FILES_TO_HASH EXCLUDE REGEX "/ipc/proto/generated/|SrcMd5\\.cpp|_xml\\.h|events\\.xml") -CREATE_SRC_MD5( "gSrcMd5" - ${GENERATED_MD5_SOURCE} ${GENERATED_MD5_FILE} - ${FILES_TO_HASH}) +SET(GLOB FILES_TO_HASH + ${CMAKE_CURRENT_SOURCE_DIR}/events-*.xml) +SET(FILES_TO_HASH ${FILES_TO_HASH} + ${GATORD_SRC_FILES} + ${GATORD_3RD_PARTY_SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/events_header.xml + ${CMAKE_CURRENT_SOURCE_DIR}/events_footer.xml + ${CMAKE_CURRENT_SOURCE_DIR}/pmus.xml + ${CMAKE_CURRENT_SOURCE_DIR}/defaults.xml) +LIST(FILTER FILES_TO_HASH EXCLUDE REGEX "/ipc/proto/generated/|SrcMd5\\.cpp|_xml\\.h|events\\.xml") + +CREATE_SRC_MD5("gSrcMd5" "gBuildId" "${GATORD_BUILD_ID}" "${GENERATED_MD5_SOURCE}" "${GENERATED_MD5_FILE}" ${FILES_TO_HASH}) # Build the merged events.xml -FILE(GLOB EVENTS_XML_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/events-*.xml) -LIST(SORT EVENTS_XML_FILES) -LIST(REMOVE_DUPLICATES EVENTS_XML_FILES) +FILE(GLOB EVENTS_XML_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/events-*.xml) +LIST(SORT EVENTS_XML_FILES) +LIST(REMOVE_DUPLICATES EVENTS_XML_FILES) # Convert the list to a string that can be passed to the custom command SET(EVENTS_XML_FILES_STRING "${CMAKE_CURRENT_SOURCE_DIR}/events_header.xml") -FOREACH(EVENTS_XML_FILE ${EVENTS_XML_FILES}) + +FOREACH(EVENTS_XML_FILE ${EVENTS_XML_FILES}) SET(EVENTS_XML_FILES_STRING - "${EVENTS_XML_FILES_STRING};${EVENTS_XML_FILE}") + "${EVENTS_XML_FILES_STRING};${EVENTS_XML_FILE}") ENDFOREACH() + SET(EVENTS_XML_FILES_STRING "${EVENTS_XML_FILES_STRING};${CMAKE_CURRENT_SOURCE_DIR}/events_footer.xml") SET(CONCATENATED_EVENTS_XML ${CMAKE_CURRENT_BINARY_DIR}/events.xml) -ADD_CUSTOM_COMMAND(OUTPUT ${CONCATENATED_EVENTS_XML} - COMMAND ${CMAKE_COMMAND} -DOUTPUT_FILE="${CONCATENATED_EVENTS_XML}" - -DFILES_TO_CONCATENATE="${EVENTS_XML_FILES_STRING}" - -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/concatenate-files.cmake - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/events_header.xml - ${CMAKE_CURRENT_SOURCE_DIR}/events_footer.xml - ${EVENTS_XML_FILES} - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/concatenate-files.cmake) +ADD_CUSTOM_COMMAND(OUTPUT ${CONCATENATED_EVENTS_XML} + COMMAND ${CMAKE_COMMAND} -DOUTPUT_FILE="${CONCATENATED_EVENTS_XML}" + -DFILES_TO_CONCATENATE="${EVENTS_XML_FILES_STRING}" + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/concatenate-files.cmake + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/events_header.xml + ${CMAKE_CURRENT_SOURCE_DIR}/events_footer.xml + ${EVENTS_XML_FILES} + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/concatenate-files.cmake) # Macro to aid generation of xml->header files -SET(ALL_XML_HEADERS ) -MACRO(CREATE_XML_HEADER CONSTANT_NAME - SOURCE_XML_FILE - OUTPUT_HEADER_FILE) +SET(ALL_XML_HEADERS) + +MACRO(CREATE_XML_HEADER CONSTANT_NAME + SOURCE_XML_FILE + OUTPUT_HEADER_FILE) ESCAPE_FILE_TO_C_STRING("${CONSTANT_NAME}" "${SOURCE_XML_FILE}" "${OUTPUT_HEADER_FILE}") LIST(APPEND ALL_XML_HEADERS ${OUTPUT_HEADER_FILE}) ENDMACRO() # Target to generate defaults_xml.h -CREATE_XML_HEADER( DEFAULTS_XML - ${CMAKE_CURRENT_SOURCE_DIR}/defaults.xml - ${CMAKE_CURRENT_BINARY_DIR}/defaults_xml.h) +CREATE_XML_HEADER(DEFAULTS_XML + ${CMAKE_CURRENT_SOURCE_DIR}/defaults.xml + ${CMAKE_CURRENT_BINARY_DIR}/defaults_xml.h) # Target to generate pmus_xml.h -CREATE_XML_HEADER( PmuXML::DEFAULT_XML - ${CMAKE_CURRENT_SOURCE_DIR}/pmus.xml - ${CMAKE_CURRENT_BINARY_DIR}/pmus_xml.h) +CREATE_XML_HEADER(PmuXML::DEFAULT_XML + ${CMAKE_CURRENT_SOURCE_DIR}/pmus.xml + ${CMAKE_CURRENT_BINARY_DIR}/pmus_xml.h) # Target to generate events.h -CREATE_XML_HEADER( DEFAULT_EVENTS_XML - ${CONCATENATED_EVENTS_XML} - ${CMAKE_CURRENT_BINARY_DIR}/events_xml.h) - - -#### -# Find various optional tools -#### -FIND_FILE(CLANG_FORMAT NAMES "clang-format${CMAKE_EXECUTABLE_SUFFIX}" - NO_CMAKE_FIND_ROOT_PATH) -FIND_FILE(CLANG_TIDY NAMES "clang-tidy${CMAKE_EXECUTABLE_SUFFIX}" - NO_CMAKE_FIND_ROOT_PATH) +CREATE_XML_HEADER(DEFAULT_EVENTS_XML + ${CONCATENATED_EVENTS_XML} + ${CMAKE_CURRENT_BINARY_DIR}/events_xml.h) -#### -# Add a custom targets for running clang-format and clang tidy -#### -IF(EXISTS ${CLANG_FORMAT}) - ADD_CUSTOM_TARGET(clang-format - COMMAND ${CLANG_FORMAT} -i ${GATORD_SRC_FILES} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${ALL_XML_HEADERS} - SOURCES ${GATORD_SRC_FILES} - COMMENT "Run clang-format on the sources") -ENDIF() - -IF(EXISTS ${CLANG_TIDY}) - ### CMAKE_xxx_CLANG_TIDY need to be before the ADD_EXECUTABLE - OPTION(ENABLE_CLANG_TIDY_DURING_BUILD "Compile and tidy at the same time" OFF) - IF(ENABLE_CLANG_TIDY_DURING_BUILD) - SET(CMAKE_C_CLANG_TIDY ${CLANG_TIDY} -p ${CMAKE_BINARY_DIR}) - SET(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY} -p ${CMAKE_BINARY_DIR}) - ENDIF() - ADD_CUSTOM_TARGET(clang-tidy - COMMAND ${CLANG_TIDY} -p ${CMAKE_BINARY_DIR} $<$:--fix> ${GATORD_SRC_FILES} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${ALL_XML_HEADERS} - SOURCES ${GATORD_SRC_FILES} - COMMENT "Run clang-tidy on the sources") -ENDIF() +# Compile the 3rd party files separately, so that +# the clang-tidy rules can be applied only to the gatord +# target +ADD_LIBRARY(gatord-tpip OBJECT ${GATORD_3RD_PARTY_SOURCES}) # Generate the gatord executable -ADD_EXECUTABLE(gatord ${GATORD_SOURCES}) +ADD_EXECUTABLE(gatord ${GATORD_SRC_FILES} + ${GENERATED_MD5_SOURCE} + ${CMAKE_CURRENT_BINARY_DIR}/defaults_xml.h + ${CMAKE_CURRENT_BINARY_DIR}/events_xml.h + ${CMAKE_CURRENT_BINARY_DIR}/pmus_xml.h) TARGET_LINK_LIBRARIES(gatord + PRIVATE gatord-tpip PRIVATE Threads::Threads PRIVATE atomic PRIVATE mxml @@ -688,6 +684,7 @@ TARGET_LINK_LIBRARIES(gatord PRIVATE ipcproto PRIVATE dl ) + IF(NOT ANDROID) TARGET_LINK_LIBRARIES(gatord PRIVATE rt @@ -696,27 +693,67 @@ IF(NOT ANDROID) ENDIF() # Strip binary -IF (NOT((${CMAKE_BUILD_TYPE} STREQUAL "Debug") OR (${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo"))) +IF(NOT((${CMAKE_BUILD_TYPE} STREQUAL "Debug") OR(${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo"))) ADD_CUSTOM_COMMAND(TARGET gatord POST_BUILD - COMMAND ${CMAKE_STRIP} --strip-unneeded --strip-debug $ - COMMENT "Stripping gatord") + COMMAND ${CMAKE_STRIP} --strip-unneeded --strip-debug $ + COMMENT "Stripping gatord") ENDIF() - # -# Strip target? +# Strip target? # STRIP_TARGET("gatord") # Installation configuration IF(NOT DEFINED GATOR_INSTALL_PREFIX) - SET(GATOR_INSTALL_PREFIX "share/gator-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}") + SET(GATOR_INSTALL_PREFIX "share/gator-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}") +ENDIF() + +SET(GATORD_INSTALL_DIR ./${GATOR_INSTALL_PREFIX}/daemon/) + +INSTALL(TARGETS gatord + RUNTIME DESTINATION ${GATORD_INSTALL_DIR}) + +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/COPYING + DESTINATION ${GATORD_INSTALL_DIR}) + + +# ### +# Find various optional tools +# ### +FIND_FILE(CLANG_FORMAT NAMES "clang-format${CMAKE_EXECUTABLE_SUFFIX}" + NO_CMAKE_FIND_ROOT_PATH) +FIND_FILE(CLANG_TIDY NAMES "clang-tidy${CMAKE_EXECUTABLE_SUFFIX}" + NO_CMAKE_FIND_ROOT_PATH) + +# ### +# Add a custom targets for running clang-format and clang tidy +# ### +IF(EXISTS ${CLANG_FORMAT}) + ADD_CUSTOM_TARGET(clang-format + COMMAND ${CLANG_FORMAT} -i ${GATORD_SRC_FILES} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${ALL_XML_HEADERS} + SOURCES ${GATORD_SRC_FILES} + COMMENT "Run clang-format on the sources") ENDIF() -SET(GATORD_INSTALL_DIR ./${GATOR_INSTALL_PREFIX}/daemon/) +IF(EXISTS ${CLANG_TIDY}) + # ## CMAKE_xxx_CLANG_TIDY need to be before the ADD_EXECUTABLE + OPTION(ENABLE_CLANG_TIDY_DURING_BUILD "Compile and tidy at the same time" ON) -INSTALL(TARGETS gatord - RUNTIME DESTINATION ${GATORD_INSTALL_DIR}) + IF(ENABLE_CLANG_TIDY_DURING_BUILD) + SET(CMAKE_C_CLANG_TIDY ) + SET(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY} -p ${CMAKE_BINARY_DIR}) + SET_TARGET_PROPERTIES(gatord PROPERTIES + C_CLANG_TIDY "${CLANG_TIDY};-p;${CMAKE_BINARY_DIR}" + CXX_CLANG_TIDY "${CLANG_TIDY};-p;${CMAKE_BINARY_DIR}") + ENDIF() -INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/COPYING - DESTINATION ${GATORD_INSTALL_DIR}) + ADD_CUSTOM_TARGET(clang-tidy + COMMAND ${CLANG_TIDY} -p ${CMAKE_BINARY_DIR} $<$:--fix> ${GATORD_SRC_FILES} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${ALL_XML_HEADERS} + SOURCES ${GATORD_SRC_FILES} + COMMENT "Run clang-tidy on the sources") +ENDIF() diff --git a/daemon/CapturedXML.cpp b/daemon/CapturedXML.cpp index 912a1a2d..ee4eca5d 100644 --- a/daemon/CapturedXML.cpp +++ b/daemon/CapturedXML.cpp @@ -8,6 +8,7 @@ #include "Logging.h" #include "OlyUtility.h" #include "PrimarySourceProvider.h" +#include "ProtocolVersion.h" #include "SessionData.h" #include "lib/FsEntry.h" #include "lib/String.h" @@ -20,6 +21,7 @@ #include #include +#include /* Basic target OS detection */ #undef GATOR_TARGET_OS @@ -108,6 +110,11 @@ static mxml_node_t * getTree(bool includeTime, } } + if (gSessionData.mWaitForProcessCommand != nullptr) { + mxml_node_t * const process_data = mxmlNewElement(captured, "process"); + mxmlElementSetAttrf(process_data, "process_name", "%s", gSessionData.mWaitForProcessCommand); + } + auto * const target = mxmlNewElement(captured, "target"); mxmlElementSetAttrf(target, "sample_rate", "%d", gSessionData.mSampleRate); const auto & cpuInfo = primarySourceProvider.getCpuInfo(); @@ -119,14 +126,14 @@ static mxml_node_t * getTree(bool includeTime, //gatord src md5 mxmlElementSetAttrf(target, "gatord_src_md5sum", "%s", gSrcMd5); //gatord build commit id - mxmlElementSetAttrf(target, "gatord_build_id", "%s", STRIFY(GATORD_BUILD_ID)); + mxmlElementSetAttrf(target, "gatord_build_id", "%s", gBuildId); assert(cpuIds.size() > 0); // gatord should've died earlier if there were no cpus mxmlElementSetAttrf(target, "cpuid", "0x%x", *std::max_element(std::begin(cpuIds), std::end(cpuIds))); /* SDDAP-10049: Removed `&& (gSessionData.mSampleRate > 0)` - this allows sample rate: none - * to work with live mode, at the risk that live display is 'jittery' as data sending is dependent - * on CPU's being active and doing some context switching. */ + * to work with live mode, at the risk that live display is 'jittery' as data sending is dependent + * on CPU's being active and doing some context switching. */ if (!gSessionData.mOneShot) { mxmlElementSetAttr(target, "supports_live", "yes"); } @@ -161,6 +168,10 @@ static mxml_node_t * getTree(bool includeTime, mxml_node_t * counters = nullptr; for (const auto & counter : gSessionData.mCounters) { + if(counter.excludeFromCapturedXml()) { + continue; + } + if (counter.isEnabled()) { if (counters == nullptr) { counters = mxmlNewElement(captured, "counters"); diff --git a/daemon/Child.cpp b/daemon/Child.cpp index c9e0dc95..a879b514 100644 --- a/daemon/Child.cpp +++ b/daemon/Child.cpp @@ -21,12 +21,16 @@ #include "SessionData.h" #include "StreamlineSetup.h" #include "UserSpaceSource.h" +#include "agents/perfetto/perfetto_driver.h" +#include "agents/spawn_agent.h" #include "armnn/ArmNNSource.h" #include "capture/CaptureProcess.h" +#include "capture/Environment.h" #include "lib/Assert.h" #include "lib/FsUtils.h" #include "lib/WaitForProcessPoller.h" #include "lib/Waiter.h" +#include "lib/perfetto_utils.h" #include "logging/global_log.h" #include "mali_userspace/MaliHwCntrSource.h" #include "xml/EventsXML.h" @@ -38,6 +42,8 @@ #include #include +#include + #include #include #include @@ -69,14 +75,16 @@ void handleException() _exit(EXCEPTION_EXIT_CODE); } -std::unique_ptr Child::createLocal(agents::i_agent_spawner_t & spawner, +std::unique_ptr Child::createLocal(agents::i_agent_spawner_t & hi_priv_spawner, + agents::i_agent_spawner_t & lo_priv_spawner, Drivers & drivers, const Child::Config & config, capture::capture_process_event_listener_t & event_listener, logging::last_log_error_supplier_t last_error_supplier, logging::log_setup_supplier_t log_setup_supplier) { - return std::unique_ptr(new Child(spawner, + return std::unique_ptr(new Child(hi_priv_spawner, + lo_priv_spawner, drivers, nullptr, config, @@ -85,14 +93,16 @@ std::unique_ptr Child::createLocal(agents::i_agent_spawner_t & spawner, std::move(log_setup_supplier))); } -std::unique_ptr Child::createLive(agents::i_agent_spawner_t & spawner, +std::unique_ptr Child::createLive(agents::i_agent_spawner_t & hi_priv_spawner, + agents::i_agent_spawner_t & lo_priv_spawner, Drivers & drivers, OlySocket & sock, capture::capture_process_event_listener_t & event_listener, logging::last_log_error_supplier_t last_error_supplier, logging::log_setup_supplier_t log_setup_supplier) { - return std::unique_ptr(new Child(spawner, + return std::unique_ptr(new Child(hi_priv_spawner, + lo_priv_spawner, drivers, &sock, {}, @@ -118,7 +128,8 @@ void Child::signalHandler(int signum) singleton->endSession(signum); } -Child::Child(agents::i_agent_spawner_t & spawner, +Child::Child(agents::i_agent_spawner_t & hi_priv_spawner, + agents::i_agent_spawner_t & lo_priv_spawner, Drivers & drivers, OlySocket * sock, Child::Config config, @@ -136,7 +147,7 @@ Child::Child(agents::i_agent_spawner_t & spawner, config(std::move(config)), last_error_supplier(std::move(last_error_supplier)), log_setup_supplier(std::move(log_setup_supplier)), - agent_workers_process(*this, spawner) + agent_workers_process(*this, hi_priv_spawner, lo_priv_spawner) { const int fd = eventfd(0, EFD_CLOEXEC); if (fd == -1) { @@ -226,6 +237,7 @@ void Child::run() counter.getDriver()->setupCounter(counter); } } + std::vector capturedSpes; for (const auto & speConfig : speConfigs) { bool claimed = false; @@ -285,13 +297,68 @@ void Child::run() }; lib::Waiter waitTillStart; - lib::Waiter waitForAgents; + lib::Waiter waitForExternalSourceAgent; + lib::Waiter waitForPerfettoAgent; auto startedCallback = [&]() { LOG_DEBUG("Received start capture callback"); waitTillStart.disable(); }; + bool enablePerfettoAgent = drivers.getPerfettoDriver().perfettoEnabled(); + + // Initialize ftrace source before child as it's slow and depends on nothing else + // If initialized later, us gator with ftrace has time sync issues + // Must be initialized before senderThread is started as senderThread checks externalSource + if (!addSource(createExternalSource(senderSem, drivers), + [this, &waitForExternalSourceAgent, &waitForPerfettoAgent, enablePerfettoAgent](auto & source) { + this->agent_workers_process.async_add_external_source( + source, + [&waitForExternalSourceAgent](bool success) { + waitForExternalSourceAgent.disable(); + if (!success) { + handleException(); + } + else { + LOG_DEBUG("Started ext_source agent"); + } + }); +#if defined(ANDROID) || defined(__ANDROID__) + if (enablePerfettoAgent) { + this->agent_workers_process.async_add_perfetto_source( + source, + [&waitForPerfettoAgent](bool success) { + waitForPerfettoAgent.disable(); + if (!success) { + LOG_ERROR("Failed to start perfetto agent"); + handleException(); + } + else { + LOG_DEBUG("Started perfetto agent"); + } + }); + } + else { + waitForPerfettoAgent.disable(); + } +#else + (void) enablePerfettoAgent; + waitForPerfettoAgent.disable(); +#endif + })) { + LOG_ERROR("Unable to prepare external source for capture"); + handleException(); + } + + // wait for the ext agent to start + if (!sessionEnded) { + LOG_DEBUG("Waiting for agents to start"); + waitForExternalSourceAgent.wait(); + waitForPerfettoAgent.wait(); + LOG_DEBUG("Waiting for agents complete"); + } + + // create the primary source last as it will launch the process, which may lead to a race receiving external messages auto newPrimarySource = primarySourceProvider.createPrimarySource( senderSem, *sender, @@ -310,31 +377,6 @@ void Child::run() auto & primarySource = *newPrimarySource; addSource(std::move(newPrimarySource)); - // Initialize ftrace source before child as it's slow and depends on nothing else - // If initialized later, us gator with ftrace has time sync issues - // Must be initialized before senderThread is started as senderThread checks externalSource - if (!addSource(createExternalSource(senderSem, drivers), [this, &waitForAgents](auto & source) { - this->agent_workers_process.async_add_external_source(source, [&waitForAgents](bool success) { - waitForAgents.disable(); - if (!success) { - handleException(); - } - else { - LOG_DEBUG("Started ext_source agent"); - } - }); - })) { - LOG_ERROR("Unable to prepare external source for capture"); - handleException(); - } - - // wait for the ext agent to start - if (!sessionEnded) { - LOG_DEBUG("Waiting for agent to start"); - waitForAgents.wait(); - LOG_DEBUG("Waiting for agent complete"); - } - // initialize midgard hardware counters if (drivers.getMaliHwCntrs().countersEnabled()) { if (!addSource(mali_userspace::createMaliHwCntrSource(senderSem, drivers.getMaliHwCntrs()))) { @@ -518,9 +560,9 @@ void Child::durationThreadEntryPoint(const lib::Waiter & waitTillStart, const li namespace { class StreamlineCommandHandler : public IStreamlineCommandHandler { public: - StreamlineCommandHandler(Sender & sender) : sender(sender) {} + explicit StreamlineCommandHandler(Sender & sender) : sender(sender) {} - State handleRequest(char *) override + State handleRequest(char * /* unused */) override { LOG_DEBUG("INVESTIGATE: Received unknown command type COMMAND_REQUEST_XML"); return State::PROCESS_COMMANDS; diff --git a/daemon/Child.h b/daemon/Child.h index 83d1f7ae..8c209e06 100644 --- a/daemon/Child.h +++ b/daemon/Child.h @@ -36,13 +36,15 @@ class Child { std::set spes; }; - static std::unique_ptr createLocal(agents::i_agent_spawner_t & spawner, + static std::unique_ptr createLocal(agents::i_agent_spawner_t & hi_priv_spawner, + agents::i_agent_spawner_t & lo_priv_spawner, Drivers & drivers, const Config & config, capture::capture_process_event_listener_t & event_listener, logging::last_log_error_supplier_t last_error_supplier, logging::log_setup_supplier_t log_setup_supplier); - static std::unique_ptr createLive(agents::i_agent_spawner_t & spawner, + static std::unique_ptr createLive(agents::i_agent_spawner_t & hi_priv_spawner, + agents::i_agent_spawner_t & lo_priv_spawner, Drivers & drivers, OlySocket & sock, capture::capture_process_event_listener_t & event_listener, @@ -92,7 +94,8 @@ class Child { std::shared_ptr command {}; agents::agent_workers_process_t agent_workers_process; - Child(agents::i_agent_spawner_t & spawner, + Child(agents::i_agent_spawner_t & hi_priv_spawner, + agents::i_agent_spawner_t & lo_priv_spawner, Drivers & drivers, OlySocket * sock, Config config, diff --git a/daemon/Config.h b/daemon/Config.h index 4d8029f4..fe126623 100644 --- a/daemon/Config.h +++ b/daemon/Config.h @@ -23,10 +23,6 @@ #define CONFIG_SUPPORT_PERF 1 #endif -#ifndef GATORD_BUILD_ID -#define GATORD_BUILD_ID "oss" -#endif - #ifndef GATOR_SELF_PROFILE #define GATOR_SELF_PROFILE 0 #endif diff --git a/daemon/Counter.h b/daemon/Counter.h index ca885f32..fa086faf 100644 --- a/daemon/Counter.h +++ b/daemon/Counter.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2021 by Arm Limited. All rights reserved. */ +/* Copyright (C) 2013-2022 by Arm Limited. All rights reserved. */ #ifndef COUNTER_H #define COUNTER_H @@ -43,6 +43,8 @@ class Counter { int getCores() const { return mCores; } int getKey() const { return mKey; } Driver * getDriver() const { return mDriver; } + void setExcludeFromCapturedXml() { mExcludeFromCapturedXml = true; } + bool excludeFromCapturedXml() const { return mExcludeFromCapturedXml; } private: std::string mType {}; @@ -52,6 +54,7 @@ class Counter { int mCores {-1}; int mKey {0}; Driver * mDriver {nullptr}; + bool mExcludeFromCapturedXml = false; }; #endif // COUNTER_H diff --git a/daemon/CounterXML.cpp b/daemon/CounterXML.cpp index 1b5d3d31..d8021ff0 100644 --- a/daemon/CounterXML.cpp +++ b/daemon/CounterXML.cpp @@ -44,6 +44,17 @@ static mxml_node_t * getTree(bool supportsMultiEbs, auto setup_message = log_setup_supplier(); mxml_node_t * setup = mxmlNewElement(counters, "setup_warnings"); mxmlNewText(setup, 0, setup_message.c_str()); + { + std::ostringstream buffer {}; + for (auto const * driver : drivers) { + auto warnings = driver->get_other_warnings(); + for (auto const & warning : warnings) { + buffer << warning << "|" << std::endl; + } + } + auto * warning_element = mxmlNewElement(counters, "other_warnings"); + mxmlNewText(warning_element, 0, buffer.str().c_str()); + } // always send the cluster information; even on devices where not all the information is available. for (size_t cluster = 0; cluster < cpuInfo.getClusters().size(); ++cluster) { diff --git a/daemon/DiskIODriver.cpp b/daemon/DiskIODriver.cpp index bb43699b..b31a00eb 100644 --- a/daemon/DiskIODriver.cpp +++ b/daemon/DiskIODriver.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2021 by Arm Limited. All rights reserved. */ +/* Copyright (C) 2013-2022 by Arm Limited. All rights reserved. */ // Define to get format macros from inttypes.h #define __STDC_FORMAT_MACROS @@ -59,6 +59,11 @@ void DiskIODriver::doRead() return; } + constexpr size_t initialMinimum = (1 << 14) + 1; + if (mBuf.ensureCapacity(initialMinimum) != 0) { + LOG_DEBUG("Failed to ensure initial minimum size of %zu bytes for diskstats buffer", initialMinimum); + } + if (!mBuf.read("/proc/diskstats")) { LOG_ERROR("Unable to read /proc/diskstats"); handleException(); diff --git a/daemon/Driver.h b/daemon/Driver.h index 3c236ed6..615e085c 100644 --- a/daemon/Driver.h +++ b/daemon/Driver.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2021 by Arm Limited. All rights reserved. */ +/* Copyright (C) 2013-2022 by Arm Limited. All rights reserved. */ #ifndef DRIVER_H #define DRIVER_H @@ -10,6 +10,8 @@ #include #include #include +#include +#include class Counter; struct SpeConfiguration; @@ -59,6 +61,8 @@ class Driver { virtual void postChildForkInChild() {} /// Called in the parent after the gator-child process exits virtual void postChildExitInParent() {} + //Any warning messages to be displayed in Streamline post analysis of a capture. + virtual std::vector get_other_warnings() const { return {}; } // name pointer is not owned by this so should just be copied Driver(const Driver &) = default; diff --git a/daemon/Drivers.cpp b/daemon/Drivers.cpp index 7a70d06c..b70c2a19 100644 --- a/daemon/Drivers.cpp +++ b/daemon/Drivers.cpp @@ -47,8 +47,8 @@ Drivers::Drivers(bool systemWide, mPrimarySourceProvider->useFtraceDriverForCpuFrequency(), mPrimarySourceProvider->getCpuInfo().getCpuIds().size()}, mAtraceDriver {mFtraceDriver}, - mTtraceDriver {mFtraceDriver} - + mTtraceDriver {mFtraceDriver}, + mPerfettoDriver {mMaliHwCntrs.getSupportedDeviceFamilyName()} { all.push_back(&mPrimarySourceProvider->getPrimaryDriver()); for (PolledDriver * driver : mPrimarySourceProvider->getAdditionalPolledDrivers()) { @@ -68,6 +68,7 @@ Drivers::Drivers(bool systemWide, all.push_back(&mExternalDriver); all.push_back(&mCcnDriver); all.push_back(&mArmnnDriver); + all.push_back(&mPerfettoDriver); auto staticEventsXml = events_xml::getStaticTree(mPrimarySourceProvider->getCpuInfo().getClusters(), mPrimarySourceProvider->getDetectedUncorePmus()); diff --git a/daemon/Drivers.h b/daemon/Drivers.h index 9028b6bc..18e0e1d6 100644 --- a/daemon/Drivers.h +++ b/daemon/Drivers.h @@ -10,6 +10,7 @@ #include "MidgardDriver.h" #include "PrimarySourceProvider.h" #include "TtraceDriver.h" +#include "agents/perfetto/perfetto_driver.h" #include "armnn/ArmNNDriver.h" #include "lib/Span.h" #include "linux/perf/PerfDriver.h" @@ -44,6 +45,8 @@ class Drivers { ExternalDriver & getExternalDriver() { return mExternalDriver; } + agents::perfetto::perfetto_driver_t & getPerfettoDriver() { return mPerfettoDriver; } + const PrimarySourceProvider & getPrimarySourceProvider() const { return *mPrimarySourceProvider; } PrimarySourceProvider & getPrimarySourceProvider() { return *mPrimarySourceProvider; } @@ -69,6 +72,7 @@ class Drivers { FtraceDriver mFtraceDriver; AtraceDriver mAtraceDriver; TtraceDriver mTtraceDriver; + agents::perfetto::perfetto_driver_t mPerfettoDriver; std::vector all {}; std::vector allPolled {}; }; diff --git a/daemon/DynBuf.cpp b/daemon/DynBuf.cpp index 809c10e3..b6e68b05 100644 --- a/daemon/DynBuf.cpp +++ b/daemon/DynBuf.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2021 by Arm Limited. All rights reserved. */ +/* Copyright (C) 2013-2022 by Arm Limited. All rights reserved. */ #include "DynBuf.h" @@ -33,6 +33,14 @@ int DynBuf::resize(const size_t minCapacity) return 0; } +int DynBuf::ensureCapacity(size_t minCapacity) +{ + if (capacity < minCapacity) { + return resize(minCapacity); + } + return 0; +} + bool DynBuf::read(const char * const path) { bool result = false; diff --git a/daemon/DynBuf.h b/daemon/DynBuf.h index 7f23b0c7..a669823c 100644 --- a/daemon/DynBuf.h +++ b/daemon/DynBuf.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2021 by Arm Limited. All rights reserved. */ +/* Copyright (C) 2013-2022 by Arm Limited. All rights reserved. */ #ifndef DYNBUF_H #define DYNBUF_H @@ -38,6 +38,7 @@ class DynBuf { size_t getLength() const { return length; } const char * getBuf() const { return buf; } char * getBuf() { return buf; } + int ensureCapacity(size_t minCapacity); private: int resize(size_t minCapacity); diff --git a/daemon/ExternalSource.cpp b/daemon/ExternalSource.cpp index 7fb83434..4295fd83 100644 --- a/daemon/ExternalSource.cpp +++ b/daemon/ExternalSource.cpp @@ -22,6 +22,7 @@ #include "lib/Syscall.h" #include +#include #include #include @@ -326,7 +327,14 @@ class ExternalSourceImpl : public ExternalSource { mBuffer.endFrame(); // Always force-flush the buffer as this frame don't work like others checkFlush(monotonicStart, true); - close(fd); + + // remove the closed fd from the monitor and potentially from the external_agent_connections map as well + // [SDDAP-11662] - lock this to prevent async creating another pipe with the same fd + std::lock_guard lock {external_agent_connections_mutex}; + mMonitor.remove(fd); + external_agent_connections.erase(fd); + LOG_DEBUG("Closed external source pipe %d", fd); + return false; } @@ -359,11 +367,15 @@ class ExternalSourceImpl : public ExternalSource { lib::AutoClosingFd add_agent_pipe() override { + std::lock_guard lock {external_agent_connections_mutex}; + std::array pfd {{-1, -1}}; if (lib::pipe2(pfd, O_CLOEXEC) < 0) { return {}; } + LOG_DEBUG("Created new external source pipe (es=%d, ag=%d)", pfd[0], pfd[1]); + lib::AutoClosingFd read {pfd[0]}; lib::AutoClosingFd write {pfd[1]}; @@ -391,6 +403,7 @@ class ExternalSourceImpl : public ExternalSource { Monitor mMonitor {}; OlyServerSocket mMidgardStartupUds; OlyServerSocket mUtgardStartupUds; + std::mutex external_agent_connections_mutex {}; std::map external_agent_connections {}; lib::AutoClosingFd mInterruptRead {}; lib::AutoClosingFd mInterruptWrite {}; diff --git a/daemon/GatorCLIParser.cpp b/daemon/GatorCLIParser.cpp index 5a05c962..5cf0241b 100644 --- a/daemon/GatorCLIParser.cpp +++ b/daemon/GatorCLIParser.cpp @@ -4,7 +4,7 @@ #include "Config.h" #include "Logging.h" -#include "lib/Istream.h" +#include "lib/String.h" #include "lib/Utils.h" #include @@ -302,7 +302,8 @@ void GatorCLIParser::parseCLIArguments(int argc, char * argv[], const char * version_string, int maxPerformanceCounter, - const char * gSrcMd5) + const char * gSrcMd5, + const char * gBuildId) { LOG_ERROR("%s", version_string); const int indexApp = findAndUpdateCmndLineCmnd(argc, argv); @@ -473,15 +474,14 @@ void GatorCLIParser::parseCLIArguments(int argc, } break; case 'i': // pid { - std::stringstream stream {optarg}; - std::vector pids = lib::parseCommaSeparatedNumbers(stream); - if (stream.fail() || !stream.eof()) { + auto const pids = lib::parseCommaSeparatedNumbers(optarg); + if (!pids) { LOG_ERROR("Invalid value for --pid (%s), comma separated and numeric list expected.", optarg); result.parsingFailed(); return; } - result.mPids.insert(pids.begin(), pids.end()); + result.mPids.insert(pids->begin(), pids->end()); break; } case 'h': @@ -653,7 +653,7 @@ void GatorCLIParser::parseCLIArguments(int argc, result.parsingFailed(); return; case 'V': - LOG_ERROR("%s\nSRC_MD5: %s\nBUILD_ID: %s", version_string, gSrcMd5, STRIFY(GATORD_BUILD_ID)); + LOG_ERROR("%s\nSRC_MD5: %s\nBUILD_ID: %s", version_string, gSrcMd5, gBuildId); result.parsingFailed(); return; case 'O': diff --git a/daemon/GatorCLIParser.h b/daemon/GatorCLIParser.h index cf828e38..58517d50 100644 --- a/daemon/GatorCLIParser.h +++ b/daemon/GatorCLIParser.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2014-2021 by Arm Limited. All rights reserved. */ +/* Copyright (C) 2014-2022 by Arm Limited. All rights reserved. */ #ifndef GATORCLIPARSER_H_ #define GATORCLIPARSER_H_ @@ -42,7 +42,8 @@ class GatorCLIParser { char * argv[], const char * version_string, int maxPerformanceCounter, - const char * gSrcMd5); + const char * gSrcMd5, + const char * gBuildId); struct cmdline_t getGatorSetting(); private: diff --git a/daemon/GatorMain.cpp b/daemon/GatorMain.cpp index 25932219..8123f841 100644 --- a/daemon/GatorMain.cpp +++ b/daemon/GatorMain.cpp @@ -9,6 +9,7 @@ #include "GatorException.h" #include "ICpuInfo.h" #include "ParserResult.h" +#include "ProtocolVersion.h" #include "SessionData.h" #include "android/AndroidActivityManager.h" #include "android/AppGatorRunner.h" @@ -304,7 +305,7 @@ int gator_main(int argc, char ** argv) } // Parse the command line parameters GatorCLIParser parser; - parser.parseCLIArguments(argc, argv, versionString, MAX_PERFORMANCE_COUNTERS, gSrcMd5); + parser.parseCLIArguments(argc, argv, versionString, MAX_PERFORMANCE_COUNTERS, gSrcMd5, gBuildId); const ParserResult & result = parser.result; if (result.mode == ParserResult::ExecutionMode::EXIT) { handleException(); diff --git a/daemon/ISender.h b/daemon/ISender.h index 6483859d..378d0707 100644 --- a/daemon/ISender.h +++ b/daemon/ISender.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2021 by Arm Limited. All rights reserved. */ +/* Copyright (C) 2010-2022 by Arm Limited. All rights reserved. */ #ifndef __ISENDER_H__ #define __ISENDER_H__ @@ -35,7 +35,7 @@ class ISender { virtual ~ISender() = default; - static constexpr int MAX_RESPONSE_LENGTH = 16 * 1024 * 1024; + static constexpr int MAX_RESPONSE_LENGTH = 256 * 1024 * 1024; }; #endif //__ISENDER_H__ diff --git a/daemon/ParserResult.h b/daemon/ParserResult.h index 88e5adde..6d7e8c6d 100644 --- a/daemon/ParserResult.h +++ b/daemon/ParserResult.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2014-2021 by Arm Limited. All rights reserved. */ +/* Copyright (C) 2014-2022 by Arm Limited. All rights reserved. */ #ifndef PARSERRESULT_H_ #define PARSERRESULT_H_ diff --git a/daemon/ProtocolVersion.h b/daemon/ProtocolVersion.h index eb9397ae..5cd69c09 100644 --- a/daemon/ProtocolVersion.h +++ b/daemon/ProtocolVersion.h @@ -3,8 +3,8 @@ /* Define the product release version / protocol version */ -// Protocol version Streamline v8.1 -#define PROTOCOL_VERSION 810 +// Protocol version Streamline v8.2 +#define PROTOCOL_VERSION 820 // Differentiates development versions from release code #define PROTOCOL_VERSION_DEV_MULTIPLIER 100000 diff --git a/daemon/Sender.cpp b/daemon/Sender.cpp index 04a0d17a..27b32ed9 100644 --- a/daemon/Sender.cpp +++ b/daemon/Sender.cpp @@ -5,6 +5,7 @@ #include "BufferUtils.h" #include "Logging.h" #include "OlySocket.h" +#include "ProtocolVersion.h" #include "SessionData.h" #include "lib/File.h" #include "lib/String.h" diff --git a/daemon/SessionData.h b/daemon/SessionData.h index 0593d330..04f47a2e 100644 --- a/daemon/SessionData.h +++ b/daemon/SessionData.h @@ -8,7 +8,6 @@ #include "Constant.h" #include "Counter.h" #include "GatorCLIFlags.h" -#include "ProtocolVersion.h" #include "Time.h" #include "lib/SharedMemory.h" #include "mxml/mxml.h" @@ -102,6 +101,7 @@ class SessionData { extern SessionData gSessionData; extern const char * const gSrcMd5; +extern const char * const gBuildId; void logCpuNotFound(); diff --git a/daemon/agents/agent_environment.cpp b/daemon/agents/agent_environment.cpp index db4162c8..ef15c711 100644 --- a/daemon/agents/agent_environment.cpp +++ b/daemon/agents/agent_environment.cpp @@ -151,6 +151,8 @@ namespace agents { // run the main work loop io_context.run(); + threads.join(); + LOG_DEBUG("Terminating [%s] agent successfully.", env->name()); } catch (std::exception const & ex) { diff --git a/daemon/agents/agent_environment.h b/daemon/agents/agent_environment.h index ce57c48e..acd27458 100644 --- a/daemon/agents/agent_environment.h +++ b/daemon/agents/agent_environment.h @@ -80,8 +80,6 @@ namespace agents { LifecycleReceiver & lifecycle_receiver; Receiver & receiver; - void co_receive_message(std::monostate /*msg*/) { LOG_DEBUG("Unexpected monostate IPC message received."); } - auto co_receive_message(ipc::msg_shutdown_t msg) { return lifecycle_receiver.co_receive_message(msg); } template @@ -183,7 +181,8 @@ namespace agents { start_on(strand) // | then([self = this->shared_from_this()]() mutable -> polymorphic_continuation_t<> { if (std::exchange(self->is_shutdown, true)) { - LOG_DEBUG("Shutdown requested by agent, but shutdown already in progress"); + LOG_DEBUG("[%s] Shutdown requested by agent, but shutdown already in progress", + self->instance_name.c_str()); return {}; } return self->co_init_shutdown(); @@ -229,12 +228,12 @@ namespace agents { using namespace async::continuations; if (agent) { - LOG_ERROR("Start message received but agent is already running"); + LOG_ERROR("[%s] Start message received but agent is already running", instance_name.c_str()); return; } if (is_shutdown) { - LOG_ERROR("Start called after environment has shut down"); + LOG_ERROR("[%s] Start called after environment has shut down", instance_name.c_str()); return; } @@ -288,10 +287,11 @@ namespace agents { using namespace async::continuations; if (std::exchange(is_shutdown, true)) { - LOG_DEBUG("Shutdown message received, but shutdown already in progress"); + LOG_DEBUG("[%s] Shutdown message received, but shutdown already in progress", instance_name.c_str()); return {}; } + LOG_TRACE("[%s] Shutdown message received - scheduling shutdown continuation", instance_name.c_str()); // ask the agent to shutdown first, then clean up the environment return start_on(strand) | co_init_shutdown(); } @@ -320,7 +320,7 @@ namespace agents { LOG_DEBUG("Failed to send shutdown IPC to host due to %s", ec.message().c_str()); } else { - LOG_TRACE("Shutdown message sent"); + LOG_TRACE("[%s] Shutdown message sent", self->instance_name.c_str()); } self->call_shutdown_handlers(); }); diff --git a/daemon/agents/agent_worker.h b/daemon/agents/agent_worker.h index 2c55061d..2ca76cc8 100644 --- a/daemon/agents/agent_worker.h +++ b/daemon/agents/agent_worker.h @@ -2,6 +2,11 @@ #pragma once +#include "async/continuations/async_initiate.h" +#include "ipc/messages.h" + +#include + #include #include @@ -11,7 +16,6 @@ namespace agents { /** * Base interface for agent process workers */ - class i_agent_worker_t { public: /** Enumerates the possible states the agent can be in */ @@ -30,5 +34,43 @@ namespace agents { virtual ~i_agent_worker_t() noexcept = default; virtual void on_sigchild() = 0; virtual void shutdown() = 0; + + /** + * Asynchronously send an IPC message to the agent. + * + * @tparam MessageType IPC message type + * @tparam CompletionToken Continuation or callback to handle the result + * @param message Message to send + * @param io_context Context to post the result handling to + * @param token Completion token instance + * @return Continuation or void if the CompletionToken is a callback + */ + template + auto async_send_message(MessageType message, boost::asio::io_context & io_context, CompletionToken && token) + { + using namespace async::continuations; + using message_type = std::decay_t; + static_assert(ipc::is_ipc_message_type_v, "MessageType must be an IPC type"); + + return async_initiate_explicit( + [&, message = std::move(message)](auto && sc) { + this->async_send_message( + ipc::all_message_types_variant_t {std::move(message)}, + io_context, + stored_continuation_t {std::forward(sc)}); + }, + std::forward(token)); + } + + protected: + /** Implements the message sending. + * + * @param message Message to send + * @param io_context Context to post the result handling to + * @param sc Stored continuation holding the user's result handler + */ + virtual void async_send_message(ipc::all_message_types_variant_t message, + boost::asio::io_context & io_context, + async::continuations::stored_continuation_t sc) = 0; }; } diff --git a/daemon/agents/agent_worker_base.h b/daemon/agents/agent_worker_base.h index b0e5ac4e..437f1219 100644 --- a/daemon/agents/agent_worker_base.h +++ b/daemon/agents/agent_worker_base.h @@ -157,6 +157,22 @@ namespace agents { } } + virtual void async_send_message( + ipc::all_message_types_variant_t message, + boost::asio::io_context & io_context, + async::continuations::stored_continuation_t sc) override + { + std::visit( + [&](auto && msg) { + sink().async_send_message( // + std::move(msg), + [&io_context, sc = std::move(sc)](const auto & ec, const auto & /*msg*/) mutable { + resume_continuation(io_context, std::move(sc), ec); + }); + }, + std::move(message)); + } + private: using launched_notification_t = async::continuations::stored_continuation_t; diff --git a/daemon/agents/agent_workers_process.h b/daemon/agents/agent_workers_process.h index afd51fe2..1c3cc373 100644 --- a/daemon/agents/agent_workers_process.h +++ b/daemon/agents/agent_workers_process.h @@ -14,6 +14,10 @@ #include "lib/String.h" #include "lib/Syscall.h" +#if defined(ANDROID) || defined(__ANDROID__) +#include "agents/perfetto/perfetto_agent_worker.h" +#endif + #include #include #include @@ -31,6 +35,13 @@ #include namespace agents { + + /** + * An enumeration that shows whether an agent process needs to be executed in a high + * privilege session (shell), or a low privilege session (Android app user). + */ + enum class agent_privilege_level_t { high, low }; + /** * The io_context, worker threads and signal_set for the agent worker processes manager. Decoupled to allow the worker process manager to be unit tested. * @@ -42,8 +53,10 @@ namespace agents { public: static constexpr std::size_t n_threads = 2; - agent_workers_process_context_t(Parent & parent, i_agent_spawner_t & spawner) - : worker_manager(io_context, parent, spawner) + agent_workers_process_context_t(Parent & parent, + i_agent_spawner_t & hi_priv_spawner, + i_agent_spawner_t & lo_priv_spawner) + : worker_manager(io_context, parent, hi_priv_spawner, lo_priv_spawner) { signal_set.add(SIGHUP); signal_set.add(SIGINT); @@ -96,20 +109,56 @@ namespace agents { { return worker_manager.template async_add_agent>( process_monitor, + agent_privilege_level_t::low, std::forward(token), std::ref(external_souce)); } +#if defined(ANDROID) || defined(__ANDROID__) + /** + * Add the 'perfetto' agent worker + * + * @param perfetto_souce A reference to the Perfetto class which receives data from the agent process + * @param token Some completion token, called asynchronously once the agent is ready + * @return depends on completion token type + */ + template + auto async_add_perfetto_source(Perfetto & perfetto_souce, CompletionToken && token) + { + return worker_manager.template async_add_agent>( + process_monitor, + agent_privilege_level_t::high, + std::forward(token), + std::ref(perfetto_souce)); + } +#endif template auto async_add_perf_source(EventHandler & event_handler, ConfigMsg && msg, CompletionToken && token) { return worker_manager.template async_add_agent>( process_monitor, + agent_privilege_level_t::low, std::forward(token), std::ref(event_handler), std::forward(msg)); } + /** Broadcast a message to all agents, once they are ready. + * + * This will cache messages for not-ready agents, and send them when + * they become ready. + * @tparam MessageType IPC message type + * @tparam CompletionToken Continuation or callback to handle the result + * @param message Message to send + * @param token Completion token instance + * @return Continuation or void if the CompletionToken is a callback + */ + template + auto async_broadcast_when_ready(MessageType message, CompletionToken && token) + { + return worker_manager.async_broadcast_when_ready(message, token); + } + private: boost::asio::io_context io_context {}; async::proc::process_monitor_t process_monitor {io_context}; @@ -173,12 +222,14 @@ namespace agents { * * @param io_context A reference to the io_context to use * @param parent A reference to the owning object that is to receive certain notifications - * @param spawner A reference to the agent spawner object, that will launch gatord binary as agent processes + * @param hi_priv_spawner A reference to the agent spawner object that will launch an agent process with a high privilege level. + * @param lo_priv_spawner A reference to the agent spawner object that will launch an agent process with a low privilege level. */ agent_workers_process_manager_t(boost::asio::io_context & io_context, Parent & parent, - i_agent_spawner_t & spawner) - : parent(parent), spawner(spawner), io_context(io_context) + i_agent_spawner_t & hi_priv_spawner, + i_agent_spawner_t & lo_priv_spawner) + : parent(parent), hi_priv_spawner(hi_priv_spawner), lo_priv_spawner(lo_priv_spawner), io_context(io_context) { } @@ -212,7 +263,7 @@ namespace agents { else { LOG_DEBUG("Requesting all agents to shut down"); for (auto & agent : agent_workers) { - agent.second->shutdown(); + agent.second.worker->shutdown(); } } })); @@ -222,27 +273,35 @@ namespace agents { * Construct a new worker object for some newly spawned agent and add it to the set of workers * * @tparam WorkerType The type for the worker class that owns the shell-side of the IPC relationship + * @param privilege_level The privilege level under which to execute the agent process. * @param token The async completion token * @param args Any additional arguments that may be passed to the constructor of the worker type (any references must be wrapped in a std::reference_wrapper or similar) * @return Depends on the completion token type */ template - auto async_add_agent(ProcessMonitor & process_monitor, CompletionToken && token, Args &&... args) + auto async_add_agent(ProcessMonitor & process_monitor, + agent_privilege_level_t privilege_level, + CompletionToken && token, + Args &&... args) { using namespace async::continuations; return async_initiate( - [this, &process_monitor](auto &&... args) mutable { - LOG_DEBUG("Creating ext_source agent process"); + [this, &process_monitor, privilege_level](auto &&... args) mutable { + LOG_DEBUG("Creating agent process"); return start_with(std::move(args)...) // | post_on(strand) // - | then([this, &process_monitor](auto &&... args) -> polymorphic_continuation_t { + | then([this, &process_monitor, privilege_level]( + auto &&... args) -> polymorphic_continuation_t { // do nothing if already terminated if (terminated) { return start_with(false); } + auto & spawner = + privilege_level == agent_privilege_level_t::high ? hi_priv_spawner : lo_priv_spawner; + // start the process, returning the wrapper instance return async_spawn_agent_worker(io_context, spawner, @@ -271,7 +330,60 @@ namespace agents { std::forward(args)...); } + /** Broadcast a message to all agents, once they are ready. + * + * This will cache messages for not-ready agents, and send them when + * they become ready. + * @tparam MessageType IPC message type + * @tparam CompletionToken Continuation or callback to handle the result + * @param message Message to send + * @param token Completion token instance + * @return Continuation or void if the CompletionToken is a callback + */ + template + auto async_broadcast_when_ready(MessageType message, CompletionToken && token) + { + using namespace async::continuations; + using message_type = std::decay_t; + static_assert(ipc::is_ipc_message_type_v); + + return async_initiate( + [this, message = std::move(message)]() { + return start_on(strand) // + | iterate(agent_workers, + [this, message = std::move(message)](auto it) -> polymorphic_continuation_t<> { + auto & agent = it->second; + if (agent.is_ready) { + LOG_DEBUG("Sending broadcast message (%s) to agent process %d", + ipc::get_message_name(message).data(), + it->first); + return agent.worker->async_send_message(message, + strand.context(), + use_continuation) + | map_error(); + } + + LOG_DEBUG( + "Agent process %d was not ready. Broadcast message [%s] will be cached", + it->first, + ipc::get_message_name(message).data()); + agent.cached_messages.push_back(message); + return {}; + }); + }, + std::forward(token)); + } + + private: + struct agent_worker_state_t { + agent_worker_state_t(std::shared_ptr w) : worker {std::move(w)}, is_ready {false} {} + + std::shared_ptr worker; + std::deque cached_messages; + bool is_ready; + }; + /** Monitor the agent process for termination */ template static void observe_agent_pid(ProcessMonitor & process_monitor, @@ -327,10 +439,12 @@ namespace agents { } Parent & parent; - i_agent_spawner_t & spawner; + i_agent_spawner_t & hi_priv_spawner; + i_agent_spawner_t & lo_priv_spawner; boost::asio::io_context & io_context; boost::asio::io_context::strand strand {io_context}; - std::map> agent_workers {}; + std::map agent_workers {}; + std::deque delayed_broadcasts {}; bool created_any = false; bool terminated = false; @@ -372,6 +486,96 @@ namespace agents { on_strand_check_terminated(); })); } + else if (new_state == i_agent_worker_t::state_t::ready) { + spawn("Handle agent ready notification operation", + start_on(strand) // + | then([this, pid]() -> polymorphic_continuation_t<> { + auto it = agent_workers.find(pid); + if (it == agent_workers.end()) { + LOG_DEBUG("Unknown agent PID: %d", pid); + return {}; + } + + auto & agent = it->second; + agent.is_ready = true; + + // Send all the cached messages asynchronously, stopping when they're + // all sent or when the agent is terminated + return start_with(false, pid) // + | loop( + [this](auto cheap_exit, auto pid) -> // + polymorphic_continuation_t { + if (cheap_exit) { + return start_with(false, false, pid); + } + + return start_on(strand) // + | then([this, pid]() { + LOG_DEBUG("Looking for pid %d", pid); + auto it = agent_workers.find(pid); + if (it == agent_workers.end()) { + LOG_DEBUG("pid not found"); + return start_with(it != agent_workers.end(), + false, + pid); + } + + LOG_DEBUG("Cached messages empty: %d", + it->second.cached_messages.empty()); + return start_with(!it->second.cached_messages.empty(), + false, + pid); + }); + }, + [this](auto /*cheap_exit*/, auto pid) { + return start_on(strand) // + | then([this, pid]() -> // + polymorphic_continuation_t { + auto it = agent_workers.find(pid); + if (it == agent_workers.end()) { + LOG_DEBUG("Not sending cached message: agent " + "was terminated"); + // Agent has been terminated and won't be coming + // back, so skip the map lookup in the predicate + return start_with(true, pid); + } + + auto & agent = it->second; + if (agent.cached_messages.empty()) { + // Now that the agent is marked as ready, new + // messages will be sent immediately, so we + // can use the cheap exit as cached_messages + // won't be used again + return start_with(true, pid); + } + + auto message = + std::move(agent.cached_messages.front()); + agent.cached_messages.pop_front(); + + return std::visit( + [&](auto msg) + -> polymorphic_continuation_t { + LOG_DEBUG("Sending cached broadcast message " + "(%s) to agent process %d", + ipc::get_message_name(msg).data(), + pid); + + return agent.worker->async_send_message( + std::move(msg), + strand.context(), + use_continuation) + | map_error() // + | then([pid]() { + return start_with(false, pid); + }); + }, + message); + }); + }) + | then([](auto...) {}); // Consume the loop output + })); + } }; } }; diff --git a/daemon/agents/ext_source/ext_source_agent.h b/daemon/agents/ext_source/ext_source_agent.h index e5e24ecd..ac9e0629 100644 --- a/daemon/agents/ext_source/ext_source_agent.h +++ b/daemon/agents/ext_source/ext_source_agent.h @@ -230,9 +230,6 @@ namespace agents { LOG_TRACE("Closing worker %d (%p)", it->first, worker.get()); - // remove from the map - self->socket_workers.erase(it); - static_assert(!std::is_const_v); return worker->async_close(use_continuation); }) @@ -329,6 +326,12 @@ namespace agents { async::continuations::polymorphic_continuation_t<> co_close_worker_by_id(ipc::annotation_uid_t id) { using namespace async::continuations; + if (is_shutdown) { + LOG_DEBUG("Ignoring connection close request for ID [%d] since this agent is shutting down and all " + "connections will be closed.", + id); + return {}; + } auto self = this->shared_from_this(); diff --git a/daemon/agents/ext_source/ext_source_agent_worker.h b/daemon/agents/ext_source/ext_source_agent_worker.h index 718292cc..1d506732 100644 --- a/daemon/agents/ext_source/ext_source_agent_worker.h +++ b/daemon/agents/ext_source/ext_source_agent_worker.h @@ -105,60 +105,6 @@ namespace agents { }); } - /** Handle one of the IPC variant values */ - static void cont_on_recv_message(std::monostate const & /*message*/) - { - LOG_DEBUG("Unexpected message std::monostate; ignoring"); - } - - /** Handle one of the IPC variant values */ - static void cont_on_recv_message(ipc::msg_capture_configuration_t const & /*message*/) - { - LOG_DEBUG("Unexpected message ipc::msg_capture_ready_t; ignoring"); - } - - /** Handle one of the IPC variant values */ - static void cont_on_recv_message(ipc::msg_capture_ready_t const & /*message*/) - { - LOG_DEBUG("Unexpected message ipc::msg_capture_ready_t; ignoring"); - } - - /** Handle one of the IPC variant values */ - static void cont_on_recv_message(ipc::msg_apc_frame_data_t const & /*message*/) - { - LOG_DEBUG("Unexpected message ipc::msg_apc_frame_data_t; ignoring"); - } - - /** Handle one of the IPC variant values */ - static void cont_on_recv_message(ipc::msg_start_t const & /*message*/) - { - LOG_DEBUG("Unexpected message ipc::msg_start_t; ignoring"); - } - - /** Handle one of the IPC variant values */ - static void cont_on_recv_message(ipc::msg_exec_target_app_t const & /*message*/) - { - LOG_DEBUG("Unexpected message ipc::msg_exec_target_app_t; ignoring"); - } - - /** Handle one of the IPC variant values */ - static void cont_on_recv_message(ipc::msg_cpu_state_change_t const & /*message*/) - { - LOG_DEBUG("Unexpected message ipc::msg_cpu_state_change_t; ignoring"); - } - - /** Handle one of the IPC variant values */ - static void cont_on_recv_message(ipc::msg_capture_failed_t const & /*message*/) - { - LOG_DEBUG("Unexpected message ipc::msg_capture_failed_t; ignoring"); - } - - /** Handle one of the IPC variant values */ - static void cont_on_recv_message(ipc::msg_capture_started_t const & /*message*/) - { - LOG_DEBUG("Unexpected message ipc::msg_capture_started_t; ignoring"); - } - /** Handle the 'ready' IPC message variant. The agent is ready. */ void cont_on_recv_message(ipc::msg_ready_t const & /*message*/) { @@ -217,7 +163,7 @@ namespace agents { auto uid = message.header; auto it = external_source_pipes.find(uid); if (it == external_source_pipes.end()) { - LOG_ERROR("Received data for external source but no pipe found"); + LOG_DEBUG("Received data for external source but no pipe found"); return {}; } @@ -232,7 +178,7 @@ namespace agents { | then([buffer_ptr, uid, st = this->shared_from_this()](auto const & ec, auto n) -> polymorphic_continuation_t<> { if (ec) { - LOG_ERROR("Forwarding external bytes failed due to %s", ec.message().c_str()); + LOG_DEBUG("Forwarding external bytes failed due to %s", ec.message().c_str()); return st->cont_close_annotation_uid(uid); } if (n != buffer_ptr->size()) { @@ -244,12 +190,6 @@ namespace agents { }); } - /** Handle the 'send' IPC message variant. The agent received data from a connection. */ - static void cont_on_recv_message(ipc::msg_annotation_send_bytes_t const & /*message*/) - { - LOG_DEBUG("Unexpected message ipc::msg_annotation_send_bytes_t; ignoring"); - } - /** Handle the 'close conn' IPC message variant. The agent closed a connection. */ void cont_on_recv_message(ipc::msg_annotation_close_conn_t const & message) { @@ -284,9 +224,14 @@ namespace agents { return true; }, [st]() { - return st->source().async_recv_message(use_continuation) // - | map_error() // - | post_on(st->strand) // + return ipc::async_receive_one_of(st->source_shared(), + use_continuation) // + | map_error() // + | post_on(st->strand) // | unpack_variant([st](auto && message) { // NOLINTNEXTLINE(bugprone-move-forwarding-reference) return st->cont_on_recv_message(std::move(message)); diff --git a/daemon/agents/perf/events/perf_ringbuffer_mmap.hpp b/daemon/agents/perf/events/perf_ringbuffer_mmap.hpp index df3b4560..858566fc 100644 --- a/daemon/agents/perf/events/perf_ringbuffer_mmap.hpp +++ b/daemon/agents/perf/events/perf_ringbuffer_mmap.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include diff --git a/daemon/agents/perf/perf_agent_worker.h b/daemon/agents/perf/perf_agent_worker.h index 496d430e..6ee4fda0 100644 --- a/daemon/agents/perf/perf_agent_worker.h +++ b/daemon/agents/perf/perf_agent_worker.h @@ -162,11 +162,6 @@ namespace agents::perf { }); } - static auto co_receive_message(const std::monostate & /*msg*/) - { - LOG_ERROR("Unexpected monostate message received in perf worker."); - } - /** * Handle the 'ready' message - the agent has started and is waiting to be configured. */ @@ -195,10 +190,10 @@ namespace agents::perf { * Handle the 'capture ready' message - the agent has been configured and is prepared to * start the capture. */ - auto co_receive_message(const ipc::msg_capture_ready_t & /*msg*/) + auto co_receive_message(ipc::msg_capture_ready_t && msg) { LOG_DEBUG("Perf agent is prepared for capture"); - observer.on_capture_ready(); + observer.on_capture_ready(std::move(msg.suffix)); } /** diff --git a/daemon/agents/perf/perf_buffer_consumer.cpp b/daemon/agents/perf/perf_buffer_consumer.cpp index 4a9e52fd..63ed88a1 100644 --- a/daemon/agents/perf/perf_buffer_consumer.cpp +++ b/daemon/agents/perf/perf_buffer_consumer.cpp @@ -58,6 +58,8 @@ namespace agents::perf { } } + runtime_assert(buffer.size() <= ISender::MAX_RESPONSE_LENGTH, "Too large APC frame created"); + // send the message return st->ipc_sink->async_send_message(ipc::msg_apc_frame_data_t {std::move(buffer)}, use_continuation) // | then([head, tail](auto ec, auto /*msg*/) { diff --git a/daemon/agents/perf/source_adapter.cpp b/daemon/agents/perf/source_adapter.cpp index dfdf2d38..338ab83c 100644 --- a/daemon/agents/perf/source_adapter.cpp +++ b/daemon/agents/perf/source_adapter.cpp @@ -13,7 +13,7 @@ namespace agents::perf { perf_source_adapter_t::perf_source_adapter_t(sem_t & sender_sem, ISender & sender, - std::function agent_started_callback, + std::function)> agent_started_callback, std::function exec_target_app_callback, std::function profiling_started_callback) : sender_sem(sender_sem), @@ -25,7 +25,10 @@ namespace agents::perf { { } - std::optional perf_source_adapter_t::sendSummary() { return {getTime()}; } + std::optional perf_source_adapter_t::sendSummary() + { + return {getTime()}; + } void perf_source_adapter_t::run(std::uint64_t monotonicStart, std::function endSession) { @@ -50,7 +53,7 @@ namespace agents::perf { perf_capture_controller_t * capture_controller = nullptr; { - auto l = std::unique_lock(event_mutex); + auto lock = std::unique_lock(event_mutex); shutdown_initiated_from_shell = true; capture_controller = this->capture_controller.get(); } @@ -61,7 +64,10 @@ namespace agents::perf { } } - bool perf_source_adapter_t::write(ISender & /*sender*/) { return capture_ended.load(std::memory_order_relaxed); } + bool perf_source_adapter_t::write(ISender & /*sender*/) + { + return capture_ended.load(std::memory_order_relaxed); + } void perf_source_adapter_t::set_controller(std::unique_ptr controller) { @@ -69,15 +75,15 @@ namespace agents::perf { capture_controller = std::move(controller); } - void perf_source_adapter_t::on_capture_ready() + void perf_source_adapter_t::on_capture_ready(std::vector monitored_pids) { - std::function f; + std::function)> f; { auto lock = std::unique_lock(event_mutex); - f = std::move(agent_started_callback); + f = std::exchange(agent_started_callback, std::function)>()); } if (f) { - f(true); + f(true, std::move(monitored_pids)); } } @@ -86,7 +92,7 @@ namespace agents::perf { std::function f; { auto lock = std::unique_lock(event_mutex); - f = profiling_started_callback; + f = std::exchange(profiling_started_callback, std::function()); runtime_assert(!agent_started_callback, "on_capture_ready was not called"); } @@ -99,19 +105,19 @@ namespace agents::perf { { capture_ended.store(true, std::memory_order_relaxed); - std::function local_agent_started; + std::function)> local_agent_started; std::function local_end_session; { auto lock = std::unique_lock(event_mutex); - local_agent_started = std::move(agent_started_callback); + local_agent_started = std::exchange(agent_started_callback, std::function)>()); if (!shutdown_initiated_from_shell) { - local_end_session = std::move(end_session); + local_end_session = std::exchange(end_session, std::function()); } } if (local_agent_started) { - local_agent_started(false); + local_agent_started(false, std::vector {}); } if (local_end_session) { @@ -125,6 +131,7 @@ namespace agents::perf { void perf_source_adapter_t::on_apc_frame_received(const std::vector & frame) { auto const length = frame.size(); + runtime_assert(length <= ISender::MAX_RESPONSE_LENGTH, "too large apc_frame msg received"); sender.writeData(frame.data(), static_cast(length), ResponseType::APC_DATA); @@ -148,5 +155,8 @@ namespace agents::perf { } } - void perf_source_adapter_t::exec_target_app() { exec_target_app_callback(); } + void perf_source_adapter_t::exec_target_app() + { + exec_target_app_callback(); + } } diff --git a/daemon/agents/perf/source_adapter.h b/daemon/agents/perf/source_adapter.h index 6c591589..82fe872a 100644 --- a/daemon/agents/perf/source_adapter.h +++ b/daemon/agents/perf/source_adapter.h @@ -22,7 +22,7 @@ namespace agents::perf { public: explicit perf_source_adapter_t(sem_t & sender_sem, ISender & sender, - std::function agent_started_callback, + std::function)> agent_started_callback, std::function exec_target_app_callback, std::function profiling_started_callback); @@ -58,8 +58,10 @@ namespace agents::perf { * Called by the agent worker once the agent ready message has been received. * * CALLED FROM THE ASIO THREAD POOL + * @param monitored_pids A list of PIDs being monitored by the worker, + * only the primary source (i.e. the perf agent) will provide these */ - void on_capture_ready(); + void on_capture_ready(std::vector monitored_pids = {}); /** * Called by the agent worker once the start message has been sent successfully. @@ -106,7 +108,7 @@ namespace agents::perf { // variables that are guarded by the event_mutex std::mutex event_mutex; - std::function agent_started_callback; + std::function)> agent_started_callback; std::function exec_target_app_callback; std::function profiling_started_callback; std::unique_ptr capture_controller; diff --git a/daemon/agents/perfetto/perfetto_agent.h b/daemon/agents/perfetto/perfetto_agent.h new file mode 100644 index 00000000..37b7c8e4 --- /dev/null +++ b/daemon/agents/perfetto/perfetto_agent.h @@ -0,0 +1,217 @@ +/* Copyright (C) 2022 by Arm Limited. All rights reserved. */ +#pragma once + +#include "Logging.h" +#include "agents/agent_environment.h" +#include "agents/common/socket_listener.h" +#include "agents/common/socket_reference.h" +#include "agents/common/socket_worker.h" +#include "agents/ext_source/ipc_sink_wrapper.h" +#include "agents/perfetto/perfetto_sdk_helper.h" +#include "android/PropertyUtils.h" +#include "async/completion_handler.h" +#include "async/continuations/continuation.h" +#include "async/continuations/operations.h" +#include "async/continuations/use_continuation.h" +#include "ipc/messages.h" +#include "ipc/raw_ipc_channel_sink.h" +#include "ipc/raw_ipc_channel_source.h" +#include "lib/Utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace agents { + /** + * The main agent object for the perfetto agent + */ + template + class perfetto_agent_t : public std::enable_shared_from_this> { + static constexpr std::size_t buffer_sz = 4096; + static constexpr std::array protocol_handshake_tag = + {'P', 'E', 'R', 'F', 'E', 'T', 'T', 'O', '\n', '\x0A', '\0'}; + + public: + using accepted_message_types = std::tuple; + + using perfetto_sdk_helper_t = PerfettoSdkHelper; + + static std::shared_ptr> create( + boost::asio::io_context & io_context, + std::shared_ptr ipc_sink, + agent_environment_base_t::terminator terminator, + std::shared_ptr perfetto_sdk_helper) + { + return std::make_shared>(io_context, + std::move(ipc_sink), + std::move(terminator), + perfetto_sdk_helper); + } + + perfetto_agent_t(boost::asio::io_context & io_context, + std::shared_ptr ipc_sink, + [[maybe_unused]] agent_environment_base_t::terminator terminator, + std::shared_ptr perfetto_sdk_helper) + : io_context(io_context), + strand(io_context), + ipc_sink(std::move(ipc_sink)), + perfetto_sdk_helper(perfetto_sdk_helper), + buffer(buffer_sz, '\0') + { + graphics_property_value = android_prop_utils::readProperty(GRAPHICS_PROFILER_PROPERTY.data(), false); + if (!android_prop_utils::setProperty(GRAPHICS_PROFILER_PROPERTY.data(), + GRAPHICS_PROFILER_PROPERTY_VALUE.data())) { + LOG_WARNING("Failed to set graphics property %s", GRAPHICS_PROFILER_PROPERTY.data()); + } + perfetto_sdk_helper->initialize_sdk(); + } + + ~perfetto_agent_t() + { + if (graphics_property_value) { + android_prop_utils::setProperty(GRAPHICS_PROFILER_PROPERTY.data(), + graphics_property_value.value().c_str()); + } + } + + async::continuations::polymorphic_continuation_t<> co_shutdown() + { + LOG_DEBUG("Got a shutdown request"); + using namespace async::continuations; + return start_on(strand) | then([self = this->shared_from_this()]() mutable -> polymorphic_continuation_t<> { + if (std::exchange(self->is_shutdown, true)) { + return {}; + } + return self->cont_shutdown(); + }); + } + + async::continuations::polymorphic_continuation_t<> co_receive_message(ipc::msg_perfetto_close_conn_t /*msg*/) + { + using namespace async::continuations; + + return start_on(strand) | then([self = this->shared_from_this()]() mutable -> polymorphic_continuation_t<> { + self->perfetto_sdk_helper->stop_sdk(); + return {}; + }); + } + + async::continuations::polymorphic_continuation_t<> co_receive_message(const ipc::msg_monitored_pids_t & /*msg*/) + { + LOG_DEBUG("Got monitored pids message"); + + if (!perfetto_sdk_helper->start_trace()) { + LOG_ERROR("Could not start the perfetto trace. This agent will shut down."); + return co_shutdown(); + } + + spawn("Perfetto Read Loop", co_send_initial_frame()); + return {}; + } + + private: + boost::asio::io_context & io_context; + boost::asio::io_context::strand strand; + std::shared_ptr ipc_sink; + bool is_shutdown {false}; + std::optional graphics_property_value; + + std::shared_ptr perfetto_sdk_helper {}; + + std::vector buffer; + + static constexpr std::string_view GRAPHICS_PROFILER_PROPERTY = "debug.graphics.gpu.profiler.perfetto"; + static constexpr std::string_view GRAPHICS_PROFILER_PROPERTY_VALUE = "1"; + + async::continuations::polymorphic_continuation_t<> cont_shutdown() + { + using namespace async::continuations; + return start_on(strand) // + | then([self = this->shared_from_this()]() mutable { + self->is_shutdown = true; + self->perfetto_sdk_helper->stop_sdk(); + }); + } + + async::continuations::polymorphic_continuation_t<> co_send_initial_frame() + { + using namespace async::continuations; + return start_on(strand) // + | then([self = this->shared_from_this()]() { + std::vector payload(self->protocol_handshake_tag.begin(), + self->protocol_handshake_tag.end()); + return start_on(self->strand) // + | self->ipc_sink->async_send_message(ipc::msg_perfetto_recv_bytes_t {std::move(payload)}, + use_continuation) + | then([self](const auto & ec, auto /*msg*/) mutable -> polymorphic_continuation_t<> { + if (ec) { + LOG_ERROR("Failed to send perfetto handshake frame: %s", ec.message().c_str()); + return self->co_shutdown(); + } + return self->co_read_perfetto_trace(); + }); + }); + } + + async::continuations::polymorphic_continuation_t<> co_forward_to_shell(std::size_t size) + { + using namespace async::continuations; + if (size == 0) { + return co_read_perfetto_trace(); + } + + auto range_start = buffer.begin(); + auto range_end = range_start + size; + + std::vector payload(range_start, range_end); + return ipc_sink->async_send_message(ipc::msg_perfetto_recv_bytes_t {std::move(payload)}, use_continuation) + | then([self = this->shared_from_this()](const auto & err, + auto /*msg*/) mutable -> polymorphic_continuation_t<> { + if (err) { + LOG_ERROR("Could not send perfetto data to the gatord shell instance: %s", + err.message().c_str()); + return self->co_shutdown(); + } + + if (self->is_shutdown) { + LOG_TRACE("Shutdown requested - breaking out of perfetto read loop"); + return {}; + } + + return self->co_read_perfetto_trace(); + }); + } + + auto co_read_perfetto_trace() + { + using namespace async::continuations; + auto self = this->shared_from_this(); + + return start_on(strand) + | do_if([self]() { return !self->is_shutdown; }, + [self]() { + return start_on(self->strand) + | self->perfetto_sdk_helper->async_read_trace( + {self->buffer.data(), self->buffer.size()}, + use_continuation) + | then([self](auto err, auto size) { + if (err) { + LOG_ERROR("Received an error while trying to read perfetto data: %s", + err.message().c_str()); + return self->co_shutdown(); + } + return self->co_forward_to_shell(size); + }); + }); + } + }; +}; diff --git a/daemon/agents/perfetto/perfetto_agent_main.cpp b/daemon/agents/perfetto/perfetto_agent_main.cpp new file mode 100644 index 00000000..144aa7fc --- /dev/null +++ b/daemon/agents/perfetto/perfetto_agent_main.cpp @@ -0,0 +1,33 @@ +/* Copyright (C) 2022 by Arm Limited. All rights reserved. */ +#include "agents/perfetto/perfetto_agent_main.h" + +#include "Logging.h" +#include "agents/agent_environment.h" +#include "agents/perfetto/perfetto_agent.h" +#include "agents/perfetto/perfetto_sdk_helper.h" +#include "ipc/raw_ipc_channel_source.h" + +#include + +namespace agents { + + int perfetto_agent_main(char const * /*argv0*/, lib::Span args) + { + return start_agent(args, [](auto /*args*/, auto & io, auto & pm, auto ipc_sink, auto ipc_source) { + auto factory = [](auto & io, auto & /*pm*/, auto sink, auto terminator) { + auto agent = perfetto_agent_t<>::create(io, + std::move(sink), + std::move(terminator), + std::make_shared(io)); + return agent; + }; + + return agent_environment_t>::create("gator-agent-pfto", + io, + pm, + std::move(factory), + std::move(ipc_sink), + std::move(ipc_source)); + }); + } +}; diff --git a/daemon/agents/perfetto/perfetto_agent_main.h b/daemon/agents/perfetto/perfetto_agent_main.h new file mode 100644 index 00000000..b1f32ef8 --- /dev/null +++ b/daemon/agents/perfetto/perfetto_agent_main.h @@ -0,0 +1,9 @@ +/* Copyright (C) 2022 by Arm Limited. All rights reserved. */ +#pragma once + +#include "lib/Span.h" + +namespace agents { + /** Agent entry point */ + int perfetto_agent_main(char const * argv0, lib::Span args); +}; diff --git a/daemon/agents/perfetto/perfetto_agent_worker.h b/daemon/agents/perfetto/perfetto_agent_worker.h new file mode 100644 index 00000000..193e2568 --- /dev/null +++ b/daemon/agents/perfetto/perfetto_agent_worker.h @@ -0,0 +1,201 @@ +/* Copyright (C) 2021-2022 by Arm Limited. All rights reserved. */ +#pragma once + +#include "agents/agent_worker_base.h" +#include "agents/spawn_agent.h" +#include "async/continuations/continuation.h" +#include "async/continuations/operations.h" +#include "async/continuations/use_continuation.h" +#include "ipc/messages.h" + +#include +#include +#include +#include +#include +#include +#include +namespace agents { + + template + class perfetto_agent_worker_t : public agent_worker_base_t, + public std::enable_shared_from_this> { + private: + boost::asio::io_context::strand strand; + PerfettoSource & perfetto_source; + std::optional perfetto_source_pipe {}; + + /** @return A continuation that requests the remote agent to shutdown */ + auto cont_shutdown() + { + using namespace async::continuations; + + return start_on(strand) // + | then([st = this->shared_from_this()]() -> polymorphic_continuation_t<> { + if (!st->transition_state(state_t::shutdown_requested)) { + LOG_DEBUG("Perfetto agent worker failed to transition to the shutdown_requested state"); + return {}; + } + + // tell the remote agent + LOG_DEBUG("Requesting perfetto agent to shut down"); + return st->sink().async_send_message(ipc::msg_shutdown_t {}, use_continuation) // + | then([st](auto const & ec, auto const & /*msg*/) { + if (ec) { + // EOF means terminated + if (ec == boost::asio::error::eof) { + st->transition_state(state_t::terminated); + return; + } + + LOG_DEBUG("Failed to send IPC message due to %s", ec.message().c_str()); + } + }); + }); + } + + auto cont_on_recv_message(ipc::msg_perfetto_recv_bytes_t && msg) + { + using namespace async::continuations; + + const auto * data = msg.suffix.data(); + return boost::asio::async_write(*perfetto_source_pipe, // + boost::asio::buffer(data, msg.suffix.size()), // + use_continuation) // + | then([self = this->shared_from_this(), + msg = std::move(msg)](const auto & err, auto n) -> polymorphic_continuation_t<> { + if (err) { + LOG_DEBUG("Error while forwarding perfetto source bytes: %s", err.message().c_str()); + return self->cont_shutdown(); + } + if (n != msg.suffix.size()) { + LOG_ERROR("Incorrect size written"); + return self->cont_shutdown(); + } + return {}; + }); + } + + /** Handle the 'ready' IPC message variant. The agent is ready. */ + void cont_on_recv_message(ipc::msg_ready_t const & /*message*/) + { + LOG_DEBUG("Received ready message."); + + if (perfetto_source_pipe) { + LOG_ERROR("Perfetto external data pipe already created."); + return; + } + + auto pipe = perfetto_source.add_agent_pipe(); + + if (!pipe) { + LOG_ERROR("Failed to create perfetto data pipe"); + return; + } + + perfetto_source_pipe = boost::asio::posix::stream_descriptor {strand.context(), pipe.release()}; + + // transition state + if (transition_state(state_t::ready)) { + LOG_DEBUG("Perfetto agent is now ready"); + } + } + + /** Handle the 'shutdown' IPC message variant. The agent is shutdown. */ + void cont_on_recv_message(ipc::msg_shutdown_t const & /*message*/) + { + LOG_DEBUG("Received shutdown message."); + + //close the write end. + perfetto_source_pipe.reset(); + + // transition state + if (transition_state(state_t::shutdown_received)) { + LOG_DEBUG("Perfetto agent is now shut down"); + } + } + + auto cont_recv_message_loop() + { + using namespace async::continuations; + using namespace ipc; + + auto st = this->shared_from_this(); + + return repeatedly( + [st]() { + // don't stop until the agent terminates and closes the connection from its end + LOG_DEBUG("Receive loop would have terminated? %d", + (st->get_state() >= state_t::terminated_pending_message_loop)); + return true; + }, + [st]() { + return async_receive_one_of( + st->source_shared(), + use_continuation) + | map_error() // + | post_on(st->strand) // + | unpack_variant([st](auto && message) { + // NOLINTNEXTLINE(bugprone-move-forwarding-reference) + return st->cont_on_recv_message(std::move(message)); + }); + }); + } + + public: + static constexpr char const * get_agent_process_id() { return agent_id_perfetto.data(); } + + perfetto_agent_worker_t(boost::asio::io_context & io_context, + agent_process_t && agent_process, + state_change_observer_t && state_change_observer, + PerfettoSource & perfetto_source) + : agent_worker_base_t(std::move(agent_process), std::move(state_change_observer)), + strand(io_context), + perfetto_source(perfetto_source) + { + } + + /** Start the worker. Spawns the receive-message loop on the io_context */ + [[nodiscard]] bool start() + { + using namespace async::continuations; + + spawn("IPC message loop", + cont_recv_message_loop(), // + [st = this->shared_from_this()](bool error) { + LOG_DEBUG("Receive loop ended"); + + boost::asio::post(st->strand, [st]() { st->set_message_loop_terminated(); }); + + if (error) { + st->shutdown(); + } + }); + + return this->exec_agent(); + } + + /** Called when SIGCHLD is received for the remote process */ + void on_sigchild() override + { + using namespace async::continuations; + spawn("SIGCHLD handler operation", + start_on(strand) // + | then([st = this->shared_from_this()]() { + if (st->transition_state(state_t::terminated)) { + LOG_DEBUG("perfetto agent is now terminated"); + } + })); + } + + /** Called to shutdown the remote process and worker */ + void shutdown() override + { + using namespace async::continuations; + spawn("Shutdown request", cont_shutdown()); + } + + protected: + [[nodiscard]] boost::asio::io_context::strand & work_strand() override { return strand; } + }; +} diff --git a/daemon/agents/perfetto/perfetto_driver.cpp b/daemon/agents/perfetto/perfetto_driver.cpp new file mode 100644 index 00000000..c73c0213 --- /dev/null +++ b/daemon/agents/perfetto/perfetto_driver.cpp @@ -0,0 +1,89 @@ +/* Copyright (C) 2022 by Arm Limited. All rights reserved. */ +#include "agents/perfetto/perfetto_driver.h" + +#include "Logging.h" +#include "SessionData.h" +#include "capture/Environment.h" +#include "k/perf_event.h" +#include "lib/perfetto_utils.h" + +#include + +namespace agents::perfetto { + + perfetto_driver_t::perfetto_driver_t(const char * maliFamilyName) + : PolledDriver("MaliTimeline") + { + if(maliFamilyName != nullptr) { + this->maliFamilyName = maliFamilyName; + } + } + + void perfetto_driver_t::setupCounter(Counter & counter) { + counter.setExcludeFromCapturedXml(); + perfetto_requested = true; + + std::string error_message = get_error_message(); + if (error_message.empty()) { + perfetto_enabled = true; + } else { + LOG_SETUP(error_message); + } + } + + void perfetto_driver_t::writeEvents(mxml_node_t * root) const + { + root = mxmlNewElement(root, "category"); + mxmlElementSetAttr(root, "name", "Mali Timeline"); + root = mxmlNewElement(root, "event"); + mxmlElementSetAttr(root, "counter", "MaliTimeline_Perfetto"); + mxmlElementSetAttr(root, "title", "Mali Timeline Events"); + mxmlElementSetAttr(root, "name", "Perfetto"); + } + + void perfetto_driver_t::readEvents(mxml_node_t * const /* unused */) + { + bool is_android = lib::is_android(); + bool traced_running = lib::check_traced_running(); + if (isMaliGpu() && is_android && traced_running) { + setCounters(new DriverCounter(getCounters(), "MaliTimeline_Perfetto")); + } + } + + std::vector perfetto_driver_t::get_other_warnings() const + { + std::vector other_message; + if(perfetto_requested) { + other_message.emplace_back(get_error_message()); + } + return other_message; + } + + bool perfetto_driver_t::isMaliGpu() const { + return !maliFamilyName.empty(); + } + + bool perfetto_driver_t::perfettoEnabled() const { + return perfetto_enabled; + } + + std::string perfetto_driver_t::get_error_message() const + { + if (!isMaliGpu()) { + return std::string {"Mali Timeline view is not available on this device as it does not have a Mali GPU"}; + } + + bool not_on_android = !lib::is_android(); + if (not_on_android) { + return std::string {"Mali Timeline view is not available on this device as it is not running Android."}; + } + + bool traced_not_running = !lib::check_traced_running(); + if (traced_not_running) { + return std::string {"Mali Timeline view is not available on this device as perfetto is unavailable."}; + } + + + return std::string {}; + } +} diff --git a/daemon/agents/perfetto/perfetto_driver.h b/daemon/agents/perfetto/perfetto_driver.h new file mode 100644 index 00000000..e949b59e --- /dev/null +++ b/daemon/agents/perfetto/perfetto_driver.h @@ -0,0 +1,26 @@ +/* Copyright (C) 2022 by Arm Limited. All rights reserved. */ +#pragma once + +#include "PolledDriver.h" + +namespace agents::perfetto { + + class perfetto_driver_t : public PolledDriver { + + public: + explicit perfetto_driver_t(const char * maliFamilyName); + void writeEvents(mxml_node_t * root) const override; + void readEvents(mxml_node_t * root) override; + std::vector get_other_warnings() const override; + void setupCounter(Counter & counter) override; + bool perfettoEnabled() const; + + private: + std::string maliFamilyName; + [[nodiscard]] bool isMaliGpu() const; + [[nodiscard]] std::string get_error_message() const; + bool perfetto_requested = false; + bool perfetto_enabled = false; + }; + +} diff --git a/daemon/agents/perfetto/perfetto_sdk_helper.cpp b/daemon/agents/perfetto/perfetto_sdk_helper.cpp new file mode 100644 index 00000000..c79e3d42 --- /dev/null +++ b/daemon/agents/perfetto/perfetto_sdk_helper.cpp @@ -0,0 +1,99 @@ +/* Copyright (C) 2022 by Arm Limited. All rights reserved. */ +#include "agents/perfetto/perfetto_sdk_helper.h" + +#include "lib/AutoClosingFd.h" + +#include +#include +#include +#include + +#include + +namespace agents { + + namespace { + constexpr std::uint32_t perfetto_buffer_size = 2048; + constexpr std::uint32_t perfetto_flush_period = 100; + constexpr std::uint32_t perfetto_file_write_period = 100; + + std::optional> create_perfetto_pipe() + { + std::array fds; + if (auto result = ::pipe2(fds.data(), O_CLOEXEC); result != 0) { + LOG_ERROR("Failed to open perfetto data pipe. Result code was: %d", result); + return {}; + } + + return {{lib::AutoClosingFd(fds[0]), lib::AutoClosingFd(fds[1])}}; + } + } + + void perfetto_sdk_helper_t::initialize_sdk() + { + if (!tracing_session) { + //Intializing perfetto SDK + LOG_TRACE("Initializing perfetto SDK"); + perfetto::TracingInitArgs tracing_init_args; + tracing_init_args.backends = perfetto::kSystemBackend; + perfetto::Tracing::Initialize(tracing_init_args); + + tracing_session = perfetto::Tracing::NewTrace(); + } + else { + LOG_DEBUG("Perfetto SDK should be initialized only one time"); + } + } + + void perfetto_sdk_helper_t::stop_sdk() + { + if (tracing_session && session_started) { + tracing_session->StopBlocking(); + session_started = false; + } + } + + bool perfetto_sdk_helper_t::start_trace() + { + if (!tracing_session) { + LOG_ERROR("Attempted to start a perfetto trace but the SDK has not been initialised"); + return false; + } + + if (session_started) { + LOG_ERROR("Attempted to start a perfetto trace but another is already in progress"); + return false; + } + + auto pipe_fds = create_perfetto_pipe(); + if (!pipe_fds) { + return false; + } + + fill_trace_configuration(); + + // we need to own this even though we hand the write fd to perfetto as it won't take ownership + // and close it for us. + perfetto_write_fd = std::move(pipe_fds.value()[1]); + // adapt the read end to something that asio can deal with + perfetto_read_stream = boost::asio::posix::stream_descriptor {ctx, pipe_fds.value()[0].release()}; + + // now tell perfetto to configure itself and start tracing + tracing_session->Setup(trace_config, perfetto_write_fd.get()); + tracing_session->Start(); + + session_started = true; + return true; + } + + void perfetto_sdk_helper_t::fill_trace_configuration() + { + trace_config.add_buffers()->set_size_kb(perfetto_buffer_size); + trace_config.set_flush_period_ms(perfetto_flush_period); + trace_config.set_file_write_period_ms(perfetto_file_write_period); + trace_config.set_write_into_file(true); + + auto * data_source = trace_config.add_data_sources()->mutable_config(); + data_source->set_name(std::string(GPU_RENDERSTAGES_DATASOURCE)); + } +} diff --git a/daemon/agents/perfetto/perfetto_sdk_helper.h b/daemon/agents/perfetto/perfetto_sdk_helper.h new file mode 100644 index 00000000..c7a7bab3 --- /dev/null +++ b/daemon/agents/perfetto/perfetto_sdk_helper.h @@ -0,0 +1,80 @@ +/* Copyright (C) 2022 by Arm Limited. All rights reserved. */ +#pragma once + +#include "Logging.h" +#include "async/continuations/async_initiate.h" +#include "async/continuations/continuation.h" +#include "async/continuations/operations.h" +#include "async/continuations/stored_continuation.h" +#include "async/continuations/use_continuation.h" +#include "lib/AutoClosingFd.h" +#include "lib/Utils.h" +#include "perfetto/sdk/perfetto.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace agents { + /** + * A handler for the connection between Perfetto SDK and perfetto agent and a wrapper for the SDK functions + */ + + class perfetto_sdk_helper_t : public std::enable_shared_from_this { + + public: + using data_source_list_t = std::unordered_map>; + + explicit perfetto_sdk_helper_t(boost::asio::io_context & context) : ctx(context), strand(context) {} + + void initialize_sdk(); + + void stop_sdk(); + + bool start_trace(); + + template + [[nodiscard]] auto async_read_trace(boost::asio::mutable_buffer buffer, CompletionToken && token) + { + using namespace async::continuations; + + return boost::asio::async_initiate( + [self = this->shared_from_this()](auto && handler, auto buffer) { + using handler_type = decltype(handler); + + if (!self->session_started) { + auto err = boost::asio::error::make_error_code(boost::asio::error::not_connected); + handler(err, 0); + } + + self->perfetto_read_stream.value().async_read_some(buffer, std::forward(handler)); + }, + std::forward(token), + buffer); + } + + private: + static constexpr std::string_view GPU_RENDERSTAGES_DATASOURCE = "gpu.renderstages"; + + boost::asio::io_context & ctx; + boost::asio::io_context::strand strand; + + std::unique_ptr tracing_session = nullptr; + perfetto::TraceConfig trace_config; + bool session_started {false}; + + lib::AutoClosingFd perfetto_write_fd; + std::optional perfetto_read_stream; + + void fill_trace_configuration(); + }; +}; diff --git a/daemon/agents/spawn_agent.cpp b/daemon/agents/spawn_agent.cpp index c1c22692..7b9f5f10 100644 --- a/daemon/agents/spawn_agent.cpp +++ b/daemon/agents/spawn_agent.cpp @@ -9,9 +9,38 @@ #include "lib/error_code_or.hpp" #include "lib/forked_process.h" +#include +#include + #include namespace agents { + namespace { + + bool check_agent_env_variable(const std::string & var_prefix, const std::string & agent_name) + { + std::string debug_token = var_prefix + agent_name; + std::replace(debug_token.begin(), debug_token.end(), '-', '_'); + std::transform(debug_token.begin(), debug_token.end(), debug_token.begin(), [](unsigned char chr) { + return std::toupper(chr); + }); + + LOG_TRACE("Checking for agent env var [%s]", debug_token.c_str()); + // NOLINTNEXTLINE(concurrency-mt-unsafe) + return std::getenv(debug_token.c_str()) != nullptr; + } + + bool should_debug_this_agent(const std::string & agent_name) + { + return check_agent_env_variable("DEBUG_", agent_name); + } + + bool should_trace_this_agent(const std::string & agent_name) + { + return check_agent_env_variable("TRACE_", agent_name); + } + } + /** Simple agent spawner */ lib::error_code_or_t simple_agent_spawner_t::spawn_agent_process(char const * agent_name) { @@ -30,14 +59,24 @@ namespace agents { return *error; } - std::vector arguments {agent_name}; + std::string exe_name = gatord_exe->path(); + std::vector arguments {}; - if (::logging::is_log_enable_trace()) { + if (should_debug_this_agent(agent_name)) { + LOG_DEBUG("Enabling debug for agent [%s]", agent_name); + arguments.emplace_back(":5001"); + arguments.emplace_back(exe_name); + exe_name = "./gdbserver"; + } + + arguments.emplace_back(agent_name); + + if (should_trace_this_agent(agent_name)) { arguments.emplace_back("--trace"); } return lib::forked_process_t::fork_process(true, - gatord_exe->path(), + exe_name, arguments, {}, {}, @@ -55,12 +94,6 @@ namespace agents { lib::error_code_or_t android_pkg_agent_spawner_t::spawn_agent_process( char const * agent_name) { -#ifdef APP_GATOR_GDB_SERVER - constexpr std::size_t extra_args = 2; -#else - constexpr std::size_t extra_args = 0; -#endif - runtime_assert(agent_name != nullptr, "agent_name is required"); if (!remote_exe_path) { @@ -75,15 +108,19 @@ namespace agents { return *error; } - std::array arguments {{ - package_name, -#ifdef APP_GATOR_GDB_SERVER - "./gdbserver", - ":5001", -#endif - *remote_exe_path, - agent_name, - }}; + std::vector arguments; + arguments.push_back(package_name); + if (should_debug_this_agent(agent_name)) { + LOG_DEBUG("Enabling debug for agent [%s]", agent_name); + arguments.emplace_back("./gdbserver"); + arguments.emplace_back(":5001"); + } + arguments.push_back(*remote_exe_path); + arguments.emplace_back(agent_name); + + if (should_trace_this_agent(agent_name)) { + arguments.emplace_back("--trace"); + } return lib::forked_process_t::fork_process(true, "run-as", diff --git a/daemon/agents/spawn_agent.h b/daemon/agents/spawn_agent.h index 27bba058..5d426257 100644 --- a/daemon/agents/spawn_agent.h +++ b/daemon/agents/spawn_agent.h @@ -24,6 +24,9 @@ namespace agents { /** ID string used to identify the external annotation agent */ constexpr std::string_view agent_id_perf {"agent-perf"}; + /** ID string used to identify the perfetto agent */ + constexpr std::string_view agent_id_perfetto {"agent-perfetto"}; + /** * An interface for some class that will spawn a gatord agent process */ diff --git a/daemon/android/AndroidActivityManager.cpp b/daemon/android/AndroidActivityManager.cpp index 3f0ca245..7d864398 100644 --- a/daemon/android/AndroidActivityManager.cpp +++ b/daemon/android/AndroidActivityManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 by Arm Limited. All rights reserved. */ +/* Copyright (C) 2021-2022 by Arm Limited. All rights reserved. */ #include "android/AndroidActivityManager.h" @@ -96,22 +96,6 @@ namespace { return executeCommand(cmd, []([[maybe_unused]] int outfd, [[maybe_unused]] int errfd) { }); // Do nothing for the read action } - - bool hasPackage(const std::string & pkg) - { - std::array cmd = {PM.data(), LIST.data(), PKGS.data(), pkg.c_str(), nullptr}; - std::array output; - - if (!executeCommandAndReadOutput(cmd, output)) { - return false; - } - - if (strstr(output.data(), pkg.c_str()) == nullptr) { - LOG_ERROR("The specified package(%s) is not installed.", pkg.c_str()); - return false; - } - return true; - } } std::unique_ptr create_android_activity_manager(const std::string & package_name, @@ -128,13 +112,29 @@ std::unique_ptr AndroidActivityManager::create(const st return nullptr; } - if (!hasPackage(pkg)) { + if (!has_package(pkg)) { return nullptr; } return std::make_unique(pkg, activity); } +bool AndroidActivityManager::has_package(const std::string & pkg) +{ + std::array cmd = {PM.data(), LIST.data(), PKGS.data(), pkg.c_str(), nullptr}; + std::array output; + + if (!executeCommandAndReadOutput(cmd, output)) { + return false; + } + + if (strstr(output.data(), pkg.c_str()) == nullptr) { + LOG_ERROR("The specified package (%s) is not installed.", pkg.c_str()); + return false; + } + return true; +} + AndroidActivityManager::AndroidActivityManager(std::string pkg, std::string activity) : pkgName {std::move(pkg)}, actName {std::move(activity)} { diff --git a/daemon/android/AndroidActivityManager.h b/daemon/android/AndroidActivityManager.h index 57ba9b28..f9022c5d 100644 --- a/daemon/android/AndroidActivityManager.h +++ b/daemon/android/AndroidActivityManager.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 by Arm Limited. All rights reserved. */ +/* Copyright (C) 2021-2022 by Arm Limited. All rights reserved. */ #pragma once @@ -44,7 +44,13 @@ class AndroidActivityManager : public IAndroidActivityManager { */ static std::unique_ptr create(const std::string & pkg, const std::string & activity); - virtual ~AndroidActivityManager() = default; + /** + * Returns true if @a pkg is installed on the target device. + * + * @param pkg Package name to query + * @return True if installed + */ + static bool has_package(const std::string & pkg); /** * Starts the activity (non-blocking) diff --git a/daemon/apc/misc_apc_frame_ipc_sender.h b/daemon/apc/misc_apc_frame_ipc_sender.h index 519b50b3..8439a86c 100644 --- a/daemon/apc/misc_apc_frame_ipc_sender.h +++ b/daemon/apc/misc_apc_frame_ipc_sender.h @@ -2,6 +2,7 @@ #pragma once +#include "ISender.h" #include "Protocol.h" #include "Time.h" #include "agents/perf/events/types.hpp" @@ -16,6 +17,7 @@ #include #include +#include #include #include @@ -25,6 +27,16 @@ namespace apc { + namespace detail { + inline std::string_view trim_to_max(std::string_view str) + { + constexpr std::size_t space_for_header = 64U; + str = str.substr(0, ISender::MAX_RESPONSE_LENGTH - space_for_header); + str = str.substr(0, str.rfind('\n')); + return str; + } + } + class misc_apc_frame_ipc_sender_t { public: explicit misc_apc_frame_ipc_sender_t(std::shared_ptr ipc_sink) @@ -82,6 +94,13 @@ namespace apc { { using namespace async::continuations; + runtime_assert(maps.size() <= ISender::MAX_RESPONSE_LENGTH, "too large maps file received"); + + // limit size + if (maps.size() >= ISender::MAX_RESPONSE_LENGTH) { + maps = detail::trim_to_max(maps); + } + return async_initiate_explicit( [ipc_sink = ipc_sink, bytes = apc::make_maps_frame(pid, tid, maps)](auto && sc) mutable { submit(ipc_sink->async_send_message(ipc::msg_apc_frame_data_t {std::move(bytes)}, @@ -132,6 +151,13 @@ namespace apc { { using namespace async::continuations; + runtime_assert(kallsyms.size() <= ISender::MAX_RESPONSE_LENGTH, "too large kallsyms received"); + + // limit size + if (kallsyms.size() >= ISender::MAX_RESPONSE_LENGTH) { + kallsyms = detail::trim_to_max(kallsyms); + } + return async_initiate_explicit( [ipc_sink = ipc_sink, bytes = apc::make_kallsyms_frame(kallsyms)](auto && sc) mutable { submit(ipc_sink->async_send_message(ipc::msg_apc_frame_data_t {std::move(bytes)}, diff --git a/daemon/capture/CaptureProcess.cpp b/daemon/capture/CaptureProcess.cpp index a4131a1b..faa8f2d3 100644 --- a/daemon/capture/CaptureProcess.cpp +++ b/daemon/capture/CaptureProcess.cpp @@ -14,6 +14,7 @@ #include "SessionData.h" #include "StreamlineSetupLoop.h" #include "agents/spawn_agent.h" +#include "android/AndroidActivityManager.h" #include "capture/internal/UdpListener.h" #include "lib/FileDescriptor.h" #include "lib/Process.h" @@ -218,6 +219,30 @@ namespace { client.closeSocket(); } + std::array, 2> create_spawners() + { + auto high_privilege_spawner = std::make_unique(); + std::unique_ptr low_privilege_spawner {}; + + // If running as root, never use run-as, just fork directly + const auto is_root = lib::geteuid() == 0; + if (!is_root && !gSessionData.mSystemWide && (gSessionData.mAndroidPackage != nullptr)) { + low_privilege_spawner = std::make_unique(gSessionData.mAndroidPackage); + } + else { + // If a package has been specified, check that it exists (error logging comes from AndroidActivityManager). + // This is done as a part of android_pkg_agent_spawner_t's construction so doesn't need to be specified + // above + if (!gSessionData.mSystemWide && (gSessionData.mAndroidPackage != nullptr) + && !AndroidActivityManager::has_package(gSessionData.mAndroidPackage)) { + handleException(); + } + low_privilege_spawner = std::make_unique(); + } + + return {std::move(high_privilege_spawner), std::move(low_privilege_spawner)}; + } + StateAndPid handleClient(StateAndPid currentStateAndChildPid, Drivers & drivers, OlyServerSocket & sock, @@ -263,17 +288,11 @@ namespace { monitor.close(); annotateListenerPtr.reset(); - // create the agent process spawner - std::unique_ptr spawner {}; + // create the agent process spawners + auto [high_privilege_spawner, low_privilege_spawner] = create_spawners(); - if ((!gSessionData.mSystemWide) && (gSessionData.mAndroidPackage != nullptr)) { - spawner = std::make_unique(gSessionData.mAndroidPackage); - } - else { - spawner = std::make_unique(); - } - - auto child = Child::createLive(*spawner, + auto child = Child::createLive(*high_privilege_spawner, + *low_privilege_spawner, drivers, client, event_listener, @@ -281,8 +300,10 @@ namespace { std::move(log_setup_supplier)); child->run(); child.reset(); - spawner.reset(); // the dtor may perform some necessary cleanup + low_privilege_spawner.reset(); // the dtor may perform some necessary cleanup + high_privilege_spawner.reset(); + // NOLINTNEXTLINE(concurrency-mt-unsafe) exit(0); } else { @@ -319,17 +340,11 @@ namespace { monitor.close(); annotateListenerPtr.reset(); - // create the agent process spawner - std::unique_ptr spawner {}; - - if ((!gSessionData.mSystemWide) && (gSessionData.mAndroidPackage != nullptr)) { - spawner = std::make_unique(gSessionData.mAndroidPackage); - } - else { - spawner = std::make_unique(); - } + // create the agent process spawners + auto [high_privilege_spawner, low_privilege_spawner] = create_spawners(); - auto child = Child::createLocal(*spawner, + auto child = Child::createLocal(*high_privilege_spawner, + *low_privilege_spawner, drivers, config, event_listener, @@ -339,7 +354,12 @@ namespace { LOG_DEBUG("gator-child finished running"); child.reset(); + low_privilege_spawner.reset(); // the dtor may perform some necessary cleanup + high_privilege_spawner.reset(); + LOG_DEBUG("gator-child exiting"); + + // NOLINTNEXTLINE(concurrency-mt-unsafe) exit(0); } else { diff --git a/daemon/cmake/compiler-flags.cmake b/daemon/cmake/compiler-flags.cmake index df678284..744d8098 100644 --- a/daemon/cmake/compiler-flags.cmake +++ b/daemon/cmake/compiler-flags.cmake @@ -1,14 +1,18 @@ -# Copyright (C) 2021 by Arm Limited. All rights reserved. +# Copyright (C) 2021-2022 by Arm Limited. All rights reserved. # Configure target flags -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GATORD_C_CXX_FLAGS}") -SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GATORD_C_CXX_FLAGS} -fexceptions") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GATORD_C_CXX_FLAGS}") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GATORD_C_CXX_FLAGS} -fexceptions") IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") # Validate version IF("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "7.0.0") MESSAGE(FATAL_ERROR "Invalid G++ version ${CMAKE_CXX_COMPILER_VERSION} (expected minimum is 7.0.0)") ENDIF() + + IF(CMAKE_ENABLE_LTO AND ("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "8.0.0")) + MESSAGE(FATAL_ERROR "LTO unsupported for G++ versions less than 8.0.0, please disable LTO and reconfigure") + ENDIF() ELSEIF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # Validate version IF("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "5.0.0") @@ -18,27 +22,51 @@ ELSE() MESSAGE(FATAL_ERROR "Unknown compiler type '${CMAKE_CXX_COMPILER_ID}'") ENDIF() -#### -# Configure build target flags -#### +# When ccache basdir is set, remap paths to allow result sharing between builds +IF(DEFINED ENV{CCACHE_BASEDIR}) + IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + IF("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "8.0.0") + SET(CCACHE_PATH_MAP_OPT "-fdebug-prefix-map=$ENV{CCACHE_BASEDIR}=.") + ELSE() + SET(CCACHE_PATH_MAP_OPT "-ffile-prefix-map=$ENV{CCACHE_BASEDIR}=.") + ENDIF() + ELSEIF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + IF("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "10.0.0") + SET(CCACHE_PATH_MAP_OPT "-fdebug-prefix-map=$ENV{CCACHE_BASEDIR}=.") + ELSE() + SET(CCACHE_PATH_MAP_OPT "-ffile-prefix-map=$ENV{CCACHE_BASEDIR}=.") + ENDIF() + ELSE() + SET(CCACHE_PATH_MAP_OPT "") + ENDIF() + + MESSAGE(STATUS "CCACHE_PATH_MAP_OPT = ${CCACHE_PATH_MAP_OPT}") + + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CCACHE_PATH_MAP_OPT}") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CCACHE_PATH_MAP_OPT}") +ENDIF() + +# ### +# Configure build target flags +# ### if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -ggdb3 -gdwarf-3 -D_DEBUG") - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -DNDEBUG") - set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O3 -g") - set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -Os -DNDEBUG") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -ggdb3 -gdwarf-3 -D_DEBUG") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -DNDEBUG") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3 -g") - set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -Os -DNDEBUG") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -ggdb3 -gdwarf-3 -D_DEBUG") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -DNDEBUG") + set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O3 -g") + set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -Os -DNDEBUG") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -ggdb3 -gdwarf-3 -D_DEBUG") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -DNDEBUG") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3 -g") + set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -Os -DNDEBUG") endif() -#### -# Add strict warning settings for C++ -#### +# ### +# Add strict warning settings for C++ +# ### IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - set(GCC_STRICT_WARNING_FLAGS_CXX "-Wall -Wextra -Wno-shadow -Wno-psabi") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_STRICT_WARNING_FLAGS_CXX}") + set(GCC_STRICT_WARNING_FLAGS_CXX "-Wall -Wextra -Wno-shadow -Wno-psabi") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_STRICT_WARNING_FLAGS_CXX}") ELSEIF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - set(CLANG_STRICT_WARNING_FLAGS_CXX "-Wall -Wextra -Wno-shadow -Wdocumentation") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CLANG_STRICT_WARNING_FLAGS_CXX}") + set(CLANG_STRICT_WARNING_FLAGS_CXX "-Wall -Wextra -Wno-shadow -Wdocumentation") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CLANG_STRICT_WARNING_FLAGS_CXX}") ENDIF() diff --git a/daemon/cmake/create-src-md5-runner.cmake b/daemon/cmake/create-src-md5-runner.cmake index 443e0d43..ac4186e0 100644 --- a/daemon/cmake/create-src-md5-runner.cmake +++ b/daemon/cmake/create-src-md5-runner.cmake @@ -1,25 +1,31 @@ -# Copyright (C) 2010-2020 by Arm Limited. All rights reserved. +# Copyright (C) 2010-2022 by Arm Limited. All rights reserved. + +# as expected for STRING CONFIGURE +CMAKE_POLICY(SET CMP0053 NEW) # Split the argument string SEPARATE_ARGUMENTS(FILES_TO_HASH) # Generate the hash string which is the concatenation of the MD5 of the hashed files -SET(HASH_STRING "") -FOREACH(FILE_TO_HASH ${FILES_TO_HASH}) - FILE(READ ${FILE_TO_HASH} - FILE_HASH) - SET(HASH_STRING "${HASH_STRING}${FILE_HASH}") +SET(HASH_STRING "") + +FOREACH(FILE_TO_HASH ${FILES_TO_HASH}) + FILE(READ ${FILE_TO_HASH} + FILE_HASH) + SET(HASH_STRING "${HASH_STRING}${FILE_HASH}") ENDFOREACH() # Hash the concatenated string -STRING(MD5 HASH_STRING - "${HASH_STRING}") +STRING(MD5 HASH_STRING + "${HASH_STRING}") -# Output to file -MESSAGE(STATUS "Generated hash value in ${HASH_FILE} = ${HASH_STRING}") -FILE(WRITE ${HASH_FILE} - "${HASH_STRING}") -MESSAGE(STATUS "Generated hash value in ${OUTPUT_FILE} with constant name ${CONSTANT_NAME}, hash = ${HASH_STRING}") -FILE(WRITE ${OUTPUT_FILE} - "extern const char * const ${CONSTANT_NAME} = \"${HASH_STRING}\";") +STRING(CONFIGURE "@ID_VALUE@" ID_VALUE @ONLY ESCAPE_QUOTES) +# Output to file +MESSAGE(STATUS "Generated hash value in ${HASH_FILE} = ${HASH_STRING}") +FILE(WRITE ${HASH_FILE} + "${HASH_STRING}") +MESSAGE(STATUS "Generated hash value in ${OUTPUT_FILE} with constant name ${CONSTANT_NAME}, hash = ${HASH_STRING}") +MESSAGE(STATUS "Generated id value in ${OUTPUT_FILE} with constant name ${ID_NAME}, text = ${ID_VALUE}") +FILE(WRITE ${OUTPUT_FILE} + "extern const char * const ${CONSTANT_NAME} = \"${HASH_STRING}\";\nextern const char * const ${ID_NAME} = \"${ID_VALUE}\";\n") diff --git a/daemon/cmake/create-src-md5.cmake b/daemon/cmake/create-src-md5.cmake index 29b9f74d..e59cc086 100644 --- a/daemon/cmake/create-src-md5.cmake +++ b/daemon/cmake/create-src-md5.cmake @@ -1,39 +1,39 @@ -# Copyright (C) 2010-2021 by Arm Limited. All rights reserved. +# Copyright (C) 2010-2022 by Arm Limited. All rights reserved. # Save this outside the macro so that development build will retrigger the generation of the source file if this file changes -SET(CREATE_SRC_MD5_CMAKE_FILE ${CMAKE_CURRENT_LIST_FILE}) +SET(CREATE_SRC_MD5_CMAKE_FILE ${CMAKE_CURRENT_LIST_FILE}) # -# Macro to create a source file containing the md5 hash of the list of provided files +# Macro to create a source file containing the md5 hash of the list of provided files # -MACRO(CREATE_SRC_MD5 CONSTANT_NAME - OUTPUT_FILE - HASH_FILE) - +MACRO(CREATE_SRC_MD5 CONSTANT_NAME ID_NAME ID_VALUE OUTPUT_FILE HASH_FILE) # Files to hash are the arguments after the expected arguments - SET(FILES_TO_HASH ${ARGN}) - LIST(SORT FILES_TO_HASH) - LIST(REMOVE_DUPLICATES FILES_TO_HASH) + SET(FILES_TO_HASH ${ARGN}) + LIST(SORT FILES_TO_HASH) + LIST(REMOVE_DUPLICATES FILES_TO_HASH) # Convert the list to a string that can be passed to the custom command SET(FILES_TO_HASH_STRING) - FOREACH(FILE_TO_HASH ${FILES_TO_HASH}) - FILE(RELATIVE_PATH FILE_TO_HASH - "${CMAKE_CURRENT_SOURCE_DIR}" - "${FILE_TO_HASH}") - SET(FILES_TO_HASH_STRING "${FILES_TO_HASH_STRING};${FILE_TO_HASH}") + + FOREACH(FILE_TO_HASH ${FILES_TO_HASH}) + FILE(RELATIVE_PATH FILE_TO_HASH + "${CMAKE_CURRENT_SOURCE_DIR}" + "${FILE_TO_HASH}") + SET(FILES_TO_HASH_STRING "${FILES_TO_HASH_STRING};${FILE_TO_HASH}") ENDFOREACH() # Target to generate OUTPUT_FILE destination file - SET(CREATE_SRC_MD5_RUNNER_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/create-src-md5-runner.cmake") - ADD_CUSTOM_COMMAND(OUTPUT ${OUTPUT_FILE} - COMMAND ${CMAKE_COMMAND} -DCONSTANT_NAME="${CONSTANT_NAME}" - -DOUTPUT_FILE="${OUTPUT_FILE}" - -DHASH_FILE="${HASH_FILE}" - -DFILES_TO_HASH="${FILES_TO_HASH_STRING}" - -P ${CREATE_SRC_MD5_RUNNER_FILE} - DEPENDS ${FILES_TO_HASH} - ${CREATE_SRC_MD5_CMAKE_FILE} - ${CREATE_SRC_MD5_RUNNER_FILE} - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") + SET(CREATE_SRC_MD5_RUNNER_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/create-src-md5-runner.cmake") + ADD_CUSTOM_COMMAND(OUTPUT ${OUTPUT_FILE} + COMMAND ${CMAKE_COMMAND} -DCONSTANT_NAME="${CONSTANT_NAME}" + -DOUTPUT_FILE="${OUTPUT_FILE}" + -DHASH_FILE="${HASH_FILE}" + -DFILES_TO_HASH="${FILES_TO_HASH_STRING}" + -DID_NAME="${ID_NAME}" + -DID_VALUE="${ID_VALUE}" + -P ${CREATE_SRC_MD5_RUNNER_FILE} + DEPENDS ${FILES_TO_HASH} + ${CREATE_SRC_MD5_CMAKE_FILE} + ${CREATE_SRC_MD5_RUNNER_FILE} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") ENDMACRO() diff --git a/daemon/events-Cortex-A15.xml b/daemon/events-Cortex-A15.xml index 6f264042..fca500ad 100644 --- a/daemon/events-Cortex-A15.xml +++ b/daemon/events-Cortex-A15.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-A17.xml b/daemon/events-Cortex-A17.xml index b55b2c97..25a1d89b 100644 --- a/daemon/events-Cortex-A17.xml +++ b/daemon/events-Cortex-A17.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-A32.xml b/daemon/events-Cortex-A32.xml index 814c9dfe..76c2853e 100644 --- a/daemon/events-Cortex-A32.xml +++ b/daemon/events-Cortex-A32.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-A34.xml b/daemon/events-Cortex-A34.xml index efd3806e..163f67d9 100644 --- a/daemon/events-Cortex-A34.xml +++ b/daemon/events-Cortex-A34.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-A35.xml b/daemon/events-Cortex-A35.xml index ec2d2872..091d47e8 100644 --- a/daemon/events-Cortex-A35.xml +++ b/daemon/events-Cortex-A35.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-A5.xml b/daemon/events-Cortex-A5.xml index 378d7fad..9c117b22 100644 --- a/daemon/events-Cortex-A5.xml +++ b/daemon/events-Cortex-A5.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-A510.xml b/daemon/events-Cortex-A510.xml index a79a354e..1df9f879 100644 --- a/daemon/events-Cortex-A510.xml +++ b/daemon/events-Cortex-A510.xml @@ -50,9 +50,9 @@ - - - + + + diff --git a/daemon/events-Cortex-A53.xml b/daemon/events-Cortex-A53.xml index 13dd176a..31866178 100644 --- a/daemon/events-Cortex-A53.xml +++ b/daemon/events-Cortex-A53.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-A55.xml b/daemon/events-Cortex-A55.xml index d889279b..21382f7f 100644 --- a/daemon/events-Cortex-A55.xml +++ b/daemon/events-Cortex-A55.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-A57.xml b/daemon/events-Cortex-A57.xml index 2c2e9bc1..dff23a86 100644 --- a/daemon/events-Cortex-A57.xml +++ b/daemon/events-Cortex-A57.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-A65AE.xml b/daemon/events-Cortex-A65AE.xml index e3c78679..9a597c87 100644 --- a/daemon/events-Cortex-A65AE.xml +++ b/daemon/events-Cortex-A65AE.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-A7.xml b/daemon/events-Cortex-A7.xml index d165027d..7d8ab49c 100644 --- a/daemon/events-Cortex-A7.xml +++ b/daemon/events-Cortex-A7.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-A710.xml b/daemon/events-Cortex-A710.xml index 694186e5..238f4e1b 100644 --- a/daemon/events-Cortex-A710.xml +++ b/daemon/events-Cortex-A710.xml @@ -1,4 +1,4 @@ - + @@ -47,9 +47,9 @@ - - - + + + diff --git a/daemon/events-Cortex-A715.xml b/daemon/events-Cortex-A715.xml new file mode 100644 index 00000000..7acf9cce --- /dev/null +++ b/daemon/events-Cortex-A715.xml @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/daemon/events-Cortex-A72.xml b/daemon/events-Cortex-A72.xml index 55fc7650..7c20999f 100644 --- a/daemon/events-Cortex-A72.xml +++ b/daemon/events-Cortex-A72.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-A73.xml b/daemon/events-Cortex-A73.xml index b7f61ecf..742dc2a5 100644 --- a/daemon/events-Cortex-A73.xml +++ b/daemon/events-Cortex-A73.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-A75.xml b/daemon/events-Cortex-A75.xml index 72e36624..3970cbe5 100644 --- a/daemon/events-Cortex-A75.xml +++ b/daemon/events-Cortex-A75.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-A76.xml b/daemon/events-Cortex-A76.xml index 58370ad5..2948c730 100644 --- a/daemon/events-Cortex-A76.xml +++ b/daemon/events-Cortex-A76.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-A77.xml b/daemon/events-Cortex-A77.xml index 9da7a376..470a98c8 100644 --- a/daemon/events-Cortex-A77.xml +++ b/daemon/events-Cortex-A77.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-A78.xml b/daemon/events-Cortex-A78.xml index ad5a55bb..74ae3f0d 100644 --- a/daemon/events-Cortex-A78.xml +++ b/daemon/events-Cortex-A78.xml @@ -1,4 +1,4 @@ - + @@ -47,9 +47,9 @@ - - - + + + diff --git a/daemon/events-Cortex-A8.xml b/daemon/events-Cortex-A8.xml index f776e049..92f0654a 100644 --- a/daemon/events-Cortex-A8.xml +++ b/daemon/events-Cortex-A8.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-A9.xml b/daemon/events-Cortex-A9.xml index 11d7d0bf..529e38b4 100644 --- a/daemon/events-Cortex-A9.xml +++ b/daemon/events-Cortex-A9.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Cortex-R52+.xml b/daemon/events-Cortex-R52+.xml index 37b800d3..d894cca3 100644 --- a/daemon/events-Cortex-R52+.xml +++ b/daemon/events-Cortex-R52+.xml @@ -1,4 +1,4 @@ - + @@ -17,7 +17,7 @@ - + diff --git a/daemon/events-Cortex-R82.xml b/daemon/events-Cortex-R82.xml index f59b684b..956d1f4b 100644 --- a/daemon/events-Cortex-R82.xml +++ b/daemon/events-Cortex-R82.xml @@ -1,4 +1,4 @@ - + @@ -46,9 +46,9 @@ - - - + + + diff --git a/daemon/events-Cortex-X1.xml b/daemon/events-Cortex-X1.xml index eeaf83ba..7cc25ee8 100644 --- a/daemon/events-Cortex-X1.xml +++ b/daemon/events-Cortex-X1.xml @@ -1,4 +1,4 @@ - + @@ -47,9 +47,9 @@ - - - + + + diff --git a/daemon/events-Cortex-X2.xml b/daemon/events-Cortex-X2.xml index b463fbc7..5b927059 100644 --- a/daemon/events-Cortex-X2.xml +++ b/daemon/events-Cortex-X2.xml @@ -1,4 +1,4 @@ - + @@ -47,9 +47,9 @@ - - - + + + diff --git a/daemon/events-Cortex-X3.xml b/daemon/events-Cortex-X3.xml new file mode 100644 index 00000000..cc4086a7 --- /dev/null +++ b/daemon/events-Cortex-X3.xml @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/daemon/events-Exynos-M3.xml b/daemon/events-Exynos-M3.xml index ff616151..449796cf 100644 --- a/daemon/events-Exynos-M3.xml +++ b/daemon/events-Exynos-M3.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Neoverse-E1.xml b/daemon/events-Neoverse-E1.xml index 46980e45..ff5c01e5 100644 --- a/daemon/events-Neoverse-E1.xml +++ b/daemon/events-Neoverse-E1.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Neoverse-N1.xml b/daemon/events-Neoverse-N1.xml index d308ff31..61958248 100644 --- a/daemon/events-Neoverse-N1.xml +++ b/daemon/events-Neoverse-N1.xml @@ -1,4 +1,4 @@ - + diff --git a/daemon/events-Neoverse-N2.xml b/daemon/events-Neoverse-N2.xml index e41b46f9..28c10106 100644 --- a/daemon/events-Neoverse-N2.xml +++ b/daemon/events-Neoverse-N2.xml @@ -1,4 +1,4 @@ - + @@ -47,9 +47,9 @@ - - - + + + diff --git a/daemon/events-Neoverse-V1.xml b/daemon/events-Neoverse-V1.xml index f21cb2da..93c3a327 100644 --- a/daemon/events-Neoverse-V1.xml +++ b/daemon/events-Neoverse-V1.xml @@ -1,4 +1,4 @@ - + @@ -47,9 +47,9 @@ - - - + + + diff --git a/daemon/ipc/message_key.h b/daemon/ipc/message_key.h index 1d464dca..5e86bbcb 100644 --- a/daemon/ipc/message_key.h +++ b/daemon/ipc/message_key.h @@ -18,6 +18,7 @@ namespace ipc { ready, shutdown, start, + monitored_pids, // external annotations annotation_new_conn, @@ -25,6 +26,12 @@ namespace ipc { annotation_send_bytes, annotation_close_conn, + //Perfetto + perfetto_new_conn, + perfetto_recv_bytes, + perfetto_send_bytes, + perfetto_close_conn, + // perf perf_capture_configuration, capture_ready, diff --git a/daemon/ipc/messages.h b/daemon/ipc/messages.h index 42c0a3dd..f57b8ff7 100644 --- a/daemon/ipc/messages.h +++ b/daemon/ipc/messages.h @@ -11,6 +11,8 @@ #include #include +#include + namespace ipc { using annotation_uid_t = int; @@ -53,9 +55,23 @@ namespace ipc { static constexpr std::string_view name {#class}; \ }; + /** + * Helper function to return the message type name from a message instance. + * + * @param message Message to return the name of + * @return Message name + */ + template + [[nodiscard]] constexpr std::string_view get_message_name(MessageType && message) noexcept + { + using message_type = std::decay_t; + + static_assert(is_ipc_message_type_v, "MessageType must be an IPC type"); + return named_message_t::name; + } + /** * Sent from agent->shell to tell when the agent is ready. - * Sent from shell->agent to start the capture. */ using msg_ready_t = message_t; DEFINE_NAMED_MESSAGE(msg_ready_t); @@ -68,24 +84,40 @@ namespace ipc { using msg_start_t = message_t; DEFINE_NAMED_MESSAGE(msg_start_t); + /** Sent from the shell to all agents notifying them of the monitored PIDs */ + using msg_monitored_pids_t = message_t>; + DEFINE_NAMED_MESSAGE(msg_monitored_pids_t); + /** Sent from the annotation agent to the shell when a new annotation connection is received */ using msg_annotation_new_conn_t = message_t; DEFINE_NAMED_MESSAGE(msg_annotation_new_conn_t); - /** Sent from the annotation agent to the shell when some data is received from an annotations connection */ + /** Sent by the agent or shell to close a connection */ using msg_annotation_close_conn_t = message_t; DEFINE_NAMED_MESSAGE(msg_annotation_close_conn_t); - /** Sent from the shell to the annotation agent when some data is to be sent to the annotation connection */ + /** Sent from the annotation agent to the shell when some data is received from an annotations connection */ using msg_annotation_recv_bytes_t = message_t>; DEFINE_NAMED_MESSAGE(msg_annotation_recv_bytes_t); - /** Sent by the agent or shell to close a connection */ + /** Sent from the shell to the annotation agent when some data is to be sent to the annotation connection */ using msg_annotation_send_bytes_t = message_t>; DEFINE_NAMED_MESSAGE(msg_annotation_send_bytes_t); + /** Sent from shell to perfetto agent to create a new connection */ + using msg_perfetto_new_conn_t = message_t; + DEFINE_NAMED_MESSAGE(msg_perfetto_new_conn_t); + + /** Sent from shell to perfetto agent to close a connection */ + using msg_perfetto_close_conn_t = message_t; + DEFINE_NAMED_MESSAGE(msg_perfetto_close_conn_t); + + /** Sent from the Perfetto agent to the shell when some data is received from the Perfetto connection */ + using msg_perfetto_recv_bytes_t = message_t>; + DEFINE_NAMED_MESSAGE(msg_perfetto_recv_bytes_t); + /** Sent by the shell to configure the perf capture */ using msg_capture_configuration_t = message_t; @@ -130,16 +162,19 @@ namespace ipc { using all_message_types_variant_t = std::variant; + msg_capture_started_t>; } diff --git a/daemon/ipc/raw_ipc_channel_source.h b/daemon/ipc/raw_ipc_channel_source.h index a1e1c054..d81778a6 100644 --- a/daemon/ipc/raw_ipc_channel_source.h +++ b/daemon/ipc/raw_ipc_channel_source.h @@ -70,9 +70,9 @@ namespace ipc { template struct message_types_trait_finder_t; - // the terminator must be std::monostate + // Terminator template<> - struct message_types_trait_finder_t { + struct message_types_trait_finder_t<> { template static constexpr void visit(message_key_t key, T & host, sc_wrapper_t && scw) { @@ -460,8 +460,8 @@ namespace ipc { template struct try_message_filter_t { - using type_tuple = std::tuple...>; - using variant_type = std::variant...>; + using type_tuple = std::tuple...>; + using variant_type = std::variant...>; using pair_type = std::pair; template @@ -484,8 +484,7 @@ namespace ipc { /** * Receive one of a subset of message types from a raw_ipc_channel_source_t. Will continuously * receive from the channel, logging and discarding any unwanted messages, util one of the - * desired types arrives. The completion handler should expect to receive a variant that could - * also contain std::monostate. + * desired types arrives. * * @tparam MessageTypes The subset of messages to receive. * @tparam CompletionToken The asio completion token for this async op. @@ -499,7 +498,7 @@ namespace ipc { using optional_pair_type = std::optional; using variant_type = typename filter_type::variant_type; - return async_initiate_explicit)>( + return async_initiate_explicit)>( [src = std::move(source)](auto && sc) { submit( start_with(optional_pair_type {}) // diff --git a/daemon/lib/FsEntry.cpp b/daemon/lib/FsEntry.cpp index 905dfae5..1fe557db 100644 --- a/daemon/lib/FsEntry.cpp +++ b/daemon/lib/FsEntry.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2021 by Arm Limited. All rights reserved. */ +/* Copyright (C) 2016-2022 by Arm Limited. All rights reserved. */ #include "lib/FsEntry.h" @@ -18,6 +18,7 @@ #include +#include #include #include @@ -77,9 +78,13 @@ namespace lib { return {}; } - FsEntry::Stats::Stats() : Stats(Type::UNKNOWN, false, false) {} + FsEntry::Stats::Stats() : Stats(Type::UNKNOWN, false, false) + { + } - FsEntry::Stats::Stats(Type t, bool e, bool s) : type_(t), exists_(e), symlink_(s) {} + FsEntry::Stats::Stats(Type t, bool e, bool s) : type_(t), exists_(e), symlink_(s) + { + } FsEntry::FsEntry(std::string p) : path_(std::move(p)), name_offset(std::string::npos) { @@ -109,7 +114,9 @@ namespace lib { name_offset = path_.rfind('/'); } - FsEntry::FsEntry(const FsEntry & p, const std::string & n) : FsEntry(p.path().append("/").append(n)) {} + FsEntry::FsEntry(const FsEntry & p, const std::string & n) : FsEntry(p.path().append("/").append(n)) + { + } std::optional FsEntry::parent() const { @@ -120,13 +127,51 @@ namespace lib { return std::optional(); } - std::string FsEntry::name() const { return path_.substr(name_offset + 1); } + std::string FsEntry::name() const + { + return path_.substr(name_offset + 1); + } + + std::string FsEntry::path() const + { + return path_; + } + + bool FsEntry::is_root() const + { + return path_.length() == 1; + } + + bool FsEntry::is_absolute() const + { + return (!path_.empty()) && (path_.front() == '/'); + } + + FsEntryDirectoryIterator FsEntry::children() const + { + return FsEntryDirectoryIterator(*this); + } - std::string FsEntry::path() const { return path_; } + std::optional FsEntry::readlink() const + { + struct stat lstat_data; + if (lstat(path_.c_str(), &lstat_data) != 0) { + return {}; + } - bool FsEntry::is_root() const { return path_.length() == 1; } + auto const length = (lstat_data.st_size > 0 ? lstat_data.st_size : PATH_MAX); - FsEntryDirectoryIterator FsEntry::children() const { return FsEntryDirectoryIterator(*this); } + std::string result(std::size_t(length), '\0'); + + auto const n = ::readlink(path_.c_str(), result.data(), result.size()); + + // empty string and error are ignored + if (n <= 0) { + return {}; + } + + return FsEntry(result.substr(0, n)); + } std::optional FsEntry::realpath() const { @@ -139,9 +184,15 @@ namespace lib { return std::optional(); } - bool FsEntry::operator==(const FsEntry & that) const { return (path_ == that.path_); } + bool FsEntry::operator==(const FsEntry & that) const + { + return (path_ == that.path_); + } - bool FsEntry::operator<(const FsEntry & that) const { return (path_ < that.path_); } + bool FsEntry::operator<(const FsEntry & that) const + { + return (path_ < that.path_); + } FsEntry::Stats FsEntry::read_stats() const { diff --git a/daemon/lib/FsEntry.h b/daemon/lib/FsEntry.h index efcb1dbd..90f754ae 100644 --- a/daemon/lib/FsEntry.h +++ b/daemon/lib/FsEntry.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2021 by Arm Limited. All rights reserved. */ +/* Copyright (C) 2016-2022 by Arm Limited. All rights reserved. */ #ifndef INCLUDE_LIB_FSENTRY_H #define INCLUDE_LIB_FSENTRY_H @@ -70,8 +70,13 @@ namespace lib { /** @return True if is the root entry (e.g. '/') */ bool is_root() const; + /** @return True if is absolute (e.g. starts with '/') */ + bool is_absolute() const; + /** @return An iterator object for enumerating the children of a directory entry */ FsEntryDirectoryIterator children() const; + /** @return The contents of a link */ + std::optional readlink() const; /** @return The absolute, cannonical path, or nothing if it was not possible to resolve the read path */ std::optional realpath() const; @@ -190,14 +195,20 @@ namespace lib { * @param entry The file entry to read * @return The contents of that file */ - inline std::string readFileContents(const FsEntry & entry) { return entry.readFileContents(); } + inline std::string readFileContents(const FsEntry & entry) + { + return entry.readFileContents(); + } /** * Write the contents of a file * @param entry The file entry to write * @return true if successful */ - inline bool writeFileContents(const FsEntry & entry, const char * data) { return entry.writeFileContents(data); } + inline bool writeFileContents(const FsEntry & entry, const char * data) + { + return entry.writeFileContents(data); + } } #endif /* INCLUDE_LIB_FSENTRY_H */ diff --git a/daemon/lib/Istream.h b/daemon/lib/Istream.h deleted file mode 100644 index 6b4301c5..00000000 --- a/daemon/lib/Istream.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (C) 2018-2021 by Arm Limited. All rights reserved. */ - -#ifndef INCLUDE_LIB_ISTREAM_H -#define INCLUDE_LIB_ISTREAM_H - -#include -#include - -namespace lib { - /** - * Extracts comma separated numbers from a stream. - * @return vector of the numbers in the order they were in the stream - */ - template - static std::vector parseCommaSeparatedNumbers(std::istream & stream) - { - std::vector ints {}; - - IntType value; - while (!(stream >> std::ws).eof() && stream >> value) { - ints.push_back(value); - if (!stream.eof()) { - stream >> std::ws; - } - else { - break; - } - if (!stream.eof() && stream.peek() != ',') { - break; - } - if (!stream.eof()) { - stream.get(); - } - } - return ints; - } - -} - -#endif // INCLUDE_LIB_ISTREAM_H diff --git a/daemon/lib/String.h b/daemon/lib/String.h index b79ac212..f6ccb69c 100644 --- a/daemon/lib/String.h +++ b/daemon/lib/String.h @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -137,9 +138,8 @@ namespace lib { constexpr std::optional try_to_int(std::string_view s) { T value {0}; - if (!boost::conversion::try_lexical_convert(s, value)) { - return {}; + return std::nullopt; } return value; @@ -173,4 +173,40 @@ namespace lib { /** Does a string_view start with some prefix */ inline bool starts_with(std::string_view str, std::string_view prefix) { return (str.rfind(prefix, 0) == 0); } + + /** + * Extracts comma separated numbers from a string. + * @return vector of the numbers in the order they were in the stream, empty on parse error + */ + template + [[nodiscard]] static std::optional> parseCommaSeparatedNumbers(std::string_view string) + { + std::vector ints {}; + + while (!string.empty()) { + auto const comma = string.find_first_of(','); + auto part = string.substr(0, comma); + + part.remove_prefix(std::min(part.find_first_not_of(' '), part.size())); + part.remove_suffix(part.size() - std::min(part.find(' '), part.size())); + + if (!part.empty()) { + IntType result {0}; + + if (!boost::conversion::try_lexical_convert(part, result)) { + return std::nullopt; + } + + ints.emplace_back(result); + } + + if (comma == std::string_view::npos) { + break; + } + + string = string.substr(comma + 1); + } + + return {std::move(ints)}; + } } diff --git a/daemon/lib/perfetto_utils.h b/daemon/lib/perfetto_utils.h new file mode 100644 index 00000000..6024dbcb --- /dev/null +++ b/daemon/lib/perfetto_utils.h @@ -0,0 +1,23 @@ +/* Copyright (C) 2022 by Arm Limited. All rights reserved. */ + +#pragma once + +#include "capture/Environment.h" +#include "lib/WaitForProcessPoller.h" + +namespace lib { + [[nodiscard]] inline bool check_traced_running() + { + //Scan for traced process running. + std::set traced_pids {}; + WaitForProcessPoller traced_poller("traced"); + + return traced_poller.poll(traced_pids); + } + + [[nodiscard]] inline bool is_android() + { + return capture::detectOs() == capture::OsType::Android; + } + +} diff --git a/daemon/linux/perf/PerfDriverCreateSource.cpp b/daemon/linux/perf/PerfDriverCreateSource.cpp index 8812a1cd..5ad960f3 100644 --- a/daemon/linux/perf/PerfDriverCreateSource.cpp +++ b/daemon/linux/perf/PerfDriverCreateSource.cpp @@ -239,13 +239,19 @@ std::unique_ptr PerfDriver::create_source_a auto source = std::make_unique( senderSem, sender, - [wait_state](bool success) { + [wait_state, &agent_workers_process](bool success, std::vector monitored_pids) { LOG_DEBUG("Received agent-ready notification, success=%u", success); { auto lock = std::unique_lock(wait_state->ready_mutex); wait_state->ready_agent = success; } wait_state->condition.notify_one(); + + if (success) { + agent_workers_process.async_broadcast_when_ready(ipc::msg_monitored_pids_t {std::move(monitored_pids)}, + async::continuations::use_continuation) // + | DETACH_LOG_ERROR("Monitored PID broadcast"); + } }, std::move(exec_target_app_callback), std::move(profiling_started_callback)); diff --git a/daemon/linux/proc/ProcessPollerBase.cpp b/daemon/linux/proc/ProcessPollerBase.cpp index 7c45b8df..1edd479e 100644 --- a/daemon/linux/proc/ProcessPollerBase.cpp +++ b/daemon/linux/proc/ProcessPollerBase.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2021 by Arm Limited. All rights reserved. */ +/* Copyright (C) 2017-2022 by Arm Limited. All rights reserved. */ #include "linux/proc/ProcessPollerBase.h" @@ -50,31 +50,49 @@ namespace lnx { } return std::optional {}; } - } - - std::optional getProcessExePath(const lib::FsEntry & entry) - { - auto proc_pid_exe = lib::FsEntry::create(entry, "exe"); + std::optional checkExePathForAndroidAppProcess(const lib::FsEntry & proc_dir, + std::optional && exe_realpath) { - auto exe_realpath = proc_pid_exe.realpath(); - - if (exe_realpath) { + if (exe_realpath && exe_realpath->is_absolute()) { // check android paths auto name = exe_realpath->name(); if ((name == "app_process") || (name == "app_process32") || (name == "app_process64")) { // use the command line instead - auto cmdline_exe = getProcessCmdlineExePath(entry); + auto cmdline_exe = getProcessCmdlineExePath(proc_dir); if (cmdline_exe) { return cmdline_exe; } } - // use realpath(/proc/pid/exe) + // use provided path + return std::move(exe_realpath); + } + + return {}; + } + } + + std::optional getProcessExePath(const lib::FsEntry & entry) + { + auto proc_pid_exe = lib::FsEntry::create(entry, "exe"); + + // try realpath on 'exe'.. most of the time this will resolve to the canonical exe path + { + auto exe_realpath = checkExePathForAndroidAppProcess(entry, proc_pid_exe.realpath()); + if (exe_realpath) { return exe_realpath; } } + // realpath failed, possibly because the canonical name is invalid (e.g. inaccessible file path); try the readlink value + { + auto exe_readlink = checkExePathForAndroidAppProcess(entry, proc_pid_exe.readlink()); + if (exe_readlink) { + return exe_readlink; + } + } + // exe was linked to nothing, try getting from cmdline (but it must be for a real file) auto cmdline_exe = getProcessCmdlineExePath(entry); if (!cmdline_exe) { @@ -83,7 +101,7 @@ namespace lnx { } // resolve the cmdline string to a real path - if (cmdline_exe->path().front() == '/') { + if (cmdline_exe->is_absolute()) { // already an absolute path, so just resolve it to its realpath auto cmldine_exe_realpath = cmdline_exe->realpath(); if (cmldine_exe_realpath) { @@ -139,7 +157,9 @@ namespace lnx { { } - ProcessPollerBase::ProcessPollerBase() : procDir(lib::FsEntry::create("/proc")) {} + ProcessPollerBase::ProcessPollerBase() : procDir(lib::FsEntry::create("/proc")) + { + } void ProcessPollerBase::poll(bool wantThreads, bool wantStats, IProcessPollerReceiver & receiver) { diff --git a/daemon/main.cpp b/daemon/main.cpp index a2293b6f..17743299 100644 --- a/daemon/main.cpp +++ b/daemon/main.cpp @@ -5,6 +5,10 @@ #include "agents/perf/perf_agent_main.h" #include "agents/spawn_agent.h" +#if defined(ANDROID) || defined(__ANDROID__) +#include "agents/perfetto/perfetto_agent_main.h" +#endif + #include int main(int argc, char ** argv) @@ -17,6 +21,11 @@ int main(int argc, char ** argv) if (std::string_view(argv[1]) == agents::agent_id_perf) { return agents::perf::perf_agent_main(argv[0], lib::Span(argv + 2, argc - 2)); } +#if defined(ANDROID) || defined(__ANDROID__) + if (std::string_view(argv[1]) == agents::agent_id_perfetto) { + return agents::perfetto_agent_main(argv[0], lib::Span(argv + 2, argc - 2)); + } +#endif } return gator_main(argc, argv); diff --git a/daemon/mali_userspace/MaliHwCntrDriver.cpp b/daemon/mali_userspace/MaliHwCntrDriver.cpp index cc9af440..e81c5a2c 100644 --- a/daemon/mali_userspace/MaliHwCntrDriver.cpp +++ b/daemon/mali_userspace/MaliHwCntrDriver.cpp @@ -6,6 +6,9 @@ #include "Logging.h" #include "MaliGPUClockPolledDriver.h" #include "MaliHwCntr.h" +#include "SessionData.h" +#include "capture/Environment.h" +#include "lib/perfetto_utils.h" #include "mali_userspace/MaliInstanceLocator.h" #include @@ -148,4 +151,5 @@ namespace mali_userspace { } return result; } + } diff --git a/daemon/mali_userspace/MaliHwCntrDriver.h b/daemon/mali_userspace/MaliHwCntrDriver.h index 77d04b69..59729f84 100644 --- a/daemon/mali_userspace/MaliHwCntrDriver.h +++ b/daemon/mali_userspace/MaliHwCntrDriver.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2021 by Arm Limited. All rights reserved. */ +/* Copyright (C) 2013-2022 by Arm Limited. All rights reserved. */ #ifndef NATIVE_GATOR_DAEMON_MIDGARDHWCOUNTERDRIVER_H_ #define NATIVE_GATOR_DAEMON_MIDGARDHWCOUNTERDRIVER_H_ diff --git a/daemon/non_root/NonRootSource.cpp b/daemon/non_root/NonRootSource.cpp index aea38138..1237c4f6 100644 --- a/daemon/non_root/NonRootSource.cpp +++ b/daemon/non_root/NonRootSource.cpp @@ -112,13 +112,19 @@ namespace non_root { mSwitchBuffers.setDone(); } - void NonRootSource::interrupt() { interrupted.store(true, std::memory_order_seq_cst); } + void NonRootSource::interrupt() + { + interrupted.store(true, std::memory_order_seq_cst); + } bool NonRootSource::write(ISender & sender) { - // bitwise & no short-circuit - return mGlobalCounterBuffer.write(sender) & mProcessCounterBuffer.write(sender) & mMiscBuffer.write(sender) - & mSwitchBuffers.write(sender); + auto const gcbw = mGlobalCounterBuffer.write(sender); + auto const pcbw = mProcessCounterBuffer.write(sender); + auto const mbw = mMiscBuffer.write(sender); + auto const sbw = mSwitchBuffers.write(sender); + + return gcbw && pcbw && mbw && sbw; } std::optional NonRootSource::sendSummary() diff --git a/daemon/pmus.xml b/daemon/pmus.xml index 2fae096b..b4cf45ab 100644 --- a/daemon/pmus.xml +++ b/daemon/pmus.xml @@ -100,6 +100,9 @@ + + + diff --git a/ext/perfetto b/ext/perfetto new file mode 160000 index 00000000..7e8d6801 --- /dev/null +++ b/ext/perfetto @@ -0,0 +1 @@ +Subproject commit 7e8d6801dbf73936a916dbcd8ed06a758c8d989e diff --git a/gator_me.py b/gator_me.py index e6d3dffb..d820d378 100755 --- a/gator_me.py +++ b/gator_me.py @@ -138,6 +138,8 @@ # Early imports for a basic Python 2.7 compat check from __future__ import print_function +import sys + try: import argparse as ap import atexit @@ -147,7 +149,6 @@ import shlex import shutil import subprocess as sp - import sys import tarfile import tempfile import time @@ -324,10 +325,13 @@ def get_device_model(device): device: The device instance. Returns: - The device model. + The device model or None if the call failed. """ - logFile = device.adb("shell", "getprop", "ro.product.model") - return logFile.strip() + try: + logFile = device.adb("shell", "getprop", "ro.product.model") + return logFile.strip() + except sp.CalledProcessError: + return None def get_connected_devices(): @@ -345,10 +349,13 @@ def get_connected_devices(): try: adb = Device() logFile = adb.adb("devices") + for line in logFile.splitlines(): line = line.rstrip() - # Match devices that are available for adb + # Match devices that are available for adb. Note devices may be + # flagged as not available if get_device_model() fails, which can + # happen with dev boards accessed over wired Ethernet. if line.endswith("device"): deviceName = line.split()[0] model = get_device_model(Device(deviceName))